From 8d2662410945ae6ede135dd141e4edecc98406a3 Mon Sep 17 00:00:00 2001 From: Petr Chornyj Date: Sun, 2 Jan 2011 09:15:19 +0000 Subject: [PATCH] 2010-02-01 11:10 UTC+0200 Petr Chornyj (myorg63 at mail.ru) * contrib/hbmxml * contrib/hbmxml/3rd * contrib/hbmxml/3rd/minixml * contrib/hbmxml/3rd/minixml/config.h * contrib/hbmxml/3rd/minixml/COPYING * contrib/hbmxml/3rd/minixml/mxml-private.h * contrib/hbmxml/3rd/minixml/mxml.h * contrib/hbmxml/3rd/minixml/mxml.hbc * contrib/hbmxml/3rd/minixml/mxml.hbp * contrib/hbmxml/3rd/minixml/mxml_att.c * contrib/hbmxml/3rd/minixml/mxml_ent.c * contrib/hbmxml/3rd/minixml/mxml_fil.c * contrib/hbmxml/3rd/minixml/mxml_ind.c * contrib/hbmxml/3rd/minixml/mxml_nod.c * contrib/hbmxml/3rd/minixml/mxml_pri.c * contrib/hbmxml/3rd/minixml/mxml_pri.h * contrib/hbmxml/3rd/minixml/mxml_sea.c * contrib/hbmxml/3rd/minixml/mxml_set.c * contrib/hbmxml/3rd/minixml/mxml_str.c * contrib/hbmxml/hbmxml.c * contrib/hbmxml/hbmxml.ch * contrib/hbmxml/hbmxml.hbc * contrib/hbmxml/hbmxml.hbp * contrib/hbmxml/tests * contrib/hbmxml/tests/hbmk.hbm * contrib/hbmxml/tests/test.prg * contrib/hbmxml/tests/test.xml + added wrapper to miniXML library. Not finished yet, work in progress * contrib/hbxdiff * contrib/hbxdiff/3rd * contrib/hbxdiff/3rd/libxdiff * contrib/hbxdiff/3rd/libxdiff/AUTHORS * contrib/hbxdiff/3rd/libxdiff/config.h * contrib/hbxdiff/3rd/libxdiff/COPYING * contrib/hbxdiff/3rd/libxdiff/xadler32.c * contrib/hbxdiff/3rd/libxdiff/xadler32.h * contrib/hbxdiff/3rd/libxdiff/xalloc.c * contrib/hbxdiff/3rd/libxdiff/xbdiff.c * contrib/hbxdiff/3rd/libxdiff/xbdiff.h * contrib/hbxdiff/3rd/libxdiff/xbpatchi.c * contrib/hbxdiff/3rd/libxdiff/xdiff.h * contrib/hbxdiff/3rd/libxdiff/xdiff.hbc * contrib/hbxdiff/3rd/libxdiff/xdiff.hbp * contrib/hbxdiff/3rd/libxdiff/xdiff.txt * contrib/hbxdiff/3rd/libxdiff/xdiffi.c * contrib/hbxdiff/3rd/libxdiff/xdiffi.h * contrib/hbxdiff/3rd/libxdiff/xemit.c * contrib/hbxdiff/3rd/libxdiff/xemit.h * contrib/hbxdiff/3rd/libxdiff/xinclude.h * contrib/hbxdiff/3rd/libxdiff/xmacros.h * contrib/hbxdiff/3rd/libxdiff/xmerge3.c * contrib/hbxdiff/3rd/libxdiff/xmissing.c * contrib/hbxdiff/3rd/libxdiff/xmissing.h * contrib/hbxdiff/3rd/libxdiff/xpatchi.c * contrib/hbxdiff/3rd/libxdiff/xprepare.c * contrib/hbxdiff/3rd/libxdiff/xprepare.h * contrib/hbxdiff/3rd/libxdiff/xrabdiff.c * contrib/hbxdiff/3rd/libxdiff/xrabply.c * contrib/hbxdiff/3rd/libxdiff/xtypes.h * contrib/hbxdiff/3rd/libxdiff/xutils.c * contrib/hbxdiff/3rd/libxdiff/xutils.h * contrib/hbxdiff/3rd/libxdiff/xversion.c * contrib/hbxdiff/hbxdiff.c * contrib/hbxdiff/hbxdiff.ch * contrib/hbxdiff/hbxdiff.hbc * contrib/hbxdiff/hbxdiff.hbp * contrib/hbxdiff/tests * contrib/hbxdiff/tests/hbmk.hbm * contrib/hbxdiff/tests/test.prg * contrib/hbxdiff/tests/test2.prg * contrib/hbxdiff/tests/test3.prg + added wrapper to libxdiff library. Not finished yet, work in progress --- harbour/ChangeLog | 76 + harbour/contrib/hbmxml/3rd/minixml/COPYING | 507 +++ harbour/contrib/hbmxml/3rd/minixml/config.h | 109 + .../contrib/hbmxml/3rd/minixml/mxml-private.h | 50 + harbour/contrib/hbmxml/3rd/minixml/mxml.h | 307 ++ harbour/contrib/hbmxml/3rd/minixml/mxml.hbc | 5 + harbour/contrib/hbmxml/3rd/minixml/mxml.hbp | 40 + harbour/contrib/hbmxml/3rd/minixml/mxml_att.c | 319 ++ harbour/contrib/hbmxml/3rd/minixml/mxml_ent.c | 460 +++ harbour/contrib/hbmxml/3rd/minixml/mxml_fil.c | 3076 +++++++++++++++++ harbour/contrib/hbmxml/3rd/minixml/mxml_ind.c | 647 ++++ harbour/contrib/hbmxml/3rd/minixml/mxml_nod.c | 778 +++++ harbour/contrib/hbmxml/3rd/minixml/mxml_pri.c | 331 ++ harbour/contrib/hbmxml/3rd/minixml/mxml_pri.h | 50 + harbour/contrib/hbmxml/3rd/minixml/mxml_sea.c | 281 ++ harbour/contrib/hbmxml/3rd/minixml/mxml_set.c | 292 ++ harbour/contrib/hbmxml/3rd/minixml/mxml_str.c | 476 +++ harbour/contrib/hbmxml/hbmxml.c | 1292 +++++++ harbour/contrib/hbmxml/hbmxml.ch | 89 + harbour/contrib/hbmxml/hbmxml.hbc | 8 + harbour/contrib/hbmxml/hbmxml.hbp | 23 + harbour/contrib/hbmxml/tests/hbmk.hbm | 7 + harbour/contrib/hbmxml/tests/test.prg | 571 +++ harbour/contrib/hbmxml/tests/test.xml | 29 + harbour/contrib/hbxdiff/3rd/libxdiff/AUTHORS | 2 + harbour/contrib/hbxdiff/3rd/libxdiff/COPYING | 504 +++ harbour/contrib/hbxdiff/3rd/libxdiff/config.h | 106 + .../contrib/hbxdiff/3rd/libxdiff/xadler32.c | 70 + .../contrib/hbxdiff/3rd/libxdiff/xadler32.h | 34 + harbour/contrib/hbxdiff/3rd/libxdiff/xalloc.c | 51 + harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.c | 315 ++ harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.h | 40 + .../contrib/hbxdiff/3rd/libxdiff/xbpatchi.c | 336 ++ harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.h | 135 + .../contrib/hbxdiff/3rd/libxdiff/xdiff.hbc | 5 + .../contrib/hbxdiff/3rd/libxdiff/xdiff.hbp | 64 + .../contrib/hbxdiff/3rd/libxdiff/xdiff.txt | 611 ++++ harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.c | 556 +++ harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.h | 60 + harbour/contrib/hbxdiff/3rd/libxdiff/xemit.c | 132 + harbour/contrib/hbxdiff/3rd/libxdiff/xemit.h | 34 + .../contrib/hbxdiff/3rd/libxdiff/xinclude.h | 71 + .../contrib/hbxdiff/3rd/libxdiff/xmacros.h | 51 + .../contrib/hbxdiff/3rd/libxdiff/xmerge3.c | 66 + .../contrib/hbxdiff/3rd/libxdiff/xmissing.c | 92 + .../contrib/hbxdiff/3rd/libxdiff/xmissing.h | 56 + .../contrib/hbxdiff/3rd/libxdiff/xpatchi.c | 641 ++++ .../contrib/hbxdiff/3rd/libxdiff/xprepare.c | 456 +++ .../contrib/hbxdiff/3rd/libxdiff/xprepare.h | 35 + .../contrib/hbxdiff/3rd/libxdiff/xrabdiff.c | 381 ++ .../contrib/hbxdiff/3rd/libxdiff/xrabply.c | 298 ++ harbour/contrib/hbxdiff/3rd/libxdiff/xtypes.h | 68 + harbour/contrib/hbxdiff/3rd/libxdiff/xutils.c | 580 ++++ harbour/contrib/hbxdiff/3rd/libxdiff/xutils.h | 47 + .../contrib/hbxdiff/3rd/libxdiff/xversion.c | 27 + harbour/contrib/hbxdiff/hbxdiff.c | 664 ++++ harbour/contrib/hbxdiff/hbxdiff.ch | 74 + harbour/contrib/hbxdiff/hbxdiff.hbc | 8 + harbour/contrib/hbxdiff/hbxdiff.hbp | 23 + harbour/contrib/hbxdiff/tests/hbmk.hbm | 7 + harbour/contrib/hbxdiff/tests/test.prg | 38 + harbour/contrib/hbxdiff/tests/test2.prg | 51 + harbour/contrib/hbxdiff/tests/test3.prg | 34 + 63 files changed, 16646 insertions(+) create mode 100644 harbour/contrib/hbmxml/3rd/minixml/COPYING create mode 100644 harbour/contrib/hbmxml/3rd/minixml/config.h create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml-private.h create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml.h create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml.hbc create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml.hbp create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_att.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_ent.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_fil.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_ind.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_nod.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_pri.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_pri.h create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_sea.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_set.c create mode 100644 harbour/contrib/hbmxml/3rd/minixml/mxml_str.c create mode 100644 harbour/contrib/hbmxml/hbmxml.c create mode 100644 harbour/contrib/hbmxml/hbmxml.ch create mode 100644 harbour/contrib/hbmxml/hbmxml.hbc create mode 100644 harbour/contrib/hbmxml/hbmxml.hbp create mode 100644 harbour/contrib/hbmxml/tests/hbmk.hbm create mode 100644 harbour/contrib/hbmxml/tests/test.prg create mode 100644 harbour/contrib/hbmxml/tests/test.xml create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/AUTHORS create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/COPYING create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/config.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xalloc.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xbpatchi.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbc create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbp create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.txt create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xemit.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xemit.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xinclude.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xmacros.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xmerge3.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xpatchi.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xrabdiff.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xrabply.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xtypes.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xutils.c create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xutils.h create mode 100644 harbour/contrib/hbxdiff/3rd/libxdiff/xversion.c create mode 100644 harbour/contrib/hbxdiff/hbxdiff.c create mode 100644 harbour/contrib/hbxdiff/hbxdiff.ch create mode 100644 harbour/contrib/hbxdiff/hbxdiff.hbc create mode 100644 harbour/contrib/hbxdiff/hbxdiff.hbp create mode 100644 harbour/contrib/hbxdiff/tests/hbmk.hbm create mode 100644 harbour/contrib/hbxdiff/tests/test.prg create mode 100644 harbour/contrib/hbxdiff/tests/test2.prg create mode 100644 harbour/contrib/hbxdiff/tests/test3.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 85d1aa2560..12078cd495 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,82 @@ The license applies to all entries newer than 2009-04-28. */ +2010-02-01 11:10 UTC+0200 Petr Chornyj (myorg63 at mail.ru) + * contrib/hbmxml + * contrib/hbmxml/3rd + * contrib/hbmxml/3rd/minixml + * contrib/hbmxml/3rd/minixml/config.h + * contrib/hbmxml/3rd/minixml/COPYING + * contrib/hbmxml/3rd/minixml/mxml-private.h + * contrib/hbmxml/3rd/minixml/mxml.h + * contrib/hbmxml/3rd/minixml/mxml.hbc + * contrib/hbmxml/3rd/minixml/mxml.hbp + * contrib/hbmxml/3rd/minixml/mxml_att.c + * contrib/hbmxml/3rd/minixml/mxml_ent.c + * contrib/hbmxml/3rd/minixml/mxml_fil.c + * contrib/hbmxml/3rd/minixml/mxml_ind.c + * contrib/hbmxml/3rd/minixml/mxml_nod.c + * contrib/hbmxml/3rd/minixml/mxml_pri.c + * contrib/hbmxml/3rd/minixml/mxml_pri.h + * contrib/hbmxml/3rd/minixml/mxml_sea.c + * contrib/hbmxml/3rd/minixml/mxml_set.c + * contrib/hbmxml/3rd/minixml/mxml_str.c + * contrib/hbmxml/hbmxml.c + * contrib/hbmxml/hbmxml.ch + * contrib/hbmxml/hbmxml.hbc + * contrib/hbmxml/hbmxml.hbp + * contrib/hbmxml/tests + * contrib/hbmxml/tests/hbmk.hbm + * contrib/hbmxml/tests/test.prg + * contrib/hbmxml/tests/test.xml + + added wrapper to miniXML library. + Not finished yet, work in progress + * contrib/hbxdiff + * contrib/hbxdiff/3rd + * contrib/hbxdiff/3rd/libxdiff + * contrib/hbxdiff/3rd/libxdiff/AUTHORS + * contrib/hbxdiff/3rd/libxdiff/config.h + * contrib/hbxdiff/3rd/libxdiff/COPYING + * contrib/hbxdiff/3rd/libxdiff/xadler32.c + * contrib/hbxdiff/3rd/libxdiff/xadler32.h + * contrib/hbxdiff/3rd/libxdiff/xalloc.c + * contrib/hbxdiff/3rd/libxdiff/xbdiff.c + * contrib/hbxdiff/3rd/libxdiff/xbdiff.h + * contrib/hbxdiff/3rd/libxdiff/xbpatchi.c + * contrib/hbxdiff/3rd/libxdiff/xdiff.h + * contrib/hbxdiff/3rd/libxdiff/xdiff.hbc + * contrib/hbxdiff/3rd/libxdiff/xdiff.hbp + * contrib/hbxdiff/3rd/libxdiff/xdiff.txt + * contrib/hbxdiff/3rd/libxdiff/xdiffi.c + * contrib/hbxdiff/3rd/libxdiff/xdiffi.h + * contrib/hbxdiff/3rd/libxdiff/xemit.c + * contrib/hbxdiff/3rd/libxdiff/xemit.h + * contrib/hbxdiff/3rd/libxdiff/xinclude.h + * contrib/hbxdiff/3rd/libxdiff/xmacros.h + * contrib/hbxdiff/3rd/libxdiff/xmerge3.c + * contrib/hbxdiff/3rd/libxdiff/xmissing.c + * contrib/hbxdiff/3rd/libxdiff/xmissing.h + * contrib/hbxdiff/3rd/libxdiff/xpatchi.c + * contrib/hbxdiff/3rd/libxdiff/xprepare.c + * contrib/hbxdiff/3rd/libxdiff/xprepare.h + * contrib/hbxdiff/3rd/libxdiff/xrabdiff.c + * contrib/hbxdiff/3rd/libxdiff/xrabply.c + * contrib/hbxdiff/3rd/libxdiff/xtypes.h + * contrib/hbxdiff/3rd/libxdiff/xutils.c + * contrib/hbxdiff/3rd/libxdiff/xutils.h + * contrib/hbxdiff/3rd/libxdiff/xversion.c + * contrib/hbxdiff/hbxdiff.c + * contrib/hbxdiff/hbxdiff.ch + * contrib/hbxdiff/hbxdiff.hbc + * contrib/hbxdiff/hbxdiff.hbp + * contrib/hbxdiff/tests + * contrib/hbxdiff/tests/hbmk.hbm + * contrib/hbxdiff/tests/test.prg + * contrib/hbxdiff/tests/test2.prg + * contrib/hbxdiff/tests/test3.prg + + added wrapper to libxdiff library. + Not finished yet, work in progress + 2010-12-23 22:40 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/src/rtl/fieldbl.prg ! fixed FieldBLock() and FieldWBLock() to be CA-Cl*pper compatible diff --git a/harbour/contrib/hbmxml/3rd/minixml/COPYING b/harbour/contrib/hbmxml/3rd/minixml/COPYING new file mode 100644 index 0000000000..d7b975cd70 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/COPYING @@ -0,0 +1,507 @@ + Mini-XML License + September 18, 2010 + + +The Mini-XML library and included programs are provided under the +terms of the GNU Library General Public License version 2 (LGPL2) +with the following exceptions: + + 1. Static linking of applications to the Mini-XML library + does not constitute a derivative work and does not require + the author to provide source code for the application, use + the shared Mini-XML libraries, or link their applications + against a user-supplied version of Mini-XML. + + If you link the application to a modified version of + Mini-XML, then the changes to Mini-XML must be provided + under the terms of the LGPL2 in sections 1, 2, and 4. + + 2. You do not have to provide a copy of the Mini-XML license + with programs that are linked to the Mini-XML library, nor + do you have to identify the Mini-XML license in your + program or documentation as required by section 6 of the + LGPL2. + + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 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. + + [This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/harbour/contrib/hbmxml/3rd/minixml/config.h b/harbour/contrib/hbmxml/3rd/minixml/config.h new file mode 100644 index 0000000000..0d2238eba6 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/config.h @@ -0,0 +1,109 @@ +/* + * $Id$ + */ + +/* + * Configuration file for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + */ + + +#if defined( _MSC_VER ) +# define _CRT_SECURE_NO_DEPRECATE +# define _CRT_SECURE_NO_WARNINGS + +# define close _close +# define open _open +# define read _read +# define snprintf _snprintf +# define strdup _strdup +# define vsnprintf _vsnprintf +# define write _write +#endif + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Version number... + */ + +#define MXML_VERSION "Mini-XML v2.7" + +/* + * Inline function support... + */ + +#if defined( __GNUC__ ) +# define inline __inline__ +#elif defined( _MSC_VER ) +# define inline _inline +#else +# define inline +#endif + +/* + * Long long support... + */ + +#define HAVE_LONG_LONG 1 + +/* + * Do we have the snprintf() and vsnprintf() functions? + */ + +#define HAVE_SNPRINTF 1 +#define HAVE_VSNPRINTF 1 + +/* + * Do we have the strXXX() functions? + */ + +#define HAVE_STRDUP 1 + +/* + * Do we have threading support? + */ + +/* #undef HAVE_PTHREAD_H */ + + +/* + * Define prototypes for string functions as needed... + */ + +# ifndef HAVE_STRDUP +extern char *_mxml_strdup(const char *); +# define strdup _mxml_strdup +# endif /* !HAVE_STRDUP */ + +extern char *_mxml_strdupf(const char *, ...); +extern char *_mxml_vstrdupf(const char *, va_list); + +# ifndef HAVE_SNPRINTF +extern int _mxml_snprintf(char *, size_t, const char *, ...); +# define snprintf _mxml_snprintf +# endif /* !HAVE_SNPRINTF */ + +# ifndef HAVE_VSNPRINTF +extern int _mxml_vsnprintf(char *, size_t, const char *, va_list); +# define vsnprintf _mxml_vsnprintf +# endif /* !HAVE_VSNPRINTF */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml-private.h b/harbour/contrib/hbmxml/3rd/minixml/mxml-private.h new file mode 100644 index 0000000000..8789e6c52c --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml-private.h @@ -0,0 +1,50 @@ +/* + * "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $" + * + * Private definitions for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + */ + +/* + * Include necessary headers... + */ + +#include "config.h" +#include "mxml.h" + + +/* + * Global, per-thread data... + */ + +typedef struct _mxml_global_s +{ + void (*error_cb)(const char *); + int num_entity_cbs; + int (*entity_cbs[100])(const char *name); + int wrap; + mxml_custom_load_cb_t custom_load_cb; + mxml_custom_save_cb_t custom_save_cb; +} _mxml_global_t; + + +/* + * Functions... + */ + +extern _mxml_global_t *_mxml_global(void); +extern int _mxml_entity_cb(const char *name); + + +/* + * End of "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml.h b/harbour/contrib/hbmxml/3rd/minixml/mxml.h new file mode 100644 index 0000000000..b52319cacd --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml.h @@ -0,0 +1,307 @@ +/* + * "$Id: mxml.h 423 2010-11-08 16:07:05Z mike $" + * + * Header file for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + */ + +/* + * Prevent multiple inclusion... + */ + +#ifndef _mxml_h_ +# define _mxml_h_ + +/* + * Include necessary headers... + */ + +# include +# include +# include +# include +# include + + +/* + * Constants... + */ + +# define MXML_TAB 8 /* Tabs every N columns */ + +# define MXML_NO_CALLBACK 0 /* Don't use a type callback */ +# define MXML_INTEGER_CALLBACK mxml_integer_cb + /* Treat all data as integers */ +# define MXML_OPAQUE_CALLBACK mxml_opaque_cb + /* Treat all data as opaque */ +# define MXML_REAL_CALLBACK mxml_real_cb + /* Treat all data as real numbers */ +# define MXML_TEXT_CALLBACK 0 /* Treat all data as text */ +# define MXML_IGNORE_CALLBACK mxml_ignore_cb + /* Ignore all non-element content */ + +# define MXML_NO_PARENT 0 /* No parent for the node */ + +# define MXML_DESCEND 1 /* Descend when finding/walking */ +# define MXML_NO_DESCEND 0 /* Don't descend when finding/walking */ +# define MXML_DESCEND_FIRST -1 /* Descend for first find */ + +# define MXML_WS_BEFORE_OPEN 0 /* Callback for before open tag */ +# define MXML_WS_AFTER_OPEN 1 /* Callback for after open tag */ +# define MXML_WS_BEFORE_CLOSE 2 /* Callback for before close tag */ +# define MXML_WS_AFTER_CLOSE 3 /* Callback for after close tag */ + +# define MXML_ADD_BEFORE 0 /* Add node before specified node */ +# define MXML_ADD_AFTER 1 /* Add node after specified node */ +# define MXML_ADD_TO_PARENT NULL /* Add node relative to parent */ + + +/* + * Data types... + */ + +typedef enum mxml_sax_event_e /**** SAX event type. ****/ +{ + MXML_SAX_CDATA, /* CDATA node */ + MXML_SAX_COMMENT, /* Comment node */ + MXML_SAX_DATA, /* Data node */ + MXML_SAX_DIRECTIVE, /* Processing directive node */ + MXML_SAX_ELEMENT_CLOSE, /* Element closed */ + MXML_SAX_ELEMENT_OPEN /* Element opened */ +} mxml_sax_event_t; + +typedef enum mxml_type_e /**** The XML node type. ****/ +{ + MXML_IGNORE = -1, /* Ignore/throw away node @since Mini-XML 2.3@ */ + MXML_ELEMENT, /* XML element with attributes */ + MXML_INTEGER, /* Integer value */ + MXML_OPAQUE, /* Opaque string */ + MXML_REAL, /* Real value */ + MXML_TEXT, /* Text fragment */ + MXML_CUSTOM /* Custom data @since Mini-XML 2.1@ */ +} mxml_type_t; + +typedef void (*mxml_custom_destroy_cb_t)(void *); + /**** Custom data destructor ****/ + +typedef void (*mxml_error_cb_t)(const char *); + /**** Error callback function ****/ + +typedef struct mxml_attr_s /**** An XML element attribute value. ****/ +{ + char *name; /* Attribute name */ + char *value; /* Attribute value */ +} mxml_attr_t; + +typedef struct mxml_element_s /**** An XML element value. ****/ +{ + char *name; /* Name of element */ + int num_attrs; /* Number of attributes */ + mxml_attr_t *attrs; /* Attributes */ +} mxml_element_t; + +typedef struct mxml_text_s /**** An XML text value. ****/ +{ + int whitespace; /* Leading whitespace? */ + char *string; /* Fragment string */ +} mxml_text_t; + +typedef struct mxml_custom_s /**** An XML custom value. @since Mini-XML 2.1@ ****/ +{ + void *data; /* Pointer to (allocated) custom data */ + mxml_custom_destroy_cb_t destroy; /* Pointer to destructor function */ +} mxml_custom_t; + +typedef union mxml_value_u /**** An XML node value. ****/ +{ + mxml_element_t element; /* Element */ + int integer; /* Integer number */ + char *opaque; /* Opaque string */ + double real; /* Real number */ + mxml_text_t text; /* Text fragment */ + mxml_custom_t custom; /* Custom data @since Mini-XML 2.1@ */ +} mxml_value_t; + +typedef struct mxml_node_s /**** An XML node. ****/ +{ + mxml_type_t type; /* Node type */ + struct mxml_node_s *next; /* Next node under same parent */ + struct mxml_node_s *prev; /* Previous node under same parent */ + struct mxml_node_s *parent; /* Parent node */ + struct mxml_node_s *child; /* First child node */ + struct mxml_node_s *last_child; /* Last child node */ + mxml_value_t value; /* Node value */ + int ref_count; /* Use count */ + void *user_data; /* User data */ +} mxml_node_t; + +typedef struct mxml_index_s /**** An XML node index. ****/ +{ + char *attr; /* Attribute used for indexing or NULL */ + int num_nodes; /* Number of nodes in index */ + int alloc_nodes; /* Allocated nodes in index */ + int cur_node; /* Current node */ + mxml_node_t **nodes; /* Node array */ +} mxml_index_t; + +typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *); + /**** Custom data load callback function ****/ + +typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *); + /**** Custom data save callback function ****/ + +typedef int (*mxml_entity_cb_t)(const char *); + /**** Entity callback function */ + +typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *); + /**** Load callback function ****/ + +typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int); + /**** Save callback function ****/ + +typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *); + /**** SAX callback function ****/ + + +/* + * C++ support... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +/* + * Prototypes... + */ + +extern void mxmlAdd(mxml_node_t *parent, int where, + mxml_node_t *child, mxml_node_t *node); +extern void mxmlDelete(mxml_node_t *node); +extern void mxmlElementDeleteAttr(mxml_node_t *node, + const char *name); +extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name); +extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, + const char *value); +extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, + const char *format, ...) +# ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 3, 4))) +# endif /* __GNUC__ */ +; +extern int mxmlEntityAddCallback(mxml_entity_cb_t cb); +extern const char *mxmlEntityGetName(int val); +extern int mxmlEntityGetValue(const char *name); +extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb); +extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, + const char *name, const char *attr, + const char *value, int descend); +extern mxml_node_t *mxmlFindValue(mxml_node_t *node, const char *path); +extern void mxmlIndexDelete(mxml_index_t *ind); +extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind); +extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind, + const char *element, + const char *value); +extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, + const char *attr); +extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind); +extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd, + mxml_type_t (*cb)(mxml_node_t *)); +extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, + mxml_type_t (*cb)(mxml_node_t *)); +extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s, + mxml_type_t (*cb)(mxml_node_t *)); +extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string); +extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, + mxml_custom_destroy_cb_t destroy); +extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name); +extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer); +extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque); +extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real); +extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace, + const char *string); +extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace, + const char *format, ...) +# ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 3, 4))) +# endif /* __GNUC__ */ +; +extern mxml_node_t *mxmlNewXML(const char *version); +extern int mxmlRelease(mxml_node_t *node); +extern void mxmlRemove(mxml_node_t *node); +extern int mxmlRetain(mxml_node_t *node); +extern char *mxmlSaveAllocString(mxml_node_t *node, + mxml_save_cb_t cb); +extern int mxmlSaveFd(mxml_node_t *node, int fd, + mxml_save_cb_t cb); +extern int mxmlSaveFile(mxml_node_t *node, FILE *fp, + mxml_save_cb_t cb); +extern int mxmlSaveString(mxml_node_t *node, char *buffer, + int bufsize, mxml_save_cb_t cb); +extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, int fd, + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); +extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp, + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); +extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s, + mxml_type_t (*cb)(mxml_node_t *), + mxml_sax_cb_t sax, void *sax_data); +extern int mxmlSetCDATA(mxml_node_t *node, const char *data); +extern int mxmlSetCustom(mxml_node_t *node, void *data, + mxml_custom_destroy_cb_t destroy); +extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load, + mxml_custom_save_cb_t save); +extern int mxmlSetElement(mxml_node_t *node, const char *name); +extern void mxmlSetErrorCallback(mxml_error_cb_t cb); +extern int mxmlSetInteger(mxml_node_t *node, int integer); +extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque); +extern int mxmlSetReal(mxml_node_t *node, double real); +extern int mxmlSetText(mxml_node_t *node, int whitespace, + const char *string); +extern int mxmlSetTextf(mxml_node_t *node, int whitespace, + const char *format, ...) +# ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 3, 4))) +# endif /* __GNUC__ */ +; +extern void mxmlSetWrapMargin(int column); +extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, + int descend); +extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, + int descend); + + +/* + * Semi-private functions... + */ + +extern void mxml_error(const char *format, ...); +extern mxml_type_t mxml_ignore_cb(mxml_node_t *node); +extern mxml_type_t mxml_integer_cb(mxml_node_t *node); +extern mxml_type_t mxml_opaque_cb(mxml_node_t *node); +extern mxml_type_t mxml_real_cb(mxml_node_t *node); + + +/* + * C++ support... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_mxml_h_ */ + + +/* + * End of "$Id: mxml.h 423 2010-11-08 16:07:05Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml.hbc b/harbour/contrib/hbmxml/3rd/minixml/mxml.hbc new file mode 100644 index 0000000000..86f6254c46 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml.hbc @@ -0,0 +1,5 @@ +# +# $Id$ +# + +libs=${hb_name}${__HB_DYN__} diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml.hbp b/harbour/contrib/hbmxml/3rd/minixml/mxml.hbp new file mode 100644 index 0000000000..f74e9f99f6 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml.hbp @@ -0,0 +1,40 @@ +# +# $Id$ +# + +-hblib +-inc + +-o${hb_targetname} + +-warn=low +-cpp=no + +{win}-cflag=-DWIN32 + +mxml_att.c +mxml_ent.c +mxml_fil.c +mxml_ind.c +mxml_nod.c +mxml_pri.c +mxml_sea.c +mxml_set.c +mxml_str.c + +# ORIGIN http://www.minixml.org +# VER 2.7 +# URL +# DIFF +# +# MAP mxml-attr.c mxml_att.c +# MAP mxml-entity.c mxml_ent.c +# MAP mxml-file.c mxml_fil.c +# MAP mxml-index.c mxml_ind.c +# MAP mxml-node.c mxml_nod.c +# MAP mxml-private.c mxml_pri.c +# MAP mxml-search.c mxml_sea.c +# MAP mxml-set.c mxml_set.c +# MAP mxml-string.c mxml_str.c +# MAP mxml.h mxml.h +# MAP mxml-private.h mxml_pri.h diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_att.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_att.c new file mode 100644 index 0000000000..c9950f5fb7 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_att.c @@ -0,0 +1,319 @@ +/* + * "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $" + * + * Attribute support code for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxmlElementDeleteAttr() - Delete an attribute. + * mxmlElementGetAttr() - Get an attribute. + * mxmlElementSetAttr() - Set an attribute. + * mxmlElementSetAttrf() - Set an attribute with a formatted value. + * mxml_set_attr() - Set or add an attribute name/value pair. + */ + +/* + * Include necessary headers... + */ + +#include "config.h" +#include "mxml.h" + + +/* + * Local functions... + */ + +static int mxml_set_attr(mxml_node_t *node, const char *name, + char *value); + + +/* + * 'mxmlElementDeleteAttr()' - Delete an attribute. + * + * @since Mini-XML 2.4@ + */ + +void +mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ + const char *name)/* I - Attribute name */ +{ + int i; /* Looping var */ + mxml_attr_t *attr; /* Cirrent attribute */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n", + node, name ? name : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!node || node->type != MXML_ELEMENT || !name) + return; + + /* + * Look for the attribute... + */ + + for (i = node->value.element.num_attrs, attr = node->value.element.attrs; + i > 0; + i --, attr ++) + { +#ifdef DEBUG + printf(" %s=\"%s\"\n", attr->name, attr->value); +#endif /* DEBUG */ + + if (!strcmp(attr->name, name)) + { + /* + * Delete this attribute... + */ + + free(attr->name); + free(attr->value); + + i --; + if (i > 0) + memmove(attr, attr + 1, i * sizeof(mxml_attr_t)); + + node->value.element.num_attrs --; + return; + } + } +} + + +/* + * 'mxmlElementGetAttr()' - Get an attribute. + * + * This function returns NULL if the node is not an element or the + * named attribute does not exist. + */ + +const char * /* O - Attribute value or NULL */ +mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ + const char *name) /* I - Name of attribute */ +{ + int i; /* Looping var */ + mxml_attr_t *attr; /* Cirrent attribute */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n", + node, name ? name : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!node || node->type != MXML_ELEMENT || !name) + return (NULL); + + /* + * Look for the attribute... + */ + + for (i = node->value.element.num_attrs, attr = node->value.element.attrs; + i > 0; + i --, attr ++) + { +#ifdef DEBUG + printf(" %s=\"%s\"\n", attr->name, attr->value); +#endif /* DEBUG */ + + if (!strcmp(attr->name, name)) + { +#ifdef DEBUG + printf(" Returning \"%s\"!\n", attr->value); +#endif /* DEBUG */ + return (attr->value); + } + } + + /* + * Didn't find attribute, so return NULL... + */ + +#ifdef DEBUG + puts(" Returning NULL!\n"); +#endif /* DEBUG */ + + return (NULL); +} + + +/* + * 'mxmlElementSetAttr()' - Set an attribute. + * + * If the named attribute already exists, the value of the attribute + * is replaced by the new string value. The string value is copied + * into the element node. This function does nothing if the node is + * not an element. + */ + +void +mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ + const char *name, /* I - Name of attribute */ + const char *value) /* I - Attribute value */ +{ + char *valuec; /* Copy of value */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n", + node, name ? name : "(null)", value ? value : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!node || node->type != MXML_ELEMENT || !name) + return; + + if (value) + valuec = strdup(value); + else + valuec = NULL; + + if (mxml_set_attr(node, name, valuec)) + free(valuec); +} + + +/* + * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value. + * + * If the named attribute already exists, the value of the attribute + * is replaced by the new formatted string. The formatted string value is + * copied into the element node. This function does nothing if the node + * is not an element. + * + * @since Mini-XML 2.3@ + */ + +void +mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */ + const char *name, /* I - Name of attribute */ + const char *format,/* I - Printf-style attribute value */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Argument pointer */ + char *value; /* Value */ + + +#ifdef DEBUG + fprintf(stderr, + "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n", + node, name ? name : "(null)", format ? format : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!node || node->type != MXML_ELEMENT || !name || !format) + return; + + /* + * Format the value... + */ + + va_start(ap, format); + value = _mxml_vstrdupf(format, ap); + va_end(ap); + + if (!value) + mxml_error("Unable to allocate memory for attribute '%s' in element %s!", + name, node->value.element.name); + else if (mxml_set_attr(node, name, value)) + free(value); +} + + +/* + * 'mxml_set_attr()' - Set or add an attribute name/value pair. + */ + +static int /* O - 0 on success, -1 on failure */ +mxml_set_attr(mxml_node_t *node, /* I - Element node */ + const char *name, /* I - Attribute name */ + char *value) /* I - Attribute value */ +{ + int i; /* Looping var */ + mxml_attr_t *attr; /* New attribute */ + + + /* + * Look for the attribute... + */ + + for (i = node->value.element.num_attrs, attr = node->value.element.attrs; + i > 0; + i --, attr ++) + if (!strcmp(attr->name, name)) + { + /* + * Free the old value as needed... + */ + + if (attr->value) + free(attr->value); + + attr->value = value; + + return (0); + } + + /* + * Add a new attribute... + */ + + if (node->value.element.num_attrs == 0) + attr = malloc(sizeof(mxml_attr_t)); + else + attr = realloc(node->value.element.attrs, + (node->value.element.num_attrs + 1) * sizeof(mxml_attr_t)); + + if (!attr) + { + mxml_error("Unable to allocate memory for attribute '%s' in element %s!", + name, node->value.element.name); + return (-1); + } + + node->value.element.attrs = attr; + attr += node->value.element.num_attrs; + + if ((attr->name = strdup(name)) == NULL) + { + mxml_error("Unable to allocate memory for attribute '%s' in element %s!", + name, node->value.element.name); + return (-1); + } + + attr->value = value; + + node->value.element.num_attrs ++; + + return (0); +} + + +/* + * End of "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_ent.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_ent.c new file mode 100644 index 0000000000..c5c9f61f73 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_ent.c @@ -0,0 +1,460 @@ +/* + * "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $" + * + * Character entity support code for Mini-XML, a small XML-like + * file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxmlEntityAddCallback() - Add a callback to convert entities to + * Unicode. + * mxmlEntityGetName() - Get the name that corresponds to the + * character value. + * mxmlEntityGetValue() - Get the character corresponding to a named + * entity. + * mxmlEntityRemoveCallback() - Remove a callback. + * _mxml_entity_cb() - Lookup standard (X)HTML entities. + */ + +/* + * Include necessary headers... + */ + +#include "mxml-private.h" + + +/* + * 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode. + */ + +int /* O - 0 on success, -1 on failure */ +mxmlEntityAddCallback( + mxml_entity_cb_t cb) /* I - Callback function to add */ +{ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0]))) + { + global->entity_cbs[global->num_entity_cbs] = cb; + global->num_entity_cbs ++; + + return (0); + } + else + { + mxml_error("Unable to add entity callback!"); + + return (-1); + } +} + + +/* + * 'mxmlEntityGetName()' - Get the name that corresponds to the character value. + * + * If val does not need to be represented by a named entity, NULL is returned. + */ + +const char * /* O - Entity name or NULL */ +mxmlEntityGetName(int val) /* I - Character value */ +{ + switch (val) + { + case '&' : + return ("amp"); + + case '<' : + return ("lt"); + + case '>' : + return ("gt"); + + case '\"' : + return ("quot"); + + default : + return (NULL); + } +} + + +/* + * 'mxmlEntityGetValue()' - Get the character corresponding to a named entity. + * + * The entity name can also be a numeric constant. -1 is returned if the + * name is not known. + */ + +int /* O - Character value or -1 on error */ +mxmlEntityGetValue(const char *name) /* I - Entity name */ +{ + int i; /* Looping var */ + int ch; /* Character value */ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + for (i = 0; i < global->num_entity_cbs; i ++) + if ((ch = (global->entity_cbs[i])(name)) >= 0) + return (ch); + + return (-1); +} + + +/* + * 'mxmlEntityRemoveCallback()' - Remove a callback. + */ + +void +mxmlEntityRemoveCallback( + mxml_entity_cb_t cb) /* I - Callback function to remove */ +{ + int i; /* Looping var */ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + for (i = 0; i < global->num_entity_cbs; i ++) + if (cb == global->entity_cbs[i]) + { + /* + * Remove the callback... + */ + + global->num_entity_cbs --; + + if (i < global->num_entity_cbs) + memmove(global->entity_cbs + i, global->entity_cbs + i + 1, + (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0])); + + return; + } +} + + +/* + * '_mxml_entity_cb()' - Lookup standard (X)HTML entities. + */ + +int /* O - Unicode value or -1 */ +_mxml_entity_cb(const char *name) /* I - Entity name */ +{ + int diff, /* Difference between names */ + current, /* Current entity in search */ + first, /* First entity in search */ + last; /* Last entity in search */ + static const struct + { + const char *name; /* Entity name */ + int val; /* Character value */ + } entities[] = + { + { "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 }, + { "Dstrok", 208 }, + { "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", '&' }, + { "and", 8743 }, + { "ang", 8736 }, + { "apos", '\'' }, + { "aring", 229 }, + { "asymp", 8776 }, + { "atilde", 227 }, + { "auml", 228 }, + { "bdquo", 8222 }, + { "beta", 946 }, + { "brkbar", 166 }, + { "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 }, + { "die", 168 }, + { "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", '>' }, + { "hArr", 8660 }, + { "harr", 8596 }, + { "hearts", 9829 }, + { "hellip", 8230 }, + { "hibar", 175 }, + { "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", '<' }, + { "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", '\"' }, + { "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 } + }; + + + /* + * Do a binary search for the named entity... + */ + + first = 0; + last = (int)(sizeof(entities) / sizeof(entities[0]) - 1); + + while ((last - first) > 1) + { + current = (first + last) / 2; + + if ((diff = strcmp(name, entities[current].name)) == 0) + return (entities[current].val); + else if (diff < 0) + last = current; + else + first = current; + } + + /* + * If we get here, there is a small chance that there is still + * a match; check first and last... + */ + + if (!strcmp(name, entities[first].name)) + return (entities[first].val); + else if (!strcmp(name, entities[last].name)) + return (entities[last].val); + else + return (-1); +} + + +/* + * End of "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_fil.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_fil.c new file mode 100644 index 0000000000..f424d60bbe --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_fil.c @@ -0,0 +1,3076 @@ +/* + * "$Id: mxml-file.c 415 2010-09-19 07:29:46Z mike $" + * + * File loading code for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxmlLoadFd() - Load a file descriptor into an XML node tree. + * mxmlLoadFile() - Load a file into an XML node tree. + * mxmlLoadString() - Load a string into an XML node tree. + * mxmlSaveAllocString() - Save an XML tree to an allocated string. + * mxmlSaveFd() - Save an XML tree to a file descriptor. + * mxmlSaveFile() - Save an XML tree to a file. + * mxmlSaveString() - Save an XML node tree to a string. + * mxmlSAXLoadFd() - Load a file descriptor into an XML node tree + * using a SAX callback. + * mxmlSAXLoadFile() - Load a file into an XML node tree + * using a SAX callback. + * mxmlSAXLoadString() - Load a string into an XML node tree + * using a SAX callback. + * mxmlSetCustomHandlers() - Set the handling functions for custom data. + * mxmlSetErrorCallback() - Set the error message callback. + * mxmlSetWrapMargin() - Set the wrap margin when saving XML data. + * mxml_add_char() - Add a character to a buffer, expanding as needed. + * mxml_fd_getc() - Read a character from a file descriptor. + * mxml_fd_putc() - Write a character to a file descriptor. + * mxml_fd_read() - Read a buffer of data from a file descriptor. + * mxml_fd_write() - Write a buffer of data to a file descriptor. + * mxml_file_getc() - Get a character from a file. + * mxml_file_putc() - Write a character to a file. + * mxml_get_entity() - Get the character corresponding to an entity... + * mxml_load_data() - Load data into an XML node tree. + * mxml_parse_element() - Parse an element for any attributes... + * mxml_string_getc() - Get a character from a string. + * mxml_string_putc() - Write a character to a string. + * mxml_write_name() - Write a name string. + * mxml_write_node() - Save an XML node to a file. + * mxml_write_string() - Write a string, escaping & and < as needed. + * mxml_write_ws() - Do whitespace callback... + */ + +/* + * Include necessary headers... + */ + +#ifndef WIN32 +# include +#endif /* !WIN32 */ +#include "mxml-private.h" + + +/* + * Character encoding... + */ + +#define ENCODE_UTF8 0 /* UTF-8 */ +#define ENCODE_UTF16BE 1 /* UTF-16 Big-Endian */ +#define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian */ + + +/* + * Macro to test for a bad XML character... + */ + +#define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t') + + +/* + * Types and structures... + */ + +typedef int (*_mxml_getc_cb_t)(void *, int *); +typedef int (*_mxml_putc_cb_t)(int, void *); + +typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/ +{ + int fd; /* File descriptor */ + unsigned char *current, /* Current position in buffer */ + *end, /* End of buffer */ + buffer[8192]; /* Character buffer */ +} _mxml_fdbuf_t; + + +/* + * Local functions... + */ + +static int mxml_add_char(int ch, char **ptr, char **buffer, + int *bufsize); +static int mxml_fd_getc(void *p, int *encoding); +static int mxml_fd_putc(int ch, void *p); +static int mxml_fd_read(_mxml_fdbuf_t *buf); +static int mxml_fd_write(_mxml_fdbuf_t *buf); +static int mxml_file_getc(void *p, int *encoding); +static int mxml_file_putc(int ch, void *p); +static int mxml_get_entity(mxml_node_t *parent, void *p, + int *encoding, + _mxml_getc_cb_t getc_cb); +static inline int mxml_isspace(int ch) + { + return (ch == ' ' || ch == '\t' || ch == '\r' || + ch == '\n'); + } +static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p, + mxml_load_cb_t cb, + _mxml_getc_cb_t getc_cb, + mxml_sax_cb_t sax_cb, void *sax_data); +static int mxml_parse_element(mxml_node_t *node, void *p, + int *encoding, + _mxml_getc_cb_t getc_cb); +static int mxml_string_getc(void *p, int *encoding); +static int mxml_string_putc(int ch, void *p); +static int mxml_write_name(const char *s, void *p, + _mxml_putc_cb_t putc_cb); +static int mxml_write_node(mxml_node_t *node, void *p, + mxml_save_cb_t cb, int col, + _mxml_putc_cb_t putc_cb, + _mxml_global_t *global); +static int mxml_write_string(const char *s, void *p, + _mxml_putc_cb_t putc_cb); +static int mxml_write_ws(mxml_node_t *node, void *p, + mxml_save_cb_t cb, int ws, + int col, _mxml_putc_cb_t putc_cb); + + +/* + * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree. + * + * The nodes in the specified file are added to the specified top node. + * If no top node is provided, the XML file MUST be well-formed with a + * single parent node like for the entire file. The callback + * function returns the value type that should be used for child nodes. + * If MXML_NO_CALLBACK is specified then all child nodes will be either + * MXML_ELEMENT or MXML_TEXT nodes. + * + * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, + * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading + * child nodes of the specified type. + */ + +mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxmlLoadFd(mxml_node_t *top, /* I - Top node */ + int fd, /* I - File descriptor to read from */ + mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */ +{ + _mxml_fdbuf_t buf; /* File descriptor buffer */ + + + /* + * Initialize the file descriptor buffer... + */ + + buf.fd = fd; + buf.current = buf.buffer; + buf.end = buf.buffer; + + /* + * Read the XML data... + */ + + return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL)); +} + + +/* + * 'mxmlLoadFile()' - Load a file into an XML node tree. + * + * The nodes in the specified file are added to the specified top node. + * If no top node is provided, the XML file MUST be well-formed with a + * single parent node like for the entire file. The callback + * function returns the value type that should be used for child nodes. + * If MXML_NO_CALLBACK is specified then all child nodes will be either + * MXML_ELEMENT or MXML_TEXT nodes. + * + * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, + * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading + * child nodes of the specified type. + */ + +mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxmlLoadFile(mxml_node_t *top, /* I - Top node */ + FILE *fp, /* I - File to read from */ + mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */ +{ + /* + * Read the XML data... + */ + + return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL)); +} + + +/* + * 'mxmlLoadString()' - Load a string into an XML node tree. + * + * The nodes in the specified string are added to the specified top node. + * If no top node is provided, the XML string MUST be well-formed with a + * single parent node like for the entire string. The callback + * function returns the value type that should be used for child nodes. + * If MXML_NO_CALLBACK is specified then all child nodes will be either + * MXML_ELEMENT or MXML_TEXT nodes. + * + * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, + * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading + * child nodes of the specified type. + */ + +mxml_node_t * /* O - First node or NULL if the string has errors. */ +mxmlLoadString(mxml_node_t *top, /* I - Top node */ + const char *s, /* I - String to load */ + mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */ +{ + /* + * Read the XML data... + */ + + return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK, + NULL)); +} + + +/* + * 'mxmlSaveAllocString()' - Save an XML tree to an allocated string. + * + * This function returns a pointer to a string containing the textual + * representation of the XML node tree. The string should be freed + * using the free() function when you are done with it. NULL is returned + * if the node would produce an empty string or if the string cannot be + * allocated. + * + * The callback argument specifies a function that returns a whitespace + * string or NULL before and after each element. If MXML_NO_CALLBACK + * is specified, whitespace will only be added before MXML_TEXT nodes + * with leading whitespace and before attribute names inside opening + * element tags. + */ + +char * /* O - Allocated string or NULL */ +mxmlSaveAllocString( + mxml_node_t *node, /* I - Node to write */ + mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ +{ + int bytes; /* Required bytes */ + char buffer[8192]; /* Temporary buffer */ + char *s; /* Allocated string */ + + + /* + * Write the node to the temporary buffer... + */ + + bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb); + + if (bytes <= 0) + return (NULL); + + if (bytes < (int)(sizeof(buffer) - 1)) + { + /* + * Node fit inside the buffer, so just duplicate that string and + * return... + */ + + return (strdup(buffer)); + } + + /* + * Allocate a buffer of the required size and save the node to the + * new buffer... + */ + + if ((s = malloc(bytes + 1)) == NULL) + return (NULL); + + mxmlSaveString(node, s, bytes + 1, cb); + + /* + * Return the allocated string... + */ + + return (s); +} + + +/* + * 'mxmlSaveFd()' - Save an XML tree to a file descriptor. + * + * The callback argument specifies a function that returns a whitespace + * string or NULL before and after each element. If MXML_NO_CALLBACK + * is specified, whitespace will only be added before MXML_TEXT nodes + * with leading whitespace and before attribute names inside opening + * element tags. + */ + +int /* O - 0 on success, -1 on error. */ +mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ + int fd, /* I - File descriptor to write to */ + mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ +{ + int col; /* Final column */ + _mxml_fdbuf_t buf; /* File descriptor buffer */ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + /* + * Initialize the file descriptor buffer... + */ + + buf.fd = fd; + buf.current = buf.buffer; + buf.end = buf.buffer + sizeof(buf.buffer); + + /* + * Write the node... + */ + + if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global)) < 0) + return (-1); + + if (col > 0) + if (mxml_fd_putc('\n', &buf) < 0) + return (-1); + + /* + * Flush and return... + */ + + return (mxml_fd_write(&buf)); +} + + +/* + * 'mxmlSaveFile()' - Save an XML tree to a file. + * + * The callback argument specifies a function that returns a whitespace + * string or NULL before and after each element. If MXML_NO_CALLBACK + * is specified, whitespace will only be added before MXML_TEXT nodes + * with leading whitespace and before attribute names inside opening + * element tags. + */ + +int /* O - 0 on success, -1 on error. */ +mxmlSaveFile(mxml_node_t *node, /* I - Node to write */ + FILE *fp, /* I - File to write to */ + mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ +{ + int col; /* Final column */ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + /* + * Write the node... + */ + + if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global)) < 0) + return (-1); + + if (col > 0) + if (putc('\n', fp) < 0) + return (-1); + + /* + * Return 0 (success)... + */ + + return (0); +} + + +/* + * 'mxmlSaveString()' - Save an XML node tree to a string. + * + * This function returns the total number of bytes that would be + * required for the string but only copies (bufsize - 1) characters + * into the specified buffer. + * + * The callback argument specifies a function that returns a whitespace + * string or NULL before and after each element. If MXML_NO_CALLBACK + * is specified, whitespace will only be added before MXML_TEXT nodes + * with leading whitespace and before attribute names inside opening + * element tags. + */ + +int /* O - Size of string */ +mxmlSaveString(mxml_node_t *node, /* I - Node to write */ + char *buffer, /* I - String buffer */ + int bufsize, /* I - Size of string buffer */ + mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */ +{ + int col; /* Final column */ + char *ptr[2]; /* Pointers for putc_cb */ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + /* + * Write the node... + */ + + ptr[0] = buffer; + ptr[1] = buffer + bufsize; + + if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0) + return (-1); + + if (col > 0) + mxml_string_putc('\n', ptr); + + /* + * Nul-terminate the buffer... + */ + + if (ptr[0] >= ptr[1]) + buffer[bufsize - 1] = '\0'; + else + ptr[0][0] = '\0'; + + /* + * Return the number of characters... + */ + + return (ptr[0] - buffer); +} + + +/* + * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree + * using a SAX callback. + * + * The nodes in the specified file are added to the specified top node. + * If no top node is provided, the XML file MUST be well-formed with a + * single parent node like for the entire file. The callback + * function returns the value type that should be used for child nodes. + * If MXML_NO_CALLBACK is specified then all child nodes will be either + * MXML_ELEMENT or MXML_TEXT nodes. + * + * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, + * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading + * child nodes of the specified type. + * + * The SAX callback must call mxmlRetain() for any nodes that need to + * be kept for later use. Otherwise, nodes are deleted when the parent + * node is closed or after each data, comment, CDATA, or directive node. + * + * @since Mini-XML 2.3@ + */ + +mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */ + int fd, /* I - File descriptor to read from */ + mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ + mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ + void *sax_data) /* I - SAX user data */ +{ + _mxml_fdbuf_t buf; /* File descriptor buffer */ + + + /* + * Initialize the file descriptor buffer... + */ + + buf.fd = fd; + buf.current = buf.buffer; + buf.end = buf.buffer; + + /* + * Read the XML data... + */ + + return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data)); +} + + +/* + * 'mxmlSAXLoadFile()' - Load a file into an XML node tree + * using a SAX callback. + * + * The nodes in the specified file are added to the specified top node. + * If no top node is provided, the XML file MUST be well-formed with a + * single parent node like for the entire file. The callback + * function returns the value type that should be used for child nodes. + * If MXML_NO_CALLBACK is specified then all child nodes will be either + * MXML_ELEMENT or MXML_TEXT nodes. + * + * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, + * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading + * child nodes of the specified type. + * + * The SAX callback must call mxmlRetain() for any nodes that need to + * be kept for later use. Otherwise, nodes are deleted when the parent + * node is closed or after each data, comment, CDATA, or directive node. + * + * @since Mini-XML 2.3@ + */ + +mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxmlSAXLoadFile( + mxml_node_t *top, /* I - Top node */ + FILE *fp, /* I - File to read from */ + mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ + mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ + void *sax_data) /* I - SAX user data */ +{ + /* + * Read the XML data... + */ + + return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data)); +} + + +/* + * 'mxmlSAXLoadString()' - Load a string into an XML node tree + * using a SAX callback. + * + * The nodes in the specified string are added to the specified top node. + * If no top node is provided, the XML string MUST be well-formed with a + * single parent node like for the entire string. The callback + * function returns the value type that should be used for child nodes. + * If MXML_NO_CALLBACK is specified then all child nodes will be either + * MXML_ELEMENT or MXML_TEXT nodes. + * + * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, + * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading + * child nodes of the specified type. + * + * The SAX callback must call mxmlRetain() for any nodes that need to + * be kept for later use. Otherwise, nodes are deleted when the parent + * node is closed or after each data, comment, CDATA, or directive node. + * + * @since Mini-XML 2.3@ + */ + +mxml_node_t * /* O - First node or NULL if the string has errors. */ +mxmlSAXLoadString( + mxml_node_t *top, /* I - Top node */ + const char *s, /* I - String to load */ + mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ + mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ + void *sax_data) /* I - SAX user data */ +{ + /* + * Read the XML data... + */ + + return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data)); +} + + +/* + * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data. + * + * The load function accepts a node pointer and a data string and must + * return 0 on success and non-zero on error. + * + * The save function accepts a node pointer and must return a malloc'd + * string on success and NULL on error. + * + */ + +void +mxmlSetCustomHandlers( + mxml_custom_load_cb_t load, /* I - Load function */ + mxml_custom_save_cb_t save) /* I - Save function */ +{ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + global->custom_load_cb = load; + global->custom_save_cb = save; +} + + +/* + * 'mxmlSetErrorCallback()' - Set the error message callback. + */ + +void +mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */ +{ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + global->error_cb = cb; +} + + +/* + * 'mxmlSetWrapMargin()' - Set the wrap margin when saving XML data. + * + * Wrapping is disabled when "column" is 0. + * + * @since Mini-XML 2.3@ + */ + +void +mxmlSetWrapMargin(int column) /* I - Column for wrapping, 0 to disable wrapping */ +{ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + global->wrap = column; +} + + +/* + * 'mxml_add_char()' - Add a character to a buffer, expanding as needed. + */ + +static int /* O - 0 on success, -1 on error */ +mxml_add_char(int ch, /* I - Character to add */ + char **bufptr, /* IO - Current position in buffer */ + char **buffer, /* IO - Current buffer */ + int *bufsize) /* IO - Current buffer size */ +{ + char *newbuffer; /* New buffer value */ + + + if (*bufptr >= (*buffer + *bufsize - 4)) + { + /* + * Increase the size of the buffer... + */ + + if (*bufsize < 1024) + (*bufsize) *= 2; + else + (*bufsize) += 1024; + + if ((newbuffer = realloc(*buffer, *bufsize)) == NULL) + { + free(*buffer); + + mxml_error("Unable to expand string buffer to %d bytes!", *bufsize); + + return (-1); + } + + *bufptr = newbuffer + (*bufptr - *buffer); + *buffer = newbuffer; + } + + if (ch < 0x80) + { + /* + * Single byte ASCII... + */ + + *(*bufptr)++ = ch; + } + else if (ch < 0x800) + { + /* + * Two-byte UTF-8... + */ + + *(*bufptr)++ = 0xc0 | (ch >> 6); + *(*bufptr)++ = 0x80 | (ch & 0x3f); + } + else if (ch < 0x10000) + { + /* + * Three-byte UTF-8... + */ + + *(*bufptr)++ = 0xe0 | (ch >> 12); + *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f); + *(*bufptr)++ = 0x80 | (ch & 0x3f); + } + else + { + /* + * Four-byte UTF-8... + */ + + *(*bufptr)++ = 0xf0 | (ch >> 18); + *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f); + *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f); + *(*bufptr)++ = 0x80 | (ch & 0x3f); + } + + return (0); +} + + +/* + * 'mxml_fd_getc()' - Read a character from a file descriptor. + */ + +static int /* O - Character or EOF */ +mxml_fd_getc(void *p, /* I - File descriptor buffer */ + int *encoding) /* IO - Encoding */ +{ + _mxml_fdbuf_t *buf; /* File descriptor buffer */ + int ch, /* Current character */ + temp; /* Temporary character */ + + + /* + * Grab the next character in the buffer... + */ + + buf = (_mxml_fdbuf_t *)p; + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + ch = *(buf->current)++; + + switch (*encoding) + { + case ENCODE_UTF8 : + /* + * Got a UTF-8 character; convert UTF-8 to Unicode and return... + */ + + if (!(ch & 0x80)) + { +#if DEBUG > 1 + printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + + return (ch); + } + else if (ch == 0xfe) + { + /* + * UTF-16 big-endian BOM? + */ + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + ch = *(buf->current)++; + + if (ch != 0xff) + return (EOF); + + *encoding = ENCODE_UTF16BE; + + return (mxml_fd_getc(p, encoding)); + } + else if (ch == 0xff) + { + /* + * UTF-16 little-endian BOM? + */ + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + ch = *(buf->current)++; + + if (ch != 0xfe) + return (EOF); + + *encoding = ENCODE_UTF16LE; + + return (mxml_fd_getc(p, encoding)); + } + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two-byte value... + */ + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + if ((temp & 0xc0) != 0x80) + return (EOF); + + ch = ((ch & 0x1f) << 6) | (temp & 0x3f); + + if (ch < 0x80) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three-byte value... + */ + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + if ((temp & 0xc0) != 0x80) + return (EOF); + + ch = ((ch & 0x0f) << 6) | (temp & 0x3f); + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + if ((temp & 0xc0) != 0x80) + return (EOF); + + ch = (ch << 6) | (temp & 0x3f); + + if (ch < 0x800) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + + /* + * Ignore (strip) Byte Order Mark (BOM)... + */ + + if (ch == 0xfeff) + return (mxml_fd_getc(p, encoding)); + } + else if ((ch & 0xf8) == 0xf0) + { + /* + * Four-byte value... + */ + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + if ((temp & 0xc0) != 0x80) + return (EOF); + + ch = ((ch & 0x07) << 6) | (temp & 0x3f); + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + if ((temp & 0xc0) != 0x80) + return (EOF); + + ch = (ch << 6) | (temp & 0x3f); + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + if ((temp & 0xc0) != 0x80) + return (EOF); + + ch = (ch << 6) | (temp & 0x3f); + + if (ch < 0x10000) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else + return (EOF); + break; + + case ENCODE_UTF16BE : + /* + * Read UTF-16 big-endian char... + */ + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + ch = (ch << 8) | temp; + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + else if (ch >= 0xd800 && ch <= 0xdbff) + { + /* + * Multi-word UTF-16 char... + */ + + int lch; + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + lch = *(buf->current)++; + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + lch = (lch << 8) | temp; + + if (lch < 0xdc00 || lch >= 0xdfff) + return (EOF); + + ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; + } + break; + + case ENCODE_UTF16LE : + /* + * Read UTF-16 little-endian char... + */ + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + ch |= (temp << 8); + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + else if (ch >= 0xd800 && ch <= 0xdbff) + { + /* + * Multi-word UTF-16 char... + */ + + int lch; + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + lch = *(buf->current)++; + + if (buf->current >= buf->end) + if (mxml_fd_read(buf) < 0) + return (EOF); + + temp = *(buf->current)++; + + lch |= (temp << 8); + + if (lch < 0xdc00 || lch >= 0xdfff) + return (EOF); + + ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; + } + break; + } + +#if DEBUG > 1 + printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); +} + + +/* + * 'mxml_fd_putc()' - Write a character to a file descriptor. + */ + +static int /* O - 0 on success, -1 on error */ +mxml_fd_putc(int ch, /* I - Character */ + void *p) /* I - File descriptor buffer */ +{ + _mxml_fdbuf_t *buf; /* File descriptor buffer */ + + + /* + * Flush the write buffer as needed... + */ + + buf = (_mxml_fdbuf_t *)p; + + if (buf->current >= buf->end) + if (mxml_fd_write(buf) < 0) + return (-1); + + *(buf->current)++ = ch; + + /* + * Return successfully... + */ + + return (0); +} + + +/* + * 'mxml_fd_read()' - Read a buffer of data from a file descriptor. + */ + +static int /* O - 0 on success, -1 on error */ +mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */ +{ + int bytes; /* Bytes read... */ + + + /* + * Range check input... + */ + + if (!buf) + return (-1); + + /* + * Read from the file descriptor... + */ + + while ((bytes = read(buf->fd, buf->buffer, sizeof(buf->buffer))) < 0) +#ifdef EINTR + if (errno != EAGAIN && errno != EINTR) +#else + if (errno != EAGAIN) +#endif /* EINTR */ + return (-1); + + if (bytes == 0) + return (-1); + + /* + * Update the pointers and return success... + */ + + buf->current = buf->buffer; + buf->end = buf->buffer + bytes; + + return (0); +} + + +/* + * 'mxml_fd_write()' - Write a buffer of data to a file descriptor. + */ + +static int /* O - 0 on success, -1 on error */ +mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */ +{ + int bytes; /* Bytes written */ + unsigned char *ptr; /* Pointer into buffer */ + + + /* + * Range check... + */ + + if (!buf) + return (-1); + + /* + * Return 0 if there is nothing to write... + */ + + if (buf->current == buf->buffer) + return (0); + + /* + * Loop until we have written everything... + */ + + for (ptr = buf->buffer; ptr < buf->current; ptr += bytes) + if ((bytes = write(buf->fd, ptr, buf->current - ptr)) < 0) + return (-1); + + /* + * All done, reset pointers and return success... + */ + + buf->current = buf->buffer; + + return (0); +} + + +/* + * 'mxml_file_getc()' - Get a character from a file. + */ + +static int /* O - Character or EOF */ +mxml_file_getc(void *p, /* I - Pointer to file */ + int *encoding) /* IO - Encoding */ +{ + int ch, /* Character from file */ + temp; /* Temporary character */ + FILE *fp; /* Pointer to file */ + + + /* + * Read a character from the file and see if it is EOF or ASCII... + */ + + fp = (FILE *)p; + ch = getc(fp); + + if (ch == EOF) + return (EOF); + + switch (*encoding) + { + case ENCODE_UTF8 : + /* + * Got a UTF-8 character; convert UTF-8 to Unicode and return... + */ + + if (!(ch & 0x80)) + { + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + +#if DEBUG > 1 + printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); + } + else if (ch == 0xfe) + { + /* + * UTF-16 big-endian BOM? + */ + + ch = getc(fp); + if (ch != 0xff) + return (EOF); + + *encoding = ENCODE_UTF16BE; + + return (mxml_file_getc(p, encoding)); + } + else if (ch == 0xff) + { + /* + * UTF-16 little-endian BOM? + */ + + ch = getc(fp); + if (ch != 0xfe) + return (EOF); + + *encoding = ENCODE_UTF16LE; + + return (mxml_file_getc(p, encoding)); + } + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two-byte value... + */ + + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); + + ch = ((ch & 0x1f) << 6) | (temp & 0x3f); + + if (ch < 0x80) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three-byte value... + */ + + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); + + ch = ((ch & 0x0f) << 6) | (temp & 0x3f); + + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); + + ch = (ch << 6) | (temp & 0x3f); + + if (ch < 0x800) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + + /* + * Ignore (strip) Byte Order Mark (BOM)... + */ + + if (ch == 0xfeff) + return (mxml_file_getc(p, encoding)); + } + else if ((ch & 0xf8) == 0xf0) + { + /* + * Four-byte value... + */ + + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); + + ch = ((ch & 0x07) << 6) | (temp & 0x3f); + + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); + + ch = (ch << 6) | (temp & 0x3f); + + if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80) + return (EOF); + + ch = (ch << 6) | (temp & 0x3f); + + if (ch < 0x10000) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + } + else + return (EOF); + break; + + case ENCODE_UTF16BE : + /* + * Read UTF-16 big-endian char... + */ + + ch = (ch << 8) | getc(fp); + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + else if (ch >= 0xd800 && ch <= 0xdbff) + { + /* + * Multi-word UTF-16 char... + */ + + int lch = (getc(fp) << 8) | getc(fp); + + if (lch < 0xdc00 || lch >= 0xdfff) + return (EOF); + + ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; + } + break; + + case ENCODE_UTF16LE : + /* + * Read UTF-16 little-endian char... + */ + + ch |= (getc(fp) << 8); + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + else if (ch >= 0xd800 && ch <= 0xdbff) + { + /* + * Multi-word UTF-16 char... + */ + + int lch = getc(fp) | (getc(fp) << 8); + + if (lch < 0xdc00 || lch >= 0xdfff) + return (EOF); + + ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; + } + break; + } + +#if DEBUG > 1 + printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); +} + + +/* + * 'mxml_file_putc()' - Write a character to a file. + */ + +static int /* O - 0 on success, -1 on failure */ +mxml_file_putc(int ch, /* I - Character to write */ + void *p) /* I - Pointer to file */ +{ + return (putc(ch, (FILE *)p) == EOF ? -1 : 0); +} + + +/* + * 'mxml_get_entity()' - Get the character corresponding to an entity... + */ + +static int /* O - Character value or EOF on error */ +mxml_get_entity(mxml_node_t *parent, /* I - Parent node */ + void *p, /* I - Pointer to source */ + int *encoding, /* IO - Character encoding */ + int (*getc_cb)(void *, int *)) + /* I - Get character function */ +{ + int ch; /* Current character */ + char entity[64], /* Entity string */ + *entptr; /* Pointer into entity */ + + + entptr = entity; + + while ((ch = (*getc_cb)(p, encoding)) != EOF) + if (ch > 126 || (!isalnum(ch) && ch != '#')) + break; + else if (entptr < (entity + sizeof(entity) - 1)) + *entptr++ = ch; + else + { + mxml_error("Entity name too long under parent <%s>!", + parent ? parent->value.element.name : "null"); + break; + } + + *entptr = '\0'; + + if (ch != ';') + { + mxml_error("Character entity \"%s\" not terminated under parent <%s>!", + entity, parent ? parent->value.element.name : "null"); + return (EOF); + } + + if (entity[0] == '#') + { + if (entity[1] == 'x') + ch = strtol(entity + 2, NULL, 16); + else + ch = strtol(entity + 1, NULL, 10); + } + else if ((ch = mxmlEntityGetValue(entity)) < 0) + mxml_error("Entity name \"%s;\" not supported under parent <%s>!", + entity, parent ? parent->value.element.name : "null"); + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x under parent <%s> not allowed by XML standard!", + ch, parent ? parent->value.element.name : "null"); + return (EOF); + } + + return (ch); +} + + +/* + * 'mxml_load_data()' - Load data into an XML node tree. + */ + +static mxml_node_t * /* O - First node or NULL if the file could not be read. */ +mxml_load_data( + mxml_node_t *top, /* I - Top node */ + void *p, /* I - Pointer to data */ + mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ + _mxml_getc_cb_t getc_cb, /* I - Read function */ + mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ + void *sax_data) /* I - SAX user data */ +{ + mxml_node_t *node, /* Current node */ + *first, /* First node added */ + *parent; /* Current parent node */ + int ch, /* Character from file */ + whitespace; /* Non-zero if whitespace seen */ + char *buffer, /* String buffer */ + *bufptr; /* Pointer into buffer */ + int bufsize; /* Size of buffer */ + mxml_type_t type; /* Current node type */ + int encoding; /* Character encoding */ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + static const char * const types[] = /* Type strings... */ + { + "MXML_ELEMENT", /* XML element with attributes */ + "MXML_INTEGER", /* Integer value */ + "MXML_OPAQUE", /* Opaque string */ + "MXML_REAL", /* Real value */ + "MXML_TEXT", /* Text fragment */ + "MXML_CUSTOM" /* Custom data */ + }; + + + /* + * Read elements and other nodes from the file... + */ + + if ((buffer = malloc(64)) == NULL) + { + mxml_error("Unable to allocate string buffer!"); + return (NULL); + } + + bufsize = 64; + bufptr = buffer; + parent = top; + first = NULL; + whitespace = 0; + encoding = ENCODE_UTF8; + + if (cb && parent) + type = (*cb)(parent); + else + type = MXML_TEXT; + + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { + if ((ch == '<' || + (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) && + bufptr > buffer) + { + /* + * Add a new value node... + */ + + *bufptr = '\0'; + + switch (type) + { + case MXML_INTEGER : + node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0)); + break; + + case MXML_OPAQUE : + node = mxmlNewOpaque(parent, buffer); + break; + + case MXML_REAL : + node = mxmlNewReal(parent, strtod(buffer, &bufptr)); + break; + + case MXML_TEXT : + node = mxmlNewText(parent, whitespace, buffer); + break; + + case MXML_CUSTOM : + if (global->custom_load_cb) + { + /* + * Use the callback to fill in the custom data... + */ + + node = mxmlNewCustom(parent, NULL, NULL); + + if ((*global->custom_load_cb)(node, buffer)) + { + mxml_error("Bad custom value '%s' in parent <%s>!", + buffer, parent ? parent->value.element.name : "null"); + mxmlDelete(node); + node = NULL; + } + break; + } + + default : /* Ignore... */ + node = NULL; + break; + } + + if (*bufptr) + { + /* + * Bad integer/real number value... + */ + + mxml_error("Bad %s value '%s' in parent <%s>!", + type == MXML_INTEGER ? "integer" : "real", buffer, + parent ? parent->value.element.name : "null"); + break; + } + + bufptr = buffer; + whitespace = mxml_isspace(ch) && type == MXML_TEXT; + + if (!node && type != MXML_IGNORE) + { + /* + * Print error and return... + */ + + mxml_error("Unable to add value node of type %s to parent <%s>!", + types[type], parent ? parent->value.element.name : "null"); + goto error; + } + + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_DATA, sax_data); + + if (!mxmlRelease(node)) + node = NULL; + } + + if (!first && node) + first = node; + } + else if (mxml_isspace(ch) && type == MXML_TEXT) + whitespace = 1; + + /* + * Add lone whitespace node if we have an element and existing + * whitespace... + */ + + if (ch == '<' && whitespace && type == MXML_TEXT) + { + node = mxmlNewText(parent, whitespace, ""); + + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_DATA, sax_data); + + if (!mxmlRelease(node)) + node = NULL; + } + + if (!first && node) + first = node; + + whitespace = 0; + } + + if (ch == '<') + { + /* + * Start of open/close tag... + */ + + bufptr = buffer; + + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer)) + break; + else if (ch == '<') + { + mxml_error("Bare < in element!"); + goto error; + } + else if (ch == '&') + { + if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF) + goto error; + + if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + else if (((bufptr - buffer) == 1 && buffer[0] == '?') || + ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) || + ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8))) + break; + + *bufptr = '\0'; + + if (!strcmp(buffer, "!--")) + { + /* + * Gather rest of comment... + */ + + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { + if (ch == '>' && bufptr > (buffer + 4) && + bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-') + break; + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + + /* + * Error out if we didn't get the whole comment... + */ + + if (ch != '>') + { + /* + * Print error and return... + */ + + mxml_error("Early EOF in comment node!"); + goto error; + } + + + /* + * Otherwise add this as an element under the current parent... + */ + + *bufptr = '\0'; + + if (!parent && first) + { + /* + * There can only be one root element! + */ + + mxml_error("<%s> cannot be a second root node after <%s>", + buffer, first->value.element.name); + goto error; + } + + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Just print error for now... + */ + + mxml_error("Unable to add comment node to parent <%s>!", + parent ? parent->value.element.name : "null"); + break; + } + + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_COMMENT, sax_data); + + if (!mxmlRelease(node)) + node = NULL; + } + + if (node && !first) + first = node; + } + else if (!strcmp(buffer, "![CDATA[")) + { + /* + * Gather CDATA section... + */ + + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { + if (ch == '>' && !strncmp(bufptr - 2, "]]", 2)) + break; + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + + /* + * Error out if we didn't get the whole comment... + */ + + if (ch != '>') + { + /* + * Print error and return... + */ + + mxml_error("Early EOF in CDATA node!"); + goto error; + } + + + /* + * Otherwise add this as an element under the current parent... + */ + + *bufptr = '\0'; + + if (!parent && first) + { + /* + * There can only be one root element! + */ + + mxml_error("<%s> cannot be a second root node after <%s>", + buffer, first->value.element.name); + goto error; + } + + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Print error and return... + */ + + mxml_error("Unable to add CDATA node to parent <%s>!", + parent ? parent->value.element.name : "null"); + goto error; + } + + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_CDATA, sax_data); + + if (!mxmlRelease(node)) + node = NULL; + } + + if (node && !first) + first = node; + } + else if (buffer[0] == '?') + { + /* + * Gather rest of processing instruction... + */ + + while ((ch = (*getc_cb)(p, &encoding)) != EOF) + { + if (ch == '>' && bufptr > buffer && bufptr[-1] == '?') + break; + else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + + /* + * Error out if we didn't get the whole processing instruction... + */ + + if (ch != '>') + { + /* + * Print error and return... + */ + + mxml_error("Early EOF in processing instruction node!"); + goto error; + } + + /* + * Otherwise add this as an element under the current parent... + */ + + *bufptr = '\0'; + + if (!parent && first) + { + /* + * There can only be one root element! + */ + + mxml_error("<%s> cannot be a second root node after <%s>", + buffer, first->value.element.name); + goto error; + } + + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Print error and return... + */ + + mxml_error("Unable to add processing instruction node to parent <%s>!", + parent ? parent->value.element.name : "null"); + goto error; + } + + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data); + + if (!mxmlRelease(node)) + node = NULL; + } + + if (node) + { + if (!first) + first = node; + + if (!parent) + { + parent = node; + + if (cb) + type = (*cb)(parent); + } + } + } + else if (buffer[0] == '!') + { + /* + * Gather rest of declaration... + */ + + do + { + if (ch == '>') + break; + else + { + if (ch == '&') + if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF) + goto error; + + if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + } + while ((ch = (*getc_cb)(p, &encoding)) != EOF); + + /* + * Error out if we didn't get the whole declaration... + */ + + if (ch != '>') + { + /* + * Print error and return... + */ + + mxml_error("Early EOF in declaration node!"); + goto error; + } + + /* + * Otherwise add this as an element under the current parent... + */ + + *bufptr = '\0'; + + if (!parent && first) + { + /* + * There can only be one root element! + */ + + mxml_error("<%s> cannot be a second root node after <%s>", + buffer, first->value.element.name); + goto error; + } + + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Print error and return... + */ + + mxml_error("Unable to add declaration node to parent <%s>!", + parent ? parent->value.element.name : "null"); + goto error; + } + + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data); + + if (!mxmlRelease(node)) + node = NULL; + } + + if (node) + { + if (!first) + first = node; + + if (!parent) + { + parent = node; + + if (cb) + type = (*cb)(parent); + } + } + } + else if (buffer[0] == '/') + { + /* + * Handle close tag... + */ + + if (!parent || strcmp(buffer + 1, parent->value.element.name)) + { + /* + * Close tag doesn't match tree; print an error for now... + */ + + mxml_error("Mismatched close tag <%s> under parent <%s>!", + buffer, parent ? parent->value.element.name : "(null)"); + goto error; + } + + /* + * Keep reading until we see >... + */ + + while (ch != '>' && ch != EOF) + ch = (*getc_cb)(p, &encoding); + + node = parent; + parent = parent->parent; + + if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data); + + mxmlRelease(node); + } + + /* + * Ascend into the parent and set the value type as needed... + */ + + if (cb && parent) + type = (*cb)(parent); + } + else + { + /* + * Handle open tag... + */ + + if (!parent && first) + { + /* + * There can only be one root element! + */ + + mxml_error("<%s> cannot be a second root node after <%s>", + buffer, first->value.element.name); + goto error; + } + + if ((node = mxmlNewElement(parent, buffer)) == NULL) + { + /* + * Just print error for now... + */ + + mxml_error("Unable to add element node to parent <%s>!", + parent ? parent->value.element.name : "null"); + goto error; + } + + if (mxml_isspace(ch)) + { + if ((ch = mxml_parse_element(node, p, &encoding, getc_cb)) == EOF) + goto error; + } + else if (ch == '/') + { + if ((ch = (*getc_cb)(p, &encoding)) != '>') + { + mxml_error("Expected > but got '%c' instead for element <%s/>!", + ch, buffer); + mxmlDelete(node); + goto error; + } + + ch = '/'; + } + + if (sax_cb) + (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data); + + if (!first) + first = node; + + if (ch == EOF) + break; + + if (ch != '/') + { + /* + * Descend into this node, setting the value type as needed... + */ + + parent = node; + + if (cb && parent) + type = (*cb)(parent); + } + else if (sax_cb) + { + (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data); + + if (!mxmlRelease(node) && first == node) + first = NULL; + } + } + + bufptr = buffer; + } + else if (ch == '&') + { + /* + * Add character entity to current buffer... + */ + + if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF) + goto error; + + if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch)) + { + /* + * Add character to current buffer... + */ + + if (mxml_add_char(ch, &bufptr, &buffer, &bufsize)) + goto error; + } + } + + /* + * Free the string buffer - we don't need it anymore... + */ + + free(buffer); + + /* + * Find the top element and return it... + */ + + if (parent) + { + node = parent; + + while (parent->parent != top && parent->parent) + parent = parent->parent; + + if (node != parent) + { + mxml_error("Missing close tag under parent <%s>!", + node->value.element.name, + node->parent ? node->parent->value.element.name : "(null)"); + + mxmlDelete(first); + + return (NULL); + } + } + + if (parent) + return (parent); + else + return (first); + + /* + * Common error return... + */ + +error: + + mxmlDelete(first); + + free(buffer); + + return (NULL); +} + + +/* + * 'mxml_parse_element()' - Parse an element for any attributes... + */ + +static int /* O - Terminating character */ +mxml_parse_element( + mxml_node_t *node, /* I - Element node */ + void *p, /* I - Data to read from */ + int *encoding, /* IO - Encoding */ + _mxml_getc_cb_t getc_cb) /* I - Data callback */ +{ + int ch, /* Current character in file */ + quote; /* Quoting character */ + char *name, /* Attribute name */ + *value, /* Attribute value */ + *ptr; /* Pointer into name/value */ + int namesize, /* Size of name string */ + valsize; /* Size of value string */ + + + /* + * Initialize the name and value buffers... + */ + + if ((name = malloc(64)) == NULL) + { + mxml_error("Unable to allocate memory for name!"); + return (EOF); + } + + namesize = 64; + + if ((value = malloc(64)) == NULL) + { + free(name); + mxml_error("Unable to allocate memory for value!"); + return (EOF); + } + + valsize = 64; + + /* + * Loop until we hit a >, /, ?, or EOF... + */ + + while ((ch = (*getc_cb)(p, encoding)) != EOF) + { +#if DEBUG > 1 + fprintf(stderr, "parse_element: ch='%c'\n", ch); +#endif /* DEBUG > 1 */ + + /* + * Skip leading whitespace... + */ + + if (mxml_isspace(ch)) + continue; + + /* + * Stop at /, ?, or >... + */ + + if (ch == '/' || ch == '?') + { + /* + * Grab the > character and print an error if it isn't there... + */ + + quote = (*getc_cb)(p, encoding); + + if (quote != '>') + { + mxml_error("Expected '>' after '%c' for element %s, but got '%c'!", + ch, node->value.element.name, quote); + goto error; + } + + break; + } + else if (ch == '<') + { + mxml_error("Bare < in element %s!", node->value.element.name); + goto error; + } + else if (ch == '>') + break; + + /* + * Read the attribute name... + */ + + name[0] = ch; + ptr = name + 1; + + if (ch == '\"' || ch == '\'') + { + /* + * Name is in quotes, so get a quoted string... + */ + + quote = ch; + + while ((ch = (*getc_cb)(p, encoding)) != EOF) + { + if (ch == '&') + if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) + goto error; + + if (mxml_add_char(ch, &ptr, &name, &namesize)) + goto error; + + if (ch == quote) + break; + } + } + else + { + /* + * Grab an normal, non-quoted name... + */ + + while ((ch = (*getc_cb)(p, encoding)) != EOF) + if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' || + ch == '?') + break; + else + { + if (ch == '&') + if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) + goto error; + + if (mxml_add_char(ch, &ptr, &name, &namesize)) + goto error; + } + } + + *ptr = '\0'; + + if (mxmlElementGetAttr(node, name)) + goto error; + + while (ch != EOF && mxml_isspace(ch)) + ch = (*getc_cb)(p, encoding); + + if (ch == '=') + { + /* + * Read the attribute value... + */ + + while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch)); + + if (ch == EOF) + { + mxml_error("Missing value for attribute '%s' in element %s!", + name, node->value.element.name); + goto error; + } + + if (ch == '\'' || ch == '\"') + { + /* + * Read quoted value... + */ + + quote = ch; + ptr = value; + + while ((ch = (*getc_cb)(p, encoding)) != EOF) + if (ch == quote) + break; + else + { + if (ch == '&') + if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) + goto error; + + if (mxml_add_char(ch, &ptr, &value, &valsize)) + goto error; + } + + *ptr = '\0'; + } + else + { + /* + * Read unquoted value... + */ + + value[0] = ch; + ptr = value + 1; + + while ((ch = (*getc_cb)(p, encoding)) != EOF) + if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>') + break; + else + { + if (ch == '&') + if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF) + goto error; + + if (mxml_add_char(ch, &ptr, &value, &valsize)) + goto error; + } + + *ptr = '\0'; + } + + /* + * Set the attribute with the given string value... + */ + + mxmlElementSetAttr(node, name, value); + } + else + { + mxml_error("Missing value for attribute '%s' in element %s!", + name, node->value.element.name); + goto error; + } + + /* + * Check the end character... + */ + + if (ch == '/' || ch == '?') + { + /* + * Grab the > character and print an error if it isn't there... + */ + + quote = (*getc_cb)(p, encoding); + + if (quote != '>') + { + mxml_error("Expected '>' after '%c' for element %s, but got '%c'!", + ch, node->value.element.name, quote); + ch = EOF; + } + + break; + } + else if (ch == '>') + break; + } + + /* + * Free the name and value buffers and return... + */ + + free(name); + free(value); + + return (ch); + + /* + * Common error return point... + */ + +error: + + free(name); + free(value); + + return (EOF); +} + + +/* + * 'mxml_string_getc()' - Get a character from a string. + */ + +static int /* O - Character or EOF */ +mxml_string_getc(void *p, /* I - Pointer to file */ + int *encoding) /* IO - Encoding */ +{ + int ch; /* Character */ + const char **s; /* Pointer to string pointer */ + + + s = (const char **)p; + + if ((ch = (*s)[0] & 255) != 0 || *encoding == ENCODE_UTF16LE) + { + /* + * Got character; convert UTF-8 to integer and return... + */ + + (*s)++; + + switch (*encoding) + { + case ENCODE_UTF8 : + if (!(ch & 0x80)) + { +#if DEBUG > 1 + printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + + return (ch); + } + else if (ch == 0xfe) + { + /* + * UTF-16 big-endian BOM? + */ + + if (((*s)[0] & 255) != 0xff) + return (EOF); + + *encoding = ENCODE_UTF16BE; + (*s)++; + + return (mxml_string_getc(p, encoding)); + } + else if (ch == 0xff) + { + /* + * UTF-16 little-endian BOM? + */ + + if (((*s)[0] & 255) != 0xfe) + return (EOF); + + *encoding = ENCODE_UTF16LE; + (*s)++; + + return (mxml_string_getc(p, encoding)); + } + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two-byte value... + */ + + if (((*s)[0] & 0xc0) != 0x80) + return (EOF); + + ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f); + + (*s)++; + + if (ch < 0x80) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + +#if DEBUG > 1 + printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three-byte value... + */ + + if (((*s)[0] & 0xc0) != 0x80 || + ((*s)[1] & 0xc0) != 0x80) + return (EOF); + + ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f); + + (*s) += 2; + + if (ch < 0x800) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + + /* + * Ignore (strip) Byte Order Mark (BOM)... + */ + + if (ch == 0xfeff) + return (mxml_string_getc(p, encoding)); + +#if DEBUG > 1 + printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); + } + else if ((ch & 0xf8) == 0xf0) + { + /* + * Four-byte value... + */ + + if (((*s)[0] & 0xc0) != 0x80 || + ((*s)[1] & 0xc0) != 0x80 || + ((*s)[2] & 0xc0) != 0x80) + return (EOF); + + ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) | + ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f); + + (*s) += 3; + + if (ch < 0x10000) + { + mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch); + return (EOF); + } + +#if DEBUG > 1 + printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); + } + else + return (EOF); + + case ENCODE_UTF16BE : + /* + * Read UTF-16 big-endian char... + */ + + ch = (ch << 8) | ((*s)[0] & 255); + (*s) ++; + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + else if (ch >= 0xd800 && ch <= 0xdbff) + { + /* + * Multi-word UTF-16 char... + */ + + int lch; /* Lower word */ + + + if (!(*s)[0]) + return (EOF); + + lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255); + (*s) += 2; + + if (lch < 0xdc00 || lch >= 0xdfff) + return (EOF); + + ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; + } + +#if DEBUG > 1 + printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); + + case ENCODE_UTF16LE : + /* + * Read UTF-16 little-endian char... + */ + + ch = ch | (((*s)[0] & 255) << 8); + + if (!ch) + { + (*s) --; + return (EOF); + } + + (*s) ++; + + if (mxml_bad_char(ch)) + { + mxml_error("Bad control character 0x%02x not allowed by XML standard!", + ch); + return (EOF); + } + else if (ch >= 0xd800 && ch <= 0xdbff) + { + /* + * Multi-word UTF-16 char... + */ + + int lch; /* Lower word */ + + + if (!(*s)[1]) + return (EOF); + + lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255); + (*s) += 2; + + if (lch < 0xdc00 || lch >= 0xdfff) + return (EOF); + + ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; + } + +#if DEBUG > 1 + printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch); +#endif /* DEBUG > 1 */ + + return (ch); + } + } + + return (EOF); +} + + +/* + * 'mxml_string_putc()' - Write a character to a string. + */ + +static int /* O - 0 on success, -1 on failure */ +mxml_string_putc(int ch, /* I - Character to write */ + void *p) /* I - Pointer to string pointers */ +{ + char **pp; /* Pointer to string pointers */ + + + pp = (char **)p; + + if (pp[0] < pp[1]) + pp[0][0] = ch; + + pp[0] ++; + + return (0); +} + + +/* + * 'mxml_write_name()' - Write a name string. + */ + +static int /* O - 0 on success, -1 on failure */ +mxml_write_name(const char *s, /* I - Name to write */ + void *p, /* I - Write pointer */ + int (*putc_cb)(int, void *)) + /* I - Write callback */ +{ + char quote; /* Quote character */ + const char *name; /* Entity name */ + + + if (*s == '\"' || *s == '\'') + { + /* + * Write a quoted name string... + */ + + if ((*putc_cb)(*s, p) < 0) + return (-1); + + quote = *s++; + + while (*s && *s != quote) + { + if ((name = mxmlEntityGetName(*s)) != NULL) + { + if ((*putc_cb)('&', p) < 0) + return (-1); + + while (*name) + { + if ((*putc_cb)(*name, p) < 0) + return (-1); + + name ++; + } + + if ((*putc_cb)(';', p) < 0) + return (-1); + } + else if ((*putc_cb)(*s, p) < 0) + return (-1); + + s ++; + } + + /* + * Write the end quote... + */ + + if ((*putc_cb)(quote, p) < 0) + return (-1); + } + else + { + /* + * Write a non-quoted name string... + */ + + while (*s) + { + if ((*putc_cb)(*s, p) < 0) + return (-1); + + s ++; + } + } + + return (0); +} + + +/* + * 'mxml_write_node()' - Save an XML node to a file. + */ + +static int /* O - Column or -1 on error */ +mxml_write_node(mxml_node_t *node, /* I - Node to write */ + void *p, /* I - File to write to */ + mxml_save_cb_t cb, /* I - Whitespace callback */ + int col, /* I - Current column */ + _mxml_putc_cb_t putc_cb,/* I - Output callback */ + _mxml_global_t *global)/* I - Global data */ +{ + int i, /* Looping var */ + width; /* Width of attr + value */ + mxml_attr_t *attr; /* Current attribute */ + char s[255]; /* Temporary string */ + + + /* + * Print the node value... + */ + + switch (node->type) + { + case MXML_ELEMENT : + col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb); + + if ((*putc_cb)('<', p) < 0) + return (-1); + if (node->value.element.name[0] == '?' || + !strncmp(node->value.element.name, "!--", 3) || + !strncmp(node->value.element.name, "![CDATA[", 8)) + { + /* + * Comments, CDATA, and processing instructions do not + * use character entities. + */ + + const char *ptr; /* Pointer into name */ + + + for (ptr = node->value.element.name; *ptr; ptr ++) + if ((*putc_cb)(*ptr, p) < 0) + return (-1); + } + else if (mxml_write_name(node->value.element.name, p, putc_cb) < 0) + return (-1); + + col += strlen(node->value.element.name) + 1; + + for (i = node->value.element.num_attrs, attr = node->value.element.attrs; + i > 0; + i --, attr ++) + { + width = strlen(attr->name); + + if (attr->value) + width += strlen(attr->value) + 3; + + if (global->wrap > 0 && (col + width) > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else + { + if ((*putc_cb)(' ', p) < 0) + return (-1); + + col ++; + } + + if (mxml_write_name(attr->name, p, putc_cb) < 0) + return (-1); + + if (attr->value) + { + if ((*putc_cb)('=', p) < 0) + return (-1); + if ((*putc_cb)('\"', p) < 0) + return (-1); + if (mxml_write_string(attr->value, p, putc_cb) < 0) + return (-1); + if ((*putc_cb)('\"', p) < 0) + return (-1); + } + + col += width; + } + + if (node->child) + { + /* + * Write children... + */ + + mxml_node_t *child; /* Current child */ + + + if ((*putc_cb)('>', p) < 0) + return (-1); + else + col ++; + + col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); + + for (child = node->child; child; child = child->next) + { + if ((col = mxml_write_node(child, p, cb, col, putc_cb, global)) < 0) + return (-1); + } + + /* + * The ? and ! elements are special-cases and have no end tags... + */ + + if (node->value.element.name[0] != '!' && + node->value.element.name[0] != '?') + { + col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb); + + if ((*putc_cb)('<', p) < 0) + return (-1); + if ((*putc_cb)('/', p) < 0) + return (-1); + if (mxml_write_string(node->value.element.name, p, putc_cb) < 0) + return (-1); + if ((*putc_cb)('>', p) < 0) + return (-1); + + col += strlen(node->value.element.name) + 3; + + col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb); + } + } + else if (node->value.element.name[0] == '!' || + node->value.element.name[0] == '?') + { + /* + * The ? and ! elements are special-cases... + */ + + if ((*putc_cb)('>', p) < 0) + return (-1); + else + col ++; + + col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); + } + else + { + if ((*putc_cb)(' ', p) < 0) + return (-1); + if ((*putc_cb)('/', p) < 0) + return (-1); + if ((*putc_cb)('>', p) < 0) + return (-1); + + col += 3; + + col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb); + } + break; + + case MXML_INTEGER : + if (node->prev) + { + if (global->wrap > 0 && col > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else if ((*putc_cb)(' ', p) < 0) + return (-1); + else + col ++; + } + + sprintf(s, "%d", node->value.integer); + if (mxml_write_string(s, p, putc_cb) < 0) + return (-1); + + col += strlen(s); + break; + + case MXML_OPAQUE : + if (mxml_write_string(node->value.opaque, p, putc_cb) < 0) + return (-1); + + col += strlen(node->value.opaque); + break; + + case MXML_REAL : + if (node->prev) + { + if (global->wrap > 0 && col > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else if ((*putc_cb)(' ', p) < 0) + return (-1); + else + col ++; + } + + sprintf(s, "%f", node->value.real); + if (mxml_write_string(s, p, putc_cb) < 0) + return (-1); + + col += strlen(s); + break; + + case MXML_TEXT : + if (node->value.text.whitespace && col > 0) + { + if (global->wrap > 0 && col > global->wrap) + { + if ((*putc_cb)('\n', p) < 0) + return (-1); + + col = 0; + } + else if ((*putc_cb)(' ', p) < 0) + return (-1); + else + col ++; + } + + if (mxml_write_string(node->value.text.string, p, putc_cb) < 0) + return (-1); + + col += strlen(node->value.text.string); + break; + + case MXML_CUSTOM : + if (global->custom_save_cb) + { + char *data; /* Custom data string */ + const char *newline; /* Last newline in string */ + + + if ((data = (*global->custom_save_cb)(node)) == NULL) + return (-1); + + if (mxml_write_string(data, p, putc_cb) < 0) + return (-1); + + if ((newline = strrchr(data, '\n')) == NULL) + col += strlen(data); + else + col = strlen(newline); + + free(data); + break; + } + + default : /* Should never happen */ + return (-1); + } + + return (col); +} + + +/* + * 'mxml_write_string()' - Write a string, escaping & and < as needed. + */ + +static int /* O - 0 on success, -1 on failure */ +mxml_write_string( + const char *s, /* I - String to write */ + void *p, /* I - Write pointer */ + _mxml_putc_cb_t putc_cb) /* I - Write callback */ +{ + const char *name; /* Entity name, if any */ + + + while (*s) + { + if ((name = mxmlEntityGetName(*s)) != NULL) + { + if ((*putc_cb)('&', p) < 0) + return (-1); + + while (*name) + { + if ((*putc_cb)(*name, p) < 0) + return (-1); + name ++; + } + + if ((*putc_cb)(';', p) < 0) + return (-1); + } + else if ((*putc_cb)(*s, p) < 0) + return (-1); + + s ++; + } + + return (0); +} + + +/* + * 'mxml_write_ws()' - Do whitespace callback... + */ + +static int /* O - New column */ +mxml_write_ws(mxml_node_t *node, /* I - Current node */ + void *p, /* I - Write pointer */ + mxml_save_cb_t cb, /* I - Callback function */ + int ws, /* I - Where value */ + int col, /* I - Current column */ + _mxml_putc_cb_t putc_cb) /* I - Write callback */ +{ + const char *s; /* Whitespace string */ + + + if (cb && (s = (*cb)(node, ws)) != NULL) + { + while (*s) + { + if ((*putc_cb)(*s, p) < 0) + return (-1); + else if (*s == '\n') + col = 0; + else if (*s == '\t') + { + col += MXML_TAB; + col = col - (col % MXML_TAB); + } + else + col ++; + + s ++; + } + } + + return (col); +} + + +/* + * End of "$Id: mxml-file.c 415 2010-09-19 07:29:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_ind.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_ind.c new file mode 100644 index 0000000000..b3274dfa93 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_ind.c @@ -0,0 +1,647 @@ +/* + * "$Id: mxml-index.c 408 2010-09-19 05:26:46Z mike $" + * + * Index support code for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxmlIndexDelete() - Delete an index. + * mxmlIndexEnum() - Return the next node in the index. + * mxmlIndexFind() - Find the next matching node. + * mxmlIndexNew() - Create a new index. + * mxmlIndexReset() - Reset the enumeration/find pointer in the index and + * return the first node in the index. + * index_compare() - Compare two nodes. + * index_find() - Compare a node with index values. + * index_sort() - Sort the nodes in the index... + */ + +/* + * Include necessary headers... + */ + +#include "config.h" +#include "mxml.h" + + +/* + * Sort functions... + */ + +static int index_compare(mxml_index_t *ind, mxml_node_t *first, + mxml_node_t *second); +static int index_find(mxml_index_t *ind, const char *element, + const char *value, mxml_node_t *node); +static void index_sort(mxml_index_t *ind, int left, int right); + + +/* + * 'mxmlIndexDelete()' - Delete an index. + */ + +void +mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */ +{ + /* + * Range check input.. + */ + + if (!ind) + return; + + /* + * Free memory... + */ + + if (ind->attr) + free(ind->attr); + + if (ind->alloc_nodes) + free(ind->nodes); + + free(ind); +} + + +/* + * 'mxmlIndexEnum()' - Return the next node in the index. + * + * Nodes are returned in the sorted order of the index. + */ + +mxml_node_t * /* O - Next node or NULL if there is none */ +mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */ +{ + /* + * Range check input... + */ + + if (!ind) + return (NULL); + + /* + * Return the next node... + */ + + if (ind->cur_node < ind->num_nodes) + return (ind->nodes[ind->cur_node ++]); + else + return (NULL); +} + + +/* + * 'mxmlIndexFind()' - Find the next matching node. + * + * You should call mxmlIndexReset() prior to using this function for + * the first time with a particular set of "element" and "value" + * strings. Passing NULL for both "element" and "value" is equivalent + * to calling mxmlIndexEnum(). + */ + +mxml_node_t * /* O - Node or NULL if none found */ +mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ + const char *element, /* I - Element name to find, if any */ + const char *value) /* I - Attribute value, if any */ +{ + int diff, /* Difference between names */ + current, /* Current entity in search */ + first, /* First entity in search */ + last; /* Last entity in search */ + + +#ifdef DEBUG + printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n", + ind, element ? element : "(null)", value ? value : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!ind || (!ind->attr && value)) + { +#ifdef DEBUG + puts(" returning NULL..."); + printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)"); +#endif /* DEBUG */ + + return (NULL); + } + + /* + * If both element and value are NULL, just enumerate the nodes in the + * index... + */ + + if (!element && !value) + return (mxmlIndexEnum(ind)); + + /* + * If there are no nodes in the index, return NULL... + */ + + if (!ind->num_nodes) + { +#ifdef DEBUG + puts(" returning NULL..."); + puts(" no nodes!"); +#endif /* DEBUG */ + + return (NULL); + } + + /* + * If cur_node == 0, then find the first matching node... + */ + + if (ind->cur_node == 0) + { + /* + * Find the first node using a modified binary search algorithm... + */ + + first = 0; + last = ind->num_nodes - 1; + +#ifdef DEBUG + printf(" find first time, num_nodes=%d...\n", ind->num_nodes); +#endif /* DEBUG */ + + while ((last - first) > 1) + { + current = (first + last) / 2; + +#ifdef DEBUG + printf(" first=%d, last=%d, current=%d\n", first, last, current); +#endif /* DEBUG */ + + if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0) + { + /* + * Found a match, move back to find the first... + */ + +#ifdef DEBUG + puts(" match!"); +#endif /* DEBUG */ + + while (current > 0 && + !index_find(ind, element, value, ind->nodes[current - 1])) + current --; + +#ifdef DEBUG + printf(" returning first match=%d\n", current); +#endif /* DEBUG */ + + /* + * Return the first match and save the index to the next... + */ + + ind->cur_node = current + 1; + + return (ind->nodes[current]); + } + else if (diff < 0) + last = current; + else + first = current; + +#ifdef DEBUG + printf(" diff=%d\n", diff); +#endif /* DEBUG */ + } + + /* + * If we get this far, then we found exactly 0 or 1 matches... + */ + + for (current = first; current <= last; current ++) + if (!index_find(ind, element, value, ind->nodes[current])) + { + /* + * Found exactly one (or possibly two) match... + */ + +#ifdef DEBUG + printf(" returning only match %d...\n", current); +#endif /* DEBUG */ + + ind->cur_node = current + 1; + + return (ind->nodes[current]); + } + + /* + * No matches... + */ + + ind->cur_node = ind->num_nodes; + +#ifdef DEBUG + puts(" returning NULL..."); +#endif /* DEBUG */ + + return (NULL); + } + else if (ind->cur_node < ind->num_nodes && + !index_find(ind, element, value, ind->nodes[ind->cur_node])) + { + /* + * Return the next matching node... + */ + +#ifdef DEBUG + printf(" returning next match %d...\n", ind->cur_node); +#endif /* DEBUG */ + + return (ind->nodes[ind->cur_node ++]); + } + + /* + * If we get this far, then we have no matches... + */ + + ind->cur_node = ind->num_nodes; + +#ifdef DEBUG + puts(" returning NULL..."); +#endif /* DEBUG */ + + return (NULL); +} + + +/* + * 'mxmlIndexNew()' - Create a new index. + * + * The index will contain all nodes that contain the named element and/or + * attribute. If both "element" and "attr" are NULL, then the index will + * contain a sorted list of the elements in the node tree. Nodes are + * sorted by element name and optionally by attribute value if the "attr" + * argument is not NULL. + */ + +mxml_index_t * /* O - New index */ +mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ + const char *element, /* I - Element to index or NULL for all */ + const char *attr) /* I - Attribute to index or NULL for none */ +{ + mxml_index_t *ind; /* New index */ + mxml_node_t *current, /* Current node in index */ + **temp; /* Temporary node pointer array */ + + + /* + * Range check input... + */ + +#ifdef DEBUG + printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n", + node, element ? element : "(null)", attr ? attr : "(null)"); +#endif /* DEBUG */ + + if (!node) + return (NULL); + + /* + * Create a new index... + */ + + if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL) + { + mxml_error("Unable to allocate %d bytes for index - %s", + sizeof(mxml_index_t), strerror(errno)); + return (NULL); + } + + if (attr) + ind->attr = strdup(attr); + + if (!element && !attr) + current = node; + else + current = mxmlFindElement(node, node, element, attr, NULL, MXML_DESCEND); + + while (current) + { + if (ind->num_nodes >= ind->alloc_nodes) + { + if (!ind->alloc_nodes) + temp = malloc(64 * sizeof(mxml_node_t *)); + else + temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *)); + + if (!temp) + { + /* + * Unable to allocate memory for the index, so abort... + */ + + mxml_error("Unable to allocate %d bytes for index: %s", + (ind->alloc_nodes + 64) * sizeof(mxml_node_t *), + strerror(errno)); + + mxmlIndexDelete(ind); + return (NULL); + } + + ind->nodes = temp; + ind->alloc_nodes += 64; + } + + ind->nodes[ind->num_nodes ++] = current; + + current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND); + } + + /* + * Sort nodes based upon the search criteria... + */ + +#ifdef DEBUG + { + int i; /* Looping var */ + + + printf("%d node(s) in index.\n\n", ind->num_nodes); + + if (attr) + { + printf("Node Address Element %s\n", attr); + puts("-------- -------- -------------- ------------------------------"); + + for (i = 0; i < ind->num_nodes; i ++) + printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name, + mxmlElementGetAttr(ind->nodes[i], attr)); + } + else + { + puts("Node Address Element"); + puts("-------- -------- --------------"); + + for (i = 0; i < ind->num_nodes; i ++) + printf("%8d %-8p %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name); + } + + putchar('\n'); + } +#endif /* DEBUG */ + + if (ind->num_nodes > 1) + index_sort(ind, 0, ind->num_nodes - 1); + +#ifdef DEBUG + { + int i; /* Looping var */ + + + puts("After sorting:\n"); + + if (attr) + { + printf("Node Address Element %s\n", attr); + puts("-------- -------- -------------- ------------------------------"); + + for (i = 0; i < ind->num_nodes; i ++) + printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name, + mxmlElementGetAttr(ind->nodes[i], attr)); + } + else + { + puts("Node Address Element"); + puts("-------- -------- --------------"); + + for (i = 0; i < ind->num_nodes; i ++) + printf("%8d %-8p %s\n", i, ind->nodes[i], + ind->nodes[i]->value.element.name); + } + + putchar('\n'); + } +#endif /* DEBUG */ + + /* + * Return the new index... + */ + + return (ind); +} + + +/* + * 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and + * return the first node in the index. + * + * This function should be called prior to using mxmlIndexEnum() or + * mxmlIndexFind() for the first time. + */ + +mxml_node_t * /* O - First node or NULL if there is none */ +mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */ +{ +#ifdef DEBUG + printf("mxmlIndexReset(ind=%p)\n", ind); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!ind) + return (NULL); + + /* + * Set the index to the first element... + */ + + ind->cur_node = 0; + + /* + * Return the first node... + */ + + if (ind->num_nodes) + return (ind->nodes[0]); + else + return (NULL); +} + + +/* + * 'index_compare()' - Compare two nodes. + */ + +static int /* O - Result of comparison */ +index_compare(mxml_index_t *ind, /* I - Index */ + mxml_node_t *first, /* I - First node */ + mxml_node_t *second) /* I - Second node */ +{ + int diff; /* Difference */ + + + /* + * Check the element name... + */ + + if ((diff = strcmp(first->value.element.name, + second->value.element.name)) != 0) + return (diff); + + /* + * Check the attribute value... + */ + + if (ind->attr) + { + if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr), + mxmlElementGetAttr(second, ind->attr))) != 0) + return (diff); + } + + /* + * No difference, return 0... + */ + + return (0); +} + + +/* + * 'index_find()' - Compare a node with index values. + */ + +static int /* O - Result of comparison */ +index_find(mxml_index_t *ind, /* I - Index */ + const char *element, /* I - Element name or NULL */ + const char *value, /* I - Attribute value or NULL */ + mxml_node_t *node) /* I - Node */ +{ + int diff; /* Difference */ + + + /* + * Check the element name... + */ + + if (element) + { + if ((diff = strcmp(element, node->value.element.name)) != 0) + return (diff); + } + + /* + * Check the attribute value... + */ + + if (value) + { + if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0) + return (diff); + } + + /* + * No difference, return 0... + */ + + return (0); +} + + +/* + * 'index_sort()' - Sort the nodes in the index... + * + * This function implements the classic quicksort algorithm... + */ + +static void +index_sort(mxml_index_t *ind, /* I - Index to sort */ + int left, /* I - Left node in partition */ + int right) /* I - Right node in partition */ +{ + mxml_node_t *pivot, /* Pivot node */ + *temp; /* Swap node */ + int templ, /* Temporary left node */ + tempr; /* Temporary right node */ + + + /* + * Loop until we have sorted all the way to the right... + */ + + do + { + /* + * Sort the pivot in the current partition... + */ + + pivot = ind->nodes[left]; + + for (templ = left, tempr = right; templ < tempr;) + { + /* + * Move left while left node <= pivot node... + */ + + while ((templ < right) && + index_compare(ind, ind->nodes[templ], pivot) <= 0) + templ ++; + + /* + * Move right while right node > pivot node... + */ + + while ((tempr > left) && + index_compare(ind, ind->nodes[tempr], pivot) > 0) + tempr --; + + /* + * Swap nodes if needed... + */ + + if (templ < tempr) + { + temp = ind->nodes[templ]; + ind->nodes[templ] = ind->nodes[tempr]; + ind->nodes[tempr] = temp; + } + } + + /* + * When we get here, the right (tempr) node is the new position for the + * pivot node... + */ + + if (index_compare(ind, pivot, ind->nodes[tempr]) > 0) + { + ind->nodes[left] = ind->nodes[tempr]; + ind->nodes[tempr] = pivot; + } + + /* + * Recursively sort the left partition as needed... + */ + + if (left < (tempr - 1)) + index_sort(ind, left, tempr - 1); + } + while (right > (left = tempr + 1)); +} + + +/* + * End of "$Id: mxml-index.c 408 2010-09-19 05:26:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_nod.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_nod.c new file mode 100644 index 0000000000..623ddba0c7 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_nod.c @@ -0,0 +1,778 @@ +/* + * "$Id: mxml-node.c 408 2010-09-19 05:26:46Z mike $" + * + * Node support code for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxmlAdd() - Add a node to a tree. + * mxmlDelete() - Delete a node and all of its children. + * mxmlNewCDATA() - Create a new CDATA node. + * mxmlNewCustom() - Create a new custom data node. + * mxmlNewElement() - Create a new element node. + * mxmlNewInteger() - Create a new integer node. + * mxmlNewOpaque() - Create a new opaque string. + * mxmlNewReal() - Create a new real number node. + * mxmlNewText() - Create a new text fragment node. + * mxmlNewTextf() - Create a new formatted text fragment node. + * mxmlNewXML() - Create a new XML document tree. + * mxmlRelease() - Release a node. + * mxmlRemove() - Remove a node from its parent. + * mxmlRetain() - Retain a node. + * mxml_new() - Create a new node. + */ + +/* + * Include necessary headers... + */ + +#include "config.h" +#include "mxml.h" + + +/* + * Local functions... + */ + +static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type); + + +/* + * 'mxmlAdd()' - Add a node to a tree. + * + * Adds the specified node to the parent. If the child argument is not + * NULL, puts the new node before or after the specified child depending + * on the value of the where argument. If the child argument is NULL, + * puts the new node at the beginning of the child list (MXML_ADD_BEFORE) + * or at the end of the child list (MXML_ADD_AFTER). The constant + * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer. + */ + +void +mxmlAdd(mxml_node_t *parent, /* I - Parent node */ + int where, /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */ + mxml_node_t *child, /* I - Child node for where or MXML_ADD_TO_PARENT */ + mxml_node_t *node) /* I - Node to add */ +{ +#ifdef DEBUG + fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent, + where, child, node); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!parent || !node) + return; + +#if DEBUG > 1 + fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent); + if (parent) + { + fprintf(stderr, " BEFORE: parent->child=%p\n", parent->child); + fprintf(stderr, " BEFORE: parent->last_child=%p\n", parent->last_child); + fprintf(stderr, " BEFORE: parent->prev=%p\n", parent->prev); + fprintf(stderr, " BEFORE: parent->next=%p\n", parent->next); + } +#endif /* DEBUG > 1 */ + + /* + * Remove the node from any existing parent... + */ + + if (node->parent) + mxmlRemove(node); + + /* + * Reset pointers... + */ + + node->parent = parent; + + switch (where) + { + case MXML_ADD_BEFORE : + if (!child || child == parent->child || child->parent != parent) + { + /* + * Insert as first node under parent... + */ + + node->next = parent->child; + + if (parent->child) + parent->child->prev = node; + else + parent->last_child = node; + + parent->child = node; + } + else + { + /* + * Insert node before this child... + */ + + node->next = child; + node->prev = child->prev; + + if (child->prev) + child->prev->next = node; + else + parent->child = node; + + child->prev = node; + } + break; + + case MXML_ADD_AFTER : + if (!child || child == parent->last_child || child->parent != parent) + { + /* + * Insert as last node under parent... + */ + + node->parent = parent; + node->prev = parent->last_child; + + if (parent->last_child) + parent->last_child->next = node; + else + parent->child = node; + + parent->last_child = node; + } + else + { + /* + * Insert node after this child... + */ + + node->prev = child; + node->next = child->next; + + if (child->next) + child->next->prev = node; + else + parent->last_child = node; + + child->next = node; + } + break; + } + +#if DEBUG > 1 + fprintf(stderr, " AFTER: node->parent=%p\n", node->parent); + if (parent) + { + fprintf(stderr, " AFTER: parent->child=%p\n", parent->child); + fprintf(stderr, " AFTER: parent->last_child=%p\n", parent->last_child); + fprintf(stderr, " AFTER: parent->prev=%p\n", parent->prev); + fprintf(stderr, " AFTER: parent->next=%p\n", parent->next); + } +#endif /* DEBUG > 1 */ +} + + +/* + * 'mxmlDelete()' - Delete a node and all of its children. + * + * If the specified node has a parent, this function first removes the + * node from its parent using the mxmlRemove() function. + */ + +void +mxmlDelete(mxml_node_t *node) /* I - Node to delete */ +{ + int i; /* Looping var */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlDelete(node=%p)\n", node); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!node) + return; + + /* + * Remove the node from its parent, if any... + */ + + mxmlRemove(node); + + /* + * Delete children... + */ + + while (node->child) + mxmlDelete(node->child); + + /* + * Now delete any node data... + */ + + switch (node->type) + { + case MXML_ELEMENT : + if (node->value.element.name) + free(node->value.element.name); + + if (node->value.element.num_attrs) + { + for (i = 0; i < node->value.element.num_attrs; i ++) + { + if (node->value.element.attrs[i].name) + free(node->value.element.attrs[i].name); + if (node->value.element.attrs[i].value) + free(node->value.element.attrs[i].value); + } + + free(node->value.element.attrs); + } + break; + case MXML_INTEGER : + /* Nothing to do */ + break; + case MXML_OPAQUE : + if (node->value.opaque) + free(node->value.opaque); + break; + case MXML_REAL : + /* Nothing to do */ + break; + case MXML_TEXT : + if (node->value.text.string) + free(node->value.text.string); + break; + case MXML_CUSTOM : + if (node->value.custom.data && + node->value.custom.destroy) + (*(node->value.custom.destroy))(node->value.custom.data); + break; + default : + break; + } + + /* + * Free this node... + */ + + free(node); +} + + +/* + * 'mxmlNewCDATA()' - Create a new CDATA node. + * + * The new CDATA node is added to the end of the specified parent's child + * list. The constant MXML_NO_PARENT can be used to specify that the new + * CDATA node has no parent. The data string must be nul-terminated and + * is copied into the new node. CDATA nodes use the MXML_ELEMENT type. + * + * @since Mini-XML 2.3@ + */ + +mxml_node_t * /* O - New node */ +mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + const char *data) /* I - Data string */ +{ + mxml_node_t *node; /* New node */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n", + parent, data ? data : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!data) + return (NULL); + + /* + * Create the node and set the name value... + */ + + if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL) + node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data); + + return (node); +} + + +/* + * 'mxmlNewCustom()' - Create a new custom data node. + * + * The new custom node is added to the end of the specified parent's child + * list. The constant MXML_NO_PARENT can be used to specify that the new + * element node has no parent. NULL can be passed when the data in the + * node is not dynamically allocated or is separately managed. + * + * @since Mini-XML 2.1@ + */ + +mxml_node_t * /* O - New node */ +mxmlNewCustom( + mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + void *data, /* I - Pointer to data */ + mxml_custom_destroy_cb_t destroy) /* I - Function to destroy data */ +{ + mxml_node_t *node; /* New node */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent, + data, destroy); +#endif /* DEBUG */ + + /* + * Create the node and set the value... + */ + + if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL) + { + node->value.custom.data = data; + node->value.custom.destroy = destroy; + } + + return (node); +} + + +/* + * 'mxmlNewElement()' - Create a new element node. + * + * The new element node is added to the end of the specified parent's child + * list. The constant MXML_NO_PARENT can be used to specify that the new + * element node has no parent. + */ + +mxml_node_t * /* O - New node */ +mxmlNewElement(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + const char *name) /* I - Name of element */ +{ + mxml_node_t *node; /* New node */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent, + name ? name : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!name) + return (NULL); + + /* + * Create the node and set the element name... + */ + + if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL) + node->value.element.name = strdup(name); + + return (node); +} + + +/* + * 'mxmlNewInteger()' - Create a new integer node. + * + * The new integer node is added to the end of the specified parent's child + * list. The constant MXML_NO_PARENT can be used to specify that the new + * integer node has no parent. + */ + +mxml_node_t * /* O - New node */ +mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + int integer) /* I - Integer value */ +{ + mxml_node_t *node; /* New node */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer); +#endif /* DEBUG */ + + /* + * Create the node and set the element name... + */ + + if ((node = mxml_new(parent, MXML_INTEGER)) != NULL) + node->value.integer = integer; + + return (node); +} + + +/* + * 'mxmlNewOpaque()' - Create a new opaque string. + * + * The new opaque node is added to the end of the specified parent's child + * list. The constant MXML_NO_PARENT can be used to specify that the new + * opaque node has no parent. The opaque string must be nul-terminated and + * is copied into the new node. + */ + +mxml_node_t * /* O - New node */ +mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + const char *opaque) /* I - Opaque string */ +{ + mxml_node_t *node; /* New node */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent, + opaque ? opaque : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!opaque) + return (NULL); + + /* + * Create the node and set the element name... + */ + + if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL) + node->value.opaque = strdup(opaque); + + return (node); +} + + +/* + * 'mxmlNewReal()' - Create a new real number node. + * + * The new real number node is added to the end of the specified parent's + * child list. The constant MXML_NO_PARENT can be used to specify that + * the new real number node has no parent. + */ + +mxml_node_t * /* O - New node */ +mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + double real) /* I - Real number value */ +{ + mxml_node_t *node; /* New node */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real); +#endif /* DEBUG */ + + /* + * Create the node and set the element name... + */ + + if ((node = mxml_new(parent, MXML_REAL)) != NULL) + node->value.real = real; + + return (node); +} + + +/* + * 'mxmlNewText()' - Create a new text fragment node. + * + * The new text node is added to the end of the specified parent's child + * list. The constant MXML_NO_PARENT can be used to specify that the new + * text node has no parent. The whitespace parameter is used to specify + * whether leading whitespace is present before the node. The text + * string must be nul-terminated and is copied into the new node. + */ + +mxml_node_t * /* O - New node */ +mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ + const char *string) /* I - String */ +{ + mxml_node_t *node; /* New node */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n", + parent, whitespace, string ? string : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!string) + return (NULL); + + /* + * Create the node and set the text value... + */ + + if ((node = mxml_new(parent, MXML_TEXT)) != NULL) + { + node->value.text.whitespace = whitespace; + node->value.text.string = strdup(string); + } + + return (node); +} + + +/* + * 'mxmlNewTextf()' - Create a new formatted text fragment node. + * + * The new text node is added to the end of the specified parent's child + * list. The constant MXML_NO_PARENT can be used to specify that the new + * text node has no parent. The whitespace parameter is used to specify + * whether leading whitespace is present before the node. The format + * string must be nul-terminated and is formatted into the new node. + */ + +mxml_node_t * /* O - New node */ +mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */ + int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ + const char *format, /* I - Printf-style frmat string */ + ...) /* I - Additional args as needed */ +{ + mxml_node_t *node; /* New node */ + va_list ap; /* Pointer to arguments */ + + +#ifdef DEBUG + fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n", + parent, whitespace, format ? format : "(null)"); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!format) + return (NULL); + + /* + * Create the node and set the text value... + */ + + if ((node = mxml_new(parent, MXML_TEXT)) != NULL) + { + va_start(ap, format); + + node->value.text.whitespace = whitespace; + node->value.text.string = _mxml_vstrdupf(format, ap); + + va_end(ap); + } + + return (node); +} + + +/* + * 'mxmlRemove()' - Remove a node from its parent. + * + * Does not free memory used by the node - use mxmlDelete() for that. + * This function does nothing if the node has no parent. + */ + +void +mxmlRemove(mxml_node_t *node) /* I - Node to remove */ +{ +#ifdef DEBUG + fprintf(stderr, "mxmlRemove(node=%p)\n", node); +#endif /* DEBUG */ + + /* + * Range check input... + */ + + if (!node || !node->parent) + return; + + /* + * Remove from parent... + */ + +#if DEBUG > 1 + fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent); + if (node->parent) + { + fprintf(stderr, " BEFORE: node->parent->child=%p\n", node->parent->child); + fprintf(stderr, " BEFORE: node->parent->last_child=%p\n", node->parent->last_child); + } + fprintf(stderr, " BEFORE: node->child=%p\n", node->child); + fprintf(stderr, " BEFORE: node->last_child=%p\n", node->last_child); + fprintf(stderr, " BEFORE: node->prev=%p\n", node->prev); + fprintf(stderr, " BEFORE: node->next=%p\n", node->next); +#endif /* DEBUG > 1 */ + + if (node->prev) + node->prev->next = node->next; + else + node->parent->child = node->next; + + if (node->next) + node->next->prev = node->prev; + else + node->parent->last_child = node->prev; + + node->parent = NULL; + node->prev = NULL; + node->next = NULL; + +#if DEBUG > 1 + fprintf(stderr, " AFTER: node->parent=%p\n", node->parent); + if (node->parent) + { + fprintf(stderr, " AFTER: node->parent->child=%p\n", node->parent->child); + fprintf(stderr, " AFTER: node->parent->last_child=%p\n", node->parent->last_child); + } + fprintf(stderr, " AFTER: node->child=%p\n", node->child); + fprintf(stderr, " AFTER: node->last_child=%p\n", node->last_child); + fprintf(stderr, " AFTER: node->prev=%p\n", node->prev); + fprintf(stderr, " AFTER: node->next=%p\n", node->next); +#endif /* DEBUG > 1 */ +} + + +/* + * 'mxmlNewXML()' - Create a new XML document tree. + * + * The "version" argument specifies the version number to put in the + * ?xml element node. If NULL, version 1.0 is assumed. + * + * @since Mini-XML 2.3@ + */ + +mxml_node_t * /* O - New ?xml node */ +mxmlNewXML(const char *version) /* I - Version number to use */ +{ + char element[1024]; /* Element text */ + + + snprintf(element, sizeof(element), "?xml version=\"%s\" encoding=\"utf-8\"?", + version ? version : "1.0"); + + return (mxmlNewElement(NULL, element)); +} + + +/* + * 'mxmlRelease()' - Release a node. + * + * When the reference count reaches zero, the node (and any children) + * is deleted via mxmlDelete(). + * + * @since Mini-XML 2.3@ + */ + +int /* O - New reference count */ +mxmlRelease(mxml_node_t *node) /* I - Node */ +{ + if (node) + { + if ((-- node->ref_count) <= 0) + { + mxmlDelete(node); + return (0); + } + else + return (node->ref_count); + } + else + return (-1); +} + + +/* + * 'mxmlRetain()' - Retain a node. + * + * @since Mini-XML 2.3@ + */ + +int /* O - New reference count */ +mxmlRetain(mxml_node_t *node) /* I - Node */ +{ + if (node) + return (++ node->ref_count); + else + return (-1); +} + + +/* + * 'mxml_new()' - Create a new node. + */ + +static mxml_node_t * /* O - New node */ +mxml_new(mxml_node_t *parent, /* I - Parent node */ + mxml_type_t type) /* I - Node type */ +{ + mxml_node_t *node; /* New node */ + + +#if DEBUG > 1 + fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type); +#endif /* DEBUG > 1 */ + + /* + * Allocate memory for the node... + */ + + if ((node = calloc(1, sizeof(mxml_node_t))) == NULL) + { +#if DEBUG > 1 + fputs(" returning NULL\n", stderr); +#endif /* DEBUG > 1 */ + + return (NULL); + } + +#if DEBUG > 1 + fprintf(stderr, " returning %p\n", node); +#endif /* DEBUG > 1 */ + + /* + * Set the node type... + */ + + node->type = type; + node->ref_count = 1; + + /* + * Add to the parent if present... + */ + + if (parent) + mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node); + + /* + * Return the new node... + */ + + return (node); +} + + +/* + * End of "$Id: mxml-node.c 408 2010-09-19 05:26:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_pri.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_pri.c new file mode 100644 index 0000000000..72f3e2320c --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_pri.c @@ -0,0 +1,331 @@ +/* + * "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $" + * + * Private functions for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxml_error() - Display an error message. + * mxml_integer_cb() - Default callback for integer values. + * mxml_opaque_cb() - Default callback for opaque values. + * mxml_real_cb() - Default callback for real number values. + * _mxml_global() - Get global data. + */ + +/* + * Include necessary headers... + */ + +#include "mxml-private.h" + + +/* + * Some crazy people think that unloading a shared object is a good or safe + * thing to do. Unfortunately, most objects are simply *not* safe to unload + * and bad things *will* happen. + * + * The following mess of conditional code allows us to provide a destructor + * function in Mini-XML for our thread-global storage so that it can possibly + * be unloaded safely, although since there is no standard way to do so I + * can't even provide any guarantees that you can do it safely on all platforms. + * + * This code currently supports AIX, HP-UX, Linux, Mac OS X, Solaris, and + * Windows. It might work on the BSDs and IRIX, but I haven't tested that. + */ + +#if defined(__sun) || defined(_AIX) +# pragma fini(_mxml_fini) +# define _MXML_FINI _mxml_fini +#elif defined(__hpux) +# pragma FINI _mxml_fini +# define _MXML_FINI _mxml_fini +#elif defined(__GNUC__) /* Linux and Mac OS X */ +# define _MXML_FINI __attribute((destructor)) _mxml_fini +#else +# define _MXML_FINI _fini +#endif /* __sun */ + + +/* + * 'mxml_error()' - Display an error message. + */ + +void +mxml_error(const char *format, /* I - Printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Pointer to arguments */ + char s[1024]; /* Message string */ + _mxml_global_t *global = _mxml_global(); + /* Global data */ + + + /* + * Range check input... + */ + + if (!format) + return; + + /* + * Format the error message string... + */ + + va_start(ap, format); + + vsnprintf(s, sizeof(s), format, ap); + + va_end(ap); + + /* + * And then display the error message... + */ + + if (global->error_cb) + (*global->error_cb)(s); + else + fprintf(stderr, "mxml: %s\n", s); +} + + +/* + * 'mxml_ignore_cb()' - Default callback for ignored values. + */ + +mxml_type_t /* O - Node type */ +mxml_ignore_cb(mxml_node_t *node) /* I - Current node */ +{ + (void)node; + + return (MXML_IGNORE); +} + + +/* + * 'mxml_integer_cb()' - Default callback for integer values. + */ + +mxml_type_t /* O - Node type */ +mxml_integer_cb(mxml_node_t *node) /* I - Current node */ +{ + (void)node; + + return (MXML_INTEGER); +} + + +/* + * 'mxml_opaque_cb()' - Default callback for opaque values. + */ + +mxml_type_t /* O - Node type */ +mxml_opaque_cb(mxml_node_t *node) /* I - Current node */ +{ + (void)node; + + return (MXML_OPAQUE); +} + + +/* + * 'mxml_real_cb()' - Default callback for real number values. + */ + +mxml_type_t /* O - Node type */ +mxml_real_cb(mxml_node_t *node) /* I - Current node */ +{ + (void)node; + + return (MXML_REAL); +} + + +#ifdef HAVE_PTHREAD_H /**** POSIX threading ****/ +# include + +static pthread_key_t _mxml_key = -1; /* Thread local storage key */ +static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT; + /* One-time initialization object */ +static void _mxml_init(void); +static void _mxml_destructor(void *g); + + +/* + * '_mxml_destructor()' - Free memory used for globals... + */ + +static void +_mxml_destructor(void *g) /* I - Global data */ +{ + free(g); +} + + +/* + * '_mxml_fini()' - Clean up when unloaded. + */ + +static void +_MXML_FINI(void) +{ + _mxml_global_t *global; /* Global data */ + + + if (_mxml_key != -1) + { + if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL) + _mxml_destructor(global); + + pthread_key_delete(_mxml_key); + _mxml_key = -1; + } +} + + +/* + * '_mxml_global()' - Get global data. + */ + +_mxml_global_t * /* O - Global data */ +_mxml_global(void) +{ + _mxml_global_t *global; /* Global data */ + + + pthread_once(&_mxml_key_once, _mxml_init); + + if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL) + { + global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t)); + pthread_setspecific(_mxml_key, global); + + global->num_entity_cbs = 1; + global->entity_cbs[0] = _mxml_entity_cb; + global->wrap = 72; + } + + return (global); +} + + +/* + * '_mxml_init()' - Initialize global data... + */ + +static void +_mxml_init(void) +{ + pthread_key_create(&_mxml_key, _mxml_destructor); +} + + +#elif defined(WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/ +# include + +static DWORD _mxml_tls_index; /* Index for global storage */ + + +/* + * 'DllMain()' - Main entry for library. + */ + +BOOL WINAPI /* O - Success/failure */ +DllMain(HINSTANCE hinst, /* I - DLL module handle */ + DWORD reason, /* I - Reason */ + LPVOID reserved) /* I - Unused */ +{ + _mxml_global_t *global; /* Global data */ + + + (void)hinst; + (void)reserved; + + switch (reason) + { + case DLL_PROCESS_ATTACH : /* Called on library initialization */ + if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) + return (FALSE); + break; + + case DLL_THREAD_DETACH : /* Called when a thread terminates */ + if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL) + free(global); + break; + + case DLL_PROCESS_DETACH : /* Called when library is unloaded */ + if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL) + free(global); + + TlsFree(_mxml_tls_index); + break; + + default: + break; + } + + return (TRUE); +} + + +/* + * '_mxml_global()' - Get global data. + */ + +_mxml_global_t * /* O - Global data */ +_mxml_global(void) +{ + _mxml_global_t *global; /* Global data */ + + + if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL) + { + global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t)); + + global->num_entity_cbs = 1; + global->entity_cbs[0] = _mxml_entity_cb; + global->wrap = 72; + + TlsSetValue(_mxml_tls_index, (LPVOID)global); + } + + return (global); +} + + +#else /**** No threading ****/ +/* + * '_mxml_global()' - Get global data. + */ + +_mxml_global_t * /* O - Global data */ +_mxml_global(void) +{ + static _mxml_global_t global = /* Global data */ + { + NULL, /* error_cb */ + 1, /* num_entity_cbs */ + { _mxml_entity_cb }, /* entity_cbs */ + 72, /* wrap */ + NULL, /* custom_load_cb */ + NULL /* custom_save_cb */ + }; + + + return (&global); +} +#endif /* HAVE_PTHREAD_H */ + + +/* + * End of "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_pri.h b/harbour/contrib/hbmxml/3rd/minixml/mxml_pri.h new file mode 100644 index 0000000000..8789e6c52c --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_pri.h @@ -0,0 +1,50 @@ +/* + * "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $" + * + * Private definitions for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + */ + +/* + * Include necessary headers... + */ + +#include "config.h" +#include "mxml.h" + + +/* + * Global, per-thread data... + */ + +typedef struct _mxml_global_s +{ + void (*error_cb)(const char *); + int num_entity_cbs; + int (*entity_cbs[100])(const char *name); + int wrap; + mxml_custom_load_cb_t custom_load_cb; + mxml_custom_save_cb_t custom_save_cb; +} _mxml_global_t; + + +/* + * Functions... + */ + +extern _mxml_global_t *_mxml_global(void); +extern int _mxml_entity_cb(const char *name); + + +/* + * End of "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_sea.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_sea.c new file mode 100644 index 0000000000..30ad5e5af6 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_sea.c @@ -0,0 +1,281 @@ +/* + * "$Id: mxml-search.c 423 2010-11-08 16:07:05Z mike $" + * + * Search/navigation functions for Mini-XML, a small XML-like file + * parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxmlFindElement() - Find the named element. + * mxmlFindValue() - Find a value with the given path. + * mxmlWalkNext() - Walk to the next logical node in the tree. + * mxmlWalkPrev() - Walk to the previous logical node in the tree. + */ + +/* + * Include necessary headers... + */ + +#include "config.h" +#include "mxml.h" + + +/* + * 'mxmlFindElement()' - Find the named element. + * + * The search is constrained by the name, attribute name, and value; any + * NULL names or values are treated as wildcards, so different kinds of + * searches can be implemented by looking for all elements of a given name + * or all elements with a specific attribute. The descend argument determines + * whether the search descends into child nodes; normally you will use + * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find + * additional direct descendents of the node. The top node argument + * constrains the search to a particular node's children. + */ + +mxml_node_t * /* O - Element node or NULL */ +mxmlFindElement(mxml_node_t *node, /* I - Current node */ + mxml_node_t *top, /* I - Top node */ + const char *name, /* I - Element name or NULL for any */ + const char *attr, /* I - Attribute name, or NULL for none */ + const char *value, /* I - Attribute value, or NULL for any */ + int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ +{ + const char *temp; /* Current attribute value */ + + + /* + * Range check input... + */ + + if (!node || !top || (!attr && value)) + return (NULL); + + /* + * Start with the next node... + */ + + node = mxmlWalkNext(node, top, descend); + + /* + * Loop until we find a matching element... + */ + + while (node != NULL) + { + /* + * See if this node matches... + */ + + if (node->type == MXML_ELEMENT && + node->value.element.name && + (!name || !strcmp(node->value.element.name, name))) + { + /* + * See if we need to check for an attribute... + */ + + if (!attr) + return (node); /* No attribute search, return it... */ + + /* + * Check for the attribute... + */ + + if ((temp = mxmlElementGetAttr(node, attr)) != NULL) + { + /* + * OK, we have the attribute, does it match? + */ + + if (!value || !strcmp(value, temp)) + return (node); /* Yes, return it... */ + } + } + + /* + * No match, move on to the next node... + */ + + if (descend == MXML_DESCEND) + node = mxmlWalkNext(node, top, MXML_DESCEND); + else + node = node->next; + } + + return (NULL); +} + + +/* + * 'mxmlFindValue()' - Find a value with the given path. + * + * The "path" is a slash-separated list of element names. The name "*" is + * considered a wildcard for one or more levels of elements. For example, + * "foo/one/two", "bar/two/one", "*\/one", and so forth. + * + * @since Mini-XML 2.7@ + */ + +mxml_node_t * /* O - First value node or NULL */ +mxmlFindValue(mxml_node_t *top, /* I - Top node */ + const char *path) /* I - Path to element */ +{ + mxml_node_t *node; /* Current node */ + char element[256], /* Current element name */ + *pathsep; /* Separator in path */ + int descend; /* mxmlFindElement option */ + + + /* + * Range check input... + */ + + if (!top || !path || !*path) + return (NULL); + + /* + * Search each element in the path... + */ + + node = top; + while (*path) + { + /* + * Handle wildcards... + */ + + if (!strncmp(path, "*/", 2)) + { + path += 2; + descend = MXML_DESCEND; + } + else + descend = MXML_DESCEND_FIRST; + + /* + * Get the next element in the path... + */ + + if ((pathsep = strchr(path, '/')) == NULL) + pathsep = path + strlen(path); + + if (pathsep == path || (pathsep - path) >= sizeof(element)) + return (NULL); + + memcpy(element, path, pathsep - path); + element[pathsep - path] = '\0'; + + if (*pathsep) + path = pathsep + 1; + else + path = pathsep; + + /* + * Search for the element... + */ + + if ((node = mxmlFindElement(node, node, element, NULL, NULL, + descend)) == NULL) + return (NULL); + } + + /* + * If we get this far, return the first child of the current node... + */ + + return (node->child); +} + + +/* + * 'mxmlWalkNext()' - Walk to the next logical node in the tree. + * + * The descend argument controls whether the first child is considered + * to be the next node. The top node argument constrains the walk to + * the node's children. + */ + +mxml_node_t * /* O - Next node or NULL */ +mxmlWalkNext(mxml_node_t *node, /* I - Current node */ + mxml_node_t *top, /* I - Top node */ + int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ +{ + if (!node) + return (NULL); + else if (node->child && descend) + return (node->child); + else if (node == top) + return (NULL); + else if (node->next) + return (node->next); + else if (node->parent && node->parent != top) + { + node = node->parent; + + while (!node->next) + if (node->parent == top || !node->parent) + return (NULL); + else + node = node->parent; + + return (node->next); + } + else + return (NULL); +} + + +/* + * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree. + * + * The descend argument controls whether the previous node's last child + * is considered to be the previous node. The top node argument constrains + * the walk to the node's children. + */ + +mxml_node_t * /* O - Previous node or NULL */ +mxmlWalkPrev(mxml_node_t *node, /* I - Current node */ + mxml_node_t *top, /* I - Top node */ + int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ +{ + if (!node || node == top) + return (NULL); + else if (node->prev) + { + if (node->prev->last_child && descend) + { + /* + * Find the last child under the previous node... + */ + + node = node->prev->last_child; + + while (node->last_child) + node = node->last_child; + + return (node); + } + else + return (node->prev); + } + else if (node->parent != top) + return (node->parent); + else + return (NULL); +} + + +/* + * End of "$Id: mxml-search.c 423 2010-11-08 16:07:05Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_set.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_set.c new file mode 100644 index 0000000000..7d641ba149 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_set.c @@ -0,0 +1,292 @@ +/* + * "$Id: mxml-set.c 408 2010-09-19 05:26:46Z mike $" + * + * Node set functions for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * mxmlSetCustom() - Set the data and destructor of a custom data node. + * mxmlSetCDATA() - Set the element name of a CDATA node. + * mxmlSetElement() - Set the name of an element node. + * mxmlSetInteger() - Set the value of an integer node. + * mxmlSetOpaque() - Set the value of an opaque node. + * mxmlSetReal() - Set the value of a real number node. + * mxmlSetText() - Set the value of a text node. + * mxmlSetTextf() - Set the value of a text node to a formatted string. + */ + +/* + * Include necessary headers... + */ + +#include "config.h" +#include "mxml.h" + + +/* + * 'mxmlSetCustom()' - Set the data and destructor of a custom data node. + * + * The node is not changed if it is not a custom node. + * + * @since Mini-XML 2.1@ + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetCustom( + mxml_node_t *node, /* I - Node to set */ + void *data, /* I - New data pointer */ + mxml_custom_destroy_cb_t destroy) /* I - New destructor function */ +{ + /* + * Range check input... + */ + + if (!node || node->type != MXML_CUSTOM) + return (-1); + + /* + * Free any old element value and set the new value... + */ + + if (node->value.custom.data && node->value.custom.destroy) + (*(node->value.custom.destroy))(node->value.custom.data); + + node->value.custom.data = data; + node->value.custom.destroy = destroy; + + return (0); +} + + +/* + * 'mxmlSetCDATA()' - Set the element name of a CDATA node. + * + * The node is not changed if it is not a CDATA element node. + * + * @since Mini-XML 2.3@ + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */ + const char *data) /* I - New data string */ +{ + /* + * Range check input... + */ + + if (!node || node->type != MXML_ELEMENT || !data || + strncmp(node->value.element.name, "![CDATA[", 8)) + return (-1); + + /* + * Free any old element value and set the new value... + */ + + if (node->value.element.name) + free(node->value.element.name); + + node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data); + + return (0); +} + + +/* + * 'mxmlSetElement()' - Set the name of an element node. + * + * The node is not changed if it is not an element node. + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetElement(mxml_node_t *node, /* I - Node to set */ + const char *name) /* I - New name string */ +{ + /* + * Range check input... + */ + + if (!node || node->type != MXML_ELEMENT || !name) + return (-1); + + /* + * Free any old element value and set the new value... + */ + + if (node->value.element.name) + free(node->value.element.name); + + node->value.element.name = strdup(name); + + return (0); +} + + +/* + * 'mxmlSetInteger()' - Set the value of an integer node. + * + * The node is not changed if it is not an integer node. + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetInteger(mxml_node_t *node, /* I - Node to set */ + int integer) /* I - Integer value */ +{ + /* + * Range check input... + */ + + if (!node || node->type != MXML_INTEGER) + return (-1); + + /* + * Set the new value and return... + */ + + node->value.integer = integer; + + return (0); +} + + +/* + * 'mxmlSetOpaque()' - Set the value of an opaque node. + * + * The node is not changed if it is not an opaque node. + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */ + const char *opaque) /* I - Opaque string */ +{ + /* + * Range check input... + */ + + if (!node || node->type != MXML_OPAQUE || !opaque) + return (-1); + + /* + * Free any old opaque value and set the new value... + */ + + if (node->value.opaque) + free(node->value.opaque); + + node->value.opaque = strdup(opaque); + + return (0); +} + + +/* + * 'mxmlSetReal()' - Set the value of a real number node. + * + * The node is not changed if it is not a real number node. + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetReal(mxml_node_t *node, /* I - Node to set */ + double real) /* I - Real number value */ +{ + /* + * Range check input... + */ + + if (!node || node->type != MXML_REAL) + return (-1); + + /* + * Set the new value and return... + */ + + node->value.real = real; + + return (0); +} + + +/* + * 'mxmlSetText()' - Set the value of a text node. + * + * The node is not changed if it is not a text node. + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetText(mxml_node_t *node, /* I - Node to set */ + int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ + const char *string) /* I - String */ +{ + /* + * Range check input... + */ + + if (!node || node->type != MXML_TEXT || !string) + return (-1); + + /* + * Free any old string value and set the new value... + */ + + if (node->value.text.string) + free(node->value.text.string); + + node->value.text.whitespace = whitespace; + node->value.text.string = strdup(string); + + return (0); +} + + +/* + * 'mxmlSetTextf()' - Set the value of a text node to a formatted string. + * + * The node is not changed if it is not a text node. + */ + +int /* O - 0 on success, -1 on failure */ +mxmlSetTextf(mxml_node_t *node, /* I - Node to set */ + int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Pointer to arguments */ + + + /* + * Range check input... + */ + + if (!node || node->type != MXML_TEXT || !format) + return (-1); + + /* + * Free any old string value and set the new value... + */ + + if (node->value.text.string) + free(node->value.text.string); + + va_start(ap, format); + + node->value.text.whitespace = whitespace; + node->value.text.string = _mxml_strdupf(format, ap); + + va_end(ap); + + return (0); +} + + +/* + * End of "$Id: mxml-set.c 408 2010-09-19 05:26:46Z mike $". + */ diff --git a/harbour/contrib/hbmxml/3rd/minixml/mxml_str.c b/harbour/contrib/hbmxml/3rd/minixml/mxml_str.c new file mode 100644 index 0000000000..6be42523f9 --- /dev/null +++ b/harbour/contrib/hbmxml/3rd/minixml/mxml_str.c @@ -0,0 +1,476 @@ +/* + * "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $" + * + * String functions for Mini-XML, a small XML-like file parsing library. + * + * Copyright 2003-2010 by Michael R Sweet. + * + * These coded instructions, statements, and computer programs are the + * property of Michael R Sweet and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "COPYING" + * which should have been included with this file. If this file is + * missing or damaged, see the license at: + * + * http://www.minixml.org/ + * + * Contents: + * + * _mxml_snprintf() - Format a string. + * _mxml_strdup() - Duplicate a string. + * _mxml_strdupf() - Format and duplicate a string. + * _mxml_vsnprintf() - Format a string into a fixed size buffer. + * _mxml_vstrdupf() - Format and duplicate a string. + */ + +/* + * Include necessary headers... + */ + +#include "config.h" + + +/* + * The va_copy macro is part of C99, but many compilers don't implement it. + * Provide a "direct assignment" implmentation when va_copy isn't defined... + */ + +#ifndef va_copy +# ifdef __va_copy +# define va_copy(dst,src) __va_copy(dst,src) +# else +# define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list)) +# endif /* __va_copy */ +#endif /* va_copy */ + + +#ifndef HAVE_SNPRINTF +/* + * '_mxml_snprintf()' - Format a string. + */ + +int /* O - Number of bytes formatted */ +_mxml_snprintf(char *buffer, /* I - Output buffer */ + size_t bufsize, /* I - Size of output buffer */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Argument list */ + int bytes; /* Number of bytes formatted */ + + + va_start(ap, format); + bytes = vsnprintf(buffer, bufsize, format, ap); + va_end(ap); + + return (bytes); +} +#endif /* !HAVE_SNPRINTF */ + + +/* + * '_mxml_strdup()' - Duplicate a string. + */ + +#ifndef HAVE_STRDUP +char * /* O - New string pointer */ +_mxml_strdup(const char *s) /* I - String to duplicate */ +{ + char *t; /* New string pointer */ + + + if (s == NULL) + return (NULL); + + if ((t = malloc(strlen(s) + 1)) == NULL) + return (NULL); + + return (strcpy(t, s)); +} +#endif /* !HAVE_STRDUP */ + + +/* + * '_mxml_strdupf()' - Format and duplicate a string. + */ + +char * /* O - New string pointer */ +_mxml_strdupf(const char *format, /* I - Printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Pointer to additional arguments */ + char *s; /* Pointer to formatted string */ + + + /* + * Get a pointer to the additional arguments, format the string, + * and return it... + */ + + va_start(ap, format); + s = _mxml_vstrdupf(format, ap); + va_end(ap); + + return (s); +} + + +#ifndef HAVE_VSNPRINTF +/* + * '_mxml_vsnprintf()' - Format a string into a fixed size buffer. + */ + +int /* O - Number of bytes formatted */ +_mxml_vsnprintf(char *buffer, /* O - Output buffer */ + size_t bufsize, /* O - Size of output buffer */ + const char *format, /* I - Printf-style format string */ + va_list ap) /* I - Pointer to additional arguments */ +{ + char *bufptr, /* Pointer to position in buffer */ + *bufend, /* Pointer to end of buffer */ + sign, /* Sign of format width */ + size, /* Size character (h, l, L) */ + type; /* Format type character */ + int width, /* Width of field */ + prec; /* Number of characters of precision */ + char tformat[100], /* Temporary format string for sprintf() */ + *tptr, /* Pointer into temporary format */ + temp[1024]; /* Buffer for formatted numbers */ + char *s; /* Pointer to string */ + int slen; /* Length of string */ + int bytes; /* Total number of bytes needed */ + + + /* + * Loop through the format string, formatting as needed... + */ + + bufptr = buffer; + bufend = buffer + bufsize - 1; + bytes = 0; + + while (*format) + { + if (*format == '%') + { + tptr = tformat; + *tptr++ = *format++; + + if (*format == '%') + { + if (bufptr && bufptr < bufend) *bufptr++ = *format; + bytes ++; + format ++; + continue; + } + else if (strchr(" -+#\'", *format)) + { + *tptr++ = *format; + sign = *format++; + } + else + sign = 0; + + if (*format == '*') + { + /* + * Get width from argument... + */ + + format ++; + width = va_arg(ap, int); + + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width); + tptr += strlen(tptr); + } + else + { + width = 0; + + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + width = width * 10 + *format++ - '0'; + } + } + + if (*format == '.') + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + format ++; + + if (*format == '*') + { + /* + * Get precision from argument... + */ + + format ++; + prec = va_arg(ap, int); + + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec); + tptr += strlen(tptr); + } + else + { + prec = 0; + + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + prec = prec * 10 + *format++ - '0'; + } + } + } + else + prec = -1; + + if (*format == 'l' && format[1] == 'l') + { + size = 'L'; + + if (tptr < (tformat + sizeof(tformat) - 2)) + { + *tptr++ = 'l'; + *tptr++ = 'l'; + } + + format += 2; + } + else if (*format == 'h' || *format == 'l' || *format == 'L') + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + size = *format++; + } + + if (!*format) + break; + + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + type = *format++; + *tptr = '\0'; + + switch (type) + { + case 'E' : /* Floating point formats */ + case 'G' : + case 'e' : + case 'f' : + case 'g' : + if ((width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, double)); + + bytes += strlen(temp); + + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'B' : /* Integer formats */ + case 'X' : + case 'b' : + case 'd' : + case 'i' : + case 'o' : + case 'u' : + case 'x' : + if ((width + 2) > sizeof(temp)) + break; + +#ifdef HAVE_LONG_LONG + if (size == 'L') + sprintf(temp, tformat, va_arg(ap, long long)); + else +#endif /* HAVE_LONG_LONG */ + sprintf(temp, tformat, va_arg(ap, int)); + + bytes += strlen(temp); + + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'p' : /* Pointer value */ + if ((width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, void *)); + + bytes += strlen(temp); + + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'c' : /* Character or character array */ + bytes += width; + + if (bufptr) + { + if (width <= 1) + *bufptr++ = va_arg(ap, int); + else + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + memcpy(bufptr, va_arg(ap, char *), (size_t)width); + bufptr += width; + } + } + break; + + case 's' : /* String */ + if ((s = va_arg(ap, char *)) == NULL) + s = "(null)"; + + slen = strlen(s); + if (slen > width && prec != width) + width = slen; + + bytes += width; + + if (bufptr) + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + if (slen > width) + slen = width; + + if (sign == '-') + { + strncpy(bufptr, s, (size_t)slen); + memset(bufptr + slen, ' ', (size_t)(width - slen)); + } + else + { + memset(bufptr, ' ', (size_t)(width - slen)); + strncpy(bufptr + width - slen, s, (size_t)slen); + } + + bufptr += width; + } + break; + + case 'n' : /* Output number of chars so far */ + *(va_arg(ap, int *)) = bytes; + break; + } + } + else + { + bytes ++; + + if (bufptr && bufptr < bufend) + *bufptr++ = *format; + + format ++; + } + } + + /* + * Nul-terminate the string and return the number of characters needed. + */ + + *bufptr = '\0'; + + return (bytes); +} +#endif /* !HAVE_VSNPRINTF */ + + +/* + * '_mxml_vstrdupf()' - Format and duplicate a string. + */ + +char * /* O - New string pointer */ +_mxml_vstrdupf(const char *format, /* I - Printf-style format string */ + va_list ap) /* I - Pointer to additional arguments */ +{ + int bytes; /* Number of bytes required */ + char *buffer, /* String buffer */ + temp[256]; /* Small buffer for first vsnprintf */ + va_list apcopy; /* Copy of argument list */ + + + /* + * First format with a tiny buffer; this will tell us how many bytes are + * needed... + */ + + va_copy(apcopy, ap); + bytes = vsnprintf(temp, sizeof(temp), format, apcopy); + + if (bytes < sizeof(temp)) + { + /* + * Hey, the formatted string fits in the tiny buffer, so just dup that... + */ + + return (strdup(temp)); + } + + /* + * Allocate memory for the whole thing and reformat to the new, larger + * buffer... + */ + + if ((buffer = calloc(1, bytes + 1)) != NULL) + vsnprintf(buffer, bytes + 1, format, ap); + + /* + * Return the new string... + */ + + return (buffer); +} + + +/* + * End of "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $". + */ diff --git a/harbour/contrib/hbmxml/hbmxml.c b/harbour/contrib/hbmxml/hbmxml.c new file mode 100644 index 0000000000..31005501d8 --- /dev/null +++ b/harbour/contrib/hbmxml/hbmxml.c @@ -0,0 +1,1292 @@ +/* + * $Id$ + */ + + +/* + * Harbour Project source code: + * MINIXML functions wrapper + * + * Copyright 2010 Petr Chornyj + * www - http://harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbapi.h" +#include "hbapiitm.h" +#include "hbapierr.h" +#include "hbapifs.h" +#include "hbstack.h" +#include "hbvm.h" + +#include "mxml.h" +#include "config.h" + +#define BUFFER_SIZE 8192 + +/* cb's funcs support */ +typedef struct +{ + PHB_DYNS type_cb; +} HB_TYPE_CB_VAR; + +typedef struct +{ + PHB_DYNS save_cb; +} HB_SAVE_CB_VAR; + +typedef struct +{ + PHB_DYNS error_cb; +} HB_ERROR_CB_VAR; + + +static void hb_type_cb_var_init( void * cargo ) +{ + HB_TYPE_CB_VAR * pType_cb = ( HB_TYPE_CB_VAR * ) cargo; + + pType_cb->type_cb = NULL; +} + +static void hb_save_cb_var_init( void * cargo ) +{ + HB_SAVE_CB_VAR * pSave_cb = ( HB_SAVE_CB_VAR * ) cargo; + + pSave_cb->save_cb = NULL; +} + +static void hb_error_cb_var_init( void * cargo ) +{ + HB_ERROR_CB_VAR * pError_cb = ( HB_ERROR_CB_VAR * ) cargo; + + pError_cb->error_cb = NULL; +} + +static HB_TSD_NEW( s_type_cb_var, sizeof( HB_TYPE_CB_VAR ), hb_type_cb_var_init, NULL ); +static HB_TSD_NEW( s_save_cb_var, sizeof( HB_SAVE_CB_VAR ), hb_save_cb_var_init, NULL ); +static HB_TSD_NEW( s_error_cb_var, sizeof( HB_ERROR_CB_VAR ), hb_error_cb_var_init, NULL ); + +/* mxml_node_t * support */ +static HB_GARBAGE_FUNC( hb_mxml_nodeDestructor ) +{ + mxml_node_t ** ppMxml_node = ( mxml_node_t ** ) Cargo; + + if( *ppMxml_node ) + { + mxmlRelease( *ppMxml_node ); + *ppMxml_node = NULL; + } +} + +static const HB_GC_FUNCS s_gc_mxml_nodeFuncs = +{ + hb_mxml_nodeDestructor, + hb_gcDummyMark +}; + +mxml_node_t * hb_mxml_node_ItemGet( PHB_ITEM pItem ) +{ + mxml_node_t ** ppMxml_node = ( mxml_node_t ** ) hb_itemGetPtrGC( pItem, + &s_gc_mxml_nodeFuncs ); + + return ppMxml_node ? *ppMxml_node : NULL; +} + +PHB_ITEM hb_mxml_node_ItemPut( PHB_ITEM pItem, mxml_node_t * pMxml_node ) +{ + mxml_node_t ** ppMxml_node = ( mxml_node_t ** ) hb_gcAllocate( sizeof( mxml_node_t * ), + &s_gc_mxml_nodeFuncs ); + + *ppMxml_node = pMxml_node; + mxmlRetain( *ppMxml_node ); + + return hb_itemPutPtrGC( pItem, ppMxml_node ); +} + +mxml_node_t * hb_mxml_node_param( int iParam ) +{ + mxml_node_t ** ppMxml_node = ( mxml_node_t ** ) hb_parptrGC( &s_gc_mxml_nodeFuncs, + iParam ); + + if( ppMxml_node && *ppMxml_node ) + return *ppMxml_node; + + hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + return NULL; +} + +void hb_mxml_node_ret( mxml_node_t * pMxml_node ) +{ + hb_mxml_node_ItemPut( hb_stackReturnItem(), pMxml_node ); +} + +/* mxml_index_t * support */ +static HB_GARBAGE_FUNC( hb_mxml_indexDestructor ) +{ + mxml_index_t ** ppMxml_index = ( mxml_index_t ** ) Cargo; + + if( *ppMxml_index ) + { + mxmlIndexDelete( *ppMxml_index ); + *ppMxml_index = NULL; + } +} + +static const HB_GC_FUNCS s_gc_mxml_indexFuncs = +{ + hb_mxml_indexDestructor, + hb_gcDummyMark +}; + +mxml_index_t * hb_mxml_index_ItemGet( PHB_ITEM pItem ) +{ + mxml_index_t ** ppMxml_index = ( mxml_index_t ** ) hb_itemGetPtrGC( pItem, + &s_gc_mxml_indexFuncs ); + + return ppMxml_index ? *ppMxml_index : NULL; +} + +PHB_ITEM hb_mxml_index_ItemPut( PHB_ITEM pItem, mxml_index_t * pMxml_index ) +{ + mxml_index_t ** ppMxml_index = ( mxml_index_t ** ) hb_gcAllocate( sizeof( mxml_index_t * ), + &s_gc_mxml_indexFuncs ); + + *ppMxml_index = pMxml_index; + return hb_itemPutPtrGC( pItem, ppMxml_index ); +} + +mxml_index_t * hb_mxml_index_param( int iParam ) +{ + mxml_index_t ** ppMxml_index = ( mxml_index_t ** ) hb_parptrGC( &s_gc_mxml_indexFuncs, + iParam ); + + if( ppMxml_index && *ppMxml_index ) + return *ppMxml_index; + + hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + return NULL; +} + +void hb_mxml_index_ret( mxml_index_t * pMxml_index ) +{ + hb_mxml_index_ItemPut( hb_stackReturnItem(), pMxml_index ); +} + +/* non-wrap HB_... funcs */ + +HB_FUNC( HB_MXMLVERSION ) +{ + hb_retc( MXML_VERSION ); +} + +HB_FUNC( HB_MXMLNODETYPE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + hb_retni( node->type ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEVALUE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + switch( node->type ) + { + case MXML_IGNORE: hb_ret(); break; + case MXML_ELEMENT: hb_retc( node->value.element.name ); break; + case MXML_INTEGER: hb_retni( node->value.integer ); break; + case MXML_OPAQUE: hb_retc( node->value.opaque ); break; + case MXML_REAL: hb_retnd( node->value.real ); break; + case MXML_TEXT: hb_retc( node->value.text.string ); break; + case MXML_CUSTOM: hb_ret() /* TODO */; + } + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEPARENT ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + if( node->parent ) + hb_mxml_node_ret( node->parent ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODECHILD ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + if( node->child ) + hb_mxml_node_ret( node->child ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODELASTCHILD ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + if( node->last_child ) + hb_mxml_node_ret( node->last_child ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODENEXT ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + if( node->next ) + hb_mxml_node_ret( node->next ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEASELEMENTNAME ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retc( node->value.element.name ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEASINTEGER ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retni( node->value.integer ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEASOPAQUE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retc( node->value.opaque ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEASREAL ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retnd( node->value.real ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEASTEXT ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retc( node->value.text.string ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLNODEWHITESPACE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retl( ! node->value.text.string || node->value.text.whitespace ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( HB_MXMLINDEXNUMNODES ) +{ + mxml_index_t * index = ( mxml_index_t * ) hb_mxml_index_param( 1 ); + + if( index ) + hb_retni( index != NULL ? index->num_nodes : 0 ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* MXML... */ + +/* void mxmlAdd( mxml_node_t * parent, int where, mxml_node_t * child, mxml_node_t * node ) */ + +HB_FUNC( MXMLADD ) +{ + mxml_node_t * parent = (mxml_node_t *) ( HB_ISNIL( 1 ) ? NULL : hb_mxml_node_param( 1 ) ); + int where = hb_parni( 2 ); + mxml_node_t * child = (mxml_node_t *) ( HB_ISNIL( 3 ) ? NULL : hb_mxml_node_param( 3 ) ); + mxml_node_t * node = (mxml_node_t *) hb_mxml_node_param( 4 ); + + if( node ) + mxmlAdd( parent, where, child, node ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* void mxmlDelete( mxml_node_t * node ) */ + +HB_FUNC( MXMLDELETE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if ( node ) + mxmlDelete( node ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* void mxmlElementDeleteAttr( mxml_node_t * node, const char * name ) */ + +HB_FUNC( MXMLELEMENTDELETEATTR ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + mxmlElementDeleteAttr( node, hb_parc( 2 ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* const char * mxmlElementGetAttr( mxml_node_t * node, const char * name ) */ + +HB_FUNC( MXMLELEMENTGETATTR ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retc( mxmlElementGetAttr( node, hb_parc( 2 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* void mxmlElementSetAttr( mxml_node_t * node, const char * name, const char * value ) */ + +HB_FUNC( MXMLELEMENTSETATTR ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + mxmlElementSetAttr( node, hb_parc( 2 ), hb_parc( 3 ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* const char * mxmlEntityGetName( int val ) */ + +HB_FUNC( MXMLENTITYGETNAME ) +{ + hb_retc( mxmlEntityGetName( hb_parni( 1 ) - 1 ) ); +} + +/* int mxmlEntityGetValue( const char * name ) */ + +HB_FUNC( MXMLENTITYGETVALUE ) +{ + int i = mxmlEntityGetValue( hb_parc( 1 ) ); + + hb_retni( i < 0 ? -1 : i + 1 ); +} + +/* + mxml_node_t * mxmlFindElement( mxml_node_t * node, mxml_node_t * top, + const char * name, const char * attr, + const char * value, int descend ); + */ + +HB_FUNC( MXMLFINDELEMENT ) +{ + mxml_node_t * node = (mxml_node_t *) hb_mxml_node_param( 1 ); + mxml_node_t * top = (mxml_node_t *) hb_mxml_node_param( 2 ); + + if( node && top ) + { + mxml_node_t * nodef = mxmlFindElement( node, top, + hb_parc( 3 ), hb_parc( 4 ), + hb_parc( 5 ), hb_parni( 6 ) ); + if ( nodef ) + hb_mxml_node_ret( nodef ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* mxml_node_t * mxmlFindValue( mxml_node_t * node, const char * path ) */ + +HB_FUNC( MXMLFINDVALUE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + mxml_node_t * nodef = mxmlFindValue( node, hb_parc( 2 ) ); + + if ( nodef ) + hb_mxml_node_ret( nodef ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* void mxmlIndexDelete( mxml_index_t * ind ) */ + +/* +HB_FUNC( MXMLINDEXDELETE ) +{ + mxml_index_t * index = ( mxml_index_t * ) hb_mxml_index_param( 1 ); + + if( index ) + mxmlIndexDelete( index ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} +*/ + +/* mxml_node_t * mxmlIndexEnum( mxml_index_t * ind ) */ + +HB_FUNC( MXMLINDEXENUM ) +{ + mxml_index_t * index = ( mxml_index_t * ) hb_mxml_index_param( 1 ); + + if( index ) + hb_mxml_node_ret( mxmlIndexEnum( index ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* mxml_node_t * mxmlIndexFind( mxml_index_t * ind, const char * element, const char * value ) */ + +HB_FUNC( MXMLINDEXFIND ) +{ + mxml_index_t * index = ( mxml_index_t * ) hb_mxml_index_param( 1 ); + + if( index ) + { + mxml_node_t * nodef = mxmlIndexFind( index, hb_parc( 2 ), hb_parc( 3 ) ); + + if ( nodef ) + hb_mxml_node_ret( nodef ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* mxml_index_t * mxmlIndexNew( mxml_node_t * node, const char * element, const char * attr ) */ + +HB_FUNC( MXMLINDEXNEW ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + mxml_index_t * index = mxmlIndexNew( node, hb_parc( 2 ), hb_parc( 3 ) ); + + if( index ) + hb_mxml_index_ret( index ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* mxml_node_t * mxmlIndexReset( mxml_index_t * ind ) */ + +HB_FUNC( MXMLINDEXRESET ) +{ + mxml_index_t * index = ( mxml_index_t * ) hb_mxml_index_param( 1 ); + + if( index ) + { + mxml_node_t * node = mxmlIndexReset( index ); + + if ( node ) + hb_mxml_node_ret( node ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* ================ mxml_type_t type_cb( mxml_node_t * node ) =================== */ + +mxml_type_t type_cb( mxml_node_t * node ) +{ + HB_TYPE_CB_VAR * pType_cb = ( HB_TYPE_CB_VAR * ) hb_stackGetTSD( &s_type_cb_var ); + + if ( pType_cb != NULL ) + { + PHB_DYNS pSym = pType_cb->type_cb; + + if( pSym && hb_vmRequestReenter() ) + { + int iResult = MXML_TEXT; + PHB_ITEM pNode = hb_itemNew( NULL ); + + hb_mxml_node_ItemPut( pNode, node ); + + hb_vmPushDynSym( pSym ); + hb_vmPushNil(); + hb_vmPushItemRef( pNode ); + + hb_vmFunction( 1 ); + iResult = hb_parnidef( -1, MXML_TEXT ); + + hb_itemRelease( pNode ); + + hb_vmRequestRestore(); + return iResult; + } + else + return MXML_TEXT; + } + else + return MXML_TEXT; +} + +/* mxml_node_t * mxmlLoadFile( mxml_node_t *top, FILE *fp, mxml_load_cb_t cb ) */ + +HB_FUNC( MXMLLOADFILE ) +{ + mxml_node_t * node_top; + mxml_load_cb_t cb; + const char * filename = hb_parc( 2 ); + const char * mode = HB_ISCHAR( 4 ) ? hb_parc( 4 ) : "r"; + HB_TYPE_CB_VAR * pType_cb = ( HB_TYPE_CB_VAR * ) hb_stackGetTSD( &s_type_cb_var ); + FILE * file; + mxml_node_t * node = NULL; + + if ( HB_ISNIL( 1 ) ) + node_top = NULL; + else + { + node_top = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if ( ! node_top ) + { + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + return ; + } + } + + if( HB_ISSYMBOL( 3 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 3, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + pType_cb->type_cb = pDynSym; + cb = type_cb; + } + else + cb = MXML_NO_CALLBACK; + } + else + { + switch( hb_parni( 3 ) ) + { + case 0: cb = MXML_NO_CALLBACK; break; + case 1: cb = MXML_INTEGER_CALLBACK; break; + case 2: cb = MXML_OPAQUE_CALLBACK; break; + case 3: cb = MXML_REAL_CALLBACK; break; + case 4: cb = MXML_TEXT_CALLBACK; break; + case 5: cb = MXML_IGNORE_CALLBACK; break; + default: cb = MXML_NO_CALLBACK; + } + } + + file = hb_fopen( filename, mode ); + if( file ) + { + node = mxmlLoadFile( node_top, file, cb ); + fclose( file ); + } + pType_cb->type_cb = NULL; + + if( node ) + hb_mxml_node_ret( node ); +} + +/* + mxml_node_t * mxmlLoadString(mxml_node_t *top, const char *s, + mxml_type_t (*cb)(mxml_node_t *)) + */ + +HB_FUNC( MXMLLOADSTRING ) +{ + mxml_node_t * node_top; + mxml_node_t * node; + mxml_load_cb_t cb; + HB_TYPE_CB_VAR * pType_cb = ( HB_TYPE_CB_VAR * ) hb_stackGetTSD( &s_type_cb_var ); + + if ( HB_ISNIL( 1 ) ) + node_top = NULL; + else + { + node_top = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if ( ! node_top ) + { + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + return ; + } + } + + if( HB_ISSYMBOL( 3 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 3, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + pType_cb->type_cb = pDynSym; + cb = type_cb; + } + else + cb = MXML_NO_CALLBACK; + } + else + { + switch( hb_parni( 3 ) ) + { + case 0: cb = MXML_NO_CALLBACK; break; + case 1: cb = MXML_INTEGER_CALLBACK; break; + case 2: cb = MXML_OPAQUE_CALLBACK; break; + case 3: cb = MXML_REAL_CALLBACK; break; + case 4: cb = MXML_TEXT_CALLBACK; break; + case 5: cb = MXML_IGNORE_CALLBACK; break; + default: cb = MXML_NO_CALLBACK; + } + } + node = mxmlLoadString( node_top, hb_parc( 2 ), cb ); + pType_cb->type_cb = NULL; + + if( node ) + hb_mxml_node_ret( node ); +} + +/* mxml_node_t * mxmlNewCDATA( mxml_node_t *parent, const char *string ) */ + +HB_FUNC( MXMLNEWCDATA ) +{ + mxml_node_t * node; + + if( HB_ISNIL( 1 ) || ( HB_ISNUM( 1 ) && hb_parni( 1 ) == MXML_NO_PARENT ) ) + { + node = mxmlNewCDATA( MXML_NO_PARENT, hb_parc( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + { + mxml_node_t * node_parent = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node_parent ) + { + node = mxmlNewCDATA( node_parent, hb_parc( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } +} + +/* mxml_node_t * mxmlNewElement( mxml_node_t *parent, const char *name ) */ + +HB_FUNC( MXMLNEWELEMENT ) +{ + mxml_node_t * node; + + if( HB_ISNIL( 1 ) || ( HB_ISNUM( 1 ) && hb_parni( 1 ) == MXML_NO_PARENT ) ) + { + node = mxmlNewElement( MXML_NO_PARENT, hb_parc( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + { + mxml_node_t * node_parent = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node_parent ) + { + node = mxmlNewElement( node_parent, hb_parc( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } +} + +/* mxml_node_t * mxmlNewInteger( mxml_node_t *parent, int integer ) */ + +HB_FUNC( MXMLNEWINTEGER ) +{ + mxml_node_t * node; + + if( HB_ISNIL( 1 ) || ( HB_ISNUM( 1 ) && hb_parni( 1 ) == MXML_NO_PARENT ) ) + { + node = mxmlNewInteger( MXML_NO_PARENT, hb_parni( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + { + mxml_node_t * node_parent = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node_parent ) + { + node = mxmlNewInteger( node_parent, hb_parni( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } +} + +/* mxml_node_t * mxmlNewOpaque( mxml_node_t *parent, const char *opaque ) */ + +HB_FUNC( MXMLNEWOPAQUE ) +{ + if( HB_ISNIL( 1 ) || ( HB_ISNUM( 1 ) && hb_parni( 1 ) == MXML_NO_PARENT ) ) + hb_mxml_node_ret( mxmlNewOpaque( MXML_NO_PARENT, hb_parc( 2 ) ) ); + else + { + mxml_node_t * node_parent = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node_parent ) + hb_mxml_node_ret( mxmlNewOpaque( node_parent, hb_parc( 2 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } +} + +/* mxml_node_t * mxmlNewReal( mxml_node_t *parent, double real ) */ + +HB_FUNC( MXMLNEWREAL ) +{ + mxml_node_t * node; + + if( HB_ISNIL( 1 ) || ( HB_ISNUM( 1 ) && hb_parni( 1 ) == MXML_NO_PARENT ) ) + { + node = mxmlNewReal( MXML_NO_PARENT, hb_parnd( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + { + mxml_node_t * node_parent = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node_parent ) + { + node = mxmlNewReal( node_parent, hb_parnd( 2 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } +} + +/* mxml_node_t * mxmlNewText( mxml_node_t *parent, int whitespace, const char *string ) */ + +HB_FUNC( MXMLNEWTEXT ) +{ + mxml_node_t * node; + + if( HB_ISNIL( 1 ) || ( HB_ISNUM( 1 ) && hb_parni( 1 ) == MXML_NO_PARENT ) ) + { + node = mxmlNewText( MXML_NO_PARENT, ( int ) hb_parldef( 2, HB_FALSE ), hb_parc( 3 ) ); + + if( node ) + hb_mxml_node_ret( node ); + } + else + { + mxml_node_t * node_parent = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node_parent ) + { + node = mxmlNewText( node_parent, ( int ) hb_parldef( 2, HB_FALSE ), + hb_parc( 3 ) ); + if( node ) + hb_mxml_node_ret( node ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } +} + +/* mxml_node_t * mxmlNewXML( const char *version ) */ + +HB_FUNC( MXMLNEWXML ) +{ + mxml_node_t * node; + + node = mxmlNewXML( HB_ISCHAR( 1 ) ? hb_parc( 1 ) : "1.0" ); + + if ( node ) + hb_mxml_node_ret( node ); +} + +/* int mxmlRelease( mxml_node_t *node ) */ + +HB_FUNC( MXMLRELEASE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if ( node ) + hb_retni( mxmlRelease( node ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* void mxmlRemove( mxml_node_t *node ) */ + +HB_FUNC( MXMLREMOVE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if ( node ) + mxmlRemove( node ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlRetain( mxml_node_t *node ) */ + +HB_FUNC( MXMLRETAIN ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if ( node ) + hb_retni( mxmlRetain( node ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* ============ const char *(*mxml_save_cb_t)(mxml_node_t *, int) =============== */ + +const char * save_cb( mxml_node_t * node, int where ) +{ + HB_SAVE_CB_VAR * pSave_cb = ( HB_SAVE_CB_VAR * ) hb_stackGetTSD( &s_save_cb_var ); + + if ( pSave_cb != NULL ) + { + PHB_DYNS pSym = pSave_cb->save_cb; + + if( pSym && hb_vmRequestReenter() ) + { + const char * pszResult; + PHB_ITEM pNode = hb_itemNew( NULL ); + + hb_mxml_node_ItemPut( pNode, node ); + + hb_vmPushDynSym( pSym ); + hb_vmPushNil(); + hb_vmPushItemRef( pNode ); + hb_vmPushInteger( where ); + + hb_vmFunction( 2 ); + pszResult = HB_ISCHAR( -1 ) ? hb_parc( -1 ) : NULL; + + hb_itemRelease( pNode ); + + hb_vmRequestRestore(); + return pszResult; + } + else + return NULL; + } + else + return NULL; +} + +/* char *mxmlSaveAllocString( mxml_node_t *node, mxml_save_cb_t cb ) */ + +HB_FUNC( MXMLSAVEALLOCSTRING ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + { + mxml_save_cb_t cb; + HB_SAVE_CB_VAR * pSave_cb = ( HB_SAVE_CB_VAR * ) hb_stackGetTSD( &s_save_cb_var ); + + char buffer[ BUFFER_SIZE ]; + int bytes; + + if( HB_ISSYMBOL( 2 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 2, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + pSave_cb->save_cb = pDynSym; + cb = save_cb; + } + else + cb = MXML_NO_CALLBACK; + } + else + cb = MXML_NO_CALLBACK; + + bytes = mxmlSaveString( node, buffer, BUFFER_SIZE, cb ); + pSave_cb->save_cb = NULL; + + if ( bytes <= 0 ) + hb_retc_null(); + else if ( bytes < ( int ) sizeof( buffer ) ) + hb_retclen_buffer( hb_strdup( buffer ), bytes - 1 ); /* Without EoL */ + else + { + char * s = ( char * ) hb_xalloc( bytes + 1 ); + + if ( s == NULL) + hb_retc_null(); + else + { + mxmlSaveString( node, s, bytes + 1, cb ); + hb_retclen_buffer( s, bytes - 1 ); + } + } + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* + int mxmlSaveString( mxml_node_t *node, char *buffer, + int bufsize, mxml_save_cb_t cb) + */ + +HB_FUNC( MXMLSAVESTRING ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + PHB_ITEM pBuffer = hb_param( 2, HB_IT_STRING ); + + if( node ) + { + mxml_save_cb_t cb; + HB_SAVE_CB_VAR * pSave_cb = ( HB_SAVE_CB_VAR * ) hb_stackGetTSD( &s_save_cb_var ); + + if ( pBuffer && ISBYREF( 2 ) ) + { + char * buffer; + HB_SIZE buffer_size; + + if( HB_ISSYMBOL( 3 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 3, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + pSave_cb->save_cb = pDynSym; + cb = save_cb; + } + else + cb = MXML_NO_CALLBACK; + } + else + cb = MXML_NO_CALLBACK; + + if ( hb_itemGetWriteCL( pBuffer, &buffer, &buffer_size ) ) + { + int bytes = mxmlSaveString( node, buffer, ( int ) buffer_size, cb ); + pSave_cb->save_cb = NULL; + + if ( bytes <= 0 ) + hb_retni( -1 ); + else if ( bytes <= ( int ) ( buffer_size - 1 ) ) + { + hb_storclen( buffer, ( int ) bytes - 1, 2 ); /* Without EoL */ + hb_retni( bytes ); + } + else + hb_retni( - ( bytes + 1 ) ); + } + else + hb_retni( -2 ); + } + else + hb_retni( -3 ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlSaveFile( mxml_node_t *node, FILE *fp, mxml_save_cb_t cb ) */ + +HB_FUNC( MXMLSAVEFILE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + const char * filename = hb_parc( 2 ); + const char * mode = HB_ISCHAR( 4 ) ? hb_parc( 4 ) : "w"; + FILE * file; + + file = hb_fopen( filename, mode ); + + if( file && node ) + { + mxml_save_cb_t cb; + HB_SAVE_CB_VAR * pSave_cb = ( HB_SAVE_CB_VAR * ) hb_stackGetTSD( &s_save_cb_var ); + + if( HB_ISSYMBOL( 3 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 3, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + pSave_cb->save_cb = pDynSym; + cb = save_cb; + } + else + cb = MXML_NO_CALLBACK; + } + else + cb = MXML_NO_CALLBACK; + + hb_retni( mxmlSaveFile( node, file, cb ) ); + + pSave_cb->save_cb = NULL; + fclose( file ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlSetCDATA( mxml_node_t * node, const char * data ) */ + +HB_FUNC( MXMLSETCDATA ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retni( mxmlSetCDATA( node, hb_parc( 2 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlSetElement( mxml_node_t * node, const char * name ) */ + +HB_FUNC( MXMLSETELEMENT ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retni( mxmlSetElement( node, hb_parc( 2 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlSetInteger( mxml_node_t * node, int integer ) */ + +HB_FUNC( MXMLSETINTEGER ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retni( mxmlSetInteger( node, hb_parnidef( 2, 0 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlSetOpaque( mxml_node_t * node, const char * opaque ) */ + +HB_FUNC( MXMLSETOPAQUE ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retni( mxmlSetOpaque( node, hb_parc( 2 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlSetReal( mxml_node_t * node, double real ) */ + +HB_FUNC( MXMLSETREAL ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retni( mxmlSetReal( node, hb_parnd( 2 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int mxmlSetText( mxml_node_t * node, int whitespace, const char * string ) */ + +HB_FUNC( MXMLSETTEXT ) +{ + mxml_node_t * node = ( mxml_node_t * ) hb_mxml_node_param( 1 ); + + if( node ) + hb_retni( mxmlSetText( node, ( int ) hb_parldef( 2, HB_FALSE ), hb_parc( 3 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* void mxmlSetWrapMargin( int column ) */ +HB_FUNC( MXMLSETWRAPMARGIN ) +{ + mxmlSetWrapMargin( hb_parni( 1 ) ); +} + +/* + mxml_node_t * mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, + int descend) + */ + +HB_FUNC( MXMLWALKNEXT ) +{ + mxml_node_t * node = (mxml_node_t *) hb_mxml_node_param( 1 ); + mxml_node_t * top = (mxml_node_t *) hb_mxml_node_param( 2 ); + + if( node && top ) + { + mxml_node_t * node_next = mxmlWalkNext( node, top, hb_parnidef( 3, MXML_NO_DESCEND ) ); + + if ( node_next ) + hb_mxml_node_ret( node_next ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* + mxml_node_t * mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, + int descend) + */ + +HB_FUNC( MXMLWALKPREV ) +{ + mxml_node_t * node = (mxml_node_t *) hb_mxml_node_param( 1 ); + mxml_node_t * top = (mxml_node_t *) hb_mxml_node_param( 2 ); + + if( node && top ) + { + mxml_node_t * node_prev = mxmlWalkPrev( node, top, hb_parnidef( 3, MXML_NO_DESCEND ) ); + + if ( node_prev ) + hb_mxml_node_ret( node_prev ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* ================ void ( *mxml_error_cb_t )( const char * ) =================== */ + +void error_cb( const char * pszErrorMsg ) +{ + HB_ERROR_CB_VAR * pError_cb = ( HB_ERROR_CB_VAR * ) hb_stackGetTSD( &s_error_cb_var ); + + if ( pError_cb != NULL ) + { + PHB_DYNS pSym = pError_cb->error_cb; + + if( pSym && hb_vmRequestReenter() ) + { + hb_vmPushDynSym( pSym ); + hb_vmPushNil(); + hb_itemPutCConst( hb_stackAllocItem(), pszErrorMsg ); + + hb_vmProc( 1 ); + hb_vmRequestRestore(); + } + } +} + +HB_FUNC( MXMLSETERRORCALLBACK ) +{ + if( HB_ISSYMBOL( 1 ) ) + { + HB_ERROR_CB_VAR * pError_cb = ( HB_ERROR_CB_VAR * ) hb_stackGetTSD( &s_error_cb_var ); + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 1, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + pError_cb->error_cb = pDynSym; + + mxmlSetErrorCallback( error_cb ); + } + else + { + pError_cb->error_cb = NULL; + + mxmlSetErrorCallback( NULL ); + } + } +} diff --git a/harbour/contrib/hbmxml/hbmxml.ch b/harbour/contrib/hbmxml/hbmxml.ch new file mode 100644 index 0000000000..46f13d61e6 --- /dev/null +++ b/harbour/contrib/hbmxml/hbmxml.ch @@ -0,0 +1,89 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * MINIXML functions wrapper + * + * Copyright 2010 Petr Chornyj + * www - http://harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef HBMXML_CH_ +#define HBMXML_CH_ + +#define MXML_TAB 8 /* Tabs every N columns */ + +#define MXML_NO_CALLBACK 0 /* Don't use a type callback */ +#define MXML_INTEGER_CALLBACK 1 /* Treat all data as integers */ +#define MXML_OPAQUE_CALLBACK 2 /* Treat all data as opaque */ +#define MXML_REAL_CALLBACK 3 /* Treat all data as real numbers */ +#define MXML_TEXT_CALLBACK 4 /* Treat all data as text */ +#define MXML_IGNORE_CALLBACK 5 /* Ignore all non-element content */ + +#define MXML_NO_PARENT 0 + +#define MXML_IGNORE -1 + +#define MXML_ELEMENT 0 +#define MXML_INTEGER 1 +#define MXML_OPAQUE 2 +#define MXML_REAL 3 +#define MXML_TEXT 4 +#define MXML_CUSTOM 5 + +#define MXML_DESCEND 1 /* Descend when finding/walking */ +#define MXML_NO_DESCEND 0 /* Don't descend when finding/walking */ +#define MXML_DESCEND_FIRST -1 /* Descend for first find */ + +#define MXML_WS_BEFORE_OPEN 0 /* Callback for before open tag */ +#define MXML_WS_AFTER_OPEN 1 /* Callback for after open tag */ +#define MXML_WS_BEFORE_CLOSE 2 /* Callback for before close tag */ +#define MXML_WS_AFTER_CLOSE 3 /* Callback for after close tag */ + +#define MXML_ADD_BEFORE 0 /* Add node before specified node */ +#define MXML_ADD_AFTER 1 /* Add node after specified node */ +#define MXML_ADD_TO_PARENT NIL /* Add node relative to parent */ + +#endif /* HBMXML_CH_ */ diff --git a/harbour/contrib/hbmxml/hbmxml.hbc b/harbour/contrib/hbmxml/hbmxml.hbc new file mode 100644 index 0000000000..7df3fad312 --- /dev/null +++ b/harbour/contrib/hbmxml/hbmxml.hbc @@ -0,0 +1,8 @@ +# +# $Id$ +# + +incpaths=. + +libs=${hb_name}${__HB_DYN__} +libs=3rd/minixml/mxml.hbc diff --git a/harbour/contrib/hbmxml/hbmxml.hbp b/harbour/contrib/hbmxml/hbmxml.hbp new file mode 100644 index 0000000000..385dcf635c --- /dev/null +++ b/harbour/contrib/hbmxml/hbmxml.hbp @@ -0,0 +1,23 @@ +# +# $Id$ +# + +-hblib +-inc + +-o${hb_name} + +-w3 -es2 + +-depkeyhead=mxml:mxml.h +-depcontrol=mxml:local{HB_BUILD_3RDEXT='no'} +-depcontrol=mxml:${HB_WITH_MXML} +-depincpath=mxml:/usr/include +-depincpathlocal=mxml:3rd/minixml +-depfinish=mxml + +-instfile=inc:hbmxml.ch + +hbmxml.c + +3rd/minixml/mxml.hbc{HBMK_HAS_MXML_LOCAL} diff --git a/harbour/contrib/hbmxml/tests/hbmk.hbm b/harbour/contrib/hbmxml/tests/hbmk.hbm new file mode 100644 index 0000000000..d4d8356580 --- /dev/null +++ b/harbour/contrib/hbmxml/tests/hbmk.hbm @@ -0,0 +1,7 @@ +# +# $Id$ +# + +../hbmxml.hbc + +-w3 -es2 diff --git a/harbour/contrib/hbmxml/tests/test.prg b/harbour/contrib/hbmxml/tests/test.prg new file mode 100644 index 0000000000..27f4baf1c7 --- /dev/null +++ b/harbour/contrib/hbmxml/tests/test.prg @@ -0,0 +1,571 @@ +/* + * $Id$ + */ + +#include "hbmxml.ch" +#include "fileio.ch" +#include "hbinkey.ch" + +FUNCTION main( cFile ) + + LOCAL tree + LOCAL node + LOCAL index + LOCAL nType, i, nLen + LOCAL cBuffer + + OutStd( hb_mxmlVersion(), hb_eol() ) + + mxmlSetErrorCallback( @my_mxmlError() ) + + /* + * Test the basic functionality... + */ + + IF ! hb_FileExists( cFile ) + cFile := hb_dirBase() + "test.xml" + ENDIF + + IF ! hb_FileExists( cFile ) + OutStd( "Usage: test filename.xml" ) + + RETURN 1 + ENDIF + + /* parent node */ + tree := mxmlNewElement( MXML_NO_PARENT, "element" ) + IF Empty( tree ) + OutErr( "ERROR: No parent node in basic test!" ) + + RETURN -1 + ENDIF + + nType := hb_mxmlNodeType( tree ) + IF nType != MXML_ELEMENT + OutErr( "ERROR: Parent has type ", Type2Text( nType ), ", expected MXML_ELEMENT!" ) + mxmlDelete( tree ) + + RETURN -1 + + ELSEIF hb_mxmlNodeValue( tree ) != "element" + OutErr( "ERROR: Parent value is ", hb_mxmlNodeValue( tree ), ', expected "element"' ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + mxmlNewInteger( tree, 123 ) + mxmlNewOpaque( tree, "opaque" ) + mxmlNewReal( tree, 123.49 ) + mxmlNewText( tree, .F. , "text" ) + + mxmlLoadString( tree, "string string string", ; + MXML_TEXT_CALLBACK ) + mxmlLoadString( tree, "1 2 3", MXML_INTEGER_CALLBACK ) + mxmlLoadString( tree, "1.0 2.0 3.0", MXML_REAL_CALLBACK ) + mxmlLoadString( tree, "opaque opaque opaque", MXML_OPAQUE_CALLBACK ) + mxmlLoadString( tree, "valuevalue2", ; + MXML_OPAQUE_CALLBACK ) + + /* 1st node */ + node := hb_mxmlNodeChild( tree ) + IF Empty( node ) + OutErr( "ERROR: No first child node in basic test!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + nType := hb_mxmlNodeType( node ) + IF nType != MXML_INTEGER + OutErr( "ERROR: First child has type ", Type2Text( nType ), ", expected MXML_INTEGER!" ) + mxmlDelete( tree ) + + RETURN -1 + + ELSEIF hb_mxmlNodeAsInteger( node ) != 123 + OutErr( "ERROR: First child value is ", hb_mxmlNodeAsInteger( node ), ", expected 123!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + /* 2nd node */ + node := hb_mxmlNodeNext( node ) + IF Empty( node ) + OutErr( "ERROR: No second child node in basic test!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + nType := hb_mxmlNodeType( node ) + IF nType != MXML_OPAQUE + OutErr( "ERROR: Second child has type ", Type2Text( nType ), ", expected MXML_OPAQUE!" ) + mxmlDelete( tree ) + + RETURN -1 + + ELSEIF hb_mxmlNodeAsOpaque( node ) != "opaque" + OutErr( "ERROR: Second child value is ", hb_mxmlNodeAsOpaque( node ), ", expected 'opaque'!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + /* 3rd node */ + node := hb_mxmlNodeNext( node ) + IF Empty( node ) + OutErr( "ERROR: No third child node in basic test!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + nType := hb_mxmlNodeType( node ) + IF nType != MXML_REAL + OutErr( "ERROR: Third child has type ", Type2Text( nType ), ", expected MXML_REAL!" ) + mxmlDelete( tree ) + + RETURN -1 + + ELSEIF hb_mxmlNodeAsReal( node ) != 123.49 + OutErr( "ERROR: Third child value is ", hb_mxmlNodeAsReal( node ), ", expected 123.49!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + /* 4th node */ + node := hb_mxmlNodeNext( node ) + IF Empty( node ) + OutErr( "ERROR: No fourth child node in basic test!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + nType := hb_mxmlNodeType( node ) + IF nType != MXML_TEXT + OutErr( "ERROR: Fourth child has type ", Type2Text( nType ), ", expected MXML_TEXT!" ) + mxmlDelete( tree ) + + RETURN -1 + + ELSEIF /*! hb_mxmlNodeWhitespace( node ) .OR. */ hb_mxmlNodeAsText( node ) != "text" + OutErr( "ERROR: Fourth child value is ", hb_mxmlNodeAsText( node ), ", expected 'text'!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + + FOR i := 1 TO 4 + node := hb_mxmlNodeNext( node ) + + IF Empty( node ) + OutErr( "ERROR: No group", hb_ntos(i), "child node in basic test!" ) + mxmlDelete( tree ) + + RETURN -1 + + ELSEIF hb_mxmlNodeType( node ) != MXML_ELEMENT + OutErr( "ERROR: Group child", i, "has type ", Type2Text( nType ), ", expected MXML_ELEMENT!" ) + mxmlDelete( tree ) + + RETURN -1 + ENDIF + NEXT + + /* + * Test mxmlFindValue... + */ + + node := mxmlFindValue( tree, "*/two" ) + IF Empty( node ) + OutErr( "ERROR: Unable to find value for '*/two'" ) + mxmlDelete( tree ) + + RETURN -2 + ELSEIF hb_mxmlNodeType( node ) != MXML_OPAQUE .OR. hb_mxmlNodeAsOpaque( node ) != "value" + OutErr( "ERROR: Bad value for '*/two'" ) + mxmlDelete( tree ) + + RETURN -2 + ENDIF + + node := mxmlFindValue( tree, "foo/*/two" ) + IF Empty( node ) + OutErr( "ERROR: Unable to find value for 'foo/*/two'" ) + mxmlDelete( tree ) + + RETURN -2 + ELSEIF hb_mxmlNodeType( node ) != MXML_OPAQUE .OR. hb_mxmlNodeAsOpaque( node ) != "value" + OutErr( "ERROR: Bad value for 'foo/*/two'" ) + mxmlDelete( tree ) + + RETURN -2 + ENDIF + + node := mxmlFindValue( tree, "foo/bar/one/two" ) + IF Empty( node ) + OutErr( "ERROR: Unable to find value for 'foo/bar/one/two'" ) + mxmlDelete( tree ) + + RETURN -2 + ELSEIF hb_mxmlNodeType( node ) != MXML_OPAQUE .OR. hb_mxmlNodeAsOpaque( node ) != "value" + OutErr( "ERROR: Bad value for 'foo/bar/one/two'" ) + mxmlDelete( tree ) + + RETURN -2 + ENDIF + + /* + * Test indices... + */ + + OutStd( "Try to create index of all nodes", hb_eol() ) + index := mxmlIndexNew( tree ) + + IF Empty( index ) + OutErr( "ERROR: Unable to create index of all nodes!" ) + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + i := hb_mxmlIndexNumNodes( index ) + IF i != 10 + OutErr( "ERROR: Index of all nodes contains ", i, "nodes; expected 10!" ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + mxmlIndexReset( index ) + IF Empty( mxmlIndexFind( index, "group" ) ) + OutErr( 'ERROR: mxmlIndexFind for "group" failed!' ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + index := NIL + + OutStd( "Try to create index of groups", hb_eol() ) + index := mxmlIndexNew( tree, "group" ) + IF Empty( index ) + OutErr( "ERROR: Unable to create index of groups!" ) + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + i := hb_mxmlIndexNumNodes( index ) + IF i != 4 + OutErr( "ERROR: Index of groups contains ", i, "nodes; expected 4!" ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + mxmlIndexReset( index ) + IF Empty( mxmlIndexEnum( index ) ) + OutErr( "ERROR: mxmlIndexEnum failed!" ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + index := NIL + + OutStd( "Try to create index of type attributes", hb_eol() ) + index := mxmlIndexNew( tree, , "type" ) + IF Empty( index ) + OutErr( "ERROR: Unable to create index of type attributes!" ) + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + i := hb_mxmlIndexNumNodes( index ) + IF i != 3 + OutErr( "ERROR: Index of type attributes contains ", i, "nodes; expected 3!" ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + mxmlIndexReset( index ) + IF Empty( mxmlIndexFind( index, "group" ) ) + OutErr( 'ERROR: mxmlIndexFind for "string" failed!' ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + index := NIL + + OutStd( "Try to create index of elements and attributes", hb_eol() ) + index := mxmlIndexNew( tree, "group", "type" ) + IF Empty( index ) + OutErr( "ERROR: Unable to create index of elements and attributes!" ) + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + i := hb_mxmlIndexNumNodes( index ) + IF i != 3 + OutErr( "ERROR: Index of elements and attributes contains contains ", i, "nodes; expected 3!" ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + mxmlIndexReset( index ) + IF Empty( mxmlIndexFind( index, "group", "string" ) ) + OutErr( 'ERROR: mxmlIndexFind for "string" failed!' ) + index := NIL + mxmlDelete( tree ) + + RETURN -3 + ENDIF + + index := NIL + + /* + * Check the mxmlDelete() works properly... + */ + + FOR i := 1 TO 9 + node := hb_mxmlNodeChild( tree ) + IF ! Empty( node ) + mxmlDelete( node ) + ELSE + OutErr( "ERROR: Child pointer prematurely NULL on child ", hb_ntos( i ) ) + mxmlDelete( tree ) + + RETURN -4 + ENDIF + NEXT + + IF ! Empty( hb_mxmlNodeChild( tree ) ) + OutErr( "ERROR: Child pointer not NULL after deleting all children!" ) + mxmlDelete( tree ) + + RETURN -4 + ENDIF + + IF ! Empty( hb_mxmlNodeLastChild( tree ) ) + OutErr( "ERROR: Last child pointer not NULL after deleting all children!" ) + mxmlDelete( tree ) + + RETURN -4 + ENDIF + + mxmlDelete( tree ) + + /* + * Verify that mxmlFindElement() and indirectly mxmlWalkNext() work + * properly... + */ + + tree := mxmlLoadFile( NIL, cFile, @type_cb() ) + // tree := mxmlLoadString( NIL, hb_memoRead( cFile ), @type_cb() ) + + + node := mxmlFindElement( tree, tree, "choice", NIL, NIL, MXML_DESCEND ) + IF Empty( node ) + OutErr( "Unable to find first element in XML tree!" ) + mxmlDelete( tree ) + + RETURN -5 + ENDIF + + IF Empty( node := mxmlFindElement( node, tree, "choice", NIL, NIL, MXML_NO_DESCEND ) ) + OutErr( "Unable to find second element in XML tree!" ) + mxmlDelete( tree ) + + RETURN -5 + ENDIF + + mxmlRemove( node ) + + /* + * Save & Print the XML tree... + */ + + cBuffer := "" + nLen := mxmlSaveString( tree, @cBuffer, @whitespace_cb() ) + cBuffer := Space( abs( nLen ) ) + + IF ( mxmlSaveString( tree, @cBuffer, @whitespace_cb() ) > 0 ) + hb_memoWrit( "test2.xml", cBuffer + hb_eol() ) + ENDIF + OutStd( cBuffer + hb_eol() ) + + mxmlDelete( tree ) + + cBuffer := mxmlSaveAllocString( node, @whitespace_cb() ) + IF Len( cBuffer ) > 0 + hb_memoWrit( "test3.xml", cBuffer + hb_eol() ) + ENDIF + + mxmlSaveFile( node, "test4.xml", @whitespace_cb() ) + + mxmlDelete( node ) + + OutStd( "--- The End! ---", hb_eol() ) + + RETURN 0 + +PROCEDURE my_mxmlError( cErrorMsg ) + + OutErr( cErrorMsg, hb_eol() ) + + RETURN + +STATIC FUNCTION Type2Text( nType ) + + LOCAL aTypes := { "MXML_ELEMENT", "MXML_INTEGER", "MXML_OPAQUE", "MXML_REAL", "MXML_TEXT" } + + RETURN iif( nType < MXML_ELEMENT .OR. nType > MXML_TEXT, "UNKNOWN", aTypes[ nType + 1 ] ) + +/* mxmlLoadString */ + +FUNCTION type_cb( node ) + + LOCAL nResult + LOCAL cType + + /* You can lookup attributes and/or use the element name, hierarchy, etc... */ + + IF Empty( cType := mxmlElementGetAttr( node, "type" ) ) + cType := hb_mxmlNodeAsElementName( node ) + ENDIF + + SWITCH Lower( cType ) + CASE "integer" + nResult := MXML_INTEGER + EXIT + + CASE "opaque" + CASE "pre" + nResult := MXML_OPAQUE + EXIT + + CASE "real" + nResult := MXML_REAL + EXIT + + CASE "text" + nResult := MXML_TEXT + EXIT + + OTHERWISE + nResult := MXML_TEXT + EXIT + ENDSWITCH + + RETURN nResult + +/* mxmlSaveString */ + +FUNCTION whitespace_cb( node, where ) + + LOCAL parent /* Parent node */ + LOCAL nLevel := -1 /* Indentation level */ + LOCAL name /* Name of element */ + + name := hb_mxmlNodeAsElementName( node ) + /* OutStd( name, hb_eol() ) */ + + /* + * We can conditionally break to a new line before or after any element. + * These are just common HTML elements... + */ + + SWITCH Lower( name ) + CASE "html" + CASE "head" + CASE "body" + CASE "pre" + CASE "p" + CASE "h1" + CASE "h2" + CASE "h3" + CASE "h4" + CASE "h5" + CASE "h6" + /* Newlines before open and after close... */ + IF where == MXML_WS_BEFORE_OPEN .OR. where == MXML_WS_AFTER_CLOSE + RETURN hb_eol() + ENDIF + EXIT + + CASE "dl" + CASE "ol" + CASE "ul" + /* Put a newline before and after list elements... */ + IF .t. + RETURN hb_eol() /* Warning W0028 Unreachable code */ + ENDIF + EXIT + + CASE "dd" + CASE "dt" + CASE "li" + /* Put a tab before
  • 's,
    's, and
    's, and a newline after them... */ + IF where == MXML_WS_BEFORE_OPEN + RETURN Chr( HB_K_TAB ) + ELSEIF where == MXML_WS_AFTER_CLOSE + RETURN hb_eol() + ENDIF + EXIT + ENDSWITCH + + IF Left( name, 4 ) == "?xml" + IF where == MXML_WS_AFTER_OPEN + RETURN hb_eol() + ELSE + RETURN NIL + ENDIF + + ELSEIF where == MXML_WS_BEFORE_OPEN .OR. ; + ( ( name == "choice" .OR. name == "option" ) .AND. ; + where == MXML_WS_BEFORE_CLOSE ) + + parent := hb_mxmlNodeParent( node ) + DO WHILE ! Empty( parent ) + nLevel++ + parent := hb_mxmlNodeParent( parent ) + ENDDO + + IF nLevel > 8 + nLevel := 8 + ELSEIF nLevel < 0 + nLevel := 0 + ENDIF + + RETURN Replicate( Chr( HB_K_TAB ), nLevel ) + + ELSEIF where == MXML_WS_AFTER_CLOSE .OR. ; + ( ( name == "group".OR. name == "option" .OR. name == "choice" ) .AND. ; + where == MXML_WS_AFTER_OPEN ) + RETURN hb_eol() + + ELSEIF where == MXML_WS_AFTER_OPEN .AND. Empty( hb_mxmlNodeChild( node ) ) + RETURN hb_eol() + ENDIF + + /* Return NIL for no added whitespace... */ + + RETURN NIL + \ No newline at end of file diff --git a/harbour/contrib/hbmxml/tests/test.xml b/harbour/contrib/hbmxml/tests/test.xml new file mode 100644 index 0000000000..044304ed7b --- /dev/null +++ b/harbour/contrib/hbmxml/tests/test.xml @@ -0,0 +1,29 @@ + + + + 123 + Now is the time for all good men to come to the aid of their +country. + + + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/AUTHORS b/harbour/contrib/hbxdiff/3rd/libxdiff/AUTHORS new file mode 100644 index 0000000000..32e63cbc56 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/AUTHORS @@ -0,0 +1,2 @@ +Davide Libenzi + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/COPYING b/harbour/contrib/hbxdiff/3rd/libxdiff/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/config.h b/harbour/contrib/hbxdiff/3rd/libxdiff/config.h new file mode 100644 index 0000000000..79fc365999 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/config.h @@ -0,0 +1,106 @@ +/* + * $Id$ + */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the `free' function. */ +#define HAVE_FREE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `malloc' function. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the `memchr' function. */ +#define HAVE_MEMCHR 1 + +/* Define to 1 if you have the `memcmp' function. */ +#define HAVE_MEMCMP 1 + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `realloc' function. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlen' function. */ +#define HAVE_STRLEN 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#if ! defined( __BORLANDC__ ) +#define HAVE_UNISTD_H 1 +#endif + +/* Name of package */ +#define PACKAGE "libxdiff" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libxdiff" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libxdiff 0.23" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libxdiff" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.23" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.23" + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.c new file mode 100644 index 0000000000..8802484730 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.c @@ -0,0 +1,70 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + + +/* largest prime smaller than 65536 */ +#define BASE 65521L + +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ +#define NMAX 5552 + + +#define DO1(buf, i) { s1 += buf[i]; s2 += s1; } +#define DO2(buf, i) DO1(buf, i); DO1(buf, i + 1); +#define DO4(buf, i) DO2(buf, i); DO2(buf, i + 2); +#define DO8(buf, i) DO4(buf, i); DO4(buf, i + 4); +#define DO16(buf) DO8(buf, 0); DO8(buf, 8); + + + +unsigned long xdl_adler32(unsigned long adler, unsigned char const *buf, + unsigned int len) { + int k; + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + + if (!buf) + return 1; + + while (len > 0) { + k = len < NMAX ? len :NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) + do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + + return (s2 << 16) | s1; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.h new file mode 100644 index 0000000000..e67e2b2596 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xadler32.h @@ -0,0 +1,34 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XADLER32_H) +#define XADLER32_H + + + +unsigned long xdl_adler32(unsigned long adler, unsigned char const *buf, + unsigned int len); + + + +#endif /* #if !defined(XADLER32_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xalloc.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xalloc.c new file mode 100644 index 0000000000..b084d295a2 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xalloc.c @@ -0,0 +1,51 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + + +static memallocator_t xmalt = {NULL, NULL, NULL}; + + + +int xdl_set_allocator(memallocator_t const *malt) { + xmalt = *malt; + return 0; +} + + +void *xdl_malloc(unsigned int size) { + return xmalt.malloc ? xmalt.malloc(xmalt.priv, size): NULL; +} + + +void xdl_free(void *ptr) { + if (xmalt.free) + xmalt.free(xmalt.priv, ptr); +} + + +void *xdl_realloc(void *ptr, unsigned int size) { + return xmalt.realloc ? xmalt.realloc(xmalt.priv, ptr, size): NULL; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.c new file mode 100644 index 0000000000..3ef28c9410 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.c @@ -0,0 +1,315 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + +typedef struct s_bdrecord { + struct s_bdrecord *next; + unsigned long fp; + char const *ptr; +} bdrecord_t; + +typedef struct s_bdfile { + char const *data, *top; + chastore_t cha; + unsigned int fphbits; + bdrecord_t **fphash; +} bdfile_t; + + + +static int xdl_prepare_bdfile(mmbuffer_t *mmb, long fpbsize, bdfile_t *bdf) { + unsigned int fphbits; + long i, size, hsize; + char const *base, *data, *top; + bdrecord_t *brec; + bdrecord_t **fphash; + + fphbits = xdl_hashbits((unsigned int) (mmb->size / fpbsize) + 1); + hsize = 1 << fphbits; + if (!(fphash = (bdrecord_t **) xdl_malloc(hsize * sizeof(bdrecord_t *)))) { + + return -1; + } + for (i = 0; i < hsize; i++) + fphash[i] = NULL; + + if (xdl_cha_init(&bdf->cha, sizeof(bdrecord_t), hsize / 4 + 1) < 0) { + + xdl_free(fphash); + return -1; + } + + if (!(size = mmb->size)) { + bdf->data = bdf->top = NULL; + } else { + bdf->data = data = base = mmb->ptr; + bdf->top = top = mmb->ptr + mmb->size; + + if ((data += (size / fpbsize) * fpbsize) == top) + data -= fpbsize; + + for (; data >= base; data -= fpbsize) { + if (!(brec = (bdrecord_t *) xdl_cha_alloc(&bdf->cha))) { + + xdl_cha_free(&bdf->cha); + xdl_free(fphash); + return -1; + } + + brec->fp = xdl_adler32(0, (unsigned char const *) data, + XDL_MIN(fpbsize, (long) (top - data))); + brec->ptr = data; + + i = (long) XDL_HASHLONG(brec->fp, fphbits); + brec->next = fphash[i]; + fphash[i] = brec; + } + } + + bdf->fphbits = fphbits; + bdf->fphash = fphash; + + return 0; +} + + +static void xdl_free_bdfile(bdfile_t *bdf) { + + xdl_free(bdf->fphash); + xdl_cha_free(&bdf->cha); +} + + +unsigned long xdl_mmb_adler32(mmbuffer_t *mmb) { + + return mmb->size ? xdl_adler32(0, (unsigned char const *) mmb->ptr, mmb->size): 0; +} + + +unsigned long xdl_mmf_adler32(mmfile_t *mmf) { + unsigned long fp = 0; + long size; + char const *blk; + + if ((blk = (char const *) xdl_mmfile_first(mmf, &size)) != NULL) { + do { + fp = xdl_adler32(fp, (unsigned char const *) blk, size); + } while ((blk = (char const *) xdl_mmfile_next(mmf, &size)) != NULL); + } + return fp; +} + + +int xdl_bdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, bdiffparam_t const *bdp, xdemitcb_t *ecb) { + long i, rsize, size, bsize, csize, msize, moff; + unsigned long fp; + char const *blk, *base, *data, *top, *ptr1, *ptr2; + bdrecord_t *brec; + bdfile_t bdf; + mmbuffer_t mb[2]; + unsigned char cpybuf[32]; + + if ((bsize = bdp->bsize) < XDL_MIN_BLKSIZE) + bsize = XDL_MIN_BLKSIZE; + if (xdl_prepare_bdfile(mmb1, bsize, &bdf) < 0) { + + return -1; + } + + /* + * Prepare and emit the binary patch file header. It will be used + * to verify that that file being patched matches in size and fingerprint + * the one that generated the patch. + */ + fp = xdl_mmb_adler32(mmb1); + size = mmb1->size; + XDL_LE32_PUT(cpybuf, fp); + XDL_LE32_PUT(cpybuf + 4, size); + + mb[0].ptr = (char *) cpybuf; + mb[0].size = 4 + 4; + + if (ecb->outf(ecb->priv, mb, 1) < 0) { + + xdl_free_bdfile(&bdf); + return -1; + } + + if ((blk = (char const *) mmb2->ptr) != NULL) { + size = mmb2->size; + for (base = data = blk, top = data + size; data < top;) { + rsize = XDL_MIN(bsize, (long) (top - data)); + fp = xdl_adler32(0, (unsigned char const *) data, rsize); + + i = (long) XDL_HASHLONG(fp, bdf.fphbits); + for (msize = 0, brec = bdf.fphash[i]; brec; brec = brec->next) + if (brec->fp == fp) { + csize = XDL_MIN((long) (top - data), (long) (bdf.top - brec->ptr)); + for (ptr1 = brec->ptr, ptr2 = data; csize && *ptr1 == *ptr2; + csize--, ptr1++, ptr2++); + + if ((csize = (long) (ptr1 - brec->ptr)) > msize) { + moff = (long) (brec->ptr - bdf.data); + msize = csize; + } + } + + if (msize < XDL_COPYOP_SIZE) { + data++; + } else { + if (data > base) { + i = (long) (data - base); + if (i > 255) { + cpybuf[0] = XDL_BDOP_INSB; + XDL_LE32_PUT(cpybuf + 1, i); + + mb[0].ptr = (char *) cpybuf; + mb[0].size = XDL_INSBOP_SIZE; + } else { + cpybuf[0] = XDL_BDOP_INS; + cpybuf[1] = (unsigned char) i; + + mb[0].ptr = (char *) cpybuf; + mb[0].size = 2; + } + mb[1].ptr = (char *) base; + mb[1].size = i; + + if (ecb->outf(ecb->priv, mb, 2) < 0) { + + xdl_free_bdfile(&bdf); + return -1; + } + } + + data += msize; + + cpybuf[0] = XDL_BDOP_CPY; + XDL_LE32_PUT(cpybuf + 1, moff); + XDL_LE32_PUT(cpybuf + 5, msize); + + mb[0].ptr = (char *) cpybuf; + mb[0].size = XDL_COPYOP_SIZE; + + if (ecb->outf(ecb->priv, mb, 1) < 0) { + + xdl_free_bdfile(&bdf); + return -1; + } + base = data; + } + } + if (data > base) { + i = (long) (data - base); + if (i > 255) { + cpybuf[0] = XDL_BDOP_INSB; + XDL_LE32_PUT(cpybuf + 1, i); + + mb[0].ptr = (char *) cpybuf; + mb[0].size = XDL_INSBOP_SIZE; + } else { + cpybuf[0] = XDL_BDOP_INS; + cpybuf[1] = (unsigned char) i; + + mb[0].ptr = (char *) cpybuf; + mb[0].size = 2; + } + mb[1].ptr = (char *) base; + mb[1].size = i; + + if (ecb->outf(ecb->priv, mb, 2) < 0) { + + xdl_free_bdfile(&bdf); + return -1; + } + } + } + + xdl_free_bdfile(&bdf); + + return 0; +} + + +int xdl_bdiff(mmfile_t *mmf1, mmfile_t *mmf2, bdiffparam_t const *bdp, xdemitcb_t *ecb) { + mmbuffer_t mmb1, mmb2; + + if (!xdl_mmfile_iscompact(mmf1) || !xdl_mmfile_iscompact(mmf2)) { + + return -1; + } + + if ((mmb1.ptr = (char *) xdl_mmfile_first(mmf1, &mmb1.size)) == NULL) + mmb1.size = 0; + if ((mmb2.ptr = (char *) xdl_mmfile_first(mmf2, &mmb2.size)) == NULL) + mmb2.size = 0; + + return xdl_bdiff_mb(&mmb1, &mmb2, bdp, ecb); +} + + +long xdl_bdiff_tgsize(mmfile_t *mmfp) { + long tgsize = 0, size, off, csize; + char const *blk; + unsigned char const *data, *top; + + if ((blk = (char const *) xdl_mmfile_first(mmfp, &size)) == NULL || + size < XDL_BPATCH_HDR_SIZE) { + + return -1; + } + blk += XDL_BPATCH_HDR_SIZE; + size -= XDL_BPATCH_HDR_SIZE; + + do { + for (data = (unsigned char const *) blk, top = data + size; + data < top;) { + if (*data == XDL_BDOP_INS) { + data++; + csize = (long) *data++; + tgsize += csize; + data += csize; + } else if (*data == XDL_BDOP_INSB) { + data++; + XDL_LE32_GET(data, csize); + data += 4; + tgsize += csize; + data += csize; + } else if (*data == XDL_BDOP_CPY) { + data++; + XDL_LE32_GET(data, off); + data += 4; + XDL_LE32_GET(data, csize); + data += 4; + tgsize += csize; + } else { + + return -1; + } + } + } while ((blk = (char const *) xdl_mmfile_next(mmfp, &size)) != NULL); + + return tgsize; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.h new file mode 100644 index 0000000000..ff9da8d6b2 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xbdiff.h @@ -0,0 +1,40 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XBDIFF_H) +#define XBDIFF_H + + +#define XDL_BPATCH_HDR_SIZE (4 + 4) +#define XDL_MIN_BLKSIZE 16 +#define XDL_INSBOP_SIZE (1 + 4) +#define XDL_COPYOP_SIZE (1 + 4 + 4) + + + +unsigned long xdl_mmb_adler32(mmbuffer_t *mmb); +unsigned long xdl_mmf_adler32(mmfile_t *mmf); + + + +#endif /* #if !defined(XBDIFF_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xbpatchi.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xbpatchi.c new file mode 100644 index 0000000000..4497b3879f --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xbpatchi.c @@ -0,0 +1,336 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + +#define XDL_MOBF_MINALLOC 128 + + +typedef struct s_mmoffbuffer { + long off, size; + char *ptr; +} mmoffbuffer_t; + + + +static int xdl_copy_range(mmfile_t *mmf, long off, long size, xdemitcb_t *ecb) { + if (xdl_seek_mmfile(mmf, off) < 0) { + + return -1; + } + if (xdl_copy_mmfile(mmf, size, ecb) != size) { + + return -1; + } + + return 0; +} + + +int xdl_bpatch(mmfile_t *mmf, mmfile_t *mmfp, xdemitcb_t *ecb) { + long size, off, csize, osize; + unsigned long fp, ofp; + char const *blk; + unsigned char const *data, *top; + mmbuffer_t mb; + + if ((blk = (char const *) xdl_mmfile_first(mmfp, &size)) == NULL || + size < XDL_BPATCH_HDR_SIZE) { + + return -1; + } + ofp = xdl_mmf_adler32(mmf); + osize = xdl_mmfile_size(mmf); + XDL_LE32_GET(blk, fp); + XDL_LE32_GET(blk + 4, csize); + if (fp != ofp || csize != osize) { + + return -1; + } + + blk += XDL_BPATCH_HDR_SIZE; + size -= XDL_BPATCH_HDR_SIZE; + + do { + for (data = (unsigned char const *) blk, top = data + size; + data < top;) { + if (*data == XDL_BDOP_INS) { + data++; + + mb.size = (long) *data++; + mb.ptr = (char *) data; + data += mb.size; + + if (ecb->outf(ecb->priv, &mb, 1) < 0) { + + return -1; + } + } else if (*data == XDL_BDOP_INSB) { + data++; + XDL_LE32_GET(data, csize); + data += 4; + + mb.size = csize; + mb.ptr = (char *) data; + data += mb.size; + + if (ecb->outf(ecb->priv, &mb, 1) < 0) { + + return -1; + } + } else if (*data == XDL_BDOP_CPY) { + data++; + XDL_LE32_GET(data, off); + data += 4; + XDL_LE32_GET(data, csize); + data += 4; + + if (xdl_copy_range(mmf, off, csize, ecb) < 0) { + + return -1; + } + } else { + + return -1; + } + } + } while ((blk = (char const *) xdl_mmfile_next(mmfp, &size)) != NULL); + + return 0; +} + + +static unsigned long xdl_mmob_adler32(mmoffbuffer_t *obf, int n) { + unsigned long ha; + + for (ha = 0; n > 0; n--, obf++) + ha = xdl_adler32(ha, (unsigned char const *) obf->ptr, obf->size); + + return ha; +} + + +static long xdl_mmob_size(mmoffbuffer_t *obf, int n) { + + return n > 0 ? obf[n - 1].off + obf[n - 1].size: 0; +} + + +static mmoffbuffer_t *xdl_mmob_new(mmoffbuffer_t **probf, int *pnobf, int *paobf) { + int aobf; + mmoffbuffer_t *cobf, *rrobf; + + if (*pnobf >= *paobf) { + aobf = 2 * (*paobf) + 1; + if ((rrobf = (mmoffbuffer_t *) + xdl_realloc(*probf, aobf * sizeof(mmoffbuffer_t))) == NULL) { + + return NULL; + } + *probf = rrobf; + *paobf = aobf; + } + cobf = (*probf) + (*pnobf); + (*pnobf)++; + + return cobf; +} + + +static int xdl_mmob_find_cntr(mmoffbuffer_t *obf, int n, long off) { + int i, lo, hi; + + for (lo = -1, hi = n; hi - lo > 1;) { + i = (hi + lo) / 2; + if (off < obf[i].off) + hi = i; + else + lo = i; + } + + return (lo >= 0 && off >= obf[lo].off && off < obf[lo].off + obf[lo].size) ? lo: -1; +} + + +static int xdl_bmerge(mmoffbuffer_t *obf, int n, mmbuffer_t *mbfp, mmoffbuffer_t **probf, + int *pnobf) { + int i, aobf, nobf; + long ooff, off, csize; + unsigned long fp, ofp; + unsigned char const *data, *top; + mmoffbuffer_t *robf, *cobf; + + if (mbfp->size < XDL_BPATCH_HDR_SIZE) { + + return -1; + } + data = (unsigned char const *) mbfp->ptr; + top = data + mbfp->size; + + ofp = xdl_mmob_adler32(obf, n); + XDL_LE32_GET(data, fp); + data += 4; + XDL_LE32_GET(data, csize); + data += 4; + if (fp != ofp || csize != xdl_mmob_size(obf, n)) { + + return -1; + } + aobf = XDL_MOBF_MINALLOC; + nobf = 0; + if ((robf = (mmoffbuffer_t *) xdl_malloc(aobf * sizeof(mmoffbuffer_t))) == NULL) { + + return -1; + } + + for (ooff = 0; data < top;) { + if (*data == XDL_BDOP_INS) { + data++; + + if ((cobf = xdl_mmob_new(&robf, &nobf, &aobf)) == NULL) { + + xdl_free(robf); + return -1; + } + cobf->off = ooff; + cobf->size = (long) *data++; + cobf->ptr = (char *) data; + + data += cobf->size; + ooff += cobf->size; + } else if (*data == XDL_BDOP_INSB) { + data++; + XDL_LE32_GET(data, csize); + data += 4; + + if ((cobf = xdl_mmob_new(&robf, &nobf, &aobf)) == NULL) { + + xdl_free(robf); + return -1; + } + cobf->off = ooff; + cobf->size = csize; + cobf->ptr = (char *) data; + + data += cobf->size; + ooff += cobf->size; + } else if (*data == XDL_BDOP_CPY) { + data++; + XDL_LE32_GET(data, off); + data += 4; + XDL_LE32_GET(data, csize); + data += 4; + + if ((i = xdl_mmob_find_cntr(obf, n, off)) < 0) { + + xdl_free(robf); + return -1; + } + off -= obf[i].off; + for (; i < n && csize > 0; i++, off = 0) { + if ((cobf = xdl_mmob_new(&robf, &nobf, &aobf)) == NULL) { + + xdl_free(robf); + return -1; + } + cobf->off = ooff; + cobf->size = XDL_MIN(csize, obf[i].size - off); + cobf->ptr = obf[i].ptr + off; + + ooff += cobf->size; + csize -= cobf->size; + } + if (csize > 0) { + + xdl_free(robf); + return -1; + } + } else { + + xdl_free(robf); + return -1; + } + } + *probf = robf; + *pnobf = nobf; + + return 0; +} + + +static int xdl_bmerge_synt(mmoffbuffer_t *obf, int n, xdemitcb_t *ecb) { + int i; + mmbuffer_t *mb; + + if ((mb = (mmbuffer_t *) xdl_malloc(n * sizeof(mmbuffer_t))) == NULL) { + + return -1; + } + for (i = 0; i < n; i++) { + mb[i].ptr = obf[i].ptr; + mb[i].size = obf[i].size; + } + if (ecb->outf(ecb->priv, mb, n) < 0) { + + xdl_free(mb); + return -1; + } + xdl_free(mb); + + return 0; +} + + +int xdl_bpatch_multi(mmbuffer_t *base, mmbuffer_t *mbpch, int n, xdemitcb_t *ecb) { + int i, nobf, fnobf; + mmoffbuffer_t *obf, *fobf; + + nobf = 1; + if ((obf = (mmoffbuffer_t *) xdl_malloc(nobf * sizeof(mmoffbuffer_t))) == NULL) { + + return -1; + } + obf->off = 0; + obf->ptr = base->ptr; + obf->size = base->size; + for (i = 0; i < n; i++) { + if (xdl_bmerge(obf, nobf, &mbpch[i], &fobf, &fnobf) < 0) { + + xdl_free(obf); + return -1; + } + xdl_free(obf); + + obf = fobf; + nobf = fnobf; + } + if (xdl_bmerge_synt(obf, nobf, ecb) < 0) { + + xdl_free(obf); + return -1; + } + xdl_free(obf); + + return 0; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.h new file mode 100644 index 0000000000..d0512167d7 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.h @@ -0,0 +1,135 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XDIFF_H) +#define XDIFF_H + +#ifdef __cplusplus +extern "C" { +#endif /* #ifdef __cplusplus */ + + +#define XDF_NEED_MINIMAL (1 << 1) + +#define XDL_PATCH_NORMAL '-' +#define XDL_PATCH_REVERSE '+' +#define XDL_PATCH_MODEMASK ((1 << 8) - 1) +#define XDL_PATCH_IGNOREBSPACE (1 << 8) + +#define XDL_MMB_READONLY (1 << 0) + +#define XDL_MMF_ATOMIC (1 << 0) + +#define XDL_BDOP_INS 1 +#define XDL_BDOP_CPY 2 +#define XDL_BDOP_INSB 3 + + + +typedef struct s_memallocator { + void *priv; + void *(*malloc)(void *, unsigned int); + void (*free)(void *, void *); + void *(*realloc)(void *, void *, unsigned int); +} memallocator_t; + +typedef struct s_mmblock { + struct s_mmblock *next; + unsigned long flags; + long size, bsize; + char *ptr; +} mmblock_t; + +typedef struct s_mmfile { + unsigned long flags; + mmblock_t *head, *tail; + long bsize, fsize, rpos; + mmblock_t *rcur, *wcur; +} mmfile_t; + +typedef struct s_mmbuffer { + char *ptr; + long size; +} mmbuffer_t; + +typedef struct s_xpparam { + unsigned long flags; +} xpparam_t; + +typedef struct s_xdemitcb { + void *priv; + int (*outf)(void *, mmbuffer_t *, int); +} xdemitcb_t; + +typedef struct s_xdemitconf { + long ctxlen; +} xdemitconf_t; + +typedef struct s_bdiffparam { + long bsize; +} bdiffparam_t; + + +int xdl_set_allocator(memallocator_t const *malt); +void *xdl_malloc(unsigned int size); +void xdl_free(void *ptr); +void *xdl_realloc(void *ptr, unsigned int size); + +int xdl_init_mmfile(mmfile_t *mmf, long bsize, unsigned long flags); +void xdl_free_mmfile(mmfile_t *mmf); +int xdl_mmfile_iscompact(mmfile_t *mmf); +int xdl_seek_mmfile(mmfile_t *mmf, long off); +long xdl_read_mmfile(mmfile_t *mmf, void *data, long size); +long xdl_write_mmfile(mmfile_t *mmf, void const *data, long size); +long xdl_writem_mmfile(mmfile_t *mmf, mmbuffer_t *mb, int nbuf); +void *xdl_mmfile_writeallocate(mmfile_t *mmf, long size); +long xdl_mmfile_ptradd(mmfile_t *mmf, char *ptr, long size, unsigned long flags); +long xdl_copy_mmfile(mmfile_t *mmf, long size, xdemitcb_t *ecb); +void *xdl_mmfile_first(mmfile_t *mmf, long *size); +void *xdl_mmfile_next(mmfile_t *mmf, long *size); +long xdl_mmfile_size(mmfile_t *mmf); +int xdl_mmfile_cmp(mmfile_t *mmf1, mmfile_t *mmf2); +int xdl_mmfile_compact(mmfile_t *mmfo, mmfile_t *mmfc, long bsize, unsigned long flags); + +int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, + xdemitconf_t const *xecfg, xdemitcb_t *ecb); +int xdl_patch(mmfile_t *mf, mmfile_t *mfp, int mode, xdemitcb_t *ecb, + xdemitcb_t *rjecb); + +int xdl_merge3(mmfile_t *mmfo, mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb, + xdemitcb_t *rjecb); + +int xdl_bdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, bdiffparam_t const *bdp, xdemitcb_t *ecb); +int xdl_bdiff(mmfile_t *mmf1, mmfile_t *mmf2, bdiffparam_t const *bdp, xdemitcb_t *ecb); +int xdl_rabdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, xdemitcb_t *ecb); +int xdl_rabdiff(mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb); +long xdl_bdiff_tgsize(mmfile_t *mmfp); +int xdl_bpatch(mmfile_t *mmf, mmfile_t *mmfp, xdemitcb_t *ecb); +int xdl_bpatch_multi(mmbuffer_t *base, mmbuffer_t *mbpch, int n, xdemitcb_t *ecb); + + +#ifdef __cplusplus +} +#endif /* #ifdef __cplusplus */ + +#endif /* #if !defined(XDIFF_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbc b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbc new file mode 100644 index 0000000000..86f6254c46 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbc @@ -0,0 +1,5 @@ +# +# $Id$ +# + +libs=${hb_name}${__HB_DYN__} diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbp b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbp new file mode 100644 index 0000000000..8336c36037 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.hbp @@ -0,0 +1,64 @@ +# +# $Id$ +# + +#-stop + +-hblib +-inc + +-o${hb_targetname} + +-warn=low +-cpp=no + +-cflag=-DHAVE_CONFIG_H + +xadler32.c +xalloc.c +xbdiff.c +xbpatchi.c +xdiffi.c +xemit.c +xmerge3.c +xmissing.c +xpatchi.c +xprepare.c +xrabdiff.c +xrabply.c +xutils.c +xversion.c + +# ORIGIN http://www.xmailserver.org/xdiff-lib.html +# VER 0.23 +# URL http://www.xmailserver.org/libxdiff-0.23.tar.gz +# DIFF +# +# MAP AUTHORS +# MAP COPYING +# MAP man/xdiff.txt xdiff.txt +# MAP xdiff/xadler32.c xadler32.c +# MAP xdiff/xadler32.h xadler32.h +# MAP xdiff/xalloc.c xalloc.c +# MAP xdiff/xbdiff.c xbdiff.c +# MAP xdiff/xbdiff.h xbdiff.h +# MAP xdiff/xbpatchi.c xbpatchi.c +# MAP xdiff/xdiff.h xdiff.h +# MAP xdiff/xdiffi.c xdiffi.c +# MAP xdiff/xdiffi.h xdiffi.h +# MAP xdiff/xemit.c xemit.c +# MAP xdiff/xemit.h xemit.h +# MAP xdiff/xinclude.h xinclude.h +# MAP xdiff/xmacros.h xmacros.h +# MAP xdiff/xmerge3.c xmerge3.c +# MAP xdiff/xmissing.c xmissing.c +# MAP xdiff/xmissing.h xmissing.h +# MAP xdiff/xpatchi.c xpatchi.c +# MAP xdiff/xprepare.c xprepare.c +# MAP xdiff/xprepare.h xprepare.h +# MAP xdiff/xrabdiff.c xrabdiff.c +# MAP xdiff/xrabply.c xrabply.c +# MAP xdiff/xtypes.h xtypes.h +# MAP xdiff/xutils.c xutils.c +# MAP xdiff/xutils.h xutils.h +# MAP xdiff/xversion.c xversion.c diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.txt b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.txt new file mode 100644 index 0000000000..1415bb06e7 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiff.txt @@ -0,0 +1,611 @@ +LibXDiff(3) File Differential Library LibXDiff(3) + + + +NAME + xdl_set_allocator, xdl_malloc, xdl_free, xdl_realloc, xdl_init_mmfile, + xdl_free_mmfile, xdl_mmfile_iscompact, xdl_seek_mmfile, + xdl_read_mmfile, xdl_write_mmfile, xdl_writem_mmfile, + xdl_mmfile_writeallocate, xdl_mmfile_ptradd, xdl_mmfile_first, + xdl_mmfile_next, xdl_mmfile_size, xdl_mmfile_cmp, xdl_mmfile_compact, + xdl_diff, xdl_patch, xdl_merge3, xdl_bdiff_mb, xdl_bdiff, xdl_rabd- + iff_mb, xdl_rabdiff, xdl_bdiff_tgsize, xdl_bpatch - File Differential + Library support functions + + +SYNOPSIS + #include + + int xdl_set_allocator(memallocator_t const *malt); + void *xdl_malloc(unsigned int size); + void xdl_free(void *ptr); + void *xdl_realloc(void *ptr, unsigned int nsize); + int xdl_init_mmfile(mmfile_t *mmf, long bsize, unsigned long flags); + void xdl_free_mmfile(mmfile_t *mmf); + int xdl_mmfile_iscompact(mmfile_t *mmf); + int xdl_seek_mmfile(mmfile_t *mmf, long off); + long xdl_read_mmfile(mmfile_t *mmf, void *data, long size); + long xdl_write_mmfile(mmfile_t *mmf, void const *data, long size); + long xdl_writem_mmfile(mmfile_t *mmf, mmbuffer_t *mb, int nbuf); + void *xdl_mmfile_writeallocate(mmfile_t *mmf, long size); + long xdl_mmfile_ptradd(mmfile_t *mmf, char *ptr, long size, unsigned long flags); + void *xdl_mmfile_first(mmfile_t *mmf, long *size); + void *xdl_mmfile_next(mmfile_t *mmf, long *size); + long xdl_mmfile_size(mmfile_t *mmf); + int xdl_mmfile_cmp(mmfile_t *mmf1, mmfile_t *mmf2); + int xdl_mmfile_compact(mmfile_t *mmfo, mmfile_t *mmfc, long bsize, unsigned long flags); + int xdl_diff(mmfile_t *mmf1, mmfile_t *mmf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); + int xdl_patch(mmfile_t *mmf, mmfile_t *mmfp, int mode, xdemitcb_t *ecb, xdemitcb_t *rjecb); + int xdl_merge3(mmfile_t *mmfo, mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb, xdemitcb_t *rjecb); + int xdl_bdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, bdiffparam_t const *bdp, xdemitcb_t *ecb); + int xdl_bdiff(mmfile_t *mmf1, mmfile_t *mmf2, bdiffparam_t const *bdp, xdemitcb_t *ecb); + int xdl_rabdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, xdemitcb_t *ecb); + int xdl_rabdiff(mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb); + long xdl_bdiff_tgsize(mmfile_t *mmfp); + int xdl_bpatch(mmfile_t *mmf, mmfile_t *mmfp, xdemitcb_t *ecb); + + +DESCRIPTION + The LibXDiff library implements basic and yet complete functionalities + to create file differences/patches to both binary and text files. The + library uses memory files as file abstraction to achieve both perfor- + mance and portability. For binary files, LibXDiff implements both (with + some modification) the algorithm described in File System Support for + Delta Compression by Joshua P. MacDonald, and the method described in + Fingerprinting by Random Polynomials by Michael O. Rabin. While for + text files it follows directives described in An O(ND) Difference Algo- + rithm and Its Variations by Eugene W. Myers. Memory files used by the + library are basically a collection of buffers that store the file con- + tent. There are two different requirements for memory files when passed + to diff/patch functions. Text files for diff/patch functions require + that a single line do not have to spawn across two different memory + file blocks. Binary diff/patch functions require memory files to be + compact. A compact memory files is a file whose content is stored + inside a single block. Functionalities inside the library are avail- + able to satisfy these rules. Using the XDL_MMF_ATOMIC memory file flag + it is possible to make writes to not split the written record across + different blocks, while the functions xdl_mmfile_iscompact() , + xdl_mmfile_compact() and xdl_mmfile_writeallocate() are usefull to test + if the file is compact and to create a compacted version of the file + itself. The text file differential output uses the raw unified output + format, by omitting the file header since the result is always relative + to a single compare operation (between two files). The output format of + the binary patch file is proprietary (and binary) and it is basically a + collection of copy and insert commands, like described inside the Mac- + Donald paper. + + + + Functions + The following functions are defined: + + int xdl_set_allocator(memallocator_t const *malt); + + The LibXDiff library enable the user to set its own memory allo- + cator, that will be used for all the following memory requests. + The allocator must be set before to start calling the LibXDiff + library with a call to xdl_set_allocator(). The memory alloca- + tor structure contains the following members: + + typedef struct s_memallocator { + void *priv; + void *(*malloc)(void *priv, unsigned int size); + void (*free)(void *priv, void *ptr); + void *(*realloc)(void *priv, void *ptr, unsigned int nsize); + } memallocator_t; + + The malloc() function pointer will be used by LibXDiff to + request a memory block of size bytes. The free() function + pointer will be called to free a previously allocated block ptr + , while the realloc() will be used to resize the ptr to a new + nsize size in bytes. The priv structure member will be passed to + the malloc(),free(),realloc() functions as first parameter. The + LibXDiff user must call xdl_set_allocator() before starting + using the library, otherwise LibXDiff functions will fail due to + the lack of memory allocation support. A typical initialization + sequence for POSIX systems will use the standard malloc(3), + free(3), realloc(3) and will look like: + + void *wrap_malloc(void *priv, unsigned int size) { + return malloc(size); + } + + void wrap_free(void *priv, void *ptr) { + free(ptr); + } + + void *wrap_realloc(void *priv, void *ptr, unsigned int size) { + return realloc(ptr, size); + } + + void my_init_xdiff(void) { + memallocator_t malt; + + malt.priv = NULL; + malt.malloc = wrap_malloc; + malt.free = wrap_free; + malt.realloc = wrap_realloc; + xdl_set_allocator(&malt); + } + + + + void *xdl_malloc(unsigned int size); + + Allocates a memory block of size bytes using the LibXDiff memory + allocator. The user can specify its own allocator using the + xdl_set_allocator() function. The xdl_malloc() return a pointer + to the newly allocated block, or NULL in case of failure. + + + void xdl_free(void *ptr); + + Free a previously allocated memory block pointed by ptr. The + ptr block must has been allocated using either xdl_malloc() or + xdl_realloc(). + + + void *xdl_realloc(void *ptr, unsigned int nsize); + + Resizes the memory block pointed by ptr to a new size nsize. + Return the resized block if successful, or NULL in case the + reallocation fails. After a successful reallocation, the old ptr + block is to be considered no more valid. + + + int xdl_init_mmfile(mmfile_t *mmf, long bsize, unsigned long flags); + + Initialize the memory file mmf by requiring an internal block + size of bsize. The flags parameter is a combination of the fol- + lowing flags : + + XDL_MMF_ATOMIC Writes on the memory file will be atomic. That + is, the data will not be split on two or more different blocks. + + Once an xdl_init_mmfile() succeeded, a matching + xdl_free_mmfile() must be called when the user has done using + the memory file, otherwise serious memory leaks will happen. + The function return 0 if succeed or -1 if an error is encoun- + tered. + + + void xdl_free_mmfile(mmfile_t *mmf); + + Free all the data associated with the mmf memory file. + + + int xdl_mmfile_iscompact(mmfile_t *mmf); + + Returns an integer different from 0 if the mmf memory file is + compact, 0 otherwise. A compact memory file is one that have the + whole content stored inside a single block. + + + int xdl_seek_mmfile(mmfile_t *mmf, long off); + + Set the current data pointer of the memory file mmf to the spec- + ified offset off from the beginning of the file itself. Returns + 0 if successful or -1 if an error happened. + + + long xdl_read_mmfile(mmfile_t *mmf, void *data, long size); + + Request to read size bytes from the memory file mmf by storing + the data inside the data buffer. Returns the number of bytes + read into the data buffer. The amount of data read can be lower + than the specified size. The function returns -1 if an error + happened. + + + long xdl_write_mmfile(mmfile_t *mmf, void const *data, long size); + + Request to write size bytes from the specified buffer data into + the memory file mmf. If the memory file has been created using + the XDL_MMF_ATOMIC flag, the write request will not be split + across different blocks. Note that all write operations done on + memory files do append data at the end the file, and writes in + the middle of it are allowed. This is because the library memory + file abstraction does not need this functionality to be avail- + able. The function returns the number of bytes written or a + number lower than size if an error happened. + + + long xdl_writem_mmfile(mmfile_t *mmf, mmbuffer_t *mb, int nbuf); + + Request to sequentially write nbuf memory buffers passed inside + the array mb into the memory file mmf. The memory buffer struc- + ture is defined as : + + typedef struct s_mmbuffer { + char *ptr; + long size; + } mmbuffer_t; + + The ptr field is a pointer to the user data, whose size is spec- + ified inside the size structure field. The function returns the + total number of bytes written or a lower number if an error hap- + pened. + + + void *xdl_mmfile_writeallocate(mmfile_t *mmf, long size); + + The function request to allocate a write buffer of size bytes in + the mmf memory file and returns the pointer to the allocated + buffer. The user will have the responsibility to store size + bytes (no more, no less) inside the memory region pointed to by + the returned pointer. The files size will grow of size bytes as + a consequence of this operation. The function will return NULL + if an error happened. + + + long xdl_mmfile_ptradd(mmfile_t *mmf, char *ptr, long size, unsigned + long flags); + + The function adds a user specified block to the end of the mem- + ory file mmf. The block first byte is pointed to by ptr and its + length is size bytes. The flags parameter can be used to specify + attributes of the user memory block. Currently supported + attributes are: + + XDL_MMB_READONLY Specify that the added memory block must be + treated as read-only, and every attempt to write on it should + result in a failure of the memory file writing functions. + + The purpose of this function is basically to avoid copying mem- + ory around, by helping the library to not drain the CPU cache. + The function returns size in case of success, or -1 in case of + error. + + + void *xdl_mmfile_first(mmfile_t *mmf, long *size); + + The function is used to return the first block of the mmf memory + file block chain. The size parameter will receive the size of + the block, while the function will return the pointer the the + first byte of the block itself. The function returns NULL if the + file is empty. + + + void *xdl_mmfile_next(mmfile_t *mmf, long *size); + + The function is used to return the next block of the mmf memory + file block chain. The size parameter will receive the size of + the block, while the function will return the pointer the the + first byte of the block itself. The function returns NULL if the + current block is the last one of the chain. + + + long xdl_mmfile_size(mmfile_t *mmf); + + The function returns the size of the specified memory file mmf. + + + int xdl_mmfile_cmp(mmfile_t *mmf1, mmfile_t *mmf2); + + Request to compare two memory files mmf1 and mmf2 and returns 0 + if files are identical, or a value different from 0 if files are + different. + + + int xdl_mmfile_compact(mmfile_t *mmfo, mmfile_t *mmfc, long bsize, + unsigned long flags); + + Request to create a compact version of the memory file mmfo into + the (uninitialized) memory file mmfc. The bsize parameter spec- + ify the requested block size and flags specify flags to be used + to create the new mmfc memory file (see xdl_init_mmfile() ). The + function returns 0 if succedded or -1 if an error happened. + + + int xdl_diff(mmfile_t *mmf1, mmfile_t *mmf2, xpparam_t const *xpp, + xdemitconf_t const *xecfg, xdemitcb_t *ecb); + + Request to create the difference between the two text memory + files mmf1 and mmf2. The mmf1 memory files is considered the + "old" file while mmf2 is considered the "new" file. So the func- + tion will create a patch file that once applied to mmf1 will + give mmf2 as result. Files mmf1 and mmf2 must be atomic from a + line point of view (or, as an extreme, compact), that means that + a single test line cannot spread among different memory file + blocks. The xpp parameter is a pointer to a structure : + + typedef struct s_xpparam { + unsigned long flags; + } xpparam_t; + + that is used to specify parameters to be used by the file dif- + ferential algorithm. The flags field is a combination of the + following flags : + + + XDF_NEED_MINIMAL Requires the minimal edit script to be found by + the algorithm (may be slow). + + The xecfg parameter point to a structure : + + typedef struct s_xdemitconf { + long ctxlen; + } xdemitconf_t; + + that is used to configure the algorithm responsible of the + creation the the differential file from an edit script. The + ctxlen field is used to specify the amount of context to be + emitted inside the differential file (the value 3 is suggested + for normal operations). The parameter ecb is a pointer to a + structure : + + typedef struct s_xdemitcb { + void *priv; + int (*outf)(void *, mmbuffer_t *, int); + } xdemitcb_t; + + that is used by the differential file creation algorithm to emit + the created data. The priv field is an opaque pointer to a user + specified data, while the outf field point to a callback func- + tion that is called internally to emit algorithm generated data + rappresenting the differential file. The first parameter of the + callback is the same priv field specified inside the xdemitcb_t + structure. The second parameter point to an array of mmbuffer_t + (see above for a definition of the structure) whose element + count is specified inside the last parameter of the callback + itself. The callback will always be called with entire records + (lines) and never a record (line) will be emitted using two dif- + ferent callback calls. This is important because if the called + will use another memory file to store the result, by creating + the target memory file with XDL_MMF_ATOMIC will guarantee the + "atomicity" of the memory file itself. The function returns 0 + if succeeded or -1 if an error occurred. + + + int xdl_patch(mmfile_t *mmf, mmfile_t *mmfp, int mode, xdemitcb_t *ecb, + xdemitcb_t *rjecb); + + Request to patch the memory file mmf using the patch file stored + in mmfp. The mmf memory file is not changed during the opera- + tion and can be considered as read only. The mode parameter can + be one of the following values : + + XDL_PATCH_NORMAL Perform standard patching like if the patch + memory file mmfp has been created using mmf as "old" file. + + XDL_PATCH_REVERSE Apply the reverse patch. That means that the + mmf memory file has to be considered as if it was specified as + "new" file during the differential operation ( xdl_diff() ). The + result of the operation will then be the file content that was + used as "old" file during the differential operation. + + The following flags can be specified (by or-ing them) to one of + the above: + + XDL_PATCH_IGNOREBSPACE Ignore the whitespace at the beginning + and the end of the line. + + The ecb will be used by the patch algorithm to create the result + file while the rjecb will be used to emit all differential + chunks that cannot be applied. Like explained above, callbacks + are always called with entire records to guarantee atomicity of + the resulting output. The function returns 0 if succeeded with- + out performing any fuzzy hunk detection, a positive value if it + secceeded with fuzzy hunk detection or -1 if an error occurred + during the patch operation. + + + int xdl_merge3(mmfile_t *mmfo, mmfile_t *mmf1, mmfile_t *mmf2, + xdemitcb_t *ecb, xdemitcb_t *rjecb); + + Merges three files together. The mmfo file is the original one, + while mmf1 and mmf2 are two modified versions of mmfo. The + function works by creating a differential between mmfo and mmf2 + and by applying the resulting patch to mmf1. Because of this + sequence, mmf1 changes will be privileged against the ones of + mmf2. The ecb will be used by the patch algorithm to create the + result file while the rjecb will be used to emit all differen- + tial chunks that cannot be applied. Like explained above, call- + backs are always called with entire records to guarantee atomic- + ity of the resulting output. The function returns 0 if suc- + ceeded or -1 if an error occurred during the patch operation. + + + int xdl_bdiff(mmfile_t *mmf1, mmfile_t *mmf2, bdiffparam_t const *bdp, + xdemitcb_t *ecb); + + Request to create the difference between the two text memory + files mmf1 and mmf2. The mmf1 memory files is considered the + "old" file while mmf2 is considered the "new" file. So the func- + tion will create a patch file that once applied to mmf1 will + give mmf2 as result. Files mmf1 and mmf2 must be compact to make + it easy and faster to perform the difference operation. Func- + tions are available to check for compactness ( xdl_mmfile_iscom- + pact() ) and to make compact a non-compact file ( + xdl_mmfile_compact() ). An example of how to create a compact + memory file (described inside the test subdirectory) is : + + int xdlt_load_mmfile(char const *fname, mmfile_t *mf, int binmode) { + char cc; + int fd; + long size, bsize; + char *blk; + + if (xdl_init_mmfile(mf, XDLT_STD_BLKSIZE, XDL_MMF_ATOMIC) < 0) + return -1; + if ((fd = open(fname, O_RDONLY)) == -1) { + perror(fname); + xdl_free_mmfile(mf); + return -1; + } + if ((size = bsize = lseek(fd, 0, SEEK_END)) > 0 && !binmode) { + if (lseek(fd, -1, SEEK_END) != (off_t) -1 && + read(fd, &cc, 1) && cc != '\n') + bsize++; + } + lseek(fd, 0, SEEK_SET); + if (!(blk = (char *) xdl_mmfile_writeallocate(mf, bsize))) { + xdl_free_mmfile(mf); + close(fd); + return -1; + } + if (read(fd, blk, (size_t) size) != (size_t) size) { + perror(fname); + xdl_free_mmfile(mf); + close(fd); + return -1; + } + close(fd); + if (bsize > size) + blk[size] = '\n'; + return 0; + } + + The bdp parameter points to a structure : + + typedef struct s_bdiffparam { + long bsize; + } bdiffparam_t; + + that is used to pass information to the binary file differential + algorithm. The bsize parameter specify the size of the block + that will be used to decompose mmf1 during the block classifica- + tion phase of the algorithm (see MacDonald paper). Suggested + values go from 16 to 64, with a preferred power of two charac- + teristic. The ecb parameter is used to pass the emission call- + back to the algorithm responsible of the output file creation. + The function returns 0 if succeede or -1 if an error is + occurred. + + + int xdl_bdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, bdiffparam_t const + *bdp, xdemitcb_t *ecb); + + Same as xdl_bdiff() but it works on memory buffer directly. The + xdl_bdiff() is implemented internally with a xdl_bdiff_mb() + after having setup the two memory buffers from the passed memory + files (that must be compact, as described above). The memory + buffer structure is defined as : + + typedef struct s_mmbuffer { + char *ptr; + long size; + } mmbuffer_t; + + An empty memory buffer is specified by setting the ptr member as + NULL and the size member as zero. The reason of having this + function is to avoid the memory file preparation, that might + involve copying memory from other sources. Using the + xdl_bdiff_mb(), the caller can setup the two memory buffer by + using, for example, mmap(2), and hence avoiding unnecessary mem- + ory copies. The other parameters and the return value of the + function xdl_bdiff_mb() are the same as the ones already + described in xdl_bdiff(). + + + int xdl_rabdiff(mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb); + + Request to create the difference between the two text memory + files mmf1 and mmf2 using the Rabin's polynomial fingerprinting + algorithm. This algorithm typically performs faster and produces + smaller deltas, when compared to the XDelta-like one. The mmf1 + memory files is considered the "old" file while mmf2 is consid- + ered the "new" file. So the function will create a patch file + that once applied to mmf1 will give mmf2 as result. Files mmf1 + and mmf2 must be compact to make it easy and faster to perform + the difference operation. Functions are available to check for + compactness ( xdl_mmfile_iscompact() ) and to make compact a + non-compact file ( xdl_mmfile_compact() ). The ecb parameter is + used to pass the emission callback to the algorithm responsible + of the output file creation. The function returns 0 if succeede + or -1 if an error is occurred. + + + int xdl_rabdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, xdemitcb_t + *ecb); + + Same as xdl_rabdiff() but it works on memory buffer directly. + The memory buffer structure is defined as : + + typedef struct s_mmbuffer { + char *ptr; + long size; + } mmbuffer_t; + + An empty memory buffer is specified by setting the ptr member as + NULL and the size member as zero. The reason of having this + function is to avoid the memory file preparation, that might + involve copying memory from other sources. Using the xdl_rabd- + iff_mb(), the caller can setup the two memory buffer by using, + for example, mmap(2), and hence avoiding unnecessary memory + copies. The other parameters and the return value of the func- + tion xdl_rabdiff_mb() are the same as the ones already described + in xdl_rabdiff(). + + + long xdl_bdiff_tgsize(mmfile_t *mmfp); + + Given a binary memory file patch, it returns the size that the + result file will have once the patch is applied to the target + file. It can be used to pre-allocate (or write-allocate) a mem- + ory block to store the patch result so that a compact file will + be available at the end of the operation. The function returns + the requested size, or -1 if an error occurred during the opera- + tion. + + + int xdl_bpatch(mmfile_t *mmf, mmfile_t *mmfp, xdemitcb_t *ecb); + + Request to patch the binary memory file mmf using the binary + patch file stored in mmfp. The mmf memory file is not changed + during the operation and can be considered as read only. The + binary patch algorithm has no notion of context, so the patch + operation cannot be partial (either success or failure). The ecb + parameter contain the callabck (see above for description) used + by the binary patch algorithm to emit the result file. The func- + tion returns 0 if succeeded or -1 if an error occurred during + the patch operation. + + +SEE ALSO + Two papers drove the content of this library and these are : + + o File System Support for Delta Compression by Joshua P. MacDonald + http://www.xmailserver.org/xdfs.pdf + + o Fingerprinting by Random Polynomials by Michael O. Rabin + http://www.xmailserver.org/rabin.pdf + + o An O(ND) Difference Algorithm and Its Variations by Eugene W. + Myers http://www.xmailserver.org/diff2.pdf + + + Also usefull information can be looked up inside the diffutil GNU pack- + age : + + http://www.gnu.org/software/diffutils/diffutils.html + + +LICENSE + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. A copy of the license is available + at : + + http://www.gnu.org/copyleft/lesser.html + + +AUTHOR + Developed by Davide Libenzi + + +AVAILABILITY + The latest version of LibXDiff can be found at : + + http://www.xmailserver.org/xdiff-lib.html + + +BUGS + There are no known bugs. Bug reports and comments to Davide Libenzi + + + + + +GNU 0.23 LibXDiff(3) diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.c new file mode 100644 index 0000000000..8537bc9590 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.c @@ -0,0 +1,556 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + + +#define XDL_MAX_COST_MIN 256 +#define XDL_HEUR_MIN_COST 256 +#define XDL_LINE_MAX (long)((1UL << (8 * sizeof(long) - 1)) - 1) +#define XDL_SNAKE_CNT 20 +#define XDL_K_HEUR 4 + + + +typedef struct s_xdpsplit { + long i1, i2; + int min_lo, min_hi; +} xdpsplit_t; + + + +/* + * See "An O(ND) Difference Algorithm and its Variations", by Eugene Myers. + * Basically considers a "box" (off1, off2, lim1, lim2) and scan from both + * the forward diagonal starting from (off1, off2) and the backward diagonal + * starting from (lim1, lim2). If the K values on the same diagonal crosses + * returns the furthest point of reach. We might end up having to expensive + * cases using this algorithm is full, so a little bit of heuristic is needed + * to cut the search and to return a suboptimal point. + */ +static long xdl_split(unsigned long const *ha1, long off1, long lim1, + unsigned long const *ha2, long off2, long lim2, + long *kvdf, long *kvdb, int need_min, xdpsplit_t *spl, + xdalgoenv_t *xenv) { + long dmin = off1 - lim2, dmax = lim1 - off2; + long fmid = off1 - off2, bmid = lim1 - lim2; + long odd = (fmid - bmid) & 1; + long fmin = fmid, fmax = fmid; + long bmin = bmid, bmax = bmid; + long ec, d, i1, i2, prev1, best, dd, v, k; + + /* + * Set initial diagonal values for both forward and backward path. + */ + kvdf[fmid] = off1; + kvdb[bmid] = lim1; + + for (ec = 1;; ec++) { + int got_snake = 0; + + /* + * We need to extent the diagonal "domain" by one. If the next + * values exits the box boundaries we need to change it in the + * opposite direction because (max - min) must be a power of two. + * Also we initialize the extenal K value to -1 so that we can + * avoid extra conditions check inside the core loop. + */ + if (fmin > dmin) + kvdf[--fmin - 1] = -1; + else + ++fmin; + if (fmax < dmax) + kvdf[++fmax + 1] = -1; + else + --fmax; + + for (d = fmax; d >= fmin; d -= 2) { + if (kvdf[d - 1] >= kvdf[d + 1]) + i1 = kvdf[d - 1] + 1; + else + i1 = kvdf[d + 1]; + prev1 = i1; + i2 = i1 - d; + for (; i1 < lim1 && i2 < lim2 && ha1[i1] == ha2[i2]; i1++, i2++); + if (i1 - prev1 > xenv->snake_cnt) + got_snake = 1; + kvdf[d] = i1; + if (odd && bmin <= d && d <= bmax && kvdb[d] <= i1) { + spl->i1 = i1; + spl->i2 = i2; + spl->min_lo = spl->min_hi = 1; + return ec; + } + } + + /* + * We need to extent the diagonal "domain" by one. If the next + * values exits the box boundaries we need to change it in the + * opposite direction because (max - min) must be a power of two. + * Also we initialize the extenal K value to -1 so that we can + * avoid extra conditions check inside the core loop. + */ + if (bmin > dmin) + kvdb[--bmin - 1] = XDL_LINE_MAX; + else + ++bmin; + if (bmax < dmax) + kvdb[++bmax + 1] = XDL_LINE_MAX; + else + --bmax; + + for (d = bmax; d >= bmin; d -= 2) { + if (kvdb[d - 1] < kvdb[d + 1]) + i1 = kvdb[d - 1]; + else + i1 = kvdb[d + 1] - 1; + prev1 = i1; + i2 = i1 - d; + for (; i1 > off1 && i2 > off2 && ha1[i1 - 1] == ha2[i2 - 1]; i1--, i2--); + if (prev1 - i1 > xenv->snake_cnt) + got_snake = 1; + kvdb[d] = i1; + if (!odd && fmin <= d && d <= fmax && i1 <= kvdf[d]) { + spl->i1 = i1; + spl->i2 = i2; + spl->min_lo = spl->min_hi = 1; + return ec; + } + } + + if (need_min) + continue; + + /* + * If the edit cost is above the heuristic trigger and if + * we got a good snake, we sample current diagonals to see + * if some of the, have reached an "interesting" path. Our + * measure is a function of the distance from the diagonal + * corner (i1 + i2) penalized with the distance from the + * mid diagonal itself. If this value is above the current + * edit cost times a magic factor (XDL_K_HEUR) we consider + * it interesting. + */ + if (got_snake && ec > xenv->heur_min) { + for (best = 0, d = fmax; d >= fmin; d -= 2) { + dd = d > fmid ? d - fmid: fmid - d; + i1 = kvdf[d]; + i2 = i1 - d; + v = (i1 - off1) + (i2 - off2) - dd; + + if (v > XDL_K_HEUR * ec && v > best && + off1 + xenv->snake_cnt <= i1 && i1 < lim1 && + off2 + xenv->snake_cnt <= i2 && i2 < lim2) { + for (k = 1; ha1[i1 - k] == ha2[i2 - k]; k++) + if (k == xenv->snake_cnt) { + best = v; + spl->i1 = i1; + spl->i2 = i2; + break; + } + } + } + if (best > 0) { + spl->min_lo = 1; + spl->min_hi = 0; + return ec; + } + + for (best = 0, d = bmax; d >= bmin; d -= 2) { + dd = d > bmid ? d - bmid: bmid - d; + i1 = kvdb[d]; + i2 = i1 - d; + v = (lim1 - i1) + (lim2 - i2) - dd; + + if (v > XDL_K_HEUR * ec && v > best && + off1 < i1 && i1 <= lim1 - xenv->snake_cnt && + off2 < i2 && i2 <= lim2 - xenv->snake_cnt) { + for (k = 0; ha1[i1 + k] == ha2[i2 + k]; k++) + if (k == xenv->snake_cnt - 1) { + best = v; + spl->i1 = i1; + spl->i2 = i2; + break; + } + } + } + if (best > 0) { + spl->min_lo = 0; + spl->min_hi = 1; + return ec; + } + } + + /* + * Enough is enough. We spent too much time here and now we collect + * the furthest reaching path using the (i1 + i2) measure. + */ + if (ec >= xenv->mxcost) { + long fbest, fbest1, bbest, bbest1; + + fbest = -1; + for (d = fmax; d >= fmin; d -= 2) { + i1 = XDL_MIN(kvdf[d], lim1); + i2 = i1 - d; + if (lim2 < i2) + i1 = lim2 + d, i2 = lim2; + if (fbest < i1 + i2) { + fbest = i1 + i2; + fbest1 = i1; + } + } + + bbest = XDL_LINE_MAX; + for (d = bmax; d >= bmin; d -= 2) { + i1 = XDL_MAX(off1, kvdb[d]); + i2 = i1 - d; + if (i2 < off2) + i1 = off2 + d, i2 = off2; + if (i1 + i2 < bbest) { + bbest = i1 + i2; + bbest1 = i1; + } + } + + if ((lim1 + lim2) - bbest < fbest - (off1 + off2)) { + spl->i1 = fbest1; + spl->i2 = fbest - fbest1; + spl->min_lo = 1; + spl->min_hi = 0; + } else { + spl->i1 = bbest1; + spl->i2 = bbest - bbest1; + spl->min_lo = 0; + spl->min_hi = 1; + } + return ec; + } + } + + return -1; +} + + +/* + * Rule: "Divide et Impera". Recursively split the box in sub-boxes by calling + * the box splitting function. Note that the real job (marking changed lines) + * is done in the two boundary reaching checks. + */ +int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, + diffdata_t *dd2, long off2, long lim2, + long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv) { + unsigned long const *ha1 = dd1->ha, *ha2 = dd2->ha; + + /* + * Shrink the box by walking through each diagonal snake (SW and NE). + */ + for (; off1 < lim1 && off2 < lim2 && ha1[off1] == ha2[off2]; off1++, off2++); + for (; off1 < lim1 && off2 < lim2 && ha1[lim1 - 1] == ha2[lim2 - 1]; lim1--, lim2--); + + /* + * If one dimension is empty, then all records on the other one must + * be obviously changed. + */ + if (off1 == lim1) { + char *rchg2 = dd2->rchg; + long *rindex2 = dd2->rindex; + + for (; off2 < lim2; off2++) + rchg2[rindex2[off2]] = 1; + } else if (off2 == lim2) { + char *rchg1 = dd1->rchg; + long *rindex1 = dd1->rindex; + + for (; off1 < lim1; off1++) + rchg1[rindex1[off1]] = 1; + } else { + long ec; + xdpsplit_t spl; + + /* + * Divide ... + */ + if ((ec = xdl_split(ha1, off1, lim1, ha2, off2, lim2, kvdf, kvdb, + need_min, &spl, xenv)) < 0) { + + return -1; + } + + /* + * ... et Impera. + */ + if (xdl_recs_cmp(dd1, off1, spl.i1, dd2, off2, spl.i2, + kvdf, kvdb, spl.min_lo, xenv) < 0 || + xdl_recs_cmp(dd1, spl.i1, lim1, dd2, spl.i2, lim2, + kvdf, kvdb, spl.min_hi, xenv) < 0) { + + return -1; + } + } + + return 0; +} + + +int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, + xdfenv_t *xe) { + long ndiags; + long *kvd, *kvdf, *kvdb; + xdalgoenv_t xenv; + diffdata_t dd1, dd2; + + if (xdl_prepare_env(mf1, mf2, xpp, xe) < 0) { + + return -1; + } + + /* + * Allocate and setup K vectors to be used by the differential algorithm. + * One is to store the forward path and one to store the backward path. + */ + ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3; + if (!(kvd = (long *) xdl_malloc((2 * ndiags + 2) * sizeof(long)))) { + + xdl_free_env(xe); + return -1; + } + kvdf = kvd; + kvdb = kvdf + ndiags; + kvdf += xe->xdf2.nreff + 1; + kvdb += xe->xdf2.nreff + 1; + + xenv.mxcost = xdl_bogosqrt(ndiags); + if (xenv.mxcost < XDL_MAX_COST_MIN) + xenv.mxcost = XDL_MAX_COST_MIN; + xenv.snake_cnt = XDL_SNAKE_CNT; + xenv.heur_min = XDL_HEUR_MIN_COST; + + dd1.nrec = xe->xdf1.nreff; + dd1.ha = xe->xdf1.ha; + dd1.rchg = xe->xdf1.rchg; + dd1.rindex = xe->xdf1.rindex; + dd2.nrec = xe->xdf2.nreff; + dd2.ha = xe->xdf2.ha; + dd2.rchg = xe->xdf2.rchg; + dd2.rindex = xe->xdf2.rindex; + + if (xdl_recs_cmp(&dd1, 0, dd1.nrec, &dd2, 0, dd2.nrec, + kvdf, kvdb, (xpp->flags & XDF_NEED_MINIMAL) != 0, &xenv) < 0) { + + xdl_free(kvd); + xdl_free_env(xe); + return -1; + } + + xdl_free(kvd); + + return 0; +} + + +static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, long chg2) { + xdchange_t *xch; + + if (!(xch = (xdchange_t *) xdl_malloc(sizeof(xdchange_t)))) + return NULL; + + xch->next = xscr; + xch->i1 = i1; + xch->i2 = i2; + xch->chg1 = chg1; + xch->chg2 = chg2; + + return xch; +} + + +static int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo) { + long ix, ixo, ixs, ixref, grpsiz, nrec = xdf->nrec; + char *rchg = xdf->rchg, *rchgo = xdfo->rchg; + xrecord_t **recs = xdf->recs; + + /* + * This is the same of what GNU diff does. Move back and forward + * change groups for a consistent and pretty diff output. This also + * helps in finding joineable change groups and reduce the diff size. + */ + for (ix = ixo = 0;;) { + /* + * Find the first changed line in the to-be-compacted file. + * We need to keep track of both indexes, so if we find a + * changed lines group on the other file, while scanning the + * to-be-compacted file, we need to skip it properly. Note + * that loops that are testing for changed lines on rchg* do + * not need index bounding since the array is prepared with + * a zero at position -1 and N. + */ + for (; ix < nrec && !rchg[ix]; ix++) + while (rchgo[ixo++]); + if (ix == nrec) + break; + + /* + * Record the start of a changed-group in the to-be-compacted file + * and find the end of it, on both to-be-compacted and other file + * indexes (ix and ixo). + */ + ixs = ix; + for (ix++; rchg[ix]; ix++); + for (; rchgo[ixo]; ixo++); + + do { + grpsiz = ix - ixs; + + /* + * If the line before the current change group, is equal to + * the last line of the current change group, shift backward + * the group. + */ + while (ixs > 0 && recs[ixs - 1]->ha == recs[ix - 1]->ha && + XDL_RECMATCH(recs[ixs - 1], recs[ix - 1])) { + rchg[--ixs] = 1; + rchg[--ix] = 0; + + /* + * This change might have joined two change groups, + * so we try to take this scenario in account by moving + * the start index accordingly (and so the other-file + * end-of-group index). + */ + for (; rchg[ixs - 1]; ixs--); + while (rchgo[--ixo]); + } + + /* + * Record the end-of-group position in case we are matched + * with a group of changes in the other file (that is, the + * change record before the enf-of-group index in the other + * file is set). + */ + ixref = rchgo[ixo - 1] ? ix: nrec; + + /* + * If the first line of the current change group, is equal to + * the line next of the current change group, shift forward + * the group. + */ + while (ix < nrec && recs[ixs]->ha == recs[ix]->ha && + XDL_RECMATCH(recs[ixs], recs[ix])) { + rchg[ixs++] = 0; + rchg[ix++] = 1; + + /* + * This change might have joined two change groups, + * so we try to take this scenario in account by moving + * the start index accordingly (and so the other-file + * end-of-group index). Keep tracking the reference + * index in case we are shifting together with a + * corresponding group of changes in the other file. + */ + for (; rchg[ix]; ix++); + while (rchgo[++ixo]) + ixref = ix; + } + } while (grpsiz != ix - ixs); + + /* + * Try to move back the possibly merged group of changes, to match + * the recorded postion in the other file. + */ + while (ixref < ix) { + rchg[--ixs] = 1; + rchg[--ix] = 0; + while (rchgo[--ixo]); + } + } + + return 0; +} + + +int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr) { + xdchange_t *cscr = NULL, *xch; + char *rchg1 = xe->xdf1.rchg, *rchg2 = xe->xdf2.rchg; + long i1, i2, l1, l2; + + /* + * Trivial. Collects "groups" of changes and creates an edit script. + */ + for (i1 = xe->xdf1.nrec, i2 = xe->xdf2.nrec; i1 >= 0 || i2 >= 0; i1--, i2--) + if (rchg1[i1 - 1] || rchg2[i2 - 1]) { + for (l1 = i1; rchg1[i1 - 1]; i1--); + for (l2 = i2; rchg2[i2 - 1]; i2--); + + if (!(xch = xdl_add_change(cscr, i1, i2, l1 - i1, l2 - i2))) { + xdl_free_script(cscr); + return -1; + } + cscr = xch; + } + + *xscr = cscr; + + return 0; +} + + +void xdl_free_script(xdchange_t *xscr) { + xdchange_t *xch; + + while ((xch = xscr) != NULL) { + xscr = xscr->next; + xdl_free(xch); + } +} + + +int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, + xdemitconf_t const *xecfg, xdemitcb_t *ecb) { + xdchange_t *xscr; + xdfenv_t xe; + + if (xdl_do_diff(mf1, mf2, xpp, &xe) < 0) { + + return -1; + } + if (xdl_change_compact(&xe.xdf1, &xe.xdf2) < 0 || + xdl_change_compact(&xe.xdf2, &xe.xdf1) < 0 || + xdl_build_script(&xe, &xscr) < 0) { + + xdl_free_env(&xe); + return -1; + } + if (xscr) { + if (xdl_emit_diff(&xe, xscr, ecb, xecfg) < 0) { + + xdl_free_script(xscr); + xdl_free_env(&xe); + return -1; + } + xdl_free_script(xscr); + } + xdl_free_env(&xe); + + return 0; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.h new file mode 100644 index 0000000000..dd8f3c986b --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xdiffi.h @@ -0,0 +1,60 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XDIFFI_H) +#define XDIFFI_H + + +typedef struct s_diffdata { + long nrec; + unsigned long const *ha; + long *rindex; + char *rchg; +} diffdata_t; + +typedef struct s_xdalgoenv { + long mxcost; + long snake_cnt; + long heur_min; +} xdalgoenv_t; + +typedef struct s_xdchange { + struct s_xdchange *next; + long i1, i2; + long chg1, chg2; +} xdchange_t; + + + +int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1, + diffdata_t *dd2, long off2, long lim2, + long *kvdf, long *kvdb, int need_min, xdalgoenv_t *xenv); +int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, + xdfenv_t *xe); +int xdl_build_script(xdfenv_t *xe, xdchange_t **xscr); +void xdl_free_script(xdchange_t *xscr); +int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, + xdemitconf_t const *xecfg); + + +#endif /* #if !defined(XDIFFI_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xemit.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xemit.c new file mode 100644 index 0000000000..51580aa6ef --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xemit.c @@ -0,0 +1,132 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + +static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) { + + *rec = xdf->recs[ri]->ptr; + + return xdf->recs[ri]->size; +} + + +static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) { + long size, psize = strlen(pre); + char const *rec; + + size = xdl_get_rec(xdf, ri, &rec); + if (xdl_emit_diffrec(rec, size, pre, psize, ecb) < 0) { + + return -1; + } + + return 0; +} + + +/* + * Starting at the passed change atom, find the latest change atom to be included + * inside the differential hunk according to the specified configuration. + */ +static xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) { + xdchange_t *xch, *xchp; + + for (xchp = xscr, xch = xscr->next; xch; xchp = xch, xch = xch->next) + if (xch->i1 - (xchp->i1 + xchp->chg1) > 2 * xecfg->ctxlen) + break; + + return xchp; +} + + +int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, + xdemitconf_t const *xecfg) { + long s1, s2, e1, e2, lctx; + xdchange_t *xch, *xche; + + for (xch = xche = xscr; xch; xch = xche->next) { + xche = xdl_get_hunk(xch, xecfg); + + s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0); + s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); + + lctx = xecfg->ctxlen; + lctx = XDL_MIN(lctx, xe->xdf1.nrec - (xche->i1 + xche->chg1)); + lctx = XDL_MIN(lctx, xe->xdf2.nrec - (xche->i2 + xche->chg2)); + + e1 = xche->i1 + xche->chg1 + lctx; + e2 = xche->i2 + xche->chg2 + lctx; + + /* + * Emit current hunk header. + */ + if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2, ecb) < 0) + return -1; + + /* + * Emit pre-context. + */ + for (; s1 < xch->i1; s1++) + if (xdl_emit_record(&xe->xdf1, s1, " ", ecb) < 0) + return -1; + + for (s1 = xch->i1, s2 = xch->i2;; xch = xch->next) { + /* + * Merge previous with current change atom. + */ + for (; s1 < xch->i1 && s2 < xch->i2; s1++, s2++) + if (xdl_emit_record(&xe->xdf1, s1, " ", ecb) < 0) + return -1; + + /* + * Removes lines from the first file. + */ + for (s1 = xch->i1; s1 < xch->i1 + xch->chg1; s1++) + if (xdl_emit_record(&xe->xdf1, s1, "-", ecb) < 0) + return -1; + + /* + * Adds lines from the second file. + */ + for (s2 = xch->i2; s2 < xch->i2 + xch->chg2; s2++) + if (xdl_emit_record(&xe->xdf2, s2, "+", ecb) < 0) + return -1; + + if (xch == xche) + break; + s1 = xch->i1 + xch->chg1; + s2 = xch->i2 + xch->chg2; + } + + /* + * Emit post-context. + */ + for (s1 = xche->i1 + xche->chg1; s1 < e1; s1++) + if (xdl_emit_record(&xe->xdf1, s1, " ", ecb) < 0) + return -1; + } + + return 0; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xemit.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xemit.h new file mode 100644 index 0000000000..e629417dd2 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xemit.h @@ -0,0 +1,34 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XEMIT_H) +#define XEMIT_H + + + +int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, + xdemitconf_t const *xecfg); + + + +#endif /* #if !defined(XEMIT_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xinclude.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xinclude.h new file mode 100644 index 0000000000..bd22cd223f --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xinclude.h @@ -0,0 +1,71 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XINCLUDE_H) +#define XINCLUDE_H + + +#if defined(HAVE_WINCONFIG_H) +#include "winconfig.h" +#endif /* #if defined(HAVE_CONFIG_H) */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif /* #if defined(HAVE_CONFIG_H) */ + +#if defined(HAVE_STDIO_H) +#include +#endif /* #if defined(HAVE_STDIO_H) */ + +#if defined(HAVE_STDLIB_H) +#include +#endif /* #if defined(HAVE_STDLIB_H) */ + +#if defined(HAVE_UNISTD_H) +#include +#endif /* #if defined(HAVE_UNISTD_H) */ + +#if defined(HAVE_STRING_H) +#include +#endif /* #if defined(HAVE_STRING_H) */ + +#if defined(HAVE_LIMITS_H) +#include +#endif /* #if defined(HAVE_LIMITS_H) */ + + + +#include "xmacros.h" +#include "xmissing.h" +#include "xdiff.h" +#include "xtypes.h" +#include "xutils.h" +#include "xadler32.h" +#include "xprepare.h" +#include "xdiffi.h" +#include "xemit.h" +#include "xbdiff.h" + + + +#endif /* #if !defined(XINCLUDE_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xmacros.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xmacros.h new file mode 100644 index 0000000000..43607f17fe --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xmacros.h @@ -0,0 +1,51 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XMACROS_H) +#define XMACROS_H + + +#define XDL_MIN(a, b) ((a) < (b) ? (a): (b)) +#define XDL_MAX(a, b) ((a) > (b) ? (a): (b)) +#define XDL_ABS(v) ((v) >= 0 ? (v): -(v)) +#define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9') +#define XDL_ADDBITS(v, b) ((v) + ((v) >> (b))) +#define XDL_MASKBITS(b) ((1UL << (b)) - 1) +#define XDL_HASHLONG(v, b) (XDL_ADDBITS((unsigned long) (v), b) & XDL_MASKBITS(b)) +#define XDL_PTRFREE(p) do { if (p) { xdl_free(p); (p) = NULL; } } while (0) +#define XDL_RECMATCH(r1, r2) ((r1)->size == (r2)->size && memcmp((r1)->ptr, (r2)->ptr, (r1)->size) == 0) +#define XDL_LE32_PUT(p, v) do { \ + unsigned char *__p = (unsigned char *) (p); \ + *__p++ = (unsigned char) (v); \ + *__p++ = (unsigned char) ((v) >> 8); \ + *__p++ = (unsigned char) ((v) >> 16); \ + *__p = (unsigned char) ((v) >> 24); \ +} while (0) +#define XDL_LE32_GET(p, v) do { \ + unsigned char const *__p = (unsigned char const *) (p); \ + (v) = (unsigned long) __p[0] | ((unsigned long) __p[1]) << 8 | \ + ((unsigned long) __p[2]) << 16 | ((unsigned long) __p[3]) << 24; \ +} while (0) + + +#endif /* #if !defined(XMACROS_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xmerge3.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xmerge3.c new file mode 100644 index 0000000000..6f7cf7b77b --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xmerge3.c @@ -0,0 +1,66 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + +#define XDL_MERGE3_BLKSIZE (1024 * 8) +#define XDL_MERGE3_CTXLEN 3 + + + +int xdl_merge3(mmfile_t *mmfo, mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb, + xdemitcb_t *rjecb) { + xpparam_t xpp; + xdemitconf_t xecfg; + xdemitcb_t xecb; + mmfile_t mmfp; + + if (xdl_init_mmfile(&mmfp, XDL_MERGE3_BLKSIZE, XDL_MMF_ATOMIC) < 0) { + + return -1; + } + + xpp.flags = 0; + + xecfg.ctxlen = XDL_MERGE3_CTXLEN; + + xecb.priv = &mmfp; + xecb.outf = xdl_mmfile_outf; + + if (xdl_diff(mmfo, mmf2, &xpp, &xecfg, &xecb) < 0) { + + xdl_free_mmfile(&mmfp); + return -1; + } + + if (xdl_patch(mmf1, &mmfp, XDL_PATCH_NORMAL, ecb, rjecb) < 0) { + + xdl_free_mmfile(&mmfp); + return -1; + } + + xdl_free_mmfile(&mmfp); + + return 0; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.c new file mode 100644 index 0000000000..cefe3362c8 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.c @@ -0,0 +1,92 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + + +#if !defined(HAVE_MEMCHR) + +void *memchr(void const *p, int c, long n) { + char const *pc = p; + + for (; n; n--, pc++) + if (*pc == (char) c) + return pc; + return NULL; +} + +#endif /* #if !defined(HAVE_MEMCHR) */ + + +#if !defined(HAVE_MEMCMP) + +int memcmp(void const *p1, void const *p2, long n) { + char const *pc1 = p1, *pc2 = p2; + + for (; n; n--, pc1++, pc2++) + if (*pc1 != *pc2) + return *pc1 - *pc2; + return 0; +} + +#endif /* #if !defined(HAVE_MEMCMP) */ + + +#if !defined(HAVE_MEMCPY) + +void *memcpy(void *d, void const *s, long n) { + char *dc = d; + char const *sc = s; + + for (; n; n--, dc++, sc++) + *dc = *sc; + return d; +} + +#endif /* #if !defined(HAVE_MEMCPY) */ + + +#if !defined(HAVE_MEMSET) + +void *memset(void *d, int c, long n) { + char *dc = d; + + for (; n; n--, dc++) + *dc = (char) c; + return d; +} + +#endif /* #if !defined(HAVE_MEMSET) */ + + +#if !defined(HAVE_STRLEN) + +long strlen(char const *s) { + char const *tmp; + + for (tmp = s; *s; s++); + return (long) (s - tmp); +} + +#endif /* #if !defined(HAVE_STRLEN) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.h new file mode 100644 index 0000000000..8fcb050e01 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xmissing.h @@ -0,0 +1,56 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XMISSING_H) +#define XMISSING_H + + +#if !defined(CHAR_BIT) +#define CHAR_BIT 8 +#endif /* #if !defined(CHAR_BIT) */ + + + +#if !defined(HAVE_MEMCHR) +void *memchr(void const *p, int c, long n); +#endif /* #if !defined(HAVE_MEMCHR) */ + +#if !defined(HAVE_MEMCMP) +int memcmp(void const *p1, void const *p2, long n); +#endif /* #if !defined(HAVE_MEMCMP) */ + +#if !defined(HAVE_MEMCPY) +void *memcpy(void *d, void const *s, long n); +#endif /* #if !defined(HAVE_MEMCPY) */ + +#if !defined(HAVE_MEMSET) +void *memset(void *d, int c, long n); +#endif /* #if !defined(HAVE_MEMSET) */ + +#if !defined(HAVE_STRLEN) +long strlen(char const *s); +#endif /* #if !defined(HAVE_STRLEN) */ + + + +#endif /* #if !defined(XMISSING_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xpatchi.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xpatchi.c new file mode 100644 index 0000000000..dc984f834e --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xpatchi.c @@ -0,0 +1,641 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + + +#define XDL_MAX_FUZZ 3 +#define XDL_MIN_SYNCLINES 4 + + + +typedef struct s_recinfo { + char const *ptr; + long size; +} recinfo_t; + +typedef struct s_recfile { + mmfile_t *mf; + long nrec; + recinfo_t *recs; +} recfile_t; + +typedef struct s_hunkinfo { + long s1, s2; + long c1, c2; + long cmn, radd, rdel, pctx, sctx; +} hunkinfo_t; + +typedef struct s_patchstats { + long adds, dels; +} patchstats_t; + +typedef struct s_patch { + recfile_t rf; + hunkinfo_t hi; + long hkrec; + long hklen; + long flags; + patchstats_t ps; + int fuzzies; +} patch_t; + + + + +static int xdl_load_hunk_info(char const *line, long size, hunkinfo_t *hki); +static int xdl_init_recfile(mmfile_t *mf, int ispatch, recfile_t *rf); +static void xdl_free_recfile(recfile_t *rf); +static char const *xdl_recfile_get(recfile_t *rf, long irec, long *size); +static int xdl_init_patch(mmfile_t *mf, long flags, patch_t *pch); +static void xdl_free_patch(patch_t *pch); +static int xdl_load_hunk(patch_t *pch, long hkrec); +static int xdl_first_hunk(patch_t *pch); +static int xdl_next_hunk(patch_t *pch); +static int xdl_line_match(patch_t *pch, const char *s, long ns, char const *m, long nm); +static int xdl_hunk_match(recfile_t *rf, long irec, patch_t *pch, int mode, int fuzz); +static int xdl_find_hunk(recfile_t *rf, long ibase, patch_t *pch, int mode, + int fuzz, long *hkpos, int *exact); +static int xdl_emit_rfile_line(recfile_t *rf, long line, xdemitcb_t *ecb); +static int xdl_flush_section(recfile_t *rf, long start, long top, xdemitcb_t *ecb); +static int xdl_apply_hunk(recfile_t *rf, long hkpos, patch_t *pch, int mode, + long *ibase, xdemitcb_t *ecb); +static int xdl_reject_hunk(recfile_t *rf, patch_t *pch, int mode, + xdemitcb_t *rjecb); +static int xdl_process_hunk(recfile_t *rff, patch_t *pch, long *ibase, int mode, + xdemitcb_t *ecb, xdemitcb_t *rjecb); + + + + +static int xdl_load_hunk_info(char const *line, long size, hunkinfo_t *hki) { + char const *next; + + /* + * The diff header format should be: + * + * @@ -OP,OC +NP,NC @@ + * + * Unfortunately some software avoid to emit OP or/and NP in case + * of not existing old or new file (it should be mitted as zero). + * We need to handle both syntaxes. + */ + if (memcmp(line, "@@ -", 4)) + return -1; + line += 4; + size -= 4; + + if (!size || !XDL_ISDIGIT(*line)) + return -1; + hki->s1 = xdl_atol(line, &next); + size -= next - line; + line = next; + if (!size) + return -1; + if (*line == ',') { + size--, line++; + if (!size || !XDL_ISDIGIT(*line)) + return -1; + hki->c1 = xdl_atol(line, &next); + size -= next - line; + line = next; + if (!size || *line != ' ') + return -1; + size--, line++; + } else if (*line == ' ') { + size--, line++; + hki->c1 = hki->s1; + hki->s1 = 0; + } else + return -1; + + if (!size || *line != '+') + return -1; + size--, line++; + if (!size || !XDL_ISDIGIT(*line)) + return -1; + hki->s2 = xdl_atol(line, &next); + size -= next - line; + line = next; + if (!size) + return -1; + if (*line == ',') { + size--, line++; + if (!size || !XDL_ISDIGIT(*line)) + return -1; + hki->c2 = xdl_atol(line, &next); + size -= next - line; + line = next; + if (!size || *line != ' ') + return -1; + size--, line++; + } else if (*line == ' ') { + size--, line++; + hki->c2 = hki->s2; + hki->s2 = 0; + } else + return -1; + if (size < 2 || memcmp(line, "@@", 2) != 0) + return -1; + + /* + * We start from zero, so decrement by one unless it's the special position + * '0' inside the unified diff (new or deleted file). + */ + if (hki->s1 > 0 && hki->c1 > 0) + hki->s1--; + if (hki->s2 > 0 && hki->c2 > 0) + hki->s2--; + + return 0; +} + + +static int xdl_init_recfile(mmfile_t *mf, int ispatch, recfile_t *rf) { + long narec, nrec, bsize; + recinfo_t *recs, *rrecs; + char const *blk, *cur, *top, *eol; + + narec = xdl_guess_lines(mf); + if (!(recs = (recinfo_t *) xdl_malloc(narec * sizeof(recinfo_t)))) { + + return -1; + } + nrec = 0; + if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) { + for (top = blk + bsize;;) { + if (cur >= top) { + if (!(cur = blk = xdl_mmfile_next(mf, &bsize))) + break; + top = blk + bsize; + } + if (nrec >= narec) { + narec *= 2; + if (!(rrecs = (recinfo_t *) + xdl_realloc(recs, narec * sizeof(recinfo_t)))) { + + xdl_free(recs); + return -1; + } + recs = rrecs; + } + recs[nrec].ptr = cur; + if (!(eol = memchr(cur, '\n', top - cur))) + eol = top - 1; + recs[nrec].size = (long) (eol - cur) + 1; + if (ispatch && *cur == '\\' && nrec > 0 && recs[nrec - 1].size > 0 && + recs[nrec - 1].ptr[recs[nrec - 1].size - 1] == '\n') + recs[nrec - 1].size--; + else + nrec++; + cur = eol + 1; + } + } + rf->mf = mf; + rf->nrec = nrec; + rf->recs = recs; + + return 0; +} + + +static void xdl_free_recfile(recfile_t *rf) { + + xdl_free(rf->recs); +} + + +static char const *xdl_recfile_get(recfile_t *rf, long irec, long *size) { + + if (irec < 0 || irec >= rf->nrec) + return NULL; + *size = rf->recs[irec].size; + + return rf->recs[irec].ptr; +} + + +static int xdl_init_patch(mmfile_t *mf, long flags, patch_t *pch) { + + if (xdl_init_recfile(mf, 1, &pch->rf) < 0) { + + return -1; + } + pch->hkrec = 0; + pch->hklen = 0; + pch->flags = flags; + pch->ps.adds = pch->ps.dels = 0; + pch->fuzzies = 0; + + return 0; +} + + +static void xdl_free_patch(patch_t *pch) { + + xdl_free_recfile(&pch->rf); +} + + +static int xdl_load_hunk(patch_t *pch, long hkrec) { + long size, i, nb; + char const *line; + + for (;; hkrec++) { + pch->hkrec = hkrec; + if (!(line = xdl_recfile_get(&pch->rf, pch->hkrec, &size))) + return 0; + if (*line == '@') + break; + } + if (xdl_load_hunk_info(line, size, &pch->hi) < 0) { + + return -1; + } + pch->hi.cmn = pch->hi.radd = pch->hi.rdel = pch->hi.pctx = pch->hi.sctx = 0; + for (i = pch->hkrec + 1, nb = 0; + (line = xdl_recfile_get(&pch->rf, i, &size)) != NULL; i++) { + if (*line == '@' || *line == '\n') + break; + if (*line == ' ') { + nb++; + pch->hi.cmn++; + } else if (*line == '+') { + if (pch->hi.radd + pch->hi.rdel == 0) + pch->hi.pctx = nb; + nb = 0; + pch->hi.radd++; + } else if (*line == '-') { + if (pch->hi.radd + pch->hi.rdel == 0) + pch->hi.pctx = nb; + nb = 0; + pch->hi.rdel++; + } else { + + return -1; + } + } + pch->hi.sctx = nb; + if (pch->hi.cmn + pch->hi.radd != pch->hi.c2 || + pch->hi.cmn + pch->hi.rdel != pch->hi.c1) { + + return -1; + } + pch->hklen = i - pch->hkrec - 1; + + return 1; +} + + +static int xdl_first_hunk(patch_t *pch) { + + return xdl_load_hunk(pch, 0); +} + + +static int xdl_next_hunk(patch_t *pch) { + + return xdl_load_hunk(pch, pch->hkrec + pch->hklen + 1); +} + + +static int xdl_line_match(patch_t *pch, const char *s, long ns, char const *m, long nm) { + + for (; ns > 0 && (s[ns - 1] == '\r' || s[ns - 1] == '\n'); ns--); + for (; nm > 0 && (m[nm - 1] == '\r' || m[nm - 1] == '\n'); nm--); + if (pch->flags & XDL_PATCH_IGNOREBSPACE) { + for (; ns > 0 && (*s == ' ' || *s == '\t'); ns--, s++); + for (; ns > 0 && (s[ns - 1] == ' ' || s[ns - 1] == '\t'); ns--); + for (; nm > 0 && (*m == ' ' || *m == '\t'); nm--, m++); + for (; nm > 0 && (m[nm - 1] == ' ' || m[nm - 1] == '\t'); nm--); + } + + return ns == nm && memcmp(s, m, ns) == 0; +} + + +static int xdl_hunk_match(recfile_t *rf, long irec, patch_t *pch, int mode, int fuzz) { + long i, j, z, fsize, psize, ptop, pfuzz, sfuzz, misses; + char const *fline, *pline; + + /* + * Limit fuzz to not be greater than the prefix and suffix context. + */ + pfuzz = fuzz < pch->hi.pctx ? fuzz: pch->hi.pctx; + sfuzz = fuzz < pch->hi.sctx ? fuzz: pch->hi.sctx; + + /* + * First loop through the prefix fuzz area. In this loop we simply + * note mismatching lines. We allow missing lines here, that is, + * some prefix context lines are missing. + */ + for (z = pfuzz, misses = 0, i = irec, j = pch->hkrec + 1, + ptop = pch->hkrec + 1 + pch->hklen - sfuzz; + z > 0 && i < rf->nrec && j < ptop; i++, j++, z--) { + if (!(pline = xdl_recfile_get(&pch->rf, j, &psize))) + return 0; + if (!(fline = xdl_recfile_get(rf, i, &fsize)) || + !xdl_line_match(pch, fline, fsize, pline + 1, psize - 1)) + misses++; + } + if (misses > fuzz) + return 0; + + /* + * Strict match loop. + */ + for (; i < rf->nrec && j < ptop; i++, j++) { + for (; j < ptop; j++) { + if (!(pline = xdl_recfile_get(&pch->rf, j, &psize))) + return 0; + if (*pline == ' ' || *pline == mode) + break; + } + if (j == ptop) + break; + if (!(fline = xdl_recfile_get(rf, i, &fsize)) || + !xdl_line_match(pch, fline, fsize, pline + 1, psize - 1)) + return 0; + } + for (; j < ptop; j++) + if (!(pline = xdl_recfile_get(&pch->rf, j, &psize)) || + *pline == ' ' || *pline == mode) + return 0; + + /* + * Finally loop through the suffix fuzz area. In this loop we simply + * note mismatching lines. We allow missing lines here, that is, + * some suffix context lines are missing. + */ + for (z = sfuzz; z > 0 && i < rf->nrec; i++, j++, z--) { + if (!(pline = xdl_recfile_get(&pch->rf, j, &psize))) + return 0; + if (!(fline = xdl_recfile_get(rf, i, &fsize)) || + !xdl_line_match(pch, fline, fsize, pline + 1, psize - 1)) + misses++; + } + + return misses <= fuzz; +} + + +static int xdl_find_hunk(recfile_t *rf, long ibase, patch_t *pch, int mode, + int fuzz, long *hkpos, int *exact) { + long hpos, hlen, i, j; + long pos[2]; + + hpos = mode == '-' ? pch->hi.s1: pch->hi.s2; + hlen = mode == '-' ? pch->hi.cmn + pch->hi.rdel: pch->hi.cmn + pch->hi.radd; + if (xdl_hunk_match(rf, hpos, pch, mode, fuzz)) { + *hkpos = hpos; + *exact = 1; + return 1; + } + for (i = 1;; i++) { + /* + * We allow a negative starting hunk position, up to the + * number of prefix context lines. + */ + j = 0; + if (hpos - i >= ibase - pch->hi.pctx) + pos[j++] = hpos - i; + if (hpos + i + hlen <= rf->nrec) + pos[j++] = hpos + i; + if (!j) + break; + for (j--; j >= 0; j--) + if (xdl_hunk_match(rf, pos[j], pch, mode, fuzz)) { + *hkpos = pos[j]; + *exact = 0; + return 1; + } + } + + return 0; +} + + +static int xdl_emit_rfile_line(recfile_t *rf, long line, xdemitcb_t *ecb) { + mmbuffer_t mb; + + if (!(mb.ptr = (char *) xdl_recfile_get(rf, line, &mb.size)) || + ecb->outf(ecb->priv, &mb, 1) < 0) { + + return -1; + } + + return 0; +} + + +static int xdl_flush_section(recfile_t *rf, long start, long top, xdemitcb_t *ecb) { + long i; + + for (i = start; i <= top; i++) { + if (xdl_emit_rfile_line(rf, i, ecb) < 0) { + + return -1; + } + } + + return 0; +} + + +static int xdl_apply_hunk(recfile_t *rf, long hkpos, patch_t *pch, int mode, + long *ibase, xdemitcb_t *ecb) { + long j, psize, ptop; + char const *pline; + mmbuffer_t mb; + + /* + * The hunk starting position (hkpos) can be negative, up to the number + * of prefix context lines. Since this function only emit the core of + * the hunk (the remaining lines are flushed by xdl_flush_section() calls) + * we need to normalize it by adding the number of prefix context lines. + * The normalized value of the starting position is then greater/equal + * to zero. + */ + hkpos += pch->hi.pctx; + if (xdl_flush_section(rf, *ibase, hkpos - 1, ecb) < 0) { + + return -1; + } + *ibase = hkpos; + for (j = pch->hkrec + 1 + pch->hi.pctx, + ptop = pch->hkrec + 1 + pch->hklen - pch->hi.sctx; j < ptop; j++) { + if (!(pline = xdl_recfile_get(&pch->rf, j, &psize))) { + + return -1; + } + if (*pline == ' ') { + if (xdl_emit_rfile_line(rf, *ibase, ecb) < 0) { + + return -1; + } + (*ibase)++; + } else if (*pline != mode) { + mb.ptr = (char *) pline + 1; + mb.size = psize - 1; + if (ecb->outf(ecb->priv, &mb, 1) < 0) { + + return -1; + } + pch->ps.adds++; + } else { + (*ibase)++; + pch->ps.dels++; + } + } + + return 0; +} + + +static int xdl_reject_hunk(recfile_t *rf, patch_t *pch, int mode, + xdemitcb_t *rjecb) { + long i, size, s1, s2, c1, c2; + char const *line, *pre; + mmbuffer_t mb; + + if (mode == '-') { + s1 = pch->hi.s1; + s2 = pch->hi.s2; + c1 = pch->hi.c1; + c2 = pch->hi.c2; + } else { + s1 = pch->hi.s2; + s2 = pch->hi.s1; + c1 = pch->hi.c2; + c2 = pch->hi.c1; + } + s1 += pch->ps.adds - pch->ps.dels; + if (xdl_emit_hunk_hdr(s1 + 1, c1, s2 + 1, c2, rjecb) < 0) { + + return -1; + } + for (i = pch->hkrec + 1; + (line = xdl_recfile_get(&pch->rf, i, &size)) != NULL; i++) { + if (*line == '@' || *line == '\n') + break; + if (mode == '-' || *line == ' ') { + mb.ptr = (char *) line; + mb.size = size; + if (rjecb->outf(rjecb->priv, &mb, 1) < 0) { + + return -1; + } + } else { + pre = *line == '+' ? "-": "+"; + if (xdl_emit_diffrec(line + 1, size - 1, pre, strlen(pre), + rjecb) < 0) { + + return -1; + } + } + } + + return 0; +} + + +static int xdl_process_hunk(recfile_t *rff, patch_t *pch, long *ibase, int mode, + xdemitcb_t *ecb, xdemitcb_t *rjecb) { + int fuzz, exact, hlen, maxfuzz; + long hkpos; + + hlen = mode == '-' ? pch->hi.cmn + pch->hi.rdel: pch->hi.cmn + pch->hi.radd; + maxfuzz = XDL_MAX_FUZZ; + if (hlen - maxfuzz < XDL_MIN_SYNCLINES) + maxfuzz = hlen - XDL_MIN_SYNCLINES; + if (maxfuzz < 0) + maxfuzz = 0; + for (fuzz = 0; fuzz <= maxfuzz; fuzz++) { + if (xdl_find_hunk(rff, *ibase, pch, mode, fuzz, + &hkpos, &exact)) { + if (xdl_apply_hunk(rff, hkpos, pch, mode, + ibase, ecb) < 0) { + + return -1; + } + if (!exact || fuzz) + pch->fuzzies++; + + return 0; + } + } + if (xdl_reject_hunk(rff, pch, mode, rjecb) < 0) { + + return -1; + } + + return 0; +} + + +int xdl_patch(mmfile_t *mf, mmfile_t *mfp, int mode, xdemitcb_t *ecb, + xdemitcb_t *rjecb) { + int hkres, exact; + long hkpos, ibase; + recfile_t rff; + patch_t pch; + + if (xdl_init_recfile(mf, 0, &rff) < 0) { + + return -1; + } + if (xdl_init_patch(mfp, mode & ~XDL_PATCH_MODEMASK, &pch) < 0) { + + xdl_free_recfile(&rff); + return -1; + } + mode &= XDL_PATCH_MODEMASK; + ibase = 0; + if ((hkres = xdl_first_hunk(&pch)) > 0) { + do { + if (xdl_process_hunk(&rff, &pch, &ibase, mode, + ecb, rjecb) < 0) { + xdl_free_patch(&pch); + xdl_free_recfile(&rff); + return -1; + } + } while ((hkres = xdl_next_hunk(&pch)) > 0); + } + if (hkres < 0) { + + xdl_free_patch(&pch); + xdl_free_recfile(&rff); + return -1; + } + if (xdl_flush_section(&rff, ibase, rff.nrec - 1, ecb) < 0) { + + xdl_free_patch(&pch); + xdl_free_recfile(&rff); + return -1; + } + xdl_free_patch(&pch); + xdl_free_recfile(&rff); + + return pch.fuzzies; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.c new file mode 100644 index 0000000000..3ebd87c138 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.c @@ -0,0 +1,456 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + +#define XDL_KPDIS_RUN 4 +#define XDL_MAX_EQLIMIT 1024 +#define XDL_SIMSCAN_WINDOWN 100 + + +typedef struct s_xdlclass { + struct s_xdlclass *next; + unsigned long ha; + char const *line; + long size; + long idx; +} xdlclass_t; + +typedef struct s_xdlclassifier { + unsigned int hbits; + long hsize; + xdlclass_t **rchash; + chastore_t ncha; + long count; +} xdlclassifier_t; + + + +static int xdl_init_classifier(xdlclassifier_t *cf, long size) { + long i; + + cf->hbits = xdl_hashbits((unsigned int) size); + cf->hsize = 1 << cf->hbits; + + if (xdl_cha_init(&cf->ncha, sizeof(xdlclass_t), size / 4 + 1) < 0) { + + return -1; + } + if (!(cf->rchash = (xdlclass_t **) xdl_malloc(cf->hsize * sizeof(xdlclass_t *)))) { + + xdl_cha_free(&cf->ncha); + return -1; + } + for (i = 0; i < cf->hsize; i++) + cf->rchash[i] = NULL; + + cf->count = 0; + + return 0; +} + + +static void xdl_free_classifier(xdlclassifier_t *cf) { + xdl_free(cf->rchash); + xdl_cha_free(&cf->ncha); +} + + +static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits, + xrecord_t *rec) { + long hi; + char const *line; + xdlclass_t *rcrec; + + line = rec->ptr; + hi = (long) XDL_HASHLONG(rec->ha, cf->hbits); + for (rcrec = cf->rchash[hi]; rcrec; rcrec = rcrec->next) + if (rcrec->ha == rec->ha && rcrec->size == rec->size && + !memcmp(line, rcrec->line, rec->size)) + break; + + if (!rcrec) { + if (!(rcrec = xdl_cha_alloc(&cf->ncha))) { + + return -1; + } + rcrec->idx = cf->count++; + rcrec->line = line; + rcrec->size = rec->size; + rcrec->ha = rec->ha; + rcrec->next = cf->rchash[hi]; + cf->rchash[hi] = rcrec; + } + + rec->ha = (unsigned long) rcrec->idx; + + hi = (long) XDL_HASHLONG(rec->ha, hbits); + rec->next = rhash[hi]; + rhash[hi] = rec; + + return 0; +} + + +static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp, + xdlclassifier_t *cf, xdfile_t *xdf) { + unsigned int hbits; + long i, nrec, hsize, bsize; + unsigned long hav; + char const *blk, *cur, *top, *prev; + xrecord_t *crec; + xrecord_t **recs, **rrecs; + xrecord_t **rhash; + unsigned long *ha; + char *rchg; + long *rindex; + + if (xdl_cha_init(&xdf->rcha, sizeof(xrecord_t), narec / 4 + 1) < 0) { + + return -1; + } + if (!(recs = (xrecord_t **) xdl_malloc(narec * sizeof(xrecord_t *)))) { + + xdl_cha_free(&xdf->rcha); + return -1; + } + + hbits = xdl_hashbits((unsigned int) narec); + hsize = 1 << hbits; + if (!(rhash = (xrecord_t **) xdl_malloc(hsize * sizeof(xrecord_t *)))) { + + xdl_free(recs); + xdl_cha_free(&xdf->rcha); + return -1; + } + for (i = 0; i < hsize; i++) + rhash[i] = NULL; + + nrec = 0; + if ((cur = blk = xdl_mmfile_first(mf, &bsize)) != NULL) { + for (top = blk + bsize;;) { + if (cur >= top) { + if (!(cur = blk = xdl_mmfile_next(mf, &bsize))) + break; + top = blk + bsize; + } + prev = cur; + hav = xdl_hash_record(&cur, top); + if (nrec >= narec) { + narec *= 2; + if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *)))) { + + xdl_free(rhash); + xdl_free(recs); + xdl_cha_free(&xdf->rcha); + return -1; + } + recs = rrecs; + } + if (!(crec = xdl_cha_alloc(&xdf->rcha))) { + + xdl_free(rhash); + xdl_free(recs); + xdl_cha_free(&xdf->rcha); + return -1; + } + crec->ptr = prev; + crec->size = (long) (cur - prev); + crec->ha = hav; + recs[nrec++] = crec; + + if (xdl_classify_record(cf, rhash, hbits, crec) < 0) { + + xdl_free(rhash); + xdl_free(recs); + xdl_cha_free(&xdf->rcha); + return -1; + } + } + } + + if (!(rchg = (char *) xdl_malloc(nrec + 2))) { + + xdl_free(rhash); + xdl_free(recs); + xdl_cha_free(&xdf->rcha); + return -1; + } + memset(rchg, 0, nrec + 2); + + if (!(rindex = (long *) xdl_malloc((nrec + 1) * sizeof(long)))) { + + xdl_free(rchg); + xdl_free(rhash); + xdl_free(recs); + xdl_cha_free(&xdf->rcha); + return -1; + } + if (!(ha = (unsigned long *) xdl_malloc((nrec + 1) * sizeof(unsigned long)))) { + + xdl_free(rindex); + xdl_free(rchg); + xdl_free(rhash); + xdl_free(recs); + xdl_cha_free(&xdf->rcha); + return -1; + } + + xdf->nrec = nrec; + xdf->recs = recs; + xdf->hbits = hbits; + xdf->rhash = rhash; + xdf->rchg = rchg + 1; + xdf->rindex = rindex; + xdf->nreff = 0; + xdf->ha = ha; + xdf->dstart = 0; + xdf->dend = nrec - 1; + + return 0; +} + + +static void xdl_free_ctx(xdfile_t *xdf) { + xdl_free(xdf->rhash); + xdl_free(xdf->rindex); + xdl_free(xdf->rchg - 1); + xdl_free(xdf->ha); + xdl_free(xdf->recs); + xdl_cha_free(&xdf->rcha); +} + + +static int xdl_clean_mmatch(char const *dis, long i, long s, long e) { + long r, rdis0, rpdis0, rdis1, rpdis1; + + /* + * Limits the window the is examined during the similar-lines + * scan. The loops below stops when dis[i - r] == 1 (line that + * has no match), but there are corner cases where the loop + * proceed all the way to the extremities by causing huge + * performance penalties in case of big files. + */ + if (i - s > XDL_SIMSCAN_WINDOWN) + s = i - XDL_SIMSCAN_WINDOWN; + if (e - i > XDL_SIMSCAN_WINDOWN) + e = i + XDL_SIMSCAN_WINDOWN; + + /* + * Scans the lines before 'i' to find a run of lines that either + * have no match (dis[j] == 0) or have multiple matches (dis[j] > 1). + * Note that we always call this function with dis[i] > 1, so the + * current line (i) is already a multimatch line. + */ + for (r = 1, rdis0 = 0, rpdis0 = 1; (i - r) >= s; r++) { + if (!dis[i - r]) + rdis0++; + else if (dis[i - r] == 2) + rpdis0++; + else + break; + } + /* + * If the run before the line 'i' found only multimatch lines, we + * return 0 and hence we don't make the current line (i) discarded. + * We want to discard multimatch lines only when they appear in the + * middle of runs with nomatch lines (dis[j] == 0). + */ + if (rdis0 == 0) + return 0; + for (r = 1, rdis1 = 0, rpdis1 = 1; (i + r) <= e; r++) { + if (!dis[i + r]) + rdis1++; + else if (dis[i + r] == 2) + rpdis1++; + else + break; + } + /* + * If the run after the line 'i' found only multimatch lines, we + * return 0 and hence we don't make the current line (i) discarded. + */ + if (rdis1 == 0) + return 0; + rdis1 += rdis0; + rpdis1 += rpdis0; + + return rpdis1 * XDL_KPDIS_RUN < (rpdis1 + rdis1); +} + + +/* + * Try to reduce the problem complexity, discard records that have no + * matches on the other file. Also, lines that have multiple matches + * might be potentially discarded if they happear in a run of discardable. + */ +static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) { + long i, nm, rhi, nreff, mlim; + unsigned long hav; + xrecord_t **recs; + xrecord_t *rec; + char *dis, *dis1, *dis2; + + if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) { + + return -1; + } + memset(dis, 0, xdf1->nrec + xdf2->nrec + 2); + dis1 = dis; + dis2 = dis1 + xdf1->nrec + 1; + + if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT) + mlim = XDL_MAX_EQLIMIT; + for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) { + hav = (*recs)->ha; + rhi = (long) XDL_HASHLONG(hav, xdf2->hbits); + for (nm = 0, rec = xdf2->rhash[rhi]; rec; rec = rec->next) + if (rec->ha == hav && ++nm == mlim) + break; + dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1; + } + + if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT) + mlim = XDL_MAX_EQLIMIT; + for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) { + hav = (*recs)->ha; + rhi = (long) XDL_HASHLONG(hav, xdf1->hbits); + for (nm = 0, rec = xdf1->rhash[rhi]; rec; rec = rec->next) + if (rec->ha == hav && ++nm == mlim) + break; + dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1; + } + + for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; + i <= xdf1->dend; i++, recs++) { + if (dis1[i] == 1 || + (dis1[i] == 2 && !xdl_clean_mmatch(dis1, i, xdf1->dstart, xdf1->dend))) { + xdf1->rindex[nreff] = i; + xdf1->ha[nreff] = (*recs)->ha; + nreff++; + } else + xdf1->rchg[i] = 1; + } + xdf1->nreff = nreff; + + for (nreff = 0, i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; + i <= xdf2->dend; i++, recs++) { + if (dis2[i] == 1 || + (dis2[i] == 2 && !xdl_clean_mmatch(dis2, i, xdf2->dstart, xdf2->dend))) { + xdf2->rindex[nreff] = i; + xdf2->ha[nreff] = (*recs)->ha; + nreff++; + } else + xdf2->rchg[i] = 1; + } + xdf2->nreff = nreff; + + xdl_free(dis); + + return 0; +} + + +/* + * Early trim initial and terminal matching records. + */ +static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) { + long i, lim; + xrecord_t **recs1, **recs2; + + recs1 = xdf1->recs; + recs2 = xdf2->recs; + for (i = 0, lim = XDL_MIN(xdf1->nrec, xdf2->nrec); i < lim; + i++, recs1++, recs2++) + if ((*recs1)->ha != (*recs2)->ha) + break; + + xdf1->dstart = xdf2->dstart = i; + + recs1 = xdf1->recs + xdf1->nrec - 1; + recs2 = xdf2->recs + xdf2->nrec - 1; + for (lim -= i, i = 0; i < lim; i++, recs1--, recs2--) + if ((*recs1)->ha != (*recs2)->ha) + break; + + xdf1->dend = xdf1->nrec - i - 1; + xdf2->dend = xdf2->nrec - i - 1; + + return 0; +} + + +static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2) { + if (xdl_trim_ends(xdf1, xdf2) < 0 || + xdl_cleanup_records(xdf1, xdf2) < 0) { + + return -1; + } + + return 0; +} + + +int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, + xdfenv_t *xe) { + long enl1, enl2; + xdlclassifier_t cf; + + enl1 = xdl_guess_lines(mf1) + 1; + enl2 = xdl_guess_lines(mf2) + 1; + + if (xdl_init_classifier(&cf, enl1 + enl2 + 1) < 0) { + + return -1; + } + + if (xdl_prepare_ctx(mf1, enl1, xpp, &cf, &xe->xdf1) < 0) { + + xdl_free_classifier(&cf); + return -1; + } + if (xdl_prepare_ctx(mf2, enl2, xpp, &cf, &xe->xdf2) < 0) { + + xdl_free_ctx(&xe->xdf1); + xdl_free_classifier(&cf); + return -1; + } + + xdl_free_classifier(&cf); + + if (xdl_optimize_ctxs(&xe->xdf1, &xe->xdf2) < 0) { + + xdl_free_ctx(&xe->xdf2); + xdl_free_ctx(&xe->xdf1); + return -1; + } + + return 0; +} + + +void xdl_free_env(xdfenv_t *xe) { + xdl_free_ctx(&xe->xdf2); + xdl_free_ctx(&xe->xdf1); +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.h new file mode 100644 index 0000000000..344c569e8b --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xprepare.h @@ -0,0 +1,35 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XPREPARE_H) +#define XPREPARE_H + + + +int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, + xdfenv_t *xe); +void xdl_free_env(xdfenv_t *xe); + + + +#endif /* #if !defined(XPREPARE_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xrabdiff.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xrabdiff.c new file mode 100644 index 0000000000..586d983718 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xrabdiff.c @@ -0,0 +1,381 @@ +/* + * xrabdiff by Davide Libenzi (Rabin's polynomial fingerprint based delta generator) + * Copyright (C) 2006 Davide Libenzi + * + * 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 + * + * Davide Libenzi + * + * + * Hints, ideas and code for the implementation came from: + * + * Rabin's original paper: http://www.xmailserver.org/rabin.pdf + * Chan & Lu's paper: http://www.xmailserver.org/rabin_impl.pdf + * Broder's paper: http://www.xmailserver.org/rabin_apps.pdf + * LBFS source code: http://www.fs.net/sfswww/lbfs/ + * Geert Bosch's post: http://marc.theaimsgroup.com/?l=git&m=114565424620771&w=2 + * + */ + +#include "xinclude.h" + + +#if !defined(XRABPLY_TYPE32) && !defined(XRABPLY_TYPE64) +#define XRABPLY_TYPE64 long long +#define XV64(v) ((xply_word) v ## ULL) +#endif + +#include "xrabply.c" + + + +#define XRAB_SLIDE(v, c) do { \ + if (++wpos == XRAB_WNDSIZE) wpos = 0; \ + v ^= U[wbuf[wpos]]; \ + wbuf[wpos] = (c); \ + v = ((v << 8) | (c)) ^ T[v >> XRAB_SHIFT]; \ + } while (0) + + +#define XRAB_MINCPYSIZE 12 +#define XRAB_WBITS (sizeof(xply_word) * 8) + + + +typedef struct s_xrabctx { + long idxsize; + long *idx; + unsigned char const *data; + long size; +} xrabctx_t; + +typedef struct s_xrabcpyi { + long src; + long tgt; + long len; +} xrabcpyi_t; + +typedef struct s_xrabcpyi_arena { + long cnt, size; + xrabcpyi_t *acpy; +} xrabcpyi_arena_t; + + + +static void xrab_init_cpyarena(xrabcpyi_arena_t *aca) { + aca->cnt = aca->size = 0; + aca->acpy = NULL; +} + + +static void xrab_free_cpyarena(xrabcpyi_arena_t *aca) { + xdl_free(aca->acpy); +} + + +static int xrab_add_cpy(xrabcpyi_arena_t *aca, xrabcpyi_t const *rcpy) { + long size; + xrabcpyi_t *acpy; + + if (aca->cnt >= aca->size) { + size = 2 * aca->size + 1024; + if ((acpy = (xrabcpyi_t *) + xdl_realloc(aca->acpy, size * sizeof(xrabcpyi_t))) == NULL) + return -1; + aca->acpy = acpy; + aca->size = size; + } + aca->acpy[aca->cnt++] = *rcpy; + + return 0; +} + + +static long xrab_cmnseq(unsigned char const *data, long start, long size) { + unsigned char ch = data[start]; + unsigned char const *ptr, *top; + + for (ptr = data + start + 1, top = data + size; ptr < top && ch == *ptr; ptr++); + + return (long) (ptr - (data + start + 1)); +} + + +static int xrab_build_ctx(unsigned char const *data, long size, xrabctx_t *ctx) { + long i, isize, idxsize, seq, wpos = 0; + xply_word fp = 0, mask; + unsigned char ch; + unsigned char const *ptr, *eot; + long *idx; + unsigned char wbuf[XRAB_WNDSIZE]; + long maxoffs[256]; + long maxseq[256]; + xply_word maxfp[256]; + + memset(wbuf, 0, sizeof(wbuf)); + memset(maxseq, 0, sizeof(maxseq)); + isize = 2 * (size / XRAB_WNDSIZE); + for (idxsize = 1; idxsize < isize; idxsize <<= 1); + mask = (xply_word) (idxsize - 1); + if ((idx = (long *) xdl_malloc(idxsize * sizeof(long))) == NULL) + return -1; + memset(idx, 0, idxsize * sizeof(long)); + for (i = 0; i + XRAB_WNDSIZE < size; i += XRAB_WNDSIZE) { + /* + * Generate a brand new hash for the current window. Here we could + * try to perform pseudo-loop unroll by 4 blocks if necessary, and + * if we force XRAB_WNDSIZE to be a multiple of 4, we could reduce + * the branch occurence inside XRAB_SLIDE by a factor of 4. + */ + for (ptr = data + i, eot = ptr + XRAB_WNDSIZE; ptr < eot; ptr++) + XRAB_SLIDE(fp, *ptr); + + /* + * Try to scan for single value scans, and store them in the + * array according to the longest one. Before we do a fast check + * to avoid calling xrab_cmnseq() when not necessary. + */ + if ((ch = data[i]) == data[i + XRAB_WNDSIZE - 1] && + (seq = xrab_cmnseq(data, i, size)) > XRAB_WNDSIZE && + seq > maxseq[ch]) { + maxseq[ch] = seq; + maxfp[ch] = fp; + maxoffs[ch] = i + XRAB_WNDSIZE; + seq = (seq / XRAB_WNDSIZE) * XRAB_WNDSIZE; + i += seq - XRAB_WNDSIZE; + } else + idx[fp & mask] = i + XRAB_WNDSIZE; + } + + /* + * Restore back the logest sequences by overwriting target hash buckets. + */ + for (i = 0; i < 256; i++) + if (maxseq[i]) + idx[maxfp[i] & mask] = maxoffs[i]; + ctx->idxsize = idxsize; + ctx->idx = idx; + ctx->data = data; + ctx->size = size; + + return 0; +} + + +static void xrab_free_ctx(xrabctx_t *ctx) { + + xdl_free(ctx->idx); +} + + +static int xrab_diff(unsigned char const *data, long size, xrabctx_t *ctx, + xrabcpyi_arena_t *aca) { + long i, offs, ssize, src, tgt, esrc, etgt, wpos = 0; + xply_word fp = 0, mask; + long const *idx; + unsigned char const *sdata; + xrabcpyi_t rcpy; + unsigned char wbuf[XRAB_WNDSIZE]; + + xrab_init_cpyarena(aca); + memset(wbuf, 0, sizeof(wbuf)); + for (i = 0; i < XRAB_WNDSIZE - 1 && i < size; i++) + XRAB_SLIDE(fp, data[i]); + idx = ctx->idx; + sdata = ctx->data; + ssize = ctx->size; + mask = (xply_word) (ctx->idxsize - 1); + while (i < size) { + unsigned char ch = data[i++]; + + XRAB_SLIDE(fp, ch); + offs = idx[fp & mask]; + + /* + * Fast check here to probabilistically reduce false positives + * that would trigger the slow path below. + */ + if (offs == 0 || ch != sdata[offs - 1]) + continue; + + /* + * Stretch the match both sides as far as possible. + */ + src = offs - 1; + tgt = i - 1; + for (; tgt > 0 && src > 0 && data[tgt - 1] == sdata[src - 1]; + tgt--, src--); + esrc = offs; + etgt = i; + for (; etgt < size && esrc < ssize && data[etgt] == sdata[esrc]; + etgt++, esrc++); + + /* + * Avoid considering copies smaller than the XRAB_MINCPYSIZE + * threshold. + */ + if (etgt - tgt >= XRAB_MINCPYSIZE) { + rcpy.src = src; + rcpy.tgt = tgt; + rcpy.len = etgt - tgt; + if (xrab_add_cpy(aca, &rcpy) < 0) { + xrab_free_cpyarena(aca); + return -1; + } + + /* + * Fill up the new window and exit with 'i' properly set on exit. + */ + for (i = etgt - XRAB_WNDSIZE; i < etgt; i++) + XRAB_SLIDE(fp, data[i]); + } + } + + return 0; +} + + +static int xrab_tune_cpyarena(unsigned char const *data, long size, xrabctx_t *ctx, + xrabcpyi_arena_t *aca) { + long i, cpos; + xrabcpyi_t *rcpy; + + for (cpos = size, i = aca->cnt - 1; i >= 0; i--) { + rcpy = aca->acpy + i; + if (rcpy->tgt >= cpos) + rcpy->len = 0; + else if (rcpy->tgt + rcpy->len > cpos) { + if ((rcpy->len = cpos - rcpy->tgt) >= XRAB_MINCPYSIZE) + cpos = rcpy->tgt; + else + rcpy->len = 0; + } else + cpos = rcpy->tgt; + } + + return 0; +} + + +int xdl_rabdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, xdemitcb_t *ecb) { + long i, cpos, size; + unsigned long fp; + xrabcpyi_t *rcpy; + xrabctx_t ctx; + xrabcpyi_arena_t aca; + mmbuffer_t mb[2]; + unsigned char cpybuf[32]; + + fp = xdl_mmb_adler32(mmb1); + if (xrab_build_ctx((unsigned char const *) mmb1->ptr, mmb1->size, + &ctx) < 0) + return -1; + if (xrab_diff((unsigned char const *) mmb2->ptr, mmb2->size, &ctx, + &aca) < 0) { + xrab_free_ctx(&ctx); + return -1; + } + xrab_tune_cpyarena((unsigned char const *) mmb2->ptr, mmb2->size, &ctx, + &aca); + xrab_free_ctx(&ctx); + + /* + * Prepare and emit the binary patch file header. It will be used + * to verify that that file being patched matches in size and fingerprint + * the one that generated the patch. + */ + size = mmb1->size; + XDL_LE32_PUT(cpybuf, fp); + XDL_LE32_PUT(cpybuf + 4, size); + + mb[0].ptr = (char *) cpybuf; + mb[0].size = 4 + 4; + if (ecb->outf(ecb->priv, mb, 1) < 0) { + xrab_free_cpyarena(&aca); + return -1; + } + for (cpos = 0, i = 0; i < aca.cnt; i++) { + rcpy = aca.acpy + i; + if (rcpy->len == 0) + continue; + if (cpos < rcpy->tgt) { + size = rcpy->tgt - cpos; + if (size > 255) { + cpybuf[0] = XDL_BDOP_INSB; + XDL_LE32_PUT(cpybuf + 1, size); + mb[0].ptr = (char *) cpybuf; + mb[0].size = XDL_INSBOP_SIZE; + } else { + cpybuf[0] = XDL_BDOP_INS; + cpybuf[1] = (unsigned char) size; + mb[0].ptr = (char *) cpybuf; + mb[0].size = 2; + } + mb[1].ptr = mmb2->ptr + cpos; + mb[1].size = size; + if (ecb->outf(ecb->priv, mb, 2) < 0) { + xrab_free_cpyarena(&aca); + return -1; + } + cpos = rcpy->tgt; + } + cpybuf[0] = XDL_BDOP_CPY; + XDL_LE32_PUT(cpybuf + 1, rcpy->src); + XDL_LE32_PUT(cpybuf + 5, rcpy->len); + mb[0].ptr = (char *) cpybuf; + mb[0].size = XDL_COPYOP_SIZE; + if (ecb->outf(ecb->priv, mb, 1) < 0) { + xrab_free_cpyarena(&aca); + return -1; + } + cpos += rcpy->len; + } + xrab_free_cpyarena(&aca); + if (cpos < mmb2->size) { + size = mmb2->size - cpos; + if (size > 255) { + cpybuf[0] = XDL_BDOP_INSB; + XDL_LE32_PUT(cpybuf + 1, size); + mb[0].ptr = (char *) cpybuf; + mb[0].size = XDL_INSBOP_SIZE; + } else { + cpybuf[0] = XDL_BDOP_INS; + cpybuf[1] = (unsigned char) size; + mb[0].ptr = (char *) cpybuf; + mb[0].size = 2; + } + mb[1].ptr = mmb2->ptr + cpos; + mb[1].size = size; + if (ecb->outf(ecb->priv, mb, 2) < 0) + return -1; + } + + return 0; +} + + +int xdl_rabdiff(mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb) { + mmbuffer_t mmb1, mmb2; + + if (!xdl_mmfile_iscompact(mmf1) || !xdl_mmfile_iscompact(mmf2)) + return -1; + if ((mmb1.ptr = (char *) xdl_mmfile_first(mmf1, &mmb1.size)) == NULL) + mmb1.size = 0; + if ((mmb2.ptr = (char *) xdl_mmfile_first(mmf2, &mmb2.size)) == NULL) + mmb2.size = 0; + + return xdl_rabdiff_mb(&mmb1, &mmb2, ecb); +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xrabply.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xrabply.c new file mode 100644 index 0000000000..daaabdaa4f --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xrabply.c @@ -0,0 +1,298 @@ +#if defined(XRABPLY_TYPE64) + +#if !defined(XV64) +#define XV64(v) ((xply_word) v ## ULL) +#endif + +#define XRAB_ROOTPOLY XV64(0x36f7381af4d70d33) + +#define XRAB_SHIFT 53 +#define XRAB_WNDSIZE 20 + +typedef unsigned XRABPLY_TYPE64 xply_word; + +static const xply_word T[256] = { + XV64(0x0), XV64(0x36f7381af4d70d33), XV64(0x5b19482f1d791755), XV64(0x6dee7035e9ae1a66), + XV64(0x80c5a844ce252399), XV64(0xb632905e3af22eaa), XV64(0xdbdce06bd35c34cc), XV64(0xed2bd871278b39ff), + XV64(0x18b50899c4a4732), XV64(0x377c6893689d4a01), XV64(0x5a9218a681335067), XV64(0x6c6520bc75e45d54), + XV64(0x814ef8cd526f64ab), XV64(0xb7b9c0d7a6b86998), XV64(0xda57b0e24f1673fe), XV64(0xeca088f8bbc17ecd), + XV64(0x316a11338948e64), XV64(0x35e19909cc438357), XV64(0x580fe93c25ed9931), XV64(0x6ef8d126d13a9402), + XV64(0x83d30957f6b1adfd), XV64(0xb524314d0266a0ce), XV64(0xd8ca4178ebc8baa8), XV64(0xee3d79621f1fb79b), + XV64(0x29df19aa4dec956), XV64(0x346ac9805009c465), XV64(0x5984b9b5b9a7de03), XV64(0x6f7381af4d70d330), + XV64(0x825859de6afbeacf), XV64(0xb4af61c49e2ce7fc), XV64(0xd94111f17782fd9a), XV64(0xefb629eb8355f0a9), + XV64(0x62d422671291cc8), XV64(0x30da7a3c85fe11fb), XV64(0x5d340a096c500b9d), XV64(0x6bc33213988706ae), + XV64(0x86e8ea62bf0c3f51), XV64(0xb01fd2784bdb3262), XV64(0xddf1a24da2752804), XV64(0xeb069a5756a22537), + XV64(0x7a612afed635bfa), XV64(0x31512ab519b456c9), XV64(0x5cbf5a80f01a4caf), XV64(0x6a48629a04cd419c), + XV64(0x8763baeb23467863), XV64(0xb19482f1d7917550), XV64(0xdc7af2c43e3f6f36), XV64(0xea8dcadecae86205), + XV64(0x53be33549bd92ac), XV64(0x33ccdb2fbd6a9f9f), XV64(0x5e22ab1a54c485f9), XV64(0x68d59300a01388ca), + XV64(0x85fe4b718798b135), XV64(0xb309736b734fbc06), XV64(0xdee7035e9ae1a660), XV64(0xe8103b446e36ab53), + XV64(0x4b0b3bcd5f7d59e), XV64(0x32478ba62120d8ad), XV64(0x5fa9fb93c88ec2cb), XV64(0x695ec3893c59cff8), + XV64(0x84751bf81bd2f607), XV64(0xb28223e2ef05fb34), XV64(0xdf6c53d706abe152), XV64(0xe99b6bcdf27cec61), + XV64(0xc5a844ce2523990), XV64(0x3aadbc56168534a3), XV64(0x5743cc63ff2b2ec5), XV64(0x61b4f4790bfc23f6), + XV64(0x8c9f2c082c771a09), XV64(0xba681412d8a0173a), XV64(0xd7866427310e0d5c), XV64(0xe1715c3dc5d9006f), + XV64(0xdd1d4c57e187ea2), XV64(0x3b26ecdf8acf7391), XV64(0x56c89cea636169f7), XV64(0x603fa4f097b664c4), + XV64(0x8d147c81b03d5d3b), XV64(0xbbe3449b44ea5008), XV64(0xd60d34aead444a6e), XV64(0xe0fa0cb45993475d), + XV64(0xf4c255fdac6b7f4), XV64(0x39bb1d452e11bac7), XV64(0x54556d70c7bfa0a1), XV64(0x62a2556a3368ad92), + XV64(0x8f898d1b14e3946d), XV64(0xb97eb501e034995e), XV64(0xd490c534099a8338), XV64(0xe267fd2efd4d8e0b), + XV64(0xec775d6468cf0c6), XV64(0x38304dccb25bfdf5), XV64(0x55de3df95bf5e793), XV64(0x632905e3af22eaa0), + XV64(0x8e02dd9288a9d35f), XV64(0xb8f5e5887c7ede6c), XV64(0xd51b95bd95d0c40a), XV64(0xe3ecada76107c939), + XV64(0xa77c66a937b2558), XV64(0x3c80fe7067ac286b), XV64(0x516e8e458e02320d), XV64(0x6799b65f7ad53f3e), + XV64(0x8ab26e2e5d5e06c1), XV64(0xbc455634a9890bf2), XV64(0xd1ab260140271194), XV64(0xe75c1e1bb4f01ca7), + XV64(0xbfc96e30f31626a), XV64(0x3d0baef9fbe66f59), XV64(0x50e5decc1248753f), XV64(0x6612e6d6e69f780c), + XV64(0x8b393ea7c11441f3), XV64(0xbdce06bd35c34cc0), XV64(0xd0207688dc6d56a6), XV64(0xe6d74e9228ba5b95), + XV64(0x9616779abefab3c), XV64(0x3f965f635f38a60f), XV64(0x52782f56b696bc69), XV64(0x648f174c4241b15a), + XV64(0x89a4cf3d65ca88a5), XV64(0xbf53f727911d8596), XV64(0xd2bd871278b39ff0), XV64(0xe44abf088c6492c3), + XV64(0x8ea37f037a5ec0e), XV64(0x3e1d0feac372e13d), XV64(0x53f37fdf2adcfb5b), XV64(0x650447c5de0bf668), + XV64(0x882f9fb4f980cf97), XV64(0xbed8a7ae0d57c2a4), XV64(0xd336d79be4f9d8c2), XV64(0xe5c1ef81102ed5f1), + XV64(0x18b50899c4a47320), XV64(0x2e42308330737e13), XV64(0x43ac40b6d9dd6475), XV64(0x755b78ac2d0a6946), + XV64(0x9870a0dd0a8150b9), XV64(0xae8798c7fe565d8a), XV64(0xc369e8f217f847ec), XV64(0xf59ed0e8e32f4adf), + XV64(0x193e581058ee3412), XV64(0x2fc9600aac393921), XV64(0x4227103f45972347), XV64(0x74d02825b1402e74), + XV64(0x99fbf05496cb178b), XV64(0xaf0cc84e621c1ab8), XV64(0xc2e2b87b8bb200de), XV64(0xf41580617f650ded), + XV64(0x1ba3a98afc30fd44), XV64(0x2d54919008e7f077), XV64(0x40bae1a5e149ea11), XV64(0x764dd9bf159ee722), + XV64(0x9b6601ce3215dedd), XV64(0xad9139d4c6c2d3ee), XV64(0xc07f49e12f6cc988), XV64(0xf68871fbdbbbc4bb), + XV64(0x1a28f903607aba76), XV64(0x2cdfc11994adb745), XV64(0x4131b12c7d03ad23), XV64(0x77c6893689d4a010), + XV64(0x9aed5147ae5f99ef), XV64(0xac1a695d5a8894dc), XV64(0xc1f41968b3268eba), XV64(0xf703217247f18389), + XV64(0x1e984abfb58d6fe8), XV64(0x286f72a5415a62db), XV64(0x45810290a8f478bd), XV64(0x73763a8a5c23758e), + XV64(0x9e5de2fb7ba84c71), XV64(0xa8aadae18f7f4142), XV64(0xc544aad466d15b24), XV64(0xf3b392ce92065617), + XV64(0x1f131a3629c728da), XV64(0x29e4222cdd1025e9), XV64(0x440a521934be3f8f), XV64(0x72fd6a03c06932bc), + XV64(0x9fd6b272e7e20b43), XV64(0xa9218a6813350670), XV64(0xc4cffa5dfa9b1c16), XV64(0xf238c2470e4c1125), + XV64(0x1d8eebac8d19e18c), XV64(0x2b79d3b679ceecbf), XV64(0x4697a3839060f6d9), XV64(0x70609b9964b7fbea), + XV64(0x9d4b43e8433cc215), XV64(0xabbc7bf2b7ebcf26), XV64(0xc6520bc75e45d540), XV64(0xf0a533ddaa92d873), + XV64(0x1c05bb251153a6be), XV64(0x2af2833fe584ab8d), XV64(0x471cf30a0c2ab1eb), XV64(0x71ebcb10f8fdbcd8), + XV64(0x9cc01361df768527), XV64(0xaa372b7b2ba18814), XV64(0xc7d95b4ec20f9272), XV64(0xf12e635436d89f41), + XV64(0x14ef8cd526f64ab0), XV64(0x2218b4cfd2214783), XV64(0x4ff6c4fa3b8f5de5), XV64(0x7901fce0cf5850d6), + XV64(0x942a2491e8d36929), XV64(0xa2dd1c8b1c04641a), XV64(0xcf336cbef5aa7e7c), XV64(0xf9c454a4017d734f), + XV64(0x1564dc5cbabc0d82), XV64(0x2393e4464e6b00b1), XV64(0x4e7d9473a7c51ad7), XV64(0x788aac69531217e4), + XV64(0x95a1741874992e1b), XV64(0xa3564c02804e2328), XV64(0xceb83c3769e0394e), XV64(0xf84f042d9d37347d), + XV64(0x17f92dc61e62c4d4), XV64(0x210e15dceab5c9e7), XV64(0x4ce065e9031bd381), XV64(0x7a175df3f7ccdeb2), + XV64(0x973c8582d047e74d), XV64(0xa1cbbd982490ea7e), XV64(0xcc25cdadcd3ef018), XV64(0xfad2f5b739e9fd2b), + XV64(0x16727d4f822883e6), XV64(0x2085455576ff8ed5), XV64(0x4d6b35609f5194b3), XV64(0x7b9c0d7a6b869980), + XV64(0x96b7d50b4c0da07f), XV64(0xa040ed11b8daad4c), XV64(0xcdae9d245174b72a), XV64(0xfb59a53ea5a3ba19), + XV64(0x12c2cef357df5678), XV64(0x2435f6e9a3085b4b), XV64(0x49db86dc4aa6412d), XV64(0x7f2cbec6be714c1e), + XV64(0x920766b799fa75e1), XV64(0xa4f05ead6d2d78d2), XV64(0xc91e2e98848362b4), XV64(0xffe9168270546f87), + XV64(0x13499e7acb95114a), XV64(0x25bea6603f421c79), XV64(0x4850d655d6ec061f), XV64(0x7ea7ee4f223b0b2c), + XV64(0x938c363e05b032d3), XV64(0xa57b0e24f1673fe0), XV64(0xc8957e1118c92586), XV64(0xfe62460bec1e28b5), + XV64(0x11d46fe06f4bd81c), XV64(0x272357fa9b9cd52f), XV64(0x4acd27cf7232cf49), XV64(0x7c3a1fd586e5c27a), + XV64(0x9111c7a4a16efb85), XV64(0xa7e6ffbe55b9f6b6), XV64(0xca088f8bbc17ecd0), XV64(0xfcffb79148c0e1e3), + XV64(0x105f3f69f3019f2e), XV64(0x26a8077307d6921d), XV64(0x4b467746ee78887b), XV64(0x7db14f5c1aaf8548), + XV64(0x909a972d3d24bcb7), XV64(0xa66daf37c9f3b184), XV64(0xcb83df02205dabe2), XV64(0xfd74e718d48aa6d1) +}; + +static const xply_word U[256] = { + XV64(0x0), XV64(0x1c3eb44b122426b2), XV64(0xe8a508cd09f4057), XV64(0x12b4e4c7c2bb66e5), + XV64(0x1d14a119a13e80ae), XV64(0x12a1552b31aa61c), XV64(0x139ef19571a1c0f9), XV64(0xfa045de6385e64b), + XV64(0xcde7a29b6aa0c6f), XV64(0x10e0ce62a48e2add), XV64(0x2542aa566354c38), XV64(0x1e6a9eee74116a8a), + XV64(0x11cadb3017948cc1), XV64(0xdf46f7b05b0aa73), XV64(0x1f408bbcc70bcc96), XV64(0x37e3ff7d52fea24), + XV64(0x19bcf4536d5418de), XV64(0x58240187f703e6c), XV64(0x1736a4dfbdcb5889), XV64(0xb081094afef7e3b), + XV64(0x4a8554acc6a9870), XV64(0x1896e101de4ebec2), XV64(0xa2205c61cf5d827), XV64(0x161cb18d0ed1fe95), + XV64(0x15628e7adbfe14b1), XV64(0x95c3a31c9da3203), XV64(0x1be8def60b6154e6), XV64(0x7d66abd19457254), + XV64(0x8762f637ac0941f), XV64(0x14489b2868e4b2ad), XV64(0x6fc7fefaa5fd448), XV64(0x1ac2cba4b87bf2fa), + XV64(0x58ed0bc2e7f3c8f), XV64(0x19b064f73c5b1a3d), XV64(0xb048030fee07cd8), XV64(0x173a347becc45a6a), + XV64(0x189a71a58f41bc21), XV64(0x4a4c5ee9d659a93), XV64(0x161021295fdefc76), XV64(0xa2e95624dfadac4), + XV64(0x950aa9598d530e0), XV64(0x156e1ede8af11652), XV64(0x7dafa19484a70b7), XV64(0x1be44e525a6e5605), + XV64(0x14440b8c39ebb04e), XV64(0x87abfc72bcf96fc), XV64(0x1ace5b00e974f019), XV64(0x6f0ef4bfb50d6ab), + XV64(0x1c3224ef432b2451), XV64(0xc90a4510f02e3), XV64(0x12b8746393b46406), XV64(0xe86c028819042b4), + XV64(0x12685f6e215a4ff), XV64(0x1d1831bdf031824d), XV64(0xfacd57a328ae4a8), XV64(0x1392613120aec21a), + XV64(0x10ec5ec6f581283e), XV64(0xcd2ea8de7a50e8c), XV64(0x1e660e4a251e6869), XV64(0x258ba01373a4edb), + XV64(0xdf8ffdf54bfa890), XV64(0x11c64b94469b8e22), XV64(0x372af538420e8c7), XV64(0x1f4c1b189604ce75), + XV64(0xb1da1785cfe791e), XV64(0x172315334eda5fac), XV64(0x597f1f48c613949), XV64(0x19a945bf9e451ffb), + XV64(0x16090061fdc0f9b0), XV64(0xa37b42aefe4df02), XV64(0x188350ed2d5fb9e7), XV64(0x4bde4a63f7b9f55), + XV64(0x7c3db51ea547571), XV64(0x1bfd6f1af87053c3), XV64(0x9498bdd3acb3526), XV64(0x15773f9628ef1394), + XV64(0x1ad77a484b6af5df), XV64(0x6e9ce03594ed36d), XV64(0x145d2ac49bf5b588), XV64(0x8639e8f89d1933a), + XV64(0x12a1552b31aa61c0), XV64(0xe9fe160238e4772), XV64(0x1c2b05a7e1352197), XV64(0x15b1ecf3110725), + XV64(0xfb5f4329094e16e), XV64(0x138b407982b0c7dc), XV64(0x13fa4be400ba139), XV64(0x1d0110f5522f878b), + XV64(0x1e7f2f0287006daf), XV64(0x2419b4995244b1d), XV64(0x10f57f8e579f2df8), XV64(0xccbcbc545bb0b4a), + XV64(0x36b8e1b263eed01), XV64(0x1f553a50341acbb3), XV64(0xde1de97f6a1ad56), XV64(0x11df6adce4858be4), + XV64(0xe9371c472814591), XV64(0x12adc58f60a56323), XV64(0x192148a21e05c6), XV64(0x1c279503b03a2374), + XV64(0x1387d0ddd3bfc53f), XV64(0xfb96496c19be38d), XV64(0x1d0d805103208568), XV64(0x133341a1104a3da), + XV64(0x24d0bedc42b49fe), XV64(0x1e73bfa6d60f6f4c), XV64(0xcc75b6114b409a9), XV64(0x10f9ef2a06902f1b), + XV64(0x1f59aaf46515c950), XV64(0x3671ebf7731efe2), XV64(0x11d3fa78b58a8907), XV64(0xded4e33a7aeafb5), + XV64(0x172f85971fd55d4f), XV64(0xb1131dc0df17bfd), XV64(0x19a5d51bcf4a1d18), XV64(0x59b6150dd6e3baa), + XV64(0xa3b248ebeebdde1), XV64(0x160590c5accffb53), XV64(0x4b174026e749db6), XV64(0x188fc0497c50bb04), + XV64(0x1bf1ffbea97f5120), XV64(0x7cf4bf5bb5b7792), XV64(0x157baf3279e01177), XV64(0x9451b796bc437c5), + XV64(0x6e55ea70841d18e), XV64(0x1adbeaec1a65f73c), XV64(0x86f0e2bd8de91d9), XV64(0x1451ba60cafab76b), + XV64(0x163b42f0b9fcf23c), XV64(0xa05f6bbabd8d48e), XV64(0x18b1127c6963b26b), XV64(0x48fa6377b4794d9), + XV64(0xb2fe3e918c27292), XV64(0x171157a20ae65420), XV64(0x5a5b365c85d32c5), XV64(0x199b072eda791477), + XV64(0x1ae538d90f56fe53), XV64(0x6db8c921d72d8e1), XV64(0x146f6855dfc9be04), XV64(0x851dc1ecded98b6), + XV64(0x7f199c0ae687efd), XV64(0x1bcf2d8bbc4c584f), XV64(0x97bc94c7ef73eaa), XV64(0x15457d076cd31818), + XV64(0xf87b6a3d4a8eae2), XV64(0x13b902e8c68ccc50), XV64(0x10de62f0437aab5), XV64(0x1d33526416138c07), + XV64(0x129317ba75966a4c), XV64(0xeada3f167b24cfe), XV64(0x1c194736a5092a1b), XV64(0x27f37db72d0ca9), + XV64(0x359cc8a6202e68d), XV64(0x1f6778c17026c03f), XV64(0xdd39c06b29da6da), XV64(0x11ed284da0b98068), + XV64(0x1e4d6d93c33c6623), XV64(0x273d9d8d1184091), XV64(0x10c73d1f13a32674), XV64(0xcf98954018700c6), + XV64(0x13b5924c9783ceb3), XV64(0xf8b260785a7e801), XV64(0x1d3fc2c0471c8ee4), XV64(0x101768b5538a856), + XV64(0xea1335536bd4e1d), XV64(0x129f871e249968af), XV64(0x2b63d9e6220e4a), XV64(0x1c15d792f40628f8), + XV64(0x1f6be8652129c2dc), XV64(0x3555c2e330de46e), XV64(0x11e1b8e9f1b6828b), XV64(0xddf0ca2e392a439), + XV64(0x27f497c80174272), XV64(0x1e41fd37923364c0), XV64(0xcf519f050880225), XV64(0x10cbadbb42ac2497), + XV64(0xa09661ffad7d66d), XV64(0x1637d254e8f3f0df), XV64(0x48336932a48963a), XV64(0x18bd82d8386cb088), + XV64(0x171dc7065be956c3), XV64(0xb23734d49cd7071), XV64(0x1997978a8b761694), XV64(0x5a923c199523026), + XV64(0x6d71c364c7dda02), XV64(0x1ae9a87d5e59fcb0), XV64(0x85d4cba9ce29a55), XV64(0x1463f8f18ec6bce7), + XV64(0x1bc3bd2fed435aac), XV64(0x7fd0964ff677c1e), XV64(0x1549eda33ddc1afb), XV64(0x97759e82ff83c49), + XV64(0x1d26e388e5028b22), XV64(0x11857c3f726ad90), XV64(0x13acb304359dcb75), XV64(0xf92074f27b9edc7), + XV64(0x324291443c0b8c), XV64(0x1c0cf6da56182d3e), XV64(0xeb8121d94a34bdb), XV64(0x1286a65686876d69), + XV64(0x11f899a153a8874d), XV64(0xdc62dea418ca1ff), XV64(0x1f72c92d8337c71a), XV64(0x34c7d669113e1a8), + XV64(0xcec38b8f29607e3), XV64(0x10d28cf3e0b22151), XV64(0x2666834220947b4), XV64(0x1e58dc7f302d6106), + XV64(0x49a17db885693fc), XV64(0x18a4a3909a72b54e), XV64(0xa10475758c9d3ab), XV64(0x162ef31c4aedf519), + XV64(0x198eb6c229681352), XV64(0x5b002893b4c35e0), XV64(0x1704e64ef9f75305), XV64(0xb3a5205ebd375b7), + XV64(0x8446df23efc9f93), XV64(0x147ad9b92cd8b921), XV64(0x6ce3d7eee63dfc4), XV64(0x1af08935fc47f976), + XV64(0x1550cceb9fc21f3d), XV64(0x96e78a08de6398f), XV64(0x1bda9c674f5d5f6a), XV64(0x7e4282c5d7979d8), + XV64(0x18a83334cb7db7ad), XV64(0x496877fd959911f), XV64(0x162263b81be2f7fa), XV64(0xa1cd7f309c6d148), + XV64(0x5bc922d6a433703), XV64(0x19822666786711b1), XV64(0xb36c2a1badc7754), XV64(0x170876eaa8f851e6), + XV64(0x1476491d7dd7bbc2), XV64(0x848fd566ff39d70), XV64(0x1afc1991ad48fb95), XV64(0x6c2addabf6cdd27), + XV64(0x962e804dce93b6c), XV64(0x155c5c4fcecd1dde), XV64(0x7e8b8880c767b3b), XV64(0x1bd60cc31e525d89), + XV64(0x114c767a629af73), XV64(0x1d2a732cb40d89c1), XV64(0xf9e97eb76b6ef24), XV64(0x13a023a06492c996), + XV64(0x1c00667e07172fdd), XV64(0x3ed2351533096f), XV64(0x128a36f2d7886f8a), XV64(0xeb482b9c5ac4938), + XV64(0xdcabd4e1083a31c), XV64(0x11f4090502a785ae), XV64(0x340edc2c01ce34b), XV64(0x1f7e5989d238c5f9), + XV64(0x10de1c57b1bd23b2), XV64(0xce0a81ca3990500), XV64(0x1e544cdb612263e5), XV64(0x26af89073064557) +}; + +#endif /* if defined(XRABPLY_TYPE64) */ + +#if defined(XRABPLY_TYPE32) + +#if !defined(XV32) +#define XV32(v) ((xply_word) v ## ULL) +#endif + +#define XRAB_ROOTPOLY XV32(0xabd1f37b) + +#define XRAB_SHIFT 23 +#define XRAB_WNDSIZE 20 + +typedef unsigned XRABPLY_TYPE32 xply_word; + +static const xply_word T[256] = { + XV32(0x0), XV32(0xabd1f37b), XV32(0x57a3e6f6), XV32(0xfc72158d), + XV32(0x4963e97), XV32(0xaf47cdec), XV32(0x5335d861), XV32(0xf8e42b1a), + XV32(0x92c7d2e), XV32(0xa2fd8e55), XV32(0x5e8f9bd8), XV32(0xf55e68a3), + XV32(0xdba43b9), XV32(0xa66bb0c2), XV32(0x5a19a54f), XV32(0xf1c85634), + XV32(0x1258fa5c), XV32(0xb9890927), XV32(0x45fb1caa), XV32(0xee2aefd1), + XV32(0x16cec4cb), XV32(0xbd1f37b0), XV32(0x416d223d), XV32(0xeabcd146), + XV32(0x1b748772), XV32(0xb0a57409), XV32(0x4cd76184), XV32(0xe70692ff), + XV32(0x1fe2b9e5), XV32(0xb4334a9e), XV32(0x48415f13), XV32(0xe390ac68), + XV32(0x24b1f4b8), XV32(0x8f6007c3), XV32(0x7312124e), XV32(0xd8c3e135), + XV32(0x2027ca2f), XV32(0x8bf63954), XV32(0x77842cd9), XV32(0xdc55dfa2), + XV32(0x2d9d8996), XV32(0x864c7aed), XV32(0x7a3e6f60), XV32(0xd1ef9c1b), + XV32(0x290bb701), XV32(0x82da447a), XV32(0x7ea851f7), XV32(0xd579a28c), + XV32(0x36e90ee4), XV32(0x9d38fd9f), XV32(0x614ae812), XV32(0xca9b1b69), + XV32(0x327f3073), XV32(0x99aec308), XV32(0x65dcd685), XV32(0xce0d25fe), + XV32(0x3fc573ca), XV32(0x941480b1), XV32(0x6866953c), XV32(0xc3b76647), + XV32(0x3b534d5d), XV32(0x9082be26), XV32(0x6cf0abab), XV32(0xc72158d0), + XV32(0x4963e970), XV32(0xe2b21a0b), XV32(0x1ec00f86), XV32(0xb511fcfd), + XV32(0x4df5d7e7), XV32(0xe624249c), XV32(0x1a563111), XV32(0xb187c26a), + XV32(0x404f945e), XV32(0xeb9e6725), XV32(0x17ec72a8), XV32(0xbc3d81d3), + XV32(0x44d9aac9), XV32(0xef0859b2), XV32(0x137a4c3f), XV32(0xb8abbf44), + XV32(0x5b3b132c), XV32(0xf0eae057), XV32(0xc98f5da), XV32(0xa74906a1), + XV32(0x5fad2dbb), XV32(0xf47cdec0), XV32(0x80ecb4d), XV32(0xa3df3836), + XV32(0x52176e02), XV32(0xf9c69d79), XV32(0x5b488f4), XV32(0xae657b8f), + XV32(0x56815095), XV32(0xfd50a3ee), XV32(0x122b663), XV32(0xaaf34518), + XV32(0x6dd21dc8), XV32(0xc603eeb3), XV32(0x3a71fb3e), XV32(0x91a00845), + XV32(0x6944235f), XV32(0xc295d024), XV32(0x3ee7c5a9), XV32(0x953636d2), + XV32(0x64fe60e6), XV32(0xcf2f939d), XV32(0x335d8610), XV32(0x988c756b), + XV32(0x60685e71), XV32(0xcbb9ad0a), XV32(0x37cbb887), XV32(0x9c1a4bfc), + XV32(0x7f8ae794), XV32(0xd45b14ef), XV32(0x28290162), XV32(0x83f8f219), + XV32(0x7b1cd903), XV32(0xd0cd2a78), XV32(0x2cbf3ff5), XV32(0x876ecc8e), + XV32(0x76a69aba), XV32(0xdd7769c1), XV32(0x21057c4c), XV32(0x8ad48f37), + XV32(0x7230a42d), XV32(0xd9e15756), XV32(0x259342db), XV32(0x8e42b1a0), + XV32(0x3916219b), XV32(0x92c7d2e0), XV32(0x6eb5c76d), XV32(0xc5643416), + XV32(0x3d801f0c), XV32(0x9651ec77), XV32(0x6a23f9fa), XV32(0xc1f20a81), + XV32(0x303a5cb5), XV32(0x9bebafce), XV32(0x6799ba43), XV32(0xcc484938), + XV32(0x34ac6222), XV32(0x9f7d9159), XV32(0x630f84d4), XV32(0xc8de77af), + XV32(0x2b4edbc7), XV32(0x809f28bc), XV32(0x7ced3d31), XV32(0xd73cce4a), + XV32(0x2fd8e550), XV32(0x8409162b), XV32(0x787b03a6), XV32(0xd3aaf0dd), + XV32(0x2262a6e9), XV32(0x89b35592), XV32(0x75c1401f), XV32(0xde10b364), + XV32(0x26f4987e), XV32(0x8d256b05), XV32(0x71577e88), XV32(0xda868df3), + XV32(0x1da7d523), XV32(0xb6762658), XV32(0x4a0433d5), XV32(0xe1d5c0ae), + XV32(0x1931ebb4), XV32(0xb2e018cf), XV32(0x4e920d42), XV32(0xe543fe39), + XV32(0x148ba80d), XV32(0xbf5a5b76), XV32(0x43284efb), XV32(0xe8f9bd80), + XV32(0x101d969a), XV32(0xbbcc65e1), XV32(0x47be706c), XV32(0xec6f8317), + XV32(0xfff2f7f), XV32(0xa42edc04), XV32(0x585cc989), XV32(0xf38d3af2), + XV32(0xb6911e8), XV32(0xa0b8e293), XV32(0x5ccaf71e), XV32(0xf71b0465), + XV32(0x6d35251), XV32(0xad02a12a), XV32(0x5170b4a7), XV32(0xfaa147dc), + XV32(0x2456cc6), XV32(0xa9949fbd), XV32(0x55e68a30), XV32(0xfe37794b), + XV32(0x7075c8eb), XV32(0xdba43b90), XV32(0x27d62e1d), XV32(0x8c07dd66), + XV32(0x74e3f67c), XV32(0xdf320507), XV32(0x2340108a), XV32(0x8891e3f1), + XV32(0x7959b5c5), XV32(0xd28846be), XV32(0x2efa5333), XV32(0x852ba048), + XV32(0x7dcf8b52), XV32(0xd61e7829), XV32(0x2a6c6da4), XV32(0x81bd9edf), + XV32(0x622d32b7), XV32(0xc9fcc1cc), XV32(0x358ed441), XV32(0x9e5f273a), + XV32(0x66bb0c20), XV32(0xcd6aff5b), XV32(0x3118ead6), XV32(0x9ac919ad), + XV32(0x6b014f99), XV32(0xc0d0bce2), XV32(0x3ca2a96f), XV32(0x97735a14), + XV32(0x6f97710e), XV32(0xc4468275), XV32(0x383497f8), XV32(0x93e56483), + XV32(0x54c43c53), XV32(0xff15cf28), XV32(0x367daa5), XV32(0xa8b629de), + XV32(0x505202c4), XV32(0xfb83f1bf), XV32(0x7f1e432), XV32(0xac201749), + XV32(0x5de8417d), XV32(0xf639b206), XV32(0xa4ba78b), XV32(0xa19a54f0), + XV32(0x597e7fea), XV32(0xf2af8c91), XV32(0xedd991c), XV32(0xa50c6a67), + XV32(0x469cc60f), XV32(0xed4d3574), XV32(0x113f20f9), XV32(0xbaeed382), + XV32(0x420af898), XV32(0xe9db0be3), XV32(0x15a91e6e), XV32(0xbe78ed15), + XV32(0x4fb0bb21), XV32(0xe461485a), XV32(0x18135dd7), XV32(0xb3c2aeac), + XV32(0x4b2685b6), XV32(0xe0f776cd), XV32(0x1c856340), XV32(0xb754903b) +}; + +static const xply_word U[256] = { + XV32(0x0), XV32(0x5ce33923), XV32(0x1217813d), XV32(0x4ef4b81e), + XV32(0x242f027a), XV32(0x78cc3b59), XV32(0x36388347), XV32(0x6adbba64), + XV32(0x485e04f4), XV32(0x14bd3dd7), XV32(0x5a4985c9), XV32(0x6aabcea), + XV32(0x6c71068e), XV32(0x30923fad), XV32(0x7e6687b3), XV32(0x2285be90), + XV32(0x3b6dfa93), XV32(0x678ec3b0), XV32(0x297a7bae), XV32(0x7599428d), + XV32(0x1f42f8e9), XV32(0x43a1c1ca), XV32(0xd5579d4), XV32(0x51b640f7), + XV32(0x7333fe67), XV32(0x2fd0c744), XV32(0x61247f5a), XV32(0x3dc74679), + XV32(0x571cfc1d), XV32(0xbffc53e), XV32(0x450b7d20), XV32(0x19e84403), + XV32(0x76dbf526), XV32(0x2a38cc05), XV32(0x64cc741b), XV32(0x382f4d38), + XV32(0x52f4f75c), XV32(0xe17ce7f), XV32(0x40e37661), XV32(0x1c004f42), + XV32(0x3e85f1d2), XV32(0x6266c8f1), XV32(0x2c9270ef), XV32(0x707149cc), + XV32(0x1aaaf3a8), XV32(0x4649ca8b), XV32(0x8bd7295), XV32(0x545e4bb6), + XV32(0x4db60fb5), XV32(0x11553696), XV32(0x5fa18e88), XV32(0x342b7ab), + XV32(0x69990dcf), XV32(0x357a34ec), XV32(0x7b8e8cf2), XV32(0x276db5d1), + XV32(0x5e80b41), XV32(0x590b3262), XV32(0x17ff8a7c), XV32(0x4b1cb35f), + XV32(0x21c7093b), XV32(0x7d243018), XV32(0x33d08806), XV32(0x6f33b125), + XV32(0x46661937), XV32(0x1a852014), XV32(0x5471980a), XV32(0x892a129), + XV32(0x62491b4d), XV32(0x3eaa226e), XV32(0x705e9a70), XV32(0x2cbda353), + XV32(0xe381dc3), XV32(0x52db24e0), XV32(0x1c2f9cfe), XV32(0x40cca5dd), + XV32(0x2a171fb9), XV32(0x76f4269a), XV32(0x38009e84), XV32(0x64e3a7a7), + XV32(0x7d0be3a4), XV32(0x21e8da87), XV32(0x6f1c6299), XV32(0x33ff5bba), + XV32(0x5924e1de), XV32(0x5c7d8fd), XV32(0x4b3360e3), XV32(0x17d059c0), + XV32(0x3555e750), XV32(0x69b6de73), XV32(0x2742666d), XV32(0x7ba15f4e), + XV32(0x117ae52a), XV32(0x4d99dc09), XV32(0x36d6417), XV32(0x5f8e5d34), + XV32(0x30bdec11), XV32(0x6c5ed532), XV32(0x22aa6d2c), XV32(0x7e49540f), + XV32(0x1492ee6b), XV32(0x4871d748), XV32(0x6856f56), XV32(0x5a665675), + XV32(0x78e3e8e5), XV32(0x2400d1c6), XV32(0x6af469d8), XV32(0x361750fb), + XV32(0x5cccea9f), XV32(0x2fd3bc), XV32(0x4edb6ba2), XV32(0x12385281), + XV32(0xbd01682), XV32(0x57332fa1), XV32(0x19c797bf), XV32(0x4524ae9c), + XV32(0x2fff14f8), XV32(0x731c2ddb), XV32(0x3de895c5), XV32(0x610bace6), + XV32(0x438e1276), XV32(0x1f6d2b55), XV32(0x5199934b), XV32(0xd7aaa68), + XV32(0x67a1100c), XV32(0x3b42292f), XV32(0x75b69131), XV32(0x2955a812), + XV32(0x271dc115), XV32(0x7bfef836), XV32(0x350a4028), XV32(0x69e9790b), + XV32(0x332c36f), XV32(0x5fd1fa4c), XV32(0x11254252), XV32(0x4dc67b71), + XV32(0x6f43c5e1), XV32(0x33a0fcc2), XV32(0x7d5444dc), XV32(0x21b77dff), + XV32(0x4b6cc79b), XV32(0x178ffeb8), XV32(0x597b46a6), XV32(0x5987f85), + XV32(0x1c703b86), XV32(0x409302a5), XV32(0xe67babb), XV32(0x52848398), + XV32(0x385f39fc), XV32(0x64bc00df), XV32(0x2a48b8c1), XV32(0x76ab81e2), + XV32(0x542e3f72), XV32(0x8cd0651), XV32(0x4639be4f), XV32(0x1ada876c), + XV32(0x70013d08), XV32(0x2ce2042b), XV32(0x6216bc35), XV32(0x3ef58516), + XV32(0x51c63433), XV32(0xd250d10), XV32(0x43d1b50e), XV32(0x1f328c2d), + XV32(0x75e93649), XV32(0x290a0f6a), XV32(0x67feb774), XV32(0x3b1d8e57), + XV32(0x199830c7), XV32(0x457b09e4), XV32(0xb8fb1fa), XV32(0x576c88d9), + XV32(0x3db732bd), XV32(0x61540b9e), XV32(0x2fa0b380), XV32(0x73438aa3), + XV32(0x6aabcea0), XV32(0x3648f783), XV32(0x78bc4f9d), XV32(0x245f76be), + XV32(0x4e84ccda), XV32(0x1267f5f9), XV32(0x5c934de7), XV32(0x7074c4), + XV32(0x22f5ca54), XV32(0x7e16f377), XV32(0x30e24b69), XV32(0x6c01724a), + XV32(0x6dac82e), XV32(0x5a39f10d), XV32(0x14cd4913), XV32(0x482e7030), + XV32(0x617bd822), XV32(0x3d98e101), XV32(0x736c591f), XV32(0x2f8f603c), + XV32(0x4554da58), XV32(0x19b7e37b), XV32(0x57435b65), XV32(0xba06246), + XV32(0x2925dcd6), XV32(0x75c6e5f5), XV32(0x3b325deb), XV32(0x67d164c8), + XV32(0xd0adeac), XV32(0x51e9e78f), XV32(0x1f1d5f91), XV32(0x43fe66b2), + XV32(0x5a1622b1), XV32(0x6f51b92), XV32(0x4801a38c), XV32(0x14e29aaf), + XV32(0x7e3920cb), XV32(0x22da19e8), XV32(0x6c2ea1f6), XV32(0x30cd98d5), + XV32(0x12482645), XV32(0x4eab1f66), XV32(0x5fa778), XV32(0x5cbc9e5b), + XV32(0x3667243f), XV32(0x6a841d1c), XV32(0x2470a502), XV32(0x78939c21), + XV32(0x17a02d04), XV32(0x4b431427), XV32(0x5b7ac39), XV32(0x5954951a), + XV32(0x338f2f7e), XV32(0x6f6c165d), XV32(0x2198ae43), XV32(0x7d7b9760), + XV32(0x5ffe29f0), XV32(0x31d10d3), XV32(0x4de9a8cd), XV32(0x110a91ee), + XV32(0x7bd12b8a), XV32(0x273212a9), XV32(0x69c6aab7), XV32(0x35259394), + XV32(0x2ccdd797), XV32(0x702eeeb4), XV32(0x3eda56aa), XV32(0x62396f89), + XV32(0x8e2d5ed), XV32(0x5401ecce), XV32(0x1af554d0), XV32(0x46166df3), + XV32(0x6493d363), XV32(0x3870ea40), XV32(0x7684525e), XV32(0x2a676b7d), + XV32(0x40bcd119), XV32(0x1c5fe83a), XV32(0x52ab5024), XV32(0xe486907) +}; + +#endif /* if defined(XRABPLY_TYPE32) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xtypes.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xtypes.h new file mode 100644 index 0000000000..3593a664fc --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xtypes.h @@ -0,0 +1,68 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XTYPES_H) +#define XTYPES_H + + + +typedef struct s_chanode { + struct s_chanode *next; + long icurr; +} chanode_t; + +typedef struct s_chastore { + chanode_t *head, *tail; + long isize, nsize; + chanode_t *ancur; + chanode_t *sncur; + long scurr; +} chastore_t; + +typedef struct s_xrecord { + struct s_xrecord *next; + char const *ptr; + long size; + unsigned long ha; +} xrecord_t; + +typedef struct s_xdfile { + chastore_t rcha; + long nrec; + unsigned int hbits; + xrecord_t **rhash; + long dstart, dend; + xrecord_t **recs; + char *rchg; + long *rindex; + long nreff; + unsigned long *ha; +} xdfile_t; + +typedef struct s_xdfenv { + xdfile_t xdf1, xdf2; +} xdfenv_t; + + + +#endif /* #if !defined(XTYPES_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xutils.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xutils.c new file mode 100644 index 0000000000..e1b0bc274f --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xutils.c @@ -0,0 +1,580 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + + +#define XDL_GUESS_NLINES 256 + + + + +long xdl_bogosqrt(long n) { + long i; + + /* + * Classical integer square root approximation using shifts. + */ + for (i = 1; n > 0; n >>= 2) + i <<= 1; + + return i; +} + + +int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, + xdemitcb_t *ecb) { + int i = 2; + mmbuffer_t mb[3]; + + mb[0].ptr = (char *) pre; + mb[0].size = psize; + mb[1].ptr = (char *) rec; + mb[1].size = size; + if (size > 0 && rec[size - 1] != '\n') { + mb[2].ptr = (char *) "\n\\ No newline at end of file\n"; + mb[2].size = strlen(mb[2].ptr); + i++; + } + if (ecb->outf(ecb->priv, mb, i) < 0) { + + return -1; + } + + return 0; +} + + +int xdl_init_mmfile(mmfile_t *mmf, long bsize, unsigned long flags) { + + mmf->flags = flags; + mmf->head = mmf->tail = NULL; + mmf->bsize = bsize; + mmf->fsize = 0; + mmf->rcur = mmf->wcur = NULL; + mmf->rpos = 0; + + return 0; +} + + +void xdl_free_mmfile(mmfile_t *mmf) { + mmblock_t *cur, *tmp; + + for (cur = mmf->head; (tmp = cur) != NULL;) { + cur = cur->next; + xdl_free(tmp); + } +} + + +int xdl_mmfile_iscompact(mmfile_t *mmf) { + + return mmf->head == mmf->tail; +} + + +int xdl_seek_mmfile(mmfile_t *mmf, long off) { + long bsize; + + if (xdl_mmfile_first(mmf, &bsize)) { + do { + if (off < bsize) { + mmf->rpos = off; + return 0; + } + off -= bsize; + } while (xdl_mmfile_next(mmf, &bsize)); + } + + return -1; +} + + +long xdl_read_mmfile(mmfile_t *mmf, void *data, long size) { + long rsize, csize; + char *ptr = data; + mmblock_t *rcur; + + for (rsize = 0, rcur = mmf->rcur; rcur && rsize < size;) { + if (mmf->rpos >= rcur->size) { + if (!(mmf->rcur = rcur = rcur->next)) + break; + mmf->rpos = 0; + } + csize = XDL_MIN(size - rsize, rcur->size - mmf->rpos); + memcpy(ptr, rcur->ptr + mmf->rpos, csize); + rsize += csize; + ptr += csize; + mmf->rpos += csize; + } + + return rsize; +} + + +long xdl_write_mmfile(mmfile_t *mmf, void const *data, long size) { + long wsize, bsize, csize; + mmblock_t *wcur; + + for (wsize = 0; wsize < size;) { + wcur = mmf->wcur; + if (wcur && (wcur->flags & XDL_MMB_READONLY)) + return wsize; + if (!wcur || wcur->size == wcur->bsize || + (mmf->flags & XDL_MMF_ATOMIC && wcur->size + size > wcur->bsize)) { + bsize = XDL_MAX(mmf->bsize, size); + if (!(wcur = (mmblock_t *) xdl_malloc(sizeof(mmblock_t) + bsize))) { + + return wsize; + } + wcur->flags = 0; + wcur->ptr = (char *) wcur + sizeof(mmblock_t); + wcur->size = 0; + wcur->bsize = bsize; + wcur->next = NULL; + if (!mmf->head) + mmf->head = wcur; + if (mmf->tail) + mmf->tail->next = wcur; + mmf->tail = wcur; + mmf->wcur = wcur; + } + csize = XDL_MIN(size - wsize, wcur->bsize - wcur->size); + memcpy(wcur->ptr + wcur->size, (char const *) data + wsize, csize); + wsize += csize; + wcur->size += csize; + mmf->fsize += csize; + } + + return size; +} + + +long xdl_writem_mmfile(mmfile_t *mmf, mmbuffer_t *mb, int nbuf) { + int i; + long size; + char *data; + + for (i = 0, size = 0; i < nbuf; i++) + size += mb[i].size; + if (!(data = (char *) xdl_mmfile_writeallocate(mmf, size))) + return -1; + for (i = 0; i < nbuf; i++) { + memcpy(data, mb[i].ptr, mb[i].size); + data += mb[i].size; + } + + return size; +} + + +void *xdl_mmfile_writeallocate(mmfile_t *mmf, long size) { + long bsize; + mmblock_t *wcur; + char *blk; + + if (!(wcur = mmf->wcur) || wcur->size + size > wcur->bsize) { + bsize = XDL_MAX(mmf->bsize, size); + if (!(wcur = (mmblock_t *) xdl_malloc(sizeof(mmblock_t) + bsize))) { + + return NULL; + } + wcur->flags = 0; + wcur->ptr = (char *) wcur + sizeof(mmblock_t); + wcur->size = 0; + wcur->bsize = bsize; + wcur->next = NULL; + if (!mmf->head) + mmf->head = wcur; + if (mmf->tail) + mmf->tail->next = wcur; + mmf->tail = wcur; + mmf->wcur = wcur; + } + + blk = wcur->ptr + wcur->size; + wcur->size += size; + mmf->fsize += size; + + return blk; +} + + +long xdl_mmfile_ptradd(mmfile_t *mmf, char *ptr, long size, unsigned long flags) { + mmblock_t *wcur; + + if (!(wcur = (mmblock_t *) xdl_malloc(sizeof(mmblock_t)))) { + + return -1; + } + wcur->flags = flags; + wcur->ptr = ptr; + wcur->size = wcur->bsize = size; + wcur->next = NULL; + if (!mmf->head) + mmf->head = wcur; + if (mmf->tail) + mmf->tail->next = wcur; + mmf->tail = wcur; + mmf->wcur = wcur; + + mmf->fsize += size; + + return size; +} + + +long xdl_copy_mmfile(mmfile_t *mmf, long size, xdemitcb_t *ecb) { + long rsize, csize; + mmblock_t *rcur; + mmbuffer_t mb; + + for (rsize = 0, rcur = mmf->rcur; rcur && rsize < size;) { + if (mmf->rpos >= rcur->size) { + if (!(mmf->rcur = rcur = rcur->next)) + break; + mmf->rpos = 0; + } + csize = XDL_MIN(size - rsize, rcur->size - mmf->rpos); + mb.ptr = rcur->ptr + mmf->rpos; + mb.size = csize; + if (ecb->outf(ecb->priv, &mb, 1) < 0) { + + return rsize; + } + rsize += csize; + mmf->rpos += csize; + } + + return rsize; +} + + +void *xdl_mmfile_first(mmfile_t *mmf, long *size) { + + if (!(mmf->rcur = mmf->head)) + return NULL; + + *size = mmf->rcur->size; + + return mmf->rcur->ptr; +} + + +void *xdl_mmfile_next(mmfile_t *mmf, long *size) { + + if (!mmf->rcur || !(mmf->rcur = mmf->rcur->next)) + return NULL; + + *size = mmf->rcur->size; + + return mmf->rcur->ptr; +} + + +long xdl_mmfile_size(mmfile_t *mmf) { + + return mmf->fsize; +} + + +int xdl_mmfile_cmp(mmfile_t *mmf1, mmfile_t *mmf2) { + int cres; + long size, bsize1, bsize2, size1, size2; + char const *blk1, *cur1, *top1; + char const *blk2, *cur2, *top2; + + if ((cur1 = blk1 = xdl_mmfile_first(mmf1, &bsize1)) != NULL) + top1 = blk1 + bsize1; + if ((cur2 = blk2 = xdl_mmfile_first(mmf2, &bsize2)) != NULL) + top2 = blk2 + bsize2; + if (!cur1) { + if (!cur2 || xdl_mmfile_size(mmf2) == 0) + return 0; + return -*cur2; + } else if (!cur2) + return xdl_mmfile_size(mmf1) ? *cur1: 0; + for (;;) { + if (cur1 >= top1) { + if ((cur1 = blk1 = xdl_mmfile_next(mmf1, &bsize1)) != NULL) + top1 = blk1 + bsize1; + } + if (cur2 >= top2) { + if ((cur2 = blk2 = xdl_mmfile_next(mmf2, &bsize2)) != NULL) + top2 = blk2 + bsize2; + } + if (!cur1) { + if (!cur2) + break; + return -*cur2; + } else if (!cur2) + return *cur1; + size1 = top1 - cur1; + size2 = top2 - cur2; + size = XDL_MIN(size1, size2); + if ((cres = memcmp(cur1, cur2, size)) != 0) + return cres; + cur1 += size; + cur2 += size; + } + + return 0; +} + + +int xdl_mmfile_compact(mmfile_t *mmfo, mmfile_t *mmfc, long bsize, unsigned long flags) { + long fsize = xdl_mmfile_size(mmfo), size; + char *data; + char const *blk; + + if (xdl_init_mmfile(mmfc, bsize, flags) < 0) { + + return -1; + } + if (!(data = (char *) xdl_mmfile_writeallocate(mmfc, fsize))) { + + xdl_free_mmfile(mmfc); + return -1; + } + if ((blk = (char const *) xdl_mmfile_first(mmfo, &size)) != NULL) { + do { + memcpy(data, blk, size); + data += size; + } while ((blk = (char const *) xdl_mmfile_next(mmfo, &size)) != NULL); + } + + return 0; +} + + +int xdl_mmfile_outf(void *priv, mmbuffer_t *mb, int nbuf) { + mmfile_t *mmf = priv; + + if (xdl_writem_mmfile(mmf, mb, nbuf) < 0) { + + return -1; + } + + return 0; +} + + +int xdl_cha_init(chastore_t *cha, long isize, long icount) { + + cha->head = cha->tail = NULL; + cha->isize = isize; + cha->nsize = icount * isize; + cha->ancur = cha->sncur = NULL; + cha->scurr = 0; + + return 0; +} + + +void xdl_cha_free(chastore_t *cha) { + chanode_t *cur, *tmp; + + for (cur = cha->head; (tmp = cur) != NULL;) { + cur = cur->next; + xdl_free(tmp); + } +} + + +void *xdl_cha_alloc(chastore_t *cha) { + chanode_t *ancur; + void *data; + + if (!(ancur = cha->ancur) || ancur->icurr == cha->nsize) { + if (!(ancur = (chanode_t *) xdl_malloc(sizeof(chanode_t) + cha->nsize))) { + + return NULL; + } + ancur->icurr = 0; + ancur->next = NULL; + if (cha->tail) + cha->tail->next = ancur; + if (!cha->head) + cha->head = ancur; + cha->tail = ancur; + cha->ancur = ancur; + } + + data = (char *) ancur + sizeof(chanode_t) + ancur->icurr; + ancur->icurr += cha->isize; + + return data; +} + + +void *xdl_cha_first(chastore_t *cha) { + chanode_t *sncur; + + if (!(cha->sncur = sncur = cha->head)) + return NULL; + + cha->scurr = 0; + + return (char *) sncur + sizeof(chanode_t) + cha->scurr; +} + + +void *xdl_cha_next(chastore_t *cha) { + chanode_t *sncur; + + if (!(sncur = cha->sncur)) + return NULL; + cha->scurr += cha->isize; + if (cha->scurr == sncur->icurr) { + if (!(sncur = cha->sncur = sncur->next)) + return NULL; + cha->scurr = 0; + } + + return (char *) sncur + sizeof(chanode_t) + cha->scurr; +} + + +long xdl_guess_lines(mmfile_t *mf) { + long nl = 0, size, tsize = 0; + char const *data, *cur, *top; + + if ((cur = data = xdl_mmfile_first(mf, &size)) != NULL) { + for (top = data + size; nl < XDL_GUESS_NLINES;) { + if (cur >= top) { + tsize += (long) (cur - data); + if (!(cur = data = xdl_mmfile_next(mf, &size))) + break; + top = data + size; + } + nl++; + if (!(cur = memchr(cur, '\n', top - cur))) + cur = top; + else + cur++; + } + tsize += (long) (cur - data); + } + + if (nl && tsize) + nl = xdl_mmfile_size(mf) / (tsize / nl); + + return nl + 1; +} + + +unsigned long xdl_hash_record(char const **data, char const *top) { + unsigned long ha = 5381; + char const *ptr = *data; + + for (; ptr < top && *ptr != '\n'; ptr++) { + ha += (ha << 5); + ha ^= (unsigned long) *ptr; + } + *data = ptr < top ? ptr + 1: ptr; + + return ha; +} + + +unsigned int xdl_hashbits(unsigned int size) { + unsigned int val = 1, bits = 0; + + for (; val < size && bits < CHAR_BIT * sizeof(unsigned int); val <<= 1, bits++); + return bits ? bits: 1; +} + + +int xdl_num_out(char *out, long val) { + char *ptr, *str = out; + char buf[32]; + + ptr = buf + sizeof(buf) - 1; + *ptr = '\0'; + if (val < 0) { + *--ptr = '-'; + val = -val; + } + for (; val && ptr > buf; val /= 10) + *--ptr = "0123456789"[val % 10]; + if (*ptr) + for (; *ptr; ptr++, str++) + *str = *ptr; + else + *str++ = '0'; + *str = '\0'; + + return str - out; +} + + +long xdl_atol(char const *str, char const **next) { + long val, base; + char const *top; + + for (top = str; XDL_ISDIGIT(*top); top++); + if (next) + *next = top; + for (val = 0, base = 1, top--; top >= str; top--, base *= 10) + val += base * (long)(*top - '0'); + return val; +} + + +int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, xdemitcb_t *ecb) { + int nb = 0; + mmbuffer_t mb; + char buf[128]; + + memcpy(buf, "@@ -", 4); + nb += 4; + + nb += xdl_num_out(buf + nb, c1 ? s1: s1 - 1); + + memcpy(buf + nb, ",", 1); + nb += 1; + + nb += xdl_num_out(buf + nb, c1); + + memcpy(buf + nb, " +", 2); + nb += 2; + + nb += xdl_num_out(buf + nb, c2 ? s2: s2 - 1); + + memcpy(buf + nb, ",", 1); + nb += 1; + + nb += xdl_num_out(buf + nb, c2); + + memcpy(buf + nb, " @@\n", 4); + nb += 4; + + mb.ptr = buf; + mb.size = nb; + if (ecb->outf(ecb->priv, &mb, 1) < 0) + return -1; + + return 0; +} + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xutils.h b/harbour/contrib/hbxdiff/3rd/libxdiff/xutils.h new file mode 100644 index 0000000000..4ceae33f51 --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xutils.h @@ -0,0 +1,47 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#if !defined(XUTILS_H) +#define XUTILS_H + + + +long xdl_bogosqrt(long n); +int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize, + xdemitcb_t *ecb); +int xdl_mmfile_outf(void *priv, mmbuffer_t *mb, int nbuf); +int xdl_cha_init(chastore_t *cha, long isize, long icount); +void xdl_cha_free(chastore_t *cha); +void *xdl_cha_alloc(chastore_t *cha); +void *xdl_cha_first(chastore_t *cha); +void *xdl_cha_next(chastore_t *cha); +long xdl_guess_lines(mmfile_t *mf); +unsigned long xdl_hash_record(char const **data, char const *top); +unsigned int xdl_hashbits(unsigned int size); +int xdl_num_out(char *out, long val); +long xdl_atol(char const *str, char const **next); +int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2, xdemitcb_t *ecb); + + + +#endif /* #if !defined(XUTILS_H) */ + diff --git a/harbour/contrib/hbxdiff/3rd/libxdiff/xversion.c b/harbour/contrib/hbxdiff/3rd/libxdiff/xversion.c new file mode 100644 index 0000000000..d3184392cc --- /dev/null +++ b/harbour/contrib/hbxdiff/3rd/libxdiff/xversion.c @@ -0,0 +1,27 @@ +/* + * LibXDiff by Davide Libenzi ( File Differential Library ) + * Copyright (C) 2003 Davide Libenzi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Davide Libenzi + * + */ + +#include "xinclude.h" + + +char libxdiff_version[] = "LibXDiff v" PACKAGE_VERSION " by Davide Libenzi "; + diff --git a/harbour/contrib/hbxdiff/hbxdiff.c b/harbour/contrib/hbxdiff/hbxdiff.c new file mode 100644 index 0000000000..db1e2cc265 --- /dev/null +++ b/harbour/contrib/hbxdiff/hbxdiff.c @@ -0,0 +1,664 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * LIBXDIFF functions wrapper + * + * Copyright 2010 Petr Chornyj + * www - http://harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbapi.h" +#include "hbapiitm.h" +#include "hbapierr.h" +#include "hbapifs.h" +#include "hbinit.h" +#include "hbstack.h" +#include "hbvm.h" + +#include "xdiff.h" + +#define HB_MMF_SIGN 8000001 + +#define HB_ERR_MEMSTRU_NOT_MEM_BLOCK 4001 +#define HB_ERR_MEMSTRU_WRONG_MEMSTRU_BLOCK 4002 +#define HB_ERR_MEMSTRU_DESTROYED 4003 + +#define XDLT_STD_BLKSIZE ( 1024 * 8 ) +#define XDLT_MAX_LINE_SIZE 80 + +static int xdlt_outf( void * priv, mmbuffer_t * mb, int nbuf ); +static int xdlt_outh( void * priv, mmbuffer_t * mb, int nbuf ); + +static PHB_ITEM hb_mmf_itemPut( PHB_ITEM pItem, void * pMemAddr, int iType ); +static void * hb_mmf_itemGet( PHB_ITEM pItem, int iType, HB_BOOL fError ); +static void hb_mmf_ret( void * pMemAddr, int iType ); +static void * hb_mmf_param( int iParam, int iType, HB_BOOL fError ); + +static void xdiff_init( void ); + +typedef struct +{ + mmfile_t * mmf; +} HB_MMF, * PHB_MMF; + +typedef struct +{ + int type; + HB_MMF * hb_mmf; +} HB_MMF_HOLDER, * PHB_MMF_HOLDER; + +static HB_GARBAGE_FUNC( hb_mmf_destructor ) +{ + PHB_MMF_HOLDER pStructHolder = ( PHB_MMF_HOLDER ) Cargo; + + if( pStructHolder->hb_mmf ) + { + if( pStructHolder->hb_mmf->mmf ) + { + xdl_free_mmfile( pStructHolder->hb_mmf->mmf ); + pStructHolder->hb_mmf->mmf = NULL; + } + hb_xfree( pStructHolder->hb_mmf ); + pStructHolder->hb_mmf = NULL; + } +} + +static const HB_GC_FUNCS s_gc_xdiffFuncs = +{ + hb_mmf_destructor, + hb_gcDummyMark +}; + +static PHB_ITEM hb_mmf_itemPut( PHB_ITEM pItem, void * pMemAddr, int iType ) +{ + PHB_MMF_HOLDER pStructHolder; + + if( pItem ) + { + if( HB_IS_COMPLEX( pItem ) ) + hb_itemClear( pItem ); + } + else + pItem = hb_itemNew( pItem ); + + pStructHolder = ( PHB_MMF_HOLDER ) hb_gcAllocate( sizeof( HB_MMF_HOLDER ), + &s_gc_xdiffFuncs ); + pStructHolder->hb_mmf = ( HB_MMF * ) pMemAddr; + pStructHolder->type = iType; + + return hb_itemPutPtrGC( pItem, pStructHolder ); +} + +static void * hb_mmf_itemGet( PHB_ITEM pItem, int iType, HB_BOOL fError ) +{ + PHB_MMF_HOLDER pStructHolder = ( PHB_MMF_HOLDER ) hb_itemGetPtrGC( pItem, + &s_gcxdiffFuncs ); + int iError = 0; + + HB_SYMBOL_UNUSED( iError ); + + if( ! pStructHolder ) + iError = HB_ERR_MEMSTRU_NOT_MEM_BLOCK; + else if( pStructHolder->type != iType ) + iError = HB_ERR_MEMSTRU_WRONG_MEMSTRU_BLOCK; + else if( ! pStructHolder->hb_mmf ) + iError = HB_ERR_MEMSTRU_DESTROYED; + else + return pStructHolder->hb_mmf; + + if( fError ) + hb_errRT_BASE_SubstR( EG_ARG, iError, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + + return NULL; +} + +static void hb_mmf_ret( void * pMemAddr, int iType ) +{ + hb_mmf_itemPut( hb_stackReturnItem(), pMemAddr, iType ); +} + +static void * hb_mmf_param( int iParam, int iType, HB_BOOL fError ) +{ + return hb_mmf_itemGet( hb_param( iParam, HB_IT_POINTER ), iType, fError ); +} + +/* int xdl_init_mmfile(mmfile_t *mmf, long bsize, unsigned long flags) */ + +HB_FUNC( XDL_INIT_MMFILE ) +{ + mmfile_t * mmf = ( mmfile_t * ) hb_xgrab( sizeof( mmfile_t ) ); + + if( xdl_init_mmfile( mmf, + hb_parnldef( 1, XDLT_STD_BLKSIZE ), ( unsigned long ) hb_parnl( 3 ) ) == 0 ) + { + HB_MMF * phb_mmf; + + phb_mmf = ( HB_MMF * ) hb_xgrab( sizeof( HB_MMF ) ); + hb_xmemset( phb_mmf, 0, sizeof( HB_MMF ) ); + phb_mmf->mmf = mmf; + hb_mmf_ret( phb_mmf, HB_MMF_SIGN ); + } + else + hb_xfree( mmf ); +} + +/* + HB_FUNC( XDL_FREE_MMFILE ) + { + HB_MMF * phb_mmf = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf && phb_mmf->mmf ) + { + xdl_free_mmfile( phb_mmf->mmf ); + phb_mmf->mmf = NULL; + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + */ + +/* int xdl_mmfile_iscompact(mmfile_t *mmf) */ + +HB_FUNC( XDL_MMFILE_ISCOMPACT ) +{ + HB_MMF * phb_mmf = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf && phb_mmf->mmf ) + hb_retl( xdl_mmfile_iscompact( phb_mmf->mmf ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int xdl_seek_mmfile(mmfile_t *mmf, long off) */ + +HB_FUNC( XDL_SEEK_MMFILE ) +{ + HB_MMF * phb_mmf = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf && phb_mmf->mmf ) + hb_retni( xdl_seek_mmfile( phb_mmf->mmf, hb_parnldef( 2, 0 ) ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* long xdl_read_mmfile(mmfile_t *mmf, void *data, long size) */ + +HB_FUNC( XDL_READ_MMFILE ) +{ + HB_MMF * phb_mmf = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf && phb_mmf->mmf ) + { + PHB_ITEM pData = HB_ISBYREF( 2 ) ? hb_param( 2, HB_IT_STRING ) : NULL; + char * data; + HB_SIZE size; + long lResult; + + if( pData ) + { + if( ! hb_itemGetWriteCL( pData, &data, &size ) ) + data = NULL; + } + else + { + size = ( HB_ISNUM( 3 ) && hb_parns( 3 ) >= 0 ) ? + hb_parns( 3 ) : xdl_mmfile_size( phb_mmf->mmf ); + + data = ( char * ) hb_xalloc( size + 1 ); + } + + if( data && size ) + { + lResult = xdl_read_mmfile( phb_mmf->mmf, data, size ); + if( lResult == -1 ) + { + hb_retc_null(); + hb_stornl( -1, 4 ); + } + else + { + hb_stornl( lResult, 4 ); + + if( pData ) + hb_retclen( data, lResult ); + else + hb_retclen_buffer( data, lResult ); + } + } + else + { + hb_retc_null(); + hb_stornl( -1, 4 ); + } + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* long xdl_write_mmfile(mmfile_t *mmf, void const *data, long size) */ + +HB_FUNC( XDL_WRITE_MMFILE ) +{ + HB_MMF * phb_mmf = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf && phb_mmf->mmf ) + { + if( HB_ISCHAR( 2 ) ) + { + long lSize = hb_parclen( 2 ); + + if( hb_pcount() > 2 ) + lSize = hb_parnldef( 3, lSize ); + + hb_retnl( xdl_write_mmfile( phb_mmf->mmf, hb_parcx( 2 ), lSize ) ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* + long xdl_writem_mmfile(mmfile_t *mmf, mmbuffer_t *mb, int nbuf); + void *xdl_mmfile_writeallocate(mmfile_t *mmf, long size); + long xdl_mmfile_ptradd(mmfile_t *mmf, char *ptr, long size, unsigned long flags); + void *xdl_mmfile_first(mmfile_t *mmf, long *size); + void *xdl_mmfile_next(mmfile_t *mmf, long *size); + */ + +/* long xdl_mmfile_size(mmfile_t *mmf) */ + +HB_FUNC( XDL_MMFILE_SIZE ) +{ + HB_MMF * phb_mmf = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf && phb_mmf->mmf ) + hb_retnl( xdl_mmfile_size( phb_mmf->mmf ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int xdl_mmfile_cmp(mmfile_t *mmf1, mmfile_t *mmf2) */ + +HB_FUNC( XDL_MMFILE_CMP ) +{ + HB_MMF * phb_mmf1 = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + HB_MMF * phb_mmf2 = ( HB_MMF * ) hb_mmf_param( 2, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf1 && phb_mmf1->mmf && phb_mmf2 && phb_mmf2->mmf ) + hb_retl( xdl_mmfile_cmp( phb_mmf1->mmf, phb_mmf2->mmf ) == 0 ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* + int xdl_mmfile_compact(mmfile_t *mmfo, mmfile_t *mmfc, long bsize, unsigned long flags); + */ + +HB_FUNC( XDL_MMFILE_COMPACT ) +{ + HB_MMF * phb_mmfo = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + mmfile_t * mmfc = ( mmfile_t * ) hb_xgrab( sizeof( mmfile_t ) ); + + if( xdl_mmfile_compact( phb_mmfo->mmf, mmfc, hb_parnldef( 1, XDLT_STD_BLKSIZE ), + ( unsigned long ) hb_parnl( 3 ) ) == 0 ) + { + HB_MMF * phb_mmf; + + phb_mmf = ( HB_MMF * ) hb_xgrab( sizeof( HB_MMF ) ); + hb_xmemset( phb_mmf, 0, sizeof( HB_MMF ) ); + phb_mmf->mmf = mmfc; + hb_mmf_ret( phb_mmf, HB_MMF_SIGN ); + + hb_stornl( 0, 4 ); + } + else + { + hb_xfree( mmfc ); + hb_stornl( -1, 4 ); + } +} + +/* cbs */ + +static int xdlt_outf( void * priv, mmbuffer_t * mb, int nbuf ) +{ + int i; + + for( i = 0; i < nbuf; i++ ) + { + hb_fsWriteLarge( ( HB_FHANDLE ) priv, mb[ i ].ptr, ( HB_SIZE ) mb[ i ].size ); + + if( hb_fsError() != 0 ) + return -1; + } + return 0; +} + +static int xdlt_outh( void * priv, mmbuffer_t * mb, int nbuf ) +{ + PHB_DYNS pSym = ( PHB_DYNS ) priv; + + if( pSym && hb_vmRequestReenter() ) + { + int iResult; + int i; + + hb_vmPushDynSym( pSym ); + hb_vmPushNil(); + + for( i = 0; i < nbuf; i++ ) + hb_vmPushString( ( const char * ) mb[ i ].ptr, mb[ i ].size ); + + hb_vmFunction( ( HB_USHORT ) nbuf ); + iResult = hb_parnidef( -1, 0 ); + + hb_vmRequestRestore(); + + return iResult; + } + else + return -1; +} + +/* int xdl_diff(mmfile_t *mmf1, mmfile_t *mmf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb) */ + +HB_FUNC( XDL_DIFF ) +{ + HB_MMF * phb_mmf1 = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + HB_MMF * phb_mmf2 = ( HB_MMF * ) hb_mmf_param( 2, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf1 && phb_mmf1->mmf && phb_mmf2 && phb_mmf2->mmf ) + { + xpparam_t xpp; + xdemitconf_t xecfg; + xdemitcb_t ecb; + + xpp.flags = ( unsigned long ) hb_parnldef( 3, 0 ); + xecfg.ctxlen = hb_parnldef( 4, 3 ); + + if( HB_ISNUM( 5 ) ) + { + ecb.priv = ( void * ) hb_numToHandle( hb_parnint( 5 ) ); + ecb.outf = xdlt_outf; + + hb_retni( xdl_diff( phb_mmf1->mmf, phb_mmf2->mmf, &xpp, &xecfg, &ecb ) ); + } + else if( HB_ISSYMBOL( 5 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 5, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + ecb.priv = pDynSym; + ecb.outf = xdlt_outh; + + hb_retni( xdl_diff( phb_mmf1->mmf, phb_mmf2->mmf, &xpp, &xecfg, &ecb ) ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int xdl_patch(mmfile_t *mmf, mmfile_t *mmfp, int mode, xdemitcb_t *ecb, xdemitcb_t *rjecb) */ + +HB_FUNC( XDL_PATCH ) +{ + HB_MMF * phb_mmf1 = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + HB_MMF * phb_mmf2 = ( HB_MMF * ) hb_mmf_param( 2, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf1 && phb_mmf1->mmf && phb_mmf2 && phb_mmf2->mmf ) + { + if( HB_ISNUM( 4 ) && HB_ISNUM( 5 ) ) + { + int mode = hb_parnidef( 3, XDL_PATCH_NORMAL ); + xdemitcb_t ecb; + xdemitcb_t rjecb; + + ecb.priv = ( void * ) hb_numToHandle( hb_parnint( 4 ) ); + ecb.outf = xdlt_outf; + + rjecb.priv = ( void * ) hb_numToHandle( hb_parnint( 5 ) ); + rjecb.outf = xdlt_outf; + + hb_retni( xdl_patch( phb_mmf1->mmf, phb_mmf2->mmf, mode, &ecb, &rjecb ) ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* + int xdl_merge3(mmfile_t *mmfo, mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb, xdemitcb_t *rjecb); + int xdl_bdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, bdiffparam_t const *bdp, xdemitcb_t *ecb); + */ + +/* int xdl_bdiff(mmfile_t *mmf1, mmfile_t *mmf2, bdiffparam_t const *bdp, xdemitcb_t *ecb) */ + +HB_FUNC( XDL_BDIFF ) +{ + HB_MMF * phb_mmf1 = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + HB_MMF * phb_mmf2 = ( HB_MMF * ) hb_mmf_param( 2, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf1 && phb_mmf1->mmf && phb_mmf2 && phb_mmf2->mmf ) + { + bdiffparam_t bdp; + xdemitcb_t ecb; + + bdp.bsize = hb_parnldef( 3, 32 ); /* from 16 to 64 */ + + if( HB_ISNUM( 4 ) ) + { + ecb.priv = ( void * ) hb_numToHandle( hb_parnint( 4 ) ); + ecb.outf = xdlt_outf; + + hb_retni( xdl_bdiff( phb_mmf1->mmf, phb_mmf2->mmf, &bdp, &ecb ) ); + } + else if( HB_ISSYMBOL( 4 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 3, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + ecb.priv = ( void * ) pDynSym; + ecb.outf = xdlt_outh; + + hb_retni( xdl_bdiff( phb_mmf1->mmf, phb_mmf2->mmf, &bdp, &ecb ) ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* + int xdl_rabdiff_mb(mmbuffer_t *mmb1, mmbuffer_t *mmb2, xdemitcb_t *ecb); + */ + +/* int xdl_rabdiff(mmfile_t *mmf1, mmfile_t *mmf2, xdemitcb_t *ecb) */ + +HB_FUNC( XDL_RABDIFF ) +{ + HB_MMF * phb_mmf1 = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + HB_MMF * phb_mmf2 = ( HB_MMF * ) hb_mmf_param( 2, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf1 && phb_mmf1->mmf && phb_mmf2 && phb_mmf2->mmf ) + { + xdemitcb_t ecb; + + if( HB_ISNUM( 3 ) ) + { + ecb.priv = ( void * ) hb_numToHandle( hb_parnint( 3 ) ); + ecb.outf = xdlt_outf; + + hb_retni( xdl_rabdiff( phb_mmf1->mmf, phb_mmf2->mmf, &ecb ) ); + } + else if( HB_ISSYMBOL( 3 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 3, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + ecb.priv = ( void * ) pDynSym; + ecb.outf = xdlt_outh; + + hb_retni( xdl_rabdiff( phb_mmf1->mmf, phb_mmf2->mmf, &ecb ) ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* int xdl_bpatch(mmfile_t *mmf, mmfile_t *mmfp, xdemitcb_t *ecb) */ + +HB_FUNC( XDL_BPATCH ) +{ + HB_MMF * phb_mmf1 = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + HB_MMF * phb_mmf2 = ( HB_MMF * ) hb_mmf_param( 2, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf1 && phb_mmf1->mmf && phb_mmf2 && phb_mmf2->mmf ) + { + xdemitcb_t ecb; + + if( HB_ISNUM( 3 ) ) + { + ecb.priv = ( void * ) hb_numToHandle( hb_parnint( 3 ) ); + ecb.outf = xdlt_outf; + + hb_retni( xdl_bpatch( phb_mmf1->mmf, phb_mmf2->mmf, &ecb ) ); + } + else if( HB_ISSYMBOL( 3 ) ) + { + PHB_DYNS pDynSym = hb_dynsymNew( hb_itemGetSymbol( hb_param( 3, HB_IT_SYMBOL ) ) ); + + if( pDynSym && hb_dynsymIsFunction( pDynSym ) ) + { + ecb.priv = ( void * ) pDynSym; + ecb.outf = xdlt_outh; + + hb_retni( xdl_bpatch( phb_mmf1->mmf, phb_mmf2->mmf, &ecb ) ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); + } + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +/* long xdl_bdiff_tgsize(mmfile_t *mmfp) */ + +HB_FUNC( XDL_BDIFF_TGSIZE ) +{ + HB_MMF * phb_mmf = ( HB_MMF * ) hb_mmf_param( 1, HB_MMF_SIGN, HB_TRUE ); + + if( phb_mmf && phb_mmf->mmf ) + hb_retnl( xdl_bdiff_tgsize( phb_mmf->mmf ) ); + else + hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +void * wf_malloc( void * priv, unsigned int size ) +{ + HB_SYMBOL_UNUSED( priv ); + + return hb_xgrab( size ); +} + +void wf_free( void * priv, void * ptr ) +{ + HB_SYMBOL_UNUSED( priv ); + + hb_xfree( ptr ); +} + +void * wf_realloc( void * priv, void * ptr, unsigned int size ) +{ + HB_SYMBOL_UNUSED( priv ); + + return hb_xrealloc( ptr, size ); +} + +static void xdiff_init( void ) +{ + memallocator_t malt; + + malt.priv = NULL; + malt.malloc = wf_malloc; + malt.free = wf_free; + malt.realloc = wf_realloc; + xdl_set_allocator( &malt ); +} + +HB_CALL_ON_STARTUP_BEGIN( _xdiff_init_ ) +xdiff_init(); +HB_CALL_ON_STARTUP_END( _xdiff_init_ ) + +#if defined( HB_PRAGMA_STARTUP ) + #pragma startup _xdiff_init_ +#elif defined( HB_DATASEG_STARTUP ) + #define HB_DATASEG_BODY HB_DATASEG_FUNC( _xdiff_init_ ) + #include "hbiniseg.h" +#endif diff --git a/harbour/contrib/hbxdiff/hbxdiff.ch b/harbour/contrib/hbxdiff/hbxdiff.ch new file mode 100644 index 0000000000..a28e9ab07a --- /dev/null +++ b/harbour/contrib/hbxdiff/hbxdiff.ch @@ -0,0 +1,74 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * LIBXDIFF functions wrapper + * + * Copyright 2010 Petr Chornyj + * www - http://harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef HBXDIFF_CH_ +#define HBXDIFF_CH_ + +#define XDLT_STD_BLKSIZE ( 1024 * 8 ) +#define XDLT_MAX_LINE_SIZE 80 + +#define XDF_NEED_MINIMAL ( hb_bitShift( 1, 1 ) ) + +#define XDL_PATCH_NORMAL ( asc( '-' ) ) +#define XDL_PATCH_REVERSE ( asc( '+' ) ) +#define XDL_PATCH_MODEMASK ( hb_bitShift( 1, 8 ) - 1 ) +#define XDL_PATCH_IGNOREBSPACE ( hb_bitShift( 1, 8 ) ) + +#define XDL_MMB_READONLY ( hb_bitShift( 1, 0 ) ) + +#define XDL_MMF_ATOMIC ( hb_bitShift( 1, 0 ) ) + +#define XDL_BDOP_INS 1 +#define XDL_BDOP_CPY 2 +#define XDL_BDOP_INSB 3 + +#endif /* HBXDIFF_CH_ */ diff --git a/harbour/contrib/hbxdiff/hbxdiff.hbc b/harbour/contrib/hbxdiff/hbxdiff.hbc new file mode 100644 index 0000000000..efa51ad56d --- /dev/null +++ b/harbour/contrib/hbxdiff/hbxdiff.hbc @@ -0,0 +1,8 @@ +# +# $Id$ +# + +incpaths=. + +libs=${hb_name}${__HB_DYN__} +libs=3rd/libxdiff/xdiff.hbc diff --git a/harbour/contrib/hbxdiff/hbxdiff.hbp b/harbour/contrib/hbxdiff/hbxdiff.hbp new file mode 100644 index 0000000000..ce50d84378 --- /dev/null +++ b/harbour/contrib/hbxdiff/hbxdiff.hbp @@ -0,0 +1,23 @@ +# +# $Id$ +# + +-hblib +-inc + +-o${hb_name} + +-w3 -es2 + +-depkeyhead=xdiff:xdiff.h +-depcontrol=xdiff:local{HB_BUILD_3RDEXT='no'} +-depcontrol=xdiff:${HB_WITH_XDIFF} +-depincpath=xdiff:/usr/include +-depincpathlocal=xdiff:3rd/libxdiff +-depfinish=xdiff + +-instfile=inc:hbxdiff.ch + +hbxdiff.c + +3rd/libxdiff/xdiff.hbc{HBMK_HAS_XDIFF_LOCAL} diff --git a/harbour/contrib/hbxdiff/tests/hbmk.hbm b/harbour/contrib/hbxdiff/tests/hbmk.hbm new file mode 100644 index 0000000000..4793c8f9fd --- /dev/null +++ b/harbour/contrib/hbxdiff/tests/hbmk.hbm @@ -0,0 +1,7 @@ +# +# $Id$ +# + +../hbxdiff.hbc + +-w3 -es2 diff --git a/harbour/contrib/hbxdiff/tests/test.prg b/harbour/contrib/hbxdiff/tests/test.prg new file mode 100644 index 0000000000..be16f6d966 --- /dev/null +++ b/harbour/contrib/hbxdiff/tests/test.prg @@ -0,0 +1,38 @@ +/* + * $Id$ + */ + +#include "hbxdiff.ch" +#include "simpleio.ch" + +#define _SIZE 62 + +PROCEDURE main + LOCAL pMMF + LOCAL cFileCtx + LOCAL nSize + + pMMF := xdl_init_mmfile( XDLT_STD_BLKSIZE, XDL_MMF_ATOMIC ) + ? xdl_mmfile_size( pMMF ) + ? xdl_mmfile_iscompact( pMMF ) + + cFileCtx := hb_memoRead( __FILE__ ) + + ? xdl_write_mmfile( pMMF, cFileCtx ), Len( cFileCtx ) + ? xdl_mmfile_size( pMMF ) + + ? xdl_read_mmfile( pMMF, NIL, _SIZE, @nSize ) + ? nSize + + xdl_seek_mmfile( pMMF, 0 ) + + ? xdl_read_mmfile( pMMF, NIL, _SIZE, @nSize ) + ? nSize + + ? xdl_read_mmfile( pMMF, NIL, _SIZE, @nSize ) + ? nSize + + xdl_seek_mmfile( pMMF, _SIZE ) + + ? xdl_read_mmfile( pMMF, NIL, _SIZE, @nSize ) + ? nSize diff --git a/harbour/contrib/hbxdiff/tests/test2.prg b/harbour/contrib/hbxdiff/tests/test2.prg new file mode 100644 index 0000000000..60ef9ce68b --- /dev/null +++ b/harbour/contrib/hbxdiff/tests/test2.prg @@ -0,0 +1,51 @@ +/* + * $Id$ + */ + +#include "hbxdiff.ch" +#include "fileio.ch" +#include "simpleio.ch" + +PROCEDURE main + + LOCAL pMMFOld, pMMFNew, pDiff + LOCAL cFileCtx + LOCAL hDif, hNew, hErr, hOld + LOCAL cDiffName + + pMMFOld := xdl_init_mmfile( XDLT_STD_BLKSIZE ) + pMMFNew := xdl_init_mmfile( XDLT_STD_BLKSIZE, XDL_MMF_ATOMIC ) + + cFileCtx := hb_memoRead( __FILE__ ) + + xdl_write_mmfile( pMMFOld, @cFileCtx ) + xdl_write_mmfile( pMMFNew, cFileCtx + hb_eol() + Space( 3 ) + "RETURN NIL" + hb_eol() ) + + ? xdl_mmfile_cmp( pMMFOld, pMMFNew ) + + hb_FNameSplit( __FILE__, NIL, @cDiffName, NIL ) + cDiffName := hb_FNameMerge( NIL, cDiffName, ".dif" ) + + hDif := FCreate( cDiffName , FC_NORMAL ) + IF FError() == 0 + FWrite( hDif, "diff ---" + hb_eol() ) + xdl_diff( pMMFOld, pMMFNew, 0, 3, hDif ) + + FClose( hDif ) + ENDIF + + pDiff := xdl_init_mmfile( XDLT_STD_BLKSIZE, XDL_MMF_ATOMIC ) + cFileCtx := hb_memoRead( cDiffName ) + xdl_write_mmfile( pDiff, cFileCtx ) + + hNew := FCreate( hb_FNameMerge( NIL, cDiffName, ".new" ), FC_NORMAL ) + hErr := FCreate( hb_FNameMerge( NIL, cDiffName, ".err" ), FC_NORMAL ) + hOld := FCreate( hb_FNameMerge( NIL, cDiffName, ".old" ), FC_NORMAL ) + IF FError() == 0 + ? xdl_patch( pMMFOld, pDiff, XDL_PATCH_NORMAL, hNew, hErr ) + ? xdl_patch( pMMFNew, pDiff, XDL_PATCH_REVERSE, hOld, hErr ) + + FClose( hNew ) + FClose( hErr ) + FClose( hOld ) + ENDIF diff --git a/harbour/contrib/hbxdiff/tests/test3.prg b/harbour/contrib/hbxdiff/tests/test3.prg new file mode 100644 index 0000000000..dcf3dc3b5e --- /dev/null +++ b/harbour/contrib/hbxdiff/tests/test3.prg @@ -0,0 +1,34 @@ +/* + * $Id$ + */ + +#include "hbxdiff.ch" + +#include "fileio.ch" +#include "simpleio.ch" + +FUNCTION Diff( ... ) + + LOCAL e + + FOR EACH e IN { ... } + OutStd( e ) + NEXT + + RETURN 0 + +PROCEDURE main + + LOCAL pMMFOld, pMMFNew + LOCAL cFileCtx + LOCAL cb := @Diff() + + pMMFOld := xdl_init_mmfile( XDLT_STD_BLKSIZE ) + pMMFNew := xdl_init_mmfile( XDLT_STD_BLKSIZE, XDL_MMF_ATOMIC ) + + cFileCtx := hb_memoRead( __FILE__ ) + + xdl_write_mmfile( pMMFOld, @cFileCtx ) + xdl_write_mmfile( pMMFNew, cFileCtx + hb_eol() + Space( 3 ) + "RETURN NIL" + hb_eol() ) + + xdl_diff( pMMFOld, pMMFNew, 0, 3, cb )