summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ABOUT-NLS226
-rw-r--r--AUTHORS1
-rw-r--r--CODING-STYLE113
-rw-r--r--COPYING340
-rw-r--r--ChangeLog8
-rw-r--r--Doxyfile946
-rw-r--r--HACKING1
-rw-r--r--INSTALL182
-rw-r--r--Makefile.am18
-rw-r--r--Makefile.in467
-rw-r--r--NEWS1
-rw-r--r--README4
-rw-r--r--TODO12
-rwxr-xr-xautogen.sh20
-rw-r--r--config.log36
-rw-r--r--configure.in153
-rw-r--r--croco-config.in87
-rw-r--r--docs/design/sel-instr.txt64
-rw-r--r--libcroco-config.h.in64
-rw-r--r--libcroco.pc.in11
-rw-r--r--src/.cvsignore2
-rw-r--r--src/Makefile.am33
-rw-r--r--src/Makefile.in400
-rw-r--r--src/cr-additional-sel.c355
-rw-r--r--src/cr-additional-sel.h111
-rw-r--r--src/cr-attr-sel.c209
-rw-r--r--src/cr-attr-sel.h80
-rw-r--r--src/cr-declaration.c342
-rw-r--r--src/cr-declaration.h92
-rw-r--r--src/cr-doc-handler.c146
-rw-r--r--src/cr-doc-handler.h283
-rw-r--r--src/cr-enc-handler.c197
-rw-r--r--src/cr-enc-handler.h102
-rw-r--r--src/cr-input.c1091
-rw-r--r--src/cr-input.h163
-rw-r--r--src/cr-num.c150
-rw-r--r--src/cr-num.h88
-rw-r--r--src/cr-om-parser.c891
-rw-r--r--src/cr-om-parser.h73
-rw-r--r--src/cr-parser-input.c1009
-rw-r--r--src/cr-parser-input.h166
-rw-r--r--src/cr-parser.c5191
-rw-r--r--src/cr-parser.h106
-rw-r--r--src/cr-pseudo.c132
-rw-r--r--src/cr-pseudo.h74
-rw-r--r--src/cr-rgb.c142
-rw-r--r--src/cr-rgb.h73
-rw-r--r--src/cr-sel-eng.c352
-rw-r--r--src/cr-sel-eng.h76
-rw-r--r--src/cr-selector.c242
-rw-r--r--src/cr-selector.h101
-rw-r--r--src/cr-simple-sel.c191
-rw-r--r--src/cr-simple-sel.h130
-rw-r--r--src/cr-statement.c1293
-rw-r--r--src/cr-statement.h315
-rw-r--r--src/cr-stylesheet.c93
-rw-r--r--src/cr-stylesheet.h62
-rw-r--r--src/cr-term.c817
-rw-r--r--src/cr-term.h199
-rw-r--r--src/cr-tknzr.c2977
-rw-r--r--src/cr-tknzr.h127
-rw-r--r--src/cr-token.c678
-rw-r--r--src/cr-token.h260
-rw-r--r--src/cr-utils.c1424
-rw-r--r--src/cr-utils.h277
-rw-r--r--src/libcroco.h21
-rw-r--r--stamp-h.in1
-rw-r--r--tests/Makefile.am17
-rw-r--r--tests/Makefile.in395
-rw-r--r--tests/core.17057bin0 -> 212992 bytes
-rw-r--r--tests/core.17936bin0 -> 212992 bytes
-rw-r--r--tests/cr-test-utils.c43
-rw-r--r--tests/cr-test-utils.h54
-rw-r--r--tests/more189
-rw-r--r--tests/test-inputs/test2.1.css35
-rw-r--r--tests/test-inputs/test2.2.css674
-rw-r--r--tests/test-inputs/test2.css9
-rw-r--r--tests/test-inputs/test3.1.css36
-rw-r--r--tests/test-inputs/test3.2.css693
-rw-r--r--tests/test-inputs/test3.css9
-rw-r--r--tests/test-inputs/test4.1.css679
-rw-r--r--tests/test-inputs/test4.2.css24
-rw-r--r--tests/test-outputs/test4.1.out762
-rw-r--r--tests/test0-main.c215
-rw-r--r--tests/test1-main.c211
-rw-r--r--tests/test2-main.c640
-rw-r--r--tests/test3-main.c643
-rw-r--r--tests/test4-main.c154
-rw-r--r--tests/valgrind.log144
-rwxr-xr-xtests/vg15
90 files changed, 29732 insertions, 0 deletions
diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100644
index 0000000..28d38c7
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,226 @@
+Notes on the Free Translation Project
+*************************************
+
+ Free software is going international! The Free Translation Project
+is a way to get maintainers of free software, translators, and users all
+together, so that will gradually become able to speak many languages.
+A few packages already provide translations for their messages.
+
+ If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site. But you do *not*
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+ Installers will find here some useful hints. These notes also
+explain how users should proceed for getting the programs to use the
+available translations. They tell how people wanting to contribute and
+work at translations should contact the appropriate team.
+
+ When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used. The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+One advise in advance
+=====================
+
+ If you want to exploit the full power of internationalization, you
+should configure it using
+
+ ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed. So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias or message inheritance) as the
+implementation here. It is also not possible to offer this additional
+functionality on top of a `catgets' implementation. Future versions of
+GNU `gettext' will very likely convey even more functionality. So it
+might be a good idea to change to GNU `gettext' as soon as possible.
+
+ So you need not provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+INSTALL Matters
+===============
+
+ Some packages are "localizable" when properly installed; the
+programs they contain can be made to speak your own native language.
+Most such packages use GNU `gettext'. Other packages have their own
+ways to internationalization, predating GNU `gettext'.
+
+ By default, this package will be installed to allow translation of
+messages. It will automatically detect whether the system provides
+usable `catgets' (if using this is selected by the installer) or
+`gettext' functions. If neither is available, the GNU `gettext' own
+library will be used. This library is wholly contained within this
+package, usually in the `intl/' subdirectory, so prior installation of
+the GNU `gettext' package is *not* required. Installers may use
+special options at configuration time for changing the default
+behaviour. The commands:
+
+ ./configure --with-included-gettext
+ ./configure --with-catgets
+ ./configure --disable-nls
+
+will respectively bypass any pre-existing `catgets' or `gettext' to use
+the internationalizing routines provided within this package, enable
+the use of the `catgets' functions (if found on the locale system), or
+else, *totally* disable translation of messages.
+
+ When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this. This might be not what is desirable. You
+should use the more recent version of the GNU `gettext' library. I.e.
+if the file `intl/VERSION' shows that the library which comes with this
+package is more recent, you should use
+
+ ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+ By default the configuration process will not test for the `catgets'
+function and therefore they will not be used. The reasons are already
+given above: the emulation on top of `catgets' cannot provide all the
+extensions provided by the GNU `gettext' library. If you nevertheless
+want to use the `catgets' functions use
+
+ ./configure --with-catgets
+
+to enable the test for `catgets' (this causes no harm if `catgets' is
+not available on your system). If you really select this option we
+would like to hear about the reasons because we cannot think of any
+good one ourself.
+
+ Internationalized packages have usually many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language. Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package. However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+Using This Package
+==================
+
+ As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+ISO 639 `LL' two-letter code prior to using the programs in the
+package. For example, let's suppose that you speak German. At the
+shell prompt, merely execute `setenv LANG de' (in `csh'),
+`export LANG; LANG=de' (in `sh') or `export LANG=de' (in `bash'). This
+can be done from your `.login' or `.profile' file, once and for all.
+
+ An operating system might already offer message localization for
+many of its programs, while other programs have been installed locally
+with the full capabilities of GNU `gettext'. Just using `gettext'
+extended syntax for `LANG' would break proper localization of already
+available operating system programs. In this case, users should set
+both `LANGUAGE' and `LANG' variables in their environment, as programs
+using GNU `gettext' give preference to `LANGUAGE'. For example, some
+Swedish users would rather read translations in German than English for
+when Swedish is not available. This is easily accomplished by setting
+`LANGUAGE' to `sv:de' while leaving `LANG' to `sv'.
+
+Translating Teams
+=================
+
+ For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list, courtesy of Linux
+International. You may reach your translation team at the address
+`LL@li.org', replacing LL by the two-letter ISO 639 code for your
+language. Language codes are *not* the same as the country codes given
+in ISO 3166. The following translation teams exist, as of December
+1997:
+
+ Chinese `zh', Czech `cs', Danish `da', Dutch `nl', English `en',
+ Esperanto `eo', Finnish `fi', French `fr', German `de', Hungarian
+ `hu', Irish `ga', Italian `it', Indonesian `id', Japanese `ja',
+ Korean `ko', Latin `la', Norwegian `no', Persian `fa', Polish
+ `pl', Portuguese `pt', Russian `ru', Slovenian `sl', Spanish `es',
+ Swedish `sv', and Turkish `tr'.
+
+For example, you may reach the Chinese translation team by writing to
+`zh@li.org'.
+
+ If you'd like to volunteer to *work* at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is *not* the same as the list itself, it has
+`-request' appended. For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+ subscribe
+
+ Keep in mind that team members are expected to participate
+*actively* in translations, or at solving translational difficulties,
+rather than merely lurking around. If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `translation@iro.umontreal.ca' to reach the
+coordinator for all translator teams.
+
+ The English team is special. It works at improving and uniformizing
+the terminology in use. Proven linguistic skill are praised more than
+programming skill, here.
+
+Available Packages
+==================
+
+ Languages are not equally supported in all packages. The following
+matrix shows the current state of internationalization, as of December
+1997. The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination.
+
+ Ready PO files cs da de en es fi fr it ja ko nl no pl pt ru sl sv
+ .----------------------------------------------------.
+ bash | [] [] [] | 3
+ bison | [] [] [] | 3
+ clisp | [] [] [] [] | 4
+ cpio | [] [] [] [] [] [] | 6
+ diffutils | [] [] [] [] [] | 5
+ enscript | [] [] [] [] [] [] | 6
+ fileutils | [] [] [] [] [] [] [] [] [] [] | 10
+ findutils | [] [] [] [] [] [] [] [] [] | 9
+ flex | [] [] [] [] | 4
+ gcal | [] [] [] [] [] | 5
+ gettext | [] [] [] [] [] [] [] [] [] [] [] | 12
+ grep | [] [] [] [] [] [] [] [] [] [] | 10
+ hello | [] [] [] [] [] [] [] [] [] [] [] | 11
+ id-utils | [] [] [] | 3
+ indent | [] [] [] [] [] | 5
+ libc | [] [] [] [] [] [] [] | 7
+ m4 | [] [] [] [] [] [] | 6
+ make | [] [] [] [] [] [] | 6
+ music | [] [] | 2
+ ptx | [] [] [] [] [] [] [] [] | 8
+ recode | [] [] [] [] [] [] [] [] [] | 9
+ sh-utils | [] [] [] [] [] [] [] [] | 8
+ sharutils | [] [] [] [] [] [] | 6
+ tar | [] [] [] [] [] [] [] [] [] [] [] | 11
+ texinfo | [] [] [] | 3
+ textutils | [] [] [] [] [] [] [] [] [] | 9
+ wdiff | [] [] [] [] [] [] [] [] | 8
+ `----------------------------------------------------'
+ 17 languages cs da de en es fi fr it ja ko nl no pl pt ru sl sv
+ 27 packages 6 4 25 1 18 1 26 2 1 12 20 9 19 7 4 7 17 179
+
+ Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect. This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+ For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer. There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+ If December 1997 seems to be old, you may fetch a more recent copy
+of this `ABOUT-NLS' file on most GNU archive sites.
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..7179b93
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Dodji Seketeli <dodji@seketli.org>
diff --git a/CODING-STYLE b/CODING-STYLE
new file mode 100644
index 0000000..2bad092
--- /dev/null
+++ b/CODING-STYLE
@@ -0,0 +1,113 @@
+Author: Dodji Seketeli.
+-----------------------
+
+Introduction
+------------
+
+The coding standard we use are based on the GNU coding standards
+available at http://www.gnu.org/prep/standards_toc.html
+and on the Gnome Coding standards available at
+http://developer.gnome.org/doc/guides/programming-guidelines/book1.html .
+
+Please, make sure you read these documents before you read this one.
+
+I) General coding style rules
+---------------------------
+
+Coding style refers to the way the code is formated.
+Here are the guidelines we use in this project:
+
+Indentation Style
+- - - - - - - - - -
+
+We use the 2-spaces tab indentation style (the GNU's one) .
+
+Make sure as much as possible that each code line does not
+exceed 80 characters length. Why ? because you don't know
+who will read your code. The smallest screens are 80 chars
+wide. So, please, make the code available to everybody.
+
+
+Functions naming
+- - - - - - - -
+
+We use the GNU name scheme to name our functions.
+
+GOOD:
+
+int
+my_function_name (char a_variable_name)
+{
+ printf ("The variable value is %c", a_variable_name) ;
+ return 0 ;
+}
+
+
+BAD:
+
+int
+myFunctionName (char blabla)
+{
+ printf ("This is awfull\n") ;
+}
+
+or
+
+int my_FunctionName (char Blabla) {
+ printf ("This is bad\n") ;
+}
+
+The words of the function names are separared by an underscore ('_') and
+are written in lower case.
+The name functions arguments allways start with by a "a_" .
+
+Avoid for instance the Java function (method) name scheme by mixing
+upper and lower case in the function names.
+
+
+Be genereous with white spaces:
+
+GOOD:
+
+int foo (int a_parameter)
+{
+ if (test == TRUE) {
+ printf ("Coucou\n") ;
+ }
+}
+
+BAD:
+
+int foo(int a_parameter)
+{
+ if(test==TRUE) {
+ printf("coucou\n")
+ }
+}
+
+
+To ensure that the each line of code is less than 80 characters,
+if a function has many parameters, you can write it this way:
+
+
+Constants naming
+- - - - - - - - -
+Constants (defines or constant variables) must be in upper case.
+The worlds of the constant name must be separated by an underscore ('_').
+For instance:
+
+GOOD:
+gint A_CONSTANT = 10 ;
+#define ANOTHER_CONSTANT 100 ;
+
+BAD:
+gin a_Constant = 10 ;
+#define another_Constant ;
+
+
+structure and enum naming
+---------------------
+
+
+II) Object Oriented C programming
+-----------------------------
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..3bc70a8
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,8 @@
+2002-09-25 dodji <dodji@seketeli.org>
+
+ * src/cr-utils.h: updated this file to define stuffs needed by
+ other modules.
+
+ * src/cr-parser-input.c: started to write down code to handle
+ the stacked parser input.
+
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..84eedbd
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,946 @@
+# Doxyfile 1.2.16
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = Libcroco
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs/apis
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean,
+# Norwegian, Polish, Portuguese, Romanian, Russian, Slovak, Slovene,
+# Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower case letters. If set to YES upper case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consist of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = src
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS = *.c *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse.
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line and do not end with a semicolon. Such function macros are typically
+# used for boiler-plate code, and will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/HACKING
@@ -0,0 +1 @@
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..b934909
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = src
+SUBDIRS += tests
+
+pkgconfigdir=$(libdir)/pkgconfig
+pkgconfig_DATA=libcroco.pc
+
+extraincludedir=$(includedir)/@PACKAGE@
+extrainclude_DATA= libcroco-config.h
+
+
+bin_SCRIPTS=croco-config
+
+
+EXTRA_DIST= croco-config.in libcroco.pc.in TODO Doxyfile HACKING
+
+apidoc:
+ if ! test -d docs/apis ; then mkdir -p docs/apis ; fi ;
+ doxygen Doxyfile \ No newline at end of file
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..4be7e0f
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,467 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CROCO_CFLAGS = @CROCO_CFLAGS@
+CROCO_LIBS = @CROCO_LIBS@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+LDFLAGS = @LDFLAGS@
+LIBCROCO_MAJOR_VERSION = @LIBCROCO_MAJOR_VERSION@
+LIBCROCO_MICRO_VERSION = @LIBCROCO_MICRO_VERSION@
+LIBCROCO_MINOR_VERSION = @LIBCROCO_MINOR_VERSION@
+LIBCROCO_VERSION = @LIBCROCO_VERSION@
+LIBCROCO_VERSION_INFO = @LIBCROCO_VERSION_INFO@
+LIBCROCO_VERSION_NUMBER = @LIBCROCO_VERSION_NUMBER@
+LIBTOOL = @LIBTOOL@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REQUIRE_LIBXML2 = @REQUIRE_LIBXML2@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+WITH_SELENG = @WITH_SELENG@
+SUBDIRS = src tests
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libcroco.pc
+
+extraincludedir = $(includedir)/@PACKAGE@
+extrainclude_DATA = libcroco-config.h
+
+bin_SCRIPTS = croco-config
+
+EXTRA_DIST = croco-config.in libcroco.pc.in TODO Doxyfile HACKING
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = libcroco-config.h
+CONFIG_CLEAN_FILES = libcroco.pc croco-config
+SCRIPTS = $(bin_SCRIPTS)
+
+DATA = $(extrainclude_DATA) $(pkgconfig_DATA)
+
+DIST_COMMON = README ./stamp-h.in ABOUT-NLS AUTHORS COPYING ChangeLog \
+INSTALL Makefile.am Makefile.in NEWS TODO aclocal.m4 config.guess \
+config.sub configure configure.in croco-config.in install-sh \
+libcroco-config.h.in libcroco.pc.in ltmain.sh missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): configure.in
+ cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+libcroco-config.h: stamp-h
+ @if test ! -f $@; then \
+ rm -f stamp-h; \
+ $(MAKE) stamp-h; \
+ else :; fi
+stamp-h: $(srcdir)/libcroco-config.h.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES= CONFIG_HEADERS=libcroco-config.h \
+ $(SHELL) ./config.status
+ @echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/libcroco-config.h.in: $(srcdir)/stamp-h.in
+ @if test ! -f $@; then \
+ rm -f $(srcdir)/stamp-h.in; \
+ $(MAKE) $(srcdir)/stamp-h.in; \
+ else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+ -rm -f libcroco-config.h
+
+maintainer-clean-hdr:
+libcroco.pc: $(top_builddir)/config.status libcroco.pc.in
+ cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+croco-config: $(top_builddir)/config.status croco-config.in
+ cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+install-binSCRIPTS: $(bin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_SCRIPTS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ else if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+ $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ else :; fi; fi; \
+ done
+
+uninstall-binSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ list='$(bin_SCRIPTS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+install-extraincludeDATA: $(extrainclude_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(extraincludedir)
+ @list='$(extrainclude_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(extraincludedir)/$$p"; \
+ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(extraincludedir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(extraincludedir)/$$p"; \
+ $(INSTALL_DATA) $$p $(DESTDIR)$(extraincludedir)/$$p; \
+ fi; fi; \
+ done
+
+uninstall-extraincludeDATA:
+ @$(NORMAL_UNINSTALL)
+ list='$(extrainclude_DATA)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(extraincludedir)/$$p; \
+ done
+
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(pkgconfigdir)
+ @list='$(pkgconfig_DATA)'; for p in $$list; do \
+ if test -f $(srcdir)/$$p; then \
+ echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkgconfigdir)/$$p"; \
+ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkgconfigdir)/$$p; \
+ else if test -f $$p; then \
+ echo " $(INSTALL_DATA) $$p $(DESTDIR)$(pkgconfigdir)/$$p"; \
+ $(INSTALL_DATA) $$p $(DESTDIR)$(pkgconfigdir)/$$p; \
+ fi; fi; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ list='$(pkgconfig_DATA)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(pkgconfigdir)/$$p; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+ rev="$$subdir $$rev"; \
+ test "$$subdir" != "." || dot_seen=yes; \
+ done; \
+ test "$$dot_seen" = "no" && rev=". $$rev"; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) libcroco-config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)libcroco-config.h.in$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags libcroco-config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) dist
+ -rm -rf $(distdir)
+ @banner="$(distdir).tar.gz is ready for distribution"; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"
+dist: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+distdir: $(DISTFILES)
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ fi; \
+ done
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+all-recursive-am: libcroco-config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am: install-binSCRIPTS
+install-exec: install-exec-recursive
+
+install-data-am: install-extraincludeDATA install-pkgconfigDATA
+install-data: install-data-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am: uninstall-binSCRIPTS uninstall-extraincludeDATA \
+ uninstall-pkgconfigDATA
+uninstall: uninstall-recursive
+all-am: Makefile $(SCRIPTS) $(DATA) libcroco-config.h
+all-redirect: all-recursive-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+ $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(extraincludedir) \
+ $(DESTDIR)$(pkgconfigdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am: clean-hdr clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am: distclean-hdr distclean-tags distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-recursive
+ -rm -f config.status
+
+maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+uninstall-binSCRIPTS install-binSCRIPTS uninstall-extraincludeDATA \
+install-extraincludeDATA uninstall-pkgconfigDATA install-pkgconfigDATA \
+install-data-recursive uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \
+install-exec-am install-exec install-data-am install-data install-am \
+install uninstall-am uninstall all-redirect all-am all installdirs-am \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+apidoc:
+ if ! test -d docs/apis ; then mkdir -p docs/apis ; fi ;
+ doxygen Doxyfile
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+
diff --git a/README b/README
new file mode 100644
index 0000000..150a4e5
--- /dev/null
+++ b/README
@@ -0,0 +1,4 @@
+What is The GNU Croco Project ?
+------------------------------
+
+Initial Author: Dodji Seketeli. <dodji@seketeli.org> \ No newline at end of file
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..7bbe5a9
--- /dev/null
+++ b/TODO
@@ -0,0 +1,12 @@
+
+*coding:)
+
+ Continue the testing of the css2 parsing using the test4 test.
+ The test4 test justs reads a css2 stylesheets and dumps it on stdout.
+
+*Doc:)
+Finish the design of the instruction set of the selection engine.
+ The draft design is in the file
+ docs/designs/docs/design/sel-instr.txt.
+
+Write a litte doc about how to use the parser as it is today. \ No newline at end of file
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..965661a
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+#Author: Dodji Seketeli.
+
+
+echo "autogen.sh: Running aclocal ..."
+aclocal
+echo "autogen.sh: aclocal: done"
+
+echo "autogen.sh: Running autoconf -f ..."
+autoconf
+echo "autogen.sh: autoconf: done"
+
+echo "autogen.sh: Running automake -a -c ..."
+automake --gnu -a -c
+echo "autogen.sh: automake: done"
+
+echo "autogen.sh: Running configure ..."
+./configure $@
+echo "autogen.sh: configure: done"
diff --git a/config.log b/config.log
new file mode 100644
index 0000000..6222e4b
--- /dev/null
+++ b/config.log
@@ -0,0 +1,36 @@
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by config.status, which was
+generated by GNU Autoconf 2.53. Invocation command line was
+
+ CONFIG_FILES = tests/Makefile
+ CONFIG_HEADERS =
+ CONFIG_LINKS =
+ CONFIG_COMMANDS =
+ $ ./config.status
+
+on tintin.mifon.org
+
+config.status:621: creating tests/Makefile
+config.status:933: executing default-1 commands
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by config.status, which was
+generated by GNU Autoconf 2.53. Invocation command line was
+
+ CONFIG_FILES = src/Makefile
+ CONFIG_HEADERS =
+ CONFIG_LINKS =
+ CONFIG_COMMANDS =
+ $ ./config.status
+
+on tintin.mifon.org
+
+config.status:621: creating src/Makefile
+config.status:933: executing default-1 commands
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..0110caa
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,153 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.5)
+AC_INIT(src/cr-input.c)
+
+PACKAGE=libcroco
+LIBCROCO_MAJOR_VERSION=0
+LIBCROCO_MINOR_VERSION=1
+LIBCROCO_MICRO_VERSION=0
+
+LIBCROCO_VERSION=$LIBCROCO_MAJOR_VERSION.$LIBCROCO_MINOR_VERSION.$LIBCROCO_MICRO_VERSION
+LIBCROCO_VERSION_INFO=$LIBCROCO_MAJOR_VERSION:$LIBCROCO_MINOR_VERSION:$LIBCROCO_MICRO_VERSION
+LIBCROCO_VERSION_NUMBER=`expr "$LIBCROCO_MAJOR_VERSION \* 10000 +$LIBCROCO_MINOR_VERSION \* 100 + $LIBCROCO_MICRO_VERSION"`
+VERSION=$LIBCROCO_VERSION
+
+USE_LIBXML2=no
+WITH_SELENG=no
+
+AC_SUBST(LIBCROCO_MAJOR_VERSION)
+AC_SUBST(LIBCROCO_MINOR_VERSION)
+AC_SUBST(LIBCROCO_MICRO_VERSION)
+AC_SUBST(LIBCROCO_VERSION)
+AC_SUBST(LIBCROCO_VERSION_INFO)
+AC_SUBST(LIBCROCO_VERSION_NUMBER)
+AC_SUBST(VERSION)
+
+AM_INIT_AUTOMAKE($PACKAGE, $LIBCROCO_VERSION)
+AM_CONFIG_HEADER(libcroco-config.h)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_CPP
+
+dnl Make sure we have an ANSI compiler
+AM_C_PROTOTYPES
+test "x$U" != "x" && AC_MSG_ERROR(Compiler not ANSI compliant)
+
+dnl Checks for libraries.
+dnl Checks for header files.
+AC_STDC_HEADERS
+AC_ISC_POSIX
+
+AM_PROG_LIBTOOL
+
+dnl **************************************************************
+dnl check for the different --enable-option=val
+dnl messages issued by the user
+dnl ***************************************************************
+
+dnl -
+dnl --enable-seleng
+dnl this option enables compilation of the selection engine
+AC_ARG_ENABLE(seleng,
+ AC_HELP_STRING([--enable-seleng=yes|no],
+ [Enables the css2 selector engine based on libxml2. Default=yes]),
+ WITH_SELENG=$enableval,
+ WITH_SELENG="yes")
+
+if test "$WITH_SELENG" = "yes" ; then
+ USE_LIBXML2=yes
+ AC_DEFINE(WITH_SELENG, 1, [use css2 selection engine])
+fi
+AC_SUBST(WITH_SELENG)
+
+dnl ************************************************
+dnl end of check of the different --enable-feature options
+dnl *************************************************
+
+dnl
+dnl Find pkg-config
+dnl
+
+AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+if test x$PKG_CONFIG = xno ; then
+ AC_MSG_ERROR([*** pkg-config not found. See http://www.freedesktop.org/software/pkgconfig/])
+fi
+
+
+dnl check libxml2 version
+if test "$USE_LIBXML2" = "yes" ; then
+ dnl
+ dnl Find awk
+ dnl
+
+ AC_PROG_AWK
+
+ AC_MSG_CHECKING([checking for libxml2])
+
+ LIBXML_MAJOR=2
+ LIBXML_MINOR=5
+ LIBXML_MICRO=1
+ LIBXML=`pkg-config --list-all|grep libxml-2.0`
+ if test "empty$LIBXML" = "empty" ; then
+ AC_MSG_ERROR([*** libxml2 not found. See http://xmlsoft.org. Make sure "pkg-config --modversion libxml2" prints at least $LIBXML_MAJOR.$LIBXML_MINOR.$LIBXML_MICRO]) ;
+ fi
+ LIBXML_VERSION=`pkg-config --modversion libxml-2.0`
+
+ MAJOR=`echo $LIBXML_VERSION |awk 'BEGIN {FS="."} {print $1}'`
+ MINOR=`echo $LIBXML_VERSION |awk 'BEGIN {FS="."} {print $2}'`
+ MICRO=`echo $LIBXML_VERSION |awk 'BEGIN {FS="."} {print $3}'`
+ LIBXML_VERSION=$MAJOR.$MINOR.$MICRO
+
+ if test "$LIBXML_MAJOR" -lt "2" ; then
+ AC_MSG_ERROR([libxml2 version at least $LIBXML_MAJOR.$LIBXML_MINOR.$LIBXML_MICRO required. Found version $LIBXML_VERSION])
+ fi
+
+ if test "$LIBXML_MINOR" -gt "$MINOR" ; then
+ AC_MSG_ERROR([libxml2 version at least $LIBXML_MAJOR.$LIBXML_MINOR.$LIBXML_MICRO required. Found version $LIBXML_VERSION])
+ fi
+
+ if test "$LIBXML_MICRO" -gt "$MICRO" ; then
+ AC_MSG_ERROR([libxml2 version at least $LIBXML_MAJOR.$LIBXML_MINOR.$LIBXML_MICRO required]. Found version $LIBXML_VERSION)
+ fi
+
+ AC_DEFINE(HAVE_LIBXML2, 1, [use libxml2])
+ AC_MSG_RESULT([yes])
+fi
+
+dnl By default compile in debug mode
+CFLAGS=-g
+
+CROCO_LIBS='-L${libdir}'
+CROCO_CFLAGS='-I${includedir}'
+
+if test "$USE_LIBXML2" = "yes" ; then
+ LIBXML2_LIBS=`pkg-config --libs libxml-2.0`
+ CROCO_LIBS="$CROCO_LIBS $LIBXML2_LIBS"
+ LIBXML2_CFLAGS=`pk-config --cflags libxml-2.0`
+ CROCO_CFLAGS="$CROCO_CFLAGS $LIBXML2_CFLAGS"
+ REQUIRE_LIBXML2=libxml-2.0
+else
+ CROCO_LIBS=
+ CROCO_FLAGS=
+ REQUIRE_LIBXML2=
+fi
+
+AC_SUBST(CROCO_CFLAGS)
+AC_SUBST(CROCO_LIBS)
+AC_SUBST(LIBXML2_LIBS)
+AC_SUBST(LIBXML2_CFLAGS)
+AC_SUBST(REQUIRE_LIBXML2)
+
+AC_SUBST(LDFLAGS)
+AC_SUBST(CFLAGS)
+
+AC_PROG_MAKE_SET
+AC_OUTPUT([
+Makefile
+libcroco.pc
+croco-config
+src/Makefile
+tests/Makefile
+]) \ No newline at end of file
diff --git a/croco-config.in b/croco-config.in
new file mode 100644
index 0000000..8c9ca05
--- /dev/null
+++ b/croco-config.in
@@ -0,0 +1,87 @@
+#! /bin/sh
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
+includedir=@includedir@
+libdir=@libdir@
+
+usage()
+{
+ cat <<EOF
+Usage: croco-config [OPTION]...
+
+Known values for OPTION are:
+
+ --prefix=DIR change CROCO prefix [default $prefix]
+ --exec-prefix=DIR change CROCO executable prefix [default $exec_prefix]
+ --libs print library linking information
+ --cflags print pre-processor and compiler flags
+ --help display this help and exit
+ --version output version information
+EOF
+
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1
+fi
+
+cflags=false
+libs=false
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case "$1" in
+ --prefix=*)
+ prefix=$optarg
+ if test $exec_prefix_set = no ; then
+ exec_prefix=$optarg
+ fi
+ ;;
+
+ --prefix)
+ echo $prefix
+ ;;
+
+ --exec-prefix=*)
+ exec_prefix=$optarg
+ exec_prefix_set=yes
+ ;;
+
+ --exec-prefix)
+ echo $exec_prefix
+ ;;
+
+ --version)
+ echo @VERSION@
+ exit 0
+ ;;
+
+ --help)
+ usage 0
+ ;;
+
+ --cflags)
+ echo -I${includedir}/libcroco
+ ;;
+
+ --libs)
+ echo -L${libdir} -lcroco
+ ;;
+
+ *)
+ usage
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+
+exit 0
diff --git a/docs/design/sel-instr.txt b/docs/design/sel-instr.txt
new file mode 100644
index 0000000..774f0e1
--- /dev/null
+++ b/docs/design/sel-instr.txt
@@ -0,0 +1,64 @@
+Draft of the libcroco selector internal instruction set.
+*********************************************************
+
+READERS SHOULD READ THE CHAPTER 5 of THE CSS2 CSS2 SPEC INTITLED
+"Selectors" FIRST.
+
+I) Introduction
+''''''''''''''''''''
+This is the instructions set understood by the libcroco
+sel-eng.c module (Selection engine).
+
+The purpose of the selection engine is to basically to say whether if a given
+xml node is matched by a given css2 selector or not.
+
+II) Rationale
+''''''''''''''''''''
+For the sake of performance (mostly processing speed) each CSS2
+selector is compiled into a sequences of atomic selection instructions
+that are easily executable by the selection engine.
+
+III) Selection instruction set overview
+''''''''''''''''''''''''''''''''''''''''
+
+Each selection instruction returns a boolean value (TRUE or FALSE).
+The execution of a sequence of selection instruction stops at the
+first instruction that returns a FALSE value and the selection engine
+returns returns the value FALSE to say that the current xml node
+is matched by the CSS2 selection expression being evaluated.
+
+Note that during the evaluation of a CSS2 selection expression,
+all the contextual information are stored into an evalutation context.
+For example, the context will hold a pointer to the xml node the
+selection engine is trying to match.
+
+III.1) The instruction set.
+'''''''''''''''''''''''''''
+
+set-cur-node 'a_node'
+----------------------
+a_node: an xml node
+Sets the current xml node (in the context) to a_node.
+
+match-n-ancestor 'a_n' 'a_parent'
+----------------------------------
+a_parent: a string.
+a_n: a number. The depth of the ancestor
+
+Returns true if the current xml node has an ancestor
+located at a depth 'n' (going upward from the current node)
+and named 'a_parent'. An ancestor located at depth '0' designates
+the current xml node. An ancesstor located at depth '1' designates
+the parent of the current xml node etc ...
+
+match-any
+---------
+Always returns true.
+
+match-first-child 'a_name'
+--------------------------
+Returns true if the current xml element's name equal 'a_name' and
+if the current xml element is the first child of its parent.
+
+TODO: continue reading the chapter 5 of the css2 spec and finish
+the design of this instruction set.
diff --git a/libcroco-config.h.in b/libcroco-config.h.in
new file mode 100644
index 0000000..c1731be
--- /dev/null
+++ b/libcroco-config.h.in
@@ -0,0 +1,64 @@
+/* libcroco-config.h.in. Generated from configure.in by autoheader. */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* use libxml2 */
+#undef HAVE_LIBXML2
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define if compiler has function prototypes */
+#undef PROTOTYPES
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* use css2 selection engine */
+#undef WITH_SELENG
diff --git a/libcroco.pc.in b/libcroco.pc.in
new file mode 100644
index 0000000..e161ed7
--- /dev/null
+++ b/libcroco.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libcroco
+Version: @VERSION@
+Description: a CSS2 Parsing Library in C.
+Requires: glib-2.0 @REQUIRE_LIBXML2@
+Libs: @CROCO_LIBS@
+Cflags: @CROCO_CFLAGS@ \ No newline at end of file
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644
index 0000000..2a4db21
--- /dev/null
+++ b/src/.cvsignore
@@ -0,0 +1,2 @@
+.libs
+.deps \ No newline at end of file
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..3d6fc3d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,33 @@
+lib_LTLIBRARIES=libcroco.la
+
+crocoincdir=$(includedir)/@PACKAGE@
+
+crocoinc_HEADERS= *.h
+
+libcroco_la_SOURCES= \
+ cr-utils.c \
+ cr-input.c \
+ cr-parser-input.c \
+ cr-enc-handler.c \
+ cr-num.c \
+ cr-rgb.c \
+ cr-token.c \
+ cr-tknzr.c \
+ cr-term.c \
+ cr-attr-sel.c \
+ cr-pseudo.c \
+ cr-additional-sel.c \
+ cr-simple-sel.c \
+ cr-selector.c \
+ cr-doc-handler.c \
+ cr-parser.c \
+ cr-declaration.c \
+ cr-statement.c \
+ cr-stylesheet.c \
+ cr-om-parser.c \
+ cr-sel-eng.c \
+ *.h
+
+INCLUDES=-I$(top_srcdir) -I$(top_srcdir)/intl `pkg-config --cflags glib-2.0` `pkg-config --cflags libxml-2.0` @LIBXM2_CFLAGS@
+libcroco_la_LDFLAGS=-version-info @LIBCROCO_VERSION_INFO@ @LIBXML2_FLAGS@
+AM_CFLAGS=-Wall \ No newline at end of file
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..145c804
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,400 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CROCO_CFLAGS = @CROCO_CFLAGS@
+CROCO_LIBS = @CROCO_LIBS@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+LDFLAGS = @LDFLAGS@
+LIBCROCO_MAJOR_VERSION = @LIBCROCO_MAJOR_VERSION@
+LIBCROCO_MICRO_VERSION = @LIBCROCO_MICRO_VERSION@
+LIBCROCO_MINOR_VERSION = @LIBCROCO_MINOR_VERSION@
+LIBCROCO_VERSION = @LIBCROCO_VERSION@
+LIBCROCO_VERSION_INFO = @LIBCROCO_VERSION_INFO@
+LIBCROCO_VERSION_NUMBER = @LIBCROCO_VERSION_NUMBER@
+LIBTOOL = @LIBTOOL@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REQUIRE_LIBXML2 = @REQUIRE_LIBXML2@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+WITH_SELENG = @WITH_SELENG@
+
+lib_LTLIBRARIES = libcroco.la
+
+crocoincdir = $(includedir)/@PACKAGE@
+
+crocoinc_HEADERS = *.h
+
+libcroco_la_SOURCES = cr-utils.c cr-input.c cr-parser-input.c cr-enc-handler.c cr-num.c cr-rgb.c cr-token.c cr-tknzr.c cr-term.c cr-attr-sel.c cr-pseudo.c cr-additional-sel.c cr-simple-sel.c cr-selector.c cr-doc-handler.c cr-parser.c cr-declaration.c cr-statement.c cr-stylesheet.c cr-om-parser.c cr-sel-eng.c *.h
+
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/intl `pkg-config --cflags glib-2.0` `pkg-config --cflags libxml-2.0` @LIBXM2_CFLAGS@
+libcroco_la_LDFLAGS = -version-info @LIBCROCO_VERSION_INFO@ @LIBXML2_FLAGS@
+AM_CFLAGS = -Wall
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../libcroco-config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(lib_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LIBS = @LIBS@
+libcroco_la_LIBADD =
+libcroco_la_OBJECTS = cr-utils.lo cr-input.lo cr-parser-input.lo \
+cr-enc-handler.lo cr-num.lo cr-rgb.lo cr-token.lo cr-tknzr.lo \
+cr-term.lo cr-attr-sel.lo cr-pseudo.lo cr-additional-sel.lo \
+cr-simple-sel.lo cr-selector.lo cr-doc-handler.lo cr-parser.lo \
+cr-declaration.lo cr-statement.lo cr-stylesheet.lo cr-om-parser.lo \
+cr-sel-eng.lo
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS = $(crocoinc_HEADERS)
+
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+DEP_FILES = .deps/cr-additional-sel.P .deps/cr-attr-sel.P \
+.deps/cr-declaration.P .deps/cr-doc-handler.P .deps/cr-enc-handler.P \
+.deps/cr-input.P .deps/cr-num.P .deps/cr-om-parser.P \
+.deps/cr-parser-input.P .deps/cr-parser.P .deps/cr-pseudo.P \
+.deps/cr-rgb.P .deps/cr-sel-eng.P .deps/cr-selector.P \
+.deps/cr-simple-sel.P .deps/cr-statement.P .deps/cr-stylesheet.P \
+.deps/cr-term.P .deps/cr-tknzr.P .deps/cr-token.P .deps/cr-utils.P
+SOURCES = $(libcroco_la_SOURCES)
+OBJECTS = $(libcroco_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .obj .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-libLTLIBRARIES:
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+
+distclean-libLTLIBRARIES:
+
+maintainer-clean-libLTLIBRARIES:
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(libdir)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \
+ $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
+ done
+
+# FIXME: We should only use cygpath when building on Windows,
+# and only if it is available.
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libcroco.la: $(libcroco_la_OBJECTS) $(libcroco_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libcroco_la_LDFLAGS) $(libcroco_la_OBJECTS) $(libcroco_la_LIBADD) $(LIBS)
+
+install-crocoincHEADERS: $(crocoinc_HEADERS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(crocoincdir)
+ @list='$(crocoinc_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
+ echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(crocoincdir)/$$p"; \
+ $(INSTALL_DATA) $$d$$p $(DESTDIR)$(crocoincdir)/$$p; \
+ done
+
+uninstall-crocoincHEADERS:
+ @$(NORMAL_UNINSTALL)
+ list='$(crocoinc_HEADERS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(crocoincdir)/$$p; \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-libLTLIBRARIES
+install-exec: install-exec-am
+
+install-data-am: install-crocoincHEADERS
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-libLTLIBRARIES uninstall-crocoincHEADERS
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(crocoincdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-libLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \
+ clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-libLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-libLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \
+clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \
+uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \
+distclean-compile clean-compile maintainer-clean-compile \
+mostlyclean-libtool distclean-libtool clean-libtool \
+maintainer-clean-libtool uninstall-crocoincHEADERS \
+install-crocoincHEADERS tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir mostlyclean-depend distclean-depend \
+clean-depend maintainer-clean-depend info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/cr-additional-sel.c b/src/cr-additional-sel.c
new file mode 100644
index 0000000..7070aba
--- /dev/null
+++ b/src/cr-additional-sel.c
@@ -0,0 +1,355 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include "cr-additional-sel.h"
+#include "string.h"
+
+/**
+ *Default constructor of #CRAdditionalSel.
+ *@return the newly build instance of #CRAdditionalSel.
+ */
+CRAdditionalSel *
+cr_additional_sel_new (void)
+{
+ CRAdditionalSel *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRAdditionalSel)) ;
+
+ if (result == NULL)
+ {
+ cr_utils_trace_debug ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRAdditionalSel)) ;
+
+ return result ;
+}
+
+
+/**
+ *Constructor of #CRAdditionalSel.
+ *@param a_sel_type the type of the newly built instance
+ *of #CRAdditionalSel.
+ *@return the newly built instance of #CRAdditionalSel.
+ */
+CRAdditionalSel *
+cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type)
+{
+ CRAdditionalSel * result = NULL ;
+
+ result = cr_additional_sel_new () ;
+
+ g_return_val_if_fail (result, NULL) ;
+
+ result->type = a_sel_type ;
+
+ return result ;
+}
+
+/**
+ *Sets a new class name to a
+ *CLASS additional selector.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAdditionalSel .
+ *@param a_class_name the new class name to set.
+ *
+ */
+void
+cr_additional_sel_set_class_name (CRAdditionalSel *a_this,
+ GString *a_class_name)
+{
+ g_return_if_fail (a_this
+ && a_this->type == CLASS_ADD_SELECTOR) ;
+
+ if (a_this->content.class_name)
+ {
+ g_string_free (a_this->content.class_name, TRUE) ;
+ }
+
+ a_this->content.class_name = a_class_name ;
+}
+
+/**
+ *Sets a new id name to an
+ *ID additional selector.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAdditionalSel .
+ *@param a_id the new id to set.
+ */
+void
+cr_additional_sel_set_id_name (CRAdditionalSel *a_this,
+ GString *a_id)
+{
+ g_return_if_fail (a_this
+ && a_this->type == ID_ADD_SELECTOR) ;
+
+ if (a_this->content.id_name)
+ {
+ g_string_free (a_this->content.id_name, TRUE) ;
+ }
+
+ a_this->content.id_name = a_id ;
+}
+
+/**
+ *Sets a new pseudo to a
+ *PSEUDO additional selector.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAdditionalSel .
+ *@param a_pseudo the new pseudo to set.
+ */
+void
+cr_additional_sel_set_pseudo (CRAdditionalSel *a_this,
+ CRPseudo *a_pseudo)
+{
+ g_return_if_fail (a_this
+ && a_this->type == PSEUDO_CLASS_ADD_SELECTOR) ;
+
+ if (a_this->content.pseudo)
+ {
+ cr_pseudo_destroy (a_this->content.pseudo) ;
+ }
+
+ a_this->content.pseudo = a_pseudo ;
+}
+
+/**
+ *Sets a new instance of #CRAttrSel to
+ *a ATTRIBUTE additional selector.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAdditionalSel .
+ *@param a_sel the new instance of #CRAttrSel to set.
+ */
+void
+cr_additional_sel_set_attr_sel (CRAdditionalSel *a_this,
+ CRAttrSel *a_sel)
+{
+ g_return_if_fail (a_this
+ && a_this->type == ATTRIBUTE_ADD_SELECTOR) ;
+
+ if (a_this->content.attr_sel)
+ {
+ cr_attr_sel_destroy (a_this->content.attr_sel) ;
+ }
+
+ a_this->content.attr_sel = a_sel ;
+}
+
+/**
+ *Appends a new instance of #CRAdditional to the
+ *current list of #CRAdditional.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAdditionalSel .
+ *@param a_sel the new instance to #CRAdditional to append.
+ *@return the new list of CRAdditionalSel or NULL if an error arises.
+ */
+CRAdditionalSel *
+cr_additional_sel_append (CRAdditionalSel *a_this,
+ CRAdditionalSel *a_sel)
+{
+ CRAdditionalSel *cur_sel = NULL ;
+
+ g_return_val_if_fail (a_sel, NULL) ;
+
+ if (a_this == NULL)
+ {
+ return a_sel ;
+ }
+
+ if (a_sel == NULL)
+ return NULL ;
+
+ for (cur_sel = a_this ;
+ cur_sel && cur_sel->next ;
+ cur_sel = cur_sel->next) ;
+
+ g_return_val_if_fail (cur_sel != NULL, NULL) ;
+
+ cur_sel->next = a_sel ;
+ a_sel->prev = cur_sel ;
+
+ return a_this ;
+}
+
+/**
+ *Preppends a new instance of #CRAdditional to the
+ *current list of #CRAdditional.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAdditionalSel .
+ *@param a_sel the new instance to #CRAdditional to preappend.
+ *@return the new list of CRAdditionalSel or NULL if an error arises.
+ */
+CRAdditionalSel *
+cr_additional_sel_prepend (CRAdditionalSel *a_this,
+ CRAdditionalSel *a_sel)
+{
+ g_return_val_if_fail (a_sel, NULL) ;
+
+ if (a_this == NULL)
+ {
+ return a_sel ;
+ }
+
+ a_sel->next = a_this ;
+ a_this->prev = a_sel ;
+
+ return a_sel ;
+}
+
+
+/**
+ *Dumps the current instance of #CRAdditionalSel to a file
+ *@param a_this the "this pointer" of the current instance of
+ *#CRAdditionalSel.
+ *@param a_fp the destination file.
+ */
+void
+cr_additional_sel_dump (CRAdditionalSel *a_this, FILE *a_fp)
+{
+ CRAdditionalSel *cur = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ for (cur = a_this ;cur ; cur = cur->next)
+ {
+ switch (cur->type)
+ {
+ case CLASS_ADD_SELECTOR:
+ {
+ guchar * name = NULL ;
+ if (cur->content.class_name)
+ {
+ name = g_strndup
+ (cur->content.class_name->str,
+ cur->content.class_name->len);
+
+ if (name)
+ {
+ fprintf (a_fp, ".%s", name) ;
+ g_free (name) ;
+ name = NULL ;
+ }
+ }
+ }
+ break ;
+
+ case ID_ADD_SELECTOR:
+ {
+ guchar * name = NULL ;
+ if (cur->content.class_name)
+ {
+ name = g_strndup
+ (cur->content.id_name->str,
+ cur->content.id_name->len);
+
+ if (name)
+ {
+ fprintf (a_fp, "#%s", name) ;
+ g_free (name) ;
+ name = NULL ;
+ }
+ }
+ }
+
+ break ;
+
+ case PSEUDO_CLASS_ADD_SELECTOR:
+ {
+ if (cur->content.pseudo)
+ {
+ fprintf (a_fp, ":") ;
+ cr_pseudo_dump (cur->content.pseudo, a_fp) ;
+ }
+ }
+ break ;
+
+ case ATTRIBUTE_ADD_SELECTOR:
+ if (cur->content.attr_sel)
+ {
+ fprintf (a_fp,"[") ;
+
+ cr_attr_sel_dump (cur->content.attr_sel,
+ a_fp) ;
+
+ fprintf (a_fp,"]") ;
+ }
+
+ break ;
+
+ default:
+ break ;
+ }
+ }
+}
+
+/**
+ *Destroys an instance of #CRAdditional.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAdditionalSel .
+ */
+void
+cr_additional_sel_destroy (CRAdditionalSel *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ switch (a_this->type)
+ {
+ case CLASS_ADD_SELECTOR:
+ g_string_free (a_this->content.class_name, TRUE) ;
+ a_this->content.class_name = NULL ;
+ break ;
+
+ case PSEUDO_CLASS_ADD_SELECTOR:
+ cr_pseudo_destroy (a_this->content.pseudo) ;
+ a_this->content.pseudo = NULL ;
+ break ;
+
+ case ID_ADD_SELECTOR:
+ g_string_free (a_this->content.id_name, TRUE) ;
+ a_this->content.id_name = NULL ;
+ break ;
+
+ case ATTRIBUTE_ADD_SELECTOR:
+ cr_attr_sel_destroy (a_this->content.attr_sel) ;
+ a_this->content.attr_sel = NULL ;
+ break ;
+
+ default :
+ break ;
+ }
+
+ if (a_this->next)
+ {
+ cr_additional_sel_destroy (a_this->next) ;
+ }
+
+ g_free (a_this) ;
+}
diff --git a/src/cr-additional-sel.h b/src/cr-additional-sel.h
new file mode 100644
index 0000000..290e78d
--- /dev/null
+++ b/src/cr-additional-sel.h
@@ -0,0 +1,111 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *This file holds the declaration of the
+ *#CRAddSel class.
+ */
+#ifndef __CR_ADD_SEL_H
+#define __CR_ADD_SEL_H
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-attr-sel.h"
+#include "cr-pseudo.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ enum AddSelectorType
+ {
+ NO_ADD_SELECTOR = 0 ,
+ CLASS_ADD_SELECTOR = 1 ,
+ PSEUDO_CLASS_ADD_SELECTOR = 1 << 1,
+ ID_ADD_SELECTOR = 1 << 3,
+ ATTRIBUTE_ADD_SELECTOR = 1 << 4
+ } ;
+
+ union CRAdditionalSelectorContent
+ {
+ GString *class_name ;
+ GString *id_name ;
+ CRPseudo *pseudo ;
+ CRAttrSel *attr_sel ;
+ } ;
+
+ typedef struct _CRAdditionalSel CRAdditionalSel ;
+
+ /**
+ *#CRAdditionalSel abstracts
+ *an additionnal selector.
+ *An additional selector is the selector part
+ *that comes after the combination of type selectors.
+ *It can be either "a class selector (the .class part),
+ *a pseudo class selector, an attribute selector
+ *or an id selector.
+ */
+ struct _CRAdditionalSel
+ {
+ enum AddSelectorType type ;
+ union CRAdditionalSelectorContent content ;
+
+ CRAdditionalSel * next ;
+ CRAdditionalSel * prev ;
+ } ;
+
+ CRAdditionalSel *
+ cr_additional_sel_new (void) ;
+
+ CRAdditionalSel *
+ cr_additional_sel_new_with_type
+ (enum AddSelectorType a_sel_type) ;
+
+ CRAdditionalSel *
+ cr_additional_sel_append (CRAdditionalSel *a_this,
+ CRAdditionalSel *a_sel) ;
+
+ CRAdditionalSel *
+ cr_additional_sel_prepend (CRAdditionalSel *a_this,
+ CRAdditionalSel *a_sel) ;
+
+ void
+ cr_additional_sel_dump (CRAdditionalSel *a_this, FILE *a_fp) ;
+
+ void
+ cr_additional_sel_destroy (CRAdditionalSel *a_this) ;
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif /*__cplusplus*/
+
+#endif /*__CR_ADD_SEL_H*/
diff --git a/src/cr-attr-sel.c b/src/cr-attr-sel.c
new file mode 100644
index 0000000..045eca6
--- /dev/null
+++ b/src/cr-attr-sel.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include "cr-attr-sel.h"
+
+/**
+ *@file
+ *The class that abstracts an attribute selector.
+ *Attributes selectors are described in the css2 spec [5.8].
+ *There are more generally used in the css2 selectors described in
+ *css2 spec [5] .
+ */
+
+
+/**
+ *The constructor of #CRAttrSel.
+ *@return the newly allocated instance
+ *of #CRAttrSel.
+ */
+CRAttrSel *
+cr_attr_sel_new (void)
+{
+ CRAttrSel *result = NULL ;
+ result = g_malloc0 (sizeof (CRAttrSel)) ;
+
+ return result ;
+}
+
+/**
+ *Appends an attribute selector to the current list of
+ *attribute selectors represented by a_this.
+ *
+ *@param a_this the this pointer of the current instance of
+ *#CRAttrSel.
+ *@param a_attr_sel selector to append.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_attr_sel_append_attr_sel (CRAttrSel *a_this, CRAttrSel *a_attr_sel)
+{
+ CRAttrSel * cur_sel = NULL ;
+
+ g_return_val_if_fail (a_this && a_attr_sel,
+ CR_BAD_PARAM_ERROR) ;
+
+ for (cur_sel = a_this ; cur_sel->next ; cur_sel = cur_sel->next) ;
+
+ cur_sel->next = a_attr_sel ;
+ a_attr_sel->prev = cur_sel ;
+
+ return CR_OK ;
+}
+
+/**
+ *Prepends an attribute selector to the list of
+ *attributes selector represented by a_this.
+ *
+ *@param a_this the "this pointer" of the current instance
+ *of #CRAttrSel.
+ *@param a_attr_sel the attribute selector to append.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_attr_sel_prepend_attr_sel (CRAttrSel *a_this, CRAttrSel *a_attr_sel)
+{
+ g_return_val_if_fail (a_this && a_attr_sel, CR_BAD_PARAM_ERROR) ;
+
+ a_attr_sel->next = a_this ;
+ a_this->prev = a_attr_sel ;
+
+ return CR_OK ;
+}
+
+/**
+ *Dumps the current instance of #CRAttrSel to a file.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRAttrSel.
+ *@param a_fp the destination file.
+ */
+void
+cr_attr_sel_dump (CRAttrSel *a_this, FILE *a_fp)
+{
+ CRAttrSel *cur = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ {
+ if (cur->prev)
+ {
+ fprintf (a_fp," ") ;
+ }
+
+ if (cur->name)
+ {
+ guchar *name = NULL ;
+
+ name = g_strndup (cur->name->str,
+ cur->name->len) ;
+ if (name)
+ {
+ fprintf (a_fp,name) ;
+ g_free (name) ;
+ name = NULL ;
+ }
+ }
+
+ if (cur->value)
+ {
+ guchar *value = NULL ;
+
+ value = g_strndup (cur->value->str,
+ cur->value->len) ;
+ if (value)
+ {
+ switch (cur->match_way)
+ {
+ case SET:
+ break ;
+
+ case EQUALS:
+ fprintf (a_fp,"=") ;
+ break ;
+
+ case INCLUDES:
+ fprintf (a_fp,"~=") ;
+ break ;
+
+ case DASHMATCH:
+ fprintf (a_fp,"|=") ;
+ break ;
+
+ default:
+ break ;
+ }
+
+ fprintf (a_fp,value) ;
+
+ g_free (value) ;
+ value = NULL ;
+ }
+ }
+ }
+}
+
+
+/**
+ *Destroys the current instance of #CRAttrSel.
+ *Frees all the fields if they are non null.
+ *@param a_this the "this pointer" of the current
+ *instance of #CRAttrSel.
+ */
+void
+cr_attr_sel_destroy (CRAttrSel *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->name)
+ {
+ g_string_free (a_this->name, TRUE) ;
+ a_this->name = NULL ;
+ }
+
+ if (a_this->value)
+ {
+ g_string_free (a_this->value, TRUE) ;
+ a_this->value = NULL ;
+ }
+
+ if (a_this->next)
+ {
+ cr_attr_sel_destroy (a_this->next) ;
+ a_this->next = NULL ;
+ }
+
+ if (a_this)
+ {
+ g_free (a_this) ;
+ a_this = NULL ;
+ }
+}
diff --git a/src/cr-attr-sel.h b/src/cr-attr-sel.h
new file mode 100644
index 0000000..c287992
--- /dev/null
+++ b/src/cr-attr-sel.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+
+#ifndef __CR_ATTR_SEL_H__
+#define __CR_ATTR_SEL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ struct _CRAttrSel ;
+ typedef struct _CRAttrSel CRAttrSel ;
+
+ enum AttrMatchWay
+ {
+ NO_MATCH = 0,
+ SET,
+ EQUALS,
+ INCLUDES,
+ DASHMATCH
+ } ;
+
+ struct _CRAttrSel
+ {
+ GString *name ;
+ GString *value ;
+ enum AttrMatchWay match_way ;
+ CRAttrSel *next ;
+ CRAttrSel *prev ;
+ } ;
+
+ CRAttrSel *
+ cr_attr_sel_new (void) ;
+
+ enum CRStatus
+ cr_attr_sel_append_attr_sel (CRAttrSel * a_this,
+ CRAttrSel *a_new) ;
+
+ void
+ cr_attr_sel_dump (CRAttrSel *a_this, FILE *a_fp) ;
+
+ void
+ cr_attr_sel_destroy (CRAttrSel *a_this) ;
+
+#ifdef __cplusplus
+} /*extern C*/
+#endif
+
+
+#endif /*__CR_ATTR_SEL_H__*/
diff --git a/src/cr-declaration.c b/src/cr-declaration.c
new file mode 100644
index 0000000..48e7467
--- /dev/null
+++ b/src/cr-declaration.c
@@ -0,0 +1,342 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <string.h>
+#include "cr-declaration.h"
+
+/**
+ *@file
+ *The definition of the #CRDeclaration class.
+ */
+
+
+/**
+ *Dumps (serializes) one css declaration to a file.
+ *@param a_this the current instance of #CRDeclaration.
+ *@param a_fp the destination file pointer.
+ *@param a_indent the number of indentation white char.
+ */
+static void
+dump (CRDeclaration *a_this, FILE *a_fp, glong a_indent)
+{
+ g_return_if_fail (a_this) ;
+ guchar *str = NULL, *tmp_str = NULL, *tmp_str2 = NULL;
+
+ if (a_this->property && a_this->property->str)
+ {
+ tmp_str = g_strndup (a_this->property->str,
+ a_this->property->len) ;
+ if (tmp_str)
+ {
+ tmp_str2 = g_strconcat (tmp_str, " : ", NULL) ;
+ if (!tmp_str2) goto error ;
+ if (tmp_str)
+ {
+ g_free (tmp_str) ;
+ tmp_str = NULL ;
+ }
+ str = tmp_str2 ;
+ }
+
+ if (str)
+ {
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+ fprintf (a_fp,"%s", str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ else
+ goto error ;
+
+ if (a_this->value)
+ {
+ cr_term_dump (a_this->value, a_fp) ;
+ }
+
+ }
+
+
+ return ;
+
+ error:
+ if (str)
+ {
+ g_free (str) ;
+ str = NULL ;
+ }
+ if (tmp_str)
+ {
+ g_free (tmp_str) ;
+ tmp_str = NULL ;
+ }
+ if (tmp_str2)
+ {
+ g_free (tmp_str2) ;
+ tmp_str2 = NULL ;
+ }
+}
+
+/**
+ *Constructor of #CRDeclaration.
+ *@param a_property the property string of the declaration
+ *@param a_value the value expression of the declaration.
+ *@return the newly built instance of #CRDeclaration, or NULL in
+ *case of error.
+ */
+CRDeclaration *
+cr_declaration_new (GString *a_property, CRTerm *a_value)
+{
+ CRDeclaration *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRDeclaration)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (CRDeclaration)) ;
+ result->property = a_property ;
+ result->value = a_value ;
+
+ if (a_value)
+ {
+ cr_term_ref (a_value) ;
+ }
+
+ return result ;
+}
+
+/**
+ *Appends a new declaration to the current declarations list.
+ *@param a_this the current declaration list.
+ *@param a_new the declaration to append.
+ *@return the declaration list with a_new appended to it, or NULL
+ *in case of error.
+ */
+CRDeclaration *
+cr_declaration_append (CRDeclaration *a_this, CRDeclaration *a_new)
+{
+ CRDeclaration *cur = NULL ;
+
+ g_return_val_if_fail (a_new, NULL) ;
+
+ if (!a_this)
+ return a_new ;
+
+ for (cur = a_this ; cur && cur->next ; cur = cur->next) ;
+
+ cur->next = a_new ;
+ a_new->prev = cur ;
+
+ return a_this ;
+}
+
+/**
+ *prepends a declaration to the current declaration list.
+ *@param a_this the current declaration list.
+ *@param a_new the declaration to prepend.
+ *@return the list with a_new prepended or NULL in case of error.
+ */
+CRDeclaration *
+cr_declaration_prepend (CRDeclaration *a_this, CRDeclaration *a_new)
+{
+ CRDeclaration *cur = NULL ;
+
+ g_return_val_if_fail (a_new, NULL) ;
+
+ if (!a_this)
+ return a_new ;
+
+ a_this->prev = a_new ;
+ a_new->next = a_this ;
+
+ for (cur = a_new ; cur && cur->prev ; cur = cur->prev) ;
+
+ return cur ;
+}
+
+/**
+ *Appends a declaration to the current declaration list.
+ *@param a_this the current declaration list.
+ *@param a_prop the property string of the declaration to append.
+ *@param a_value the value of the declaration to append.
+ *@return the list with the new property appended to it, or NULL in
+ *case of an error.
+ */
+CRDeclaration *
+cr_declaration_append2 (CRDeclaration *a_this, GString *a_prop,
+ CRTerm *a_value)
+{
+ CRDeclaration *new_elem = NULL ;
+
+ new_elem = cr_declaration_new (a_prop, a_value) ;
+ g_return_val_if_fail (new_elem, NULL) ;
+
+ return cr_declaration_append (a_this, new_elem) ;
+}
+
+/**
+ *Dumps a declaration list to a file.
+ *@param a_this the current instance of #CRDeclaration.
+ *@param a_fp the destination file.
+ *@param a_indent the number of indentation white char.
+ */
+void
+cr_declaration_dump (CRDeclaration *a_this, FILE *a_fp, glong a_indent,
+ gboolean a_one_per_line)
+{
+ CRDeclaration *cur = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ {
+ if (cur->prev)
+ {
+ if (a_one_per_line == TRUE)
+ fprintf (a_fp,";\n") ;
+ else
+ fprintf (a_fp,"; ") ;
+ }
+ dump (cur, a_fp, a_indent) ;
+ }
+}
+
+/**
+ *Increases the ref count of the current instance of #CRDeclaration.
+ *@param a_this the current instance of #CRDeclaration.
+ */
+void
+cr_declaration_ref (CRDeclaration *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ a_this->ref_count ++ ;
+}
+
+/**
+ *Decrements the ref count of the current instance of #CRDeclaration.
+ *If the ref count reaches zero, the current instance of #CRDeclaration
+ *if destroyed.
+ *@param a_this the current instance of #CRDeclaration.
+ *@return TRUE if the current instance of #CRDeclaration has been destroyed
+ *(ref count reached zero), FALSE otherwise.
+ */
+gboolean
+cr_declaration_unref (CRDeclaration *a_this)
+{
+ g_return_val_if_fail (a_this, FALSE) ;
+
+ if (a_this->ref_count)
+ {
+ a_this->ref_count -- ;
+ }
+
+ if (a_this->ref_count == 0)
+ {
+ cr_declaration_destroy (a_this) ;
+ return TRUE ;
+ }
+ return FALSE ;
+}
+
+
+/**
+ *Destructor of the declaration list.
+ *@param a_this the current instance of #CRDeclaration.
+ */
+void
+cr_declaration_destroy (CRDeclaration *a_this)
+{
+ CRDeclaration *cur = NULL ;
+ g_return_if_fail (a_this) ;
+
+ /*
+ *Go get the tail of the list.
+ *Meanwhile, free each property/value pair contained in the list.
+ */
+ for (cur = a_this ; cur && cur->next; cur = cur->next)
+ {
+ if (cur->property)
+ {
+ g_string_free (cur->property, TRUE) ;
+ cur->property = NULL ;
+ }
+
+ if (cur->value)
+ {
+ cr_term_destroy (cur->value) ;
+ cur->value = NULL ;
+ }
+ }
+
+ if (cur)
+ {
+ if (cur->property)
+ {
+ g_string_free (cur->property, TRUE) ;
+ cur->property = NULL ;
+ }
+
+ if (cur->value)
+ {
+ cr_term_destroy (cur->value) ;
+ cur->value = NULL ;
+ }
+ }
+
+ /*in case the list contains only one element*/
+ if (cur && !cur->prev)
+ {
+ g_free (cur) ;
+ return ;
+ }
+
+ /*walk backward the list and free each "next" element*/
+ for (cur = cur->prev ; cur && cur->prev ; cur = cur->prev)
+ {
+ if (cur->next)
+ {
+ g_free (cur->next) ;
+ cur->next = NULL ;
+ }
+ }
+
+ if (!cur)
+ return ;
+
+ if (cur->next)
+ {
+ g_free (cur->next) ;
+ cur->next = NULL ;
+ }
+
+ g_free (cur) ;
+}
diff --git a/src/cr-declaration.h b/src/cr-declaration.h
new file mode 100644
index 0000000..20bd859
--- /dev/null
+++ b/src/cr-declaration.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_DECLARATION_H__
+#define __CR_DECLARATION_H__
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-term.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the #CRDeclaration class.
+ */
+
+/**
+ *The abstraction of a css declaration defined by the
+ *css2 spec in chapter 4.
+ */
+typedef struct _CRDeclaration CRDeclaration ;
+struct _CRDeclaration
+{
+ /**The property.*/
+ GString *property ;
+
+ /**The value of the property.*/
+ CRTerm *value ;
+
+ CRDeclaration *next ;
+ CRDeclaration *prev ;
+ glong ref_count ;
+} ;
+
+
+CRDeclaration *
+cr_declaration_new (GString *a_property, CRTerm *a_value) ;
+
+CRDeclaration *
+cr_declaration_append (CRDeclaration *a_this, CRDeclaration *a_new) ;
+
+CRDeclaration *
+cr_declaration_prepend (CRDeclaration *a_this, CRDeclaration *a_new) ;
+
+CRDeclaration *
+cr_declaration_append2 (CRDeclaration *a_this, GString *a_prop,
+ CRTerm *a_value) ;
+
+void
+cr_declaration_dump (CRDeclaration *a_this, FILE *a_fp, glong a_indent,
+ gboolean a_one_per_line) ;
+
+void
+cr_declaration_ref (CRDeclaration *a_this) ;
+
+gboolean
+cr_declaration_unref (CRDeclaration *a_this) ;
+
+void
+cr_declaration_destroy (CRDeclaration *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_DECLARATION_H__*/
diff --git a/src/cr-doc-handler.c b/src/cr-doc-handler.c
new file mode 100644
index 0000000..16fb3a7
--- /dev/null
+++ b/src/cr-doc-handler.c
@@ -0,0 +1,146 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+
+#include "cr-doc-handler.h"
+#include <string.h>
+
+/**
+ *@file
+ *The definition of the CRDocHandler class.
+ *Contains methods to instantiate, destroy,
+ *and initialyze instances of #CRDocHandler
+ *to custom values.
+ */
+
+
+/**
+ *Constructor of #CRDocHandler.
+ *@return the newly built instance of
+ *#CRDocHandler
+ */
+CRDocHandler *
+cr_doc_handler_new (void)
+{
+ CRDocHandler * result = NULL ;
+
+ result = g_try_malloc (sizeof (CRDocHandler)) ;
+
+ g_return_val_if_fail (result, NULL) ;
+
+ memset (result, 0, sizeof (CRDocHandler)) ;
+
+ cr_doc_handler_set_default_sac_handler (result) ;
+
+ return result ;
+}
+
+
+/**
+ *Sets the sac handlers contained in the current
+ *instance of DocHandler to the default handlers.
+ *For the time being the default handlers are
+ *test handlers. This is expected to change in a
+ *near future, when the libcroco gets a bit debugged.
+ *
+ *@param a_this a pointer to the current instance of #CRDocHandler.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_set_default_sac_handler (CRDocHandler *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ a_this->start_document = NULL;
+ a_this->end_document = NULL ;
+ a_this->import_style = NULL ;
+ a_this->namespace_declaration = NULL ;
+ a_this->comment = NULL ;
+ a_this->start_selector = NULL ;
+ a_this->end_selector = NULL ;
+ a_this->property = NULL ;
+ a_this->start_font_face = NULL ;
+ a_this->end_font_face = NULL ;
+ a_this->start_media = NULL ;
+ a_this->end_media = NULL ;
+ a_this->start_page = NULL ;
+ a_this->end_page = NULL ;
+ a_this->ignorable_at_rule = NULL ;
+ a_this->error = NULL ;
+ a_this->unrecoverable_error = NULL ;
+ return CR_OK ;
+}
+
+/**
+ *Increases the reference count of the doc handler
+ *@param a_this the current instance of #CRDocHandler.
+ */
+void
+cr_doc_handler_ref (CRDocHandler *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ a_this->ref_count++ ;
+}
+
+/**
+ *Decreases the ref count of the current instance of #CRDocHandler.
+ *If the ref count reaches '0' then, destroys the instance.
+ *@param a_this the currrent instance of #CRDocHandler.
+ *@return TRUE if the instance as been destroyed, FALSE otherwise.
+ */
+gboolean
+cr_doc_handler_unref (CRDocHandler *a_this)
+{
+ g_return_val_if_fail (a_this, FALSE) ;
+
+ if (a_this->ref_count > 0)
+ {
+ a_this->ref_count -- ;
+ }
+
+ if (a_this->ref_count == 0)
+ {
+ cr_doc_handler_destroy (a_this) ;
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+
+/**
+ *The destructor of the #CRDocHandler class.
+ *@param a_this the instance of #CRDocHandler to
+ *destroy.
+ */
+void
+cr_doc_handler_destroy (CRDocHandler *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ g_free (a_this) ;
+}
diff --git a/src/cr-doc-handler.h b/src/cr-doc-handler.h
new file mode 100644
index 0000000..c47f544
--- /dev/null
+++ b/src/cr-doc-handler.h
@@ -0,0 +1,283 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+#ifndef __CR_DOC_HANDLER_H__
+#define __CR_DOC_HANDLER_H__
+
+/**
+ *@file
+ *The declaration of the #CRDocumentHandler class.
+ *This class is actually the parsing events handler.
+ */
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parser-input.h"
+#include "cr-selector.h"
+#include "cr-term.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRDocHandler CRDocHandler ;
+
+/**
+ *The SAC document handler.
+ *An instance of this class is to
+ *be passed to a parser. Then, during the parsing
+ *the parser calls the convenient function pointer
+ *whenever a particular event (a css construction) occurs.
+ */
+struct _CRDocHandler
+{
+ /**
+ *This pointer is to be used by the application for
+ *it custom needs. It is there to extend the doc handler.
+ */
+ void * app_data ;
+
+ /**
+ *This pointer is to hold an application parsing context.
+ *For example, it used by the Object Model parser to
+ *store it parsing context. #CRParser does not touch it, but
+ *#CROMParser does. #CROMParser allocates this pointer at
+ *the beginning of the css document, and frees it at the end
+ *of the document.
+ */
+ void * context ;
+
+ /**
+ *The place where #CROMParser put the result of it parsing, if
+ *any.
+ */
+ void * result ;
+
+ /**
+ *Is called at the beginning of the parsing of the document.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ */
+ void (*start_document) (CRDocHandler *a_this) ;
+
+ /**
+ *Is called to notify the end of the parsing of the document.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ */
+ void (*end_document) (CRDocHandler *a_this) ;
+
+ /**
+ *Is called to notify an at charset rule.
+ *@param a_this the document handler.
+ *@param a_charset the declared charset.
+ */
+ void (*charset) (CRDocHandler *a_this, GString *a_charset) ;
+
+ /**
+ *Is called to notify an import statement in
+ *the stylesheet.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_media_list a doubly linked list of GString objects.
+ *Each GString object contains a string which is the
+ *destination media for style information.
+ *@param a_uri the uri of the imported style sheet.
+ *@param a_uri_default_ns the default namespace of URI
+ *of the imported style sheet.
+ */
+ void (*import_style) (CRDocHandler *a_this,
+ GList *a_media_list,
+ GString *a_uri,
+ GString *a_uri_default_ns) ;
+
+
+ /**
+ *Is called to notify a namespace declaration.
+ *Not used yet.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_prefix the prefix of the namespace.
+ *@param a_uri the uri of the namespace.
+ */
+ void (*namespace_declaration) (CRDocHandler *a_this,
+ GString *a_prefix,
+ GString *a_uri) ;
+
+ /**
+ *Is called to notify a comment.
+ *@param a_this a pointer to the current instance
+ *of #CRDocHandler.
+ *@param a_comment the comment.
+ */
+ void (*comment) (CRDocHandler *a_this,
+ GString *a_comment) ;
+
+ /**
+ *Is called to notify the beginning of a rule
+ *statement.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_selector_list the list of selectors that precedes
+ *the rule declarations. The GList named a_selector_list
+ *is a chained list of instances of #CRSimpleSel
+ *
+ */
+ void (*start_selector) (CRDocHandler * a_this,
+ CRSelector *a_selector_list) ;
+
+ /**
+ *Is called to notify the end of a rule statement.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_selector_list the list of selectors that precedes
+ *the rule declarations. This pointer is the same as
+ *the one passed to start_selector() ;
+ */
+ void (*end_selector) (CRDocHandler *a_this,
+ CRSelector *a_selector_list) ;
+
+
+ /**
+ *Is called to notify a declaration.
+ *@param a_this a pointer to the current instance
+ *of #CRDocHandler.
+ *@param a_name the name of the parsed property.
+ *@param a_expression a css expression that represents
+ *the value of the property. A css expression is
+ *actually a linked list of 'terms'. Each term can
+ *be linked to other using operators.
+ *
+ */
+ void (*property) (CRDocHandler *a_this,
+ GString *a_name,
+ CRTerm *a_expression) ;
+
+ /**
+ *Is called to notify the start of a font face statement.
+ *The parser invokes this method at the beginning of every
+ *font face statement in the style sheet. There will
+ *be a corresponding end_font_face () event for every
+ *start_font_face () event.
+ *
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ */
+ void (*start_font_face) (CRDocHandler *a_this) ;
+
+ /**
+ *Is called to notify the end of a font face statement.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ */
+ void (*end_font_face) (CRDocHandler *a_this) ;
+
+
+ /**
+ *Is called to notify the beginning of a media statement.
+ *The parser will invoke this method at the beginning of
+ *every media statement in the style sheet. There will be
+ *a corresponding end_media() event for every start_media()
+ *event.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ *@param a_media_list a double linked list of GString * objects.
+ *Each GString objects is actually a destination media for
+ *the style information.
+ */
+ void (*start_media) (CRDocHandler *a_this,
+ GList *a_media_list) ;
+
+ /**
+ *Is called to notify the end of a media statement.
+ *@param a_this a pointer to the current instance
+ *of #CRDocHandler.
+ *@param a_media_list a double linked list of GString * objects.
+ *Each GString objects is actually a destination media for
+ *the style information.
+ */
+ void (*end_media) (CRDocHandler *a_this,
+ GList *a_media_list) ;
+
+ /**
+ *Is called to notify the beginning of a page statement.
+ *The parser invokes this function at the beginning of
+ *every page statement in the style sheet. There will be
+ *a corresponding end_page() event for every single
+ *start_page() event.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ *@param a_name the name of the page (if any, null otherwise).
+ *@param a_pseudo_page the pseudo page (if any, null otherwise).
+ */
+ void (*start_page) (CRDocHandler *a_this,
+ GString *a_name,
+ GString *pseudo_page) ;
+
+ /**
+ *Is called to notify the end of a page statement.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ *@param a_name the name of the page (if any, null otherwise).
+ *@parap a_pseudo_page the pseudo page (if any, null otherwise).
+ */
+ void (*end_page) (CRDocHandler *a_this,
+ GString *a_name,
+ GString *pseudo_page) ;
+
+ /**
+ *Is Called to notify an unknown at-rule not supported
+ *by this parser.
+ */
+ void (*ignorable_at_rule) (CRDocHandler *a_this,
+ GString *a_name) ;
+
+ /**
+ *Is called to notify a parsing error. After this error
+ *the application must ignore the rule being parsed, if
+ *any. After completion of this callback,
+ *the parser will then try to resume the parsing,
+ *ignoring the current error.
+ */
+ void (*error) (CRDocHandler *a_this) ;
+
+ /**
+ *Is called to notify an unrecoverable parsing error.
+ *
+ */
+ void (*unrecoverable_error) (CRDocHandler *a_this) ;
+
+ gulong ref_count ;
+} ;
+
+CRDocHandler * cr_doc_handler_new (void) ;
+
+enum CRStatus
+cr_doc_handler_set_default_sac_handler (CRDocHandler *a_this) ;
+
+void cr_doc_handler_ref (CRDocHandler *a_this) ;
+gboolean cr_doc_handler_unref (CRDocHandler *a_this) ;
+
+void cr_doc_handler_destroy (CRDocHandler *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_DOC_HANDLER_H__*/
diff --git a/src/cr-enc-handler.c b/src/cr-enc-handler.c
new file mode 100644
index 0000000..65678aa
--- /dev/null
+++ b/src/cr-enc-handler.c
@@ -0,0 +1,197 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition of the #CREncHandler class.
+ */
+
+
+#include "cr-enc-handler.h"
+#include "cr-utils.h"
+
+#include <string.h>
+
+struct CREncAlias {
+ guchar * name ;
+ enum CREncoding encoding ;
+} ;
+
+static struct CREncAlias gv_default_aliases[] =
+{
+ {"UTF-8", CR_UTF_8},
+ {"UTF_8", CR_UTF_8},
+ {"UTF8", CR_UTF_8},
+ {"UTF-16", CR_UTF_16},
+ {"UTF_16", CR_UTF_16},
+ {"UTF16", CR_UTF_16},
+ {"UCS1", CR_UCS_1},
+ {"UCS-1", CR_UCS_1},
+ {"UCS_1", CR_UCS_1},
+ {"ISO-8859-1", CR_UCS_1},
+ {"ISO_8859-1", CR_UCS_1},
+ {"UCS-1", CR_UCS_1},
+ {"UCS_1", CR_UCS_1},
+ {"UCS4", CR_UCS_4},
+ {"UCS-4", CR_UCS_4},
+ {"UCS_4", CR_UCS_4},
+ {"ASCII", CR_ASCII},
+ {0}
+} ;
+
+
+static CREncHandler gv_default_enc_handlers[] =
+{
+ {CR_UCS_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+ {CR_ISO_8859_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+ {CR_ASCII, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+ {0}
+} ;
+
+
+/**
+ *Gets the instance of encoding handler.
+ *This function implements a singleton pattern.
+ *@param a_enc the encoding of the Handler.
+ *@return the instance of #CREncHandler.
+ */
+CREncHandler *
+cr_enc_handler_get_instance (enum CREncoding a_enc)
+{
+ gulong i = 0 ;
+
+ for (i = 0 ;gv_default_enc_handlers[i].encoding ; i++)
+ {
+ if (gv_default_enc_handlers[i].encoding == a_enc)
+ {
+ return
+ (CREncHandler *)
+ &gv_default_enc_handlers[i].encoding ;
+ }
+ }
+
+ return NULL ;
+}
+
+
+/**
+ *Given an encoding name (called an alias name)
+ *the function returns the matching encoding type.
+ *@param a_alias_name the encoding name
+ *@param a_enc output param. The returned encoding type
+ *or 0 if the alias is not supported.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_enc_handler_resolve_enc_alias (guchar *a_alias_name,
+ enum CREncoding *a_enc)
+{
+ gulong i = 0 ;
+ guchar * alias_name_up = NULL ;
+ enum CRStatus status = CR_ENCODING_NOT_FOUND_ERROR ;
+
+ g_return_val_if_fail (a_alias_name != NULL, CR_BAD_PARAM_ERROR) ;
+
+ alias_name_up = g_strdup (a_alias_name) ;
+ g_strup (alias_name_up) ;
+
+ for (i = 0 ; gv_default_aliases[i].name ; i++)
+ {
+ if (!strcmp (gv_default_aliases[i].name, alias_name_up))
+ {
+ *a_enc = gv_default_aliases[i].encoding ;
+ status = CR_OK ;
+ break ;
+ }
+ }
+
+ return status ;
+}
+
+
+/**
+ *Converts a raw input buffer into an utf8 buffer.
+ *@param a_this the current instance of #CREncHandler.
+ *@param a_in the input buffer to convert.
+ *@param a_in_len in/out parameter. The len of the input
+ *buffer to convert. After return, contains the number of
+ *bytes actually consumed.
+ *@param @a_out output parameter. The converted output buffer.
+ *Must be freed by the buffer.
+ *@param a_out_len output parameter. The length of the output buffer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_enc_handler_convert_input (CREncHandler *a_this,
+ guchar *a_in,
+ gulong *a_in_len,
+ guchar **a_out,
+ gulong *a_out_len)
+{
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && a_in && a_in_len && a_out,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (a_this->decode_input == NULL) return CR_OK ;
+
+ if (a_this->enc_str_len_as_utf8)
+ {
+ status =
+ a_this->enc_str_len_as_utf8 (a_in,
+ &a_in[*a_in_len -1],
+ a_out_len) ;
+
+ g_return_val_if_fail (status == CR_OK, status) ;
+ }
+ else
+ {
+ *a_out_len = *a_in_len ;
+ }
+
+ *a_out = g_malloc0 (*a_out_len) ;
+
+ status = a_this->decode_input (a_in, a_in_len, *a_out, a_out_len) ;
+
+ if (status != CR_OK)
+ {
+ g_free (*a_out) ;
+ *a_out = NULL ;
+ }
+
+ g_return_val_if_fail (status == CR_OK, status) ;
+
+ return CR_OK ;
+}
diff --git a/src/cr-enc-handler.h b/src/cr-enc-handler.h
new file mode 100644
index 0000000..32ef756
--- /dev/null
+++ b/src/cr-enc-handler.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file:
+ *The declaration of the #CREncHandler class.
+ *
+ */
+
+#ifndef __CR_ENC_HANDLER_H__
+#define __CR_ENC_HANDLER_H__
+
+#include "cr-utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus*/
+
+
+typedef struct _CREncHandler CREncHandler ;
+
+ typedef enum CRStatus (*CREncInputFunc) (guchar * a_in,
+ gulong *a_in_len,
+ guchar *a_out,
+ gulong *a_out_len) ;
+
+ typedef enum CRStatus (*CREncOutputFunc) (guchar * a_in,
+ gulong *a_in_len,
+ guchar *a_out,
+ gulong *a_out_len) ;
+
+ typedef enum CRStatus (*CREncInputStrLenAsUtf8Func) (guchar *a_in_start,
+ guchar *a_in_end,
+ gulong *a_in_size);
+
+ typedef enum CRStatus (*CREncUtf8StrLenAsOutputFunc)
+ (guchar *a_in_start,
+ guchar *a_in_end,
+ gulong *a_in_size) ;
+
+/**
+ *This class is responsible of the
+ *the encoding conversions stuffs in
+ *libcroco.
+ */
+
+ struct _CREncHandler
+ {
+ enum CREncoding encoding ;
+ CREncInputFunc decode_input ;
+ CREncInputFunc encode_output ;
+ CREncInputStrLenAsUtf8Func enc_str_len_as_utf8 ;
+ CREncUtf8StrLenAsOutputFunc utf8_str_len_as_enc ;
+ } ;
+
+ CREncHandler *
+ cr_enc_handler_get_instance (enum CREncoding a_enc) ;
+
+ enum CRStatus
+ cr_enc_handler_resolve_enc_alias (guchar *a_en_alias,
+ enum CREncoding *a_enc) ;
+ void
+ cr_enc_handler_destroy (CREncHandler * a_enc_hdlr) ;
+
+ enum CRStatus
+ cr_enc_handler_convert_input (CREncHandler *a_this,
+ guchar *a_in,
+ gulong *a_in_len,
+ guchar **a_out,
+ gulong *a_out_len) ;
+
+#ifdef __cplusplus
+} /*extern "C" {*/
+#endif /*__cplusplus*/
+
+#endif /*__CR_ENC_HANDLER_H__*/
diff --git a/src/cr-input.c b/src/cr-input.c
new file mode 100644
index 0000000..18c0f5a
--- /dev/null
+++ b/src/cr-input.c
@@ -0,0 +1,1091 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+
+#include "stdio.h"
+#include "string.h"
+#include "cr-input.h"
+#include "cr-enc-handler.h"
+
+
+/**
+ *@file
+ *The definition of the #CRInput class.
+ */
+
+/*******************
+ *Private type defs
+ *******************/
+
+
+/**
+ *The privated attributes of
+ *the #CRInputPriv class.
+ */
+struct _CRInputPriv
+{
+ /*
+ *The input buffer
+ */
+ guchar *in_buf ;
+ glong in_buf_size ;
+
+ glong nb_bytes ;
+
+ /*
+ *The index of the next byte
+ *to be read.
+ */
+ glong next_byte_index ;
+
+ /*
+ *The current line number
+ */
+ gulong line ;
+
+ /*
+ *The current col number.
+ */
+ gulong col ;
+
+ gboolean end_of_line ;
+ gboolean end_of_input ;
+
+ /*
+ *the reference count of this
+ *instance.
+ */
+ guint ref_count ;
+} ;
+
+
+#define PRIVATE(object) (object)->priv
+
+
+/***************************
+ *private constants
+ **************************/
+#define CR_INPUT_MEM_CHUNK_SIZE 1024
+
+
+/****************
+ *Public methods
+ ***************/
+
+
+/**
+ *Creates a new input stream from
+ *a file.
+ *@param a_file_uri the file to create
+ *the input stream from.
+ *@param a_enc the encoding of the file
+ *to create the input from
+ *@return the newly created input stream if
+ *this method couldn read the file and create it,
+ *NULL otherwise.
+ */
+CRInput *
+cr_input_new_from_uri (gchar *a_file_uri, enum CREncoding a_enc)
+{
+ CRInput * result = NULL ;
+ enum CRStatus status = CR_OK ;
+ FILE * file_ptr = NULL ;
+ guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = {0} ;
+ gint nb_read = 0 ;
+ gboolean loop = TRUE ;
+ CREncHandler * enc_handler = NULL ;
+
+ g_return_val_if_fail (a_file_uri, NULL) ;
+
+ file_ptr = fopen (a_file_uri, "r") ;
+
+ if (file_ptr == NULL)
+ {
+
+#ifdef CR_DEBUG
+ cr_utils_trace_debug ("could not open file") ;
+#endif
+ g_warning ("Could not open file %s\n", a_file_uri) ;
+
+ return NULL ;
+ }
+
+ result = g_malloc0 (sizeof (CRInput)) ;
+ PRIVATE (result) = g_malloc0 (sizeof (CRInputPriv)) ;
+
+ while (loop)
+ {
+
+ nb_read =
+ fread (tmp_buf, 1/*read bytes*/,
+ CR_INPUT_MEM_CHUNK_SIZE/*nb of bytes*/,
+ file_ptr) ;
+
+ if (nb_read != CR_INPUT_MEM_CHUNK_SIZE)
+ {
+ /*we read less chars than we wanted*/
+
+ if (feof (file_ptr))
+ {
+ /*we reached eof*/
+ loop = FALSE ;
+ }
+ else
+ {
+ /*a pb occured !!*/
+#ifdef CR_DEBUG
+ cr_utils_trace_debug
+ ("an io error occured") ;
+#endif
+ status = CR_ERROR ;
+ }
+ }
+
+ if (status == CR_OK)
+ {
+ /*read went well*/
+
+ PRIVATE (result)->in_buf =
+ g_realloc (PRIVATE (result)->in_buf,
+ PRIVATE (result)->in_buf_size
+ + CR_INPUT_MEM_CHUNK_SIZE) ;
+
+ memcpy (PRIVATE (result)->in_buf
+ + PRIVATE (result)->in_buf_size ,
+ tmp_buf, nb_read) ;
+
+ PRIVATE (result)->in_buf_size +=
+ nb_read ;
+ }
+ }
+
+ PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size ;
+
+ if (file_ptr)
+ {
+ fclose (file_ptr) ;
+ file_ptr = NULL ;
+ }
+
+ if (status == CR_OK)
+ {
+ /*
+ *Make sure the input's internal buffer
+ *is encoded in utf-8.
+ */
+ if (a_enc != CR_UTF_8)
+ {
+ enc_handler = cr_enc_handler_get_instance (a_enc);
+ if (enc_handler == NULL && result)
+ {
+ goto error ;
+ }
+ else
+ {
+ /*encode the buffer in utf8.*/
+ guchar *utf8_buf = NULL ;
+ gulong len = 0 ;
+
+ status = cr_enc_handler_convert_input
+ (enc_handler,
+ PRIVATE (result)->in_buf,
+ &PRIVATE (result)->in_buf_size,
+ &utf8_buf, &len) ;
+
+ if (status != CR_OK)
+ {
+ goto error ;
+ }
+
+ g_free (PRIVATE (result)->in_buf) ;
+ PRIVATE (result)->in_buf = utf8_buf ;
+ PRIVATE (result)->in_buf_size = len ;
+ PRIVATE (result)->line = 1 ;
+ }
+ }
+ }
+ else
+ {
+ cr_utils_trace_debug ("Input loading failed") ;
+ goto error ;
+ }
+
+ return result ;
+
+ error:
+ if (result)
+ {
+
+ /*free result*/
+ cr_input_destroy (result) ;
+ result = NULL ;
+ }
+
+ return NULL ;
+}
+
+
+/**
+ *The destructor of the #CRInput class.
+ *@param a_this the current instance of #CRInput.
+ */
+void
+cr_input_destroy (CRInput *a_this)
+{
+ if (a_this == NULL)
+ return ;
+
+ if (PRIVATE (a_this))
+ {
+ if (PRIVATE (a_this)->in_buf)
+ {
+ g_free (PRIVATE (a_this)->in_buf) ;
+ PRIVATE (a_this)->in_buf = NULL ;
+
+ }
+
+ g_free (PRIVATE (a_this)) ;
+ PRIVATE (a_this) = NULL ;
+ }
+
+ g_free (a_this) ;
+}
+
+
+/**
+ *Increments the reference count of the current
+ *instance of #CRInput.
+ *@param a_this the current instance of #CRInput.
+ */
+void
+cr_input_ref (CRInput *a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)) ;
+
+ PRIVATE (a_this)->ref_count ++ ;
+}
+
+
+/**
+ *Decrements the reference count of this instance
+ *of #CRInput. If the reference count goes down to
+ *zero, this instance is destroyed.
+ *@param a_this the current instance of #CRInput.
+ *
+ */
+void
+cr_input_unref (CRInput *a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)) ;
+
+ if (PRIVATE (a_this)->ref_count)
+ {
+ PRIVATE (a_this)->ref_count -- ;
+ }
+
+ if (PRIVATE (a_this)->ref_count == 0)
+ {
+ cr_input_destroy (a_this) ;
+ }
+}
+
+
+/**
+ *Tests wether the current instance of
+ *#CRInput has reached it's input buffer.
+ *@param a_this the current instance of #CRInput.
+ *@param a_end_of_input out parameter. Is set to TRUE if
+ *the current instance has reached the end of its input buffer,
+ *FALSE otherwise.
+ *@param CR_OK upon successfull completion, an error code otherwise.
+ *Note that all the out parameters of this method are valid if
+ *and only if this method returns CR_OK.
+ */
+enum CRStatus
+cr_input_end_of_input (CRInput *a_this, gboolean *a_end_of_input)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_end_of_input, CR_BAD_PARAM_ERROR) ;
+
+ *a_end_of_input = (PRIVATE (a_this)->next_byte_index
+ >= PRIVATE (a_this)->in_buf_size)? TRUE : FALSE ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Retunrs the number of bytes left in the input stream
+ *before the end.
+ *@param a_this the current instance of #CRInput.
+ *@return the number of characters left or -1 in case of error.
+ */
+glong
+cr_input_get_nb_bytes_left (CRInput *a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), -1) ;
+ g_return_val_if_fail (PRIVATE (a_this)->nb_bytes
+ >= PRIVATE (a_this)->in_buf_size, -1) ;
+ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index
+ <= PRIVATE (a_this)->nb_bytes, -1) ;
+
+ if (PRIVATE (a_this)->end_of_input)
+ return 0 ;
+
+ return PRIVATE (a_this)->nb_bytes
+ - PRIVATE (a_this)->next_byte_index ;
+}
+
+
+/**
+ *Returns the next byte of the input.
+ *Update the state of the input so that
+ *the next invocation of this method returns
+ *the next coming byte.
+ *
+ *@param a_this the current instance of #CRInput.
+ *@param a_byte out parameter the returned byte.
+ *@return CR_OK upon sucessfull completion, an error code
+ *otherwise. All the out param of this method are valid if
+ *and only if this method returns CR_OK.
+ */
+enum CRStatus
+cr_input_read_byte (CRInput *a_this, guchar *a_byte)
+{
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this)
+ && a_byte,
+ CR_BAD_PARAM_ERROR) ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index >= 0
+ && PRIVATE (a_this)->nb_bytes >= 0,
+ CR_BAD_PARAM_ERROR) ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <=
+ PRIVATE (a_this)->nb_bytes,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->end_of_input == TRUE)
+ return CR_END_OF_INPUT_ERROR ;
+
+ *a_byte =
+ PRIVATE
+ (a_this)->in_buf[PRIVATE (a_this)->next_byte_index] ;
+
+ if (PRIVATE (a_this)->nb_bytes -
+ PRIVATE (a_this)->next_byte_index < 2)
+ {
+ PRIVATE (a_this)->end_of_input = TRUE ;
+ }
+ else
+ {
+ PRIVATE (a_this)->next_byte_index ++ ;
+ }
+
+ return CR_OK ;
+}
+
+
+/**
+ *Reads an unicode character from the current instance of
+ *#CRInput.
+ *@param a_this the current instance of CRInput.
+ *@param a_char out parameter. The read character.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_read_char (CRInput *a_this, guint32 *a_char)
+{
+ enum CRStatus status = CR_OK ;
+ gulong consumed = 0, nb_bytes_left = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->end_of_input == TRUE)
+ return CR_END_OF_INPUT_ERROR ;
+
+ nb_bytes_left = cr_input_get_nb_bytes_left (a_this) ;
+
+ if (nb_bytes_left < 1)
+ {
+ return CR_END_OF_INPUT_ERROR ;
+ }
+
+ status =
+ cr_utils_read_char_from_utf8_buf
+ (PRIVATE (a_this)->in_buf
+ +
+ PRIVATE (a_this)->next_byte_index,
+ nb_bytes_left, a_char, &consumed) ;
+
+ if (status == CR_OK)
+ {
+ /*update next byte index*/
+ PRIVATE (a_this)->next_byte_index += consumed ;
+
+ /*upate line and column number*/
+ if (PRIVATE (a_this)->end_of_line == TRUE)
+ {
+ PRIVATE (a_this)->col = 1 ;
+ PRIVATE (a_this)->line ++ ;
+ PRIVATE (a_this)->end_of_line = FALSE ;
+ }
+ else if (*a_char != '\n')
+ {
+ PRIVATE (a_this)->col ++ ;
+ }
+
+ if (*a_char == '\n')
+ {
+ PRIVATE (a_this)->end_of_line = TRUE ;
+ }
+
+ }
+
+ return status ;
+}
+
+
+/**
+ *Setter of the current line number.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput.
+ *@param a_line_num the new line number.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_line_num (CRInput *a_this, glong a_line_num)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->line = a_line_num ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Getter of the curren line number.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput.
+ *@param a_line_num the returned line number.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_line_num (CRInput *a_this, glong *a_line_num)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_line_num,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_line_num = PRIVATE (a_this)->line ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Setter of the current column number.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput.
+ *@param a_col the new column column number.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_column_num (CRInput *a_this, glong a_col)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->col = a_col ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Getter of the current column number.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput.
+ *@param a_col out parameter
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_column_num (CRInput *a_this, glong *a_col)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_col = PRIVATE (a_this)->col ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Increments the current line number.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_increment_line_num (CRInput *a_this, glong a_increment)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->line += a_increment ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Increments the current column number.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_increment_col_num (CRInput *a_this, glong a_increment)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->col += a_increment ;
+
+ return CR_OK ;
+}
+
+
+
+/**
+ *Consumes the next character of the input stream if
+ *and only if that character equals a_char.
+ *
+ *@param a_this the this pointer.
+ *@param a_char the character to consume. If set to zero,
+ *consumes any character.
+ *@return CR_OK upon successfull completion, CR_PARSING_ERROR if
+ *next char is different from a_char, an other error code otherwise
+ */
+enum CRStatus
+cr_input_consume_char (CRInput *a_this, guint32 a_char)
+{
+ guint32 c ;
+ enum CRStatus status ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if ((status = cr_input_peek_char (a_this, &c)) != CR_OK)
+ {
+ return status ;
+ }
+
+ if (c == a_char || a_char == 0)
+ {
+ status = cr_input_read_char (a_this, &c) ;
+ }
+ else
+ {
+ return CR_PARSING_ERROR ;
+ }
+
+ return status ;
+}
+
+
+/**
+ *Consumes up to a_nb_char occurences of the next contiguous characters
+ *which equal a_char. Note that the next character of the input stream
+ **MUST* equal a_char to trigger the consumption, or else, the error
+ *code CR_PARSING_ERROR is returned.
+ *If the number of contiguous characters that equals a_char is less than
+ *a_nb_char, then this function consumes all the characters it can consumed.
+ *
+ *@param a_this the this pointer of the current instance of #CRInput.
+ *@param a_char the character to consume.
+ *@param a_nb_char in/out parameter. The number of characters to consume.
+ *If set to a negative value, the function will consume all the occurences
+ *of a_char found.
+ *After return, if the return value equals CR_OK, this variable contains
+ *the number of characters actually consumed.
+ *@return CR_OK if at least one character has been consumed, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_consume_chars (CRInput *a_this, guint32 a_char, glong *a_nb_char)
+{
+ enum CRStatus status = CR_OK ;
+ gulong nb_consumed = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ g_return_val_if_fail (a_char != 0 || a_nb_char >=0,
+ CR_BAD_PARAM_ERROR) ;
+
+ for (nb_consumed = 0 ;
+ (status == CR_OK)
+ && ((*a_nb_char > 0 && nb_consumed < *a_nb_char)
+ || (*a_nb_char < 0)) ;
+ nb_consumed ++)
+ {
+ status = cr_input_consume_char (a_this, a_char) ;
+ }
+
+ *a_nb_char = nb_consumed ;
+
+ if ((nb_consumed > 0)
+ && ((status == CR_PARSING_ERROR)
+ || (status == CR_END_OF_INPUT_ERROR)))
+ {
+ status = CR_OK ;
+ }
+
+ return status ;
+}
+
+/**
+ *Same as cr_input_consume_chars() but this one consumes white
+ *spaces.
+ *
+ *@param a_this the "this pointer" of the current instance of #CRInput.
+ *@param a_nb_chars in/out parameter. The number of white spaces to
+ *consume. After return, holds the number of white spaces actually consumed.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_consume_white_spaces (CRInput *a_this, glong *a_nb_chars)
+{
+ enum CRStatus status = CR_OK ;
+ guint32 cur_char = 0, nb_consumed = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars,
+ CR_BAD_PARAM_ERROR) ;
+
+ for (nb_consumed = 0;
+ ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars))
+ || (*a_nb_chars < 0) ;
+ nb_consumed ++)
+ {
+ status = cr_input_peek_char (a_this, &cur_char) ;
+ if (status != CR_OK) break ;
+
+ /*if the next char is a white space, consume it !*/
+ if (cr_utils_is_white_space (cur_char) == TRUE)
+ {
+ status = cr_input_read_char (a_this, &cur_char) ;
+ if (status != CR_OK) break ;
+ continue ;
+ }
+
+ break ;
+
+ }
+
+ if (nb_consumed && status == CR_END_OF_INPUT_ERROR)
+ {
+ status = CR_OK ;
+ }
+
+ return status ;
+}
+
+
+/**
+ *Same as cr_input_read_char() but does not update the
+ *internal state of the input stream. The next call
+ *to cr_input_peek_char() or cr_input_read_char() will thus
+ *return the same character as the current one.
+ *@param a_this the current instance of #CRInput.
+ *@param a_char out parameter. The returned character.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_peek_char (CRInput *a_this, guint32 *a_char)
+{
+ enum CRStatus status = CR_OK ;
+ glong consumed = 0, nb_bytes_left = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_char, CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->next_byte_index >=
+ PRIVATE (a_this)->in_buf_size)
+ {
+ return CR_END_OF_INPUT_ERROR ;
+ }
+
+ nb_bytes_left = cr_input_get_nb_bytes_left (a_this) ;
+
+ if (nb_bytes_left < 1)
+ {
+ return CR_END_OF_INPUT_ERROR ;
+ }
+
+ status =
+ cr_utils_read_char_from_utf8_buf
+ (PRIVATE (a_this)->in_buf + PRIVATE (a_this)->next_byte_index,
+ nb_bytes_left, a_char, &consumed) ;
+
+ return status ;
+}
+
+
+/**
+ *Gets a byte from the input stream.
+ *starting from the current position in the input stream.
+ *Unlike cr_input_peek_next_byte() this method
+ *does not update the state of the current input stream.
+ *Subsequent calls to cr_input_peek_byte with the same arguments
+ *will return the same byte.
+ *
+ *@param a_this the current instance of #CRInput.
+ *@param a_origin the origin to consider in the calculation
+ *of the position of the byte to peek.
+ *@param a_offset the offset of the byte to peek, starting from
+ *the origin specified by a_origin.
+ *@param a_byte out parameter the peeked byte.
+ *@return CR_OK upon successfull completion or,
+ *
+ *<ul>
+ *<li>CR_BAD_PARAM_ERROR if at least of of the parameters is invalid</li>
+ *<li>CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds</li>
+ *</ul>
+ */
+enum CRStatus
+cr_input_peek_byte (CRInput *a_this, enum CRSeekPos a_origin,
+ gulong a_offset, guchar *a_byte)
+{
+ gulong abs_offset = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_byte,
+ CR_BAD_PARAM_ERROR) ;
+
+
+ switch (a_origin) {
+
+ case CR_SEEK_CUR:
+ abs_offset =
+ PRIVATE (a_this)->next_byte_index - 1 + a_offset ;
+ break ;
+
+ case CR_SEEK_BEGIN:
+ abs_offset = a_offset ;
+ break ;
+
+ case CR_SEEK_END:
+ abs_offset =
+ PRIVATE (a_this)->in_buf_size - 1 - a_offset ;
+ break;
+
+ default:
+ return CR_BAD_PARAM_ERROR ;
+ }
+
+ if (abs_offset < PRIVATE (a_this)->in_buf_size) {
+
+ *a_byte =
+ PRIVATE (a_this)->in_buf[abs_offset] ;
+
+ return CR_OK ;
+
+ } else {
+ return CR_END_OF_INPUT_ERROR ;
+ }
+}
+
+/**
+ *Returns the memory address of the byte located at a given offset
+ *in the input stream.
+ *@param a_this the current instance of #CRInput.
+ *@param a_offset the offset of the byte in the input stream starting
+ *from the begining of the stream.
+ *@return the address, otherwise NULL if an error occured.
+ */
+guchar *
+cr_input_get_byte_addr (CRInput *a_this,
+ gulong a_offset)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL) ;
+
+ if (a_offset >= PRIVATE (a_this)->nb_bytes)
+ {
+ return NULL ;
+ }
+
+ return &PRIVATE (a_this)->in_buf[a_offset] ;
+}
+
+/**
+ *Sets the "current byte index" of the current instance
+ *of #CRInput. Next call to cr_input_get_byte() will return
+ *the byte next after the new "current byte index".
+ *
+ *@param a_this the current instance of #CRInput.
+ *
+ *@param a_origin the origin to consider during the calculation
+ *of the absolute position of the new "current byte index".
+ *
+ *@param a_pos the relative offset of the new "current byte index."
+ *This offset is relative to the origin a_origin.
+ *
+ *@return CR_OK upon successfull completion otherwise returns
+ *<ul>
+ *<li>CR_BAD_PARAM_ERROR if at least one of the parameters is not valid</li>
+ *<li>CR_OUT_BOUNDS_ERROR</li>
+ *</ul>
+ */
+enum CRStatus
+cr_input_seek_index (CRInput *a_this, enum CRSeekPos a_origin, gint a_pos)
+{
+
+ glong abs_offset = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR) ;
+
+
+ switch (a_origin) {
+
+ case CR_SEEK_CUR:
+ abs_offset =
+ PRIVATE (a_this)->next_byte_index - 1 + a_pos ;
+ break ;
+
+ case CR_SEEK_BEGIN:
+ abs_offset = a_pos ;
+ break ;
+
+ case CR_SEEK_END:
+ abs_offset =
+ PRIVATE (a_this)->in_buf_size - 1 - a_pos ;
+ break ;
+
+ default:
+ return CR_BAD_PARAM_ERROR ;
+ }
+
+ if (abs_offset < PRIVATE (a_this)->nb_bytes) {
+
+ /*update the input stream's internal state*/
+ PRIVATE (a_this)->next_byte_index = abs_offset + 1 ;
+
+ return CR_OK ;
+ }
+
+ return CR_OUT_OF_BOUNDS_ERROR ;
+}
+
+
+/**
+ *Gets the position of the "current byte index" which
+ *is basically the position of the last returned byte in the
+ *input stream.
+ *
+ *@param a_this the current instance of #CRInput.
+ *
+ *@param a_pos out parameter. The returned position.
+ *
+ *@return CR_OK upon sucessfull completion. Otherwise,
+ *<ul>
+ *<li>CR_BAD_PARAMETER_ERROR if at least of the arguments is invalid.</li>
+ *<li>CR_START_OF_INPUT if no call to neither cr_input_read_byte()
+ *not cr_input_seek_index() have been issued before calling
+ *cr_input_get_cur_pos()</li>
+ *</ul>
+ *Note that the out parameters of this function are valid if and only if this
+ *function returns CR_OK.
+ */
+enum CRStatus
+cr_input_get_cur_pos (CRInput *a_this, CRInputPos * a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->next_byte_index < 0)
+ return CR_START_OF_INPUT_ERROR ;
+
+ a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index ;
+ a_pos->line = PRIVATE (a_this)->line ;
+ a_pos->col = PRIVATE (a_this)->col ;
+ a_pos->end_of_line = PRIVATE (a_this)->end_of_line ;
+ a_pos->end_of_file = PRIVATE (a_this)->end_of_input ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Getter of the next byte index.
+ *It actually returns the index of the
+ *next byte to be read.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput
+ *@param a_index out parameter. The returned index.
+ *@return CR_OK upon sucessfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_get_cur_index (CRInput *a_this, glong *a_index)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_index,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_index = PRIVATE (a_this)->next_byte_index ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Setter of the next byte index.
+ *It sets the index of the next byte to be read.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRInput .
+ *@param a_index the new index to set.
+ *@return CR_OK upon sucessfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_cur_index (CRInput *a_this, glong a_index)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->next_byte_index = a_index ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the end of file flag.
+ *@param a_this the current instance of #CRInput.
+ *@param a_eof the new end of file flag.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_end_of_file (CRInput *a_this, gboolean a_eof)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->end_of_input = a_eof ;
+
+ return CR_OK ;
+}
+
+/**
+ *Gets the end of file flag.
+ *@param a_this the current instance of #CRInput.
+ *@param a_eof out parameter the place where to put the end of
+ *file flag.
+ *@return CR_OK upon sucessfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_end_of_file (CRInput *a_this, gboolean *a_eof)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_eof,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_eof = PRIVATE (a_this)->end_of_input ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the end of line flag.
+ *@param a_this the current instance of #CRInput.
+ *@param a_eol the new end of line flag.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_set_end_of_line (CRInput *a_this, gboolean a_eol)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->end_of_line = a_eol ;
+
+ return CR_OK ;
+}
+
+/**
+ *Gets the end of line flag of the current input.
+ *@param a_this the current instance of #CRInput
+ *@param a_eol out parameter. The place where to put
+ *the returned flag
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_get_end_of_line (CRInput *a_this, gboolean *a_eol)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_eol,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_eol = PRIVATE (a_this)->end_of_line ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the current position in the input stream.
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRInput.
+ *@param a_pos the new position.
+ */
+enum CRStatus
+cr_input_set_cur_pos (CRInput *a_this, CRInputPos *a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_input_set_column_num (a_this, a_pos->col) ;
+ cr_input_set_line_num (a_this, a_pos->line) ;
+ cr_input_set_cur_index (a_this, a_pos->next_byte_index) ;
+ cr_input_set_end_of_line (a_this, a_pos->end_of_line) ;
+ cr_input_set_end_of_file (a_this, a_pos->end_of_file) ;
+
+ return CR_OK ;
+}
diff --git a/src/cr-input.h b/src/cr-input.h
new file mode 100644
index 0000000..b908aee
--- /dev/null
+++ b/src/cr-input.h
@@ -0,0 +1,163 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_INPUT_SRC_H__
+#define __CR_INPUT_SRC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus*/
+
+#include <glib.h>
+#include "cr-utils.h"
+
+/**
+ *@file
+ *The libcroco basic input source
+ *declaration file.
+ */
+
+ typedef struct _CRInput CRInput ;
+ typedef struct _CRInputPriv CRInputPriv ;
+
+ struct _CRInput
+ {
+ CRInputPriv *priv ;
+ } ;
+
+ typedef struct _CRInputPos CRInputPos ;
+
+ struct _CRInputPos
+ {
+ glong line ;
+ glong col ;
+ gboolean end_of_file ;
+ gboolean end_of_line ;
+ glong next_byte_index ;
+ } ;
+
+
+ CRInput *
+ cr_input_new_from_uri (gchar *a_file_uri, enum CREncoding a_enc) ;
+
+ void
+ cr_input_destroy (CRInput *a_this) ;
+
+ void
+ cr_input_ref (CRInput *a_this) ;
+
+ void
+ cr_input_unref (CRInput *a_this) ;
+
+ enum CRStatus
+ cr_input_read_byte (CRInput *a_this, guchar *a_byte) ;
+
+ enum CRStatus
+ cr_input_read_char (CRInput *a_this, guint32 *a_char) ;
+
+ enum CRStatus
+ cr_input_consume_chars (CRInput *a_this, guint32 a_char,
+ glong *a_nb_char) ;
+
+ enum CRStatus
+ cr_input_consume_char (CRInput *a_this, guint32 a_char) ;
+
+ enum CRStatus
+ cr_input_consume_white_spaces (CRInput *a_this, glong *a_nb_chars) ;
+
+ enum CRStatus
+ cr_input_peek_byte (CRInput *a_this, enum CRSeekPos a_origin,
+ gulong a_offset, guchar *a_byte) ;
+
+ enum CRStatus
+ cr_input_peek_char (CRInput *a_this, guint32 *a_char) ;
+
+ guchar *
+ cr_input_get_byte_addr (CRInput *a_this,
+ gulong a_offset) ;
+
+ enum CRStatus
+ cr_input_seek_index (CRInput *a_this,
+ enum CRSeekPos a_origin, gint a_pos) ;
+
+ enum CRStatus
+ cr_input_get_cur_index (CRInput *a_this, glong *a_index) ;
+
+ enum CRStatus
+ cr_input_set_cur_index (CRInput *a_this, glong a_index) ;
+
+ enum CRStatus
+ cr_input_get_cur_pos (CRInput *a_this, CRInputPos * a_pos) ;
+
+ enum CRStatus
+ cr_input_set_cur_pos (CRInput *a_this, CRInputPos *a_pos) ;
+
+ enum CRStatus
+ cr_input_get_end_of_line (CRInput *a_this, gboolean *a_eol) ;
+
+ enum CRStatus
+ cr_input_set_end_of_line (CRInput *a_this, gboolean a_eol) ;
+
+ enum CRStatus
+ cr_input_get_end_of_file (CRInput *a_this, gboolean *a_eof) ;
+
+ enum CRStatus
+ cr_input_set_end_of_file (CRInput *a_this, gboolean a_eof) ;
+
+ enum CRStatus
+ cr_input_set_line_num (CRInput *a_this, glong a_line_num) ;
+
+ enum CRStatus
+ cr_input_get_line_num (CRInput *a_this, glong *a_line_num) ;
+
+ enum CRStatus
+ cr_input_set_column_num (CRInput *a_this, glong a_col) ;
+
+ enum CRStatus
+ cr_input_get_column_num (CRInput *a_this, glong *a_col) ;
+
+ enum CRStatus
+ cr_input_increment_line_num (CRInput *a_this,
+ glong a_increment) ;
+
+ enum CRStatus
+ cr_input_increment_col_num (CRInput *a_this,
+ glong a_increment) ;
+
+ glong
+ cr_input_get_nb_bytes_left (CRInput *a_this) ;
+
+#ifdef __cplusplus
+} /*extern C*/
+
+#endif /*__cplusplus*/
+#endif /*__CR_INPUT_SRC_H__*/
+
diff --git a/src/cr-num.c b/src/cr-num.c
new file mode 100644
index 0000000..a15a67b
--- /dev/null
+++ b/src/cr-num.c
@@ -0,0 +1,150 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition
+ *of the #CRNum class.
+ */
+
+#include "cr-num.h"
+#include "string.h"
+
+
+/**
+ *The default constructor of
+ *#CRNum.
+ *@return the newly built instance of
+ *#CRNum.
+ */
+CRNum *
+cr_num_new (void)
+{
+ CRNum * result = NULL ;
+
+ result = g_try_malloc (sizeof (CRNum)) ;
+
+ if (result == NULL)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRNum)) ;
+
+ return result ;
+}
+
+
+/**
+ *A constructor of #CRNum.
+ *@param a_is_natural whether if the intance of #CRNum is
+ *a natural number or not.
+ *@param a_integer_part the integer part of the instance
+ *of #CRNum
+ *@param a_decimal_part in case the instance of #CRNum
+ *natural number (but a decimal one) this parameter
+ *is the decimal part of the instance of #CRNum.
+ *@return the newly built instance of #CRNum or
+ *NULL if an error arises.
+ */
+CRNum *
+cr_num_new_with_vals (gboolean a_is_natural,
+ glong a_integer_part,
+ glong a_decimal_part)
+{
+ CRNum * result = NULL ;
+
+ result = cr_num_new () ;
+
+ g_return_val_if_fail (result, NULL) ;
+
+ result->is_natural = a_is_natural ;
+ result->int_part = a_integer_part ;
+
+ if (a_is_natural == FALSE)
+ {
+ result->dec_part = a_decimal_part ;
+ }
+
+ return result ;
+}
+
+/**
+ *Returns the string representation of the
+ *current instance of #CRNum.
+ *@param a_this the current instance of #CRNum.
+ *@return the newly built string representation
+ *of the current instance of #CRNum. The returned
+ *string is NULL terminated. The caller *must*
+ *free the returned string.
+ */
+guchar *
+cr_num_to_string (CRNum *a_this)
+{
+ guchar *tmp_char1 = NULL, *tmp_char2 = NULL, *result = NULL ;
+
+ g_return_val_if_fail (a_this, NULL) ;
+
+ tmp_char1 = g_strdup_printf ("%ld", a_this->int_part) ;
+
+ g_return_val_if_fail (tmp_char1, NULL) ;
+
+ if (a_this->is_natural == FALSE)
+ {
+ tmp_char2 = g_strdup_printf (".%ld", a_this->dec_part) ;
+ }
+
+ if (tmp_char2)
+ {
+ result = g_strconcat (tmp_char1, tmp_char2, NULL) ;
+ g_free (tmp_char1) ;
+ g_free (tmp_char2) ;
+ }
+ else
+ {
+ result = tmp_char1 ;
+ }
+
+ return result ;
+}
+
+/**
+ *The destructor of #CRNum.
+ *@param a_this the this pointer of
+ *the current instance of #CRNum.
+ */
+void
+cr_num_destroy (CRNum *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ g_free (a_this) ;
+}
diff --git a/src/cr-num.h b/src/cr-num.h
new file mode 100644
index 0000000..5650d0c
--- /dev/null
+++ b/src/cr-num.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+
+/**
+ *@file
+ *The declaration
+ *of the #CRNum class.
+ */
+
+#ifndef __CR_NUM_H__
+#define __CR_NUM_H__
+
+#include <glib.h>
+#include "cr-utils.h"
+
+#ifdef __cpluplus
+extern "C"
+{
+#endif
+
+ typedef struct _CRNum CRNum ;
+
+ /**
+ *An abstraction of a number (num)
+ *as defined in the css2 spec.
+ */
+ struct _CRNum
+ {
+ gboolean is_natural ;
+
+ /**
+ *integer part of the number
+ */
+ glong int_part ;
+
+ /**
+ *decimal part of the number.
+ */
+ glong dec_part ;
+ } ;
+
+ CRNum *
+ cr_num_new (void) ;
+
+ CRNum *
+ cr_num_new_with_vals (gboolean a_is_natural,
+ glong a_integer_part,
+ glong a_decimal_part) ;
+
+ guchar *
+ cr_num_to_string (CRNum *a_this) ;
+
+ void
+ cr_num_destroy (CRNum *a_this) ;
+
+#ifdef __cpluplus
+} /*extern "C"*/
+#endif
+
+#endif /*__CR_NUM_H__*/
diff --git a/src/cr-om-parser.c b/src/cr-om-parser.c
new file mode 100644
index 0000000..63232cc
--- /dev/null
+++ b/src/cr-om-parser.c
@@ -0,0 +1,891 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <string.h>
+#include "cr-utils.h"
+#include "cr-om-parser.h"
+
+/**
+ *@file
+ *The definition of the CSS Object Model Parser.
+ *This parser uses (and sits) the SAC api of libcroco defined
+ *in cr-parser.h and cr-doc-handler.h
+ */
+
+struct _CROMParserPriv
+{
+ CRParser *parser ;
+} ;
+
+#define PRIVATE(a_this) ((a_this)->priv)
+
+/*
+ *Forward declaration of a type defined later
+ *in this file.
+ */
+struct _ParsingContext ;
+typedef struct _ParsingContext ParsingContext ;
+
+static ParsingContext *
+new_parsing_context (void) ;
+
+static void
+destroy_context (ParsingContext *a_ctxt) ;
+
+static void
+unrecoverable_error (CRDocHandler *a_this) ;
+
+static void
+error (CRDocHandler *a_this) ;
+
+static void
+property (CRDocHandler *a_this,
+ GString *a_name,
+ CRTerm *a_expression) ;
+
+static void
+end_selector (CRDocHandler *a_this,
+ CRSelector *a_selector_list) ;
+
+static void
+start_selector (CRDocHandler *a_this,
+ CRSelector *a_selector_list) ;
+
+static void
+start_font_face (CRDocHandler *a_this) ;
+
+static void
+end_font_face (CRDocHandler *a_this) ;
+
+static void
+end_document (CRDocHandler *a_this) ;
+
+static void
+start_document (CRDocHandler *a_this) ;
+
+static void
+charset (CRDocHandler *a_this, GString *a_charset) ;
+
+static void
+start_page (CRDocHandler *a_this, GString *a_page,
+ GString *a_pseudo_page) ;
+
+static void
+end_page (CRDocHandler *a_this, GString *a_page,
+ GString *a_pseudo_page) ;
+
+static void
+start_media (CRDocHandler *a_this, GList *a_media_list) ;
+
+static void
+end_media (CRDocHandler *a_this, GList *a_media_list) ;
+
+static void
+import_style (CRDocHandler *a_this, GList *a_media_list,
+ GString *a_uri, GString *a_uri_default_ns) ;
+
+
+struct _ParsingContext
+{
+ CRStyleSheet *stylesheet ;
+ CRStatement *cur_stmt ;
+ CRStatement *cur_media_stmt ;
+} ;
+
+
+/********************************************
+ *Private methods
+ ********************************************/
+
+static ParsingContext *
+new_parsing_context (void)
+{
+ ParsingContext *result = NULL ;
+
+ result = g_try_malloc (sizeof (ParsingContext)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of Memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (ParsingContext)) ;
+ return result ;
+}
+
+static void
+destroy_context (ParsingContext *a_ctxt)
+{
+ g_return_if_fail (a_ctxt) ;
+
+ if (a_ctxt->stylesheet)
+ {
+ cr_stylesheet_destroy (a_ctxt->stylesheet) ;
+ a_ctxt->stylesheet = NULL ;
+ }
+ if (a_ctxt->cur_stmt)
+ {
+ cr_statement_destroy (a_ctxt->cur_stmt) ;
+ a_ctxt->cur_stmt = NULL ;
+ }
+ g_free (a_ctxt) ;
+}
+
+
+static enum CRStatus
+cr_om_parser_init_default_sac_handler (CROMParser *a_this)
+{
+ CRDocHandler *sac_handler = NULL ;
+ gboolean free_hdlr_if_error = FALSE ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->parser,
+ CR_BAD_PARAM_ERROR) ;
+
+ status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+ &sac_handler) ;
+ g_return_val_if_fail (status == CR_OK, status) ;
+
+ if (!sac_handler)
+ {
+ sac_handler = cr_doc_handler_new ();
+ free_hdlr_if_error = TRUE ;
+ }
+
+ /*
+ *initialyze here the sac handler.
+ */
+ sac_handler->start_document = start_document ;
+ sac_handler->end_document = end_document ;
+ sac_handler->start_selector = start_selector ;
+ sac_handler->end_selector = end_selector;
+ sac_handler->property = property ;
+ sac_handler->start_font_face = start_font_face ;
+ sac_handler->end_font_face = end_font_face ;
+ sac_handler->error = error ;
+ sac_handler->unrecoverable_error = unrecoverable_error ;
+ sac_handler->charset = charset ;
+ sac_handler->start_page = start_page ;
+ sac_handler->end_page = end_page ;
+ sac_handler->start_media = start_media ;
+ sac_handler->end_media = end_media ;
+ sac_handler->import_style = import_style ;
+
+ status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser,
+ sac_handler) ;
+ if (status == CR_OK)
+ {
+ return CR_OK;
+ }
+
+ if (sac_handler && free_hdlr_if_error == TRUE)
+ {
+ cr_doc_handler_destroy (sac_handler) ;
+ sac_handler = NULL ;
+ }
+
+ return status ;
+
+}
+
+static void
+start_document (CRDocHandler *a_this)
+{
+ ParsingContext *ctxt = NULL ;
+ CRStyleSheet * stylesheet = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ ctxt = new_parsing_context () ;
+ g_return_if_fail (ctxt) ;
+
+ stylesheet = cr_stylesheet_new (NULL) ;
+ ctxt->stylesheet = stylesheet ;
+ a_this->context = ctxt ;
+}
+
+static void
+start_font_face (CRDocHandler *a_this)
+{
+ ParsingContext *ctxt = NULL ;
+ g_return_if_fail (a_this) ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+ ctxt = a_this->context ;
+ g_return_if_fail (ctxt->cur_stmt == NULL) ;
+
+ ctxt->cur_stmt = cr_statement_new_at_font_face_rule (NULL) ;
+ g_return_if_fail (ctxt->cur_stmt) ;
+}
+
+static void
+end_font_face (CRDocHandler *a_this)
+{
+ ParsingContext *ctxt = NULL ;
+ CRStatement *stmts = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+ ctxt = a_this->context ;
+ g_return_if_fail
+ (ctxt->cur_stmt
+ && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
+ && ctxt->stylesheet) ;
+
+ stmts = cr_statement_append (ctxt->stylesheet->statements,
+ ctxt->cur_stmt) ;
+ if (!stmts)
+ goto error ;
+
+ ctxt->stylesheet->statements = stmts ;
+ stmts = NULL ;
+ ctxt->cur_stmt = NULL ;
+
+ return ;
+
+ error:
+
+ if (ctxt->cur_stmt)
+ {
+ cr_statement_destroy (ctxt->cur_stmt) ;
+ ctxt->cur_stmt = NULL ;
+ }
+
+ if (!stmts)
+ {
+ cr_statement_destroy (stmts) ;
+ stmts = NULL;
+ }
+}
+
+
+static void
+end_document (CRDocHandler *a_this)
+{
+ ParsingContext *ctxt = NULL ;
+ g_return_if_fail (a_this) ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+ ctxt = a_this->context ;
+
+ if (!ctxt->stylesheet || ctxt->cur_stmt)
+ goto error ;
+
+ a_this->result = ctxt->stylesheet ;
+ ctxt->stylesheet = NULL ;
+
+ destroy_context (ctxt) ;
+
+ a_this->context = NULL ;
+ return ;
+
+ error:
+ if (ctxt)
+ {
+ destroy_context (ctxt) ;
+ }
+}
+
+static void
+charset (CRDocHandler *a_this, GString *a_charset)
+{
+ CRStatement *stmt = NULL, *stmt2 = NULL ;
+ GString * charset = NULL ;
+
+ ParsingContext *ctxt = NULL ;
+ g_return_if_fail (a_this && a_this->context) ;
+
+ ctxt = a_this->context ;
+ g_return_if_fail (ctxt->stylesheet) ;
+
+ charset = g_string_new_len (a_charset->str,
+ a_charset->len) ;
+
+ stmt = cr_statement_new_at_charset_rule (charset) ;
+ g_return_if_fail (stmt) ;
+
+ stmt2 = cr_statement_append (ctxt->stylesheet->statements,
+ stmt) ;
+ if (!stmt2)
+ {
+ if (stmt)
+ {
+ cr_statement_destroy (stmt) ;
+ stmt = NULL ;
+ }
+
+ if (charset)
+ {
+ g_string_free (charset, TRUE) ;
+ }
+ return ;
+ }
+
+ ctxt->stylesheet->statements = stmt2 ;
+ stmt2 = NULL ;
+}
+
+static void
+start_page (CRDocHandler *a_this, GString *a_page,
+ GString *a_pseudo)
+{
+ ParsingContext *ctxt = NULL ;
+ g_return_if_fail (a_this && a_this->context) ;
+
+ ctxt = a_this->context ;
+ g_return_if_fail (ctxt->cur_stmt == NULL) ;
+
+ ctxt->cur_stmt = cr_statement_new_at_page_rule (NULL, NULL, NULL) ;
+
+ if (a_page)
+ {
+ ctxt->cur_stmt->kind.page_rule->name =
+ g_string_new_len (a_page->str, a_page->len) ;
+
+ if (!ctxt->cur_stmt->kind.page_rule->name)
+ {
+ goto error ;
+ }
+ }
+
+ if (a_pseudo)
+ {
+ ctxt->cur_stmt->kind.page_rule->pseudo =
+ g_string_new_len (a_pseudo->str, a_pseudo->len) ;
+
+ if (!ctxt->cur_stmt->kind.page_rule->pseudo)
+ {
+ goto error ;
+ }
+ }
+
+ return ;
+
+ error:
+ if (ctxt->cur_stmt)
+ {
+ cr_statement_destroy (ctxt->cur_stmt) ;
+ ctxt->cur_stmt = NULL ;
+ }
+}
+
+
+static void
+end_page (CRDocHandler *a_this, GString *a_page,
+ GString *a_pseudo_page)
+{
+ ParsingContext *ctxt = NULL ;
+ CRStatement *stmt = NULL ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+
+ ctxt = a_this->context ;
+ g_return_if_fail (ctxt->cur_stmt
+ && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
+ && ctxt->stylesheet) ;
+
+ stmt = cr_statement_append (ctxt->stylesheet->statements,
+ ctxt->cur_stmt) ;
+
+ if (stmt)
+ {
+ ctxt->stylesheet->statements = stmt ;
+ stmt = NULL ;
+ ctxt->cur_stmt = NULL ;
+ }
+
+ if (ctxt->cur_stmt)
+ {
+ cr_statement_destroy (ctxt->cur_stmt) ;
+ ctxt->cur_stmt = NULL ;
+ }
+}
+
+static void
+start_media (CRDocHandler *a_this, GList *a_media_list)
+{
+ ParsingContext *ctxt = NULL ;
+ GList * media_list = NULL ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+ ctxt = a_this->context ;
+
+ g_return_if_fail (ctxt
+ && ctxt->cur_stmt == NULL
+ && ctxt->cur_media_stmt == NULL
+ && ctxt->stylesheet) ;
+
+ if (a_media_list)
+ {
+ GList *cur = NULL ;
+
+ /*duplicate the media_list*/
+ for (cur = a_media_list; cur ; cur = cur->next)
+ {
+ GString *str = NULL ;
+
+ str = g_string_new_len (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+ if (str)
+ media_list = g_list_append (media_list,
+ str) ;
+ }
+ }
+
+ ctxt->cur_media_stmt =
+ cr_statement_new_at_media_rule (NULL, media_list) ;
+
+}
+
+static void
+end_media (CRDocHandler *a_this, GList *a_media_list)
+{
+ ParsingContext *ctxt = NULL ;
+ CRStatement * stmts = NULL ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+ ctxt = a_this->context ;
+
+ g_return_if_fail (ctxt
+ && ctxt->cur_media_stmt
+ && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
+ && ctxt->stylesheet) ;
+
+ stmts = cr_statement_append (ctxt->stylesheet->statements,
+ ctxt->cur_media_stmt) ;
+ if (!stmts)
+ {
+ cr_statement_destroy (ctxt->cur_media_stmt) ;
+ ctxt->cur_media_stmt = NULL ;
+ }
+
+ ctxt->stylesheet->statements = stmts ;
+ stmts = NULL ;
+
+}
+
+
+static void
+import_style (CRDocHandler *a_this, GList *a_media_list,
+ GString *a_uri, GString *a_uri_default_ns)
+{
+ GString *uri = NULL ;
+ CRStatement *stmt = NULL, *stmt2 = NULL ;
+ ParsingContext *ctxt = NULL ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+
+ ctxt = a_this->context ;
+ g_return_if_fail (ctxt->stylesheet) ;
+
+ uri = g_string_new_len (a_uri->str, a_uri->len) ;
+ stmt = cr_statement_new_at_import_rule (uri,
+ a_media_list,
+ NULL) ;
+ if (!stmt)
+ goto error ;
+
+ if (ctxt->cur_stmt)
+ {
+ stmt2 = cr_statement_append (ctxt->cur_stmt, stmt) ;
+ if (!stmt2)
+ goto error ;
+ ctxt->cur_stmt = stmt2 ;
+ stmt2 = NULL ;
+ stmt = NULL ;
+ }
+ else
+ {
+ stmt2 = cr_statement_append (ctxt->stylesheet->statements,
+ stmt) ;
+ if (!stmt2)
+ goto error ;
+ ctxt->stylesheet->statements = stmt2 ;
+ stmt2 = NULL ;
+ stmt = NULL ;
+ }
+
+ return ;
+
+ error:
+ if (uri)
+ {
+ g_string_free (uri, TRUE) ;
+ }
+
+ if (stmt)
+ {
+ cr_statement_destroy (stmt) ;
+ stmt = NULL ;
+ }
+}
+
+static void
+start_selector (CRDocHandler *a_this,
+ CRSelector *a_selector_list)
+{
+ ParsingContext *ctxt = NULL ;
+ g_return_if_fail (a_this && a_this->context) ;
+
+ ctxt = a_this->context ;
+ if (ctxt->cur_stmt)
+ {
+ /*hmm, this should be NULL so free it*/
+ cr_statement_destroy (ctxt->cur_stmt) ;
+ ctxt->cur_stmt = NULL ;
+ }
+
+ ctxt->cur_stmt =cr_statement_new_ruleset
+ (a_selector_list,NULL, NULL) ;
+}
+
+
+static void
+end_selector (CRDocHandler *a_this,
+ CRSelector *a_selector_list)
+{
+ ParsingContext *ctxt = NULL ;
+ g_return_if_fail (a_this && a_this->context) ;
+
+ ctxt = a_this->context ;
+ g_return_if_fail (ctxt->cur_stmt
+ && ctxt->stylesheet) ;
+
+ if (ctxt->cur_stmt)
+ {
+ CRStatement *stmts = NULL ;
+
+ if (ctxt->cur_media_stmt)
+ {
+ CRAtMediaRule *media_rule = NULL ;
+
+ media_rule = ctxt->cur_media_stmt->kind.media_rule ;
+
+ stmts = cr_statement_append
+ (media_rule->rulesets, ctxt->cur_stmt) ;
+
+ if (!stmts)
+ {
+ cr_utils_trace_info
+ ("Could not append a new statement");
+ cr_statement_destroy
+ (media_rule->rulesets) ;
+ ctxt->cur_media_stmt->
+ kind.media_rule->rulesets = NULL ;
+ return ;
+ }
+ media_rule->rulesets = stmts ;
+ ctxt->cur_stmt = NULL ;
+ }
+ else
+ {
+ stmts = cr_statement_append
+ (ctxt->stylesheet->statements,
+ ctxt->cur_stmt) ;
+ if (!stmts)
+ {
+ cr_utils_trace_info
+ ("Could not append a new statement");
+ cr_statement_destroy (ctxt->cur_stmt) ;
+ ctxt->cur_stmt = NULL ;
+ return ;
+ }
+ ctxt->stylesheet->statements = stmts ;
+ ctxt->cur_stmt = NULL ;
+ }
+
+ }
+}
+
+static void
+property (CRDocHandler *a_this,
+ GString *a_name,
+ CRTerm *a_expression)
+{
+ ParsingContext *ctxt = NULL ;
+ CRDeclaration *decl = NULL, *decl2 = NULL ;
+ GString *str = NULL ;
+
+ g_return_if_fail (a_this && a_this->context) ;
+ ctxt = a_this->context ;
+
+ /*
+ *make sure a current ruleset statement has been allocated
+ *already.
+ */
+ g_return_if_fail
+ (ctxt->cur_stmt
+ &&
+ (ctxt->cur_stmt->type == RULESET_STMT
+ || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
+ || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT));
+
+ if (a_name)
+ {
+ str = g_string_new_len (a_name->str,
+ a_name->len) ;
+ g_return_if_fail (str) ;
+ }
+
+ /*instanciates a new declaration*/
+ decl = cr_declaration_new (str, a_expression) ;
+ g_return_if_fail (decl) ;
+ str = NULL ;
+
+ /*
+ *add the new declaration to the current statement
+ *being build.
+ */
+ switch (ctxt->cur_stmt->type)
+ {
+ case RULESET_STMT:
+ decl2 = cr_declaration_append
+ (ctxt->cur_stmt->kind.ruleset->decl_list,
+ decl) ;
+ if (!decl2)
+ {
+ cr_declaration_destroy (decl) ;
+ cr_utils_trace_info
+ ("Could not append decl to ruleset");
+ goto error ;
+ }
+ ctxt->cur_stmt->kind.ruleset->decl_list = decl2 ;
+ decl = NULL ; decl2 = NULL ;
+ break ;
+
+ case AT_FONT_FACE_RULE_STMT:
+ decl2 = cr_declaration_append
+ (ctxt->cur_stmt->kind.font_face_rule->decls_list,
+ decl) ;
+ if (!decl2)
+ {
+ cr_declaration_destroy (decl) ;
+ cr_utils_trace_info
+ ("Could not append decl to ruleset");
+ goto error ;
+ }
+ ctxt->cur_stmt->kind.font_face_rule->decls_list = decl2 ;
+ decl = NULL ; decl2 = NULL ;
+ break ;
+ case AT_PAGE_RULE_STMT:
+ decl2 = cr_declaration_append
+ (ctxt->cur_stmt->kind.page_rule->decls_list,
+ decl) ;
+ if (!decl2)
+ {
+ cr_declaration_destroy (decl) ;
+ cr_utils_trace_info
+ ("Could not append decl to ruleset");
+ goto error ;
+ }
+ ctxt->cur_stmt->kind.page_rule->decls_list = decl2 ;
+ decl = NULL ; decl2 = NULL ;
+ break ;
+
+ default:
+ goto error ;
+ break ;
+ }
+
+ return ;
+
+ error:
+ if (str)
+ {
+ g_free (str) ;
+ str = NULL ;
+ }
+
+ if (decl)
+ {
+ cr_declaration_destroy (decl) ;
+ decl = NULL ;
+ }
+}
+
+static void
+error (CRDocHandler *a_this)
+{
+ ParsingContext *ctxt = NULL ;
+ g_return_if_fail (a_this && a_this->context) ;
+
+ ctxt = a_this->context ;
+
+ if (ctxt->cur_stmt)
+ {
+ cr_statement_destroy (ctxt->cur_stmt) ;
+ ctxt->cur_stmt = NULL ;
+ }
+}
+
+
+
+static void
+unrecoverable_error (CRDocHandler *a_this)
+{
+ if (a_this->context)
+ {
+ if (((ParsingContext*)a_this->context)->stylesheet)
+ {
+ a_this->result =
+ ((ParsingContext*)a_this->context)->
+ stylesheet ;
+ }
+ g_free (a_this->context) ;
+ a_this->context = NULL ;
+ }
+}
+
+
+/********************************************
+ *Public methods
+ ********************************************/
+
+/**
+ *Constructor of the CROMParser.
+ *@param a_input the input stream.
+ *@return the newly built instance of #CROMParser.
+ */
+CROMParser *
+cr_om_parser_new (CRParserInput *a_input)
+{
+ CROMParser *result = NULL ;
+ enum CRStatus status = CR_OK ;
+
+ result = g_try_malloc (sizeof (CROMParser)) ;
+
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CROMParser)) ;
+ PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv)) ;
+
+ if (!PRIVATE (result))
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ goto error ;
+ }
+
+ memset (PRIVATE (result), 0, sizeof (CROMParserPriv)) ;
+
+ PRIVATE (result)->parser = cr_parser_new_from_input (a_input);
+
+ if (!PRIVATE (result)->parser)
+ {
+ cr_utils_trace_info ("parsing instanciation failed") ;
+ goto error ;
+ }
+
+ status = cr_om_parser_init_default_sac_handler (result) ;
+
+ if (status != CR_OK)
+ {
+ goto error ;
+ }
+
+ return result ;
+
+ error:
+
+ if (result)
+ {
+ cr_om_parser_destroy (result) ;
+ }
+
+ return NULL ;
+}
+
+
+enum CRStatus
+cr_om_parser_parse_file (CROMParser *a_this,
+ guchar *a_file_uri,
+ enum CREncoding a_enc,
+ CRStyleSheet **a_result)
+{
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && a_file_uri && a_result,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (!PRIVATE (a_this)->parser)
+ {
+ PRIVATE (a_this)->parser = cr_parser_new_from_file
+ (a_file_uri, a_enc) ;
+ }
+
+ status = cr_parser_parse_from_file (PRIVATE (a_this)->parser,
+ a_file_uri, a_enc) ;
+
+ if (status == CR_OK)
+ {
+ CRDocHandler *sac_handler = NULL ;
+ cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+ &sac_handler) ;
+ g_return_val_if_fail (sac_handler, CR_ERROR) ;
+
+ if (sac_handler->result)
+ *a_result = sac_handler->result ;
+ }
+
+ return status ;
+}
+
+/**
+ *Destructor of the #CROMParser.
+ *@param a_this the current instance of #CROMParser.
+ */
+void
+cr_om_parser_destroy (CROMParser *a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)) ;
+
+ if (PRIVATE (a_this)->parser)
+ {
+ cr_parser_destroy (PRIVATE (a_this)->parser) ;
+ PRIVATE (a_this)->parser = NULL ;
+ }
+
+ if (PRIVATE (a_this))
+ {
+ g_free (PRIVATE (a_this)) ;
+ PRIVATE (a_this) = NULL ;
+ }
+
+ if (a_this)
+ {
+ g_free (a_this) ;
+ a_this = NULL ;
+ }
+}
+
diff --git a/src/cr-om-parser.h b/src/cr-om-parser.h
new file mode 100644
index 0000000..ba711d0
--- /dev/null
+++ b/src/cr-om-parser.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_OM_PARSER_H__
+#define __CR_OM_PARSER_H__
+
+#include "cr-parser.h"
+#include "cr-stylesheet.h"
+
+/**
+ *@file
+ *The definition of the CSS Object Model Parser.
+ *This parser uses (and sits) the SAC api of libcroco defined
+ *in cr-parser.h and cr-doc-handler.h
+ */
+
+G_BEGIN_DECLS
+
+typedef struct _CROMParser CROMParser ;
+typedef struct _CROMParserPriv CROMParserPriv ;
+
+/**
+ *The Object model parser.
+ *Can parse a css file and build a css object model.
+ *This parser uses an instance of #CRParser and defines
+ *a set of SAC callbacks to build the Object Model.
+ */
+struct _CROMParser
+{
+ CROMParserPriv *priv ;
+} ;
+
+CROMParser *
+cr_om_parser_new (CRParserInput *a_input) ;
+
+enum CRStatus
+cr_om_parser_parse_file (CROMParser *a_this,
+ guchar *a_file_uri,
+ enum CREncoding a_enc,
+ CRStyleSheet **a_result) ;
+void
+cr_om_parser_destroy (CROMParser *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_OM_PARSER_H__*/
diff --git a/src/cr-parser-input.c b/src/cr-parser-input.c
new file mode 100644
index 0000000..a635432
--- /dev/null
+++ b/src/cr-parser-input.c
@@ -0,0 +1,1009 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition of the #CRParserInput class.
+ *This class abstracts the high level input of the
+ *parser.
+ */
+#include "cr-parser-input.h"
+
+#define PRIVATE(obj) ((obj)->priv)
+
+struct _CRParserInputPriv
+{
+ /*
+ *The stack of the different
+ *inputs. The parser is actually
+ *fed by bytes coming from the input
+ *that is on the top of the input
+ *stack.
+ *The initial style sheet input
+ *is initially pushed on the stack.
+ *Then, each time a new input is needed
+ *(if an @import rule is encountered for ex,)
+ *it is put on the top of the stack. Each time
+ *an input becomes empty it is poped from the stack.
+ */
+ CRInput **inputs ;
+
+ /**
+ *The index of the topmost element
+ *of the input stack.
+ *When the stack is empty, this value is set to -1.
+ */
+ glong top_index ;
+
+ /**
+ *The memory size of
+ *the stack.
+ *The stack is allocated by multiples
+ *of CR_INPUT_STACK_SIZE_CHUNK ;
+ */
+ gulong input_stack_size ;
+
+ /**
+ *The reference count of
+ *the current instance.
+ */
+ gulong ref_count ;
+} ;
+
+#define CR_INPUT_STACK_SIZE_CHUNK 16
+
+/**
+ *Creates a new instance of #CRParserInput.
+ *If a_basic_input is not NULL, it is pushed on top
+ *of the basic input stack.
+ *Note that the memory management scheme adopted for
+ *a_basic_input is the reference counting.
+ *In this case, this method increments the reference count
+ *of a_basic_input.
+ *
+ *@param a_basic_input the first basic input to push on the
+ *basic input stack.
+ *@return the newly created instance of #CRParserInput.
+ */
+CRParserInput *
+cr_parser_input_new_from_uri (gchar *a_uri, enum CREncoding a_enc)
+{
+ CRParserInput * result = NULL ;
+ CRInput *input = NULL ;
+
+ result = g_malloc0 (sizeof (CRParserInput)) ;
+
+ PRIVATE (result) = g_malloc0 (sizeof (CRParserInputPriv)) ;
+
+ if (a_uri)
+ {
+ input = cr_input_new_from_uri (a_uri, a_enc) ;
+ if (input)
+ {
+ cr_parser_input_push_input (result, input) ;
+ }
+ else
+ {
+ if (result)
+ {
+ cr_parser_input_destroy (result) ;
+ result = NULL ;
+ }
+ }
+ }
+
+ return result ;
+}
+
+
+/**
+ *Gets the number of bytes left in the topmost input.
+ *@param a_this the current instance of #CRParserInput
+ *@eturn the number of bytes left, or -1 in case of an error.
+ */
+glong
+cr_parser_input_get_nb_bytes_left (CRParserInput *a_this)
+{
+ CRInput *top_input = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), -1) ;
+
+ top_input = cr_parser_input_peek_input (a_this) ;
+ g_return_val_if_fail (top_input, -1) ;
+
+ return cr_input_get_nb_bytes_left (top_input) ;
+}
+
+
+/**
+ *Increments the reference count of
+ *the current instance of #CRParserInput.
+ *@param a_this the current instance of
+ *#CRParserInput.
+ */
+void
+cr_parser_input_ref (CRParserInput *a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)) ;
+
+ PRIVATE (a_this)->ref_count ++ ;
+}
+
+
+/**
+ *Decrements the reference count of the current instance
+ *of #CRParserInput and if the reference count reaches 0, destroys
+ *this intance.
+ *@param a_this the current instance of #CRParserInput.
+ *@return TRUE if the instance has been destroyed, FALSE otherwise.
+ */
+gboolean
+cr_parser_input_unref (CRParserInput *a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE) ;
+
+ if (PRIVATE (a_this)->ref_count)
+ {
+ PRIVATE (a_this)->ref_count -- ;
+ }
+
+ if (PRIVATE (a_this)->ref_count == 0)
+ {
+ cr_parser_input_destroy (a_this) ;
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+
+/**
+ *The destructor of the #CRParserInput class.
+ *Unreferences each basic input contained
+ *contained in the input stack, destroys the input
+ *stack and destroy the parser input.
+ *@param a_this the current instance of #CRParserInput.
+ */
+void
+cr_parser_input_destroy (CRParserInput *a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)) ;
+
+ if (PRIVATE (a_this)->inputs)
+ {
+ enum CRStatus status = CR_OK ;
+
+ /*
+ *Pop all the inputs contained
+ *in the parser input stack.
+ */
+ while (status == CR_OK)
+ {
+ status = cr_parser_input_pop_input (a_this) ;
+ }
+
+ g_free (PRIVATE (a_this)->inputs) ;
+
+ PRIVATE (a_this)->inputs = NULL ;
+ }
+
+ if (PRIVATE (a_this))
+ {
+ g_free (PRIVATE (a_this)) ;
+ PRIVATE (a_this) = NULL ;
+ }
+
+ g_free (a_this) ;
+}
+
+
+/**
+ *Pushes a basic input on top of the input stack of
+ *the parser input.
+ *This methods references (increments the ref count) the
+ *pushed input.
+ *@param a_this the current instance of #CRParserInput.
+ *@param a_input the basic input to push on top of the input stack.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_push_input (CRParserInput *a_this, CRInput *a_input)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_input,
+ CR_BAD_PARAM_ERROR) ;
+
+ /*
+ *make sure there is enough space to push the input stream.
+ */
+
+ if (PRIVATE (a_this)->inputs == NULL)
+ {
+ PRIVATE (a_this)->inputs =
+ g_malloc0 (sizeof (CRInput*)
+ *
+ CR_INPUT_STACK_SIZE_CHUNK) ;
+ PRIVATE (a_this)->top_index = -1 ;
+ PRIVATE (a_this)->input_stack_size = 0 ;
+ }
+ else if ( (PRIVATE (a_this)->top_index + 1
+ ==
+ PRIVATE (a_this)->input_stack_size)
+ && PRIVATE (a_this)->input_stack_size)
+ {
+ /*The input stack is full => increase it's size!*/
+
+ PRIVATE (a_this)->inputs =
+ g_realloc (PRIVATE (a_this)->inputs,
+ PRIVATE (a_this)->input_stack_size
+ +
+ CR_INPUT_STACK_SIZE_CHUNK) ;
+
+ PRIVATE (a_this)->input_stack_size +=
+ CR_INPUT_STACK_SIZE_CHUNK ;
+ }
+ else
+ {
+ return CR_ERROR ;
+ }
+
+ PRIVATE (a_this)->top_index++ ;
+ PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index] = a_input ;
+
+ cr_input_ref (a_input) ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Pops the input stack of the the current instance of
+ *#CRParserInput.
+ *This method unreferences the poped input.
+ *@param a_this the current instance of #CRParserInput.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *error codes are:
+ *<ul>
+ *<li>CR_BAD_PARAM_ERROR: if at least one of the
+ *parameters are invalid</li>
+ *<li>CR_OUT_OF_BOUNDS_ERROR: if the stack is empty,
+ *thus cannot be poped.</li>
+ *</ul>
+ */
+enum CRStatus
+cr_parser_input_pop_input (CRParserInput *a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index > -1)
+ {
+ cr_input_unref
+ (PRIVATE
+ (a_this)->inputs[PRIVATE (a_this)->top_index]) ;
+
+ PRIVATE (a_this)->top_index -- ;
+ }
+ else
+ {
+ /*
+ *The stack is empty.
+ */
+
+ return CR_OUT_OF_BOUNDS_ERROR ;
+ }
+
+ return CR_OK ;
+}
+
+
+/**
+ *Returns the basic input that is on the top of the input stack.
+ *@param a_this the current instance of the CRParserInput.
+ *@return the instance of CRInput on top the
+ *input stack or NULL otherwise.
+ */
+CRInput *
+cr_parser_input_peek_input (CRParserInput *a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL) ;
+
+ if (PRIVATE (a_this)->top_index > -1)
+ {
+ return PRIVATE
+ (a_this)->inputs[PRIVATE (a_this)->top_index] ;
+ }
+
+ return NULL ;
+}
+
+/**
+ *Returns the memory address of the byte located at a given offset
+ *in the input stream.
+ *@param a_this the current instance of #CRParserInput.
+ *@param a_offset the offset of the byte in the input stream starting
+ *from the beginning of the stream.
+ *@param a_offset output parameter. The returned address.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_get_byte_addr (CRParserInput *a_this,
+ gulong a_offset,
+ guchar **a_addr)
+{
+ CRInput *input = NULL ;
+ guchar *addr = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ input = cr_parser_input_peek_input (a_this) ;
+
+ if (input == NULL)
+ return CR_BAD_PARAM_ERROR ;
+
+ addr = cr_input_get_byte_addr (input, a_offset) ;
+
+ if (addr)
+ {
+ *a_addr = addr ;
+ return CR_OK ;
+ }
+
+ return CR_ERROR ;
+}
+
+
+/**
+ *Reads a byte from the parser input.
+ *Actually tries to read the byte from the topmost
+ *basic input of the input stack. FIXME: (to be done:)
+ *If this basic input becomes empty
+ *or if an error occurs during the read from it, pops the basic input
+ *from the input stack and resume the read from the new topmost basic
+ *input stream.
+ *
+ *@param a_this the current instance of #CRParserInput to consider.
+ *@param a_byte out parameter. The pointer to the byte actually read.
+ */
+enum CRStatus
+cr_parser_input_read_byte (CRParserInput *a_this, guchar * a_byte)
+{
+ CRInput * top_input = NULL ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_byte,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ {
+ return CR_EMPTY_PARSER_INPUT_ERROR ;
+ }
+
+ top_input = cr_parser_input_peek_input (a_this) ;
+
+ if (top_input)
+ status = cr_input_read_byte (top_input, a_byte) ;
+ else
+ status = CR_EMPTY_PARSER_INPUT_ERROR ;
+
+ /*
+ *If we reach end the end of the topmost input stream
+ *pop that input stream end read the next char from the
+ *new topmost input stream.
+ */
+
+ return status ;
+}
+
+
+/**
+ *Reads an unicode character from the parser input.
+ *Actually tries to read the char from the topmost
+ *basic input of the input stack. FIXME: (to be done:)
+ *If this basic input becomes empty
+ *or if an error occurs during the read from it, pops the basic input
+ *from the input stack and resume the read from the new topmost basic
+ *input stream.
+ *
+ *@param a_this the current instance of #CRParserInput to consider.
+ *@param a_byte out parameter. The pointer to the byte actually read.
+ */
+enum CRStatus
+cr_parser_input_read_char (CRParserInput *a_this, guint32 * a_char)
+{
+ CRInput * top_input = NULL ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ {
+ return CR_EMPTY_PARSER_INPUT_ERROR ;
+ }
+
+ top_input = cr_parser_input_peek_input (a_this) ;
+
+ if (top_input)
+ status = cr_input_read_char (top_input, a_char) ;
+ else
+ status = CR_EMPTY_PARSER_INPUT_ERROR ;
+
+ return status ;
+}
+
+/**
+ *Consumes the next character of the input stream if
+ *and only if that character equals a_char.
+ *
+ *@param a_this the this pointer.
+ *@param a_char the character to consume.
+ *@return CR_OK upon successfull completion, CR_PARSING_ERROR if
+ *next char is different from a_char, an other error code otherwise
+ */
+enum CRStatus
+cr_parser_input_consume_char (CRParserInput *a_this, guint32 a_char)
+{
+ enum CRStatus status = CR_OK ;
+ CRInput *top_input = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ top_input = cr_parser_input_peek_input (a_this) ;
+
+ if (top_input)
+ {
+ status = cr_input_consume_char (top_input, a_char) ;
+ }
+ else
+ {
+ status = CR_EMPTY_PARSER_INPUT_ERROR ;
+ }
+
+ return status ;
+}
+
+
+/**
+ *Consumes up to a_nb_char occurences of the next contiguous characters
+ *which equal a_char. Note that the next character of the input stream
+ **MUST* equal a_char to trigger the consumption, or else, the error
+ *code CR_PARSING_ERROR is returned.
+ *If the number of contiguous characters that equals a_char is less than
+ *a_nb_char, then this function consumes all
+ *the characters it can consumed.
+ *
+ *@param a_this the this pointer of the
+ *current instance of #CRParserInput.
+ *@param a_char the character to consume. If
+ *set to 0, consume any character.
+ *@param a_nb_char in/out parameter. The number of characters to consume.
+ *If set to a negative value, the function will consume all the occurences
+ *of a_char found.
+ *After return, if the return value equals CR_OK, this variable contains
+ *the number of characters actually consumed.
+ *@return CR_OK if at least one character has been consumed, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parser_input_consume_chars (CRParserInput *a_this, guint32 a_char,
+ glong *a_nb_char)
+{
+ enum CRStatus status = CR_OK ;
+ CRInput *top_input = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ top_input = cr_parser_input_peek_input (a_this) ;
+
+ if (top_input)
+ {
+ status = cr_input_consume_chars (top_input,
+ a_char, a_nb_char) ;
+ }
+ else
+ {
+ status = CR_EMPTY_PARSER_INPUT_ERROR ;
+ }
+
+ return status ;
+}
+
+
+/**
+ *Same as cr_input_consume_chars() but this one consumes white
+ *spaces.
+ *
+ *@param a_this the "this pointer"
+ *of the current instance of #CRParserInput.
+ *@param a_nb_chars in/out parameter. The number of white spaces to
+ *consume. After return, holds the number
+ *of white spaces actually consumed.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_consume_spaces (CRParserInput *a_this, glong *a_nb_char)
+{
+ enum CRStatus status = CR_OK ;
+ CRInput *top_input = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ top_input = cr_parser_input_peek_input (a_this) ;
+
+ if (top_input)
+ {
+ status = cr_input_consume_white_spaces (top_input,
+ a_nb_char) ;
+ }
+ else
+ {
+ status = CR_EMPTY_PARSER_INPUT_ERROR ;
+ }
+
+ return status ;
+}
+
+/**
+ *Same as cr_parser_input_read_char() but does
+ *not update the internal state of the instance of
+ *#CRParserInput.
+ *@param a_this the current instance of #CRParserInput.
+ *@param a_origin the origin to consider while considering
+ *the offset.
+ *@param a_offset the offset of the character to peek.
+ *@param a_char out parameter. The char read.
+ *@return CR_OK upon sucessfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parser_input_peek_char (CRParserInput *a_this,
+ guint32 *a_char)
+{
+ CRInput * top_input = NULL ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_char, CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ {
+ return CR_EMPTY_PARSER_INPUT_ERROR ;
+ }
+
+ top_input = cr_parser_input_peek_input (a_this) ;
+
+ if (top_input)
+ {
+ status = cr_input_peek_char (top_input, a_char) ;
+ }
+ else
+ {
+ status = CR_EMPTY_PARSER_INPUT_ERROR ;
+ }
+
+ return status ;
+}
+
+/**
+ *Tests wether the topmost input stream
+ *reached end of file or not.
+ *@param a_this the current instance of #CRParserInput.
+ *@param a_eof out parameter. The returned boolean.
+ *Is set to TRUE if the topmost input stream reached end of file,
+ *FALSE otherwise.
+ *@return CR_OK uppon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_get_end_of_file (CRParserInput *a_this,
+ gboolean *a_eof)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_eof,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_get_end_of_file
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_eof) ;
+
+ return CR_OK ;
+}
+
+/**
+ *Peeks a byte from the topmost input stream of
+ *the input stack.
+ *@param a_this the current instance of #CRParserInput.
+ *@param a_origin the origin to consider in the calculation
+ *of the absolute position of the byte to peek.
+ *@param a_offset the offset of the byte to peek starting from
+ *the origin specified by a_origin.
+ *@param a_byte out parameter. The resulting peeked byte.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *Error codes are:
+ *<ul>
+ *<li>CR_BAD_PARAM_ERROR: if at least one the parameters is invalid</li>
+ *<li>CR_OUT_OF_BOUNDS_ERROR: if there is no input stream in the input
+ *input stack.</li>
+ *<li>the error codes returned by cr_input_peek_byte()</li>
+ *</ul>
+ */
+enum CRStatus
+cr_parser_input_peek_byte (CRParserInput *a_this,
+ enum CRSeekPos a_origin,
+ gulong a_offset, guchar *a_byte)
+{
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_byte,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_peek_byte
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_origin, a_offset, a_byte) ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the "current byte index" of the topmost
+ *input stream of the input stack.
+ *
+ *@param a_this the current instance of #CRParserInput.
+ *
+ *@param a_origin the origin to consider during the calculation
+ *of the absolute position of the new "current byte index".
+ *
+ *@param a_pos the relative offset of the new "current byte index".
+ *this offset is relative to the origin a_origin.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *Error codes can be:
+ *<ul>
+ *<li>CR_BAD_PARAM_ERROR: at least one argument is invalid</li>
+ *<li>CR_OUT_OF_BOUNDS_ERROR: there is no input
+ *stream in the input stack</li>
+ *</ul>
+ */
+enum CRStatus
+cr_parser_input_seek_index (CRParserInput *a_this,
+ enum CRSeekPos a_origin,
+ gint a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_seek_index
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_origin, a_pos) ;
+
+}
+
+
+/**
+ *Sets the line number of the topmost input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParserInput .
+ *@param a_line the new line number.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_set_line_num (CRParserInput *a_this, glong a_line)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_set_line_num
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_line) ;
+
+ return CR_OK ;
+}
+
+/**
+ *Increments the line number by adding an increment
+ *to the current line number.
+ *@param a_this the current instance of #CRParserInput
+ *@param a_increment the increment to add.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_incr_line_num (CRParserInput *a_this,
+ glong a_increment)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_increment_line_num
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_increment) ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Increments the column number by adding an increment to the current
+ *colum number.
+ *@param a_this the current instance of #CRParserInput.
+ *@param a_increment the increment to add to the current
+ *column number.
+ */
+enum CRStatus
+cr_parser_input_incr_col_num (CRParserInput *a_this,
+ glong a_increment)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_increment_col_num
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_increment) ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the current column number of the topmpost input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParserInput .
+ *@param a_col out parameter. The new column number.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_set_col_num (CRParserInput *a_this, glong a_col)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_set_column_num
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_col) ;
+}
+
+
+/**
+ *Gets the current column number of the topmost input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParserInput .
+ *@param a_col out paramater. The returned column number.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_get_col_num (CRParserInput *a_this, glong *a_col)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_get_column_num
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_col) ;
+}
+
+
+/**
+ *Gets the current line number of the topmost input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParserInput .
+ *@param a_line out parameter the returned a_line.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_get_line_num (CRParserInput *a_this, glong *a_line)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_line,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_get_line_num
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_line) ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Invokes a cr_input_get_cur_pos() on the topmost
+ *input stream of the input stack.
+ *
+ *@param a_this the current instance of #CRParserInput.
+ *@param a_pos out parmeter the returned position.
+ *@param a_import_depth the offset of the topmost
+ *input stream in the parser input stack.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *The error codes are the one returned by cr_input_get_cur_pos().
+ *Note that the out parameters are valid if and only if this function
+ *returns CR_OK.
+ */
+enum CRStatus
+cr_parser_input_get_cur_pos (CRParserInput *a_this,
+ CRParserInputPos *a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+
+ return cr_input_get_cur_pos
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ &a_pos->input_pos) ;
+}
+
+
+/**
+ *Sets the current position of the topmost input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParserInput.
+ *@param a_pos the new position
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_set_cur_pos (CRParserInput *a_this,
+ CRParserInputPos *a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_set_cur_pos
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ &a_pos->input_pos) ;
+}
+
+
+/**
+ *Getter of the next byte index.
+ *It actually returns the index of the
+ *next byte to be read.
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParserInput
+ *@param a_index out parameter. The returned byte index
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_input_get_cur_index (CRParserInput *a_this, glong *a_index)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_index,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->top_index < 0)
+ return CR_OUT_OF_BOUNDS_ERROR ;
+
+ g_return_val_if_fail (PRIVATE (a_this)->inputs,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_get_cur_index
+ (PRIVATE (a_this)->inputs[PRIVATE (a_this)->top_index],
+ a_index) ;
+
+}
+
+
+/**
+ *Returns the address of the current byte.
+ *That is, returns the address of the last byte
+ *returned by the cr_parser_input_read_byte().
+ *
+ *@param a_this the current instance of #CRParser.
+ *@param a_addr out param. The returned address.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parser_input_get_cur_byte_addr (CRParserInput *a_this, guchar **a_addr)
+{
+ glong index = 0 ;
+ enum CRStatus status = CR_OK ;
+
+ status = cr_parser_input_get_cur_index (a_this, &index) ;
+
+ if (index)
+ {
+ index -- ;
+ }
+ else
+ {
+ return CR_OUT_OF_BOUNDS_ERROR ;
+ }
+
+ if (status != CR_OK) return status ;
+
+ status = cr_parser_input_get_byte_addr (a_this, index, a_addr) ;
+
+ return status ;
+}
diff --git a/src/cr-parser-input.h b/src/cr-parser-input.h
new file mode 100644
index 0000000..e6076d7
--- /dev/null
+++ b/src/cr-parser-input.h
@@ -0,0 +1,166 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+#ifndef __CR_PARSER_INPUT_H__
+#define __CR_PARSER_INPUT_H__
+
+#include "cr-input.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct _CRParserInput CRParserInput ;
+ typedef struct _CRParserInputPriv CRParserInputPriv ;
+
+ struct _CRParserInput
+ {
+ CRParserInputPriv *priv ;
+ } ;
+
+ typedef struct _CRParserInputPos CRParserInputPos ;
+
+ struct _CRParserInputPos
+ {
+ CRInputPos input_pos ;
+
+ /*not used yet*/
+ glong stack_size ;
+ } ;
+
+ CRParserInput *
+ cr_parser_input_new_from_uri (gchar *a_uri, enum CREncoding) ;
+
+ void
+ cr_parser_input_ref (CRParserInput *a_this) ;
+
+ gboolean
+ cr_parser_input_unref (CRParserInput *a_this) ;
+
+ void
+ cr_parser_input_destroy (CRParserInput *a_this) ;
+
+ enum CRStatus
+ cr_parser_input_push_input (CRParserInput *a_this,
+ CRInput *a_input) ;
+
+ enum CRStatus
+ cr_parser_input_pop_input (CRParserInput *a_this) ;
+
+ CRInput *
+ cr_parser_input_peek_input (CRParserInput *a_this) ;
+
+ enum CRStatus
+ cr_parser_input_get_byte_addr (CRParserInput *a_this,
+ gulong a_offset,
+ guchar **a_addr) ;
+
+ enum CRStatus
+ cr_parser_input_get_cur_byte_addr (CRParserInput *a_this,
+ guchar **a_addr) ;
+ enum CRStatus
+ cr_parser_input_read_byte (CRParserInput *a_this,
+ guchar * a_byte) ;
+
+ enum CRStatus
+ cr_parser_input_read_char (CRParserInput *a_this,
+ guint32 * a_byte) ;
+
+ enum CRStatus
+ cr_parser_input_get_end_of_file (CRParserInput *a_this,
+ gboolean *a_eof) ;
+
+ enum CRStatus
+ cr_parser_input_consume_char (CRParserInput *a_this,
+ guint32 a_char) ;
+
+ enum CRStatus
+ cr_parser_input_consume_chars (CRParserInput *a_this,
+ guint32 a_char,
+ glong *a_nb_char) ;
+
+ enum CRStatus
+ cr_parser_input_consume_spaces (CRParserInput *a_this,
+ glong *a_nb_char) ;
+
+ enum CRStatus
+ cr_parser_input_peek_byte (CRParserInput *a_this,
+ enum CRSeekPos a_origin,
+ gulong a_offset, guchar *a_byte) ;
+
+ enum CRStatus
+ cr_parser_input_peek_char (CRParserInput *a_this,
+ guint32 *a_char) ;
+
+ glong
+ cr_parser_input_get_nb_bytes_left (CRParserInput *a_this) ;
+
+ enum CRStatus
+ cr_parser_input_seek_index (CRParserInput *a_this,
+ enum CRSeekPos a_origin,
+ gint a_pos) ;
+
+ enum CRStatus
+ cr_parser_input_get_cur_pos (CRParserInput *a_this,
+ CRParserInputPos *a_pos) ;
+
+ enum CRStatus
+ cr_parser_input_set_cur_pos (CRParserInput *a_this,
+ CRParserInputPos *a_pos) ;
+
+ enum CRStatus
+ cr_parser_input_set_line_num (CRParserInput *a_this,
+ glong a_line) ;
+
+ enum CRStatus
+ cr_parser_input_set_col_num (CRParserInput *a_this,
+ glong a_col) ;
+
+ enum CRStatus
+ cr_parser_input_incr_line_num (CRParserInput *a_this,
+ glong a_increment) ;
+
+ enum CRStatus
+ cr_parser_input_incr_col_num (CRParserInput *a_this,
+ glong a_increment) ;
+
+ enum CRStatus
+ cr_parser_input_get_col_num (CRParserInput *a_this,
+ glong *a_col) ;
+
+ enum CRStatus
+ cr_parser_input_get_line_num (CRParserInput *a_this,
+ glong *a_line) ;
+
+ enum CRStatus
+ cr_parser_input_get_cur_index (CRParserInput *a_this,
+ glong *a_index) ;
+
+#ifdef __cplusplus
+} /*extern "C" {*/
+#endif
+
+#endif /*__CR_PARSER_INPUT_H__*/
diff --git a/src/cr-parser.c b/src/cr-parser.c
new file mode 100644
index 0000000..5165390
--- /dev/null
+++ b/src/cr-parser.c
@@ -0,0 +1,5191 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition of the #CRParser class.
+ */
+
+#include "string.h"
+#include "cr-parser.h"
+#include "cr-num.h"
+#include "cr-term.h"
+#include "cr-simple-sel.h"
+#include "cr-attr-sel.h"
+
+/*
+ *Random notes:
+ *CSS core syntax vs CSS level 2 syntax
+ *=====================================
+ *
+ *One must keep in mind
+ *that css UA must comply with two syntax.
+ *
+ *1/the specific syntax that defines the css language
+ *for a given level of specificatin (e.g css2 syntax
+ *defined in appendix D.1 of the css2 spec)
+ *
+ *2/the core (general) syntax that is there to allow
+ *UAs to parse style sheets written in levels of CSS that
+ *didn't exist at the time the UAs were created.
+ *
+ *the name of parsing functions (or methods) contained in this file
+ *follows the following scheme: cr_parser_parse_<production_name> (...) ;
+ *where <production_name> is the name of a production of the css2 language.
+ *When a given production is defined by the css2 level grammar *and* by the
+ *css core syntax, there will be two functions to parse that production:
+ *one will parse the production defined by the css2 level grammar and the
+ *other will parse the production defined by the css core grammar.
+ *The css2 level grammar related parsing function will be called:
+ *cr_parser_parse_<production_name> (...) ;
+ *Then css core grammar related parsing function will be called:
+ *cr_parser_parse_<production_name>_core (...) ;
+ *
+ *If a production is defined only by the css core grammar, then
+ *it will be named:
+ *cr_parser_parse_<production_name>_core (...) ;
+ */
+
+
+
+typedef struct _CRParserError CRParserError ;
+
+/**
+ *An abstraction of an error reported by by the
+ *parsing routines.
+ */
+struct _CRParserError
+{
+ guchar * msg ;
+ enum CRStatus status ;
+ glong line ;
+ glong column ;
+ glong byte_num ;
+} ;
+
+
+enum CRParserState
+{
+ READY_STATE = 0,
+ TRY_PARSE_CHARSET_STATE,
+ CHARSET_PARSED_STATE,
+ TRY_PARSE_IMPORT_STATE,
+ IMPORT_PARSED_STATE,
+ TRY_PARSE_RULESET_STATE,
+ RULESET_PARSED_STATE,
+ TRY_PARSE_MEDIA_STATE,
+ MEDIA_PARSED_STATE,
+ TRY_PARSE_PAGE_STATE,
+ PAGE_PARSED_STATE,
+ TRY_PARSE_FONT_FACE_STATE,
+ FONT_FACE_PARSED_STATE
+} ;
+
+
+/**
+ *The private attributes of
+ *#CRParser.
+ */
+struct _CRParserPriv
+{
+ /**
+ *The tokenizer
+ */
+ CRTknzr *tknzr ;
+
+ /**
+ *The sac handlers to call
+ *to notify the parsing of
+ *the css2 constructions.
+ */
+ CRDocHandler *sac_handler ;
+
+ /**
+ *A stack of errors reported
+ *by the parsing routines.
+ *Contains instance of #CRParserError.
+ *This pointer is the top of the stack.
+ */
+ GList *err_stack ;
+
+ enum CRParserState state ;
+ gboolean is_case_sensitive ;
+ gboolean use_core_grammar ;
+} ;
+
+
+#define PRIVATE(obj) ((obj)->priv)
+
+#define CHARS_TAB_SIZE 12
+
+/**
+ *return TRUE if the character is a number ([0-9]), FALSE otherwise
+ *@param a_char the char to test.
+ */
+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
+
+/**
+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
+ *
+ *@param status the status (of type enum CRStatus) to test.
+ *@param is_exception if set to FALSE, the final status returned the
+ *current function will be CR_PARSING_ERROR. If set to TRUE, the
+ *current status will be the current value of the 'status' variable.
+ *
+ */
+#define CHECK_PARSING_STATUS(status, is_exception) \
+if ((status) != CR_OK) \
+{ \
+ if (is_exception == FALSE) \
+ { \
+ status = CR_PARSING_ERROR ; \
+ } \
+ goto error ; \
+}
+
+
+/**
+ *same as CHECK_PARSING_STATUS() but this one pushes an error
+ *on the parser error stack when an error arises.
+ *@param a_this the current instance of #CRParser .
+ *@param a_status the status to check. Is of type enum #CRStatus.
+ *@param a_is_exception in case of error, if is FALSE, the status
+ *is set to CR_PARSING_ERROR before goto error. If is false, the
+ *real low level status is kept and will be returned by the
+ *upper level function that called this macro. Usally,this must
+ *be set to FALSE.
+ *
+ */
+#define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\
+ a_err_msg, a_err_status) \
+if ((status) != CR_OK) \
+{ \
+ if (a_is_exception == FALSE) status = CR_PARSING_ERROR ; \
+ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
+ goto error ; \
+}
+
+
+/**
+ *Peeks the next char from the input stream of the current parser
+ *by invoking cr_tknzr_input_peek_char().
+ *invokes CHECK_PARSING_STATUS on the status returned by
+ *cr_tknzr_peek_char().
+ *
+ *@param a_this the current instance of #CRParser.
+ *@param a_to_char a pointer to the char where to store the
+ *char peeked.
+ */
+#define PEEK_NEXT_CHAR(a_this, a_to_char) \
+{\
+enum CRStatus status ; \
+status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE) \
+}
+
+
+
+/**
+ *Reads the next char from the input stream of the current parser.
+ *In case of error, jumps to the "error:" label located in the
+ *function where this macro is called.
+ *@param a_this the curent instance of #CRParser
+ *@param to_char a pointer to the guint32 char where to store
+ *the character read.
+ */
+#define READ_NEXT_CHAR(a_this, a_to_char) \
+status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+
+/**
+ *Gets information about the current position in
+ *the input of the parser.
+ *In case of failure, this macro returns from the
+ *calling function and
+ *returns a status code of type enum #CRStatus.
+ *@param a_this the current instance of #CRParser.
+ *@param a_pos out parameter. A pointer to the position
+ *inside the current parser input. Must
+ */
+#define RECORD_INITIAL_POS(a_this, a_pos) \
+status = cr_tknzr_get_cur_pos (PRIVATE \
+(a_this)->tknzr, a_pos) ; \
+g_return_val_if_fail (status == CR_OK, status)
+
+
+/**
+ *Gets the address of the current byte inside the
+ *parser input.
+ *@param parser the current instance of #CRParser.
+ *@param addr out parameter a pointer (guchar*)
+ *to where the address must be put.
+ */
+#define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \
+status = cr_tknzr_get_cur_byte_addr \
+ (PRIVATE (a_this)->tknzr, a_addr) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+
+/**
+ *Peeks a byte from the topmost parser input at
+ *a given offset from the current position.
+ *If it fails, goto the "error:" label.
+ *
+ *@param a_parser the current instance of #CRParser.
+ *@param a_offset the offset of the byte to peek, the
+ *current byte having the offset '0'.
+ *@param a_byte_ptr out parameter a pointer (guchar*) to
+ *where the peeked char is to be stored.
+ */
+#define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \
+status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \
+ a_offset, \
+ a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+
+/**
+ *Reads a byte from the topmost parser input
+ *steam.
+ *If it fails, goto the "error" label.
+ *@param a_this the current instance of #CRParser.
+ *@param a_byte_ptr the guchar * where to put the read char.
+ */
+#define READ_NEXT_BYTE(a_this, a_byte_ptr) \
+status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+
+/**
+ *Skips a given number of byte in the topmost
+ *parser input. Don't update line and column number.
+ *In case of error, jumps to the "error:" label
+ *of the surrounding function.
+ *@param a_parser the current instance of #CRParser.
+ *@param a_nb_bytes the number of bytes to skip.
+ */
+#define SKIP_BYTES(a_this, a_nb_bytes) \
+status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \
+ CR_SEEK_CUR, a_nb_bytes) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+
+/**
+ *Skip utf8 encoded characters.
+ *Updates line and column numbers.
+ *@param a_parser the current instance of #CRParser.
+ *@param a_nb_chars the number of chars to skip. Must be of
+ *type glong.
+ */
+#define SKIP_CHARS(a_parser, a_nb_chars) \
+{ \
+glong nb_chars = a_nb_chars ; \
+status = cr_tknzr_consume_chars \
+ (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \
+CHECK_PARSING_STATUS (status, TRUE) ; \
+}
+
+
+/**
+ *Tests the condition and if it is false, sets
+ *status to "CR_PARSING_ERROR" and goto the 'error'
+ *label.
+ *@param condition the condition to test.
+ */
+#define ENSURE_PARSING_COND(condition) \
+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
+
+
+
+#define ENSURE_PARSING_COND_ERR(a_this, a_condition, \
+ a_err_msg, a_err_status) \
+if (! (a_condition)) \
+{ \
+ status = CR_PARSING_ERROR; \
+ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
+ goto error ; \
+}
+
+
+#define GET_NEXT_TOKEN(a_this, a_token_ptr) \
+status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \
+ a_token_ptr) ; \
+ENSURE_PARSING_COND (status == CR_OK) ;
+
+static enum CRStatus
+cr_parser_try_to_skip_spaces_and_comments (CRParser *a_this) ;
+
+#ifdef WITH_UNICODE_ESCAPE_AND_RANGE
+static enum CRStatus
+cr_parser_parse_unicode_escape (CRParser *a_this,
+ guint32 *a_unicode) ;
+static enum CRStatus
+cr_parser_parse_escape (CRParser *a_this, guint32 *a_esc_code) ;
+
+static enum CRStatus
+cr_parser_parse_unicode_range (CRParser *a_this,
+ GString **a_inf,
+ GString **a_sup) ;
+#endif
+
+static enum CRStatus
+cr_parser_parse_stylesheet_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_atrule_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_ruleset_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_statement_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_selector_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_declaration_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_any_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_block_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_value_core (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_string (CRParser *a_this, GString **a_str) ;
+
+static enum CRStatus
+cr_parser_parse_ident (CRParser *a_this, GString **a_str) ;
+
+static enum CRStatus
+cr_parser_parse_uri (CRParser *a_this, GString **a_str) ;
+
+static enum CRStatus
+cr_parser_parse_term (CRParser *a_this, CRTerm **a_term) ;
+
+static enum CRStatus
+cr_parser_parse_function (CRParser *a_this, GString **a_func_name,
+ CRTerm **a_expr) ;
+static enum CRStatus
+cr_parser_parse_property (CRParser *a_this, GString **a_property) ;
+
+static enum CRStatus
+cr_parser_parse_attribute_selector (CRParser *a_this, CRAttrSel **a_sel) ;
+
+static enum CRStatus
+cr_parser_parse_simple_selector (CRParser *a_this, CRSimpleSel **a_sel) ;
+
+static enum CRStatus
+cr_parser_parse_simple_sels (CRParser *a_this, CRSimpleSel **a_sel) ;
+
+static enum CRStatus
+cr_parser_parse_ruleset (CRParser *a_this) ;
+
+static enum CRStatus
+cr_parser_parse_expr (CRParser *a_this, CRTerm **a_expr) ;
+
+static CRParserError *
+cr_parser_error_new (guchar * a_msg, enum CRStatus) ;
+
+static guchar *
+cr_parser_error_get_msg (CRParserError *a_this) ;
+
+static void
+cr_parser_error_set_msg (CRParserError *a_this, guchar *a_msg) ;
+
+static void
+cr_parser_error_dump (CRParserError *a_this) ;
+
+static enum CRStatus
+cr_parser_error_get_status (CRParserError *a_this) ;
+
+static void
+cr_parser_error_set_status (CRParserError *a_this,
+ enum CRStatus a_status) ;
+
+static void
+cr_parser_error_set_pos (CRParserError *a_this,
+ glong a_line,
+ glong a_column,
+ glong a_byte_num) ;
+static void
+cr_parser_error_destroy (CRParserError *a_this) ;
+
+static enum CRStatus
+cr_parser_push_error (CRParser *a_this,
+ guchar * a_msg,
+ enum CRStatus a_status) ;
+
+static enum CRStatus
+cr_parser_dump_err_stack (CRParser *a_this,
+ gboolean a_clear_errs) ;
+static enum CRStatus
+cr_parser_pop_error (CRParser *a_this, CRParserError **a_error) ;
+
+static enum CRStatus
+cr_parser_clear_errors (CRParser *a_this) ;
+
+static gboolean
+cr_parser_errors_exist (CRParser *a_this) ;
+
+
+/*****************************
+ *error managemet methods
+ *****************************/
+
+/**
+ *Constructor of #CRParserError class.
+ *@param a_msg the brute error message.
+ *@param a_status the error status.
+ *@return the newly built instance of #CRParserError.
+ */
+static CRParserError *
+cr_parser_error_new (guchar * a_msg, enum CRStatus a_status)
+{
+ CRParserError * result = NULL ;
+
+ result = g_try_malloc (sizeof (CRParserError)) ;
+
+ if (result == NULL)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRParserError)) ;
+
+ cr_parser_error_set_msg (result, a_msg) ;
+ cr_parser_error_set_status (result, a_status) ;
+
+ return result ;
+}
+
+/**
+ *Gets the brute error message
+ *sets by cr_parser_set_error_msg().
+ *@param a_this the current instance of #CRParserError .
+ *@return the error msg. Be carefull not to destroy the returned
+ *pointer because it points to the internals of "a_this".
+ */
+static guchar *
+cr_parser_error_get_msg (CRParserError *a_this)
+{
+ g_return_val_if_fail (a_this, NULL) ;
+
+ return a_this->msg ;
+}
+
+/**
+ *Gets the 'formatted' error msg associated
+ *to this instance of #CRParserError. The formatted
+ *message is made of some generic info (like
+ *the line and column number where
+ *the error arised etc ...) followed by the "brute"
+ *message itself.
+ *TODO: code this function.
+ *@param a_this the current instance of #CRParserError.
+ *@return the formatted msg. The caller *MUST* free
+ *the returned pointer.
+ */
+static guchar *
+cr_parser_error_get_f_msg (CRParserError *a_this)
+{
+ g_return_val_if_fail (a_this, NULL) ;
+
+ return a_this->msg ;
+}
+
+/**
+ *Sets the message associated to this instance of #CRError.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_msg the new message.
+ */
+static void
+cr_parser_error_set_msg (CRParserError *a_this, guchar *a_msg)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->msg)
+ {
+ g_free (a_this->msg) ;
+ }
+
+ a_this->msg = g_strdup (a_msg) ;
+}
+
+/**
+ *Gets the error status.
+ *@param a_this the current instance of #CRParserError.
+ *@return the error status.
+ */
+static enum CRStatus
+cr_parser_error_get_status (CRParserError *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ return a_this->status ;
+}
+
+/**
+ *Sets the error status.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_status the new error status.
+ *
+ */
+static void
+cr_parser_error_set_status (CRParserError *a_this,
+ enum CRStatus a_status)
+{
+ g_return_if_fail (a_this) ;
+
+ a_this->status = a_status ;
+}
+
+/**
+ *Sets the position of the parser error.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_line the line number.
+ *@param a_column the column number.
+ *@param a_byte_num the byte number.
+ */
+static void
+cr_parser_error_set_pos (CRParserError *a_this,
+ glong a_line,
+ glong a_column,
+ glong a_byte_num)
+{
+ g_return_if_fail (a_this) ;
+
+ a_this->line = a_line ;
+ a_this->column = a_column ;
+ a_this->byte_num = a_byte_num ;
+}
+
+
+static void
+cr_parser_error_dump (CRParserError *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ g_printerr ("parsing error: %ld:%ld:", a_this->line,
+ a_this->column) ;
+
+ g_printerr ("%s\n", a_this->msg) ;
+}
+
+
+/**
+ *The destructor of #CRParserError.
+ *@param a_this the current instance of #CRParserError.
+ */
+static void
+cr_parser_error_destroy (CRParserError *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->msg)
+ {
+ g_free (a_this->msg) ;
+ a_this->msg = NULL ;
+ }
+
+ g_free (a_this) ;
+}
+
+
+/**
+ *Pushes an error on the parser error stack.
+ *@param a_this the current instance of #CRParser.
+ *@param a_msg the error message.
+ *@param a_status the error status.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_push_error (CRParser *a_this,
+ guchar * a_msg,
+ enum CRStatus a_status)
+{
+ enum CRStatus status = CR_OK ;
+
+ CRParserError *error = NULL ;
+ CRParserInputPos pos ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_msg,
+ CR_BAD_PARAM_ERROR) ;
+
+ error = cr_parser_error_new (a_msg, a_status) ;
+
+ g_return_val_if_fail (error, CR_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &pos) ;
+
+ cr_parser_error_set_pos
+ (error, pos.input_pos.line,
+ pos.input_pos.col,
+ pos.input_pos.next_byte_index - 1);
+
+
+ PRIVATE (a_this)->err_stack =
+ g_list_prepend (PRIVATE (a_this)->err_stack,
+ error) ;
+
+ if (PRIVATE (a_this)->err_stack == NULL) goto error ;
+
+ return CR_OK ;
+
+ error:
+
+ if (error)
+ {
+ cr_parser_error_destroy (error) ;
+ error = NULL ;
+ }
+
+ return status ;
+}
+
+
+/**
+ *Pops an error from the error stack.
+ *@param a_this the current instance of #CRParser.
+ *@param a_error out parameter. The error returned.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+static enum CRStatus
+cr_parser_pop_error (CRParser *a_this, CRParserError **a_error)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_error,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->err_stack)
+ {
+ *a_error = (CRParserError *)
+ PRIVATE (a_this)->err_stack->data ;
+
+ if (PRIVATE (a_this)->err_stack->data)
+ {
+ cr_parser_error_destroy
+ ((CRParserError*)
+ PRIVATE (a_this)->err_stack->data) ;
+ }
+
+ PRIVATE (a_this)->err_stack = g_list_delete_link
+ (PRIVATE (a_this)->err_stack,
+ PRIVATE (a_this)->err_stack) ;
+
+ }
+ else
+ {
+ *a_error = NULL ;
+ }
+
+ return CR_OK ;
+}
+
+/**
+ *Dumps the error stack on stdout.
+ *@param a_this the current instance of #CRParser.
+ *@param a_clear_errs whether to clear the error stack
+ *after the dump or not.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_dump_err_stack (CRParser *a_this,
+ gboolean a_clear_errs)
+{
+ GList *cur = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->err_stack == NULL)
+ return CR_OK ;
+
+ for (cur = PRIVATE (a_this)->err_stack ;
+ cur;
+ cur = cur->next)
+ {
+ cr_parser_error_dump ((CRParserError*)cur->data) ;
+ }
+
+ if (a_clear_errs == TRUE)
+ {
+ cr_parser_clear_errors (a_this) ;
+ }
+
+ return CR_OK ;
+}
+
+
+/**
+ *Clears all the errors contained in the parser error stack.
+ *Frees all the errors, and the stack that contains'em.
+ *@param a_this the current instance of #CRParser.
+ */
+static enum CRStatus
+cr_parser_clear_errors (CRParser *a_this)
+{
+ GList *cur = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ for (cur = PRIVATE (a_this)->err_stack ;
+ cur ;
+ cur = cur->next)
+ {
+ if (cur->data)
+ {
+ cr_parser_error_destroy ((CRParserError*)
+ cur->data) ;
+ }
+ }
+
+ if (PRIVATE (a_this)->err_stack)
+ {
+ g_list_free (PRIVATE (a_this)->err_stack) ;
+ PRIVATE (a_this)->err_stack = NULL ;
+ }
+
+ return CR_OK ;
+}
+
+
+/**
+ *Returns TRUE if there are some errors on the error
+ *stack FALSE otherwise.
+ *@param a_this the current instance of #CRParser.
+ */
+static gboolean
+cr_parser_errors_exist (CRParser *a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->err_stack)
+ return TRUE ;
+ else
+ return FALSE ;
+
+}
+
+/**
+ *Same as cr_parser_try_to_skip_spaces() but this one skips
+ *spaces and comments.
+ *
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_try_to_skip_spaces_and_comments (CRParser *a_this)
+{
+ enum CRStatus status = CR_ERROR ;
+ CRToken *token = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr,
+ CR_BAD_PARAM_ERROR) ;
+ do
+ {
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status != CR_OK) goto error ;
+ }
+ while ((token != NULL)
+ && (token->type == COMMENT_TK || token->type == S_TK)) ;
+
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token) ;
+
+ return status ;
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ return status ;
+}
+
+/***************************************
+ *End of Parser input handling routines
+ ***************************************/
+
+#ifdef WITH_UNICODE_ESCAPE_AND_RANGE
+
+/**
+ *Parses an "unicode-range" as defined in the css spec at [4.1.1]:
+ * UNICODE-RANGE ::= U\+[0-9A-F?]{1,6}(-[0-9A-F]{1,6})?
+ *@param a_this the current instance of #CRParser.
+ *@param a_inf out parameter. The inferior barrier of the range.
+ *@param a_sup out parameter. The superior barrier of the range.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_unicode_range (CRParser *a_this, GString **a_inf,
+ GString **a_sup)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos;
+ glong i = 0 ;
+ gboolean min_str_needs_free = FALSE,
+ sup_str_needs_free = FALSE ;
+ guint32 cur_char = 0, next_char = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr
+ && a_inf && a_sup,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND_ERR
+ (a_this, cur_char == 'U',
+ "while parsing an unicode range: unicode range must start with an U",
+ CR_SYNTAX_ERROR) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND_ERR
+ (a_this, cur_char == '+',
+ "while parsing an unicode range: there must be a + after the U",
+ CR_SYNTAX_ERROR) ;
+
+ if (*a_inf == NULL)
+ {
+ *a_inf = g_string_new (NULL) ;
+ min_str_needs_free = TRUE ;
+ }
+
+ for (i = 0 ;i < 6 ; i++)
+ {
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (cr_utils_is_hexa_char (next_char) == TRUE
+ || next_char == '?')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ g_string_append_unichar (*a_inf, cur_char) ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+
+ if (i < 1)
+ {
+ status = CR_PARSING_ERROR ;
+ cr_parser_push_error (a_this,
+ "No unicode range expressed",
+ CR_SYNTAX_ERROR) ;
+ goto error ;
+ }
+
+ if (next_char != '-')
+ {
+ return CR_OK ;
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ /*we are sure that cur_char == '-'*/
+
+ if (*a_sup == NULL)
+ {
+ *a_sup = g_string_new (NULL) ;
+ sup_str_needs_free = TRUE ;
+ }
+
+
+ for (i = 0 ;i < 6 ; i++)
+ {
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (cr_utils_is_hexa_char (next_char) == TRUE)
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ if (*a_sup == NULL)
+ {
+ *a_sup = g_string_new (NULL) ;
+ sup_str_needs_free = TRUE ;
+ }
+ g_string_append_unichar (*a_sup, cur_char) ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+
+ error:
+
+ if (min_str_needs_free == TRUE && *a_inf)
+ {
+ g_free (*a_inf) ;
+ *a_inf = NULL ;
+ }
+
+ if (sup_str_needs_free == TRUE && *a_sup)
+ {
+ g_free (*a_sup) ;
+ *a_sup = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses an 'unicode' escape sequence defined
+ *in css spec at chap 4.1.1:
+ *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]?
+ *@param a_this the current instance of #CRParser.
+ *@param a_start out parameter. A pointer to the start
+ *of the unicode escape sequence. Must *NOT* be deleted by
+ *the caller.
+ *@param a_end out parameter. A pointer to the last character
+ *of the unicode escape sequence. Must *NOT* be deleted by the caller.
+ *@return CR_OK if parsing succeded, an error code otherwise.
+ *Error code can be either CR_PARSING_ERROR if the string
+ *parsed just doesn't
+ *respect the production or another error if a
+ *lower level error occured.
+ */
+static enum CRStatus
+cr_parser_parse_unicode_escape (CRParser *a_this,
+ guint32 *a_unicode)
+{
+ guint32 cur_char ;
+ CRParserInputPos init_pos ;
+ glong occur = 0 ;
+ guint32 unicode = 0 ;
+ guchar *tmp_char_ptr1 = NULL, *tmp_char_ptr2 = NULL ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_unicode,
+ CR_BAD_PARAM_ERROR) ;
+
+ /*first, let's backup the current position pointer*/
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char != '\\')
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ for (occur = 0, unicode = 0 ;
+ ((cur_char >= '0' && cur_char <= '9')
+ || (cur_char >= 'a' && cur_char <= 'f')
+ || (cur_char >= 'A' && cur_char <= 'F')) && occur < 6 ;
+ occur ++)
+ {
+ gint cur_char_val = 0 ;
+
+ if ((cur_char >= '0' && cur_char <= '9'))
+ {
+ cur_char_val = (cur_char - '0') ;
+ }
+ else if ((cur_char >= 'a' && cur_char <= 'f'))
+ {
+ cur_char_val = 10 + (cur_char - 'a') ;
+ }
+ else if ((cur_char >= 'A' && cur_char <= 'F'))
+ {
+ cur_char_val = 10 + (cur_char - 'A') ;
+ }
+
+ unicode = unicode * 10 + cur_char_val ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ }
+
+
+ if (occur == 5)
+ {
+ /*
+ *the unicode escape is 6 digit length
+ */
+
+ /*
+ *parse one space that may
+ *appear just after the unicode
+ *escape.
+ */
+ cr_parser_parse_w (a_this, &tmp_char_ptr1,
+ &tmp_char_ptr2) ;
+ status = CR_OK ;
+ }
+ else
+ {
+ /*
+ *The unicode escape is less than
+ *6 digit length. The character
+ *that comes right after the escape
+ *must be a white space.
+ */
+ status = cr_parser_parse_w (a_this, &tmp_char_ptr1,
+ &tmp_char_ptr2) ;
+
+ CHECK_PARSING_STATUS_ERR
+ (a_this, status, FALSE,
+ "next char expected to be a space",
+ CR_SYNTAX_ERROR) ;
+ }
+
+ if (status == CR_OK)
+ {
+ *a_unicode = unicode ;
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+ }
+
+ error:
+ /*
+ *restore the initial position pointer backuped at
+ *the beginning of this function.
+ */
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)tknzr,
+ &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *parses an escape sequence as defined by the css spec:
+ *escape ::= {unicode}|\\[ -~\200-\4177777]
+ *@param a_this the current instance of #CRParser .
+ */
+static enum CRStatus
+cr_parser_parse_escape (CRParser *a_this, guint32 *a_esc_code)
+{
+ enum CRStatus status = CR_OK ;
+ guint32 cur_char = 0 ;
+ CRParserInputPos init_pos ;
+ guchar next_chars[2] ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_esc_code, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PEEK_BYTE (a_this, 1, &next_chars[0]) ;
+ PEEK_BYTE (a_this, 2, &next_chars[1]) ;
+
+ if (next_chars[0] != '\\')
+ {
+ status = CR_PARSING_ERROR ;
+ cr_parser_push_error
+ (a_this,
+ "next char expected to be a '\\'",
+ CR_SYNTAX_ERROR) ;
+
+ goto error ;
+ }
+
+ if ((next_chars[1] >= '0' && next_chars[1] <= '9')
+ || (next_chars[1] >= 'a' && next_chars[1] <='z')
+ || (next_chars[1] >= 'A' && next_chars[1] <='Z'))
+ {
+ status =
+ cr_parser_parse_unicode_escape (a_this,
+ a_esc_code);
+ if (status != CR_OK
+ && cr_parser_errors_exist (a_this) == TRUE)
+ {
+ cr_parser_clear_errors (a_this) ;
+ }
+ }
+ else
+ {
+ /*consume the '\' char*/
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ /*then read the char after the '\'*/
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char != ' '
+ && (cur_char < 200 || cur_char > 4177777))
+ {
+ status = CR_PARSING_ERROR ;
+
+ cr_parser_push_error
+ (a_this,
+ "next char expected to be a space",
+ CR_SYNTAX_ERROR) ;
+
+ goto error ;
+ }
+
+ *a_esc_code = cur_char ;
+
+ }
+
+ if (status == CR_OK)
+ {
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+ }
+
+ error:
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)tknzr,
+ &init_pos) ;
+
+ return status ;
+}
+#endif /*WITH_UNICODE_ESCAPE_AND_RANGE*/
+
+
+/*************************************
+ *Non trivial terminal productions
+ *parsing routines
+ *************************************/
+
+/**
+ *Parses a css stylesheet following the core css grammar.
+ *This is mainly done for test purposes.
+ *During the parsing, no callback is called. This is just
+ *to validate that the stylesheet is well formed according to the
+ *css core syntax.
+ *stylesheet : [ CDO | CDC | S | statement ]*;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_stylesheet_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ continue_parsing:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status == CR_END_OF_INPUT_ERROR)
+ {
+ status = CR_OK ;
+ goto done ;
+ }
+ else if (status != CR_OK)
+ {
+ goto error ;
+ }
+
+ switch (token->type)
+ {
+
+ case CDO_TK:
+ case CDC_TK:
+ goto continue_parsing ;
+ break ;
+ default:
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token = NULL ;
+ status = cr_parser_parse_statement_core (a_this) ;
+ cr_parser_clear_errors (a_this) ;
+ if (status == CR_OK)
+ {
+ goto continue_parsing ;
+ }
+ else if (status == CR_END_OF_INPUT_ERROR)
+ {
+ goto done ;
+ }
+ else
+ {
+ goto error ;
+ }
+ }
+
+ done:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+ error:
+
+ cr_parser_push_error
+ (a_this, "could not recognize next production",
+ CR_ERROR) ;
+
+ cr_parser_dump_err_stack (a_this, TRUE) ;
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a statement as defined by the css core grammar in
+ *chapter 4.1 of the css2 spec.
+ *statement : ruleset | at-rule;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_statement_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK && token) ;
+
+ switch (token->type)
+ {
+ case ATKEYWORD_TK:
+ case IMPORT_SYM_TK:
+ case PAGE_SYM_TK:
+ case MEDIA_SYM_TK:
+ case FONT_FACE_SYM_TK:
+ case CHARSET_SYM_TK:
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ status = cr_parser_parse_atrule_core (a_this) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ break ;
+
+ default:
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ status = cr_parser_parse_ruleset_core (a_this) ;
+ cr_parser_clear_errors (a_this) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ }
+
+ return CR_OK ;
+
+ error:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses an at-rule as defined by the css core grammar
+ *in chapter 4.1 in the css2 spec.
+ *at-rule : ATKEYWORD S* any* [ block | ';' S* ];
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_atrule_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ &&
+ (token->type == ATKEYWORD_TK
+ ||token->type == IMPORT_SYM_TK
+ ||token->type == PAGE_SYM_TK
+ ||token->type == MEDIA_SYM_TK
+ ||token->type == FONT_FACE_SYM_TK
+ ||token->type == CHARSET_SYM_TK)) ;
+
+ cr_token_destroy (token) ; token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ do
+ {
+ status = cr_parser_parse_any_core (a_this) ;
+ } while (status == CR_OK) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token) ;
+ ENSURE_PARSING_COND (status == CR_OK && token) ;
+
+ if (token->type == CBO_TK)
+ {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ status = cr_parser_parse_block_core (a_this) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ goto done ;
+ }
+ else if (token->type == SEMICOLON_TK)
+ {
+ goto done ;
+ }
+ else
+ {
+ goto error ;
+ }
+
+ done:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ return CR_OK ;
+
+ error:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a ruleset as defined by the css core grammar in chapter
+ *4.1 of the css2 spec.
+ *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_ruleset_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_selector_core (a_this) ;
+
+ ENSURE_PARSING_COND (status == CR_OK
+ || status == CR_PARSING_ERROR
+ || status == CR_END_OF_INPUT_ERROR) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == CBO_TK) ;
+ cr_token_destroy (token) ; token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ status = cr_parser_parse_declaration_core (a_this) ;
+
+ parse_declaration_list:
+ if (token)
+ {
+ cr_token_destroy (token) ; token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token) ;
+ if (token->type == CBC_TK)
+ {
+ goto done ;
+ }
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == SEMICOLON_TK) ;
+
+ cr_token_destroy (token) ; token = NULL ;
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ status = cr_parser_parse_declaration_core (a_this) ;
+ cr_parser_clear_errors (a_this) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ || status == CR_PARSING_ERROR) ;
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK && token) ;
+ if (token->type == CBC_TK)
+ {
+ cr_token_destroy (token) ; token = NULL ;
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ goto done ;
+ }
+ else
+ {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ goto parse_declaration_list ;
+ }
+
+ done:
+ if (token)
+ {
+ cr_token_destroy (token) ; token = NULL ;
+ }
+
+ if (status == CR_OK)
+ {
+ return CR_OK ;
+ }
+
+ error:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a "selector" as specified by the css core
+ *grammar.
+ *selector : any+;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_selector_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_any_core (a_this) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ do
+ {
+ status = cr_parser_parse_any_core (a_this) ;
+
+ }while (status == CR_OK) ;
+
+ return CR_OK ;
+
+ error:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a "block" as defined in the css core grammar
+ *in chapter 4.1 of the css2 spec.
+ *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*;
+ *@param a_this the current instance of #CRParser.
+ *FIXME: code this function.
+ */
+static enum CRStatus
+cr_parser_parse_block_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == CBO_TK) ;
+
+ parse_block_content:
+
+ cr_token_destroy (token) ; token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK && token) ;
+
+ if (token->type == CBC_TK)
+ {
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ goto done ;
+ }
+ else if (token->type == SEMICOLON_TK)
+ {
+ goto parse_block_content ;
+ }
+ else if (token->type == ATKEYWORD_TK)
+ {
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ goto parse_block_content ;
+ }
+ else if (token->type == CBO_TK)
+ {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ status = cr_parser_parse_block_core (a_this) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ goto parse_block_content ;
+ }
+ else
+ {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ status = cr_parser_parse_any_core (a_this) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ goto parse_block_content ;
+ }
+
+ done:
+ if (token)
+ {
+ cr_token_destroy (token) ; token = NULL ;
+ }
+
+ if (status == CR_OK) return CR_OK ;
+
+ error:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+
+static enum CRStatus
+cr_parser_parse_declaration_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+ GString *prop = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_property (a_this, &prop) ;
+ cr_parser_clear_errors (a_this) ;
+ ENSURE_PARSING_COND (status == CR_OK && prop) ;
+ g_string_free (prop, TRUE) ; prop = NULL ;
+
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == DELIM_TK
+ && token->unichar == ':' ) ;
+ cr_token_destroy (token) ; token = NULL ;
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ status = cr_parser_parse_value_core (a_this) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ return CR_OK ;
+
+ error:
+
+ if (prop)
+ {
+ g_string_free (prop, TRUE) ;
+ prop = NULL ;
+ }
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a "value" production as defined by the css core grammar
+ *in chapter 4.1.
+ *value ::= [ any | block | ATKEYWORD S* ]+;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_value_core (CRParser *a_this)
+{
+ CRToken *token = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+ glong ref = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+
+ continue_parsing:
+
+ if (token)
+ {
+ cr_token_destroy (token) ; token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK && token) ;
+
+ switch (token->type)
+ {
+ case CBO_TK:
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ status = cr_parser_parse_block_core (a_this) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ ref ++ ;
+ goto continue_parsing ;
+
+ case ATKEYWORD_TK:
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ ref ++ ;
+ goto continue_parsing ;
+
+ default :
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ status = cr_parser_parse_any_core (a_this) ;
+ if (status == CR_OK)
+ {
+ ref ++ ;
+ goto continue_parsing ;
+ }
+ else if (status == CR_PARSING_ERROR)
+ {
+ status = CR_OK ;
+ goto done ;
+ }
+ else
+ {
+ goto error ;
+ }
+ }
+
+ done:
+ if (token)
+ {
+ cr_token_destroy (token) ; token = NULL ;
+ }
+
+ if (status == CR_OK && ref)
+ return CR_OK ;
+ error:
+ if (token)
+ {
+ cr_token_destroy (token) ; token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses an "any" as defined by the css core grammar in the
+ *css2 spec in chapter 4.1.
+ *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
+ * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
+ * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*;
+ *
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_any_core (CRParser *a_this)
+{
+ CRToken *token1 = NULL, *token2 = NULL ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token1) ;
+
+ ENSURE_PARSING_COND (status == CR_OK && token1) ;
+
+ switch (token1->type)
+ {
+ case IDENT_TK:
+ case NUMBER_TK:
+ case PERCENTAGE_TK:
+ case DIMEN_TK:
+ case EMS_TK:
+ case EXS_TK:
+ case LENGTH_TK:
+ case ANGLE_TK:
+ case FREQ_TK:
+ case TIME_TK:
+ case STRING_TK:
+ case DELIM_TK:
+ case URI_TK:
+ case HASH_TK:
+ case UNICODERANGE_TK:
+ case INCLUDES_TK:
+ case DASHMATCH_TK:
+ case S_TK:
+ status = CR_OK ;
+ break ;
+ case FUNCTION_TK:
+ /*
+ *this case isn't specified by the spec but it
+ *does happen. So we have to handle it.
+ *We must consider function with parameters.
+ *We consider parameter as being an "any*" production.
+ */
+ do
+ {
+ status = cr_parser_parse_any_core (a_this) ;
+ } while (status == CR_OK) ;
+
+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR) ;
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token2
+ && token2->type == PC_TK) ;
+ break ;
+ case PO_TK:
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2) ;
+ ENSURE_PARSING_COND (status == CR_OK && token2) ;
+
+ if (token2->type == PC_TK)
+ {
+ cr_token_destroy (token2) ;
+ token2 = NULL ;
+ goto done ;
+ }
+ else
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token2) ;
+ token2 = NULL ;
+ }
+
+ do
+ {
+ status = cr_parser_parse_any_core (a_this) ;
+ } while (status == CR_OK) ;
+
+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token2
+ && token2->type == PC_TK) ;
+ status = CR_OK ;
+ break ;
+
+ case BO_TK:
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2) ;
+ ENSURE_PARSING_COND (status == CR_OK && token2) ;
+
+ if (token2->type == BC_TK)
+ {
+ cr_token_destroy (token2) ;
+ token2 = NULL ;
+ goto done ;
+ }
+ else
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token2) ;
+ token2 = NULL ;
+ }
+
+ do
+ {
+ status = cr_parser_parse_any_core (a_this) ;
+ } while (status == CR_OK) ;
+
+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token2
+ && token2->type == BC_TK) ;
+ status = CR_OK ;
+ break ;
+ default:
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ done:
+ if (token1)
+ {
+ cr_token_destroy (token1) ;
+ token1 = NULL ;
+ }
+
+ if (token2)
+ {
+ cr_token_destroy (token2) ;
+ token2 = NULL ;
+ }
+
+ return CR_OK ;
+
+ error:
+
+ if (token1)
+ {
+ cr_token_destroy (token1) ;
+ token1 = NULL ;
+ }
+
+ if (token2)
+ {
+ cr_token_destroy (token2) ;
+ token2 = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+ return status ;
+}
+
+/**
+ *Parses a "declaration" as defined by the css2 spec in appendix D.1:
+ *declaration ::= [property ':' S* expr prio?]?
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param a_property the successfully parsed property. The caller
+ * *must* free the returned pointer.
+ *@param a_expr the expression that represents the attribute value.
+ *The caller *must* free the returned pointer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_declaration (CRParser *a_this, GString **a_property,
+ CRTerm **a_expr)
+{
+ enum CRStatus status = CR_ERROR ;
+ CRParserInputPos init_pos ;
+ guint32 cur_char = 0 ;
+ CRTerm *expr = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_property && a_expr,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_property (a_this, a_property) ;
+
+ CHECK_PARSING_STATUS_ERR
+ (a_this, status, FALSE,
+ "while parsing declaration: next property is malformed",
+ CR_SYNTAX_ERROR) ;
+
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char != ':')
+ {
+ status = CR_PARSING_ERROR ;
+ cr_parser_push_error
+ (a_this,
+ "while parsing declaration: this char must be ':'",
+ CR_SYNTAX_ERROR) ;
+ goto error ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_expr (a_this, &expr) ;
+
+ CHECK_PARSING_STATUS_ERR
+ (a_this, status, FALSE,
+ "while parsing declaration: next expression is malformed",
+ CR_SYNTAX_ERROR) ;
+
+ if (*a_expr)
+ {
+ cr_term_append_term (*a_expr, expr) ;
+ expr = NULL ;
+ }
+ else
+ {
+ *a_expr = expr ;
+ expr = NULL ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+
+ error:
+
+ if (expr)
+ {
+ cr_term_destroy (expr) ;
+ expr = NULL ;
+ }
+
+ if (*a_property)
+ {
+ g_string_free (*a_property, TRUE) ;
+ *a_property = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses an attribute selector as defined in the css2 spec in
+ *appendix D.1:
+ *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
+ * [ IDENT | STRING ] S* ]? ']'
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser .
+ *@param a_sel out parameter. The successfully parsed attribute selector.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_attribute_selector (CRParser *a_this, CRAttrSel **a_sel)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ CRToken *token = NULL ;
+ CRAttrSel *result = NULL ;
+
+ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == BO_TK) ;
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ result = cr_attr_sel_new () ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == IDENT_TK) ;
+
+ result->name = token->str ;
+ token->str = NULL ;
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token) ;
+
+ if (token->type == INCLUDES_TK)
+ {
+ result->match_way = INCLUDES ;
+ goto parse_right_part ;
+ }
+ else if (token->type == DASHMATCH_TK)
+ {
+ result->match_way = DASHMATCH ;
+ goto parse_right_part ;
+ }
+ else if (token->type == DELIM_TK && token->unichar == '=')
+ {
+ result->match_way = EQUALS ;
+ goto parse_right_part ;
+ }
+ else if (token->type == BC_TK)
+ {
+ result->match_way = SET ;
+ goto done ;
+ }
+
+ parse_right_part:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token) ;
+
+ if (token->type == IDENT_TK)
+ {
+ result->value = token->str ;
+ token->str = NULL ;
+ }
+ else if (token->type == STRING_TK)
+ {
+ result->value = token->str ;
+ token->str = NULL ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == BC_TK) ;
+ done:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (*a_sel)
+ {
+ status = cr_attr_sel_append_attr_sel (*a_sel,
+ result) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ }
+ else
+ {
+ *a_sel = result ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+
+ error:
+
+ if (result)
+ {
+ cr_attr_sel_destroy (result) ;
+ result = NULL ;
+ }
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return CR_OK ;
+}
+
+
+
+/**
+ *Parses a "property" as specified by the css2 spec at [4.1.1]:
+ *property : IDENT S*;
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param GString a_property out parameter. The parsed property without the
+ *trailing spaces. If *a_property is NULL, this function allocates a
+ *new instance of GString and set it content to the parsed property.
+ *If not, the property is just appended to a_property's previous content.
+ *In both cases, it is up to the caller to free a_property.
+ *@return CR_OK upon successfull completion, CR_PARSING_ERROR if the
+ *next construction was not a "property", or an error code.
+ */
+static enum CRStatus
+cr_parser_parse_property (CRParser *a_this, GString **a_property)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr
+ && a_property,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_ident (a_this, a_property) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+
+ error:
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses a "term" as defined in the css2 spec, appendix D.1:
+ *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* |
+ *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] |
+ *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor
+ *
+ *TODO: handle parsing of 'RGB'
+ *
+ *@param a_term out parameter. The successfully parsed term.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_term (CRParser *a_this, CRTerm **a_term)
+{
+ enum CRStatus status = CR_PARSING_ERROR ;
+ CRParserInputPos init_pos ;
+ CRTerm *result = NULL;
+ CRTerm *param = NULL ;
+ CRToken * token = NULL ;
+ GString *func_name = NULL ;
+
+ g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ result = cr_term_new () ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status != CR_OK) goto error ;
+
+ if (token && token->type == DELIM_TK && token->unichar == '+')
+ {
+ result->unary_op = PLUS_UOP ;
+ }
+ else if (token && token->type == DELIM_TK && token->unichar == '-')
+ {
+ result->unary_op = MINUS_UOP ;
+ }
+ else if (token && token->type == EMS_TK)
+ {
+ status = cr_term_set_ems (result, token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ status = CR_OK ;
+ }
+ else if (token && token->type == EXS_TK)
+ {
+ status = cr_term_set_exs (result, token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ status = CR_OK ;
+ }
+ else if (token && token->type == LENGTH_TK)
+ {
+ switch (token->extra_type)
+ {
+ case LENGTH_PX_ET :
+ status = cr_term_set_length (result, UNIT_PX,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+
+ case LENGTH_CM_ET :
+ status = cr_term_set_length (result, UNIT_CM,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+
+ case LENGTH_MM_ET :
+ status = cr_term_set_length (result, UNIT_MM,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+
+ case LENGTH_IN_ET :
+ status = cr_term_set_length (result, UNIT_IN,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+
+ case LENGTH_PT_ET :
+ status = cr_term_set_length (result, UNIT_PT,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+
+ case LENGTH_PC_ET :
+ status = cr_term_set_length (result, UNIT_PC,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if (token && token->type == ANGLE)
+ {
+ switch (token->extra_type)
+ {
+ case ANGLE_DEG_ET:
+ status = cr_term_set_angle (result, UNIT_DEG,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+
+ case ANGLE_RAD_ET:
+ status = cr_term_set_angle (result, UNIT_RAD,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+
+ case ANGLE_GRAD_ET:
+ status = cr_term_set_angle (result, UNIT_GRAD,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if (token && token->type == TIME_TK)
+ {
+ status = cr_term_set_time (result, token->extra_type,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ }
+ else if (token && token->type == FREQ_TK)
+ {
+ status = cr_term_set_freq (result, token->extra_type,
+ token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ }
+ else if (token && token->type == PERCENTAGE_TK)
+ {
+ status = cr_term_set_percentage (result, token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ }
+ else if (token && token->type == NUMBER_TK)
+ {
+ status = cr_term_set_number (result, token->num) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->num = NULL ;
+ }
+ else if (token && token->type == FUNCTION_TK)
+ {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ status = cr_parser_parse_function
+ (a_this, &func_name, &param) ;
+
+ if (status == CR_OK)
+ {
+ status = cr_term_set_function (result, func_name,
+ param) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ }
+ }
+ else if (token && token->type == STRING_TK)
+ {
+ status = cr_term_set_string (result, token->str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->str = NULL ;
+ }
+ else if (token && token->type == IDENT_TK)
+ {
+ status = cr_term_set_ident (result, token->str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->str = NULL ;
+ }
+ else if (token && token->type == URI_TK)
+ {
+ status = cr_term_set_uri (result, token->str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->str = NULL ;
+ }
+ else if (token && token->type == RGB_TK)
+ {
+ status = cr_term_set_rgb (result, token->rgb) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->rgb = NULL ;
+ }
+ else if (token && token->type == UNICODERANGE_TK)
+ {
+ result->type = UNICODERANGE ;
+ status = CR_PARSING_ERROR ;
+ }
+ else if (token && token->type == HASH_TK)
+ {
+ status = cr_term_set_hash (result, token->str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token->str = NULL ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ }
+
+ if (status != CR_OK)
+ {
+ goto error ;
+ }
+
+ *a_term = cr_term_append_term (*a_term, result) ;
+
+ result = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ if (token)
+ {
+ cr_token_destroy (token);
+ token = NULL ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+
+ error:
+
+ if (result)
+ {
+ cr_term_destroy (result) ;
+ result = NULL ;
+ }
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (param)
+ {
+ cr_term_destroy (param) ;
+ param = NULL ;
+ }
+
+ if (func_name)
+ {
+ g_string_free (func_name, TRUE) ;
+ func_name = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses an expression as defined by the css2 spec in appendix
+ *D.1:
+ *expr: term [ operator term ]*
+ */
+static enum CRStatus
+cr_parser_parse_expr (CRParser *a_this, CRTerm **a_expr)
+{
+ enum CRStatus status = CR_ERROR ;
+ CRParserInputPos init_pos ;
+ CRTerm *expr = NULL, *expr2 = NULL ;
+ guchar next_byte = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_expr,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_term (a_this, &expr) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ for (;;)
+ {
+ guchar operator = 0 ;
+
+ PEEK_BYTE (a_this, 1, &next_byte) ;
+
+ if (next_byte == '/' || next_byte == ',')
+ {
+ READ_NEXT_BYTE (a_this, &operator) ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+
+ status = cr_parser_parse_term (a_this, &expr2) ;
+
+ if (status != CR_OK || expr2 == NULL)
+ {
+ status = CR_OK ;
+ break ;
+ }
+
+ switch (operator)
+ {
+ case '/':
+ expr2->operator = DIVIDE ;
+ break ;
+ case ',':
+ expr2->operator = COMMA ;
+
+ default:
+ break ;
+ }
+
+ expr = cr_term_append_term (expr, expr2) ;
+ expr2 = NULL ;
+ operator = 0 ;
+ }
+
+ if (status == CR_OK)
+ {
+ *a_expr = cr_term_append_term (*a_expr, expr) ;
+ expr = NULL ;
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+ }
+
+ error:
+
+ if (expr)
+ {
+ cr_term_destroy (expr) ;
+ expr = NULL ;
+ }
+
+ if (expr2)
+ {
+ cr_term_destroy (expr2) ;
+ expr2 = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
+ &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 :
+ *element_name? [ HASH | class | attrib | pseudo ]* S*
+ *and where pseudo is:
+ *pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ]
+ *
+ *@Param a_this the "this pointer" of the current instance of #CRParser.
+ *@param a_sel out parameter. Is set to the successfully parsed simple
+ *selector.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_simple_selector (CRParser *a_this, CRSimpleSel **a_sel)
+{
+ enum CRStatus status = CR_ERROR ;
+ CRParserInputPos init_pos ;
+ CRToken *token = NULL ;
+ CRSimpleSel * sel = NULL ;
+ CRAdditionalSel *add_sel_list = NULL ;
+ gboolean found_sel = FALSE ;
+ guint32 cur_char = 0 ;
+
+ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status != CR_OK) goto error ;
+
+ sel = cr_simple_sel_new () ;
+ ENSURE_PARSING_COND (sel) ;
+
+ if (token && token->type == DELIM_TK && token->unichar == '*')
+ {
+ sel->type_mask |= UNIVERSAL_SELECTOR ;
+ sel->name = g_string_new ("*") ;
+ found_sel = TRUE ;
+ }
+ else if (token && token->type == IDENT_TK)
+ {
+ sel->name = token->str ;
+ token->str = NULL ;
+ found_sel = TRUE ;
+ }
+ else
+ {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ }
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ for (;;)
+ {
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status != CR_OK) goto error ;
+
+ if (token && token->type == HASH_TK)
+ {
+ /*we parsed an attribute id*/
+ CRAdditionalSel *add_sel = NULL ;
+
+ add_sel = cr_additional_sel_new_with_type
+ (ID_ADD_SELECTOR) ;
+
+ add_sel->content.id_name = token->str ;
+ token->str = NULL ;
+
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel) ;
+
+ found_sel = TRUE ;
+ }
+ else if (token
+ && (token->type == DELIM_TK)
+ && (token->unichar == '.'))
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token) ;
+ if (status != CR_OK) goto error ;
+
+ if (token && token->type == IDENT_TK)
+ {
+ CRAdditionalSel *add_sel = NULL ;
+
+ add_sel = cr_additional_sel_new_with_type
+ (CLASS_ADD_SELECTOR) ;
+
+ add_sel->content.class_name = token->str ;
+ token->str = NULL ;
+
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel) ;
+ found_sel = TRUE ;
+ }
+ else
+ {
+ status = CR_OK ;
+ goto error ;
+ }
+ }
+ else if (token
+ && token->type == BO_TK)
+ {
+ CRAttrSel *attr_sel = NULL ;
+ CRAdditionalSel *add_sel = NULL ;
+
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ if (status != CR_OK) goto error ;
+ token = NULL ;
+
+ status = cr_parser_parse_attribute_selector
+ (a_this, &attr_sel) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ add_sel = cr_additional_sel_new_with_type
+ (ATTRIBUTE_ADD_SELECTOR) ;
+
+ ENSURE_PARSING_COND (add_sel != NULL) ;
+
+ add_sel->content.attr_sel = attr_sel ;
+
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel) ;
+ found_sel = TRUE ;
+ }
+ else if (token
+ && (token->type == DELIM_TK)
+ && (token->unichar == ':'))
+ {
+ CRPseudo *pseudo = NULL ;
+
+ /*try to parse a pseudo*/
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ pseudo = cr_pseudo_new () ;
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token) ;
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token) ;
+
+ if (token->type == IDENT_TK)
+ {
+ pseudo->type = IDENT_PSEUDO ;
+ pseudo->name = token->str ;
+ token->str = NULL ;
+ found_sel = TRUE ;
+ }
+ else if (token->type == FUNCTION_TK)
+ {
+ pseudo->name = token->str ;
+ token->str = NULL ;
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+ status = cr_parser_parse_ident
+ (a_this, &pseudo->extra) ;
+
+ ENSURE_PARSING_COND (status == CR_OK) ;
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ ENSURE_PARSING_COND (cur_char == ')') ;
+ pseudo->type = FUNCTION_PSEUDO ;
+ found_sel = TRUE ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ if (status == CR_OK)
+ {
+ CRAdditionalSel *add_sel = NULL ;
+
+ add_sel = cr_additional_sel_new_with_type
+ (PSEUDO_CLASS_ADD_SELECTOR) ;
+
+ add_sel->content.pseudo = pseudo ;
+
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel) ;
+
+ status = CR_OK ;
+ }
+ }
+ else
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ break ;
+ }
+ }
+
+ if (status == CR_OK && found_sel == TRUE)
+ {
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ sel->add_sel = add_sel_list ;
+ add_sel_list = NULL ;
+
+ if (*a_sel == NULL)
+ {
+ *a_sel = sel ;
+ }
+ else
+ {
+ cr_simple_sel_append_simple_sel (*a_sel, sel) ;
+ }
+
+ sel = NULL ;
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ }
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (add_sel_list)
+ {
+ cr_additional_sel_destroy (add_sel_list) ;
+ add_sel_list = NULL ;
+ }
+
+ if (sel)
+ {
+ cr_simple_sel_destroy (sel) ;
+ sel = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+
+
+}
+
+
+/**
+ *Parses a "selector" as defined by the css2 spec in appendix D.1:
+ *selector ::= simple_selector [ combinator simple_selector ]*
+ *
+ *@param a_this the this pointer of the current instance of #CRParser.
+ *@param a_start a pointer to the
+ *first chararcter of the successfully parsed
+ *string.
+ *@param a_end a pointer to the last character of the successfully parsed
+ *string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_simple_sels (CRParser *a_this, CRSimpleSel **a_sel)
+{
+ enum CRStatus status = CR_ERROR ;
+ CRParserInputPos init_pos ;
+ CRSimpleSel *sel = NULL ;
+ guint32 cur_char = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_simple_selector (a_this, &sel) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel) ;
+
+ for (;;)
+ {
+ guint32 next_char = 0 ;
+ enum Combinator comb = 0 ;
+
+ sel = NULL ;
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == '+')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ comb = COMB_PLUS ;
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+ }
+ else if (next_char == '>')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ comb = COMB_GT ;
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+ }
+ else
+ {
+ comb = COMB_WS ;
+ }
+
+ status = cr_parser_parse_simple_selector (a_this, &sel) ;
+ if (status != CR_OK) break ;
+
+ if (comb)
+ {
+ sel->combinator = comb ;
+ comb = 0 ;
+ }
+
+ *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel) ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+
+ error:
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a charset declaration as defined implictly by the css2 spec in
+ *appendix D.1:
+ *charset ::= CHARSET_SYM S* STRING S* ';'
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param a_value out parameter. The actual parsed value of the charset
+ *declararation.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_charset (CRParser *a_this, GString **a_value)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ CRToken *token = NULL ;
+ GString *charset_str = NULL ;
+
+ g_return_val_if_fail (a_this && a_value
+ && (*a_value == NULL),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == CHARSET_SYM_TK) ;
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == STRING_TK) ;
+ charset_str = token->str ;
+ token->str = NULL ;
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == SEMICOLON_TK) ;
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ if (charset_str)
+ {
+ *a_value = charset_str ;
+ }
+
+ PRIVATE (a_this)->state = CHARSET_PARSED_STATE ;
+ return CR_OK ;
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (*a_value)
+ {
+ g_string_free (*a_value, TRUE) ;
+ *a_value = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
+ &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses an 'import' declaration as defined in the css2 spec
+ *in appendix D.1:
+ *
+ *import ::=
+ *@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S*
+ *
+ *@param a_this the "this pointer" of the current instance
+ *of #CRParser.
+ *
+ *@param a_medium_list out parameter. A linked list of
+ *GString (see the doc of glib-2).
+ *Each GString is a string that contains
+ *a 'medium' declaration part of the successfully
+ *parsed 'import' declaration.
+ *
+ *@param a_import_string out parameter.
+ *A string that contains the 'import
+ *string". The import string can be either an uri (if it starts with
+ *the substring "uri(") or a any other css2 string. Note that
+ * *a_import_string must be initially set to NULL or else, this function
+ *will return CR_BAD_PARAM_ERROR.
+ *
+ *@return CR_OK upon sucessfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_import (CRParser *a_this, GList ** a_media_list,
+ GString **a_import_string)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ guint32 cur_char = 0, next_char = 0 ;
+ guchar next_bytes[CHARS_TAB_SIZE] = {0} ;
+ GString *medium = NULL ;
+
+ g_return_val_if_fail (a_this
+ && a_import_string
+ && (*a_import_string == NULL),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+ PEEK_BYTE (a_this, 5, &next_bytes[4]) ;
+ PEEK_BYTE (a_this, 6, &next_bytes[5]) ;
+ PEEK_BYTE (a_this, 7, &next_bytes[6]) ;
+
+ if (next_bytes[0] == '@'
+ && next_bytes[1] == 'i'
+ && next_bytes[2] == 'm'
+ && next_bytes[3] == 'p'
+ && next_bytes[4] == 'o'
+ && next_bytes[5] == 'r'
+ && next_bytes[6] == 't')
+ {
+ SKIP_CHARS (a_this, 7) ;
+ status = CR_OK ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE ;
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == '"' || next_char == '\'')
+ {
+ status = cr_parser_parse_string
+ (a_this, a_import_string) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ }
+ else
+ {
+ status = cr_parser_parse_uri
+ (a_this, a_import_string) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_ident (a_this, &medium) ;
+
+ if (status == CR_OK && medium)
+ {
+ *a_media_list = g_list_append (*a_media_list,
+ medium) ;
+ medium = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ for (;status == CR_OK;)
+ {
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == ',')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ }
+ else
+ {
+ break ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_ident (a_this,
+ &medium) ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ if ((status == CR_OK) && medium)
+ {
+ *a_media_list = g_list_append
+ (*a_media_list, medium) ;
+
+ medium = NULL ;
+ }
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND (cur_char == ';') ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ PRIVATE (a_this)->state = IMPORT_PARSED_STATE ;
+
+ return CR_OK ;
+
+ error:
+
+ if (*a_media_list)
+ {
+ GList *cur = NULL ;
+ /*
+ *free each element of *a_media_list.
+ *Note that each element of *a_medium list *must*
+ *be a GString* or else, the code that is coming next
+ *will corrupt the memory and lead to hard to debug
+ *random crashes.
+ *This is where C++ and its compile time
+ *type checking mecanism (through STL containers) would
+ *have prevented us to go through this hassle.
+ */
+ for (cur = *a_media_list; cur ; cur = cur->next)
+ {
+ if (cur->data)
+ {
+ g_string_free (cur->data, TRUE) ;
+ }
+ }
+
+ g_list_free (*a_media_list) ;
+ *a_media_list = NULL ;
+ }
+
+ if (*a_import_string)
+ {
+ g_string_free (*a_import_string, TRUE) ;
+ *a_import_string = NULL ;
+ }
+
+ if (medium)
+ {
+ g_string_free (medium, TRUE) ;
+ medium = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a 'media' declaration as specified in the css2 spec at
+ *appendix D.1:
+ *
+ *media ::= @media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S*
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_media (CRParser *a_this)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ CRToken * token = NULL ;
+ guint32 next_char = 0, cur_char = 0 ;
+ GString * medium = NULL ;
+ GList *media_list = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == MEDIA_SYM_TK) ;
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == IDENT_TK) ;
+
+ medium = token->str ;
+ token->str = NULL ;
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ if (medium)
+ {
+ media_list = g_list_append (media_list, medium) ;
+ medium = NULL ;
+ }
+
+ for (;status == CR_OK;)
+ {
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == ',')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ }
+ else
+ {
+ break ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_ident (a_this, &medium) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ if (medium)
+ {
+ media_list = g_list_append (media_list,
+ medium) ;
+ medium = NULL ;
+ }
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND (cur_char == '{') ;
+
+ /*
+ *call the SAC handler api here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->start_media)
+ {
+ PRIVATE (a_this)->sac_handler->start_media
+ (PRIVATE (a_this)->sac_handler, media_list) ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE ;
+
+ for (;status == CR_OK;)
+ {
+ status = cr_parser_parse_ruleset (a_this) ;
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND (cur_char == '}') ;
+
+ /*
+ *call the right SAC handler api here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->end_media)
+ {
+ PRIVATE (a_this)->sac_handler->end_media
+ (PRIVATE (a_this)->sac_handler,
+ media_list) ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ /*
+ *Then, free the data structures passed to
+ *the last call to the SAC handler.
+ */
+ if (medium)
+ {
+ g_string_free (medium, TRUE) ;
+ medium = NULL ;
+ }
+
+ if (media_list)
+ {
+ GList *cur = NULL ;
+
+ for (cur = media_list ; cur ; cur = cur->next)
+ {
+ g_string_free (cur->data, TRUE) ;
+ }
+
+ g_list_free (media_list) ;
+ media_list = NULL ;
+ }
+
+
+ cr_parser_clear_errors (a_this) ;
+ PRIVATE (a_this)->state = MEDIA_PARSED_STATE ;
+
+ return CR_OK ;
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (medium)
+ {
+ g_string_free (medium, TRUE) ;
+ medium = NULL ;
+ }
+
+ if (media_list)
+ {
+ GList *cur = NULL ;
+
+ for (cur = media_list ; cur ; cur = cur->next)
+ {
+ g_string_free (cur->data, TRUE) ;
+ }
+
+ g_list_free (media_list) ;
+ media_list = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status ;
+}
+
+
+/**
+ *Parses '@page' rule as specified in the css2 spec in appendix D.1:
+ *page ::= PAGE_SYM S* IDENT? pseudo_page? S*
+ *'{' S* declaration [ ';' S* declaration ]* '}' S*
+ *
+ *This function also calls the relevant SAC handlers whenever it
+ *encounters a construction that must
+ *be reported to the calling application.
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_page (CRParser *a_this)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ CRToken * token = NULL ;
+ CRTerm * css_expression = NULL ;
+ GString *page_selector = NULL,
+ *page_pseudo_class = NULL,
+ *property = NULL ;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == PAGE_SYM_TK) ;
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK && token) ;
+
+ if (token->type == IDENT_TK)
+ {
+ page_selector = token->str ;
+ token->str = NULL ;
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+ else
+ {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ }
+
+ /*
+ *try to parse pseudo_page
+ */
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token) ;
+
+ if (token->type == DELIM_TK && token->unichar == ':')
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ status = cr_parser_parse_ident (a_this, &page_pseudo_class) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ }
+ else
+ {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ }
+
+ /*
+ *parse_block
+ *
+ */
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == CBO_TK) ;
+
+ cr_token_destroy (token) ; token = NULL ;
+
+ /*
+ *Call the appropriate SAC handler here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->start_page)
+ {
+ PRIVATE (a_this)->sac_handler->start_page
+ (PRIVATE (a_this)->sac_handler,
+ page_selector, page_pseudo_class) ;
+ }
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE ;
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &css_expression) ;
+
+ /*
+ *call the relevant SAC handler here...
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->property)
+ {
+ cr_term_ref (css_expression) ;
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property,
+ css_expression) ;
+ }
+
+ /*
+ *... and free the data structure passed to that last
+ *SAC handler.
+ */
+
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (css_expression)
+ {
+ cr_term_unref (css_expression) ;
+ css_expression = NULL ;
+ }
+
+ for (;;)
+ {
+ /*parse the other ';' separated declarations*/
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token) ;
+
+ ENSURE_PARSING_COND (status == CR_OK && token) ;
+
+ if (token->type != SEMICOLON_TK) break ;
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &css_expression) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ /*
+ *call the relevant SAC handler here...
+ */
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->property)
+ {
+ cr_term_ref (css_expression) ;
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property,
+ css_expression) ;
+ }
+
+ /*
+ *... and free the data structure passed to that last
+ *SAC handler.
+ */
+
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (css_expression)
+ {
+ cr_term_unref (css_expression) ;
+ css_expression = NULL ;
+ }
+ }
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == CBC_TK) ;
+
+ cr_token_destroy (token) ; token = NULL ;
+
+
+ /*
+ *call the relevant SAC handler here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->end_page)
+ {
+ PRIVATE (a_this)->sac_handler->end_page
+ (PRIVATE (a_this)->sac_handler,
+ page_selector, page_pseudo_class) ;
+ }
+
+ if (page_selector)
+ {
+ g_string_free (page_selector, TRUE) ;
+ page_selector = NULL ;
+ }
+
+ if (page_pseudo_class)
+ {
+ g_string_free (page_pseudo_class, TRUE) ;
+ page_pseudo_class = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ /*here goes the former implem of this function ...*/
+
+ cr_parser_clear_errors (a_this) ;
+ PRIVATE (a_this)->state = PAGE_PARSED_STATE ;
+
+ return CR_OK ;
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (page_selector)
+ {
+ g_string_free (page_selector, TRUE) ;
+ page_selector = NULL ;
+ }
+
+ if (page_pseudo_class)
+ {
+ g_string_free (page_pseudo_class, TRUE) ;
+ page_pseudo_class = NULL ;
+ }
+
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (css_expression)
+ {
+ cr_term_destroy (css_expression) ;
+ css_expression = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses the "@font-face" rule specified in the css1 spec in
+ *appendix D.1:
+ *
+ *font_face ::= FONT_FACE_SYM S*
+ *'{' S* declaration [ ';' S* declaration ]* '}' S*
+ *
+ *This function will call SAC handlers whenever it is necessary.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_font_face (CRParser *a_this)
+{
+ enum CRStatus status = CR_ERROR ;
+ CRParserInputPos init_pos ;
+ GString *property = NULL ;
+ CRTerm * css_expression = NULL ;
+ CRToken *token = NULL ;
+ guint32 next_char = 0, cur_char = 0 ;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == FONT_FACE_SYM_TK) ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == CBO_TK) ;
+
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ /*
+ *here, call the relevant SAC handler.
+ */
+
+ if (PRIVATE (a_this)->sac_handler->start_font_face)
+ {
+ PRIVATE (a_this)->sac_handler->start_font_face
+ (PRIVATE (a_this)->sac_handler) ;
+ }
+
+ PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE ;
+
+ /*
+ *and resume the parsing.
+ */
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &css_expression) ;
+
+ if (status == CR_OK)
+ {
+ /*
+ *here, call the relevant SAC handler.
+ */
+ cr_term_ref (css_expression) ;
+
+ if (PRIVATE (a_this)->sac_handler->property)
+ {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, css_expression) ;
+ }
+ ENSURE_PARSING_COND (css_expression && property) ;
+ }
+
+ /*free the data structures allocated during last parsing.*/
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (css_expression)
+ {
+ cr_term_unref (css_expression) ;
+ css_expression = NULL ;
+ }
+
+ for (;;)
+ {
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == ';')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ }
+ else
+ {
+ break ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &css_expression) ;
+
+ if (status != CR_OK) break ;
+
+ /*
+ *here, call the relevant SAC handler.
+ */
+ cr_term_ref (css_expression) ;
+
+ if (PRIVATE (a_this)->sac_handler->property)
+ {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, css_expression) ;
+ }
+
+ /*
+ *Then, free the data structures allocated during
+ *last parsing.
+ */
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (css_expression)
+ {
+ cr_term_unref (css_expression) ;
+ css_expression = NULL ;
+ }
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND (cur_char == '}') ;
+
+ /*
+ *here, call the relevant SAC handler.
+ */
+
+ if (PRIVATE (a_this)->sac_handler->end_font_face)
+ {
+ PRIVATE (a_this)->sac_handler->end_font_face
+ (PRIVATE (a_this)->sac_handler) ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+
+ PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE ;
+
+ return CR_OK ;
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (css_expression)
+ {
+ cr_term_destroy (css_expression) ;
+ css_expression = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses a "ruleset" as defined in the css2 spec at appendix D.1.
+ *ruleset ::= selector [ ',' S* selector ]*
+ *'{' S* declaration? [ ';' S* declaration? ]* '}' S*;
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_ruleset (CRParser *a_this)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ guint32 cur_char = 0, next_char = 0 ;
+ GString * property = NULL ;
+ CRTerm *expr = NULL ;
+ CRSimpleSel * simple_sels = NULL ;
+ CRSelector *selector = NULL ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_parse_simple_sels (a_this, &simple_sels) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ if (simple_sels)
+ {
+ selector = cr_selector_append_simple_sel
+ (selector, simple_sels) ;
+ simple_sels = NULL ;
+ }
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == ',')
+ {
+ for (;;)
+ {
+ simple_sels = NULL ;
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char != ',') break ;
+
+ /*consume the ',' char*/
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+
+ status = cr_parser_parse_simple_sels
+ (a_this, &simple_sels) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ if (simple_sels)
+ {
+ selector =
+ cr_selector_append_simple_sel
+ (selector, simple_sels) ;
+
+ simple_sels = NULL ;
+ }
+ }
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND_ERR
+ (a_this, cur_char == '{',
+ "while parsing rulset: current char should be '{'",
+ CR_SYNTAX_ERROR) ;
+
+
+ if (PRIVATE (a_this)->sac_handler
+ &&PRIVATE (a_this)->sac_handler->start_selector)
+ {
+ /*
+ *the selector if ref counted so that the parser's user
+ *can choose to keep it.
+ */
+ if (selector)
+ {
+ cr_selector_ref (selector) ;
+ }
+
+ PRIVATE (a_this)->sac_handler->start_selector
+ (PRIVATE (a_this)->sac_handler, selector) ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE ;
+
+ status = cr_parser_parse_declaration (a_this, &property, &expr) ;
+
+ if (expr)
+ {
+ cr_term_ref (expr) ;
+ }
+
+ if ( status == CR_OK && PRIVATE (a_this)->sac_handler->property)
+ {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler, property, expr) ;
+ }
+
+ if (status == CR_OK)
+ {
+ /*
+ *free the allocated
+ *'property' and 'term' before parsing
+ *next declarations.
+ */
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (expr)
+ {
+ cr_term_unref (expr) ;
+ expr = NULL ;
+ }
+ }
+
+ CHECK_PARSING_STATUS_ERR
+ (a_this, status, FALSE,
+ "while parsing ruleset: next construction should be a declaration",
+ CR_SYNTAX_ERROR) ;
+
+ for (;;)
+ {
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+ if (next_char != ';') break ;
+
+ /*consume the ';' char*/
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &expr) ;
+
+ if (expr)
+ {
+ cr_term_ref (expr) ;
+ }
+
+ if (status == CR_OK &&
+ PRIVATE (a_this)->sac_handler->property)
+ {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, expr) ;
+ }
+
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ property = NULL ;
+ }
+
+ if (expr)
+ {
+ cr_term_unref (expr) ;
+ expr = NULL ;
+ }
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND_ERR
+ (a_this, cur_char == '}',
+ "while parsing rulset: current char must be a '}'",
+ CR_SYNTAX_ERROR) ;
+
+ if (PRIVATE (a_this)->sac_handler->end_selector)
+ {
+ PRIVATE (a_this)->sac_handler->end_selector
+ (PRIVATE (a_this)->sac_handler, selector) ;
+ }
+
+ if (expr)
+ {
+ cr_term_unref (expr) ;
+ expr = NULL ;
+ }
+
+ if (simple_sels)
+ {
+ cr_simple_sel_destroy (simple_sels) ;
+ simple_sels = NULL ;
+ }
+
+ if (selector)
+ {
+ cr_selector_unref (selector) ;
+ selector = NULL ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ PRIVATE (a_this)->state = RULESET_PARSED_STATE ;
+
+ return CR_OK ;
+
+ error:
+
+ if (expr)
+ {
+ cr_term_unref (expr) ;
+ expr = NULL ;
+ }
+
+ if (simple_sels)
+ {
+ cr_simple_sel_destroy (simple_sels) ;
+ simple_sels = NULL ;
+ }
+
+ if (property)
+ {
+ g_string_free (property, TRUE) ;
+ }
+
+ if (selector)
+ {
+ cr_selector_unref (selector) ;
+ selector = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a "function" as defined in css spec at appendix D.1:
+ *function ::= FUNCTION S* expr ')' S*
+ *FUNCTION ::= ident'('
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser.
+ *
+ *@param a_func_name out parameter. The parsed function name
+ *@param a_expr out parameter. The successfully parsed term.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_function (CRParser *a_this, GString **a_func_name,
+ CRTerm **a_expr)
+{
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+ CRToken *token = NULL ;
+ CRTerm *expr = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_func_name,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status != CR_OK) goto error ;
+
+ if (token && token->type == FUNCTION_TK)
+ {
+ *a_func_name = token->str ;
+ token->str = NULL ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status != CR_OK) goto error ;
+
+ ENSURE_PARSING_COND (token && token->type == PO_TK) ;
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ status = cr_parser_parse_term (a_this, &expr) ;
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ if (status != CR_OK) goto error ;
+
+ ENSURE_PARSING_COND (token && token->type == PC_TK) ;
+
+ cr_token_destroy (token) ;
+ token = NULL ;
+
+ if (expr)
+ {
+ *a_expr = cr_term_append_term (*a_expr, expr) ;
+ expr = NULL ;
+ }
+
+ cr_parser_clear_errors (a_this) ;
+ return CR_OK ;
+
+ error:
+
+ if (*a_func_name)
+ {
+ g_string_free (*a_func_name, TRUE) ;
+ *a_func_name = NULL ;
+ }
+
+ if (expr)
+ {
+ cr_term_destroy (expr) ;
+ expr = NULL ;
+ }
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos) ;
+
+ return status ;
+}
+
+
+
+
+/**
+ *Parses an uri as defined by the css spec [4.1.1]:
+ * URI ::= url\({w}{string}{w}\)
+ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
+ *
+ *@param a_this the current instance of #CRParser.
+ *@param a_str the successfully parsed url.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_uri (CRParser *a_this, GString **a_str)
+{
+
+ enum CRStatus status = CR_PARSING_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr,
+ CR_BAD_PARAM_ERROR) ;
+
+
+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+ URI_TK, NO_ET, a_str, NULL) ;
+ return status ;
+}
+
+
+/**
+ *Parses a string type as defined in css spec [4.1.1]:
+ *
+ *string ::= {string1}|{string2}
+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
+ *
+ *@param a_this the current instance of #CRParser.
+ *@param a_start out parameter. Upon successfull completion,
+ *points to the beginning of the string, points to an undefined value
+ *otherwise.
+ *@param a_end out parameter. Upon successfull completion, points to
+ *the beginning of the string, points to an undefined value otherwise.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_string (CRParser *a_this, GString **a_str)
+{
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr
+ && a_str,
+ CR_BAD_PARAM_ERROR) ;
+
+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+ STRING_TK, NO_ET, a_str, NULL) ;
+ return status ;
+}
+
+/**
+ *Parses an "ident" as defined in css spec [4.1.1]:
+ *ident ::= {nmstart}{nmchar}*
+ *
+ *@param a_this the currens instance of #CRParser.
+ *
+ *@param a_str a pointer to parsed ident. If *a_str is NULL,
+ *this function allocates a new instance of GString. If not,
+ *the function just appends the parsed string to the one passed.
+ *In both cases it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_ident (CRParser *a_this, GString **a_str)
+{
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr
+ && a_str,
+ CR_BAD_PARAM_ERROR) ;
+
+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+ IDENT_TK, NO_ET, a_str, NULL) ;
+ return status ;
+}
+
+/**
+ *Parses a stylesheet as defined in the css2 spec in appendix D.1:
+ *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]?
+ * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
+ * [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]*
+ *
+ *TODO: Finish the code of this function. Think about splitting it into
+ *smaller functions.
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param a_start out parameter. A pointer to the first character of
+ *the successfully parsed string.
+ *@param a_end out parameter. A pointer to the first character of
+ *the successfully parsed string.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_stylesheet (CRParser *a_this)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ CRToken * token = NULL ;
+ GString *charset = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PRIVATE (a_this)->state = READY_STATE ;
+
+ if (PRIVATE (a_this)->sac_handler->start_document)
+ {
+ PRIVATE (a_this)->sac_handler->start_document
+ (PRIVATE (a_this)->sac_handler) ;
+ }
+
+/* parse_charset:*/
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+
+ if (status == CR_END_OF_INPUT_ERROR) goto done ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+
+ if (token && token->type == CHARSET_SYM_TK)
+ {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token = NULL ;
+
+ status = cr_parser_parse_charset (a_this, &charset) ;
+
+ if (status == CR_OK && charset)
+ {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->charset)
+ {
+ PRIVATE (a_this)->sac_handler->charset
+ (PRIVATE (a_this)->sac_handler,
+ charset) ;
+ }
+ }
+ else if (status != CR_END_OF_INPUT_ERROR)
+ {
+ status = cr_parser_parse_atrule_core (a_this) ;
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ }
+
+ if (charset)
+ {
+ g_string_free (charset, TRUE) ;
+ charset = NULL ;
+ }
+ }
+ else if (token
+ && (token->type == S_TK || token->type == COMMENT_TK))
+ {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+ }
+ else if (token)
+ {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ }
+
+
+/* parse_imports:*/
+ do
+ {
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token) ;
+
+ if (status == CR_END_OF_INPUT_ERROR) goto done ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ } while (token
+ && (token->type == S_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK)) ;
+
+ if (token)
+ {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token) ;
+ token = NULL ;
+ }
+
+ for (;;)
+ {
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token) ;
+ if (status == CR_END_OF_INPUT_ERROR) goto done ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+
+ if (token && token->type == IMPORT_SYM_TK)
+ {
+ GList *media_list = NULL ;
+ GString *import_string = NULL ;
+
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+
+ status = cr_parser_parse_import (a_this,
+ &media_list,
+ &import_string) ;
+
+ if (status == CR_OK)
+ {
+ if (import_string
+ && PRIVATE
+ (a_this)->sac_handler->import_style)
+ {
+ PRIVATE (a_this)->
+ sac_handler->import_style
+ (PRIVATE (a_this)->
+ sac_handler,
+ media_list,
+ import_string,
+ NULL) ;
+ }
+ }
+ else if (status != CR_END_OF_INPUT_ERROR)
+ {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->
+ error)
+ {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE
+ (a_this)->sac_handler) ;
+ }
+
+ status = cr_parser_parse_atrule_core
+ (a_this) ;
+ }
+
+ /*
+ *then, after calling the appropriate
+ *SAC handler, free
+ *the media_list and import_string.
+ */
+ if (media_list)
+ {
+ GList * cur = NULL ;
+
+ /*free the medium list*/
+ for (cur = media_list ;
+ cur ; cur = cur->next)
+ {
+ if (cur->data)
+ {
+ g_string_free
+ (cur->data,
+ TRUE) ;
+ }
+ }
+
+ g_list_free (media_list) ;
+ media_list = NULL ;
+ }
+
+ if (import_string)
+ {
+ g_string_free (import_string,
+ TRUE) ;
+ import_string = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+ }
+ else if (token
+ && (token->type == S_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK))
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+
+ do
+ {
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto done ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ } while (token
+ && (token->type == S_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK)) ;
+ }
+ else
+ {
+ if (token)
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ }
+ goto parse_ruleset_and_others ;
+ }
+ }
+
+ parse_ruleset_and_others:
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ for (;;)
+ {
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token) ;
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto done ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+
+ if (token
+ && (token->type == S_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK))
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+
+ do
+ {
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+ }while (token
+ && (token->type == S_TK
+ || token->type == COMMENT_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK)) ;
+ if (token)
+ {
+ cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ token = NULL ;
+ }
+ }
+ else if (token
+ && (token->type == HASH_TK
+ || (token->type == DELIM_TK
+ && token->unichar == '.')
+ || (token->type == DELIM_TK
+ && token->unichar == ':')
+ || (token->type == DELIM_TK
+ && token->unichar == '*')
+ || token->type == IDENT_TK))
+ {
+ /*
+ *Try to parse a CSS2 ruleset.
+ *if the parsing fails, try to parse
+ *a css core ruleset.
+ */
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token = NULL ;
+
+ status = cr_parser_parse_ruleset (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->
+ error)
+ {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE
+ (a_this)->sac_handler) ;
+ }
+
+ status = cr_parser_parse_ruleset_core
+ (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+ }
+ else if (token && token->type == MEDIA_SYM_TK)
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token = NULL ;
+
+ status = cr_parser_parse_media (a_this) ;
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->
+ error)
+ {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE
+ (a_this)->sac_handler) ;
+ }
+
+ status = cr_parser_parse_atrule_core
+ (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+
+ }
+ else if (token && token->type == PAGE_SYM_TK)
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token = NULL ;
+ status = cr_parser_parse_page (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->
+ error)
+ {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE
+ (a_this)->sac_handler) ;
+ }
+
+ status = cr_parser_parse_atrule_core
+ (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+ }
+ else if (token && token->type == FONT_FACE_SYM_TK)
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token = NULL ;
+ status = cr_parser_parse_font_face (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->
+ error)
+ {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE
+ (a_this)->sac_handler) ;
+ }
+
+ status = cr_parser_parse_atrule_core
+ (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+ }
+ else
+ {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ token = NULL ;
+ status = cr_parser_parse_statement_core
+ (a_this) ;
+
+ if (status == CR_OK)
+ {
+ continue ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+ }
+
+ done:
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (status == CR_END_OF_INPUT_ERROR
+ || status == CR_OK)
+ {
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->end_document)
+ {
+ PRIVATE (a_this)->sac_handler->end_document
+ (PRIVATE (a_this)->sac_handler) ;
+ }
+
+ return CR_OK ;
+ }
+
+ cr_parser_push_error
+ (a_this, "could not recognize next production",
+ CR_ERROR) ;
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->
+ unrecoverable_error)
+ {
+ PRIVATE (a_this)->sac_handler->
+ unrecoverable_error
+ (PRIVATE
+ (a_this)->sac_handler) ;
+ }
+
+ cr_parser_dump_err_stack (a_this, TRUE) ;
+
+ return status ;
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->
+ unrecoverable_error)
+ {
+ PRIVATE (a_this)->sac_handler->
+ unrecoverable_error
+ (PRIVATE
+ (a_this)->sac_handler) ;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
+ &init_pos) ;
+
+ return status ;
+}
+
+
+/****************************************
+ *Public CRParser Methods
+ ****************************************/
+
+/**
+ *Creates a new parser to parse data
+ *coming the input stream given in parameter.
+ *@param a_input the input stream of the parser.
+ *Note that the newly created parser will ref
+ *a_input and unref it when parsing reaches the
+ *end of the input stream.
+ *@return the newly created instance of #CRParser,
+ *or NULL if an error occured.
+ */
+CRParser *
+cr_parser_new (CRTknzr *a_tknzr)
+{
+ CRParser * result = NULL ;
+ enum CRStatus status = CR_OK ;
+
+ result = g_malloc0 (sizeof (CRParserInput)) ;
+
+ PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv)) ;
+
+ if (a_tknzr)
+ {
+ status = cr_parser_set_tknzr (result, a_tknzr) ;
+ }
+
+ g_return_val_if_fail (status == CR_OK, NULL) ;
+
+ return result ;
+}
+
+
+CRParser *
+cr_parser_new_from_input (CRParserInput *a_input)
+{
+ CRParser *result = NULL ;
+ CRTknzr *tokenizer = NULL ;
+
+ if (a_input)
+ {
+ tokenizer = cr_tknzr_new (a_input) ;
+ g_return_val_if_fail (tokenizer, NULL) ;
+ }
+
+ result = cr_parser_new (tokenizer) ;
+ g_return_val_if_fail (result, NULL) ;
+
+ return result ;
+}
+
+
+CRParser *
+cr_parser_new_from_file (guchar *a_file_uri,
+ enum CREncoding a_enc)
+{
+ CRParser *result = NULL ;
+ CRTknzr *tokenizer = NULL ;
+
+ tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc) ;
+ if (!tokenizer)
+ {
+ cr_utils_trace_info ("Could not open input file") ;
+ return NULL ;
+ }
+
+ result = cr_parser_new (tokenizer) ;
+ g_return_val_if_fail (result, NULL) ;
+ return result ;
+}
+
+
+/**
+ *Sets a SAC document handler to the parser.
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param a_handler the handler to set.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_sac_handler (CRParser *a_this, CRDocHandler *a_handler)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->sac_handler)
+ {
+ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler) ;
+ }
+
+ PRIVATE (a_this)->sac_handler = a_handler ;
+ cr_doc_handler_ref (a_handler) ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Gets the SAC document handler.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser.
+ *@param a_handler out parameter. The returned handler.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parser_get_sac_handler (CRParser *a_this, CRDocHandler **a_handler)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ *a_handler = PRIVATE (a_this)->sac_handler ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the SAC handler associated to the current instance
+ *of #CRParser to the default SAC handler.
+ *@param a_this a pointer to the current instance of #CRParser.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_default_sac_handler (CRParser *a_this)
+{
+ CRDocHandler *default_sac_handler = NULL ;
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ default_sac_handler = cr_doc_handler_new () ;
+
+ cr_doc_handler_set_default_sac_handler (default_sac_handler) ;
+
+ status = cr_parser_set_sac_handler (a_this, default_sac_handler) ;
+
+ if (status != CR_OK)
+ {
+ cr_doc_handler_destroy (default_sac_handler) ;
+ default_sac_handler = NULL ;
+ }
+
+ return status ;
+}
+
+
+enum CRStatus
+cr_parser_set_use_core_grammar (CRParser *a_this,
+ gboolean a_use_core_grammar)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->use_core_grammar = a_use_core_grammar ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_parser_get_use_core_grammar (CRParser *a_this,
+ gboolean *a_use_core_grammar)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Parses the data that comes from the
+ *input previously associated to the current instance of
+ *#CRParser.
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK ;
+ */
+enum CRStatus
+cr_parser_parse (CRParser *a_this)
+{
+ enum CRStatus status = CR_ERROR ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->use_core_grammar == FALSE)
+ {
+ status = cr_parser_parse_stylesheet (a_this) ;
+ }
+ else
+ {
+ status = cr_parser_parse_stylesheet_core (a_this) ;
+ }
+
+ return status ;
+}
+
+
+enum CRStatus
+cr_parser_set_tknzr (CRParser *a_this, CRTknzr *a_tknzr)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->tknzr)
+ {
+ cr_tknzr_unref (PRIVATE (a_this)->tknzr) ;
+ }
+
+ PRIVATE (a_this)->tknzr = a_tknzr ;
+
+ if (a_tknzr)
+ cr_tknzr_ref (a_tknzr) ;
+
+ return CR_OK ;
+}
+
+
+
+
+/**
+ *Parses a the given in parameter.
+ *@param a_this a pointer to the current instance of #CRParser.
+ *@param a_file_uri the uri to the file to load. For the time being,
+ *only local files are supported.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_from_file (CRParser *a_this, guchar *a_file_uri,
+ enum CREncoding a_enc)
+{
+ enum CRStatus status = CR_ERROR ;
+ CRTknzr *tknzr = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_file_uri,
+ CR_BAD_PARAM_ERROR) ;
+
+ tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc) ;
+
+ g_return_val_if_fail (tknzr != NULL, CR_ERROR) ;
+
+ status = cr_parser_set_tknzr (a_this, tknzr) ;
+ g_return_val_if_fail (status == CR_OK, CR_ERROR) ;
+
+ status = cr_parser_parse (a_this) ;
+
+ return status ;
+}
+
+
+/**
+ *Destroys the current instance
+ *of #CRParser.
+ *@param a_this the current instance of #CRParser to
+ *destroy.
+ */
+void
+cr_parser_destroy (CRParser *a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)) ;
+
+
+ if (PRIVATE (a_this)->tknzr)
+ {
+ if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE)
+ PRIVATE (a_this)->tknzr = NULL ;
+ }
+
+ if (PRIVATE (a_this)->sac_handler)
+ {
+ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler) ;
+ PRIVATE (a_this)->sac_handler = NULL ;
+ }
+
+ if (PRIVATE (a_this)->err_stack)
+ {
+ cr_parser_clear_errors (a_this);
+ PRIVATE (a_this)->err_stack = NULL ;
+ }
+
+ if (PRIVATE (a_this))
+ {
+ g_free (PRIVATE (a_this)) ;
+ PRIVATE (a_this) = NULL ;
+ }
+
+ if (a_this)
+ {
+ g_free (a_this) ;
+ a_this = NULL ;/*useless. Just for the sake of coherence*/
+ }
+}
diff --git a/src/cr-parser.h b/src/cr-parser.h
new file mode 100644
index 0000000..2de3506
--- /dev/null
+++ b/src/cr-parser.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+
+/*
+ *$Id$
+ */
+#ifndef __CR_PARSER_H__
+#define __CR_PARSER_H__
+
+#include <glib.h>
+#include "cr-parser-input.h"
+#include "cr-tknzr.h"
+#include "cr-utils.h"
+#include "cr-doc-handler.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration file
+ *of the #CRParser class.
+ */
+typedef struct _CRParser CRParser ;
+typedef struct _CRParserPriv CRParserPriv ;
+
+
+/**
+ *The implementation of
+ *the SAC parser.
+ *The Class is opaque
+ *and must be manipulated through
+ *the provided methods.
+ */
+struct _CRParser
+{
+ CRParserPriv *priv ;
+} ;
+
+CRParser *
+cr_parser_new (CRTknzr *a_tknzr) ;
+
+CRParser *
+cr_parser_new_from_file (guchar *a_file_uril,
+ enum CREncoding a_enc) ;
+
+CRParser *
+cr_parser_new_from_input (CRParserInput *a_input) ;
+
+enum CRStatus
+cr_parser_set_tknzr (CRParser *a_this, CRTknzr *a_tknzr) ;
+
+
+enum CRStatus
+cr_parser_set_sac_handler (CRParser *a_this,
+ CRDocHandler *a_handler) ;
+
+enum CRStatus
+cr_parser_get_sac_handler (CRParser *a_this,
+ CRDocHandler **a_handler) ;
+enum CRStatus
+cr_parser_set_use_core_grammar (CRParser *a_this,
+ gboolean a_use_core_grammar) ;
+enum CRStatus
+cr_parser_get_use_core_grammar (CRParser *a_this,
+ gboolean *a_use_core_grammar) ;
+
+enum CRStatus
+cr_parser_parse (CRParser *a_this) ;
+
+enum CRStatus
+cr_parser_parse_from_file (CRParser *a_this, guchar *a_file_uri,
+ enum CREncoding a_enc) ;
+
+enum CRStatus
+cr_parser_set_default_sac_handler (CRParser *a_this) ;
+
+void
+cr_parser_destroy (CRParser *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_PARSER_H__*/
diff --git a/src/cr-pseudo.c b/src/cr-pseudo.c
new file mode 100644
index 0000000..717fbb9
--- /dev/null
+++ b/src/cr-pseudo.c
@@ -0,0 +1,132 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include "cr-pseudo.h"
+
+/**
+ *@file
+ *The definition of the #CRPseudo class.
+ */
+
+/**
+ *Constructor of the #CRPseudo class.
+ *@return the newly build instance.
+ */
+CRPseudo *
+cr_pseudo_new (void)
+{
+ CRPseudo * result = NULL ;
+
+ result = g_malloc0 (sizeof (CRPseudo)) ;
+
+ return result ;
+}
+
+/**
+ *Dumps the pseudo to a file.
+ *@param a_this the current instance of pseudo
+ *@param a_fp the destination file pointer.
+ */
+void
+cr_pseudo_dump (CRPseudo *a_this, FILE *a_fp)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->type == IDENT_PSEUDO)
+ {
+ guchar * name = NULL ;
+
+ if (a_this->name == NULL)
+ return ;
+
+ name = g_strndup (a_this->name->str,
+ a_this->name->len) ;
+ if (name)
+ {
+ fprintf (a_fp,"%s", name) ;
+ g_free (name) ;
+ name = NULL ;
+ }
+ }
+ else if (a_this->type == FUNCTION_PSEUDO)
+ {
+ guchar * name = NULL, *arg = NULL ;
+
+ if (a_this->name == NULL)
+ return ;
+
+ name = g_strndup (a_this->name->str,
+ a_this->name->len) ;
+ if (a_this->extra)
+ {
+ arg = g_strndup (a_this->extra->str,
+ a_this->extra->len) ;
+ }
+
+ if (name)
+ {
+ fprintf (a_fp,"%s(", name) ;
+ g_free (name) ;
+ name = NULL ;
+
+ if (arg)
+ {
+ fprintf (a_fp,arg) ;
+ g_free (arg) ;
+ arg = NULL ;
+ }
+
+ fprintf (a_fp,")") ;
+ }
+ }
+}
+
+/**
+ *destructor of the #CRPseudo class.
+ *@param a_this the current instance to destroy.
+ */
+void
+cr_pseudo_destroy (CRPseudo *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->name)
+ {
+ g_string_free (a_this->name, TRUE) ;
+ a_this->name = NULL ;
+ }
+
+ if (a_this->extra)
+ {
+ g_string_free (a_this->extra, TRUE) ;
+ a_this->extra = NULL ;
+ }
+
+ g_free (a_this) ;
+}
diff --git a/src/cr-pseudo.h b/src/cr-pseudo.h
new file mode 100644
index 0000000..7719d82
--- /dev/null
+++ b/src/cr-pseudo.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_PSEUDO_H__
+#define __CR_PSEUDO_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-attr-sel.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ enum CRPseudoType
+ {
+ IDENT_PSEUDO = 0,
+ FUNCTION_PSEUDO
+ } ;
+
+ typedef struct _CRPseudo CRPseudo ;
+
+ /**
+ *The CRPseudo Class.
+ *Abstract a "pseudo" as defined by the css2 spec
+ *in appendix D.1 .
+ */
+ struct _CRPseudo
+ {
+ enum CRPseudoType type ;
+ GString *name ;
+ GString *extra ;
+ } ;
+
+ CRPseudo *
+ cr_pseudo_new (void) ;
+
+ void
+ cr_pseudo_dump (CRPseudo *a_this, FILE *a_fp) ;
+
+ void
+ cr_pseudo_destroy (CRPseudo *a_this) ;
+
+#ifdef __cplusplus
+} /*extern "C" {*/
+#endif
+
+#endif /*__CR_PSEUDO_H__*/
diff --git a/src/cr-rgb.c b/src/cr-rgb.c
new file mode 100644
index 0000000..8318bfc
--- /dev/null
+++ b/src/cr-rgb.c
@@ -0,0 +1,142 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "cr-rgb.h"
+
+/**
+ *The default constructor of #CRRgb.
+ *@return the newly built instance of #CRRgb
+ */
+CRRgb *
+cr_rgb_new (void)
+{
+ CRRgb *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRRgb)) ;
+
+ if (result == NULL)
+ {
+ cr_utils_trace_info ("No more memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRRgb)) ;
+
+ return result ;
+}
+
+
+/**
+ *A constructor of #CRRgb.
+ *@param a_red the red component of the color.
+ *@param a_green the green component of the color.
+ *@param a_blue the blue component of the color.
+ *@param a_unit the unit of the rgb values.
+ *(either percentage or integer values)
+ *@return the newly built instance of #CRRgb.
+ */
+CRRgb *
+cr_rgb_new_with_vals (glong a_red, glong a_green,
+ glong a_blue, enum TermUnit a_unit)
+{
+ CRRgb *result = NULL ;
+
+ result = cr_rgb_new () ;
+
+ g_return_val_if_fail (result, NULL) ;
+
+ result->red = a_red ;
+ result->green = a_green ;
+ result->blue = a_blue ;
+
+ if (a_unit == UNIT_PERCENTAGE)
+ {
+ result->unit = UNIT_PERCENTAGE ;
+ }
+ else
+ {
+ result->unit = NO_UNIT ;
+ }
+
+ return result ;
+}
+
+
+/**
+ *Dumps the current instance of #CRRgb
+ *to a file.
+ *@param a_this the "this pointer" of
+ *the current instance of #CRRgb.
+ *@param a_fp the destination file pointer.
+ */
+void
+cr_rgb_dump (CRRgb *a_this, FILE *a_fp)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->unit == UNIT_PERCENTAGE)
+ {
+ fprintf (a_fp,"%ld", a_this->red) ;
+ fputc ('%', a_fp) ;
+ fprintf (a_fp,", ") ;
+
+ fprintf (a_fp,"%ld", a_this->green) ;
+ fputc ('%', a_fp) ; ;
+ fprintf (a_fp,", ") ;
+
+ fprintf (a_fp,"%ld", a_this->blue) ;
+ fputc ('%', a_fp) ;
+ }
+ else
+ {
+ fprintf (a_fp,"%ld", a_this->red) ;
+ fprintf (a_fp,", ") ;
+
+ fprintf (a_fp,"%ld", a_this->green) ;
+ fprintf (a_fp,", ") ;
+
+ fprintf (a_fp,"%ld", a_this->blue) ;
+ }
+}
+
+/**
+ *Destructor of #CRRgb.
+ *@param a_this the "this pointer" of the
+ *current instance of #CRRgb.
+ */
+void
+cr_rgb_destroy (CRRgb *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ g_free (a_this) ;
+}
diff --git a/src/cr-rgb.h b/src/cr-rgb.h
new file mode 100644
index 0000000..2bfc9cd
--- /dev/null
+++ b/src/cr-rgb.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+
+#ifndef __CR_RGB_H__
+#define __CR_RGB_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ typedef struct _CRRgb CRRgb ;
+ struct _CRRgb
+ {
+ /*
+ *the unit of the rgb.
+ *Either NO_UNIT (integer) or
+ *UNIT_PERCENTAGE (percentage).
+ */
+ enum TermUnit unit ;
+ glong red ;
+ glong green ;
+ glong blue ;
+ } ;
+
+ CRRgb *
+ cr_rgb_new (void) ;
+
+ CRRgb *
+ cr_rgb_new_with_vals (glong a_red, glong a_green,
+ glong a_blue, enum TermUnit a_unit) ;
+ void
+ cr_rgb_dump (CRRgb *a_this, FILE *a_fp) ;
+
+ void
+ cr_rgb_destroy (CRRgb *a_this) ;
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*__CR_RGB_H__*/
diff --git a/src/cr-sel-eng.c b/src/cr-sel-eng.c
new file mode 100644
index 0000000..331b3a9
--- /dev/null
+++ b/src/cr-sel-eng.c
@@ -0,0 +1,352 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+#include <string.h>
+#include "cr-sel-eng.h"
+
+/**
+ *@file:
+ *The definition of the #CRSelEng class.
+ *The #CRSelEng is actually the "Selection Engine"
+ *class.
+ */
+#ifdef WITH_SELENG
+
+#define PRIVATE(a_this) (a_this)->priv
+
+static gboolean
+class_add_sel_matches_node (CRAdditionalSel *a_add_sel,
+ xmlNode *a_node) ;
+
+static gboolean
+id_add_sel_matches_node (CRAdditionalSel *a_add_sel,
+ xmlNode *a_node) ;
+
+static gboolean
+attr_add_sel_matches_node (CRAdditionalSel *a_add_sel,
+ xmlNode *a_node) ;
+
+static gboolean
+class_add_sel_matches_node (CRAdditionalSel *a_add_sel,
+ xmlNode *a_node)
+{
+ gboolean result = FALSE ;
+ xmlChar *class = NULL ;
+
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == CLASS_ADD_SELECTOR
+ && a_add_sel->content.class_name
+ && a_add_sel->content.class_name->str
+ && a_node, FALSE) ;
+
+ if (xmlHasProp (a_node, "class"))
+ {
+ class = xmlGetProp (a_node, "class") ;
+ if (!strncmp (class, a_add_sel->content.class_name->str,
+ a_add_sel->content.class_name->len))
+ {
+ result = TRUE ;
+ }
+ }
+
+ if (class)
+ {
+ xmlFree (class) ;
+ class = NULL ;
+ }
+ return result ;
+
+}
+
+static gboolean
+id_add_sel_matches_node (CRAdditionalSel *a_add_sel,
+ xmlNode *a_node)
+{
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == ID_ADD_SELECTOR
+ && a_add_sel->content.id_name
+ && a_add_sel->content.id_name->str
+ && a_node, FALSE) ;
+
+ gboolean result = FALSE ;
+ xmlChar *id = NULL ;
+
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == ID_ADD_SELECTOR
+ && a_node, FALSE) ;
+
+ if (xmlHasProp (a_node, "id"))
+ {
+ id = xmlGetProp (a_node, "id") ;
+ if (!strncmp (id, a_add_sel->content.id_name->str,
+ a_add_sel->content.id_name->len))
+ {
+ result = TRUE ;
+ }
+ }
+
+ if (id)
+ {
+ xmlFree (id) ;
+ id = NULL ;
+ }
+ return result ;
+}
+
+
+static gboolean
+attr_add_sel_matches_node (CRAdditionalSel *a_add_sel,
+ xmlNode *a_node)
+{
+ CRAttrSel *cur_sel = NULL ;
+
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == ATTRIBUTE_ADD_SELECTOR
+ && a_node, FALSE) ;
+
+ for (cur_sel = a_add_sel->content.attr_sel ;
+ cur_sel ; cur_sel = cur_sel->next)
+ {
+ switch (cur_sel->match_way)
+ {
+ case SET:
+ if (!cur_sel->name || !cur_sel->name->str)
+ return FALSE ;
+
+ if (!xmlHasProp (a_node, cur_sel->name->str))
+ return FALSE ;
+ break ;
+
+ case EQUALS:
+ {
+ xmlChar *value = NULL ;
+
+ if (!cur_sel->name || !cur_sel->name->str
+ || !cur_sel->value || !cur_sel->value->str)
+ return FALSE ;
+
+ if (!xmlHasProp (a_node, cur_sel->name->str))
+ return FALSE ;
+
+ value = xmlGetProp (a_node, cur_sel->name->str) ;
+
+ if (value && strncmp (value, cur_sel->value->str,
+ cur_sel->value->len))
+ {
+ xmlFree (value) ;
+ return FALSE ;
+ }
+ xmlFree (value);
+ }
+ break ;
+
+ case INCLUDES:
+ {
+ xmlChar *value = NULL ;
+
+ if (!xmlHasProp (a_node, cur_sel->name->str))
+ return FALSE ;
+ value = xmlGetProp (a_node, cur_sel->name->str) ;
+
+ /*
+ *here, make sure value is a space
+ *separated list of "words", where one
+ *value is exactly cur_sel->value->str
+ */
+
+ xmlFree (value) ;
+ }
+ break ;
+ case DASHMATCH:
+ {
+ xmlChar *value = NULL ;
+
+ if (!xmlHasProp (a_node, cur_sel->name->str))
+ return FALSE ;
+ value = xmlGetProp (a_node, cur_sel->name->str) ;
+
+ /*
+ *here, make sure value is an hyphen
+ *separated list of "words", each of which
+ *starting with "cur_sel->value->str"
+ */
+
+
+ xmlFree (value) ;
+ }
+ break ;
+ default:
+ return FALSE ;
+ }
+ }
+
+ return TRUE ;
+}
+
+struct _CRSelEngPriv
+{
+
+};
+
+
+
+/**
+ *Creates a new instance of #CRSelEng.
+ *@return the newly built instance of #CRSelEng of
+ *NULL if an error occurs.
+ */
+CRSelEng *
+cr_sel_eng_new (void)
+{
+ CRSelEng *result ;
+
+ result = g_try_malloc (sizeof (CRSelEng)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (CRSelEng)) ;
+ return result ;
+}
+
+
+/**
+ *Evaluates a chained list of simple selectors (known as a css2 selector).
+ *Says wheter if this selector matches the xml node given in parameter or
+ *not.
+ */
+enum CRStatus
+cr_sel_eng_sel_matches_node (CRSelEng *a_this, CRSimpleSel *a_sel,
+ xmlNode *a_node, gboolean *a_result)
+{
+ CRSimpleSel *cur_sel = NULL ;
+ xmlNode *cur_node = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_this && a_node
+ && a_node->type == XML_ELEMENT_NODE
+ && a_result,
+ CR_BAD_PARAM_ERROR) ;
+
+ /*go and get the last simple selector of the list*/
+ for (cur_sel = a_sel ;
+ cur_sel && cur_sel->next ;
+ cur_sel = cur_sel->next) ;
+
+ for (; cur_sel ; cur_sel = cur_sel->prev)
+ {
+
+ if (cur_sel->type_mask & UNIVERSAL_SELECTOR)
+ {
+ return TRUE ;
+ }
+ else if (cur_sel->type_mask & TYPE_SELECTOR)
+ {
+ if (cur_sel && cur_sel->name && cur_sel->name->str)
+ {
+ if (!strcmp (cur_sel->name->str,
+ cur_node->name))
+ {
+ return TRUE ;
+ }
+ goto walk_a_step_in_expr ;
+ }
+ else
+ {
+ return FALSE ;
+ }
+ }
+
+ if (!cur_sel->add_sel)
+ return FALSE ;
+
+ if (cur_sel->add_sel->type == NO_ADD_SELECTOR)
+ return FALSE ;
+
+ if (cur_sel->add_sel->type == CLASS_ADD_SELECTOR
+ && cur_sel->add_sel->content.class_name
+ && cur_sel->add_sel->content.class_name->str)
+ {
+ if (class_add_sel_matches_node
+ (cur_sel->add_sel, a_node) == FALSE)
+ return FALSE ;
+ goto walk_a_step_in_expr ;
+ }
+ else if (cur_sel->add_sel->type == ID_ADD_SELECTOR
+ && cur_sel->add_sel->content.id_name
+ && cur_sel->add_sel->content.id_name->str)
+ {
+ if (id_add_sel_matches_node
+ (cur_sel->add_sel, a_node) == FALSE)
+ return FALSE ;
+ goto walk_a_step_in_expr ;
+
+ }
+ else if (cur_sel->add_sel->type == ATTRIBUTE_ADD_SELECTOR
+ && cur_sel->add_sel->content.attr_sel)
+ {
+
+ /*
+ *here, call a function that does the match
+ *against an attribute additionnal selector
+ *and a list of attribute xml node.
+ */
+ }
+
+ walk_a_step_in_expr:
+ continue ;
+ /*
+ *here, depending on the combinator of cur_sel
+ *choose the axis of the xml tree traversing
+ *and walk one step in the xml tree.
+ */
+ }
+
+ return TRUE ;
+}
+
+/**
+ *The destructor of #CRSelEng
+ *@param a_this the current instance of the selection engine.
+ */
+void
+cr_sel_eng_destroy (CRSelEng *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ if (PRIVATE (a_this))
+ {
+ g_free (PRIVATE (a_this)) ;
+ PRIVATE (a_this) = NULL ;
+ }
+
+ if (a_this)
+ {
+ g_free (a_this) ;
+ }
+}
+
+#endif /*WITH_SELENG*/
diff --git a/src/cr-sel-eng.h b/src/cr-sel-eng.h
new file mode 100644
index 0000000..72c744d
--- /dev/null
+++ b/src/cr-sel-eng.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+#ifndef __CR_SEL_ENG_H__
+#define __CR_SEL_ENG_H__
+
+#include "cr-utils.h"
+#include "cr-simple-sel.h"
+
+#ifdef HAVE_LIBXML2
+ #include <libxml/tree.h>
+#endif
+
+#ifdef WITH_SELENG
+
+
+/**
+ *@file:
+ *The declaration of the #CRSelEng class.
+ *The #CRSelEng is actually the "Selection Engine"
+ *class.
+ */
+
+G_BEGIN_DECLS
+
+typedef struct _CRSelEng CRSelEng ;
+typedef struct _CRSelEngPriv CRSelEngPriv ;
+
+/**
+ *The Selection engine class.
+ *The main service provided by this class, is
+ *the ability to interpret a libcroco implementation
+ *of css2 selectors, and given an xml node, say if
+ *the selector matches the node or not.
+ */
+struct _CRSelEng
+{
+ CRSelEngPriv *priv ;
+} ;
+
+CRSelEng *
+cr_sel_eng_new (void) ;
+
+enum CRStatus
+cr_sel_eng_sel_matches_node (CRSelEng *a_this, CRSimpleSel *a_sel,
+ xmlNode *a_node, gboolean *a_result) ;
+void
+cr_sel_eng_destroy (CRSelEng *a_this) ;
+
+G_END_DECLS
+
+#endif /*WITH_SELENG*/
+
+#endif/*__CR_SEL_ENG_H__*/
diff --git a/src/cr-selector.c b/src/cr-selector.c
new file mode 100644
index 0000000..a602302
--- /dev/null
+++ b/src/cr-selector.c
@@ -0,0 +1,242 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+#include <string.h>
+#include "cr-selector.h"
+
+/**
+ *Creates a new instance of #CRSelector.
+ *@param a_simple_sel the initial simple selector list
+ *of the current instance of #CRSelector.
+ *@return the newly built instance of #CRSelector, or
+ *NULL in case of failure.
+ */
+CRSelector*
+cr_selector_new (CRSimpleSel *a_simple_sel)
+{
+ CRSelector *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRSelector)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (CRSelector)) ;
+ result->simple_sel = a_simple_sel ;
+ return result ;
+}
+
+/**
+ *Appends a new instance of #CRSelector to the current selector list.
+ *@param a_this the current instance of #CRSelector.
+ *@param a_new the instance of #CRSelector to be appended.
+ *@return the new list.
+ */
+CRSelector*
+cr_selector_append (CRSelector *a_this, CRSelector *a_new)
+{
+ CRSelector *cur = NULL ;
+
+ if (!a_this)
+ return a_new ;
+
+ /*walk forward the list headed by a_this to get the list tail*/
+ for (cur = a_this ; cur && cur->next ; cur = cur->next) ;
+
+ cur->next = a_new ;
+ a_new->prev = cur ;
+
+ return a_this ;
+}
+
+/**
+ *Prepends an element to the #CRSelector list.
+ *@param a_this the current instance of #CRSelector list.
+ *@param a_new the instance of #CRSelector.
+ *@return the new list.
+ */
+CRSelector*
+cr_selector_prepend (CRSelector *a_this, CRSelector *a_new)
+{
+ CRSelector *cur = NULL ;
+
+ a_new->next = a_this ;
+ a_this->prev = a_new ;
+
+ for (cur = a_new ; cur && cur->prev ; cur = cur->prev) ;
+
+ return cur ;
+}
+
+/**
+ *append a simple selector to the current #CRSelector list.
+ *@param a_this the current instance of #CRSelector.
+ *@param a_simple_sel the simple selector to append.
+ *@return the new list or NULL in case of failure.
+ */
+CRSelector*
+cr_selector_append_simple_sel (CRSelector *a_this,
+ CRSimpleSel *a_simple_sel)
+{
+ CRSelector * selector = NULL ;
+
+ selector = cr_selector_new (a_simple_sel) ;
+ g_return_val_if_fail (selector, NULL) ;
+
+ return cr_selector_append (a_this, selector) ;
+}
+
+/**
+ *Serializes the current instance of #CRSelector to a file.
+ *@param a_this the current instance of #CRSelector.
+ *@param a_fp the destination file.
+ */
+void
+cr_selector_dump (CRSelector *a_this, FILE *a_fp)
+{
+ if (a_this)
+ {
+ CRSelector *cur = NULL ;
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ {
+ if (cur->simple_sel)
+ {
+ if (cur->prev)
+ fprintf (a_fp,", ") ;
+
+ cr_simple_sel_dump (cur->simple_sel, a_fp) ;
+ }
+ }
+ }
+}
+
+/**
+ *Increments the ref count of the current instance
+ *of #CRSelector.
+ *@param a_this the current instance of #CRSelector.
+ */
+void
+cr_selector_ref (CRSelector *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ a_this->ref_count ++ ;
+}
+
+/**
+ *Decrements the ref count of the current instance of
+ *#CRSelector.
+ *If the ref count reaches zero, the current instance of
+ *#CRSelector is destroyed.
+ *@param a_this the current instance of #CRSelector.
+ *@return TRUE if this function destroyed the current instance
+ *of #CRSelector, FALSE otherwise.
+ */
+gboolean
+cr_selector_unref (CRSelector *a_this)
+{
+ g_return_val_if_fail (a_this, FALSE) ;
+
+ if (a_this->ref_count)
+ {
+ a_this->ref_count -- ;
+ }
+
+ if (a_this->ref_count == 0)
+ {
+ cr_selector_destroy (a_this) ;
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+/**
+ *Destroys the selector list.
+ *@param a_this the current instance of #CRSelector.
+ */
+void
+cr_selector_destroy (CRSelector *a_this)
+{
+ CRSelector *cur = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ /*
+ *go and get the list tail. In the same time, free
+ *all the simple selectors contained in the list.
+ */
+ for (cur = a_this ;cur && cur->next ; cur = cur->next)
+ {
+ if (cur->simple_sel)
+ {
+ cr_simple_sel_destroy (cur->simple_sel) ;
+ cur->simple_sel = NULL ;
+ }
+ }
+
+ if (cur)
+ {
+ if (cur->simple_sel)
+ {
+ cr_simple_sel_destroy (cur->simple_sel) ;
+ cur->simple_sel = NULL ;
+ }
+ }
+
+ /*in case the list has only one element*/
+ if (cur && !cur->prev)
+ {
+ g_free (cur) ;
+ return ;
+ }
+
+ /*walk backward the list and free each "next element"*/
+ for (cur = cur->prev ; cur && cur->prev ; cur = cur->prev)
+ {
+ if (cur->next)
+ {
+ g_free (cur->next) ;
+ cur->next = NULL ;
+ }
+ }
+
+ if (!cur)
+ return ;
+
+ if (cur->next)
+ {
+ g_free (cur->next) ;
+ cur->next = NULL ;
+ }
+
+ g_free (cur) ;
+}
diff --git a/src/cr-selector.h b/src/cr-selector.h
new file mode 100644
index 0000000..98960e4
--- /dev/null
+++ b/src/cr-selector.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+#ifndef __CR_SELECTOR_H__
+#define __CR_SELECTOR_H__
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-simple-sel.h"
+
+/**
+ *@file
+ *The declaration file of the #CRSelector file.
+ */
+
+#define G_BEGIN_DECLS
+typedef struct _CRSelector CRSelector ;
+
+/**
+ *Abstracts a CSS2 selector as defined in the right part
+ *of the 'ruleset" production in the appendix D.1 of the
+ *css2 spec.
+ *It is actually the abstraction of a comma separated list
+ *of a simple selectors list.
+ *In a css2 file, a selector is a list of simple selectors
+ *separated by a comma.
+ *e.g: sel0, sel1, sel2 ...
+ *Each seln is a simple selector
+ */
+struct _CRSelector
+{
+ /**
+ *A Selection expression.
+ *It is a list of basic selectors.
+ *Each basic selector can be either an element
+ *selector, an id selector, a class selector, an
+ *attribute selector, an universal selector etc ...
+ */
+ CRSimpleSel *simple_sel ;
+
+ /**The next selector list element*/
+ CRSelector *next ;
+ CRSelector *prev ;
+
+ glong ref_count ;
+};
+
+CRSelector*
+cr_selector_new (CRSimpleSel *a_sel_expr) ;
+
+CRSelector*
+cr_selector_append (CRSelector *a_this, CRSelector *a_new) ;
+
+CRSelector*
+cr_selector_append_simple_sel (CRSelector *a_this,
+ CRSimpleSel *a_simple_sel) ;
+
+CRSelector*
+cr_selector_prepend (CRSelector *a_this, CRSelector *a_new) ;
+
+void
+cr_selector_dump (CRSelector *a_this, FILE *a_fp) ;
+
+void
+cr_selector_ref (CRSelector *a_this) ;
+
+gboolean
+cr_selector_unref (CRSelector *a_this) ;
+
+void
+cr_selector_destroy (CRSelector *a_this) ;
+
+#define G_END_DECLS
+
+#endif /*__CR_SELECTOR_H__*/
diff --git a/src/cr-simple-sel.c b/src/cr-simple-sel.c
new file mode 100644
index 0000000..f22f678
--- /dev/null
+++ b/src/cr-simple-sel.c
@@ -0,0 +1,191 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "cr-simple-sel.h"
+
+
+/**
+ *The constructor of #CRSimpleSel.
+ *
+ *@return the new instance of #CRSimpleSel.
+ */
+CRSimpleSel *
+cr_simple_sel_new (void)
+{
+ CRSimpleSel *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRSimpleSel)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (CRSimpleSel)) ;
+
+ return result ;
+}
+
+/**
+ *Appends a simpe selector to the current list of simple selector.
+ *
+ *@param a_this the this pointer of the current instance of #CRSimpleSel.
+ *@param a_sel the simple selector to append.
+ *@return the new list upon successfull completion, an error code otherwise.
+ */
+CRSimpleSel *
+cr_simple_sel_append_simple_sel (CRSimpleSel *a_this, CRSimpleSel *a_sel)
+{
+ CRSimpleSel *cur = NULL ;
+
+ g_return_val_if_fail (a_sel, NULL) ;
+
+ if (a_this == NULL)
+ return a_sel ;
+
+ for (cur = a_this ; cur->next ; cur = cur->next) ;
+
+ cur->next = a_sel ;
+ a_sel->prev = cur ;
+
+ return a_this ;
+}
+
+/**
+ *Prepends a simple selector to the current list of simple selectors.
+ *@param a_this the this pointer of the current instance of #CRSimpleSel.
+ *@param a_sel the simple selector to prepend.
+ *@return the new list upon successfull completion, an error code otherwise.
+ */
+CRSimpleSel *
+cr_simple_sel_prepend_simple_sel (CRSimpleSel *a_this, CRSimpleSel *a_sel)
+{
+ g_return_val_if_fail (a_sel, NULL) ;
+
+ if (a_this == NULL)
+ return a_sel ;
+
+ a_sel->next = a_this ;
+ a_this->prev = a_sel ;
+
+ return a_sel ;
+}
+
+
+/**
+ *Dumps the selector to a file.
+ *TODO: add the support of unicode in the dump.
+ *
+ *@param a_this the current instance of #CRSimpleSel.
+ *@param a_fp the destination file pointer.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_simple_sel_dump (CRSimpleSel *a_this, FILE *a_fp)
+{
+ CRSimpleSel *cur = NULL ;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ {
+ if (cur->name)
+ {
+ guchar * str = g_strndup (cur->name->str,
+ cur->name->len) ;
+ if (str)
+ {
+ switch (cur->combinator)
+ {
+ case COMB_WS:
+ fprintf (a_fp," ") ;
+ break ;
+ case COMB_PLUS:
+ fprintf (a_fp,"+") ;
+ break ;
+ case COMB_GT:
+ fprintf (a_fp,">") ;
+ break ;
+ default:
+ break ;
+ }
+
+ fprintf (a_fp,str) ;
+
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+
+ if (cur->add_sel)
+ {
+ cr_additional_sel_dump (cur->add_sel, a_fp) ;
+ }
+ }
+
+ return CR_OK ;
+}
+
+
+/**
+ *The destructor of the current instance of
+ *#CRSimpleSel.
+ *@param a_this the this pointer of the current instance of #CRSimpleSel.
+ *
+ */
+void
+cr_simple_sel_destroy (CRSimpleSel *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->name)
+ {
+ g_string_free (a_this->name, TRUE) ;
+ a_this->name = NULL ;
+ }
+
+ if (a_this->add_sel)
+ {
+ cr_additional_sel_destroy (a_this->add_sel) ;
+ a_this->add_sel = NULL ;
+ }
+
+ if (a_this->next)
+ {
+ cr_simple_sel_destroy (a_this->next) ;
+ }
+
+ if (a_this)
+ {
+ g_free (a_this) ;
+ }
+}
+
diff --git a/src/cr-simple-sel.h b/src/cr-simple-sel.h
new file mode 100644
index 0000000..d7e9642
--- /dev/null
+++ b/src/cr-simple-sel.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_SEL_H__
+#define __CR_SEL_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-additional-sel.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *the declaration of the #CRSimpleSel class.
+ *
+ */
+enum Combinator
+{
+ NO_COMBINATOR,
+ COMB_WS,/*whitesape*/
+ COMB_PLUS,
+ COMB_GT/*greater than*/
+} ;
+
+enum SimpleSelectorType
+{
+ NO_SELECTOR_TYPE = 0,
+ UNIVERSAL_SELECTOR = 1,
+ TYPE_SELECTOR = 1 << 1,
+ DESCENDANT_SELECTOR = 1 << 2,
+ CHILD_SELECTOR = 1 << 3
+} ;
+
+typedef struct _CRSimpleSel CRSimpleSel ;
+
+/**
+ *The abstraction of a css2 simple selection list
+ *as defined by the right part of the "selector" production in the
+ *appendix D.1 of the css2 spec.
+ *It is basically a list of simple selector, each
+ *simple selector being separated by a combinator.
+ *
+ *In the libcroco's implementation, each simple selector
+ *is made of at most two parts:
+ *
+ *1/An element name or 'type selector' (which can hold a '*' and
+ *then been called 'universal selector')
+ *
+ *2/An additional selector that "specializes" the preceding type or
+ *universal selector. The additionnal selector can be either
+ *an id selector, or a class selector, or an attribute selector.
+ */
+struct _CRSimpleSel
+{
+ enum SimpleSelectorType type_mask ;
+ gboolean is_case_sentive ;
+ GString * name ;
+
+ /**
+ *The combinator that separates
+ *this simple selector from the previous
+ *one.
+ */
+ enum Combinator combinator ;
+
+ /**
+ *The additional selector list of the
+ *current simple selector.
+ *An additional selector may
+ *be a class selector, an id selector,
+ *or an attribute selector.
+ *Note that this field is a linked list.
+ */
+ CRAdditionalSel *add_sel ;
+
+ CRSimpleSel *next ;
+ CRSimpleSel *prev ;
+} ;
+
+CRSimpleSel *
+cr_simple_sel_new (void) ;
+
+CRSimpleSel *
+cr_simple_sel_append_simple_sel (CRSimpleSel *a_this,
+ CRSimpleSel *a_sel) ;
+
+CRSimpleSel *
+cr_simple_sel_prepend_simple_sel (CRSimpleSel *a_this,
+ CRSimpleSel *a_sel) ;
+
+enum CRStatus
+cr_simple_sel_dump (CRSimpleSel *a_this, FILE *a_fp) ;
+
+enum CRStatus
+cr_simple_sel_dump_attr_sel_list (CRSimpleSel *a_this) ;
+
+void
+cr_simple_sel_destroy (CRSimpleSel *a_this) ;
+
+G_END_DECLS
+
+
+#endif /*__CR_SIMPLE_SEL_H__*/
diff --git a/src/cr-statement.c b/src/cr-statement.c
new file mode 100644
index 0000000..237ce49
--- /dev/null
+++ b/src/cr-statement.c
@@ -0,0 +1,1293 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <string.h>
+#include "cr-statement.h"
+
+
+/**
+ *@file
+ *Definition of the #CRStatement class.
+ */
+
+#define DECLARATION_INDENT_NB 2
+
+static void
+cr_statement_clear (CRStatement *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ switch (a_this->type)
+ {
+ case AT_RULE_STMT:
+ break ;
+ case RULESET_STMT:
+ if (!a_this->kind.ruleset)
+ return ;
+ if (a_this->kind.ruleset->sel_list)
+ {
+ cr_selector_unref
+ (a_this->kind.ruleset->sel_list) ;
+ a_this->kind.ruleset->sel_list = NULL ;
+ }
+ if (a_this->kind.ruleset->decl_list)
+ {
+ cr_declaration_destroy
+ (a_this->kind.ruleset->decl_list) ;
+ a_this->kind.ruleset->decl_list = NULL ;
+ }
+ g_free (a_this->kind.ruleset) ;
+ a_this->kind.ruleset = NULL ;
+ break ;
+
+ case AT_IMPORT_RULE_STMT:
+ if (!a_this->kind.import_rule)
+ return ;
+ if (a_this->kind.import_rule->url)
+ {
+ g_string_free
+ (a_this->kind.import_rule->url,
+ TRUE) ;
+ a_this->kind.import_rule->url = NULL ;
+ }
+ g_free (a_this->kind.import_rule) ;
+ a_this->kind.import_rule = NULL ;
+ break ;
+
+ case AT_MEDIA_RULE_STMT:
+ if (!a_this->kind.media_rule)
+ return;
+ if (a_this->kind.media_rule->rulesets)
+ {
+ cr_statement_destroy
+ (a_this->kind.media_rule->rulesets) ;
+ a_this->kind.media_rule->rulesets = NULL ;
+ }
+ if (a_this->kind.media_rule->media_list)
+ {
+ GList *cur = NULL ;
+
+ for (cur = a_this->kind.media_rule->media_list;
+ cur ; cur = cur->next)
+ {
+ if (cur->data)
+ {
+ g_string_free ((GString*)cur->data,
+ TRUE) ;
+ cur->data = NULL ;
+ }
+
+ }
+ g_list_free
+ (a_this->kind.media_rule->media_list) ;
+ a_this->kind.media_rule->media_list = NULL ;
+ }
+ g_free (a_this->kind.media_rule) ;
+ a_this->kind.media_rule = NULL ;
+ break ;
+
+ case AT_PAGE_RULE_STMT:
+ if (!a_this->kind.page_rule)
+ return ;
+
+ if (a_this->kind.page_rule->decls_list)
+ {
+ cr_declaration_destroy
+ (a_this->kind.page_rule->decls_list) ;
+ a_this->kind.page_rule->decls_list = NULL ;
+ }
+ if (a_this->kind.page_rule->name)
+ {
+ g_string_free (a_this->kind.page_rule->name,
+ TRUE) ;
+ a_this->kind.page_rule->name = NULL ;
+ }
+ if (a_this->kind.page_rule->pseudo)
+ {
+ g_string_free (a_this->kind.page_rule->pseudo,
+ TRUE) ;
+ a_this->kind.page_rule->pseudo = NULL ;
+ }
+
+ g_free (a_this->kind.page_rule) ;
+ a_this->kind.page_rule = NULL ;
+ break ;
+
+ case AT_CHARSET_RULE_STMT:
+ if (!a_this->kind.charset_rule)
+ return ;
+
+ if (a_this->kind.charset_rule->charset)
+ {
+ g_string_free
+ (a_this->kind.charset_rule->charset,
+ TRUE) ;
+ a_this->kind.charset_rule->charset = NULL ;
+ }
+ g_free (a_this->kind.charset_rule) ;
+ a_this->kind.charset_rule = NULL;
+ break ;
+
+ case AT_FONT_FACE_RULE_STMT:
+ if (!a_this->kind.font_face_rule)
+ return ;
+
+ if (a_this->kind.font_face_rule->decls_list)
+ {
+ cr_declaration_unref
+ (a_this->kind.font_face_rule->decls_list);
+ a_this->kind.font_face_rule->decls_list = NULL ;
+ }
+ g_free (a_this->kind.font_face_rule) ;
+ a_this->kind.font_face_rule = NULL ;
+ break ;
+
+ default:
+ break ;
+ }
+}
+
+/**
+ *Dumps a ruleset statement to a file.
+ *@param a_this the current instance of #CRStatement.
+ *@param a_fp the destination file pointer.
+ *@param a_indent the number of indentation white spaces to add.
+ */
+static void
+cr_statement_dump_ruleset (CRStatement *a_this, FILE *a_fp, glong a_indent)
+{
+ guchar *str = NULL, *tmp_str = NULL ;
+
+ g_return_if_fail (a_this && a_this->type == RULESET_STMT) ;
+
+ if (a_this->kind.ruleset->sel_list)
+ {
+ if (a_indent)
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+
+ cr_selector_dump (a_this->kind.ruleset->sel_list, a_fp) ;
+ }
+
+ if (a_this->kind.ruleset->decl_list)
+ {
+ fprintf (a_fp," {\n") ;
+ cr_declaration_dump (a_this->kind.ruleset->decl_list,
+ a_fp, a_indent + DECLARATION_INDENT_NB,
+ TRUE) ;
+ fprintf (a_fp,"\n") ;
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+ fprintf (a_fp,"}") ;
+ }
+
+ if (str)
+ {
+ g_free (str) ;
+ str = NULL ;
+ }
+ if (tmp_str)
+ {
+ g_free (tmp_str) ;
+ tmp_str = NULL ;
+ }
+}
+
+/**
+ *Dumps a font face rule statement to a file.
+ *@param a_this the current instance of font face rule statement.
+ *@param a_fp the destination file pointer.
+ *@param a_indent the number of white space indentation.
+ */
+static void
+cr_statement_dump_font_face_rule (CRStatement *a_this , FILE *a_fp,
+ glong a_indent)
+{
+ g_return_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT) ;
+
+ if (a_this->kind.font_face_rule->decls_list)
+ {
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+
+ if (a_indent)
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+
+ fprintf (a_fp,"@font-face {\n") ;
+ cr_declaration_dump
+ (a_this->kind.font_face_rule->decls_list,
+ a_fp, a_indent + DECLARATION_INDENT_NB, TRUE) ;
+ fprintf (a_fp,"\n}") ;
+ }
+}
+
+/**
+ *Dumps an @charset rule statement to a file.
+ *@param a_this the current instance of the @charset rule statement.
+ *@param a_fp the destination file pointer.
+ *@param a_indent the number of indentation white spaces.
+ */
+static void
+cr_statement_dump_charset (CRStatement *a_this, FILE *a_fp,
+ gulong a_indent)
+{
+ guchar *str = NULL ;
+
+ g_return_if_fail (a_this
+ && a_this->type == AT_CHARSET_RULE_STMT) ;
+
+ if (a_this->kind.charset_rule
+ && a_this->kind.charset_rule->charset)
+ {
+ str = g_strndup (a_this->kind.charset_rule->charset->str,
+ a_this->kind.charset_rule->charset->len) ;
+
+ g_return_if_fail (str) ;
+
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+ fprintf (a_fp,"@charset \"%s\" ;", str) ;
+ if (str)
+ {
+ g_free (str) ;
+ str = NULL;
+ }
+ }
+}
+
+/**
+ *Dumps an @page rule statement on stdout.
+ *@param a_this the statement to dump on stdout.
+ *@param a_fp the destination file pointer.
+ *@param a_indent the number of indentation white spaces.
+ */
+static void
+cr_statement_dump_page (CRStatement *a_this, FILE *a_fp, gulong a_indent)
+{
+ guchar *str = NULL ;
+
+ g_return_if_fail (a_this
+ && a_this->type == AT_PAGE_RULE_STMT
+ && a_this->kind.page_rule) ;
+
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+ fprintf (a_fp,"@page") ;
+
+ if (a_this->kind.page_rule->name)
+ {
+ str = g_strndup (a_this->kind.page_rule->name->str,
+ a_this->kind.page_rule->name->len) ;
+ g_return_if_fail (str) ;
+ fprintf (a_fp," %s", str) ;
+ if (str)
+ {
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+ else
+ {
+ fprintf (a_fp," ") ;
+ }
+
+ if (a_this->kind.page_rule->pseudo)
+ {
+ str = g_strndup (a_this->kind.page_rule->pseudo->str,
+ a_this->kind.page_rule->pseudo->len) ;
+ g_return_if_fail (str) ;
+ fprintf (a_fp,":%s", str) ;
+ if (str)
+ {
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+
+ if (a_this->kind.page_rule->decls_list)
+ {
+ fprintf (a_fp," {\n") ;
+ cr_declaration_dump
+ (a_this->kind.page_rule->decls_list,
+ a_fp, a_indent + DECLARATION_INDENT_NB, TRUE) ;
+ fprintf (a_fp,"\n}\n") ;
+ }
+}
+
+/**
+ *Dumps an @media rule statement to a file.
+ *@param a_this the statement to dump.
+ *@param a_fp the destination file pointer
+ *@param a_indent the number of white spaces indentation.
+ */
+static void
+cr_statement_dump_media_rule (CRStatement *a_this, FILE *a_fp,
+ gulong a_indent)
+{
+ GList *cur = NULL ;
+
+ g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT) ;
+
+ if (a_this->kind.media_rule)
+ {
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+ fprintf (a_fp,"@media") ;
+ for (cur = a_this->kind.media_rule->media_list ; cur ;
+ cur = cur->next)
+ {
+ if (cur->data)
+ {
+ guchar *str = g_strndup
+ (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+ if (str)
+ {
+ if (cur->prev)
+ {
+ fprintf (a_fp,",") ;
+ }
+ fprintf (a_fp," %s", str) ;
+ g_free (str) ; str = NULL ;
+ }
+ }
+ }
+ fprintf (a_fp," {\n") ;
+ cr_statement_dump (a_this->kind.media_rule->rulesets,
+ a_fp, a_indent + DECLARATION_INDENT_NB) ;
+ fprintf (a_fp,"\n}") ;
+ }
+}
+
+/**
+ *Dumps an @import rule statement to a file.
+ *@param a_fp the destination file pointer.
+ *@param a_indent the number of white space indentations.
+ */
+static void
+cr_statement_dump_import_rule (CRStatement *a_this, FILE *a_fp,
+ gulong a_indent)
+{
+ g_return_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule) ;
+
+ if (a_this->kind.import_rule->url)
+ {
+ guchar *str = NULL ;
+
+ str = g_strndup (a_this->kind.import_rule->url->str,
+ a_this->kind.import_rule->url->len) ;
+ cr_utils_dump_n_chars (' ', a_fp, a_indent) ;
+
+ if (str)
+ {
+ fprintf (a_fp,"@import url(\"%s\")", str) ;
+ g_free (str) ;
+ }
+ else /*there is no url, so no import rule, get out!*/
+ return ;
+
+ if (a_this->kind.import_rule->media_list)
+ {
+ GList *cur = NULL ;
+
+ for (cur = a_this->kind.import_rule->media_list ;
+ cur; cur = cur->next)
+ {
+ if (cur->data)
+ {
+ GString *gstr = cur->data ;
+
+ if (cur->prev)
+ {
+ fprintf (a_fp,", ") ;
+ }
+
+ str = g_strndup (gstr->str,
+ gstr->len) ;
+ if (str)
+ {
+ fprintf (a_fp,str) ;
+ g_free (str) ;
+ }
+ }
+ }
+ fprintf (a_fp," ;") ;
+ }
+ }
+}
+
+
+/**
+ *Creates a new instance of #CRStatement of type
+ *#CRRulSet.
+ *@param a_sel_list the list of #CRSimpleSel (selectors)
+ *the rule applies to.
+ *@param a_decl_list the list of instances of #CRDeclaration
+ *that composes the ruleset.
+ *@param a_media_types a list of instances of GString that
+ *describe the media list this ruleset applies to.
+ *@return the new instance of #CRStatement or NULL if something
+ *went wrong.
+ */
+CRStatement*
+cr_statement_new_ruleset (CRSelector *a_sel_list,
+ CRDeclaration *a_decl_list,
+ CRAtMediaRule *a_media_rule)
+{
+ CRStatement *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRStatement)) ;
+
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRStatement)) ;
+ result->type = RULESET_STMT ;
+ result->kind.ruleset = g_try_malloc (sizeof (CRRuleSet)) ;
+
+ if (!result->kind.ruleset)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ if (result) g_free (result) ;
+ return NULL ;
+ }
+
+ memset (result->kind.ruleset, 0, sizeof (CRRuleSet)) ;
+ result->kind.ruleset->sel_list = a_sel_list;
+ if (a_sel_list)
+ cr_selector_ref (a_sel_list) ;
+ result->kind.ruleset->decl_list = a_decl_list;
+ result->kind.ruleset->media_rule = a_media_rule;
+
+ return result ;
+}
+
+/**
+ *Instanciates an instance of #CRStatement of type
+ *AT_MEDIA_RULE_STMT (@media ruleset).
+ *@param a_ruleset the ruleset statements contained
+ *in the @media rule.
+ *@param a_media, the media string list. A list of GString pointers.
+ */
+CRStatement *
+cr_statement_new_at_media_rule (CRStatement *a_rulesets,
+ GList *a_media)
+{
+ CRStatement *result = NULL ;
+
+ if (a_rulesets)
+ g_return_val_if_fail (a_rulesets->type == RULESET_STMT,
+ NULL) ;
+
+ result = g_try_malloc (sizeof (CRStatement)) ;
+
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRStatement)) ;
+ result->type = AT_MEDIA_RULE_STMT ;
+
+ result->kind.media_rule = g_try_malloc (sizeof (CRAtMediaRule)) ;
+ if (!result->kind.media_rule)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ g_free (result) ;
+ return NULL ;
+ }
+ memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule)) ;
+ result->kind.media_rule->rulesets = a_rulesets ;
+ result->kind.media_rule->media_list = a_media ;
+ return result ;
+}
+
+
+/**
+ *Creates a new instance of #CRStatment of type
+ *#CRAtImportRule.
+ *@param a_url the url to connect to the get the file
+ *to be imported.
+ *@param a_sheet the imported parsed stylesheet.
+ *@return the newly built instance of #CRStatement.
+ */
+CRStatement*
+cr_statement_new_at_import_rule (GString *a_url,
+ GList *a_media_list,
+ CRStyleSheet *a_sheet)
+{
+ CRStatement *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRStatement)) ;
+
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRStatement)) ;
+ result->type = AT_IMPORT_RULE_STMT ;
+
+ result->kind.import_rule =
+ g_try_malloc (sizeof (CRAtImportRule)) ;
+
+ if (!result->kind.import_rule)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ g_free (result) ;
+ return NULL ;
+ }
+
+ memset (result->kind.import_rule, 0, sizeof (CRAtImportRule)) ;
+ result->kind.import_rule->url = a_url;
+ result->kind.import_rule->media_list = a_media_list ;
+ result->kind.import_rule->sheet = a_sheet;
+
+ return result ;
+}
+
+/**
+ *Creates a new instance of #CRStatement of type
+ *#CRAtPageRule.
+ *@param a_decl_list a list of instances of #CRDeclarations
+ *which is actually the list of declarations that applies to
+ *this page rule.
+ *@param a_selector the page rule selector.
+ *@return the newly built instance of #CRStatement or NULL
+ *in case of error.
+ */
+CRStatement *
+cr_statement_new_at_page_rule (CRDeclaration *a_decl_list,
+ GString *a_name,
+ GString *a_pseudo)
+{
+ CRStatement *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRStatement)) ;
+
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRStatement)) ;
+ result->type = AT_PAGE_RULE_STMT ;
+
+ result->kind.page_rule = g_try_malloc (sizeof (CRAtPageRule)) ;
+
+ if (!result->kind.page_rule)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ g_free (result) ;
+ return NULL ;
+ }
+
+ memset (result->kind.page_rule, 0, sizeof (CRAtPageRule)) ;
+ result->kind.page_rule->decls_list = a_decl_list;
+ result->kind.page_rule->name = a_name ;
+ result->kind.page_rule->name = a_pseudo ;
+ return result ;
+}
+
+/**
+ *Creates a new instance of #CRStatement of type
+ *#CRAtCharsetRule.
+ *@param a_charset the string representing the charset.
+ *@return the newly built instance of #CRStatement or NULL
+ *if an error arises.
+ */
+CRStatement *
+cr_statement_new_at_charset_rule (GString *a_charset)
+{
+ CRStatement * result = NULL ;
+
+ result = g_try_malloc (sizeof (CRStatement)) ;
+
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRStatement)) ;
+ result->type = AT_CHARSET_RULE_STMT ;
+
+ result->kind.charset_rule = g_try_malloc
+ (sizeof (CRAtCharsetRule)) ;
+
+ if (!result->kind.charset_rule)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ g_free (result) ;
+ return NULL ;
+ }
+ memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule)) ;
+ result->kind.charset_rule->charset = a_charset ;
+
+ return result ;
+}
+
+/**
+ *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
+ *@param a_font_decls a list of instances of #CRDeclaration. Each declaration
+ *is actually a font declaration.
+ *@return the newly built instance of #CRStatement.
+ */
+CRStatement *
+cr_statement_new_at_font_face_rule (CRDeclaration *a_font_decls)
+{
+ CRStatement *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRStatement)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (CRStatement)) ;
+ result->type = AT_FONT_FACE_RULE_STMT ;
+
+ result->kind.font_face_rule = g_try_malloc
+ (sizeof (CRAtFontFaceRule)) ;
+
+ if (!result->kind.font_face_rule)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ g_free (result) ;
+ return NULL ;
+ }
+ memset (result->kind.font_face_rule, 0,
+ sizeof (CRAtFontFaceRule));
+
+ result->kind.font_face_rule->decls_list = a_font_decls ;
+
+ return result ;
+}
+
+/**
+ *Appends a new statement to the statement list.
+ *@param a_this the current instance of the statement list.
+ *@param a_this a_new the new instance of #CRStatement to append.
+ *@return the new list statement list, or NULL in cas of failure.
+ */
+CRStatement *
+cr_statement_append (CRStatement *a_this,
+ CRStatement *a_new)
+{
+ CRStatement * cur = NULL ;
+
+ g_return_val_if_fail (a_new, NULL) ;
+
+ if (!a_this)
+ {
+ return a_new ;
+ }
+
+ /*walk forward in the current list to find the tail list element*/
+ for (cur = a_this ; cur && cur->next ; cur = cur->next) ;
+
+ cur->next = a_new ;
+ a_new->prev = cur ;
+
+ return a_this ;
+}
+
+/**
+ *Prepends the an instance of #CRStatement to
+ *the current statement list.
+ *@param a_this the current instance of #CRStatement.
+ *@param a_new the new statement to prepend.
+ *@return the new list with the new statement prepended,
+ *or NULL in case of an error.
+ */
+CRStatement*
+cr_statement_prepend (CRStatement *a_this,
+ CRStatement *a_new)
+{
+ CRStatement *cur = NULL ;
+
+ g_return_val_if_fail (a_new, NULL) ;
+
+ if (!a_this)
+ return a_new ;
+
+ a_new->next = a_this ;
+ a_this->prev = a_new ;
+
+ /*walk backward in the prepended list to find the head list element*/
+ for (cur = a_new ; cur && cur->prev ; cur = cur->prev) ;
+
+ return cur ;
+}
+
+/**
+ *Unlinks a statement from the statements list.
+ *@param a_this the current statements list.
+ *@param a_to_unlink the statement to unlink from the list.
+ *@return the new list where a_to_unlink has been unlinked
+ *from, or NULL in case of error.
+ */
+CRStatement *
+cr_statement_unlink (CRStatement *a_this,
+ CRStatement *a_to_unlink)
+{
+ CRStatement *cur = NULL, *next = NULL, *prev = NULL ;
+
+ g_return_val_if_fail (a_this && a_to_unlink, NULL) ;
+
+ /*make sure a_to_unlink belongs to the list headed by a_this*/
+ for (cur = a_this ; cur && (cur != a_to_unlink) ; cur = cur->next) ;
+
+ if (!cur) return NULL ;
+
+ next = a_to_unlink->next ;
+ prev = a_to_unlink->prev ;
+
+ if (prev)
+ prev->next = next ;
+
+ if (next)
+ next->prev = prev ;
+
+ return a_to_unlink ;
+}
+
+
+/**
+ *Sets a selector list to a ruleset statement.
+ *@param a_this the current ruleset statement.
+ *@param a_sel_list the selector list to set. Note
+ *that this function increments the ref count of a_sel_list.
+ *The sel list will be destroyed at the destruction of the
+ *current instance of #CRStatement.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_set_sel_list (CRStatement *a_this,
+ CRSelector *a_sel_list)
+{
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (a_this->kind.ruleset->sel_list)
+ cr_selector_unref (a_this->kind.ruleset->sel_list) ;
+
+ a_this->kind.ruleset->sel_list = a_sel_list ;
+
+ if (a_sel_list)
+ cr_selector_ref (a_sel_list) ;
+
+ return CR_OK ;
+}
+
+/**
+ *Gets a pointer to the selector list contained in
+ *the current ruleset statement.
+ *@param a_this the current ruleset statement.
+ *@param a_list out parameter. The returned selector list,
+ *if and only if the function returned CR_OK.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_get_sel_list (CRStatement *a_this,
+ CRSelector **a_list)
+{
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR) ;
+
+ *a_list = a_this->kind.ruleset->sel_list ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets a declaration list to the current ruleset statement.
+ *@param a_this the current ruleset statement.
+ *@param a_list the declaration list to be added to the current
+ *ruleset statement.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_set_decl_list (CRStatement *a_this,
+ CRDeclaration *a_list)
+{
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+ if (a_this->kind.ruleset->decl_list == a_list)
+ return CR_OK ;
+
+ if (a_this->kind.ruleset->sel_list)
+ {
+ cr_declaration_destroy (a_this->kind.ruleset->decl_list) ;
+ }
+
+ a_this->kind.ruleset->sel_list = NULL;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Appends a declaration to the current ruleset statement.
+ *@param a_this the current statement.
+ *@param a_prop the property of the declaration.
+ *@param a_value the value of the declaration.
+ *@return CR_OK uppon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_append_decl2 (CRStatement *a_this,
+ GString *a_prop, CRTerm *a_value)
+{
+ CRDeclaration * new_decls = NULL ;
+
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR) ;
+
+ new_decls = cr_declaration_append2
+ (a_this->kind.ruleset->decl_list, a_prop, a_value) ;
+ g_return_val_if_fail (new_decls, CR_ERROR) ;
+ a_this->kind.ruleset->decl_list = new_decls ;
+
+ return CR_OK ;
+}
+
+/**
+ *Appends a declaration to the current statement.
+ *@param a_this the current statement.
+ *@param a_declaration the declaration to append.
+ *@return CR_OK upon sucessfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_append_decl (CRStatement *a_this,
+ CRDeclaration *a_decl)
+{
+ CRDeclaration * new_decls = NULL ;
+
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR) ;
+
+ new_decls = cr_declaration_append
+ (a_this->kind.ruleset->decl_list, a_decl) ;
+ g_return_val_if_fail (new_decls, CR_ERROR) ;
+ a_this->kind.ruleset->decl_list = new_decls ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets a stylesheet to the current @import rule.
+ *@param a_this the current @import rule.
+ *@param a_sheet the stylesheet. The stylesheet is owned
+ *by the current instance of #CRStatement, that is, the
+ *stylesheet will be destroyed when the current instance
+ *of #CRStatement will be destroyed.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_set_sheet (CRStatement *a_this,
+ CRStyleSheet *a_sheet)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ a_this->kind.import_rule->sheet = a_sheet ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Gets the stylesheet contained by the @import rule statement.
+ *@param a_this the current @import rule statement.
+ *@param a_sheet out parameter. The returned stylesheet if and
+ *only if the function returns CR_OK.
+ *@return CR_OK upon sucessfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_get_sheet (CRStatement *a_this,
+ CRStyleSheet **a_sheet)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_sheet = a_this->kind.import_rule->sheet ;
+
+ return CR_OK ;
+
+}
+
+/**
+ *Sets an url to the current @import rule statement.
+ *@param a_this the current @import rule statement.
+ *@param a_url the url to set.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_set_url (CRStatement *a_this,
+ GString *a_url)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (a_this->kind.import_rule->url)
+ {
+ g_string_free (a_this->kind.import_rule->url, TRUE) ;
+ }
+
+ a_this->kind.import_rule->url = a_url ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Gets the url of the @import rule statement.
+ *@param the current @import rule statement.
+ *@param a_url out parameter. The returned url if
+ *and only if the function returned CR_OK.
+ */
+enum CRStatus
+cr_statement_at_import_rule_get_url (CRStatement *a_this,
+ GString **a_url)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_url = a_this->kind.import_rule->url ;
+
+ return CR_OK ;
+}
+
+/**
+ *Sets a declaration list to the current @page rule statement.
+ *@param a_this the current @page rule statement.
+ *@param a_decl_list the declaration list to add. Will be freed
+ *by the current instance of #CRStatement when it is destroyed.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_page_rule_set_declarations (CRStatement *a_this,
+ CRDeclaration *a_decl_list)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_PAGE_RULE_STMT
+ && a_this->kind.page_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (a_this->kind.page_rule->decls_list)
+ {
+ cr_declaration_unref (a_this->kind.page_rule->decls_list);
+ }
+
+ a_this->kind.page_rule->decls_list = a_decl_list ;
+
+ if (a_decl_list)
+ {
+ cr_declaration_ref (a_decl_list) ;
+ }
+
+ return CR_OK ;
+}
+
+
+/**
+ *Gets the declaration list associated to the current @page rule
+ *statement.
+ *@param a_this the current @page rule statement.
+ *@param a_decl_list out parameter. The returned declaration list.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_page_rule_get_declarations (CRStatement *a_this,
+ CRDeclaration **a_decl_list)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_PAGE_RULE_STMT
+ && a_this->kind.page_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_decl_list = a_this->kind.page_rule->decls_list ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the charset of the current @charset rule statement.
+ *@param a_this the current @charset rule statement.
+ *@param a_charset the charset to set.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_charset_rule_set_charset (CRStatement *a_this,
+ GString *a_charset)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_CHARSET_RULE_STMT
+ && a_this->kind.charset_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (a_this->kind.charset_rule->charset)
+ {
+ g_string_free (a_this->kind.charset_rule->charset,
+ TRUE) ;
+ }
+
+ a_this->kind.charset_rule->charset = a_charset ;
+ return CR_OK ;
+}
+
+
+/**
+ *Gets the charset string associated to the current
+ *@charset rule statement.
+ *@param a_this the current @charset rule statement.
+ *@param a_charset out parameter. The returned charset string if
+ *and only if the function returned CR_OK.
+ */
+enum CRStatus
+cr_statement_at_charset_rule_get_charset (CRStatement *a_this,
+ GString **a_charset)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_CHARSET_RULE_STMT
+ && a_this->kind.charset_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_charset = a_this->kind.charset_rule->charset ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets a declaration list to the current @font-face rule statement.
+ *@param a_this the current @font-face rule statement.
+ *@param a_decls the declarations list to set.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_set_decls (CRStatement *a_this,
+ CRDeclaration *a_decls)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT
+ && a_this->kind.font_face_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (a_this->kind.font_face_rule->decls_list)
+ {
+ cr_declaration_unref
+ (a_this->kind.font_face_rule->decls_list) ;
+ }
+
+ a_this->kind.font_face_rule->decls_list = a_decls;
+ cr_declaration_ref (a_decls) ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Gets the declaration list associated to the current instance
+ *of @font-face rule statement.
+ *@param a_this the current @font-face rule statement.
+ *@param a_decls out parameter. The returned declaration list if
+ *and only if this function returns CR_OK.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_get_decls (CRStatement *a_this,
+ CRDeclaration **a_decls)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT
+ && a_this->kind.font_face_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_decls = a_this->kind.font_face_rule->decls_list ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Adds a declaration to the current @font-face rule
+ *statement.
+ *@param a_this the current @font-face rule statement.
+ *@param a_prop the property of the declaration.
+ *@param a_value the value of the declaration.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_add_decl (CRStatement *a_this,
+ GString *a_prop,
+ CRTerm *a_value)
+{
+ CRDeclaration *decls = NULL ;
+
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT
+ && a_this->kind.font_face_rule,
+ CR_BAD_PARAM_ERROR) ;
+
+ decls = cr_declaration_append2
+ (a_this->kind.font_face_rule->decls_list,
+ a_prop, a_value) ;
+
+ g_return_val_if_fail (decls, CR_ERROR) ;
+
+ if (a_this->kind.font_face_rule->decls_list == NULL)
+ cr_declaration_ref (decls) ;
+
+ a_this->kind.font_face_rule->decls_list = decls ;
+
+ return CR_OK ;
+}
+
+/**
+ *Dumps the css2 statement to a file.
+ *@param a_this the current css2 statement.
+ *@param a_fp the destination file pointer.
+ *@param a_indent the number of white space indentation characters.
+ */
+void
+cr_statement_dump (CRStatement *a_this, FILE *a_fp, gulong a_indent)
+{
+ CRStatement *cur = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ {
+ if (cur->prev)
+ {
+ fprintf (a_fp,"\n\n") ;
+ }
+
+ switch (cur->type)
+ {
+ case RULESET_STMT:
+ cr_statement_dump_ruleset (cur, a_fp, a_indent) ;
+ break ;
+
+ case AT_FONT_FACE_RULE_STMT:
+ cr_statement_dump_font_face_rule
+ (cur, a_fp, a_indent);
+ break ;
+
+ case AT_CHARSET_RULE_STMT:
+ cr_statement_dump_charset (cur, a_fp, a_indent) ;
+ break ;
+
+ case AT_PAGE_RULE_STMT:
+ cr_statement_dump_page (cur, a_fp, a_indent) ;
+ break ;
+
+ case AT_MEDIA_RULE_STMT:
+ cr_statement_dump_media_rule (cur, a_fp, a_indent) ;
+ break ;
+
+ case AT_IMPORT_RULE_STMT:
+ cr_statement_dump_import_rule (cur, a_fp, a_indent) ;
+ break ;
+
+ default :
+ fprintf (a_fp, "Statement unrecognized at %s:%d",
+ __FILE__, __LINE__) ;
+ break ;
+ }
+ }
+}
+
+/**
+ *Destructor of #CRStatement.
+ */
+void
+cr_statement_destroy (CRStatement *a_this)
+{
+ CRStatement *cur = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ /*go get the tail of the list*/
+ for (cur = a_this ; cur && cur->next; cur = cur->next)
+ {
+ cr_statement_clear (cur) ;
+ }
+
+ if (cur)
+ cr_statement_clear (cur) ;
+
+ if (cur->prev == NULL)
+ {
+ g_free (a_this);
+ return ;
+ }
+
+ /*walk backward and free next element*/
+ for (cur = cur->prev ; cur && cur->prev; cur = cur->prev)
+ {
+ if (cur->next)
+ {
+ g_free (cur->next) ;
+ cur->next = NULL ;
+ }
+ }
+
+ if (!cur)
+ return ;
+
+ /*free the one remaining list*/
+ if (cur->next)
+ {
+ g_free (cur->next) ;
+ cur->next = NULL ;
+ }
+
+ g_free (cur) ;
+ cur = NULL ;
+}
diff --git a/src/cr-statement.h b/src/cr-statement.h
new file mode 100644
index 0000000..1ce4852
--- /dev/null
+++ b/src/cr-statement.h
@@ -0,0 +1,315 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-term.h"
+#include "cr-selector.h"
+#include "cr-declaration.h"
+
+#ifndef __CR_STATEMENT_H__
+#define __CR_STATEMENT_H__
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *Declaration of the #CRStatement class.
+ */
+
+struct _CRStatement ;
+typedef struct _CRStatement CRStatement ;
+
+struct _CRAtMediaRule ;
+typedef struct _CRAtMediaRule CRAtMediaRule ;
+
+typedef struct _CRRuleSet CRRuleSet ;
+/**
+ *The abstraction of a css ruleset.
+ *A ruleset is made of a list of selectors,
+ *followed by a list of declarations.
+ */
+struct _CRRuleSet
+{
+ /**A list of instances of #CRSimpeSel*/
+ CRSelector *sel_list ;
+
+ /**A list of instances of #CRDeclaration*/
+ CRDeclaration *decl_list ;
+
+ /**
+ *The parent media rule, or NULL if
+ *no parent media rule exists.
+ */
+ CRAtMediaRule *media_rule ;
+} ;
+
+/*
+ *a forward declaration of CRStylesheet.
+ *CRStylesheet is actually declared in
+ *cr-stylesheet.h
+ */
+struct _CRStyleSheet ;
+typedef struct _CRStyleSheet CRStyleSheet;
+
+
+/**The @import rule abstraction.*/
+typedef struct _CRAtImportRule CRAtImportRule ;
+struct _CRAtImportRule
+{
+ /**the url of the import rule*/
+ GString *url ;
+
+ GList *media_list ;
+
+ /**
+ *the stylesheet fetched from the url, if any.
+ *this is not "owned" by #CRAtImportRule which means
+ *it is not destroyed by the destructor of #CRAtImportRule.
+ */
+ CRStyleSheet * sheet;
+};
+
+
+/**abstraction of an @media rule*/
+struct _CRAtMediaRule
+{
+ GList *media_list ;
+ CRStatement *rulesets ;
+} ;
+
+
+typedef struct _CRAtPageRule CRAtPageRule ;
+/**The @page rule abstraction*/
+struct _CRAtPageRule
+{
+ /**a list of instances of #CRDeclaration*/
+ CRDeclaration *decls_list ;
+
+ /**page selector. Is a pseudo selector*/
+ GString *name ;
+ GString *pseudo ;
+} ;
+
+/**The @charset rule abstraction*/
+typedef struct _CRAtCharsetRule CRAtCharsetRule ;
+struct _CRAtCharsetRule
+{
+ GString * charset ;
+};
+
+/**The abstaction of the @font-face rule.*/
+typedef struct _CRAtFontFaceRule CRAtFontFaceRule ;
+struct _CRAtFontFaceRule
+{
+ /*a list of instanaces of #CRDeclaration*/
+ CRDeclaration *decls_list ;
+} ;
+
+
+/**
+ *The possible types of css2 statements.
+ */
+enum CRStatementType
+{
+ /**
+ *A generic css at-rule
+ *each unknown at-rule will
+ *be of this type.
+ */
+ AT_RULE_STMT = 0,
+
+ /**A css at-rule*/
+ RULESET_STMT,
+
+ /**A css2 import rule*/
+ AT_IMPORT_RULE_STMT,
+
+ /**A css2 media rule*/
+ AT_MEDIA_RULE_STMT,
+
+ /**A css2 page rule*/
+ AT_PAGE_RULE_STMT,
+
+ /**A css2 charset rule*/
+ AT_CHARSET_RULE_STMT,
+
+ /**A css2 font face rule*/
+ AT_FONT_FACE_RULE_STMT
+} ;
+
+
+/**
+ *The abstraction of css statement as defined
+ *in the chapter 4 and appendix D.1 of the css2 spec.
+ *A statement is actually a double chained list of
+ *statements.A statement can be a ruleset, an @import
+ *rule, an @page rule etc ...
+ */
+struct _CRStatement
+{
+ /**
+ *The type of the statement.
+ */
+ enum CRStatementType type ;
+
+ union
+ {
+ CRRuleSet *ruleset ;
+ CRAtImportRule *import_rule ;
+ CRAtMediaRule *media_rule ;
+ CRAtPageRule *page_rule ;
+ CRAtCharsetRule *charset_rule ;
+ CRAtFontFaceRule *font_face_rule ;
+ } kind ;
+
+ CRStatement *next ;
+ CRStatement *prev ;
+} ;
+
+
+CRStatement*
+cr_statement_new_ruleset (CRSelector *a_sel_list,
+ CRDeclaration *a_decl_list,
+ CRAtMediaRule *a_media_rule) ;
+
+CRStatement*
+cr_statement_new_at_import_rule (GString *a_url,
+ GList *a_media_list,
+ CRStyleSheet *a_sheet) ;
+
+CRStatement *
+cr_statement_new_at_media_rule (CRStatement *a_ruleset,
+ GList *a_media) ;
+
+CRStatement *
+cr_statement_new_at_charset_rule (GString *a_charset) ;
+
+CRStatement *
+cr_statement_new_at_font_face_rule (CRDeclaration *a_font_decls) ;
+
+CRStatement *
+cr_statement_new_at_page_rule (CRDeclaration *a_decl_list,
+ GString *a_name,
+ GString *a_pseudo) ;
+CRStatement *
+cr_statement_append (CRStatement *a_this,
+ CRStatement *a_new) ;
+
+CRStatement*
+cr_statement_prepend (CRStatement *a_this,
+ CRStatement *a_new) ;
+
+CRStatement *
+cr_statement_unlink (CRStatement *a_this,
+ CRStatement *a_to_unlink) ;
+
+enum CRStatus
+cr_statement_ruleset_set_sel_list (CRStatement *a_this,
+ CRSelector *a_sel_list) ;
+
+enum CRStatus
+cr_statement_ruleset_get_sel_list (CRStatement *a_this,
+ CRSelector **a_list) ;
+
+enum CRStatus
+cr_statement_ruleset_set_decl_list (CRStatement *a_this,
+ CRDeclaration *a_list) ;
+
+enum CRStatus
+cr_statement_ruleset_append_decl2 (CRStatement *a_this,
+ GString *a_prop, CRTerm *a_value) ;
+
+enum CRStatus
+cr_statement_ruleset_append_decl (CRStatement *a_this,
+ CRDeclaration *a_decl) ;
+
+enum CRStatus
+cr_statement_at_import_rule_set_sheet (CRStatement *a_this,
+ CRStyleSheet *a_sheet) ;
+
+enum CRStatus
+cr_statement_at_import_rule_get_sheet (CRStatement *a_this,
+ CRStyleSheet **a_sheet) ;
+
+enum CRStatus
+cr_statement_at_import_rule_set_url (CRStatement *a_this,
+ GString *a_url) ;
+
+enum CRStatus
+cr_statement_at_import_rule_get_url (CRStatement *a_this,
+ GString **a_url) ;
+
+enum CRStatus
+cr_statement_at_page_rule_set_sel (CRStatement *a_this,
+ CRSelector *a_sel) ;
+
+enum CRStatus
+cr_statement_at_page_rule_get_sel (CRStatement *a_this,
+ CRSelector **a_sel) ;
+
+enum CRStatus
+cr_statement_at_page_rule_set_declarations (CRStatement *a_this,
+ CRDeclaration *a_decl_list) ;
+
+enum CRStatus
+cr_statement_at_page_rule_get_declarations (CRStatement *a_this,
+ CRDeclaration **a_decl_list) ;
+
+enum CRStatus
+cr_statement_at_charset_rule_set_charset (CRStatement *a_this,
+ GString *a_charset) ;
+
+enum CRStatus
+cr_statement_at_charset_rule_get_charset (CRStatement *a_this,
+ GString **a_charset) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_set_decls (CRStatement *a_this,
+ CRDeclaration *a_decls) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_get_decls (CRStatement *a_this,
+ CRDeclaration **a_decls) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_add_decl (CRStatement *a_this,
+ GString *a_prop,
+ CRTerm *a_value) ;
+
+void
+cr_statement_dump (CRStatement *a_this, FILE *a_fp, gulong a_indent) ;
+
+void
+cr_statement_destroy (CRStatement *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_STATEMENT_H__*/
diff --git a/src/cr-stylesheet.c b/src/cr-stylesheet.c
new file mode 100644
index 0000000..893e83b
--- /dev/null
+++ b/src/cr-stylesheet.c
@@ -0,0 +1,93 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include "string.h"
+#include "cr-stylesheet.h"
+
+/**
+ *@file
+ *The definition of the #CRStyleSheet class
+ */
+
+/**
+ *Constructor of the #CRStyleSheet class.
+ *@param the initial list of css statements.
+ *@return the newly built css2 stylesheet, or NULL in case of error.
+ */
+CRStyleSheet *
+cr_stylesheet_new (CRStatement *a_stmts)
+{
+ CRStyleSheet *result ;
+
+ result = g_try_malloc (sizeof (CRStyleSheet)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRStyleSheet)) ;
+
+ if (a_stmts)
+ result->statements = a_stmts ;
+
+ return result ;
+}
+
+
+/**
+ *Dumps the current css2 stylesheet to a file.
+ *@param a_this the current instance of #CRStyleSheet.
+ *@param a_fp the destination file
+ */
+void
+cr_stylesheet_dump (CRStyleSheet *a_this, FILE *a_fp)
+{
+ g_return_if_fail (a_this && a_this->statements) ;
+
+ cr_statement_dump (a_this->statements, a_fp, 0) ;
+}
+
+/**
+ *Destructor of the #CRStyleSheet class.
+ *@param a_this the current instance of the #CRStyleSheet class.
+ */
+void
+cr_stylesheet_destroy (CRStyleSheet *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->statements)
+ {
+ cr_statement_destroy (a_this->statements) ;
+ a_this->statements = NULL ;
+ }
+ g_free (a_this) ;
+}
diff --git a/src/cr-stylesheet.h b/src/cr-stylesheet.h
new file mode 100644
index 0000000..1226e29
--- /dev/null
+++ b/src/cr-stylesheet.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; indent-tabs-mode: ni; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_STYLESHEET_H__
+#define __CR_STYLESHEET_H__
+
+#include "cr-utils.h"
+#include "cr-statement.h"
+
+/**
+ *@file
+ *The declaration of the #CRStyleSheet class.
+ */
+
+/**
+ *An abstraction of a css stylesheet as defined
+ *by the css2 spec in chapter 4.
+ */
+struct _CRStyleSheet
+{
+ /**The css statements list*/
+ CRStatement *statements ;
+} ;
+
+
+CRStyleSheet *
+cr_stylesheet_new (CRStatement *a_stmts) ;
+
+void
+cr_stylesheet_dump (CRStyleSheet *a_this, FILE *a_fp) ;
+
+void
+cr_stylesheet_destroy (CRStyleSheet *a_this) ;
+
+#endif /*__CR_STYLESHEET_H__*/
diff --git a/src/cr-term.c b/src/cr-term.c
new file mode 100644
index 0000000..833a0b7
--- /dev/null
+++ b/src/cr-term.c
@@ -0,0 +1,817 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+#include <stdio.h>
+#include <string.h>
+#include "cr-term.h"
+#include "cr-num.h"
+
+/**
+ *@file
+ *Definition of the #CRTem class.
+ */
+
+
+static void
+cr_term_clear (CRTerm *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ switch (a_this->type)
+ {
+ case NO_TYPE:
+ break ;
+
+ case NUMBER:
+ case PERCENTAGE :
+ case EMS:
+ case EXS:
+ case LENGTH:
+ case ANGLE:
+ case TIME:
+ case FREQ:
+ if (a_this->content.num)
+ {
+ cr_num_destroy (a_this->content.num) ;
+ a_this->content.num = NULL ;
+ }
+ break ;
+
+ case FUNCTION:
+ if (a_this->ext_content.func_param)
+ {
+ cr_term_destroy (a_this->ext_content.func_param) ;
+ a_this->ext_content.func_param = NULL ;
+ }
+ case STRING:
+ case IDENT:
+ case URI:
+ case HASH:
+ if (a_this->content.str)
+ {
+ g_string_free (a_this->content.str, TRUE) ;
+ a_this->content.str = NULL ;
+ }
+ break ;
+ case RGB:
+ if (a_this->content.rgb)
+ {
+ cr_rgb_destroy (a_this->content.rgb) ;
+ a_this->content.rgb = NULL ;
+ }
+ break ;
+ case UNICODERANGE:
+ default :
+ break ;
+ }
+
+ a_this->unit = NO_UNIT ;
+ a_this->type = NO_TYPE ;
+}
+
+/**
+ *Instanciate a #CRTerm.
+ *@return the newly build instance
+ *of #CRTerm.
+ */
+CRTerm *
+cr_term_new (void)
+{
+ CRTerm *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRTerm)) ;
+ if (!result)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (CRTerm)) ;
+ return result ;
+}
+
+
+enum CRStatus
+cr_term_set_number (CRTerm *a_this, CRNum *a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = NUMBER ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_percentage (CRTerm *a_this, CRNum *a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = PERCENTAGE ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_length (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = LENGTH ;
+ a_this->unit = a_unit ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_ems (CRTerm *a_this, CRNum *a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = EMS ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_exs (CRTerm *a_this, CRNum * a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = EXS ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_angle (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = ANGLE ;
+ a_this->unit = a_unit ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_time (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = TIME ;
+ a_this->unit = a_unit ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_freq (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = FREQ ;
+ a_this->unit = a_unit ;
+ a_this->content.num = a_num ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_function (CRTerm *a_this, GString *a_func_name,
+ CRTerm *a_func_param)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = FUNCTION ;
+ a_this->content.str = a_func_name ;
+ a_this->ext_content.func_param = a_func_param ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_string (CRTerm *a_this, GString *a_str)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = STRING ;
+ a_this->content.str = a_str ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_ident (CRTerm *a_this, GString *a_str)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = IDENT ;
+ a_this->content.str = a_str ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_uri (CRTerm *a_this, GString *a_str)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = URI ;
+ a_this->content.str = a_str ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_rgb (CRTerm *a_this, CRRgb *a_rgb)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = RGB ;
+ a_this->content.rgb = a_rgb ;
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_term_set_hash (CRTerm *a_this, GString *a_str)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_term_clear (a_this) ;
+
+ a_this->type = HASH ;
+ a_this->content.str = a_str ;
+ return CR_OK ;
+}
+
+/**
+ *Appends a new term to the current list of #CRTerm.
+ *
+ *@param a_this the "this pointer" of the current instance
+ *of #CRTerm .
+ *@param a_new_term the term to append.
+ *@return the list of terms with the a_new_term appended to it.
+ */
+CRTerm *
+cr_term_append_term (CRTerm *a_this, CRTerm *a_new_term)
+{
+ CRTerm *cur = NULL ;
+
+ g_return_val_if_fail (a_new_term,
+ NULL) ;
+
+ if (a_this == NULL)
+ return a_new_term ;
+
+ for (cur = a_this ;cur->next ; cur = cur->next) ;
+
+ cur->next = a_new_term ;
+ a_new_term->prev = cur ;
+
+ return a_this ;
+}
+
+
+/**
+ *Prepends a term to the list of terms represented by a_this.
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRTerm .
+ *@param a_new_term the term to prepend.
+ *@return the head of the new list.
+ */
+CRTerm *
+cr_term_prepend_term (CRTerm *a_this, CRTerm *a_new_term)
+{
+ g_return_val_if_fail (a_this && a_new_term,
+ NULL) ;
+
+ a_new_term->next = a_this ;
+ a_this->prev = a_new_term ;
+
+ return a_new_term ;
+}
+
+
+/**
+ *Dumps the expression (a list of terms connected by operators)
+ *to a file.
+ *TODO: finish the dump. The dump of some type of terms have not yet been
+ *implemented.
+ *@param a_this the current instance of #CRTerm.
+ *@param a_fp the destination file pointer.
+ */
+void
+cr_term_dump (CRTerm *a_this, FILE *a_fp)
+{
+ guchar *content=NULL ;
+ CRTerm *cur = NULL ;
+
+ g_return_if_fail (a_this) ;
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ {
+ if ((cur->content.str == NULL)
+ && (cur->content.num == NULL)
+ && (cur->content.str == NULL)
+ && (cur->content.rgb == NULL))
+ continue ;
+
+ switch (cur->operator)
+ {
+ case DIVIDE:
+ fprintf (a_fp, " / ") ;
+ break ;
+ case COMMA:
+ fprintf (a_fp, ", ") ;
+ break ;
+
+ case NO_OP:
+ if (cur->prev)
+ {
+ fprintf (a_fp, " ") ;
+ }
+ break ;
+ default:
+
+ break ;
+ }
+
+ switch (cur->unary_op)
+ {
+ case PLUS_UOP:
+ fprintf (a_fp, "+") ;
+ break ;
+
+ case MINUS_UOP:
+ fprintf (a_fp, "-") ;
+ break ;
+
+ default :
+ break ;
+ }
+
+ switch (cur->type)
+ {
+ case NUMBER:
+ if (cur->content.num)
+ {
+ content =
+ cr_num_to_string
+ (cur->content.num) ;
+ }
+
+ if (content)
+ {
+ fprintf (a_fp, content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+
+ break ;
+
+ case PERCENTAGE:
+ if (cur->content.num)
+ {
+ content = cr_num_to_string
+ (cur->content.num) ;
+ }
+
+ if (content)
+ {
+ fprintf (a_fp, "%s", content) ;
+ putchar ('%') ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case LENGTH:
+ if (cur->content.num)
+ {
+ content = cr_num_to_string
+ (cur->content.num) ;
+ }
+
+ g_return_if_fail (content) ;
+
+ switch (cur->unit)
+ {
+ case UNIT_PX:
+ fprintf (a_fp, "%spx", content) ;
+ break ;
+
+ case UNIT_CM:
+ fprintf (a_fp, "%scm", content) ;
+ break ;
+
+ case UNIT_MM:
+ fprintf (a_fp, "%smm", content) ;
+ break ;
+
+ case UNIT_IN:
+ fprintf (a_fp, "%sin", content) ;
+ break ;
+
+ case UNIT_PT:
+ fprintf (a_fp, "%spt", content) ;
+ break ;
+
+ case UNIT_PC:
+ fprintf (a_fp, "%spc", content) ;
+ break ;
+
+ default:
+ fprintf (a_fp, "%s",content) ;
+ }
+
+ if (content)
+ {
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case EMS:
+ if (cur->content.num)
+ {
+ content = cr_num_to_string
+ (cur->content.num) ;
+ }
+ if (content)
+ {
+ fprintf (a_fp, "%sem", content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case EXS:
+ if (cur->content.num)
+ {
+ content = cr_num_to_string
+ (cur->content.num) ;
+ }
+
+ if (content)
+ {
+ fprintf (a_fp, "%sex", content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break;
+
+ case ANGLE:
+ if (cur->content.num)
+ {
+ content = cr_num_to_string
+ (cur->content.num) ;
+ }
+
+ switch (cur->unit)
+ {
+ case UNIT_DEG:
+ if (content)
+ {
+ fprintf (a_fp, "%sdeg",content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case UNIT_RAD:
+ if (content)
+ {
+ fprintf (a_fp, "%srad",content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case UNIT_GRAD:
+ if (content)
+ {
+ fprintf (a_fp, "%sgrad",content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ default :
+ if (content)
+ {
+ fprintf (a_fp, "%s", content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+ }
+
+ break ;
+
+ case TIME:
+ if (cur->content.num)
+ {
+ content = cr_num_to_string
+ (cur->content.num) ;
+ }
+
+ g_return_if_fail (content) ;
+
+ switch (cur->unit)
+ {
+ case UNIT_MS:
+ fprintf (a_fp, "%sms", content) ;
+ break ;
+
+ case UNIT_S:
+ fprintf (a_fp, "%ss",content) ;
+ break ;
+
+ default :
+ break ;
+ }
+
+ if (content)
+ {
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case FREQ:
+ if (cur->content.num)
+ {
+ content = cr_num_to_string
+ (cur->content.num) ;
+ }
+
+ g_return_if_fail (content) ;
+
+ switch (cur->unit)
+ {
+ case UNIT_HZ:
+ fprintf (a_fp, "%sHz", content) ;
+ break ;
+
+ case UNIT_KHZ:
+ fprintf (a_fp, "%sKHz",content) ;
+ break ;
+
+ default:
+ fprintf (a_fp, "%s",content) ;
+ break ;
+ }
+
+ if (content)
+ {
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case FUNCTION:
+ if (cur->content.str)
+ {
+ content = g_strndup
+ (cur->content.str->str,
+ cur->content.str->len) ;
+ }
+
+ if (content)
+ {
+ fprintf (a_fp, "%s(", content) ;
+
+ if (a_this->ext_content.func_param)
+ {
+ cr_term_dump
+ (a_this->
+ ext_content.func_param,
+ a_fp) ;
+ }
+
+ fprintf (a_fp, ")") ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case STRING:
+ if (cur->content.str)
+ {
+ content = g_strndup
+ (cur->content.str->str,
+ cur->content.str->len) ;
+ }
+
+ if (content)
+ {
+ fprintf (a_fp, "\"%s\"", content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case IDENT:
+ if (cur->content.str)
+ {
+ content = g_strndup
+ (cur->content.str->str,
+ cur->content.str->len) ;
+ }
+
+ if (content)
+ {
+ fprintf (a_fp, "%s",content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case URI:
+ if (cur->content.str)
+ {
+ content = g_strndup
+ (cur->content.str->str,
+ cur->content.str->len) ;
+ }
+
+ if (content)
+ {
+ fprintf (a_fp, "uri(%s)",content) ;
+ g_free (content) ;
+ content = NULL ;
+ }
+ break ;
+
+ case RGB:
+ if (cur->content.rgb)
+ {
+ fprintf (a_fp, "rgb(") ;
+ cr_rgb_dump (cur->content.rgb, a_fp) ;
+ fprintf (a_fp, ")") ;
+ }
+
+ break ;
+
+ case UNICODERANGE:
+ fprintf
+ (a_fp,
+ "?found unicoderange: dump not supported yet?") ;
+ break ;
+
+ case HASH:
+ if (cur->content.str)
+ {
+ content = g_strndup
+ (cur->content.str->str,
+ cur->content.str->len) ;
+ }
+ g_return_if_fail (content) ;
+
+ fprintf (a_fp, "#%s", content) ;
+
+ break ;
+
+ default:
+ fprintf (a_fp, "%s", "Unrecognized Term type") ;
+ break ;
+ }
+
+ if (content)
+ {
+ g_free (content) ;
+ content = NULL ;
+ }
+ }
+}
+
+
+/**
+ *Increments the reference counter of the current instance
+ *of #CRTerm.*
+ *@param a_this the current instance of #CRTerm.
+ */
+void
+cr_term_ref (CRTerm *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ a_this->ref_count ++ ;
+}
+
+
+/**
+ *Decrements the ref count of the current instance of
+ *#CRTerm. If the ref count reaches zero, the instance is
+ *destroyed.
+ *@param a_this the current instance of #CRTerm.
+ *@return TRUE if the current instance has been destroyed, FALSE otherwise.
+ */
+gboolean
+cr_term_unref (CRTerm *a_this)
+{
+ g_return_val_if_fail (a_this, FALSE) ;
+
+ if (a_this->ref_count)
+ {
+ a_this->ref_count -- ;
+ }
+
+ if (a_this->ref_count == 0)
+ {
+ cr_term_destroy (a_this) ;
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+/**
+ *The destructor of the the #CRTerm class.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRTerm.
+ */
+void
+cr_term_destroy (CRTerm *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ cr_term_clear (a_this) ;
+
+ if (a_this->next)
+ {
+ cr_term_destroy (a_this->next) ;
+ a_this->next = NULL ;
+ }
+
+ if (a_this)
+ {
+ g_free (a_this) ;
+ }
+
+}
diff --git a/src/cr-term.h b/src/cr-term.h
new file mode 100644
index 0000000..405332b
--- /dev/null
+++ b/src/cr-term.h
@@ -0,0 +1,199 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-rgb.h"
+#include "cr-num.h"
+
+#ifndef __CR_TERM_H__
+#define __CR_TERM_H__
+
+G_END_DECLS
+
+/**
+ *@file
+ *Declaration of the #CRTem class.
+ */
+
+struct _CRTerm ;
+typedef struct _CRTerm CRTerm ;
+
+/**
+ *An abstraction of a css2 term as
+ *defined in the CSS2 spec in appendix D.1:
+ *term ::=
+ *[ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S*
+ *| ANGLE S* | TIME S* | FREQ S* | function ]
+ * | STRING S* | IDENT S* | URI S* | RGB S*
+ *| UNICODERANGE S* | hexcolor
+ */
+struct _CRTerm
+{
+ /**
+ *The type of the term.
+ */
+ enum TermType type ;
+
+ /**
+ *The unit of the term
+ */
+ enum TermUnit unit ;
+
+ /**
+ *The unary operator associated to
+ *the current term.
+ */
+ enum UnaryOperator unary_op ;
+
+ /**
+ *The operator associated to the current term.
+ */
+ enum Operator operator ;
+
+
+ /**
+ *The content of the term.
+ *Depending of the type of the term,
+ *this holds either a number, a percentage ...
+ */
+ union
+ {
+ CRNum *num ;
+ GString * str ;
+ CRRgb * rgb ;
+ } content ;
+
+ /**
+ *If the term is of type UNICODERANGE,
+ *this field holds the upper bound of the range.
+ *if the term is of type FUNCTION, this holds
+ *an instance of CRTerm that represents
+ * the expression which is the argument of the function.
+ */
+ union
+ {
+ CRTerm *func_param ;
+ } ext_content ;
+
+ /**
+ *A spare pointer, just in case.
+ *Can be used by the application.
+ */
+ void * custom_data ;
+
+ glong ref_count ;
+
+ /**
+ *A pointer to the next term,
+ *just in case this term is part of
+ *an expression.
+ */
+ CRTerm *next ;
+
+ /**
+ *A pointer to the previous
+ *term.
+ */
+ CRTerm *prev ;
+} ;
+
+CRTerm *
+cr_term_new (void) ;
+
+enum CRStatus
+cr_term_set_number (CRTerm *a_this, CRNum *a_num) ;
+
+enum CRStatus
+cr_term_set_percentage (CRTerm *a_this, CRNum *a_num) ;
+
+enum CRStatus
+cr_term_set_length (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num) ;
+
+enum CRStatus
+cr_term_set_ems (CRTerm *a_this, CRNum *a_num) ;
+
+enum CRStatus
+cr_term_set_exs (CRTerm *a_this, CRNum * a_num) ;
+
+enum CRStatus
+cr_term_set_angle (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num) ;
+
+enum CRStatus
+cr_term_set_time (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num) ;
+
+enum CRStatus
+cr_term_set_freq (CRTerm *a_this, enum TermUnit a_unit,
+ CRNum *a_num) ;
+
+enum CRStatus
+cr_term_set_function (CRTerm *a_this, GString *a_func_name,
+ CRTerm *a_func_param) ;
+
+enum CRStatus
+cr_term_set_string (CRTerm *a_this, GString *a_str) ;
+
+enum CRStatus
+cr_term_set_ident (CRTerm *a_this, GString *a_str) ;
+
+enum CRStatus
+cr_term_set_uri (CRTerm *a_this, GString *a_str) ;
+
+enum CRStatus
+cr_term_set_rgb (CRTerm *a_this, CRRgb *a_rgb) ;
+
+enum CRStatus
+cr_term_set_hash (CRTerm *a_this, GString *a_str) ;
+
+CRTerm *
+cr_term_append_term (CRTerm *a_this, CRTerm *a_new_term) ;
+
+CRTerm *
+cr_term_prepend_term (CRTerm *a_this, CRTerm *a_new_term) ;
+
+void
+cr_term_dump (CRTerm *a_this, FILE *a_fp) ;
+
+void
+cr_term_ref (CRTerm *a_this) ;
+
+gboolean
+cr_term_unref (CRTerm *a_this) ;
+
+void
+cr_term_destroy (CRTerm * a_term) ;
+
+G_END_DECLS
+
+#endif /*__CR_TERM_H__*/
diff --git a/src/cr-tknzr.c b/src/cr-tknzr.c
new file mode 100644
index 0000000..82887c9
--- /dev/null
+++ b/src/cr-tknzr.c
@@ -0,0 +1,2977 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition of the #CRTknzr (tokenizer)
+ *class.
+ */
+
+#include "string.h"
+#include "cr-tknzr.h"
+#include "cr-doc-handler.h"
+
+struct _CRTknzrPriv
+{
+ /**The parser input stream of bytes*/
+ CRParserInput *input ;
+
+ /**
+ *A cache where tknzr_unget_token()
+ *puts back the token. tknzr_get_next_token()
+ *first look in this cache, and if and
+ *only if it's empty, fetches the next token
+ *from the input stream.
+ */
+ CRToken *token_cache ;
+
+ /**
+ *The position of the end of the previous token
+ *or char fetched.
+ */
+ CRParserInputPos prev_pos ;
+
+ CRDocHandler *sac_handler ;
+
+ /**
+ *The reference count of the current instance
+ *of #CRTknzr. Is manipulated by cr_tknzr_ref()
+ *and cr_tknzr_unref().
+ */
+ glong ref_count ;
+} ;
+
+
+#define PRIVATE(obj) ((obj)->priv)
+
+/**
+ *return TRUE if the character is a number ([0-9]), FALSE otherwise
+ *@param a_char the char to test.
+ */
+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
+
+/**
+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
+ *
+ *@param status the status (of type enum CRStatus) to test.
+ *@param is_exception if set to FALSE, the final status returned the
+ *current function will be CR_PARSING_ERROR. If set to TRUE, the
+ *current status will be the current value of the 'status' variable.
+ *
+ */
+#define CHECK_PARSING_STATUS(status, is_exception) \
+if ((status) != CR_OK) \
+{ \
+ if (is_exception == FALSE) \
+ { \
+ status = CR_PARSING_ERROR ; \
+ } \
+ goto error ; \
+}
+
+
+/**
+ *Peeks the next char from the input stream of the current tokenizer.
+ *invokes CHECK_PARSING_STATUS on the status returned by
+ *cr_tknzr_input_peek_char().
+ *
+ *@param the current instance of #CRTkzr.
+ *@param to_char a pointer to the char where to store the
+ *char peeked.
+ */
+#define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \
+{\
+status = cr_tknzr_peek_char (a_tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE) \
+}
+
+
+
+/**
+ *Reads the next char from the input stream of the current parser.
+ *In case of error, jumps to the "error:" label located in the
+ *function where this macro is called.
+ *@param parser the curent instance of #CRTknzr
+ *@param to_char a pointer to the guint32 char where to store
+ *the character read.
+ */
+#define READ_NEXT_CHAR(a_tknzr, to_char) \
+status = cr_tknzr_read_char (a_tknzr, to_char) ;\
+CHECK_PARSING_STATUS (status, TRUE)
+
+
+/**
+ *Gets information about the current position in
+ *the input of the parser.
+ *In case of failure, this macro returns from the
+ *calling function and
+ *returns a status code of type enum #CRStatus.
+ *@param parser the current instance of #CRTknzr.
+ *@param pos out parameter. A pointer to the position
+ *inside the current parser input. Must
+ */
+#define RECORD_INITIAL_POS(a_tknzr, a_pos) \
+status = cr_parser_input_get_cur_pos (PRIVATE \
+(a_tknzr)->input, a_pos) ; \
+g_return_val_if_fail (status == CR_OK, status)
+
+
+/**
+ *Gets the address of the current byte inside the
+ *parser input.
+ *@param parser the current instance of #CRTknzr.
+ *@param addr out parameter a pointer (guchar*)
+ *to where the address must be put.
+ */
+#define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \
+status = cr_parser_input_get_cur_byte_addr \
+ (PRIVATE (a_tknzr)->input, a_addr) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+
+/**
+ *Peeks a byte from the topmost parser input at
+ *a given offset from the current position.
+ *If it fails, goto the "error:" label.
+ *
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_offset the offset of the byte to peek, the
+ *current byte having the offset '0'.
+ *@param a_byte_ptr out parameter a pointer (guchar*) to
+ *where the peeked char is to be stored.
+ */
+#define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \
+status = cr_tknzr_peek_byte (a_tknzr, \
+ a_offset, \
+ a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+
+/**
+ *Reads a byte from the topmost parser input
+ *steam.
+ *If it fails, goto the "error" label.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_byte_ptr the guchar * where to put the read char.
+ */
+#define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \
+status = \
+cr_parser_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+
+/**
+ *Skips a given number of byte in the topmost
+ *parser input. Don't update line and column number.
+ *In case of error, jumps to the "error:" label
+ *of the surrounding function.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_nb_bytes the number of bytes to skip.
+ */
+#define SKIP_BYTES(a_tknzr, a_nb_bytes) \
+status = cr_parser_input_seek_index (PRIVATE (a_tknzr)->input, \
+ CR_SEEK_CUR, a_nb_bytes) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+
+/**
+ *Skip utf8 encoded characters.
+ *Updates line and column numbers.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_nb_chars the number of chars to skip. Must be of
+ *type glong.
+ */
+#define SKIP_CHARS(a_tknzr, a_nb_chars) \
+{ \
+glong nb_chars = a_nb_chars ; \
+status = cr_parser_input_consume_chars \
+ (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \
+CHECK_PARSING_STATUS (status, TRUE) ; \
+}
+
+
+/**
+ *Tests the condition and if it is false, sets
+ *status to "CR_PARSING_ERROR" and goto the 'error'
+ *label.
+ *@param condition the condition to test.
+ */
+#define ENSURE_PARSING_COND(condition) \
+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
+
+
+static enum CRStatus
+cr_tknzr_parse_nl (CRTknzr *a_this, guchar **a_start, guchar **a_end) ;
+
+static enum CRStatus
+cr_tknzr_parse_w (CRTknzr *a_this, guchar **a_start, guchar **a_end) ;
+
+static enum CRStatus
+cr_tknzr_parse_unicode_escape (CRTknzr *a_this,
+ guint32 *a_unicode) ;
+
+static enum CRStatus
+cr_tknzr_parse_escape (CRTknzr *a_this, guint32 *a_esc_code) ;
+
+
+static enum CRStatus
+cr_tknzr_parse_string (CRTknzr *a_this, GString **a_str) ;
+
+static enum CRStatus
+cr_tknzr_parse_comment (CRTknzr *a_this, GString **a_comment) ;
+
+static enum CRStatus
+cr_tknzr_parse_nmstart (CRTknzr *a_this, guint32 *a_char) ;
+
+static enum CRStatus
+cr_tknzr_parse_num (CRTknzr *a_this, CRNum ** a_num) ;
+
+/**********************************
+ *PRIVATE methods
+ **********************************/
+
+/**
+ *Parses a "w" as defined by the css spec at [4.1.1]:
+ * w ::= [ \t\r\n\f]*
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. Upon successfull completion, points
+ *to the beginning of the parsed white space, points to NULL otherwise.
+ *Can also point to NULL is there is no white space actually.
+ *@param a_end out param. Upon successfull completion, points
+ *to the end of the parsed white space, points to NULL otherwise.
+ *Can also point to NULL is there is no white space actually.
+ */
+static enum CRStatus
+cr_tknzr_parse_w (CRTknzr *a_this, guchar **a_start, guchar **a_end)
+{
+ guint32 cur_char = 0 ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_start && a_end,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ *a_start = NULL ;
+ *a_end = NULL ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cr_utils_is_white_space (cur_char) == FALSE)
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ RECORD_CUR_BYTE_ADDR (a_this, a_start) ;
+ *a_end = *a_start ;
+
+ for (;;)
+ {
+ gboolean is_eof = FALSE ;
+
+ cr_parser_input_get_end_of_file (PRIVATE (a_this)->input,
+ &is_eof) ;
+ if (is_eof)
+ break ;
+
+ status = cr_tknzr_peek_char (a_this, &cur_char) ;
+ if (status == CR_END_OF_INPUT_ERROR)
+ {
+ status = CR_OK ;
+ break ;
+ }
+ else if (status != CR_OK)
+ {
+ goto error ;
+ }
+
+ if (cr_utils_is_white_space (cur_char) == TRUE)
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ RECORD_CUR_BYTE_ADDR (a_this, a_end) ;
+ }
+ else
+ {
+ break ;
+ }
+ }
+
+ return CR_OK ;
+
+ error:
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses a newline as defined in the css2 spec:
+ * nl ::= \n|\r\n|\r|\f
+ *
+ *@param a_this the "this pointer" of the current instance of #CRTknzr.
+ *@param a_start a pointer to the first character of the successfully
+ *parsed string.
+ *@param a_end a pointer to the last character of the successfully parsed
+ *string.
+ *@result CR_OK uppon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nl (CRTknzr *a_this, guchar **a_start, guchar **a_end)
+{
+ CRParserInputPos init_pos ;
+ guchar next_chars[2] = {0} ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_start && a_end,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PEEK_BYTE (a_this, 1, &next_chars[0]) ;
+ PEEK_BYTE (a_this, 2, &next_chars[1]) ;
+
+ if ((next_chars[0] == '\r' && next_chars[1] == '\n'))
+ {
+ SKIP_BYTES (a_this, 1) ;
+ SKIP_CHARS (a_this, 1) ;
+
+ RECORD_CUR_BYTE_ADDR (a_this, a_end) ;
+
+ status = CR_OK ;
+ }
+ else if (next_chars[0] == '\n'
+ || next_chars[0] == '\r'
+ || next_chars[0] == '\f')
+ {
+ SKIP_CHARS (a_this, 1) ;
+
+ RECORD_CUR_BYTE_ADDR (a_this, a_start) ;
+ *a_end = *a_start ;
+ status = CR_OK ;
+ }
+
+ if (status == CR_OK)
+ {
+ return CR_OK ;
+ }
+
+ error:
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Go ahead in the parser input, skipping all the spaces.
+ *If the next char if not a white space, this function does nothing.
+ *In any cases, it stops when it encounters a non white space character.
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_try_to_skip_spaces (CRTknzr *a_this)
+{
+ enum CRStatus status = CR_ERROR ;
+ guint32 cur_char = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ status = cr_parser_input_peek_char
+ (PRIVATE (a_this)->input, &cur_char) ;
+
+ if (status != CR_OK)
+ {
+ if (status == CR_END_OF_INPUT_ERROR) return CR_OK ;
+ return status ;
+ }
+
+ if (cr_utils_is_white_space (cur_char) == TRUE)
+ {
+ glong nb_chars = -1; /*consume all spaces*/
+
+ status = cr_parser_input_consume_spaces
+ (PRIVATE (a_this)->input, &nb_chars) ;
+ }
+
+ return status ;
+}
+
+
+/**
+ *Parses a "comment" as defined in the css spec at [4.1.1]:
+ *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ .
+ *This complex regexp is just to say that comments start
+ *with the two chars '/''*' and ends with the two chars '*''/'.
+ *It also means that comments cannot be nested.
+ *So based on that, I've just tried to implement the parsing function
+ *simply and in a straight forward manner.
+ */
+static enum CRStatus
+cr_tknzr_parse_comment (CRTknzr *a_this, GString **a_comment)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ guint32 cur_char = 0 ;
+ GString *comment = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ ENSURE_PARSING_COND (cur_char == '/') ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ ENSURE_PARSING_COND (cur_char == '*') ;
+
+ comment = g_string_new (NULL) ;
+
+ for (;;)
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ /*make sure there are no nested comments*/
+ if (cur_char == '/') {
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ ENSURE_PARSING_COND (cur_char != '*') ;
+
+ g_string_append_c (comment, '/') ;
+ g_string_append_unichar (comment, cur_char) ;
+
+ continue ;
+ }
+
+ /*Detect the end of the comments region*/
+ if (cur_char == '*')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char == '/')
+ {
+ /*
+ *end of comments region
+ *Now, call the right SAC callback.
+ */
+ status = CR_OK ;
+ break ;
+ }
+ else
+ {
+ g_string_append_c (comment, '*') ;
+
+ }
+ }
+
+ g_string_append_unichar (comment, cur_char) ;
+ }
+
+ if (status == CR_OK)
+ {
+ /*
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->comment)
+ {
+ PRIVATE (a_this)->sac_handler->comment
+ (PRIVATE (a_this)->sac_handler,
+ comment) ;
+
+ if (comment)
+ {
+ g_string_free (comment, TRUE) ;
+ comment = NULL ;
+ }
+ }
+ */
+
+ *a_comment = comment ;
+
+ return CR_OK ;
+ }
+
+ error:
+
+ if (comment)
+ {
+ g_string_free (comment, TRUE) ;
+ comment = NULL ;
+ }
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses an 'unicode' escape sequence defined
+ *in css spec at chap 4.1.1:
+ *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]?
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out parameter. A pointer to the start
+ *of the unicode escape sequence. Must *NOT* be deleted by
+ *the caller.
+ *@param a_end out parameter. A pointer to the last character
+ *of the unicode escape sequence. Must *NOT* be deleted by the caller.
+ *@return CR_OK if parsing succeded, an error code otherwise.
+ *Error code can be either CR_PARSING_ERROR if the string
+ *parsed just doesn't
+ *respect the production or another error if a
+ *lower level error occured.
+ */
+static enum CRStatus
+cr_tknzr_parse_unicode_escape (CRTknzr *a_this,
+ guint32 *a_unicode)
+{
+ guint32 cur_char ;
+ CRParserInputPos init_pos ;
+ glong occur = 0 ;
+ guint32 unicode = 0 ;
+ guchar *tmp_char_ptr1 = NULL, *tmp_char_ptr2 = NULL ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_unicode,
+ CR_BAD_PARAM_ERROR) ;
+
+ /*first, let's backup the current position pointer*/
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char != '\\')
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ for (occur = 0, unicode = 0 ;
+ ((cur_char >= '0' && cur_char <= '9')
+ || (cur_char >= 'a' && cur_char <= 'f')
+ || (cur_char >= 'A' && cur_char <= 'F')) && occur < 6 ;
+ occur ++)
+ {
+ gint cur_char_val = 0 ;
+
+ if ((cur_char >= '0' && cur_char <= '9'))
+ {
+ cur_char_val = (cur_char - '0') ;
+ }
+ else if ((cur_char >= 'a' && cur_char <= 'f'))
+ {
+ cur_char_val = 10 + (cur_char - 'a') ;
+ }
+ else if ((cur_char >= 'A' && cur_char <= 'F'))
+ {
+ cur_char_val = 10 + (cur_char - 'A') ;
+ }
+
+ unicode = unicode * 10 + cur_char_val ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ }
+
+
+ if (occur == 5)
+ {
+ /*
+ *the unicode escape is 6 digit length
+ */
+
+ /*
+ *parse one space that may
+ *appear just after the unicode
+ *escape.
+ */
+ cr_tknzr_parse_w (a_this, &tmp_char_ptr1,
+ &tmp_char_ptr2) ;
+ status = CR_OK ;
+ }
+ else
+ {
+ /*
+ *The unicode escape is less than
+ *6 digit length. The character
+ *that comes right after the escape
+ *must be a white space.
+ */
+ status = cr_tknzr_parse_w (a_this, &tmp_char_ptr1,
+ &tmp_char_ptr2) ;
+ }
+
+ if (status == CR_OK)
+ {
+ *a_unicode = unicode ;
+ return CR_OK ;
+ }
+
+ error:
+ /*
+ *restore the initial position pointer backuped at
+ *the beginning of this function.
+ */
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *parses an escape sequence as defined by the css spec:
+ *escape ::= {unicode}|\\[ -~\200-\4177777]
+ *@param a_this the current instance of #CRTknzr .
+ */
+static enum CRStatus
+cr_tknzr_parse_escape (CRTknzr *a_this, guint32 *a_esc_code)
+{
+ enum CRStatus status = CR_OK ;
+ guint32 cur_char = 0 ;
+ CRParserInputPos init_pos ;
+ guchar next_chars[2] ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_esc_code, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PEEK_BYTE (a_this, 1, &next_chars[0]) ;
+ PEEK_BYTE (a_this, 2, &next_chars[1]) ;
+
+ if (next_chars[0] != '\\')
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ if ((next_chars[1] >= '0' && next_chars[1] <= '9')
+ || (next_chars[1] >= 'a' && next_chars[1] <='z')
+ || (next_chars[1] >= 'A' && next_chars[1] <='Z'))
+ {
+ status =
+ cr_tknzr_parse_unicode_escape (a_this,
+ a_esc_code);
+ }
+ else
+ {
+ /*consume the '\' char*/
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ /*then read the char after the '\'*/
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char != ' '
+ && (cur_char < 200 || cur_char > 4177777))
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ *a_esc_code = cur_char ;
+
+ }
+
+ if (status == CR_OK)
+ {
+ return CR_OK ;
+ }
+
+ error:
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses a string type as defined in css spec [4.1.1]:
+ *
+ *string ::= {string1}|{string2}
+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out parameter. Upon successfull completion,
+ *points to the beginning of the string, points to an undefined value
+ *otherwise.
+ *@param a_end out parameter. Upon successfull completion, points to
+ *the beginning of the string, points to an undefined value otherwise.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_string (CRTknzr *a_this, GString **a_str)
+{
+ guint32 cur_char = 0, delim = 0 ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+ GString *str = NULL ;
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char == '"') delim = '"' ;
+ else if (cur_char == '\'') delim = '\'' ;
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ str = g_string_new (NULL) ;
+
+ for (;;)
+ {
+ guchar next_chars[2] = {0} ;
+
+ PEEK_BYTE (a_this, 1, &next_chars[0]) ;
+ PEEK_BYTE (a_this, 2, &next_chars[1]) ;
+
+ if (strchr ("\t !#$%&", next_chars[0])
+ || (next_chars[0] >= '(' && next_chars[0] <= '~'))
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ g_string_append_unichar (str, cur_char) ;
+ status = CR_OK ;
+ }
+ else if (next_chars[0] == '\\')
+ {
+ guchar *tmp_char_ptr1 = NULL,
+ *tmp_char_ptr2 = NULL ;
+ guint32 esc_code = 0 ;
+
+ if (next_chars[1] == '\''
+ || next_chars[1] == '"')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ g_string_append_unichar (str,
+ cur_char) ;
+ status = CR_OK ;
+ }
+ else
+ {
+ status = cr_tknzr_parse_escape
+ (a_this, &esc_code) ;
+
+ if (status == CR_OK)
+ {
+ g_string_append_unichar
+ (str, esc_code);
+ }
+ }
+
+ if (status != CR_OK)
+ {
+ /*
+ *consume the '\' char, and try to parse
+ *a newline.
+ */
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ status = cr_tknzr_parse_nl
+ (a_this,&tmp_char_ptr1,
+ &tmp_char_ptr2) ;
+ }
+
+ CHECK_PARSING_STATUS (status, FALSE) ;
+ }
+ else if (cr_utils_is_nonascii (next_chars[0]))
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ g_string_append_unichar (str, cur_char) ;
+ }
+ else if (next_chars[0] == delim)
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ break ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+ }
+
+ if (status == CR_OK)
+ {
+ if (*a_str == NULL)
+ {
+ *a_str = str ;
+ str = NULL ;
+ }
+ else
+ {
+ *a_str = g_string_append_len (*a_str,
+ str->str,
+ str->len) ;
+ g_string_free (str, TRUE) ;
+ }
+ return CR_OK ;
+ }
+
+ error:
+
+ if (str)
+ {
+ g_string_free (str, TRUE) ;
+ str = NULL ;
+ }
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses the an nmstart as defined by css spec [4.1.1]:
+ * nmstart [a-zA-Z]|{nonascii}|{escape}
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. A pointer to the starting point of
+ *the token.
+ *@param a_end out param. A pointer to the ending point of the
+ *token.
+ *@param a_char out param. The actual parsed nmchar.
+ *@return CR_OK upon successfull completion,
+ *an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nmstart (CRTknzr *a_this, guint32 *a_char)
+{
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+ guint32 cur_char = 0, next_char = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == '\\')
+ {
+ status =
+ cr_tknzr_parse_escape (a_this, a_char) ;
+
+ if (status != CR_OK) goto error ;
+
+ }
+ else if (cr_utils_is_nonascii (next_char) == TRUE
+ || ((next_char >= 'a') && (next_char <= 'z'))
+ || ((next_char >= 'A') && (next_char <= 'Z'))
+ )
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ *a_char = cur_char ;
+ status = CR_OK ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ return CR_OK ;
+
+ error:
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &init_pos) ;
+
+ return status ;
+
+}
+
+/**
+ *Parses an nmchar as described in the css spec at
+ *chap 4.1.1:
+ *nmchar ::= [a-z0-9-]|{nonascii}|{escape}
+ *
+ *Humm, I have added the possibility for nmchar to
+ *contain upper case letters.
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. A pointer to the starting point of
+ *the token.
+ *@param a_end out param. A pointer to the ending point of the
+ *token.
+ *@param a_char out param. The actual parsed nmchar.
+ *@return CR_OK upon successfull completion,
+ *an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nmchar (CRTknzr *a_this, guint32 *a_char)
+{
+ guint32 cur_char = 0, next_char = 0 ;
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status =
+ cr_parser_input_peek_char (PRIVATE (a_this)->input,
+ &next_char) ;
+
+ if (status != CR_OK) goto error ;
+
+ if (next_char == '\\')
+ {
+ status =
+ cr_tknzr_parse_escape (a_this, a_char) ;
+
+ if (status != CR_OK) goto error ;
+
+ }
+ else if (cr_utils_is_nonascii (next_char) == TRUE
+ || ((next_char >= 'a') && (next_char <= 'z'))
+ || ((next_char >= 'A') && (next_char <= 'Z'))
+ || ((next_char >= '0') && (next_char <= '9'))
+ || (next_char == '-')
+ || (next_char == '_') /*'_' not allowed by the spec.*/
+ )
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ *a_char = cur_char ;
+ status = CR_OK ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ return CR_OK ;
+
+ error:
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses an "ident" as defined in css spec [4.1.1]:
+ *ident ::= {nmstart}{nmchar}*
+ *
+ *@param a_this the currens instance of #CRTknzr.
+ *
+ *@param a_str a pointer to parsed ident. If *a_str is NULL,
+ *this function allocates a new instance of GString. If not,
+ *the function just appends the parsed string to the one passed.
+ *In both cases it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_ident (CRTknzr *a_this, GString **a_str)
+{
+ guint32 tmp_char = 0 ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_tknzr_parse_nmstart (a_this, &tmp_char) ;
+
+ if (*a_str == NULL)
+ {
+ *a_str = g_string_new (NULL) ;
+ }
+
+ g_string_append_unichar (*a_str, tmp_char) ;
+
+ for (;;)
+ {
+ status =
+ cr_tknzr_parse_nmchar (a_this, &tmp_char);
+
+ if (status != CR_OK) break ;
+
+ g_string_append_unichar (*a_str, tmp_char) ;
+ }
+
+ return CR_OK ;
+}
+
+/**
+ *Parses a "name" as defined by css spec [4.1.1]:
+ *name ::= {nmchar}+
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *
+ *@param a_str out parameter. A pointer to the successfully parsed
+ *name. If *a_str is set to NULL, this function allocates a new instance
+ *of GString. If not, it just appends the parsed name to the passed *a_str.
+ *In both cases, it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_name (CRTknzr *a_this, GString **a_str)
+{
+ guint32 tmp_char = 0 ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+ gboolean str_needs_free = FALSE ;
+ glong i = 0 ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str, CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ if (*a_str == NULL)
+ {
+ *a_str = g_string_new (NULL) ;
+ str_needs_free = TRUE ;
+ }
+
+ for (i = 0 ; ; i++)
+ {
+ status = cr_tknzr_parse_nmchar (a_this, &tmp_char) ;
+
+ if (status != CR_OK) break ;
+
+ g_string_append_unichar (*a_str, tmp_char) ;
+ }
+
+ if (i > 0)
+ {
+ return CR_OK ;
+ }
+
+ if (str_needs_free == TRUE && *a_str)
+ {
+ g_free (*a_str) ;
+ *a_str= NULL ;
+ }
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return CR_PARSING_ERROR ;
+}
+
+/**
+ *Parses a "hash" as defined by the css spec in [4.1.1]:
+ *HASH ::= #{name}
+ */
+static enum CRStatus
+cr_tknzr_parse_hash (CRTknzr *a_this, GString **a_str)
+{
+ guint32 cur_char = 0 ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+ gboolean str_needs_free = FALSE ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char != '#')
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ if (*a_str == NULL)
+ {
+ *a_str = g_string_new (NULL) ;
+ str_needs_free = TRUE ;
+ }
+
+ status = cr_tknzr_parse_name (a_this, a_str) ;
+
+ if (status != CR_OK)
+ {
+ goto error ;
+ }
+
+ return CR_OK ;
+
+ error:
+
+ if (str_needs_free == TRUE && *a_str)
+ {
+ g_free (*a_str) ;
+ *a_str = NULL ;
+ }
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *Parses an uri as defined by the css spec [4.1.1]:
+ * URI ::= url\({w}{string}{w}\)
+ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_str the successfully parsed url.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_uri (CRTknzr *a_this, GString **a_str)
+{
+ guint32 cur_char = 0 ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_PARSING_ERROR ;
+ guchar tab[4] = {0}, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL ;
+ GString *str = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PEEK_BYTE (a_this, 1, &tab[0]) ;
+ PEEK_BYTE (a_this, 2, &tab[1]) ;
+ PEEK_BYTE (a_this, 3, &tab[2]) ;
+ PEEK_BYTE (a_this, 4, &tab[3]) ;
+
+ if (tab[0] != 'u'
+ || tab[1] != 'r'
+ || tab[2] != 'l'
+ || tab[3] != '(')
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ SKIP_CHARS (a_this, 4) ;
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+
+ status = cr_tknzr_parse_string (a_this, a_str) ;
+
+ if (status == CR_OK)
+ {
+ guint32 next_char = 0 ;
+
+ status = cr_tknzr_parse_w (a_this, &tmp_ptr1,
+ &tmp_ptr2) ;
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == ')')
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ status = CR_OK ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ }
+ }
+
+
+ if (status != CR_OK)
+ {
+ str = g_string_new (NULL) ;
+
+ for (;;)
+ {
+ guint32 next_char = 0 ;
+
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (strchr ("!#$%&", next_char)
+ || (cur_char >= '*' && next_char <= '~')
+ || (cr_utils_is_nonascii (next_char) == TRUE))
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ g_string_append_unichar (str,
+ cur_char);
+ status = CR_OK ;
+ }
+ else
+ {
+ guint32 esc_code = 0 ;
+
+ status = cr_tknzr_parse_escape
+ (a_this,
+ &esc_code) ;
+
+ if (status == CR_OK)
+ {
+ g_string_append_unichar
+ (str, esc_code) ;
+ }
+ else
+ {
+ status = CR_OK ;
+ break ;
+ }
+ }
+ }
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char == ')')
+ {
+ status = CR_OK ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+ if (str)
+ {
+ if (*a_str == NULL)
+ {
+ *a_str = str ;
+ str = NULL ;
+ }
+ else
+ {
+ g_string_append_len (*a_str,
+ str->str,
+ str->len) ;
+ g_string_free (str, TRUE) ;
+ }
+ }
+ }
+
+ return CR_OK ;
+
+ error:
+
+ if (str)
+ {
+ g_string_free (str, TRUE) ;
+ str = NULL ;
+ }
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+/**
+ *parses an RGB as defined in the css2 spec.
+ *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')'
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *@param a_rgb out parameter the parsed rgb.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_rgb (CRTknzr *a_this, CRRgb **a_rgb)
+{
+ enum CRStatus status = CR_OK ;
+ CRParserInputPos init_pos ;
+ CRNum * num = NULL ;
+ guchar next_bytes[3] = {0}, cur_byte = 0 ;
+ glong red = 0, green = 0, blue = 0, i = 0 ;
+ gboolean is_percentage = FALSE ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+
+ if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R'))
+ && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G'))
+ && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B')))
+ {
+ SKIP_CHARS (a_this, 3) ;
+ }
+ else
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ READ_NEXT_BYTE (a_this, &cur_byte) ;
+
+ ENSURE_PARSING_COND (cur_byte == '(') ;
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+
+ status = cr_tknzr_parse_num (a_this, &num) ;
+
+ ENSURE_PARSING_COND
+ ((status == CR_OK) && (num!= NULL)) ;
+
+ red = num->int_part ;
+
+ cr_num_destroy (num) ;
+ num = NULL ;
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+
+ if (next_bytes[0] == '%')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ is_percentage = TRUE ;
+ }
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+
+ for (i = 0 ; i < 2 ; i++)
+ {
+ READ_NEXT_BYTE (a_this, &cur_byte) ;
+
+ ENSURE_PARSING_COND (cur_byte == ',') ;
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+
+ status = cr_tknzr_parse_num (a_this, &num) ;
+
+ ENSURE_PARSING_COND
+ ((status == CR_OK)&&(num != NULL)) ;
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+
+ if (next_bytes[0] == '%')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ is_percentage = TRUE ;
+ }
+
+ if (i == 0)
+ {
+ green = num->int_part ;
+ }
+ else if (i == 1)
+ {
+ blue = num->int_part ;
+ }
+
+ if (num)
+ {
+ cr_num_destroy (num) ;
+ num = NULL ;
+ }
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+ }
+
+ READ_NEXT_BYTE (a_this, &cur_byte) ;
+
+ if (*a_rgb == NULL)
+ {
+ enum TermUnit unit ;
+
+ if (is_percentage == TRUE)
+ {
+ unit = UNIT_PERCENTAGE ;
+ }
+ else
+ {
+ unit = NO_UNIT ;
+ }
+
+ *a_rgb =
+ cr_rgb_new_with_vals (red, green, blue, unit) ;
+
+ if (*a_rgb == NULL)
+ {
+ status = CR_ERROR ;
+ goto error ;
+ }
+ status = CR_OK ;
+ }
+ else
+ {
+ enum TermUnit unit ;
+
+ if (is_percentage == TRUE)
+ {
+ unit = UNIT_PERCENTAGE ;
+ }
+ else
+ {
+ unit = NO_UNIT ;
+ }
+
+ (*a_rgb)->red = red ;
+ (*a_rgb)->green = green ;
+ (*a_rgb)->blue = blue ;
+ (*a_rgb)->unit = unit ;
+
+ status = CR_OK ;
+ }
+
+ if (status == CR_OK)
+ {
+ return CR_OK ;
+ }
+
+ error:
+
+ if (num)
+ {
+ cr_num_destroy (num) ;
+ num = NULL ;
+ }
+
+ cr_tknzr_set_cur_pos (a_this, &init_pos) ;
+
+ return CR_OK ;
+}
+
+/**
+ *Parses a atkeyword as defined by the css spec in [4.1.1]:
+ *ATKEYWORD ::= @{ident}
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRTknzr.
+ *
+ *@param a_str out parameter. The parsed atkeyword. If *a_str is
+ *set to NULL this function allocates a new instance of GString and
+ *sets it to the parsed atkeyword. If not, this function just appends
+ *the parsed atkeyword to the end of *a_str. In both cases it is up to
+ *the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_atkeyword (CRTknzr *a_this, GString **a_str)
+{
+ guint32 cur_char = 0 ;
+ CRParserInputPos init_pos ;
+ gboolean str_needs_free = FALSE ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (cur_char != '@')
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ if (*a_str == NULL)
+ {
+ *a_str = g_string_new (NULL) ;
+ str_needs_free = TRUE ;
+ }
+
+ status = cr_tknzr_parse_ident (a_this, a_str) ;
+
+ if (status != CR_OK)
+ {
+ goto error ;
+ }
+
+ return CR_OK ;
+
+ error:
+
+ if (str_needs_free == TRUE && *a_str)
+ {
+ g_free (*a_str) ;
+ *a_str = NULL ;
+ }
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+
+
+static enum CRStatus
+cr_tknzr_parse_important (CRTknzr *a_this)
+{
+ guint32 cur_char = 0 ;
+ guchar next_bytes [9] ;
+ CRParserInputPos init_pos ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ ENSURE_PARSING_COND (cur_char == '!') ;
+
+ cr_tknzr_try_to_skip_spaces (a_this) ;
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+ PEEK_BYTE (a_this, 5, &next_bytes[4]) ;
+ PEEK_BYTE (a_this, 6, &next_bytes[5]) ;
+ PEEK_BYTE (a_this, 7, &next_bytes[6]) ;
+ PEEK_BYTE (a_this, 8, &next_bytes[7]) ;
+ PEEK_BYTE (a_this, 9, &next_bytes[9]) ;
+
+ if (next_bytes[0] == 'i'
+ && next_bytes[1] == 'm'
+ && next_bytes[2] == 'p'
+ && next_bytes[3] == 'o'
+ && next_bytes[4] == 'r'
+ && next_bytes[5] == 't'
+ && next_bytes[6] == 'a'
+ && next_bytes[7] == 'n'
+ && next_bytes[8] == 't')
+ {
+ SKIP_BYTES (a_this, 9) ;
+ return CR_OK ;
+ }
+
+ error:
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+
+/**
+ *Parses a num as defined in the css spec [4.1.1]:
+ *[0-9]+|[0-9]*\.[0-9]+
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_num out parameter. The parsed number.
+ *@return CR_OK upon successfull completion,
+ *an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_num (CRTknzr *a_this, CRNum ** a_num)
+{
+ enum CRStatus status = CR_PARSING_ERROR ;
+ gboolean parsing_dec = FALSE, parsed = FALSE ;
+ guint32 cur_char = 0, int_part = 0, dec_part = 0,
+ next_char = 0 ;
+ CRParserInputPos init_pos ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+
+ if (IS_NUM (cur_char) == TRUE)
+ {
+ int_part = int_part * 10
+ + (cur_char - '0') ;
+
+ parsed = TRUE ;
+ }
+ else if (cur_char != '.')
+ {
+ status = CR_PARSING_ERROR ;
+
+ goto error ;
+ }
+
+ for (;;)
+ {
+ PEEK_NEXT_CHAR (a_this, &next_char) ;
+
+ if (next_char == '.')
+ {
+ if (parsing_dec == TRUE)
+ {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ parsing_dec = TRUE ;
+ parsed = TRUE ;
+ }
+ else if (IS_NUM (next_char) == TRUE)
+ {
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ parsed = TRUE ;
+
+ if (parsing_dec == FALSE)
+ {
+ int_part = int_part * 10
+ + (cur_char - '0') ;
+ }
+ else
+ {
+ dec_part = dec_part *10
+ + (cur_char - '0') ;
+ }
+ }
+ else
+ {
+ break ;
+ }
+ }
+
+ if (parsed == FALSE)
+ {
+ status = CR_PARSING_ERROR ;
+ }
+
+ /*
+ *Now, set the output param values.
+ */
+ if (status == CR_OK)
+ {
+ if (*a_num == NULL)
+ {
+ *a_num = cr_num_new_with_vals
+ ((parsing_dec == FALSE)?TRUE:FALSE,
+ int_part,
+ dec_part) ;
+
+ if (*a_num == NULL)
+ {
+ status = CR_ERROR ;
+ goto error ;
+ }
+ }
+ else
+ {
+ (*a_num)->is_natural =
+ (parsing_dec == FALSE)?TRUE:FALSE ;
+
+ (*a_num)->int_part = int_part ;
+
+ (*a_num)->dec_part = dec_part ;
+ }
+
+ return CR_OK ;
+ }
+
+ error:
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input, &init_pos) ;
+
+ return status ;
+}
+
+
+/*********************************************
+ *PUBLIC methods
+ ********************************************/
+
+CRTknzr *
+cr_tknzr_new (CRParserInput *a_input)
+{
+ CRTknzr * result = NULL ;
+
+ result = g_try_malloc (sizeof (CRTknzr)) ;
+
+ if (result == NULL)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRTknzr)) ;
+
+ result->priv = g_try_malloc (sizeof (CRTknzrPriv)) ;
+
+ if (result->priv == NULL)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+
+ if (result)
+ {
+ g_free (result) ;
+ result = NULL ;
+ }
+
+ return NULL ;
+ }
+
+ memset (result->priv, 0, sizeof (CRTknzrPriv)) ;
+
+ if (a_input)
+ cr_tknzr_set_input (result, a_input) ;
+
+ return result ;
+}
+
+
+CRTknzr *
+cr_tknzr_new_from_uri (guchar *a_file_uri,
+ enum CREncoding a_enc)
+{
+ CRTknzr * result = NULL ;
+ CRParserInput *input = NULL ;
+
+ input = cr_parser_input_new_from_uri (a_file_uri, a_enc) ;
+ g_return_val_if_fail (input != NULL, NULL) ;
+
+ result = cr_tknzr_new (input) ;
+
+ return result ;
+}
+
+void
+cr_tknzr_ref (CRTknzr *a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)) ;
+
+ PRIVATE (a_this)->ref_count ++ ;
+}
+
+gboolean
+cr_tknzr_unref (CRTknzr *a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE) ;
+
+ if (PRIVATE (a_this)->ref_count > 0)
+ {
+ PRIVATE (a_this)->ref_count -- ;
+ }
+
+ if (PRIVATE (a_this)->ref_count == 0)
+ {
+ cr_tknzr_destroy (a_this) ;
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+enum CRStatus
+cr_tknzr_set_input (CRTknzr *a_this, CRParserInput *a_input)
+{
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->input)
+ {
+ cr_parser_input_unref (PRIVATE (a_this)->input) ;
+ }
+
+ PRIVATE (a_this)->input = a_input ;
+
+ cr_parser_input_ref (PRIVATE (a_this)->input) ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_tknzr_get_input (CRTknzr *a_this, CRParserInput **a_input)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ *a_input = PRIVATE (a_this)->input ;
+
+ return CR_OK ;
+}
+
+
+/*********************************
+ *Tokenizer input handling routines
+ *********************************/
+
+/**
+ *Reads the next byte from the parser input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser.
+ *@param a_byte out parameter the place where to store the byte
+ *read.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_tknzr_read_byte (CRTknzr *a_this, guchar *a_byte)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_parser_input_read_byte (PRIVATE (a_this)->input,
+ a_byte) ;
+
+}
+
+
+/**
+ *Reads the next char from the parser input stream.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_char out parameter. The read char.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_tknzr_read_char (CRTknzr *a_this, guint32 *a_char)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_read_char (PRIVATE (a_this)->input,
+ a_char) ;
+}
+
+/**
+ *Peeks a char from the parser input stream.
+ *To "peek a char" means reads the next char without consuming it.
+ *Subsequent calls to this function return the same char.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_char out parameter. The peeked char uppon successfull completion.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_tknzr_peek_char (CRTknzr *a_this, guint32 *a_char)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_char,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_peek_char (PRIVATE (a_this)->input,
+ a_char) ;
+}
+
+
+/**
+ *Peeks a byte ahead at a given postion in the parser input stream.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_offset the offset of the peeked byte starting from the current
+ *byte in the parser input stream.
+ *@param a_byte out parameter. The peeked byte upon
+ *successfull completion.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_tknzr_peek_byte (CRTknzr *a_this, gulong a_offset, guchar *a_byte)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input && a_byte,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_peek_byte (PRIVATE (a_this)->input,
+ CR_SEEK_CUR, a_offset, a_byte) ;
+}
+
+/**
+ *Gets the number of bytes left in the topmost input stream
+ *associated to this parser.
+ *@param a_this the current instance of #CRTknzr
+ *@return the number of bytes left or -1 in case of error.
+ */
+glong
+cr_tknzr_get_nb_bytes_left (CRTknzr *a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_get_nb_bytes_left (PRIVATE (a_this)->input) ;
+}
+
+
+enum CRStatus
+cr_tknzr_get_cur_pos (CRTknzr *a_this, CRParserInputPos *a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_pos, CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_get_cur_pos (PRIVATE (a_this)->input,
+ a_pos) ;
+}
+
+enum CRStatus
+cr_tknzr_get_cur_byte_addr (CRTknzr *a_this, guchar **a_addr)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_get_cur_byte_addr
+ (PRIVATE (a_this)->input, a_addr) ;
+}
+
+
+enum CRStatus
+cr_tknzr_seek_index (CRTknzr *a_this,
+ enum CRSeekPos a_origin,
+ gint a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_seek_index (PRIVATE (a_this)->input,
+ a_origin, a_pos) ;
+}
+
+enum CRStatus
+cr_tknzr_consume_chars (CRTknzr *a_this, guint32 a_char,
+ glong *a_nb_char)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos) ;
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_consume_chars (PRIVATE (a_this)->input,
+ a_char, a_nb_char) ;
+}
+
+enum CRStatus
+cr_tknzr_set_cur_pos (CRTknzr *a_this, CRParserInputPos *a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ return cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ a_pos) ;
+}
+
+enum CRStatus
+cr_tknzr_unget_token (CRTknzr *a_this, CRToken *a_token)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->token_cache == NULL,
+ CR_BAD_PARAM_ERROR) ;
+
+ PRIVATE (a_this)->token_cache = a_token ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_tknzr_get_next_token (CRTknzr *a_this, CRToken ** a_tk)
+{
+ enum CRStatus status = CR_OK ;
+ guchar next_bytes[10] = {0} ;
+ CRParserInputPos init_pos ;
+ CRToken *token = NULL ;
+ GString *str = NULL ;
+ CRNum *num = NULL ;
+ glong nb_bytes_left = 0 ;
+ gboolean reached_eof = FALSE ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_tk && *a_tk == NULL
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR) ;
+
+ memset (&init_pos,0, sizeof (CRParserInputPos)) ;
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ *a_tk = PRIVATE (a_this)->token_cache ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ return CR_OK ;
+ }
+
+ RECORD_INITIAL_POS (a_this, &init_pos) ;
+
+ status = cr_parser_input_get_end_of_file
+ (PRIVATE (a_this)->input, &reached_eof) ;
+ ENSURE_PARSING_COND (status == CR_OK) ;
+
+ if (reached_eof == TRUE)
+ {
+ status = CR_END_OF_INPUT_ERROR ;
+ goto error ;
+ }
+
+ nb_bytes_left = cr_parser_input_get_nb_bytes_left
+ (PRIVATE (a_this)->input) ;
+
+ if (nb_bytes_left >= 10)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+ PEEK_BYTE (a_this, 5, &next_bytes[4]) ;
+ PEEK_BYTE (a_this, 6, &next_bytes[5]) ;
+ PEEK_BYTE (a_this, 7, &next_bytes[6]) ;
+ PEEK_BYTE (a_this, 8, &next_bytes[7]) ;
+ PEEK_BYTE (a_this, 9, &next_bytes[8]) ;
+ PEEK_BYTE (a_this, 10, &next_bytes[9]) ;
+
+ if (next_bytes[0] == '@'
+ && next_bytes[1] == 'f'
+ && next_bytes[2] == 'o'
+ && next_bytes[3] == 'n'
+ && next_bytes[4] == 't'
+ && next_bytes[5] == '-'
+ && next_bytes[6] == 'f'
+ && next_bytes[7] == 'a'
+ && next_bytes[8] == 'c'
+ && next_bytes[9] == 'e')
+ {
+ SKIP_CHARS (a_this, 10) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_font_face_sym (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ }
+
+ if (nb_bytes_left >= 8)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+ PEEK_BYTE (a_this, 5, &next_bytes[4]) ;
+ PEEK_BYTE (a_this, 6, &next_bytes[5]) ;
+ PEEK_BYTE (a_this, 7, &next_bytes[6]) ;
+ PEEK_BYTE (a_this, 8, &next_bytes[7]) ;
+
+ if (next_bytes[0] == '@'
+ && next_bytes[1] == 'c'
+ && next_bytes[2] == 'h'
+ && next_bytes[3] == 'a'
+ && next_bytes[4] == 'r'
+ && next_bytes[5] == 's'
+ && next_bytes[6] == 'e'
+ && next_bytes[7] == 't')
+ {
+ SKIP_CHARS (a_this, 8) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_charset_sym (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+ if (nb_bytes_left >= 7)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+ PEEK_BYTE (a_this, 5, &next_bytes[4]) ;
+ PEEK_BYTE (a_this, 6, &next_bytes[5]) ;
+ PEEK_BYTE (a_this, 7, &next_bytes[6]) ;
+
+ if (next_bytes[0] == '@'
+ && next_bytes[1] == 'i'
+ && next_bytes[2] == 'm'
+ && next_bytes[3] == 'p'
+ && next_bytes[4] == 'o'
+ && next_bytes[5] == 'r'
+ && next_bytes[6] == 't')
+ {
+ SKIP_CHARS (a_this, 7) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_import_sym (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ }
+
+ if (nb_bytes_left >= 6)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+ PEEK_BYTE (a_this, 5, &next_bytes[4]) ;
+ PEEK_BYTE (a_this, 6, &next_bytes[5]) ;
+
+ if (next_bytes[0] == '@'
+ && next_bytes[1] == 'm'
+ && next_bytes[2] == 'e'
+ && next_bytes[3] == 'd'
+ && next_bytes[4] == 'i'
+ && next_bytes[5] == 'a')
+ {
+ SKIP_CHARS (a_this, 6) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_media_sym (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ }
+
+ if (nb_bytes_left >= 5)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+ PEEK_BYTE (a_this, 5, &next_bytes[4]) ;
+
+ if (next_bytes[0] == '@'
+ && next_bytes[1] == 'p'
+ && next_bytes[2] == 'a'
+ && next_bytes[3] == 'g'
+ && next_bytes[4] == 'e')
+ {
+ SKIP_CHARS (a_this, 5) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_page_sym (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+
+ if (nb_bytes_left >= 4)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+ PEEK_BYTE (a_this, 4, &next_bytes[3]) ;
+
+ if (next_bytes[0] == 'u'
+ && next_bytes[1] == 'r'
+ && next_bytes[2] == 'l'
+ && next_bytes[3] == '(')
+ {
+ status = cr_tknzr_parse_uri (a_this, &str) ;
+
+ if (status == CR_OK && str)
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_uri (token, str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ str = NULL ;
+ goto done ;
+ }
+ }
+
+ if (next_bytes[0] == 'r'
+ && next_bytes[1] == 'g'
+ && next_bytes[2] == 'b'
+ && next_bytes[3] == '(')
+ {
+ CRRgb * rgb = NULL ;
+
+ status = cr_tknzr_parse_rgb (a_this, &rgb) ;
+ if (status == CR_OK && rgb)
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_rgb (token, rgb) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+ }
+
+ if (nb_bytes_left >= 3)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+ PEEK_BYTE (a_this, 3, &next_bytes[2]) ;
+
+ if (next_bytes[0] == '<'
+ && next_bytes[1] == '-'
+ && next_bytes[2] == '-')
+ {
+ SKIP_CHARS (a_this, 3) ;
+ token = cr_token_new () ;
+ CHECK_PARSING_STATUS(status, TRUE) ;
+ status = cr_token_set_cdo (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == '-'
+ && next_bytes[1] == '-'
+ && next_bytes[2] == '>')
+ {
+ SKIP_CHARS (a_this, 3) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+ status = cr_token_set_cdc (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+
+ if (nb_bytes_left >= 2)
+ {
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+
+ if (next_bytes[0] == '~'
+ && next_bytes[1] == '=')
+ {
+ SKIP_CHARS (a_this, 2) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+ status = cr_token_set_includes (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == '|'
+ && next_bytes[1] == '=')
+ {
+ SKIP_CHARS (a_this, 2) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+ status = cr_token_set_dashmatch (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == '/' && next_bytes[1] == '*')
+ {
+ status = cr_tknzr_parse_comment (a_this, &str) ;
+
+ if (status == CR_OK)
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+ status = cr_token_set_comment (token, str) ;
+ str = NULL ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+ }
+
+ if (nb_bytes_left < 1)
+ {
+ return CR_END_OF_INPUT_ERROR ;
+ }
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+
+ if (next_bytes[0] == ';')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_semicolon (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == '{')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_cbo (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == '}')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_cbc (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == '(')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_po (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == ')')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_pc (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == '[')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_bo (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (next_bytes[0] == ']')
+ {
+ SKIP_CHARS (a_this, 1) ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_bc (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ if (cr_utils_is_white_space (next_bytes[0]) == TRUE)
+ {
+ guchar *start = NULL, *end = NULL ;
+
+ status = cr_tknzr_parse_w (a_this, &start, &end) ;
+ if (status == CR_OK)
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token) ;
+ status = cr_token_set_s (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+
+ if (next_bytes[0] == '#')
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_tknzr_parse_hash (a_this, &str) ;
+ if (status == CR_OK && str)
+ {
+ status = cr_token_set_hash (token, str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ str = NULL ;
+ goto done ;
+ }
+ }
+
+ if (next_bytes[0] == '@')
+ {
+ status = cr_tknzr_parse_atkeyword (a_this, &str) ;
+ if (status == CR_OK)
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_atkeyword (token, str) ;
+ str = NULL ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+
+ if (next_bytes[0] == '!')
+ {
+ status = cr_tknzr_parse_important (a_this) ;
+ if (status == CR_OK)
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_token_set_important_sym (token) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ }
+
+ if (IS_NUM (next_bytes[0])
+ || next_bytes[0] == '.')
+ {
+ status = cr_tknzr_parse_num (a_this, &num) ;
+ if (status == CR_OK && num)
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]) ;
+ PEEK_BYTE (a_this, 2, &next_bytes[1]) ;
+
+ if (next_bytes[0] == 'e'
+ && next_bytes[1] == 'm')
+ {
+ status = cr_token_set_ems (token, num) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'e'
+ && next_bytes[1] == 'x')
+ {
+ status = cr_token_set_exs (token, num) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'p'
+ && next_bytes[1] == 'x')
+ {
+ status = cr_token_set_length
+ (token, num,
+ LENGTH_PX_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'c'
+ && next_bytes[1] == 'm')
+ {
+ status = cr_token_set_length
+ (token, num, LENGTH_CM_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'm'
+ && next_bytes[1] == 'm')
+ {
+ status = cr_token_set_length
+ (token, num, LENGTH_MM_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'i'
+ && next_bytes[1] == 'n')
+ {
+ status = cr_token_set_length
+ (token, num, LENGTH_IN_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'p'
+ && next_bytes[1] == 't')
+ {
+ status = cr_token_set_length
+ (token, num, LENGTH_PT_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'p'
+ && next_bytes[1] == 'c')
+ {
+ status = cr_token_set_length
+ (token, num, LENGTH_PC_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'd'
+ && next_bytes[1] == 'e'
+ && next_bytes[2] == 'g')
+ {
+ status = cr_token_set_angle
+ (token, num, ANGLE_DEG_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 3) ;
+ }
+ else if (next_bytes[0] == 'r'
+ && next_bytes[1] == 'a'
+ && next_bytes[2] == 'd')
+ {
+ status = cr_token_set_angle
+ (token, num, ANGLE_RAD_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 3) ;
+ }
+ else if (next_bytes[0] == 'g'
+ && next_bytes[1] == 'r'
+ && next_bytes[2] == 'a'
+ && next_bytes[3] == 'd')
+ {
+ status = cr_token_set_angle
+ (token, num, ANGLE_GRAD_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 4) ;
+ }
+ else if (next_bytes[0] == 'm'
+ && next_bytes[1] == 's')
+ {
+ status = cr_token_set_time
+ (token, num,TIME_MS_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] =='s')
+ {
+ status = cr_token_set_time
+ (token, num, TIME_S_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 1) ;
+ }
+ else if (next_bytes[0] == 'H'
+ && next_bytes[1] == 'z')
+ {
+ status = cr_token_set_freq
+ (token, num, FREQ_HZ_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 2) ;
+ }
+ else if (next_bytes[0] == 'k'
+ && next_bytes[1] == 'H'
+ && next_bytes[1] == 'z')
+ {
+ status = cr_token_set_freq
+ (token, num, FREQ_KHZ_ET) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 3) ;
+ }
+ else if (next_bytes[0] == '%')
+ {
+ status = cr_token_set_percentage (token,
+ num) ;
+ num = NULL ;
+ SKIP_CHARS (a_this, 1) ;
+ }
+ else
+ {
+ status = cr_tknzr_parse_ident (a_this,
+ &str) ;
+ if (status == CR_OK && str)
+ {
+ status = cr_token_set_dimen
+ (token, num, str) ;
+ num = NULL ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ str = NULL ;
+ }
+ else
+ {
+ status = cr_token_set_number
+ (token, num) ;
+ num = NULL ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ str = NULL ;
+ }
+ }
+
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+ else
+ {
+ /*could not parse a {num}*/
+ if (num)
+ {
+ cr_num_destroy (num) ;
+ num = NULL ;
+ }
+ }
+ }
+
+ if (next_bytes[0] == '\''
+ || next_bytes[0] == '"')
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+ status = cr_tknzr_parse_string (a_this, &str) ;
+
+ if (status == CR_OK && str)
+ {
+ status = cr_token_set_string (token, str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ str = NULL ;
+ goto done ;
+ }
+ }
+
+ if (next_bytes[0] == '\\'
+ || (cr_utils_is_nonascii (next_bytes[0]) == TRUE)
+ || ((next_bytes[0] >= 'a') && (next_bytes[0] <= 'z'))
+ || ((next_bytes[0] >= 'A') && (next_bytes[0] <= 'Z')))
+ {
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ status = cr_tknzr_parse_ident (a_this, &str) ;
+ if (status == CR_OK && str)
+ {
+ guint32 next_char = 0 ;
+
+ status = cr_parser_input_peek_char
+ (PRIVATE (a_this)->input, &next_char) ;
+
+ if (status == CR_OK && next_char == '(')
+ {
+
+ SKIP_CHARS (a_this, 1) ;
+ status = cr_token_set_function
+ (token, str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ str = NULL ;/*ownership is transfered
+ *to cr_token_set_function.
+ */
+ }
+ else
+ {
+ status = cr_token_set_ident (token, str) ;
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ str = NULL ;
+ }
+
+ goto done ;
+ }
+ else
+ {
+ g_string_free (str, TRUE) ;
+ str = NULL ;
+ }
+ }
+
+
+ {
+ guint32 cur_char = 0 ;
+ token = cr_token_new () ;
+ ENSURE_PARSING_COND (token != NULL) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ status = cr_token_set_delim (token, cur_char) ;
+
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ goto done ;
+ }
+
+ done:
+
+ if (str)
+ {
+ g_string_free (str, TRUE) ;
+ str = NULL ;
+ }
+
+ if (num)
+ {
+ cr_num_destroy (num) ;
+ num = NULL ;
+ }
+
+ if (status == CR_OK)
+ {
+ *a_tk = token ;
+ memmove (&PRIVATE (a_this)->prev_pos,
+ &init_pos, sizeof (CRParserInputPos)) ;
+ return CR_OK ;
+ }
+
+
+
+ error:
+
+ if (token)
+ {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ if (str)
+ {
+ g_string_free (str, TRUE) ;
+ str = NULL ;
+ }
+
+ if (num)
+ {
+ cr_num_destroy (num) ;
+ num = NULL ;
+ }
+
+ cr_parser_input_set_cur_pos (PRIVATE (a_this)->input,
+ &init_pos) ;
+ return status ;
+
+}
+
+
+enum CRStatus
+cr_tknzr_parse_token (CRTknzr *a_this, enum CRTokenType a_type,
+ enum CRTokenExtraType a_et, void *a_res,
+ void *a_extra_res)
+{
+ enum CRStatus status = CR_OK ;
+ CRToken *token = NULL ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_res,
+ CR_BAD_PARAM_ERROR) ;
+
+ status = cr_tknzr_get_next_token (a_this,
+ &token) ;
+ if (status != CR_OK) return status ;
+ if (token == NULL) return CR_PARSING_ERROR ;
+
+ if (token->type == a_type)
+ {
+ switch (a_type)
+ {
+ case NO_TK:
+ case S_TK:
+ case CDO_TK:
+ case CDC_TK:
+ case INCLUDES_TK:
+ case DASHMATCH_TK:
+ case IMPORT_SYM_TK:
+ case PAGE_SYM_TK:
+ case MEDIA_SYM_TK:
+ case FONT_FACE_SYM_TK:
+ case CHARSET_SYM_TK:
+ case IMPORTANT_SYM_TK:
+ status = CR_OK ;
+ break ;
+
+ case STRING_TK:
+ case IDENT_TK:
+ case HASH_TK:
+ case ATKEYWORD_TK:
+ case FUNCTION_TK:
+ case COMMENT_TK:
+ case URI_TK:
+ *((GString**)a_res) = token->str ;
+ token->str = NULL ;
+ status = CR_OK ;
+ break ;
+
+ case EMS_TK:
+ case EXS_TK:
+ case PERCENTAGE_TK:
+ case NUMBER_TK:
+ *((CRNum**)a_res) = token->num ;
+ token->num = NULL ;
+ status = CR_OK ;
+ break ;
+
+ case LENGTH_TK:
+ case ANGLE_TK:
+ case TIME_TK:
+ case FREQ_TK:
+ if (token->extra_type == a_et)
+ {
+ *((CRNum**)a_res) = token->num ;
+ token->num = NULL ;
+ status = CR_OK ;
+ }
+ break ;
+
+ case DIMEN_TK:
+ *((CRNum**)a_res) = token->num ;
+ if (a_extra_res == NULL)
+ {
+ status = CR_BAD_PARAM_ERROR ;
+ goto error ;
+ }
+
+ *((GString**)a_extra_res) = token->dimen ;
+ token->num = NULL ;
+ token->dimen = NULL ;
+ status = CR_OK ;
+ break ;
+
+ case DELIM_TK:
+ *((guint32*)a_res) = token->unichar ;
+ status = CR_OK ;
+ break ;
+
+ case UNICODERANGE_TK:
+ default:
+ status = CR_PARSING_ERROR ;
+ break ;
+ }
+
+ cr_token_destroy (token) ; token = NULL ;
+ }
+ else
+ {
+ cr_tknzr_unget_token (a_this,
+ token) ;
+ token = NULL ;
+ status = CR_PARSING_ERROR ;
+ }
+
+ return status ;
+
+ error:
+
+ if (token)
+ {
+ cr_tknzr_unget_token (a_this, token) ;
+ token = NULL ;
+ }
+
+ return status ;
+}
+
+void
+cr_tknzr_destroy (CRTknzr *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+
+ if (PRIVATE (a_this) && PRIVATE (a_this)->input)
+ {
+ if (cr_parser_input_unref (PRIVATE (a_this)->input)
+ == TRUE)
+ {
+ PRIVATE (a_this)->input = NULL ;
+ }
+ }
+
+ if (PRIVATE (a_this)->token_cache)
+ {
+ cr_token_destroy (PRIVATE (a_this)->token_cache) ;
+ PRIVATE (a_this)->token_cache = NULL ;
+ }
+
+ if (PRIVATE (a_this))
+ {
+ g_free (PRIVATE (a_this)) ;
+ PRIVATE (a_this) = NULL ;
+ }
+
+ g_free (a_this) ;
+}
diff --git a/src/cr-tknzr.h b/src/cr-tknzr.h
new file mode 100644
index 0000000..8852f64
--- /dev/null
+++ b/src/cr-tknzr.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The declaration of the #CRTknzr (tokenizer)
+ *class.
+ */
+#ifndef __CR_TKNZR_H__
+#define __CR_TKNZR_H__
+
+#include "cr-utils.h"
+#include "cr-parser-input.h"
+#include "cr-token.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRTknzr CRTknzr ;
+typedef struct _CRTknzrPriv CRTknzrPriv ;
+
+struct _CRTknzr
+{
+ CRTknzrPriv *priv ;
+} ;
+
+CRTknzr *
+cr_tknzr_new (CRParserInput *a_input) ;
+
+CRTknzr *
+cr_tknzr_new_from_uri (guchar *a_file_uri,
+ enum CREncoding a_enc) ;
+
+gboolean
+cr_tknzr_unref (CRTknzr *a_this) ;
+
+void
+cr_tknzr_ref (CRTknzr *a_this) ;
+
+enum CRStatus
+cr_tknzr_read_byte (CRTknzr *a_this, guchar *a_byte) ;
+
+enum CRStatus
+cr_tknzr_read_char (CRTknzr *a_this, guint32 *a_char);
+
+enum CRStatus
+cr_tknzr_peek_char (CRTknzr *a_this, guint32 *a_char) ;
+
+enum CRStatus
+cr_tknzr_peek_byte (CRTknzr *a_this, gulong a_offset,
+ guchar *a_byte) ;
+
+enum CRStatus
+cr_tknzr_set_cur_pos (CRTknzr *a_this, CRParserInputPos *a_pos) ;
+
+glong
+cr_tknzr_get_nb_bytes_left (CRTknzr *a_this) ;
+
+enum CRStatus
+cr_tknzr_get_cur_pos (CRTknzr *a_this, CRParserInputPos *a_pos) ;
+
+enum CRStatus
+cr_tknzr_get_cur_byte_addr (CRTknzr *a_this, guchar **a_addr) ;
+
+enum CRStatus
+cr_tknzr_seek_index (CRTknzr *a_this,
+ enum CRSeekPos a_origin,
+ gint a_pos) ;
+
+enum CRStatus
+cr_tknzr_get_cur_byte_addr (CRTknzr *a_this, guchar **a_addr) ;
+
+
+enum CRStatus
+cr_tknzr_consume_chars (CRTknzr *a_this, guint32 a_char,
+ glong *a_nb_char) ;
+
+enum CRStatus
+cr_tknzr_get_next_token (CRTknzr *a_this, CRToken ** a_tk) ;
+
+enum CRStatus
+cr_tknzr_unget_token (CRTknzr *a_this, CRToken *a_token) ;
+
+
+enum CRStatus
+cr_tknzr_parse_token (CRTknzr *a_this, enum CRTokenType a_type,
+ enum CRTokenExtraType a_et, void *a_res,
+ void *a_extra_res) ;
+enum CRStatus
+cr_tknzr_set_input (CRTknzr *a_this, CRParserInput *a_input) ;
+
+enum CRStatus
+cr_tknzr_get_input (CRTknzr *a_this, CRParserInput **a_input) ;
+
+void
+cr_tknzr_destroy (CRTknzr *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_TKZNR_H__*/
diff --git a/src/cr-token.c b/src/cr-token.c
new file mode 100644
index 0000000..03921b5
--- /dev/null
+++ b/src/cr-token.c
@@ -0,0 +1,678 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition of the #CRToken class.
+ *Abstracts a css2 token.
+ */
+#include <string.h>
+#include "cr-token.h"
+
+
+/**
+ *Frees the attributes of the current instance
+ *of #CRtoken.
+ *@param a_this the current instance of #CRToken.
+ */
+static void
+cr_token_clear (CRToken *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ switch (a_this->type)
+ {
+ case S_TK:
+ case CDO_TK:
+ case INCLUDES_TK:
+ case DASHMATCH_TK:
+ case PAGE_SYM_TK:
+ case MEDIA_SYM_TK:
+ case FONT_FACE_SYM_TK:
+ case CHARSET_SYM_TK:
+ case IMPORT_SYM_TK:
+ case IMPORTANT_SYM_TK:
+ break ;
+
+ case STRING_TK:
+ case IDENT_TK:
+ case HASH_TK:
+ case URI_TK:
+ case FUNCTION_TK:
+ case COMMENT_TK:
+ if (a_this->str)
+ {
+ g_string_free (a_this->str, TRUE) ;
+ a_this->str = NULL ;
+ }
+ break ;
+
+ case EMS_TK:
+ case EXS_TK:
+ case LENGTH_TK:
+ case ANGLE_TK:
+ case TIME_TK:
+ case FREQ_TK:
+ case PERCENTAGE_TK:
+ case NUMBER_TK:
+ if (a_this->num)
+ {
+ cr_num_destroy (a_this->num) ;
+ a_this->num = NULL ;
+ }
+ break ;
+
+ case DIMEN_TK:
+ if (a_this->num)
+ {
+ cr_num_destroy (a_this->num) ;
+ a_this->num = NULL ;
+ }
+
+ if (a_this->dimen)
+ {
+ g_string_free (a_this->dimen, TRUE) ;
+ a_this->dimen = NULL ;
+ }
+
+ break ;
+
+ case UNICODERANGE_TK:
+ /*not supported yet.*/
+ break ;
+
+ default:
+ break ;
+ }
+
+ a_this->type = NO_TK ;
+}
+
+
+/**
+ *Default constructor of
+ *the #CRToken class.
+ *@return the newly built instance of #CRToken.
+ */
+CRToken*
+cr_token_new (void)
+{
+ CRToken *result = NULL ;
+
+ result = g_try_malloc (sizeof (CRToken)) ;
+
+ if (result == NULL)
+ {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+
+ memset (result, 0, sizeof (CRToken)) ;
+
+ return result ;
+}
+
+
+/**
+ *Sets the type of curren instance of
+ *#CRToken to 'S_TK' (S in the css2 spec)
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_s (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = S_TK ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to 'CDO_TK' (CDO as said by the css2 spec)
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_cdo (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = CDO_TK ;
+
+ return CR_OK ;
+}
+
+/**
+ *Sets the type of the current token to
+ *CDC_TK (CDC as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_cdc (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = CDC_TK ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to INCLUDES_TK (INCLUDES as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_includes (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = INCLUDES_TK ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to DASHMATCH_TK (DASHMATCH as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_dashmatch (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = DASHMATCH_TK ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_token_set_comment (CRToken *a_this, GString *a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = COMMENT_TK ;
+
+ a_this->str = a_str ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_string (CRToken *a_this, GString *a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = STRING_TK ;
+
+ a_this->str = a_str ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_token_set_ident (CRToken *a_this, GString * a_ident)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = IDENT_TK ;
+
+ a_this->str = a_ident ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_token_set_function (CRToken *a_this, GString *a_fun_name)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = FUNCTION_TK ;
+
+ a_this->str = a_fun_name ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_hash (CRToken *a_this, GString *a_hash)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = HASH_TK ;
+
+ a_this->str = a_hash ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_rgb (CRToken *a_this, CRRgb *a_rgb)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = RGB_TK ;
+
+ a_this->rgb = a_rgb ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_import_sym (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = IMPORT_SYM_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_page_sym (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = PAGE_SYM_TK ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_token_set_media_sym (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = MEDIA_SYM_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_font_face_sym (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = FONT_FACE_SYM_TK ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_token_set_charset_sym (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = CHARSET_SYM_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_atkeyword (CRToken *a_this, GString *a_atname)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = ATKEYWORD_TK ;
+
+ a_this->str = a_atname ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_important_sym (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = IMPORTANT_SYM_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_ems (CRToken *a_this, CRNum *a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = EMS_TK ;
+
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_token_set_exs (CRToken *a_this, CRNum *a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = EXS_TK ;
+
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_length (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = LENGTH_TK ;
+
+ a_this->extra_type = a_et ;
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_angle (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = ANGLE_TK ;
+ a_this->extra_type = a_et ;
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_time (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = TIME_TK ;
+ a_this->extra_type = a_et;
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_freq (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = FREQ_TK ;
+ a_this->extra_type = a_et ;
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_dimen (CRToken *a_this, CRNum *a_num,
+ GString *a_dim)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = DIMEN_TK ;
+ a_this->num = a_num ;
+ a_this->dimen = a_dim ;
+
+ return CR_OK ;
+
+}
+
+
+enum CRStatus
+cr_token_set_percentage (CRToken *a_this, CRNum *a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = PERCENTAGE_TK ;
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_number (CRToken *a_this, CRNum *a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = NUMBER_TK ;
+ a_this->num = a_num ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_uri (CRToken *a_this, GString *a_uri)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = URI_TK ;
+ a_this->str = a_uri ;
+
+ return CR_OK ;
+}
+
+
+enum CRStatus
+cr_token_set_delim (CRToken *a_this, guint32 a_char)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = DELIM_TK ;
+ a_this->unichar = a_char ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_semicolon (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = SEMICOLON_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_cbo (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = CBO_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_cbc (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = CBC_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_po (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = PO_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_pc (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = PC_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_bo (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = BO_TK ;
+
+ return CR_OK ;
+}
+
+enum CRStatus
+cr_token_set_bc (CRToken *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_token_clear (a_this) ;
+
+ a_this->type = BC_TK ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *The destructor of the #CRToken class.
+ *@param a_this the current instance of #CRToken.
+ */
+void
+cr_token_destroy (CRToken *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ cr_token_clear (a_this) ;
+
+ g_free (a_this) ;
+}
diff --git a/src/cr-token.h b/src/cr-token.h
new file mode 100644
index 0000000..dc0a028
--- /dev/null
+++ b/src/cr-token.h
@@ -0,0 +1,260 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_TOKEN_H__
+#define __CR_TOKEN_H__
+
+#include "cr-utils.h"
+#include "cr-input.h"
+#include "cr-num.h"
+#include "cr-rgb.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ enum CRTokenType
+ {
+ NO_TK,
+ S_TK,
+ CDO_TK,
+ CDC_TK,
+ INCLUDES_TK,
+ DASHMATCH_TK,
+ COMMENT_TK,
+ STRING_TK,
+ IDENT_TK,
+ HASH_TK,
+ IMPORT_SYM_TK,
+ PAGE_SYM_TK,
+ MEDIA_SYM_TK,
+ FONT_FACE_SYM_TK,
+ CHARSET_SYM_TK,
+ ATKEYWORD_TK,
+ IMPORTANT_SYM_TK,
+ EMS_TK,
+ EXS_TK,
+ LENGTH_TK,
+ ANGLE_TK,
+ TIME_TK,
+ FREQ_TK,
+ DIMEN_TK,
+ PERCENTAGE_TK,
+ NUMBER_TK,
+ RGB_TK,
+ URI_TK,
+ FUNCTION_TK,
+ UNICODERANGE_TK,
+ SEMICOLON_TK,
+ CBO_TK, /*opening curly bracket*/
+ CBC_TK, /*closing curly bracket*/
+ PO_TK, /*opening parenthesis*/
+ PC_TK, /*closing parenthesis*/
+ BO_TK, /*opening bracket*/
+ BC_TK, /*closing bracket*/
+ DELIM_TK,
+ } ;
+
+ enum CRTokenExtraType
+ {
+ NO_ET = 0,
+ LENGTH_PX_ET,
+ LENGTH_CM_ET,
+ LENGTH_MM_ET,
+ LENGTH_IN_ET,
+ LENGTH_PT_ET,
+ LENGTH_PC_ET,
+ ANGLE_DEG_ET,
+ ANGLE_RAD_ET,
+ ANGLE_GRAD_ET,
+ TIME_MS_ET,
+ TIME_S_ET,
+ FREQ_HZ_ET,
+ FREQ_KHZ_ET,
+ } ;
+
+ typedef struct _CRToken CRToken ;
+
+ /**
+ *This class abstracts a css2 token.
+ */
+ struct _CRToken
+ {
+ enum CRTokenType type ;
+ enum CRTokenExtraType extra_type ;
+ CRInputPos pos ;
+
+ union
+ {
+ GString *str ;
+ CRRgb *rgb ;
+ CRNum *num ;
+ guint32 unichar ;
+ } ;
+
+ GString * dimen ;
+ } ;
+
+ CRToken*
+ cr_token_new (void) ;
+
+ enum CRStatus
+ cr_token_set_s (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_cdo (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_cdc (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_includes (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_dashmatch (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_comment (CRToken *a_this, GString *a_str) ;
+
+ enum CRStatus
+ cr_token_set_string (CRToken *a_this, GString *a_str) ;
+
+ enum CRStatus
+ cr_token_set_ident (CRToken *a_this, GString * a_ident) ;
+
+ enum CRStatus
+ cr_token_set_hash (CRToken *a_this, GString *a_hash) ;
+
+ enum CRStatus
+ cr_token_set_rgb (CRToken *a_this, CRRgb *a_rgb) ;
+
+ enum CRStatus
+ cr_token_set_import_sym (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_page_sym (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_media_sym (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_font_face_sym (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_charset_sym (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_atkeyword (CRToken *a_this, GString *a_atname) ;
+
+ enum CRStatus
+ cr_token_set_important_sym (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_ems (CRToken *a_this, CRNum *a_num) ;
+
+ enum CRStatus
+ cr_token_set_exs (CRToken *a_this, CRNum *a_num) ;
+
+ enum CRStatus
+ cr_token_set_length (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+
+ enum CRStatus
+ cr_token_set_angle (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+
+ enum CRStatus
+ cr_token_set_time (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+
+ enum CRStatus
+ cr_token_set_freq (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+ enum CRStatus
+ cr_token_set_dimen (CRToken *a_this, CRNum *a_num,
+ GString *a_dim) ;
+
+ enum CRStatus
+ cr_token_set_percentage (CRToken *a_this, CRNum *a_num) ;
+
+ enum CRStatus
+ cr_token_set_number (CRToken *a_this, CRNum *a_num) ;
+
+ enum CRStatus
+ cr_token_set_uri (CRToken *a_this, GString *a_uri) ;
+
+ enum CRStatus
+ cr_token_set_delim (CRToken *a_this, guint32 a_char) ;
+
+ enum CRStatus
+ cr_token_set_function (CRToken *a_this, GString *a_fun_name) ;
+
+ enum CRStatus
+ cr_token_set_bc (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_bo (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_po (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_pc (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_cbc (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_cbo (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_semicolon (CRToken *a_this) ;
+
+ enum CRStatus
+ cr_token_set_delim (CRToken *a_this, guint32 a_char) ;
+
+
+ /*
+ enum CRStatus
+ cr_token_set_unicoderange (CRToken *a_this,
+ CRUnicodeRange *a_range) ;
+ */
+
+ void
+ cr_token_destroy (CRToken *a_this) ;
+
+
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*__CR_TOKEN_H__*/
diff --git a/src/cr-utils.c b/src/cr-utils.c
new file mode 100644
index 0000000..ad3669c
--- /dev/null
+++ b/src/cr-utils.c
@@ -0,0 +1,1424 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include "cr-utils.h"
+
+/**
+ *@file:
+ *Some misc utility functions used
+ *in the libcroco.
+ *Note that troughout this file I will
+ *refer to the CSS SPECIFICATIONS DOCUMENTATION
+ *written by the w3c guys. You can find that document
+ *at http://www.w3.org/TR/REC-CSS2/ .
+ */
+
+
+/****************************
+ *Encoding transformations and
+ *encoding helpers
+ ****************************/
+
+/*
+ *Here is the correspondance between the ucs-4 charactere codes
+ *and there matching utf-8 encoding pattern as dscribed by RFC 2279:
+ *
+ *UCS-4 range (hex.) UTF-8 octet sequence (binary)
+ *------------------ -----------------------------
+ *0000 0000-0000 007F 0xxxxxxx
+ *0000 0080-0000 07FF 110xxxxx 10xxxxxx
+ *0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
+ *0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx
+ */
+
+
+
+/**
+ *Given an utf8 string buffer, calculates
+ *the length of this string if it was encoded
+ *in ucs4.
+ *@param a_in_start a pointer to the begining of
+ *the input utf8 string.
+ *@param a_in_end a pointre to the end of the input
+ *utf8 string (points to the last byte of the buffer)
+ *@param a_len out parameter the calculated length.
+ *@return CR_OK upon succesfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs4 (guchar *a_in_start,
+ guchar *a_in_end,
+ gulong *a_len)
+{
+ guchar *byte_ptr = NULL ;
+ gint len = 0 ;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint c = 0 ;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR) ;
+ *a_len = 0 ;
+
+ for (byte_ptr = a_in_start ;
+ byte_ptr <= a_in_end ;
+ byte_ptr++)
+ {
+ gint nb_bytes_2_decode = 0 ;
+
+ if (*byte_ptr <= 0x7F)
+ {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = *byte_ptr ;
+ nb_bytes_2_decode = 1 ;
+
+ }
+ else if ((*byte_ptr & 0xE0) == 0xC0)
+ {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x1F ;
+ nb_bytes_2_decode = 2 ;
+
+ }
+ else if ((*byte_ptr & 0xF0) == 0xE0)
+ {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x0F ;
+ nb_bytes_2_decode = 3 ;
+
+ }
+ else if ((*byte_ptr & 0xF8) == 0xF0)
+ {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x7 ;
+ nb_bytes_2_decode = 4 ;
+
+ }
+ else if ((*byte_ptr & 0xFC) == 0xF8)
+ {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 3 ;
+ nb_bytes_2_decode = 5 ;
+
+ }
+ else if ((*byte_ptr & 0xFE) == 0xFC)
+ {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 1 ;
+ nb_bytes_2_decode = 6 ;
+
+ }
+ else
+ {
+ /*
+ *BAD ENCODING
+ */
+ return CR_ENCODING_ERROR ;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for ( ;
+ nb_bytes_2_decode > 1 ;
+ nb_bytes_2_decode --)
+ {
+ /*decode the next byte*/
+ byte_ptr ++ ;
+
+ /*byte pattern must be: 10xx xxxx*/
+ if ((*byte_ptr & 0xC0) != 0x80)
+ {
+ return CR_ENCODING_ERROR ;
+ }
+
+ c = (c << 6) | (*byte_ptr & 0x3F) ;
+ }
+
+ len ++ ;
+ }
+
+ *a_len = len ;
+
+ return CR_OK ;
+}
+
+
+
+/**
+ *Given an ucs4 string, this function
+ *returns the size (in bytes) this string
+ *would have occupied if it was encoded in utf-8.
+ *@param a_in_start a pointer to the beginning of the input
+ *buffer.
+ *@param a_in_end a pointer to the end of the input buffer.
+ *@param a_len out parameter. The computed length.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_str_len_as_utf8 (guint32 *a_in_start, guint32 *a_in_end,
+ gulong *a_len)
+{
+ gint len = 0 ;
+ guint32 *char_ptr = NULL ;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR) ;
+
+ for (char_ptr = a_in_start ;
+ char_ptr <= a_in_end ;
+ char_ptr ++)
+ {
+ if (*char_ptr <= 0x7F)
+ {
+ /*the utf-8 char would take 1 byte*/
+ len += 1 ;
+ }
+ else if (*char_ptr <= 0x7FF)
+ {
+ /*the utf-8 char would take 2 bytes*/
+ len += 2 ;
+ }
+ else if (*char_ptr <= 0xFFFF)
+ {
+ len += 3 ;
+ }
+ else if (*char_ptr <= 0x1FFFFF)
+ {
+ len += 4 ;
+ }
+ else if (*char_ptr <= 0x3FFFFFF)
+ {
+ len += 5 ;
+ }
+ else if (*char_ptr <= 0x7FFFFFFF)
+ {
+ len+= 6 ;
+ }
+ }
+
+ *a_len = len ;
+ return CR_OK ;
+}
+
+
+/**
+ *Given an ucsA string, this function
+ *returns the size (in bytes) this string
+ *would have occupied if it was encoded in utf-8.
+ *@param a_in_start a pointer to the beginning of the input
+ *buffer.
+ *@param a_in_end a pointer to the end of the input buffer.
+ *@param a_len out parameter. The computed length.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs1_str_len_as_utf8 (guchar *a_in_start, guchar *a_in_end,
+ gulong *a_len)
+{
+ gint len = 0 ;
+ guchar *char_ptr = NULL ;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR) ;
+
+ for (char_ptr = a_in_start ;
+ char_ptr <= a_in_end ;
+ char_ptr ++)
+ {
+ if (*char_ptr <= 0x7F)
+ {
+ /*the utf-8 char would take 1 byte*/
+ len += 1 ;
+ }
+ else
+ {
+ /*the utf-8 char would take 2 bytes*/
+ len += 2 ;
+ }
+ }
+
+ *a_len = len ;
+ return CR_OK ;
+}
+
+/**
+ *Converts an utf8 buffer into an ucs4 buffer.
+ *
+ *@param a_in the input utf8 buffer to convert.
+ *@param a_in_len in/out parameter. The size of the
+ *input buffer to convert. After return, this parameter contains
+ *the actual number of bytes consumed.
+ *@param a_out the output converted ucs4 buffer. Must be allocated by
+ *the caller.
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If this size is actually smaller than the real needed size, the function
+ *just converts what it can and returns a success status. After return,
+ *this param points to the actual number of characters decoded.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_to_ucs4 (guchar * a_in, gulong *a_in_len,
+ guint32 *a_out, gulong *a_out_len)
+{
+ gulong in_len = 0, out_len = 0, in_index = 0, out_index = 0 ;
+ enum CRStatus status = CR_OK ;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint c = 0 ;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (*a_in_len < 1)
+ {
+ status = CR_OK ;
+ goto end ;
+ }
+
+ in_len = *a_in_len ;
+ out_len = *a_out_len ;
+
+ for (in_index = 0, out_index = 0 ;
+ (in_index < in_len) && (out_index < out_len) ;
+ in_index++, out_index++)
+ {
+ gint nb_bytes_2_decode = 0 ;
+
+ if (a_in[in_index] <= 0x7F)
+ {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = a_in[in_index] ;
+ nb_bytes_2_decode = 1 ;
+
+ }
+ else if ((a_in[in_index] & 0xE0) == 0xC0)
+ {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x1F ;
+ nb_bytes_2_decode = 2 ;
+
+ }
+ else if ((a_in[in_index] & 0xF0) == 0xE0)
+ {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x0F ;
+ nb_bytes_2_decode = 3 ;
+
+ }
+ else if ((a_in[in_index] & 0xF8) == 0xF0)
+ {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x7 ;
+ nb_bytes_2_decode = 4 ;
+
+ }
+ else if ((a_in[in_index] & 0xFC) == 0xF8)
+ {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 3 ;
+ nb_bytes_2_decode = 5 ;
+
+ }
+ else if ((a_in[in_index] & 0xFE) == 0xFC)
+ {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 1 ;
+ nb_bytes_2_decode = 6 ;
+
+ }
+ else
+ {
+ /*BAD ENCODING*/
+ goto end ;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for ( ;
+ nb_bytes_2_decode > 1 ;
+ nb_bytes_2_decode --)
+ {
+ /*decode the next byte*/
+ in_index ++ ;
+
+ /*byte pattern must be: 10xx xxxx*/
+ if ((a_in[in_index] & 0xC0) != 0x80)
+ {
+ goto end ;
+ }
+
+ c = (c << 6) | (a_in[in_index] & 0x3F) ;
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ /************************
+ *Some security tests
+ ***********************/
+
+ /*be sure c is a char*/
+ if (c == 0xFFFF || c == 0xFFFE) goto end ;
+
+ /*be sure c is inferior to the max ucs4 char value*/
+ if (c > 0x10FFFF) goto end ;
+
+ /*
+ *c must be less than UTF16 "lower surrogate begin"
+ *or higher than UTF16 "High surrogate end"
+ */
+ if (c >= 0xD800 && c <= 0xDFFF) goto end ;
+
+ /*Avoid characters that equals zero*/
+ if (c == 0) goto end ;
+
+
+ a_out[out_index] = c ;
+ }
+
+ end:
+ *a_out_len = out_index + 1;
+ *a_in_len = in_index + 1;
+
+ return status ;
+}
+
+
+/**
+ *Reads a character from an utf8 buffer.
+ *Actually decode the next character code (unicode character code)
+ *and returns it.
+ *@param a_in the starting address of the utf8 buffer.
+ *@param a_in_len the length of the utf8 buffer.
+ *@param a_out output parameter. The resulting read char.
+ *@param a_consumed the number of the bytes consumed to
+ *decode the returned character code.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_read_char_from_utf8_buf (guchar * a_in, gulong a_in_len,
+ guint32 *a_out, gulong *a_consumed)
+{
+ gulong in_len = 0, in_index = 0, nb_bytes_2_decode = 0 ;
+ enum CRStatus status = CR_OK ;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint32 c = 0 ;
+
+ g_return_val_if_fail (a_in && a_out && a_out
+ && a_consumed, CR_BAD_PARAM_ERROR) ;
+
+ if (a_in_len < 1)
+ {
+ status = CR_OK ;
+ goto end ;
+ }
+
+ in_len = a_in_len ;
+
+ if (*a_in <= 0x7F)
+ {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = *a_in ;
+ nb_bytes_2_decode = 1 ;
+
+ }
+ else if ((*a_in & 0xE0) == 0xC0)
+ {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = *a_in & 0x1F ;
+ nb_bytes_2_decode = 2 ;
+
+ }
+ else if ((*a_in & 0xF0) == 0xE0)
+ {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 0x0F ;
+ nb_bytes_2_decode = 3 ;
+
+ }
+ else if ((*a_in & 0xF8) == 0xF0)
+ {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 0x7 ;
+ nb_bytes_2_decode = 4 ;
+
+ }
+ else if ((*a_in & 0xFC) == 0xF8)
+ {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 3 ;
+ nb_bytes_2_decode = 5 ;
+
+ }
+ else if ((*a_in & 0xFE) == 0xFC)
+ {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 1 ;
+ nb_bytes_2_decode = 6 ;
+
+ }
+ else
+ {
+ /*BAD ENCODING*/
+ goto end ;
+ }
+
+ if (nb_bytes_2_decode > a_in_len)
+ {
+ status = CR_END_OF_INPUT_ERROR ;
+ goto end ;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for ( in_index = 1 ;
+ in_index < nb_bytes_2_decode ;
+ in_index ++)
+ {
+ /*byte pattern must be: 10xx xxxx*/
+ if ((a_in[in_index] & 0xC0) != 0x80)
+ {
+ goto end ;
+ }
+
+ c = (c << 6) | (a_in[in_index] & 0x3F) ;
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ /************************
+ *Some security tests
+ ***********************/
+
+ /*be sure c is a char*/
+ if (c == 0xFFFF || c == 0xFFFE) goto end ;
+
+ /*be sure c is inferior to the max ucs4 char value*/
+ if (c > 0x10FFFF) goto end ;
+
+ /*
+ *c must be less than UTF16 "lower surrogate begin"
+ *or higher than UTF16 "High surrogate end"
+ */
+ if (c >= 0xD800 && c <= 0xDFFF) goto end ;
+
+ /*Avoid characters that equals zero*/
+ if (c == 0) goto end ;
+
+ *a_out = c ;
+
+ end:
+ *a_consumed = nb_bytes_2_decode ;
+
+ return status ;
+}
+
+
+/**
+ *
+ */
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs1 (guchar *a_in_start,
+ guchar *a_in_end,
+ gulong *a_len)
+{
+ /*
+ *Note: this function can be made shorter
+ *but it considers all the cases of the utf8 encoding
+ *to ease further extensions ...
+ */
+
+ guchar *byte_ptr = NULL ;
+ gint len = 0 ;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint c = 0 ;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR) ;
+ *a_len = 0 ;
+
+ for (byte_ptr = a_in_start ;
+ byte_ptr <= a_in_end ;
+ byte_ptr++)
+ {
+ gint nb_bytes_2_decode = 0 ;
+
+ if (*byte_ptr <= 0x7F)
+ {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = *byte_ptr ;
+ nb_bytes_2_decode = 1 ;
+
+ }
+ else if ((*byte_ptr & 0xE0) == 0xC0)
+ {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x1F ;
+ nb_bytes_2_decode = 2 ;
+
+ }
+ else if ((*byte_ptr & 0xF0) == 0xE0)
+ {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x0F ;
+ nb_bytes_2_decode = 3 ;
+
+ }
+ else if ((*byte_ptr & 0xF8) == 0xF0)
+ {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x7 ;
+ nb_bytes_2_decode = 4 ;
+
+ }
+ else if ((*byte_ptr & 0xFC) == 0xF8)
+ {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 3 ;
+ nb_bytes_2_decode = 5 ;
+
+ }
+ else if ((*byte_ptr & 0xFE) == 0xFC)
+ {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 1 ;
+ nb_bytes_2_decode = 6 ;
+
+ }
+ else
+ {
+ /*
+ *BAD ENCODING
+ */
+ return CR_ENCODING_ERROR ;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for ( ;
+ nb_bytes_2_decode > 1 ;
+ nb_bytes_2_decode --)
+ {
+ /*decode the next byte*/
+ byte_ptr ++ ;
+
+ /*byte pattern must be: 10xx xxxx*/
+ if ((*byte_ptr & 0xC0) != 0x80)
+ {
+ return CR_ENCODING_ERROR ;
+ }
+
+ c = (c << 6) | (*byte_ptr & 0x3F) ;
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ if (c <= 0xFF) {/*Add other conditions to support
+ *other char sets (ucs2, ucs3, ucs4).
+ */
+ len ++ ;
+ } else {
+ /*the char is too long to fit
+ *into the supposed charset len.
+ */
+ return CR_ENCODING_ERROR ;
+ }
+ }
+
+ *a_len = len ;
+
+ return CR_OK ;
+}
+
+/**
+ *Converts an utf8 string into an ucs4 string.
+ *@param a_in the input string to convert.
+ *@param a_in_len in/out parameter. The length of the input
+ *string. After return, points to the actual number of bytes
+ *consumed. This can be usefull to debug the input stream in case
+ *of encoding error.
+ *@param a_out out parameter. Points to the output string. It is allocated
+ *by this function and must be freed by the caller.
+ *@param a_out_len out parameter. The length of the output string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_utf8_str_to_ucs4 (guchar * a_in, gulong *a_in_len,
+ guint32 **a_out, gulong *a_out_len)
+{
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len,
+ CR_BAD_PARAM_ERROR) ;
+
+ status =
+ cr_utils_utf8_str_len_as_ucs4 (a_in,
+ &a_in[*a_in_len - 1],
+ a_out_len) ;
+
+ g_return_val_if_fail (status == CR_OK, status) ;
+
+ *a_out = g_malloc0 (*a_out_len * sizeof (guint32)) ;
+
+ status =
+ cr_utils_utf8_to_ucs4 (a_in, a_in_len,
+ *a_out, a_out_len) ;
+
+ return status ;
+}
+
+/**
+ *Converts an ucs4 buffer into an utf8 buffer.
+ *
+ *@param a_in the input ucs4 buffer to convert.
+ *@param a_in_len in/out parameter. The size of the
+ *input buffer to convert. After return, this parameter contains
+ *the actual number of characters consumed.
+ *@param a_out the output converted utf8 buffer. Must be allocated by
+ *the caller.
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If this size is actually smaller than the real needed size, the function
+ *just converts what it can and returns a success status. After return,
+ *this param points to the actual number of bytes in the buffer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_to_utf8 (guint32 *a_in, gulong *a_in_len,
+ guchar *a_out, gulong *a_out_len)
+{
+ gulong in_len = 0, in_index = 0, out_index = 0 ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_in && a_in_len && a_out && a_out_len,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (*a_in_len < 1)
+ {
+ status = CR_OK ;
+ goto end ;
+ }
+
+ in_len = *a_in_len ;
+
+ for (in_index = 0 ;
+ in_index < in_len ;
+ in_index++)
+ {
+ /*
+ *FIXME: return whenever we encounter forbidden char values.
+ */
+
+ if (a_in[in_index] <= 0x7F)
+ {
+ a_out[out_index] = a_in[in_index] ;
+ out_index ++ ;
+ }
+ else if (a_in[in_index] <= 0x7FF)
+ {
+ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6)) ;
+ a_out[out_index + 1] = (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 2 ;
+ }
+ else if (a_in[in_index] <= 0xFFFF)
+ {
+ a_out[out_index] = (0xE0 | (a_in[in_index] >> 12)) ;
+ a_out[out_index + 1] =
+ (0x80 | ((a_in[in_index] >> 6) & 0x3F)) ;
+ a_out[out_index + 2] = (0x80 | (a_in[in_index] & 0x3F)) ;
+ out_index += 3 ;
+ }
+ else if (a_in[in_index] <= 0x1FFFFF)
+ {
+ a_out[out_index] = (0xF0 | (a_in[in_index] >> 18)) ;
+ a_out[out_index + 1]
+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)) ;
+ a_out[out_index + 2]
+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)) ;
+ a_out[out_index + 3]
+ = (0x80 | (a_in[in_index] & 0x3F)) ;
+ out_index += 4 ;
+ }
+ else if (a_in[in_index] <= 0x3FFFFFF)
+ {
+ a_out[out_index] = (0xF8 | (a_in[in_index] >> 24)) ;
+ a_out[out_index + 1] = (0x80 | (a_in[in_index] >> 18)) ;
+ a_out[out_index + 2]
+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)) ;
+ a_out[out_index + 3]
+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)) ;
+ a_out[out_index + 4]
+ = (0x80 | (a_in[in_index] & 0x3F)) ;
+ out_index += 5 ;
+ }
+ else if (a_in[in_index] <= 0x7FFFFFFF)
+ {
+ a_out[out_index] = (0xFC | (a_in[in_index] >> 30)) ;
+ a_out[out_index + 1] = (0x80 | (a_in[in_index] >> 24)) ;
+ a_out[out_index + 2]
+ = (0x80 | ((a_in[in_index] >> 18) & 0x3F)) ;
+ a_out[out_index + 3]
+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F)) ;
+ a_out[out_index + 4]
+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F)) ;
+ a_out[out_index + 4]
+ = (0x80 | (a_in[in_index] & 0x3F)) ;
+ out_index += 6 ;
+ }
+ else
+ {
+ status = CR_ENCODING_ERROR ;
+ goto end ;
+ }
+ }/*end for*/
+
+ end:
+ *a_in_len = in_index + 1 ;
+ *a_out_len = out_index + 1 ;
+
+ return status ;
+}
+
+
+/**
+ *Converts an ucs4 string into an utf8 string.
+ *@param a_in the input string to convert.
+ *@param a_in_len in/out parameter. The length of the input
+ *string. After return, points to the actual number of characters
+ *consumed. This can be usefull to debug the input string in case
+ *of encoding error.
+ *@param a_out out parameter. Points to the output string. It is allocated
+ *by this function and must be freed by the caller.
+ *@param a_out_len out parameter. The length (in bytes) of the output string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_str_to_utf8 (guint32 *a_in, gulong *a_in_len,
+ guchar **a_out, gulong *a_out_len)
+{
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_in && a_in_len && a_out
+ && a_out_len, CR_BAD_PARAM_ERROR) ;
+
+ status =
+ cr_utils_ucs4_str_len_as_utf8 (a_in,
+ &a_in[*a_out_len -1],
+ a_out_len) ;
+
+ g_return_val_if_fail (status == CR_OK, status) ;
+
+ status =
+ cr_utils_ucs4_to_utf8 (a_in, a_in_len, *a_out, a_out_len) ;
+
+ return status ;
+}
+
+
+/**
+ *Converts an ucs1 buffer into an utf8 buffer.
+ *The caller must know the size of the resulting buffer and
+ *allocate it prior to calling this function.
+ *
+ *@param a_in the input ucs1 buffer.
+ *
+ *@param a_in_len in/out parameter. The length of the input buffer.
+ *After return, points to the number of bytes actually consumed even
+ *in case of encoding error.
+ *
+ *@param a_out out parameter. The output utf8 converted buffer.
+ *
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If the output buffer size is shorter than the actual needed size,
+ *this function just convert what it can.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_ucs1_to_utf8 (guchar *a_in, gulong *a_in_len,
+ guchar *a_out, gulong *a_out_len)
+{
+ gulong out_index = 0, in_index = 0, in_len = 0, out_len = 0 ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_in && a_in_len && a_out
+ && a_out_len, CR_BAD_PARAM_ERROR) ;
+
+ if (*a_in_len < 1)
+ {
+ status = CR_OK ;
+ goto end ;
+ }
+
+ in_len = *a_in_len ;
+ out_len = *a_out_len ;
+
+ for (in_index = 0, out_index = 0 ;
+ (in_index < in_len) && (out_index < out_len) ;
+ in_index ++)
+ {
+ /*
+ *FIXME: return whenever we encounter forbidden char values.
+ */
+
+ if (a_in[in_index] <= 0x7F)
+ {
+ a_out[out_index] = a_in[in_index] ;
+ out_index ++ ;
+ }
+ else
+ {
+ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6)) ;
+ a_out[out_index + 1] = (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 2 ;
+ }
+ }/*end for*/
+
+ end:
+ *a_in_len = in_index ;
+ *a_out_len = out_index ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Converts an ucs1 string into an utf8 string.
+ *@param a_in_start the beginning of the input string to convert.
+ *@param a_in_end the end of the input string to convert.
+ *@param a_out out parameter. The converted string.
+ *@param a_out out parameter. The length of the converted string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_ucs1_str_to_utf8 (guchar *a_in, gulong *a_in_len,
+ guchar **a_out, gulong *a_out_len)
+{
+ gulong in_len = 0, out_len = 0 ;
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_in && a_in_len && a_out
+ && a_out_len, CR_BAD_PARAM_ERROR) ;
+
+ if (*a_in_len < 1)
+ {
+ *a_out_len = 0 ;
+ *a_out = NULL ;
+ return CR_OK ;
+ }
+
+ status =
+ cr_utils_ucs1_str_len_as_utf8 (a_in, &a_in[*a_in_len -1],
+ &out_len) ;
+
+ g_return_val_if_fail (status == CR_OK, status) ;
+
+ in_len = *a_in_len ;
+
+ *a_out = g_malloc0 (out_len) ;
+
+ status = cr_utils_ucs1_to_utf8 (a_in, a_in_len,
+ *a_out, &out_len) ;
+
+ *a_out_len = out_len ;
+
+ return status ;
+}
+
+
+/**
+ *Converts an utf8 buffer into an ucs1 buffer.
+ *The caller must know the size of the resulting
+ *converted buffer, and allocated it prior to calling this
+ *function.
+ *
+ *@param a_in the input utf8 buffer to convert.
+ *
+ *@param a_in_len in/out parameter. The size of the input utf8 buffer.
+ *After return, points to the number of bytes consumed
+ *by the function even in case of encoding error.
+ *
+ *@param a_out out parameter. Points to the resulting buffer.
+ *Must be allocated by the caller. If the size of a_out is shorter
+ *than its required size, this function converts what it can and return
+ *a successfull status.
+ *
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *After return, points to the number of bytes consumed even in case of
+ *encoding error.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_to_ucs1 (guchar * a_in, gulong * a_in_len,
+ guchar *a_out, gulong *a_out_len)
+{
+ gulong in_index = 0, out_index = 0, in_len = 0, out_len = 0 ;
+ enum CRStatus status = CR_OK ;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint32 c = 0 ;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (*a_in_len < 1)
+ {
+ status = CR_OK ;
+ goto end ;
+ }
+
+ in_len = *a_in_len ;
+ out_len = *a_out_len ;
+
+ for (in_index = 0 , out_index = 0 ;
+ (in_index < in_len) && (out_index < out_len) ;
+ in_index ++, out_index++)
+ {
+ gint nb_bytes_2_decode = 0 ;
+
+ if (a_in[in_index] <= 0x7F)
+ {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = a_in[in_index] ;
+ nb_bytes_2_decode = 1 ;
+
+ }
+ else if ((a_in[in_index] & 0xE0) == 0xC0)
+ {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x1F ;
+ nb_bytes_2_decode = 2 ;
+
+ }
+ else if ((a_in[in_index] & 0xF0) == 0xE0)
+ {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x0F ;
+ nb_bytes_2_decode = 3 ;
+
+ }
+ else if ((a_in[in_index] & 0xF8) == 0xF0)
+ {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x7 ;
+ nb_bytes_2_decode = 4 ;
+
+ }
+ else if ((a_in[in_index] & 0xFC) == 0xF8)
+ {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 3 ;
+ nb_bytes_2_decode = 5 ;
+
+ }
+ else if ((a_in[in_index] & 0xFE) == 0xFC)
+ {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 1 ;
+ nb_bytes_2_decode = 6 ;
+
+ }
+ else
+ {
+ /*BAD ENCODING*/
+ status = CR_ENCODING_ERROR ;
+ goto end ;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ if (in_index + nb_bytes_2_decode - 1 >= in_len)
+ {
+ status = CR_OK ;
+ goto end ;
+ }
+
+ for ( ;
+ nb_bytes_2_decode > 1 ;
+ nb_bytes_2_decode --)
+ {
+ /*decode the next byte*/
+ in_index ++ ;
+
+ /*byte pattern must be: 10xx xxxx*/
+ if ((a_in[in_index] & 0xC0) != 0x80)
+ {
+ status = CR_ENCODING_ERROR ;
+ goto end ;
+ }
+
+ c = (c << 6) | (a_in[in_index] & 0x3F) ;
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ if (c > 0xFF)
+ {
+ status = CR_ENCODING_ERROR ;
+ goto end ;
+ }
+
+ a_out[out_index] = c ;
+ }
+
+ end:
+ *a_out_len = out_index ;
+ *a_in_len = in_index ;
+
+ return CR_OK ;
+}
+
+
+/**
+ *Converts an utf8 buffer into an
+ *ucs1 buffer.
+ *@param a_in_start the start of the input buffer.
+ *@param a_in_end the end of the input buffer.
+ *@param a_out out parameter. The resulting converted ucs4 buffer.
+ *Must be freed by the caller.
+ *@param a_out_len out parameter. The length of the converted buffer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *Note that out parameters are valid if and only if this function
+ *returns CR_OK.
+ */
+enum CRStatus
+cr_utils_utf8_str_to_ucs1 (guchar * a_in, gulong * a_in_len,
+ guchar **a_out, gulong *a_out_len)
+{
+ enum CRStatus status = CR_OK ;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len,
+ CR_BAD_PARAM_ERROR) ;
+
+ if (*a_in_len < 1)
+ {
+ *a_out_len = 0 ;
+ *a_out = NULL ;
+ return CR_OK ;
+ }
+
+ status =
+ cr_utils_utf8_str_len_as_ucs4 (a_in, &a_in[*a_in_len - 1],
+ a_out_len) ;
+
+ g_return_val_if_fail (status == CR_OK, status) ;
+
+ *a_out = g_malloc0 (*a_out_len * sizeof (guint32)) ;
+
+ status =
+ cr_utils_utf8_to_ucs1 (a_in, a_in_len,
+ *a_out, a_out_len) ;
+ return status ;
+}
+
+
+/*****************************************
+ *CSS basic types identification utilities
+ *****************************************/
+
+
+/**
+ *Returns TRUE if a_char is a white space as
+ *defined in the css spec in chap 4.1.1.
+ *
+ *white-space ::= ' '| \t|\r|\n|\f
+ *
+ *@param a_char the character to test.
+ *return TRUE if is a white space, false otherwise.
+ */
+gboolean
+cr_utils_is_white_space (guint32 a_char)
+{
+ switch (a_char)
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case '\f':
+ return TRUE ;
+ break ;
+ default:
+ return FALSE ;
+ }
+}
+
+/**
+ *Returns true if the character is a newline
+ *as defined in the css spec in the chap 4.1.1.
+ *
+ *nl ::= \n|\r\n|\r|\f
+ *
+ *@param a_char the character to test.
+ *@return TRUE if the character is a newline, FALSE otherwise.
+ */
+gboolean
+cr_utils_is_newline (guint32 a_char)
+{
+ switch (a_char)
+ {
+ case '\n':
+ case '\r':
+ case '\f':
+ return TRUE ;
+ break;
+ default:
+ return FALSE ;
+ }
+}
+
+/**
+ *returns TRUE if the char is part of an hexa num char:
+ *i.e hexa_char ::= [0-9A-F]
+ */
+gboolean
+cr_utils_is_hexa_char (guint32 a_char)
+{
+ if ((a_char >= '0' && a_char <= '9')
+ || (a_char >= 'A' && a_char <= 'F'))
+ {
+ return TRUE ;
+ }
+ return FALSE ;
+}
+
+/**
+ *Returns true if the character is a nonascii
+ *character (as defined in the css spec chap 4.1.1):
+ *
+ *nonascii ::= [^\0-\177]
+ *
+ *@param a_char the character to test.
+ *@return TRUE if the character is a nonascii char,
+ *FALSE otherwise.
+ */
+gboolean
+cr_utils_is_nonascii (guint32 a_char)
+{
+ if ((a_char >= 0) && (a_char <= 177))
+ {
+ return FALSE ;
+ }
+
+ return TRUE ;
+}
+
+/**
+ *Dumps a character a_nb times on a file.
+ *@param a_char the char to dump
+ *@param a_fp the destination file pointer
+ *@param a_nb the number of times a_char is to be dumped.
+ */
+void
+cr_utils_dump_n_chars (guchar a_char, FILE *a_fp, glong a_nb)
+{
+ glong i = 0 ;
+
+ for (i = 0 ; i < a_nb ; i++)
+ {
+ fprintf (a_fp, "%c", a_char) ;
+ }
+}
diff --git a/src/cr-utils.h b/src/cr-utils.h
new file mode 100644
index 0000000..3093c9f
--- /dev/null
+++ b/src/cr-utils.h
@@ -0,0 +1,277 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *This file is part of The Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *GNU The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+#ifndef __CR_DEFS_H__
+#define __CR_DEFS_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "libcroco-config.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The Croco library basic types definitions
+ *And global definitions.
+ */
+
+ /**
+ *The status type returned
+ *by the methods of the croco library.
+ */
+ enum CRStatus {
+ CR_OK,
+ CR_BAD_PARAM_ERROR,
+ CR_START_OF_INPUT_ERROR,
+ CR_END_OF_INPUT_ERROR,
+ CR_OUTPUT_TOO_SHORT_ERROR,
+ CR_INPUT_TOO_SHORT_ERROR,
+ CR_OUT_OF_BOUNDS_ERROR,
+ CR_EMPTY_PARSER_INPUT_ERROR,
+ CR_ENCODING_ERROR,
+ CR_ENCODING_NOT_FOUND_ERROR,
+ CR_PARSING_ERROR,
+ CR_SYNTAX_ERROR,
+ CR_NO_TOKEN,
+ CR_ERROR
+ } ;
+
+ /**
+ *Values used by
+ *cr_input_seek_position() ;
+ */
+ enum CRSeekPos {
+ CR_SEEK_CUR,
+ CR_SEEK_BEGIN,
+ CR_SEEK_END
+ } ;
+
+ /**
+ *Encoding values.
+ */
+ enum CREncoding
+ {
+ CR_UCS_4 = 1/*Must be not NULL*/,
+ CR_UCS_1,
+ CR_ISO_8859_1,
+ CR_ASCII,
+ CR_UTF_8,
+ CR_UTF_16,
+ CR_AUTO/*should be the last one*/
+ } ;
+
+
+ enum TermType
+ {
+ NO_TYPE = 0,
+ NUMBER,
+ PERCENTAGE ,
+ LENGTH,
+ EMS,
+ EXS,
+ ANGLE,
+ TIME,
+ FREQ,
+ FUNCTION,
+ STRING,
+ IDENT,
+ URI,
+ RGB,
+ UNICODERANGE,
+ HASH
+ } ;
+
+ /**
+ *Possible Units of
+ *LENGTH, ANGLE, FREQ,
+ *TIME,
+ */
+ enum TermUnit
+ {
+ NO_UNIT,
+
+ UNIT_EMS,
+ UNIT_EXS,
+
+ UNIT_PX,/*length pixel unit*/
+ UNIT_CM,/*length centimeter unit*/
+ UNIT_MM,/*length millimeter unit*/
+ UNIT_IN,/*length inch unit*/
+ UNIT_PT,/*length point unit*/
+ UNIT_PC,/*length pc? unit*/
+
+ UNIT_DEG,/*angle degre unit*/
+ UNIT_RAD, /*angle radian unit*/
+ UNIT_GRAD, /*angle gradian unit*/
+
+ UNIT_MS, /*time millisecond unit*/
+ UNIT_S, /*time second unit*/
+
+ UNIT_HZ, /*frequency herz unit*/
+ UNIT_KHZ, /*frequency kiloherz unit*/
+
+ UNIT_DIMEN, /*custom dimension unit*/
+
+ UNIT_PERCENTAGE,
+ } ;
+
+ enum Operator
+ {
+ NO_OP = 0,
+ DIVIDE,
+ COMMA
+ } ;
+
+ enum UnaryOperator
+ {
+ NO_UNARY_UOP = 0,
+ PLUS_UOP,
+ MINUS_UOP,
+ EMPTY_UNARY_UOP
+ } ;
+
+#define CROCO_LOG_DOMAIN "LIBCROCO"
+
+#ifdef __GNUC__
+#define cr_utils_trace(a_log_level, a_msg) \
+g_log (CROCO_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d (%s): %s\n", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ a_msg)
+#else /*__GNUC__*/
+
+#define cr_utils_trace(a_log_level, a_msg) \
+g_log (CROCO_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: %s\n", \
+ __FILE__, \
+ __LINE__, \
+ a_msg)
+#endif
+
+/**
+ *Traces an info message.
+ *The file, line and enclosing function
+ *of the message will be automatically
+ *added to the message.
+ *@param a_msg the msg to trace.
+ */
+#define cr_utils_trace_info(a_msg) \
+cr_utils_trace (G_LOG_LEVEL_INFO, a_msg)
+
+/**
+ *Trace a debug message.
+ *The file, line and enclosing function
+ *of the message will be automatically
+ *added to the message.
+ *@param a_msg the msg to trace.
+ */
+#define cr_utils_trace_debug(a_msg) \
+cr_utils_trace (G_LOG_LEVEL_DEBUG, a_msg) ;
+
+
+/****************************
+ *Encoding transformations and
+ *encoding helpers
+ ****************************/
+
+enum CRStatus
+cr_utils_read_char_from_utf8_buf (guchar * a_in, gulong a_in_len,
+ guint32 *a_out, gulong *a_consumed) ;
+
+enum CRStatus
+cr_utils_ucs1_to_utf8 (guchar *a_in, gulong *a_in_len,
+ guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_to_ucs1 (guchar * a_in, gulong * a_in_len,
+ guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_ucs4_to_utf8 (guint32 *a_in, gulong *a_in_len,
+ guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs4 (guchar *a_in_start,
+ guchar *a_in_end,
+ gulong *a_len) ;
+enum CRStatus
+cr_utils_ucs1_str_len_as_utf8 (guchar *a_in_start, guchar *a_in_end,
+ gulong *a_len) ;
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs1 (guchar *a_in_start,
+ guchar *a_in_end,
+ gulong *a_len) ;
+enum CRStatus
+cr_utils_ucs4_str_len_as_utf8 (guint32 *a_in_start, guint32 *a_in_end,
+ gulong *a_len) ;
+
+enum CRStatus
+cr_utils_ucs1_str_to_utf8 (guchar *a_in_start, gulong *a_in_len,
+ guchar **a_out, gulong *a_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_to_ucs1 (guchar * a_in_start, gulong * a_in_len,
+ guchar **a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_to_ucs4 (guchar * a_in, gulong * a_in_len,
+ guint32 *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_ucs4_str_to_utf8 (guint32 *a_in, gulong *a_in_len,
+ guchar **a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_to_ucs4 (guchar * a_in, gulong *a_in_len,
+ guint32 **a_out, gulong *a_out_len) ;
+
+
+/*****************************************
+ *CSS basic types identification utilities
+ *****************************************/
+
+gboolean
+cr_utils_is_newline (guint32 a_char) ;
+
+gboolean
+cr_utils_is_white_space (guint32 a_char) ;
+
+gboolean
+cr_utils_is_nonascii (guint32 a_char) ;
+
+gboolean
+cr_utils_is_hexa_char (guint32 a_char) ;
+
+void
+cr_utils_dump_n_chars (guchar a_char, FILE *a_fp, glong a_nb) ;
+
+G_END_DECLS
+
+#endif /*__CR_DEFS_H__*/
diff --git a/src/libcroco.h b/src/libcroco.h
new file mode 100644
index 0000000..f143cfd
--- /dev/null
+++ b/src/libcroco.h
@@ -0,0 +1,21 @@
+#ifndef __LIBCROCO_H__
+#define __LIBCROCO_H__
+
+#include "libcroco-config.h"
+
+#include "cr-utils.h"
+#include "cr-pseudo.h"
+#include "cr-term.h"
+#include "cr-attr-sel.h"
+#include "cr-simple-sel.h"
+#include "cr-selector.h"
+#include "cr-enc-handler.h"
+#include "cr-doc-handler.h"
+#include "cr-parser-input.h"
+#include "cr-input.h"
+#include "cr-parser.h"
+#include "cr-statement.h"
+#include "cr-stylesheet.h"
+#include "cr-om-parser.h"
+
+#endif /*__LIBCROCO_H__*/
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..20fa73c
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,17 @@
+#SUBDIRS=test-inputs
+
+noinst_PROGRAMS=test0 test1 test2 test3 test4
+test0_SOURCES=test0-main.c
+test1_SOURCES=test1-main.c
+test2_SOURCES=test2-main.c cr-test-utils.c cr-test-utils.h
+test3_SOURCES=test3-main.c cr-test-utils.c cr-test-utils.h
+test4_SOURCES=test4-main.c cr-test-utils.c cr-test-utils.h
+
+LDADD=$(top_srcdir)/src/libcroco.la
+
+INCLUDES=-I$(top_srcdir)/intl \
+ -I$(top_srcdir)/src \
+ `pkg-config --cflags glib-2.0`
+
+LDFLAGS=`pkg-config --libs glib-2.0` @LIBXML2_LIBS@
+AM_CFLAGS=-Wall -I. \ No newline at end of file
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644
index 0000000..72c68b6
--- /dev/null
+++ b/tests/Makefile.in
@@ -0,0 +1,395 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#SUBDIRS=test-inputs
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CROCO_CFLAGS = @CROCO_CFLAGS@
+CROCO_LIBS = @CROCO_LIBS@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+LIBCROCO_MAJOR_VERSION = @LIBCROCO_MAJOR_VERSION@
+LIBCROCO_MICRO_VERSION = @LIBCROCO_MICRO_VERSION@
+LIBCROCO_MINOR_VERSION = @LIBCROCO_MINOR_VERSION@
+LIBCROCO_VERSION = @LIBCROCO_VERSION@
+LIBCROCO_VERSION_INFO = @LIBCROCO_VERSION_INFO@
+LIBCROCO_VERSION_NUMBER = @LIBCROCO_VERSION_NUMBER@
+LIBTOOL = @LIBTOOL@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+REQUIRE_LIBXML2 = @REQUIRE_LIBXML2@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+WITH_SELENG = @WITH_SELENG@
+
+noinst_PROGRAMS = test0 test1 test2 test3 test4
+test0_SOURCES = test0-main.c
+test1_SOURCES = test1-main.c
+test2_SOURCES = test2-main.c cr-test-utils.c cr-test-utils.h
+test3_SOURCES = test3-main.c cr-test-utils.c cr-test-utils.h
+test4_SOURCES = test4-main.c cr-test-utils.c cr-test-utils.h
+
+LDADD = $(top_srcdir)/src/libcroco.la
+
+INCLUDES = -I$(top_srcdir)/intl -I$(top_srcdir)/src `pkg-config --cflags glib-2.0`
+
+
+LDFLAGS = `pkg-config --libs glib-2.0` @LIBXML2_LIBS@
+AM_CFLAGS = -Wall -I.
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../libcroco-config.h
+CONFIG_CLEAN_FILES =
+noinst_PROGRAMS = test0$(EXEEXT) test1$(EXEEXT) test2$(EXEEXT) \
+test3$(EXEEXT) test4$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LIBS = @LIBS@
+test0_OBJECTS = test0-main.$(OBJEXT)
+test0_LDADD = $(LDADD)
+test0_DEPENDENCIES = $(top_srcdir)/src/libcroco.la
+test0_LDFLAGS =
+test1_OBJECTS = test1-main.$(OBJEXT)
+test1_LDADD = $(LDADD)
+test1_DEPENDENCIES = $(top_srcdir)/src/libcroco.la
+test1_LDFLAGS =
+test2_OBJECTS = test2-main.$(OBJEXT) cr-test-utils.$(OBJEXT)
+test2_LDADD = $(LDADD)
+test2_DEPENDENCIES = $(top_srcdir)/src/libcroco.la
+test2_LDFLAGS =
+test3_OBJECTS = test3-main.$(OBJEXT) cr-test-utils.$(OBJEXT)
+test3_LDADD = $(LDADD)
+test3_DEPENDENCIES = $(top_srcdir)/src/libcroco.la
+test3_LDFLAGS =
+test4_OBJECTS = test4-main.$(OBJEXT) cr-test-utils.$(OBJEXT)
+test4_LDADD = $(LDADD)
+test4_DEPENDENCIES = $(top_srcdir)/src/libcroco.la
+test4_LDFLAGS =
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+DEP_FILES = .deps/cr-test-utils.P .deps/test0-main.P .deps/test1-main.P \
+.deps/test2-main.P .deps/test3-main.P .deps/test4-main.P
+SOURCES = $(test0_SOURCES) $(test1_SOURCES) $(test2_SOURCES) $(test3_SOURCES) $(test4_SOURCES)
+OBJECTS = $(test0_OBJECTS) $(test1_OBJECTS) $(test2_OBJECTS) $(test3_OBJECTS) $(test4_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .obj .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstPROGRAMS:
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+distclean-noinstPROGRAMS:
+
+maintainer-clean-noinstPROGRAMS:
+
+# FIXME: We should only use cygpath when building on Windows,
+# and only if it is available.
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+test0$(EXEEXT): $(test0_OBJECTS) $(test0_DEPENDENCIES)
+ @rm -f test0$(EXEEXT)
+ $(LINK) $(test0_LDFLAGS) $(test0_OBJECTS) $(test0_LDADD) $(LIBS)
+
+test1$(EXEEXT): $(test1_OBJECTS) $(test1_DEPENDENCIES)
+ @rm -f test1$(EXEEXT)
+ $(LINK) $(test1_LDFLAGS) $(test1_OBJECTS) $(test1_LDADD) $(LIBS)
+
+test2$(EXEEXT): $(test2_OBJECTS) $(test2_DEPENDENCIES)
+ @rm -f test2$(EXEEXT)
+ $(LINK) $(test2_LDFLAGS) $(test2_OBJECTS) $(test2_LDADD) $(LIBS)
+
+test3$(EXEEXT): $(test3_OBJECTS) $(test3_DEPENDENCIES)
+ @rm -f test3$(EXEEXT)
+ $(LINK) $(test3_LDFLAGS) $(test3_OBJECTS) $(test3_LDADD) $(LIBS)
+
+test4$(EXEEXT): $(test4_OBJECTS) $(test4_DEPENDENCIES)
+ @rm -f test4$(EXEEXT)
+ $(LINK) $(test4_LDFLAGS) $(test4_OBJECTS) $(test4_LDADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = tests
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu tests/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstPROGRAMS clean-compile clean-libtool clean-tags \
+ clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstPROGRAMS distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstPROGRAMS \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \
+clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/core.17057 b/tests/core.17057
new file mode 100644
index 0000000..9839108
--- /dev/null
+++ b/tests/core.17057
Binary files differ
diff --git a/tests/core.17936 b/tests/core.17936
new file mode 100644
index 0000000..a57d90f
--- /dev/null
+++ b/tests/core.17936
Binary files differ
diff --git a/tests/cr-test-utils.c b/tests/cr-test-utils.c
new file mode 100644
index 0000000..b39419e
--- /dev/null
+++ b/tests/cr-test-utils.c
@@ -0,0 +1,43 @@
+#include <string.h>
+#include "cr-test-utils.h"
+
+/**
+ *Parses the command line.
+ *@param a_argc the argc parameter of the main routine.
+ *@param the argv parameter of the main routine.
+ *@param a_options out parameter the parsed options.
+ */
+void
+cr_test_utils_parse_cmd_line (int a_argc, char **a_argv,
+ struct Options *a_options)
+{
+ int i= 0 ;
+
+ g_return_if_fail (a_options) ;
+
+ memset (a_options, 0, sizeof (struct Options)) ;
+
+ for (i = 1 ; i < a_argc ; i++)
+ {
+ if (a_argv[i][0] != '-') break ;
+
+ if (!strcmp (a_argv[i], "-h") || !strcmp (a_argv[i], "--help"))
+ {
+ a_options->display_help = TRUE ;
+ }
+ if (!strcmp (a_argv[i], "--about"))
+ {
+ a_options->display_about = TRUE ;
+ }
+ }
+
+ if (i >= a_argc)
+ {
+ /*No file parameter where given*/
+ a_options->files_list = NULL ;
+ }
+ else
+ {
+ a_options->files_list = &a_argv[i] ;
+ }
+}
diff --git a/tests/cr-test-utils.h b/tests/cr-test-utils.h
new file mode 100644
index 0000000..579e6ca
--- /dev/null
+++ b/tests/cr-test-utils.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+#ifndef __CR_TEST_UTILS_H__
+#define __CR_TEST_UTILS_H__
+
+#include <stdio.h>
+#include <glib.h>
+
+/**
+ *The options data structure.
+ *The variable of this data structure are set
+ *during the parsing the command line by the
+ *parse_command_line() function.
+ */
+struct Options
+{
+ gboolean display_help ;
+ gboolean display_about ;
+ gchar ** files_list ;
+};
+
+
+void
+cr_test_utils_parse_cmd_line (int a_argc, char **a_argv,
+ struct Options *a_options) ;
+
+#endif /*__CR_TEST_UTILS_H__*/
diff --git a/tests/more b/tests/more
new file mode 100644
index 0000000..dc336d6
--- /dev/null
+++ b/tests/more
@@ -0,0 +1,189 @@
+***************
+start_document
+***************
+
+***************
+start_selector
+h1.rubrique_info
+***************
+
+***************
+property
+color: #990033
+***************
+
+***************
+property
+margin: 0px 0px 0px 0px
+***************
+
+***************
+property
+padding: 0em
+***************
+
+***************
+property
+border: 0px
+***************
+
+***************
+property
+font-size: 12px
+***************
+
+***************
+end_selector
+h1.rubrique_info
+***************
+
+***************
+start_selector
+*
+***************
+
+***************
+property
+font-family: Verdana, Arial, Helvetica, sans-serif, monospace
+***************
+
+***************
+end_selector
+*
+***************
+
+***************
+start_selector
+body
+***************
+
+***************
+property
+background: #606060
+***************
+
+***************
+property
+color: #000000
+***************
+
+***************
+end_selector
+body
+***************
+
+***************
+start_selector
+a:link
+***************
+
+***************
+property
+color: #0000FF
+***************
+
+***************
+property
+background: transparent
+***************
+
+***************
+property
+text-decoration: none
+***************
+
+***************
+end_selector
+a:link
+***************
+
+***************
+start_selector
+a:visited
+***************
+
+***************
+property
+color: #990099
+***************
+
+***************
+property
+background: transparent
+***************
+
+***************
+property
+text-decoration: none
+***************
+
+***************
+end_selector
+a:visited
+***************
+
+***************
+start_selector
+a:active
+***************
+
+***************
+property
+color: #000000
+***************
+
+***************
+property
+background: #ADD8E6
+***************
+
+***************
+property
+text-decoration: none
+***************
+
+***************
+end_selector
+a:active
+***************
+
+***************
+start_selector
+h1.rubrique_info
+***************
+
+***************
+property
+color: #990033
+***************
+
+***************
+property
+margin: 0px 0px 0px 0px
+***************
+
+***************
+property
+padding: 0em
+***************
+
+***************
+property
+border: 0px
+***************
+
+***************
+property
+font-size: 12px
+***************
+
+***************
+end_selector
+h1.rubrique_info
+***************
+
+***************
+end_document
+***************
+
+OK
diff --git a/tests/test-inputs/test2.1.css b/tests/test-inputs/test2.1.css
new file mode 100644
index 0000000..7b3e88c
--- /dev/null
+++ b/tests/test-inputs/test2.1.css
@@ -0,0 +1,35 @@
+
+/*simple Attribute set selectors*/
+s1[foo] {prop1 : value1}
+
+/*simple exact attribute selector, simple ruleset*/
+s1[foo="warning"] {prop1 : value1}
+
+/**
+ *"space separated value list"
+ *attribute selector, simple ruleset
+ */
+s1[foo~="warning"] {prop1 :value1}
+
+/**
+ *"hyphen separated value list" attribute selector,
+ * simple ruleset
+ */
+
+ /*simple class selector, simple ruleset*/
+ s1.warning {prop1 : value}
+
+ E#myid {prop1 : value1}
+
+
+/*below are tests that we know are working*/
+
+/*simple ident pseudo class selector, simple ruleset test*/
+S1:first-child {prop1 : value1 ; prop2 : value2}
+
+/*function pseudo class selector, simple ruleset test*/
+S1:lang(c) {prop1 : value1}
+
+/*Adjacent selectors, simple ruleset test*/
+S1 + s2 {prop1: value1}
+
diff --git a/tests/test-inputs/test2.2.css b/tests/test-inputs/test2.2.css
new file mode 100644
index 0000000..658e545
--- /dev/null
+++ b/tests/test-inputs/test2.2.css
@@ -0,0 +1,674 @@
+* {
+ font-family: Verdana, Arial, Helvetica, sans-serif, monospace;
+}
+
+body {
+ background: #606060;
+ color: #000000;
+}
+
+a:link {
+ color: #0000FF;
+ background: transparent;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #990099;
+ background: transparent;
+ text-decoration: none;
+}
+
+
+a:active {
+ color: #000000;
+ background: #ADD8E6;
+ text-decoration: none;
+}
+
+h1.rubrique_info {
+ color: #990033;
+ margin: 0px 0px 0px 0px;
+ padding: 0em;
+ border: 0px;
+ font-size: 12px;
+}
+h1.connexe {
+ font-size: 12px;
+ padding: 0em;
+ margin: 0px 0px 0px 0px;
+ color: #990033;
+}
+
+a.rubrique_infolink {
+ text-decoration: none;
+}
+
+ul.rubrique_infoul {
+ display: inline;
+ list-style-type: square;
+}
+ul.rubrique_infoul * {
+ width: 100%;
+}
+li.rubrique_infoul {
+ margin-left: 15px;
+}
+h1 {
+ color: #990033;
+}
+
+div.main {
+ background: white;
+ color: #000000;
+ margin-left: 5px;
+ margin-right: 5px;
+ border: 1px black solid;
+ text-align: left;
+ font-size: 12px;
+}
+div.lsfnbanner {
+ margin-left: 150px;
+ margin-right: 170px;
+ border-top: none;
+ padding-left: 10px;
+ padding-right: 10px;
+ border-bottom: 1px black solid;
+ border-right: 1px black solid;
+ border-left: 1px black solid;
+ text-align: left;
+ font-size: 11px;
+ padding-top: 2px;
+ background-color: #eeeae6;
+}
+div.footer {
+ padding-top: 5px;
+ padding-bottom: 3px;
+ border-top: 1px black solid;
+ border-left: 1px black solid;
+ border-right: 1px black solid;
+ text-align: left;
+ font-size: 9px;
+ background: #dcdff4;
+ width: 600px;
+ margin-top: 40px;
+ margin-left: 20px;
+}
+div.footer p {
+ margin-left: 10px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+}
+
+a.lsfnlink:link,a.lsfnlink:visited,a.lsfnlink:active {
+ text-decoration: none;
+ color: #333333;
+ font-size: 10px;
+}
+a.lsfnlink:hover {
+ text-decoration: underline;
+ color: black;
+}
+div.menubartop {
+ margin-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 0px;
+ font-size: 13px;
+}
+div.smallmenubar {
+ background: white;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ font-weight:bold;
+ font-size: 10px;
+ text-align: right;
+}
+div.menuevent {
+ float: left;
+ width: 350px;
+ font-size: 11px;
+ text-align: left;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 10px;
+ font-weight: bold;
+ margin: 0px;
+}
+div.menubar {
+ background: #cac2a8;
+ border-top: 1px black solid;
+ border-bottom: 1px black solid;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 3px;
+ padding-bottom: 2px;
+ font-weight:bold;
+ font-size: 13px;
+}
+div.menubar a {
+ text-decoration: none;
+}
+div.menudate {
+ float: left;
+ width: 130px;
+ padding-top: 5px;
+}
+div.menuaccroche {
+ margin-left: 30px;
+ float: left;
+ text-decoration: underline;
+ font-size: 14px;
+}
+div.menusearch {
+ float: right;
+ text-align: right;
+ padding-top: 5px;
+ width: 170px;
+}
+div.menusearch p {
+ margin: 0px 0px 0px 0px;
+}
+.searchinput {
+ border: solid 1px black;
+}
+a#menulinkselect {
+ color: #ed7e00;
+}
+
+div.leftbox {
+ width: 200px;
+ float: left;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-bottom: 5px;
+ border-right: 1px black solid;
+ border-bottom: 1px black solid;
+ background: white;
+ margin-bottom: 10px;
+}
+div.leftbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.leftbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.leftbox ul {
+ list-style-type: square;
+ margin-bottom: 10px;
+ margin-left: 0em;
+ padding-left: 0em;
+}
+div.leftbox li {
+ margin-left: 10px;
+}
+
+div.rightbox {
+ width: 150px;
+ float: right;
+ padding-top: 10px;
+ padding-left: 5px;
+ padding-right: 15px;
+ padding-bottom: 5px;
+ border-left: 1px black solid;
+ border-bottom: 1px black solid;
+ text-align: left;
+}
+div.newjournaldiv {
+ text-align: justify;
+ margin-left: 10%;
+ font-size: 12px;
+ width: 600px;
+}
+div.newjournaldiv p {
+ margin-bottom: 0px;
+ margin-top: 20px;
+}
+div.journaldiv {
+ margin-left: 0px;
+ margin-right: 0px;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 1px black solid;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ padding-right: 10px;
+ padding-left: 10px;
+ background-color: #eef;
+}
+div.journaldiv p {
+ margin-top: 10px;
+ margin-bottom: 0px;
+}
+div.journaldiv h1 {
+ color: #990033;
+ font-size: 14px;
+ margin: 0px;
+}
+div.journaldiv h2 {
+ font-size: 10px;
+ margin: 0px;
+}
+div.tipdiv {
+ margin-left: 220px;
+ margin-right: 50px;
+ margin-top: 20px;
+ padding-top: 5px;
+ padding-right: 10px;
+ padding-left: 10px;
+ text-align: justify;
+ background-color: #eee;
+ border: black solid 1px;
+}
+div.tipdiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ color: black;
+ margin-top: 0px;
+ margin-bottom: 20px;
+}
+div.tipdiv h2 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 12px;
+ margin: 0px;
+}
+
+div.newsdiv {
+ margin-left: 220px;
+ margin-right: 180px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ text-align: justify;
+}
+div.newsdiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ margin: 0px;
+}
+div.newsdiv h2 {
+ font-weight: normal;
+ font-size: 12px;
+ margin: 0px;
+}
+div.newsdiv h3 {
+ font-weight: normal;
+ font-size: 12px;
+ margin-bottom: 20px;
+}
+div.objdiv {
+ margin-left: 220px;
+ margin-right: 20px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+}
+
+h1.newstitle {
+ text-align: left;
+ font-size: 14px;
+ margin: 0px 0px 0px 0px;
+ color: black;
+}
+div.titlediv {
+ border-top: solid #cac2a8 2px;
+ margin-top: 20px;
+ background-color: #eeeae6;
+ padding-left: 10px;
+ font-size: 11px;
+}
+div.bodydiv {
+ border: solid #9e9784 1px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+ padding-bottom: 5px;
+ margin-top: 2px;
+ text-align: justify;
+}
+
+div.comments {
+ padding: 10px;
+ border-top: solid 2px #d37537;
+ border-bottom: solid 2px #d37537;
+ margin-top: 20px;
+ margin-bottom: 10px;
+ background-color: #cacaca;
+ font-size: 12px;
+ line-height: 1.3em;
+}
+
+p.commentsbody {
+ border-left-style: solid;
+ border-width: 1px;
+ border-color: rgb(0, 0, 0);
+ padding-left: 10px;
+ text-align: justify;
+ margin-right: 20px;
+}
+
+div.commentsreply {
+ margin-left: 220px;
+ text-align: center;
+ margin-top: 50px;
+}
+
+ul.commentsul {
+ list-style-type: none;
+ margin-bottom: 10px;
+ margin-left: 1.25em;
+ padding-left: 0em;
+ border-left: 1px solid black;
+}
+ul.commentsli {
+ margin: 10px;
+}
+div.comments li {
+ margin-top: 20px;
+ margin-left: 2px;
+}
+
+div.comments h1 {
+ font-size: 12px;
+ color: black;
+ margin: 0px 20px 3px 0px;
+ background-color: rgb(226, 226, 226);
+ padding-left: 1px;
+ font-weight: none;
+}
+
+div.articlediv {
+ padding-left: 20px;
+ padding-right: 20px;
+ padding-top: 10px;
+ padding-bottom: 20px;
+ margin-right: 10px;
+ margin-left: 220px;
+ border: solid 1px black;
+ margin-top: 10px;
+ text-align: justify;
+ background-color: #E2E2E2;
+}
+img {
+ border: 0px;
+}
+div.sectionimg {
+ float: left;
+ margin-right: 10px;
+ margin-top: 5px;
+}
+p.hautpage {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ margin-left: 10px;
+}
+div.leftcol {
+ width: 202px;
+ width: 202px;
+ float: left;
+ padding: 0px;
+}
+div.logodiv {
+ border-right: 1px black solid;
+ border-bottom: 1px black solid;
+ padding: 0px;
+ line-height: 0px
+}
+div.loginbox {
+ margin-left: 4px;
+ border: solid #a59f8b 1px;
+ margin-top: 2px;
+ padding: 5px;
+ background-color: #fff2e8;
+ font-size: 10px;
+}
+div.loginbox p {
+ margin: 0px;
+ padding: 0px;
+}
+div.loginbox ul {
+ margin-left: 10px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+ list-style-type: none;
+}
+div.loginbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.loginbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.loginbox h3 {
+ margin-top: 0px;
+ margin-bottom: 5px;
+ font-size: 12px;
+}
+div.polldivtitle {
+ margin-bottom: 1px;
+ background-color: #cac2a8;
+ margin-left: 4px;
+ margin-top: 15px;
+ padding-left: 5px;
+ font-size: 10px;
+ border-top: solid #a59f8b 1px;
+ border-bottom: solid #a59f8b 1px;
+ text-transform: uppercase;
+}
+div.polldiv {
+ margin-left: 4px;
+ border: 1px #a59f8b solid;
+ margin-top: 0px;
+ padding: 5px;
+ background: #fff2e8;
+}
+div.polldiv p {
+margin: 5px; padding: 0px;
+}
+div.polldiv ul {
+ margin-left: 5px;
+ margin-top: 0px;
+ margin-bottom: 10px;
+ padding: 0px;
+ list-style-type: none;
+}
+div.otherboxtitle {
+ margin-bottom: 2px;
+ background-color: #e3dabc;
+ margin-left: 4px;
+ margin-top: 15px;
+ padding-left: 5px;
+ padding-top: 2px;
+ font-size: 11px;
+ border-top: solid #777364 1px;
+ border-bottom: solid #777364 1px;
+ text-transform: uppercase;
+ font-weight: bold;
+}
+div.otherbox {
+ margin-left: 4px;
+ border: 1px #a59f8b solid;
+ margin-top: 0px;
+ padding: 5px;
+ text-align: justify;
+ background: #fff2e8;
+ font-size: 10px;
+}
+div.otherbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.otherbox h2 {
+ font-weight: bold;
+ font-size: 11px;
+ margin: 0px;
+}
+div.otherbox p {
+ margin-top: 5px;
+ margin-bottom: 10px;
+}
+div.rightlogo {
+ width: 90px;
+ float: right;
+ margin-right: 0px;
+ padding-top: 0px;
+ padding-left: 0px;
+ padding-bottom: 0px;
+}
+div.centraldiv {
+ margin-left: 220px;
+ margin-right: 10px;
+ margin-bottom: 20px;
+ margin-top: 10px;
+}
+div.centraldiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ margin: 0px;
+}
+div.centraldiv h2 {
+ font-weight: normal;
+ font-size: 12px;
+ margin: 0px;
+}
+div.centraldiv h3 {
+ font-weight: normal;
+ font-size: 12px;
+ margin-bottom: 20px;
+}
+div.centralinfo {
+ position:relative;
+ height:160px;
+}
+div.lefttopbox {
+ position:relative;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-top: 5px;
+ border: 1px #a59f8b solid;
+ text-align: justify;
+ background: #fff2e8;
+ font-size: 12px;
+ width: 47%;
+ float: left;
+}
+div.lefttopbox p {
+ margin-top: 5px; margin-bottom: 10px;
+}
+div.lefttopbox h1 {
+ font-size: 13px;
+ font-weight: bold;
+ margin: 0px;
+ text-align: right;
+}
+div.lefttopbox h2 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.lefttopbox h3 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.righttopbox {
+ position:relative;
+ border: 1px #a59f8b solid;
+ background: white;
+ padding: 5px;
+ text-align: justify;
+ font-size: 12px;
+ width: 47%;
+ float: right;
+}
+div.righttopbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.righttopbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.boardindex {
+ text-align: justify;
+ font-size: 11px;
+ padding: 10px;
+ margin-left: 20px;
+ margin-right: 20px;
+}
+a.boardindex:link,a.boardindex:visited,a.boardindex:active {
+ text-decoration:none;
+ color: red;
+}
+div.boardleftmsg {
+ float: left;
+ margin-top: 3px;
+}
+div.boardrightmsg {
+ margin-left: 130px;
+ margin-top: 3px;
+ padding-left: 5px;
+}
+div.journalbody {
+ margin-left: 40px;
+ margin-top: 40px;
+}
+div.journalbody h1 {
+ font-size: 15px;
+ font-weight: bold;
+}
+div.journalbody p {
+ margin-bottom: 20px;
+}
+.formulaire {
+ border: solid 1px black;
+font-size: 12px;
+background-color: #eef;
+color: #000000;
+}
+.newcomments {
+ color: red;
+ font-weight: bold;
+}
+div.commentsreplythanks {
+ margin-left: 100px;
+ margin-top: 50px;
+ margin-right: 100px;
+ background-color: #eee;
+ border: black solid 1px;
+ padding: 10px;
+}
+div.archivediv {
+ margin-right: 20px;
+}
+.archivedate {
+ color:#f30;
+}
+.archivelink {
+ font-size: 14px;
+ font-weight: bold;
+ text-decoration: underline;
+}
diff --git a/tests/test-inputs/test2.css b/tests/test-inputs/test2.css
new file mode 100644
index 0000000..2442048
--- /dev/null
+++ b/tests/test-inputs/test2.css
@@ -0,0 +1,9 @@
+
+/*simple selector and simple rulset test*/
+S1 {prop1 : value1}
+
+/*Simple selector list and simple ruleset test*/
+s1,s2 {color: black ; background: white}
+
+/*descendants and child selector list, simple ruleset test*/
+s1 s2, S3 > s4 {prop1 : value1 ; prop2 : value2}
diff --git a/tests/test-inputs/test3.1.css b/tests/test-inputs/test3.1.css
new file mode 100644
index 0000000..9c53843
--- /dev/null
+++ b/tests/test-inputs/test3.1.css
@@ -0,0 +1,36 @@
+S1:lang(c) {prop1 : value1}
+
+/*simple Attribute set selectors*/
+s1[foo] {prop1 : value1}
+
+/*simple exact attribute selector, simple ruleset*/
+s1[foo="warning"] {prop1 : value1}
+
+/**
+ *"space separated value list"
+ *attribute selector, simple ruleset
+ */
+s1[foo~="warning"] {prop1 :value1}
+
+/**
+ *"hyphen separated value list" attribute selector,
+ * simple ruleset
+ */
+
+ /*simple class selector, simple ruleset*/
+ s1.warning {prop1 : value}
+
+ E#myid {prop1 : value1}
+
+
+/*below are tests that we know are working*/
+
+/*simple ident pseudo class selector, simple ruleset test*/
+S1:first-child {prop1 : value1 ; prop2 : value2}
+
+/*function pseudo class selector, simple ruleset test => merdoie*/
+S1:lang(c) {prop1 : value1}
+
+/*Adjacent selectors, simple ruleset test*/
+S1 + s2 {prop1: value1}
+
diff --git a/tests/test-inputs/test3.2.css b/tests/test-inputs/test3.2.css
new file mode 100644
index 0000000..2857fc4
--- /dev/null
+++ b/tests/test-inputs/test3.2.css
@@ -0,0 +1,693 @@
+h1.rubrique_info {
+ color: #990033;
+ margin: 0px 0px 0px 0px;
+ padding: 0em;
+ border: 0px;
+ font-size: 12px;
+}
+
+* {
+ font-family: Verdana, Arial, Helvetica, sans-serif, monospace;
+}
+
+body {
+ background: #606060;
+ color: #000000;
+}
+
+a:link {
+ color: #0000FF;
+ background: transparent;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #990099;
+ background: transparent;
+ text-decoration: none;
+}
+
+
+a:active {
+ color: #000000;
+ background: #ADD8E6;
+ text-decoration: none;
+}
+
+
+h1.rubrique_info {
+ color: #990033;
+ margin: 0px 0px 0px 0px;
+ padding: 0em;
+ border: 0px;
+ font-size: 12px;
+}
+
+/*
+h1.connexe {
+ font-size: 12px;
+ padding: 0em;
+ margin: 0px 0px 0px 0px;
+ color: #990033;
+}
+
+
+a.rubrique_infolink {
+ text-decoration: none;
+}
+
+
+ul.rubrique_infoul {
+ display: inline;
+ list-style-type: square;
+}
+
+
+ul.rubrique_infoul * {
+ width: 100%;
+}
+
+li.rubrique_infoul {
+ margin-left: 15px;
+}
+h1 {
+ color: #990033;
+}
+
+div.main {
+ background: white;
+ color: #000000;
+ margin-left: 5px;
+ margin-right: 5px;
+ border: 1px black solid;
+ text-align: left;
+ font-size: 12px;
+}
+div.lsfnbanner {
+ margin-left: 150px;
+ margin-right: 170px;
+ border-top: none;
+ padding-left: 10px;
+ padding-right: 10px;
+ border-bottom: 1px black solid;
+ border-right: 1px black solid;
+ border-left: 1px black solid;
+ text-align: left;
+ font-size: 11px;
+ padding-top: 2px;
+ background-color: #eeeae6;
+}
+div.footer {
+ padding-top: 5px;
+ padding-bottom: 3px;
+ border-top: 1px black solid;
+ border-left: 1px black solid;
+ border-right: 1px black solid;
+ text-align: left;
+ font-size: 9px;
+ background: #dcdff4;
+ width: 600px;
+ margin-top: 40px;
+ margin-left: 20px;
+}
+div.footer p {
+ margin-left: 10px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+}
+
+a.lsfnlink:link,a.lsfnlink:visited,a.lsfnlink:active {
+ text-decoration: none;
+ color: #333333;
+ font-size: 10px;
+}
+a.lsfnlink:hover {
+ text-decoration: underline;
+ color: black;
+}
+div.menubartop {
+ margin-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 0px;
+ font-size: 13px;
+}
+div.smallmenubar {
+ background: white;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ font-weight:bold;
+ font-size: 10px;
+ text-align: right;
+}
+
+div.menuevent {
+ float: left;
+ width: 350px;
+ font-size: 11px;
+ text-align: left;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 10px;
+ font-weight: bold;
+ margin: 0px;
+}
+div.menubar {
+ background: #cac2a8;
+ border-top: 1px black solid;
+ border-bottom: 1px black solid;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 3px;
+ padding-bottom: 2px;
+ font-weight:bold;
+ font-size: 13px;
+}
+div.menubar a {
+ text-decoration: none;
+}
+div.menudate {
+ float: left;
+ width: 130px;
+ padding-top: 5px;
+}
+div.menuaccroche {
+ margin-left: 30px;
+ float: left;
+ text-decoration: underline;
+ font-size: 14px;
+}
+div.menusearch {
+ float: right;
+ text-align: right;
+ padding-top: 5px;
+ width: 170px;
+}
+div.menusearch p {
+ margin: 0px 0px 0px 0px;
+}
+.searchinput {
+ border: solid 1px black;
+}
+a#menulinkselect {
+ color: #ed7e00;
+}
+
+div.leftbox {
+ width: 200px;
+ float: left;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-bottom: 5px;
+ border-right: 1px black solid;
+ border-bottom: 1px black solid;
+ background: white;
+ margin-bottom: 10px;
+}
+div.leftbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.leftbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.leftbox ul {
+ list-style-type: square;
+ margin-bottom: 10px;
+ margin-left: 0em;
+ padding-left: 0em;
+}
+div.leftbox li {
+ margin-left: 10px;
+}
+
+div.rightbox {
+ width: 150px;
+ float: right;
+ padding-top: 10px;
+ padding-left: 5px;
+ padding-right: 15px;
+ padding-bottom: 5px;
+ border-left: 1px black solid;
+ border-bottom: 1px black solid;
+ text-align: left;
+}
+div.newjournaldiv {
+ text-align: justify;
+ margin-left: 10%;
+ font-size: 12px;
+ width: 600px;
+}
+div.newjournaldiv p {
+ margin-bottom: 0px;
+ margin-top: 20px;
+}
+div.journaldiv {
+ margin-left: 0px;
+ margin-right: 0px;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 1px black solid;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ padding-right: 10px;
+ padding-left: 10px;
+ background-color: #eef;
+}
+div.journaldiv p {
+ margin-top: 10px;
+ margin-bottom: 0px;
+}
+div.journaldiv h1 {
+ color: #990033;
+ font-size: 14px;
+ margin: 0px;
+}
+div.journaldiv h2 {
+ font-size: 10px;
+ margin: 0px;
+}
+div.tipdiv {
+ margin-left: 220px;
+ margin-right: 50px;
+ margin-top: 20px;
+ padding-top: 5px;
+ padding-right: 10px;
+ padding-left: 10px;
+ text-align: justify;
+ background-color: #eee;
+ border: black solid 1px;
+}
+div.tipdiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ color: black;
+ margin-top: 0px;
+ margin-bottom: 20px;
+}
+div.tipdiv h2 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 12px;
+ margin: 0px;
+}
+
+div.newsdiv {
+ margin-left: 220px;
+ margin-right: 180px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ text-align: justify;
+}
+div.newsdiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ margin: 0px;
+}
+div.newsdiv h2 {
+ font-weight: normal;
+ font-size: 12px;
+ margin: 0px;
+}
+div.newsdiv h3 {
+ font-weight: normal;
+ font-size: 12px;
+ margin-bottom: 20px;
+}
+div.objdiv {
+ margin-left: 220px;
+ margin-right: 20px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+}
+
+h1.newstitle {
+ text-align: left;
+ font-size: 14px;
+ margin: 0px 0px 0px 0px;
+ color: black;
+}
+div.titlediv {
+ border-top: solid #cac2a8 2px;
+ margin-top: 20px;
+ background-color: #eeeae6;
+ padding-left: 10px;
+ font-size: 11px;
+}
+div.bodydiv {
+ border: solid #9e9784 1px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+ padding-bottom: 5px;
+ margin-top: 2px;
+ text-align: justify;
+}
+
+div.comments {
+ padding: 10px;
+ border-top: solid 2px #d37537;
+ border-bottom: solid 2px #d37537;
+ margin-top: 20px;
+ margin-bottom: 10px;
+ background-color: #cacaca;
+ font-size: 12px;
+ line-height: 1.3em;
+}
+
+p.commentsbody {
+ border-left-style: solid;
+ border-width: 1px;
+ border-color: rgb(0, 0, 0);
+ padding-left: 10px;
+ text-align: justify;
+ margin-right: 20px;
+}
+
+div.commentsreply {
+ margin-left: 220px;
+ text-align: center;
+ margin-top: 50px;
+}
+
+ul.commentsul {
+ list-style-type: none;
+ margin-bottom: 10px;
+ margin-left: 1.25em;
+ padding-left: 0em;
+ border-left: 1px solid black;
+}
+ul.commentsli {
+ margin: 10px;
+}
+div.comments li {
+ margin-top: 20px;
+ margin-left: 2px;
+}
+
+div.comments h1 {
+ font-size: 12px;
+ color: black;
+ margin: 0px 20px 3px 0px;
+ background-color: rgb(226, 226, 226);
+ padding-left: 1px;
+ font-weight: none;
+}
+
+div.articlediv {
+ padding-left: 20px;
+ padding-right: 20px;
+ padding-top: 10px;
+ padding-bottom: 20px;
+ margin-right: 10px;
+ margin-left: 220px;
+ border: solid 1px black;
+ margin-top: 10px;
+ text-align: justify;
+ background-color: #E2E2E2;
+}
+img {
+ border: 0px;
+}
+div.sectionimg {
+ float: left;
+ margin-right: 10px;
+ margin-top: 5px;
+}
+p.hautpage {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ margin-left: 10px;
+}
+div.leftcol {
+ width: 202px;
+ width: 202px;
+ float: left;
+ padding: 0px;
+}
+div.logodiv {
+ border-right: 1px black solid;
+ border-bottom: 1px black solid;
+ padding: 0px;
+ line-height: 0px
+}
+div.loginbox {
+ margin-left: 4px;
+ border: solid #a59f8b 1px;
+ margin-top: 2px;
+ padding: 5px;
+ background-color: #fff2e8;
+ font-size: 10px;
+}
+div.loginbox p {
+ margin: 0px;
+ padding: 0px;
+}
+div.loginbox ul {
+ margin-left: 10px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+ list-style-type: none;
+}
+div.loginbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.loginbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.loginbox h3 {
+ margin-top: 0px;
+ margin-bottom: 5px;
+ font-size: 12px;
+}
+div.polldivtitle {
+ margin-bottom: 1px;
+ background-color: #cac2a8;
+ margin-left: 4px;
+ margin-top: 15px;
+ padding-left: 5px;
+ font-size: 10px;
+ border-top: solid #a59f8b 1px;
+ border-bottom: solid #a59f8b 1px;
+ text-transform: uppercase;
+}
+div.polldiv {
+ margin-left: 4px;
+ border: 1px #a59f8b solid;
+ margin-top: 0px;
+ padding: 5px;
+ background: #fff2e8;
+}
+div.polldiv p {
+margin: 5px; padding: 0px;
+}
+div.polldiv ul {
+ margin-left: 5px;
+ margin-top: 0px;
+ margin-bottom: 10px;
+ padding: 0px;
+ list-style-type: none;
+}
+div.otherboxtitle {
+ margin-bottom: 2px;
+ background-color: #e3dabc;
+ margin-left: 4px;
+ margin-top: 15px;
+ padding-left: 5px;
+ padding-top: 2px;
+ font-size: 11px;
+ border-top: solid #777364 1px;
+ border-bottom: solid #777364 1px;
+ text-transform: uppercase;
+ font-weight: bold;
+}
+div.otherbox {
+ margin-left: 4px;
+ border: 1px #a59f8b solid;
+ margin-top: 0px;
+ padding: 5px;
+ text-align: justify;
+ background: #fff2e8;
+ font-size: 10px;
+}
+div.otherbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.otherbox h2 {
+ font-weight: bold;
+ font-size: 11px;
+ margin: 0px;
+}
+div.otherbox p {
+ margin-top: 5px;
+ margin-bottom: 10px;
+}
+div.rightlogo {
+ width: 90px;
+ float: right;
+ margin-right: 0px;
+ padding-top: 0px;
+ padding-left: 0px;
+ padding-bottom: 0px;
+}
+div.centraldiv {
+ margin-left: 220px;
+ margin-right: 10px;
+ margin-bottom: 20px;
+ margin-top: 10px;
+}
+div.centraldiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ margin: 0px;
+}
+div.centraldiv h2 {
+ font-weight: normal;
+ font-size: 12px;
+ margin: 0px;
+}
+div.centraldiv h3 {
+ font-weight: normal;
+ font-size: 12px;
+ margin-bottom: 20px;
+}
+div.centralinfo {
+ position:relative;
+ height:160px;
+}
+div.lefttopbox {
+ position:relative;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-top: 5px;
+ border: 1px #a59f8b solid;
+ text-align: justify;
+ background: #fff2e8;
+ font-size: 12px;
+ width: 47%;
+ float: left;
+}
+div.lefttopbox p {
+ margin-top: 5px; margin-bottom: 10px;
+}
+div.lefttopbox h1 {
+ font-size: 13px;
+ font-weight: bold;
+ margin: 0px;
+ text-align: right;
+}
+div.lefttopbox h2 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.lefttopbox h3 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.righttopbox {
+ position:relative;
+ border: 1px #a59f8b solid;
+ background: white;
+ padding: 5px;
+ text-align: justify;
+ font-size: 12px;
+ width: 47%;
+ float: right;
+}
+div.righttopbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.righttopbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.boardindex {
+ text-align: justify;
+ font-size: 11px;
+ padding: 10px;
+ margin-left: 20px;
+ margin-right: 20px;
+}
+a.boardindex:link,a.boardindex:visited,a.boardindex:active {
+ text-decoration:none;
+ color: red;
+}
+div.boardleftmsg {
+ float: left;
+ margin-top: 3px;
+}
+div.boardrightmsg {
+ margin-left: 130px;
+ margin-top: 3px;
+ padding-left: 5px;
+}
+div.journalbody {
+ margin-left: 40px;
+ margin-top: 40px;
+}
+div.journalbody h1 {
+ font-size: 15px;
+ font-weight: bold;
+}
+div.journalbody p {
+ margin-bottom: 20px;
+}
+
+.formulaire {
+ border: solid 1px black;
+font-size: 12px;
+background-color: #eef;
+color: #000000;
+}
+.newcomments {
+ color: red;
+ font-weight: bold;
+}
+div.commentsreplythanks {
+ margin-left: 100px;
+ margin-top: 50px;
+ margin-right: 100px;
+ background-color: #eee;
+ border: black solid 1px;
+ padding: 10px;
+}
+div.archivediv {
+ margin-right: 20px;
+}
+.archivedate {
+ color:#f30;
+}
+.archivelink {
+ font-size: 14px;
+ font-weight: bold;
+ text-decoration: underline;
+}
+*/ \ No newline at end of file
diff --git a/tests/test-inputs/test3.css b/tests/test-inputs/test3.css
new file mode 100644
index 0000000..2442048
--- /dev/null
+++ b/tests/test-inputs/test3.css
@@ -0,0 +1,9 @@
+
+/*simple selector and simple rulset test*/
+S1 {prop1 : value1}
+
+/*Simple selector list and simple ruleset test*/
+s1,s2 {color: black ; background: white}
+
+/*descendants and child selector list, simple ruleset test*/
+s1 s2, S3 > s4 {prop1 : value1 ; prop2 : value2}
diff --git a/tests/test-inputs/test4.1.css b/tests/test-inputs/test4.1.css
new file mode 100644
index 0000000..ba128d4
--- /dev/null
+++ b/tests/test-inputs/test4.1.css
@@ -0,0 +1,679 @@
+* {
+ font-family: Verdana, Arial, Helvetica, sans-serif, monospace;
+}
+
+
+body {
+ background: #606060;
+ color: #000000;
+}
+
+
+a:link {
+ color: #0000FF;
+ background: transparent;
+ text-decoration: none;
+}
+
+
+a:visited {
+ color: #990099;
+ background: transparent;
+ text-decoration: none;
+}
+
+
+a:active {
+ color: #000000;
+ background: #ADD8E6;
+ text-decoration: none;
+}
+
+h1.rubrique_info {
+ color: #990033;
+ margin: 0px 0px 0px 0px;
+ padding: 0em;
+ border: 0px;
+ font-size: 12px;
+}
+h1.connexe {
+ font-size: 12px;
+ padding: 0em;
+ margin: 0px 0px 0px 0px;
+ color: #990033;
+}
+
+a.rubrique_infolink {
+ text-decoration: none;
+}
+
+ul.rubrique_infoul {
+ display: inline;
+ list-style-type: square;
+}
+ul.rubrique_infoul * {
+ width: 100%;
+}
+li.rubrique_infoul {
+ margin-left: 15px;
+}
+h1 {
+ color: #990033;
+}
+
+div.main {
+ background: white;
+ color: #000000;
+ margin-left: 5px;
+ margin-right: 5px;
+ border: 1px black solid;
+ text-align: left;
+ font-size: 12px;
+}
+div.lsfnbanner {
+ margin-left: 150px;
+ margin-right: 170px;
+ border-top: none;
+ padding-left: 10px;
+ padding-right: 10px;
+ border-bottom: 1px black solid;
+ border-right: 1px black solid;
+ border-left: 1px black solid;
+ text-align: left;
+ font-size: 11px;
+ padding-top: 2px;
+ background-color: #eeeae6;
+}
+div.footer {
+ padding-top: 5px;
+ padding-bottom: 3px;
+ border-top: 1px black solid;
+ border-left: 1px black solid;
+ border-right: 1px black solid;
+ text-align: left;
+ font-size: 9px;
+ background: #dcdff4;
+ width: 600px;
+ margin-top: 40px;
+ margin-left: 20px;
+}
+div.footer p {
+ margin-left: 10px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+}
+
+a.lsfnlink:link,a.lsfnlink:visited,a.lsfnlink:active {
+ text-decoration: none;
+ color: #333333;
+ font-size: 10px;
+}
+a.lsfnlink:hover {
+ text-decoration: underline;
+ color: black;
+}
+div.menubartop {
+ margin-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 0px;
+ font-size: 13px;
+}
+div.smallmenubar {
+ background: white;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ font-weight:bold;
+ font-size: 10px;
+ text-align: right;
+}
+div.menuevent {
+ float: left;
+ width: 350px;
+ font-size: 11px;
+ text-align: left;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-left: 10px;
+ font-weight: bold;
+ margin: 0px;
+}
+div.menubar {
+ background: #cac2a8;
+ border-top: 1px black solid;
+ border-bottom: 1px black solid;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 3px;
+ padding-bottom: 2px;
+ font-weight:bold;
+ font-size: 13px;
+}
+div.menubar a {
+ text-decoration: none;
+}
+div.menudate {
+ float: left;
+ width: 130px;
+ padding-top: 5px;
+}
+div.menuaccroche {
+ margin-left: 30px;
+ float: left;
+ text-decoration: underline;
+ font-size: 14px;
+}
+div.menusearch {
+ float: right;
+ text-align: right;
+ padding-top: 5px;
+ width: 170px;
+}
+div.menusearch p {
+ margin: 0px 0px 0px 0px;
+}
+.searchinput {
+ border: solid 1px black;
+}
+a#menulinkselect {
+ color: #ed7e00;
+}
+
+div.leftbox {
+ width: 200px;
+ float: left;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-bottom: 5px;
+ border-right: 1px black solid;
+ border-bottom: 1px black solid;
+ background: white;
+ margin-bottom: 10px;
+}
+div.leftbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.leftbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.leftbox ul {
+ list-style-type: square;
+ margin-bottom: 10px;
+ margin-left: 0em;
+ padding-left: 0em;
+}
+div.leftbox li {
+ margin-left: 10px;
+}
+
+div.rightbox {
+ width: 150px;
+ float: right;
+ padding-top: 10px;
+ padding-left: 5px;
+ padding-right: 15px;
+ padding-bottom: 5px;
+ border-left: 1px black solid;
+ border-bottom: 1px black solid;
+ text-align: left;
+}
+div.newjournaldiv {
+ text-align: justify;
+ margin-left: 10%;
+ font-size: 12px;
+ width: 600px;
+}
+div.newjournaldiv p {
+ margin-bottom: 0px;
+ margin-top: 20px;
+}
+div.journaldiv {
+ margin-left: 0px;
+ margin-right: 0px;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 1px black solid;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ padding-right: 10px;
+ padding-left: 10px;
+ background-color: #eef;
+}
+div.journaldiv p {
+ margin-top: 10px;
+ margin-bottom: 0px;
+}
+div.journaldiv h1 {
+ color: #990033;
+ font-size: 14px;
+ margin: 0px;
+}
+div.journaldiv h2 {
+ font-size: 10px;
+ margin: 0px;
+}
+div.tipdiv {
+ margin-left: 220px;
+ margin-right: 50px;
+ margin-top: 20px;
+ padding-top: 5px;
+ padding-right: 10px;
+ padding-left: 10px;
+ text-align: justify;
+ background-color: #eee;
+ border: black solid 1px;
+}
+div.tipdiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ color: black;
+ margin-top: 0px;
+ margin-bottom: 20px;
+}
+div.tipdiv h2 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 12px;
+ margin: 0px;
+}
+
+div.newsdiv {
+ margin-left: 220px;
+ margin-right: 180px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ text-align: justify;
+}
+div.newsdiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ margin: 0px;
+}
+div.newsdiv h2 {
+ font-weight: normal;
+ font-size: 12px;
+ margin: 0px;
+}
+div.newsdiv h3 {
+ font-weight: normal;
+ font-size: 12px;
+ margin-bottom: 20px;
+}
+div.objdiv {
+ margin-left: 220px;
+ margin-right: 20px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+}
+
+h1.newstitle {
+ text-align: left;
+ font-size: 14px;
+ margin: 0px 0px 0px 0px;
+ color: black;
+}
+div.titlediv {
+ border-top: solid #cac2a8 2px;
+ margin-top: 20px;
+ background-color: #eeeae6;
+ padding-left: 10px;
+ font-size: 11px;
+}
+div.bodydiv {
+ border: solid #9e9784 1px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+ padding-bottom: 5px;
+ margin-top: 2px;
+ text-align: justify;
+}
+
+div.comments {
+ padding: 10px;
+ border-top: solid 2px #d37537;
+ border-bottom: solid 2px #d37537;
+ margin-top: 20px;
+ margin-bottom: 10px;
+ background-color: #cacaca;
+ font-size: 12px;
+ line-height: 1.3em;
+}
+
+
+p.commentsbody {
+ border-left-style: solid;
+ border-width: 1px;
+ border-color: rgb(0, 0, 0);
+ padding-left: 10px;
+ text-align: justify;
+ margin-right: 20px;
+}
+
+
+div.commentsreply {
+ margin-left: 220px;
+ text-align: center;
+ margin-top: 50px;
+}
+
+ul.commentsul {
+ list-style-type: none;
+ margin-bottom: 10px;
+ margin-left: 1.25em;
+ padding-left: 0em;
+ border-left: 1px solid black;
+}
+ul.commentsli {
+ margin: 10px;
+}
+div.comments li {
+ margin-top: 20px;
+ margin-left: 2px;
+}
+
+div.comments h1 {
+ font-size: 12px;
+ color: black;
+ margin: 0px 20px 3px 0px;
+ background-color: rgb(226, 226, 226);
+ padding-left: 1px;
+ font-weight: none;
+}
+
+div.articlediv {
+ padding-left: 20px;
+ padding-right: 20px;
+ padding-top: 10px;
+ padding-bottom: 20px;
+ margin-right: 10px;
+ margin-left: 220px;
+ border: solid 1px black;
+ margin-top: 10px;
+ text-align: justify;
+ background-color: #E2E2E2;
+}
+img {
+ border: 0px;
+}
+div.sectionimg {
+ float: left;
+ margin-right: 10px;
+ margin-top: 5px;
+}
+p.hautpage {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ margin-left: 10px;
+}
+div.leftcol {
+ width: 202px;
+ width: 202px;
+ float: left;
+ padding: 0px;
+}
+div.logodiv {
+ border-right: 1px black solid;
+ border-bottom: 1px black solid;
+ padding: 0px;
+ line-height: 0px
+}
+div.loginbox {
+ margin-left: 4px;
+ border: solid #a59f8b 1px;
+ margin-top: 2px;
+ padding: 5px;
+ background-color: #fff2e8;
+ font-size: 10px;
+}
+div.loginbox p {
+ margin: 0px;
+ padding: 0px;
+}
+div.loginbox ul {
+ margin-left: 10px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+ list-style-type: none;
+}
+div.loginbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.loginbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.loginbox h3 {
+ margin-top: 0px;
+ margin-bottom: 5px;
+ font-size: 12px;
+}
+div.polldivtitle {
+ margin-bottom: 1px;
+ background-color: #cac2a8;
+ margin-left: 4px;
+ margin-top: 15px;
+ padding-left: 5px;
+ font-size: 10px;
+ border-top: solid #a59f8b 1px;
+ border-bottom: solid #a59f8b 1px;
+ text-transform: uppercase;
+}
+div.polldiv {
+ margin-left: 4px;
+ border: 1px #a59f8b solid;
+ margin-top: 0px;
+ padding: 5px;
+ background: #fff2e8;
+}
+div.polldiv p {
+margin: 5px; padding: 0px;
+}
+div.polldiv ul {
+ margin-left: 5px;
+ margin-top: 0px;
+ margin-bottom: 10px;
+ padding: 0px;
+ list-style-type: none;
+}
+div.otherboxtitle {
+ margin-bottom: 2px;
+ background-color: #e3dabc;
+ margin-left: 4px;
+ margin-top: 15px;
+ padding-left: 5px;
+ padding-top: 2px;
+ font-size: 11px;
+ border-top: solid #777364 1px;
+ border-bottom: solid #777364 1px;
+ text-transform: uppercase;
+ font-weight: bold;
+}
+div.otherbox {
+ margin-left: 4px;
+ border: 1px #a59f8b solid;
+ margin-top: 0px;
+ padding: 5px;
+ text-align: justify;
+ background: #fff2e8;
+ font-size: 10px;
+}
+div.otherbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.otherbox h2 {
+ font-weight: bold;
+ font-size: 11px;
+ margin: 0px;
+}
+div.otherbox p {
+ margin-top: 5px;
+ margin-bottom: 10px;
+}
+div.rightlogo {
+ width: 90px;
+ float: right;
+ margin-right: 0px;
+ padding-top: 0px;
+ padding-left: 0px;
+ padding-bottom: 0px;
+}
+div.centraldiv {
+ margin-left: 220px;
+ margin-right: 10px;
+ margin-bottom: 20px;
+ margin-top: 10px;
+}
+div.centraldiv h1 {
+ font-weight: bold;
+ font-size: 14px;
+ margin: 0px;
+}
+div.centraldiv h2 {
+ font-weight: normal;
+ font-size: 12px;
+ margin: 0px;
+}
+div.centraldiv h3 {
+ font-weight: normal;
+ font-size: 12px;
+ margin-bottom: 20px;
+}
+div.centralinfo {
+ position:relative;
+ height:160px;
+}
+div.lefttopbox {
+ position:relative;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-top: 5px;
+ border: 1px #a59f8b solid;
+ text-align: justify;
+ background: #fff2e8;
+ font-size: 12px;
+ width: 47%;
+ float: left;
+}
+div.lefttopbox p {
+ margin-top: 5px; margin-bottom: 10px;
+}
+div.lefttopbox h1 {
+ font-size: 13px;
+ font-weight: bold;
+ margin: 0px;
+ text-align: right;
+}
+div.lefttopbox h2 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.lefttopbox h3 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.righttopbox {
+ position:relative;
+ border: 1px #a59f8b solid;
+ background: white;
+ padding: 5px;
+ text-align: justify;
+ font-size: 12px;
+ width: 47%;
+ float: right;
+}
+div.righttopbox h1 {
+ text-transform: uppercase;
+ font-weight: bold;
+ color: #ed7e00;
+ font-size: 10px;
+ margin: 0px;
+}
+div.righttopbox h2 {
+ font-weight: bold;
+ font-size: 12px;
+ margin: 0px;
+}
+div.boardindex {
+ text-align: justify;
+ font-size: 11px;
+ padding: 10px;
+ margin-left: 20px;
+ margin-right: 20px;
+}
+a.boardindex:link,a.boardindex:visited,a.boardindex:active {
+ text-decoration:none;
+ color: red;
+}
+div.boardleftmsg {
+ float: left;
+ margin-top: 3px;
+}
+div.boardrightmsg {
+ margin-left: 130px;
+ margin-top: 3px;
+ padding-left: 5px;
+}
+div.journalbody {
+ margin-left: 40px;
+ margin-top: 40px;
+}
+div.journalbody h1 {
+ font-size: 15px;
+ font-weight: bold;
+}
+div.journalbody p {
+ margin-bottom: 20px;
+}
+.formulaire {
+ border: solid 1px black;
+font-size: 12px;
+background-color: #eef;
+color: #000000;
+}
+.newcomments {
+ color: red;
+ font-weight: bold;
+}
+div.commentsreplythanks {
+ margin-left: 100px;
+ margin-top: 50px;
+ margin-right: 100px;
+ background-color: #eee;
+ border: black solid 1px;
+ padding: 10px;
+}
+div.archivediv {
+ margin-right: 20px;
+}
+.archivedate {
+ color:#f30;
+}
+.archivelink {
+ font-size: 14px;
+ font-weight: bold;
+ text-decoration: underline;
+}
diff --git a/tests/test-inputs/test4.2.css b/tests/test-inputs/test4.2.css
new file mode 100644
index 0000000..2dafbef
--- /dev/null
+++ b/tests/test-inputs/test4.2.css
@@ -0,0 +1,24 @@
+@charset "ISO-8859-1" ;
+
+@import url("http://www.yahoo.com/css") print , screen ;
+
+@font-face {
+ font-family: "Robson Celtic";
+ src: url("http://site/fonts/rob-celt")
+}
+
+
+
+@page left:one-two {
+ margin: 10pt;
+ border:none
+}
+
+@media print , screen , projection {
+ H1 { font-family: "Robson Celtic", serif }
+
+ P {
+ background: black ;
+ foreground: white ;
+ }
+}
diff --git a/tests/test-outputs/test4.1.out b/tests/test-outputs/test4.1.out
new file mode 100644
index 0000000..cf3292e
--- /dev/null
+++ b/tests/test-outputs/test4.1.out
@@ -0,0 +1,762 @@
+* {
+ font-family : Verdana, Arial, Helvetica, sans-serif, monospace
+}
+
+body {
+ background : #606060;
+ color : #000000
+}
+
+a:link {
+ color : #0000FF;
+ background : transparent;
+ text-decoration : none
+}
+
+a:visited {
+ color : #990099;
+ background : transparent;
+ text-decoration : none
+}
+
+a:active {
+ color : #000000;
+ background : #ADD8E6;
+ text-decoration : none
+}
+
+h1.rubrique_info {
+ color : #990033;
+ margin : 0px 0px 0px 0px;
+ padding : 0em;
+ border : 0px;
+ font-size : 12px
+}
+
+h1.connexe {
+ font-size : 12px;
+ padding : 0em;
+ margin : 0px 0px 0px 0px;
+ color : #990033
+}
+
+a.rubrique_infolink {
+ text-decoration : none
+}
+
+ul.rubrique_infoul {
+ display : inline;
+ list-style-type : square
+}
+
+ul.rubrique_infoul * {
+ width : 100%
+}
+
+li.rubrique_infoul {
+ margin-left : 15px
+}
+
+h1 {
+ color : #990033
+}
+
+div.main {
+ background : white;
+ color : #000000;
+ margin-left : 5px;
+ margin-right : 5px;
+ border : 1px black solid;
+ text-align : left;
+ font-size : 12px
+}
+
+div.lsfnbanner {
+ margin-left : 150px;
+ margin-right : 170px;
+ border-top : none;
+ padding-left : 10px;
+ padding-right : 10px;
+ border-bottom : 1px black solid;
+ border-right : 1px black solid;
+ border-left : 1px black solid;
+ text-align : left;
+ font-size : 11px;
+ padding-top : 2px;
+ background-color : #eeeae6
+}
+
+div.footer {
+ padding-top : 5px;
+ padding-bottom : 3px;
+ border-top : 1px black solid;
+ border-left : 1px black solid;
+ border-right : 1px black solid;
+ text-align : left;
+ font-size : 9px;
+ background : #dcdff4;
+ width : 600px;
+ margin-top : 40px;
+ margin-left : 20px
+}
+
+div.footer p {
+ margin-left : 10px;
+ margin-top : 2px;
+ margin-bottom : 2px
+}
+
+a.lsfnlink:link, a.lsfnlink:visited, a.lsfnlink:active {
+ text-decoration : none;
+ color : #333333;
+ font-size : 10px
+}
+
+a.lsfnlink:hover {
+ text-decoration : underline;
+ color : black
+}
+
+div.menubartop {
+ margin-bottom : 10px;
+ padding-left : 10px;
+ padding-right : 10px;
+ padding-top : 0px;
+ font-size : 13px
+}
+
+div.smallmenubar {
+ background : white;
+ padding-left : 10px;
+ padding-right : 10px;
+ padding-top : 0px;
+ padding-bottom : 0px;
+ font-weight : bold;
+ font-size : 10px;
+ text-align : right
+}
+
+div.menuevent {
+ float : left;
+ width : 350px;
+ font-size : 11px;
+ text-align : left;
+ padding-top : 0px;
+ padding-bottom : 0px;
+ padding-left : 10px;
+ font-weight : bold;
+ margin : 0px
+}
+
+div.menubar {
+ background : #cac2a8;
+ border-top : 1px black solid;
+ border-bottom : 1px black solid;
+ padding-left : 10px;
+ padding-right : 10px;
+ padding-top : 3px;
+ padding-bottom : 2px;
+ font-weight : bold;
+ font-size : 13px
+}
+
+div.menubar a {
+ text-decoration : none
+}
+
+div.menudate {
+ float : left;
+ width : 130px;
+ padding-top : 5px
+}
+
+div.menuaccroche {
+ margin-left : 30px;
+ float : left;
+ text-decoration : underline;
+ font-size : 14px
+}
+
+div.menusearch {
+ float : right;
+ text-align : right;
+ padding-top : 5px;
+ width : 170px
+}
+
+div.menusearch p {
+ margin : 0px 0px 0px 0px
+}
+
+.searchinput {
+ border : solid 1px black
+}
+
+a#menulinkselect {
+ color : #ed7e00
+}
+
+div.leftbox {
+ width : 200px;
+ float : left;
+ padding-left : 5px;
+ padding-right : 5px;
+ padding-bottom : 5px;
+ border-right : 1px black solid;
+ border-bottom : 1px black solid;
+ background : white;
+ margin-bottom : 10px
+}
+
+div.leftbox h1 {
+ text-transform : uppercase;
+ font-weight : bold;
+ color : #ed7e00;
+ font-size : 10px;
+ margin : 0px
+}
+
+div.leftbox h2 {
+ font-weight : bold;
+ font-size : 12px;
+ margin : 0px
+}
+
+div.leftbox ul {
+ list-style-type : square;
+ margin-bottom : 10px;
+ margin-left : 0em;
+ padding-left : 0em
+}
+
+div.leftbox li {
+ margin-left : 10px
+}
+
+div.rightbox {
+ width : 150px;
+ float : right;
+ padding-top : 10px;
+ padding-left : 5px;
+ padding-right : 15px;
+ padding-bottom : 5px;
+ border-left : 1px black solid;
+ border-bottom : 1px black solid;
+ text-align : left
+}
+
+div.newjournaldiv {
+ text-align : justify;
+ margin-left : 10%;
+ font-size : 12px;
+ width : 600px
+}
+
+div.newjournaldiv p {
+ margin-bottom : 0px;
+ margin-top : 20px
+}
+
+div.journaldiv {
+ margin-left : 0px;
+ margin-right : 0px;
+ margin-top : 20px;
+ margin-bottom : 20px;
+ border : 1px black solid;
+ padding-top : 5px;
+ padding-bottom : 5px;
+ padding-right : 10px;
+ padding-left : 10px;
+ background-color : #eef
+}
+
+div.journaldiv p {
+ margin-top : 10px;
+ margin-bottom : 0px
+}
+
+div.journaldiv h1 {
+ color : #990033;
+ font-size : 14px;
+ margin : 0px
+}
+
+div.journaldiv h2 {
+ font-size : 10px;
+ margin : 0px
+}
+
+div.tipdiv {
+ margin-left : 220px;
+ margin-right : 50px;
+ margin-top : 20px;
+ padding-top : 5px;
+ padding-right : 10px;
+ padding-left : 10px;
+ text-align : justify;
+ background-color : #eee;
+ border : black solid 1px
+}
+
+div.tipdiv h1 {
+ font-weight : bold;
+ font-size : 14px;
+ color : black;
+ margin-top : 0px;
+ margin-bottom : 20px
+}
+
+div.tipdiv h2 {
+ text-transform : uppercase;
+ font-weight : bold;
+ color : #ed7e00;
+ font-size : 12px;
+ margin : 0px
+}
+
+div.newsdiv {
+ margin-left : 220px;
+ margin-right : 180px;
+ margin-top : 10px;
+ margin-bottom : 20px;
+ text-align : justify
+}
+
+div.newsdiv h1 {
+ font-weight : bold;
+ font-size : 14px;
+ margin : 0px
+}
+
+div.newsdiv h2 {
+ font-weight : normal;
+ font-size : 12px;
+ margin : 0px
+}
+
+div.newsdiv h3 {
+ font-weight : normal;
+ font-size : 12px;
+ margin-bottom : 20px
+}
+
+div.objdiv {
+ margin-left : 220px;
+ margin-right : 20px;
+ margin-top : 10px;
+ margin-bottom : 20px
+}
+
+h1.newstitle {
+ text-align : left;
+ font-size : 14px;
+ margin : 0px 0px 0px 0px;
+ color : black
+}
+
+div.titlediv {
+ border-top : solid #cac2a8 2px;
+ margin-top : 20px;
+ background-color : #eeeae6;
+ padding-left : 10px;
+ font-size : 11px
+}
+
+div.bodydiv {
+ border : solid #9e9784 1px;
+ padding-left : 10px;
+ padding-right : 10px;
+ padding-top : 10px;
+ padding-bottom : 5px;
+ margin-top : 2px;
+ text-align : justify
+}
+
+div.comments {
+ padding : 10px;
+ border-top : solid 2px #d37537;
+ border-bottom : solid 2px #d37537;
+ margin-top : 20px;
+ margin-bottom : 10px;
+ background-color : #cacaca;
+ font-size : 12px;
+ line-height : 1.3em
+}
+
+p.commentsbody {
+ border-left-style : solid;
+ border-width : 1px;
+ border-color : rgb(0, 0, 0);
+ padding-left : 10px;
+ text-align : justify;
+ margin-right : 20px
+}
+
+div.commentsreply {
+ margin-left : 220px;
+ text-align : center;
+ margin-top : 50px
+}
+
+ul.commentsul {
+ list-style-type : none;
+ margin-bottom : 10px;
+ margin-left : 1.25em;
+ padding-left : 0em;
+ border-left : 1px solid black
+}
+
+ul.commentsli {
+ margin : 10px
+}
+
+div.comments li {
+ margin-top : 20px;
+ margin-left : 2px
+}
+
+div.comments h1 {
+ font-size : 12px;
+ color : black;
+ margin : 0px 20px 3px 0px;
+ background-color : rgb(226, 226, 226);
+ padding-left : 1px;
+ font-weight : none
+}
+
+div.articlediv {
+ padding-left : 20px;
+ padding-right : 20px;
+ padding-top : 10px;
+ padding-bottom : 20px;
+ margin-right : 10px;
+ margin-left : 220px;
+ border : solid 1px black;
+ margin-top : 10px;
+ text-align : justify;
+ background-color : #E2E2E2
+}
+
+img {
+ border : 0px
+}
+
+div.sectionimg {
+ float : left;
+ margin-right : 10px;
+ margin-top : 5px
+}
+
+p.hautpage {
+ margin-top : 20px;
+ margin-bottom : 20px;
+ margin-left : 10px
+}
+
+div.leftcol {
+ width : 202px;
+ width : 202px;
+ float : left;
+ padding : 0px
+}
+
+div.logodiv {
+ border-right : 1px black solid;
+ border-bottom : 1px black solid;
+ padding : 0px;
+ line-height : 0px
+}
+
+div.loginbox {
+ margin-left : 4px;
+ border : solid #a59f8b 1px;
+ margin-top : 2px;
+ padding : 5px;
+ background-color : #fff2e8;
+ font-size : 10px
+}
+
+div.loginbox p {
+ margin : 0px;
+ padding : 0px
+}
+
+div.loginbox ul {
+ margin-left : 10px;
+ margin-top : 0px;
+ margin-bottom : 0px;
+ padding : 0px;
+ list-style-type : none
+}
+
+div.loginbox h1 {
+ text-transform : uppercase;
+ font-weight : bold;
+ color : #ed7e00;
+ font-size : 10px;
+ margin : 0px
+}
+
+div.loginbox h2 {
+ font-weight : bold;
+ font-size : 12px;
+ margin : 0px
+}
+
+div.loginbox h3 {
+ margin-top : 0px;
+ margin-bottom : 5px;
+ font-size : 12px
+}
+
+div.polldivtitle {
+ margin-bottom : 1px;
+ background-color : #cac2a8;
+ margin-left : 4px;
+ margin-top : 15px;
+ padding-left : 5px;
+ font-size : 10px;
+ border-top : solid #a59f8b 1px;
+ border-bottom : solid #a59f8b 1px;
+ text-transform : uppercase
+}
+
+div.polldiv {
+ margin-left : 4px;
+ border : 1px #a59f8b solid;
+ margin-top : 0px;
+ padding : 5px;
+ background : #fff2e8
+}
+
+div.polldiv p {
+ margin : 5px;
+ padding : 0px
+}
+
+div.polldiv ul {
+ margin-left : 5px;
+ margin-top : 0px;
+ margin-bottom : 10px;
+ padding : 0px;
+ list-style-type : none
+}
+
+div.otherboxtitle {
+ margin-bottom : 2px;
+ background-color : #e3dabc;
+ margin-left : 4px;
+ margin-top : 15px;
+ padding-left : 5px;
+ padding-top : 2px;
+ font-size : 11px;
+ border-top : solid #777364 1px;
+ border-bottom : solid #777364 1px;
+ text-transform : uppercase;
+ font-weight : bold
+}
+
+div.otherbox {
+ margin-left : 4px;
+ border : 1px #a59f8b solid;
+ margin-top : 0px;
+ padding : 5px;
+ text-align : justify;
+ background : #fff2e8;
+ font-size : 10px
+}
+
+div.otherbox h1 {
+ text-transform : uppercase;
+ font-weight : bold;
+ color : #ed7e00;
+ font-size : 10px;
+ margin : 0px
+}
+
+div.otherbox h2 {
+ font-weight : bold;
+ font-size : 11px;
+ margin : 0px
+}
+
+div.otherbox p {
+ margin-top : 5px;
+ margin-bottom : 10px
+}
+
+div.rightlogo {
+ width : 90px;
+ float : right;
+ margin-right : 0px;
+ padding-top : 0px;
+ padding-left : 0px;
+ padding-bottom : 0px
+}
+
+div.centraldiv {
+ margin-left : 220px;
+ margin-right : 10px;
+ margin-bottom : 20px;
+ margin-top : 10px
+}
+
+div.centraldiv h1 {
+ font-weight : bold;
+ font-size : 14px;
+ margin : 0px
+}
+
+div.centraldiv h2 {
+ font-weight : normal;
+ font-size : 12px;
+ margin : 0px
+}
+
+div.centraldiv h3 {
+ font-weight : normal;
+ font-size : 12px;
+ margin-bottom : 20px
+}
+
+div.centralinfo {
+ position : relative;
+ height : 160px
+}
+
+div.lefttopbox {
+ position : relative;
+ padding-left : 5px;
+ padding-right : 5px;
+ padding-top : 5px;
+ border : 1px #a59f8b solid;
+ text-align : justify;
+ background : #fff2e8;
+ font-size : 12px;
+ width : 47%;
+ float : left
+}
+
+div.lefttopbox p {
+ margin-top : 5px;
+ margin-bottom : 10px
+}
+
+div.lefttopbox h1 {
+ font-size : 13px;
+ font-weight : bold;
+ margin : 0px;
+ text-align : right
+}
+
+div.lefttopbox h2 {
+ text-transform : uppercase;
+ font-weight : bold;
+ color : #ed7e00;
+ font-size : 10px;
+ margin : 0px
+}
+
+div.lefttopbox h3 {
+ font-weight : bold;
+ font-size : 12px;
+ margin : 0px
+}
+
+div.righttopbox {
+ position : relative;
+ border : 1px #a59f8b solid;
+ background : white;
+ padding : 5px;
+ text-align : justify;
+ font-size : 12px;
+ width : 47%;
+ float : right
+}
+
+div.righttopbox h1 {
+ text-transform : uppercase;
+ font-weight : bold;
+ color : #ed7e00;
+ font-size : 10px;
+ margin : 0px
+}
+
+div.righttopbox h2 {
+ font-weight : bold;
+ font-size : 12px;
+ margin : 0px
+}
+
+div.boardindex {
+ text-align : justify;
+ font-size : 11px;
+ padding : 10px;
+ margin-left : 20px;
+ margin-right : 20px
+}
+
+a.boardindex:link, a.boardindex:visited, a.boardindex:active {
+ text-decoration : none;
+ color : red
+}
+
+div.boardleftmsg {
+ float : left;
+ margin-top : 3px
+}
+
+div.boardrightmsg {
+ margin-left : 130px;
+ margin-top : 3px;
+ padding-left : 5px
+}
+
+div.journalbody {
+ margin-left : 40px;
+ margin-top : 40px
+}
+
+div.journalbody h1 {
+ font-size : 15px;
+ font-weight : bold
+}
+
+div.journalbody p {
+ margin-bottom : 20px
+}
+
+.formulaire {
+ border : solid 1px black;
+ font-size : 12px;
+ background-color : #eef;
+ color : #000000
+}
+
+.newcomments {
+ color : red;
+ font-weight : bold
+}
+
+div.commentsreplythanks {
+ margin-left : 100px;
+ margin-top : 50px;
+ margin-right : 100px;
+ background-color : #eee;
+ border : black solid 1px;
+ padding : 10px
+}
+
+div.archivediv {
+ margin-right : 20px
+}
+
+.archivedate {
+ color : #f30
+}
+
+.archivelink {
+ font-size : 14px;
+ font-weight : bold;
+ text-decoration : underline
+}OK
diff --git a/tests/test0-main.c b/tests/test0-main.c
new file mode 100644
index 0000000..ee6cf72
--- /dev/null
+++ b/tests/test0-main.c
@@ -0,0 +1,215 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include "stdio.h"
+#include "cr-parser-input.h"
+#include "string.h"
+
+/**
+ *@file
+ *Some test facilities for the #CRInput class.
+ */
+
+/**
+ *The options data structure.
+ *The variable of this data structure are set
+ *during the parsing the command line by the
+ *parse_command_line() function.
+ */
+struct Options
+{
+ gboolean display_help ;
+ gboolean display_about ;
+ gchar ** files_list ;
+};
+
+
+/**
+ *Displays the usage of the test
+ *facility.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_help (int a_argc, char ** a_argv)
+{
+ g_print ("\n\n") ;
+ g_print ("usage: %s <file-to-parse>\n", a_argv[0]) ;
+ g_print ("\t <file-to-parse>: the file to parse\n") ;
+ g_print ("\n\n") ;
+ g_print ("This test just reads the file byte per byte\nand sends each byte to stdout\n") ;
+ g_print ("\n\n") ;
+}
+
+/**
+ *Displays the about text.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_about (int a_argc, char ** a_argv)
+{
+ g_print ("\n\n") ;
+ g_print ("%s is a libcroco CRInput class test program.\n", a_argv[0]) ;
+ g_print ("It should run on GNU compliants systems.\n") ;
+ g_print ("\n\n") ;
+ g_print ("Initial author: Dodji Seketeli <dodji@seketeli.org>.\n") ;
+ g_print ("\n\n") ;
+}
+
+/**
+ *Parses the command line and updates an abstract "options" data structure.
+ *@param a_argc the argc variable passed to the main function by the OS.
+ *@param a_argv the argv variable passed to the main function by the OS.
+ *@param a_options out parameter. The abstraction of the parsed the options.
+ */
+void
+parse_command_line (int a_argc, char **a_argv,
+ struct Options *a_options)
+{
+ int i= 0 ;
+
+ g_return_if_fail (a_options) ;
+
+ memset (a_options, 0, sizeof (struct Options)) ;
+
+ for (i = 1 ; i < a_argc ; i++)
+ {
+ if (a_argv[i][0] != '-') break ;
+
+ if (!strcmp (a_argv[i], "-h") || !strcmp (a_argv[i], "--help"))
+ {
+ a_options->display_help = TRUE ;
+ }
+ if (!strcmp (a_argv[i], "--about"))
+ {
+ a_options->display_about = TRUE ;
+ }
+ }
+
+ if (i >= a_argc)
+ {
+ /*No file parameter where given*/
+ a_options->files_list = NULL ;
+ }
+ else
+ {
+ a_options->files_list = &a_argv[i] ;
+ }
+}
+
+
+/**
+ *The test of the cr_input_read_byte() method.
+ *Reads the each byte of a_file_uri using the
+ *cr_input_read_byte() method. Each byte is send to
+ *stdout.
+ *@param a_file_uri the file to read.
+ *@return CR_OK upon successfull completion of the
+ *function, an error code otherwise.
+ */
+enum CRStatus
+test_cr_input_read_byte (guchar * a_file_uri)
+{
+ enum CRStatus status = CR_OK ;
+ CRInput * input = NULL ;
+ guchar byte = 0 ;
+ guint c = 0 ;
+
+ g_return_val_if_fail (a_file_uri, CR_BAD_PARAM_ERROR) ;
+
+ input =
+ cr_input_new_from_uri (a_file_uri, CR_UTF_8) ;
+
+ if (!input)
+ {
+ cr_utils_trace_debug ("Input Stream creation failed.") ;
+ return CR_ERROR ;
+ }
+
+ for (status = CR_OK;
+ status == CR_OK ;)
+ {
+ status = cr_input_read_byte (input, &byte) ;
+
+ if (status == CR_OK)
+ {
+ c = byte ;
+ printf ("%d", c) ;
+ fflush (stdout) ;
+ }
+ }
+
+
+
+ if (status == CR_END_OF_INPUT_ERROR)
+ {
+ status = CR_OK ;
+ }
+
+ cr_input_destroy (input) ;
+ input = NULL ;
+
+ return status ;
+}
+
+
+/**
+ *The entry point of the testing routine.
+ */
+int
+main (int argc, char ** argv)
+{
+ struct Options options ;
+
+ parse_command_line (argc, argv, &options) ;
+
+ if (options.display_help == TRUE)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.display_about == TRUE)
+ {
+ display_about (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.files_list == NULL)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ test_cr_input_read_byte (options.files_list[0]) ;
+
+ return 0 ;
+}
diff --git a/tests/test1-main.c b/tests/test1-main.c
new file mode 100644
index 0000000..6f8c92b
--- /dev/null
+++ b/tests/test1-main.c
@@ -0,0 +1,211 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include "stdio.h"
+#include "cr-parser-input.h"
+#include "string.h"
+
+/**
+ *@file
+ *Some test facilities for the #CRInput class.
+ */
+
+/**
+ *The options data structure.
+ *The variable of this data structure are set
+ *during the parsing the command line by the
+ *parse_command_line() function.
+ */
+struct Options
+{
+ gboolean display_help ;
+ gboolean display_about ;
+ gchar ** files_list ;
+};
+
+
+/**
+ *Displays the usage of the test
+ *facility.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_help (int a_argc, char ** a_argv)
+{
+ g_print ("\n\n") ;
+ g_print ("usage: %s <file-to-parse>\n", a_argv[0]) ;
+ g_print ("\t <file-to-parse>: the file to parse\n") ;
+ g_print ("\n\n") ;
+ g_print ("This test just reads the file character per character\nand sends each character to stdout\n") ;
+ g_print ("\n\n") ;
+}
+
+/**
+ *Displays the about text.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_about (int a_argc, char ** a_argv)
+{
+ g_print ("\n\n") ;
+ g_print ("%s is a libcroco CRInput class test program.\n", a_argv[0]) ;
+ g_print ("It should run on GNU compliants systems.\n") ;
+ g_print ("\n\n") ;
+ g_print ("Initial author: Dodji Seketeli <dodji@seketeli.org>.\n") ;
+ g_print ("\n\n") ;
+}
+
+/**
+ *Parses the command line and updates an abstract "options" data structure.
+ *@param a_argc the argc variable passed to the main function by the OS.
+ *@param a_argv the argv variable passed to the main function by the OS.
+ *@param a_options out parameter. The abstraction of the parsed the options.
+ */
+void
+parse_command_line (int a_argc, char **a_argv,
+ struct Options *a_options)
+{
+ int i= 0 ;
+
+ g_return_if_fail (a_options) ;
+
+ memset (a_options, 0, sizeof (struct Options)) ;
+
+ for (i = 1 ; i < a_argc ; i++)
+ {
+ if (a_argv[i][0] != '-') break ;
+
+ if (!strcmp (a_argv[i], "-h") || !strcmp (a_argv[i], "--help"))
+ {
+ a_options->display_help = TRUE ;
+ }
+ if (!strcmp (a_argv[i], "--about"))
+ {
+ a_options->display_about = TRUE ;
+ }
+ }
+
+ if (i >= a_argc)
+ {
+ /*No file parameter where given*/
+ a_options->files_list = NULL ;
+ }
+ else
+ {
+ a_options->files_list = &a_argv[i] ;
+ }
+}
+
+
+/**
+ *The test of the cr_input_read_byte() method.
+ *Reads the each byte of a_file_uri using the
+ *cr_input_read_byte() method. Each byte is send to
+ *stdout.
+ *@param a_file_uri the file to read.
+ *@return CR_OK upon successfull completion of the
+ *function, an error code otherwise.
+ */
+enum CRStatus
+test_cr_input_read_char (guchar * a_file_uri)
+{
+ enum CRStatus status = CR_OK ;
+ CRInput * input = NULL ;
+ guint32 c = 0 ;
+
+ g_return_val_if_fail (a_file_uri, CR_BAD_PARAM_ERROR) ;
+
+ input =
+ cr_input_new_from_uri (a_file_uri, CR_UTF_8) ;
+
+ if (!input)
+ {
+ cr_utils_trace_debug ("Input Stream creation failed.") ;
+ return CR_ERROR ;
+ }
+
+ for (status = CR_OK;
+ status == CR_OK ;)
+ {
+ status = cr_input_read_char (input, &c) ;
+
+ if (status == CR_OK)
+ {
+ printf ("%c", c) ;
+ fflush (stdout) ;
+ }
+ }
+
+ if (status == CR_END_OF_INPUT_ERROR)
+ {
+ status = CR_OK ;
+ }
+
+ cr_input_destroy (input) ;
+ input = NULL ;
+
+ return status ;
+}
+
+
+/**
+ *The entry point of the testing routine.
+ */
+int
+main (int argc, char ** argv)
+{
+ struct Options options ;
+
+ parse_command_line (argc, argv, &options) ;
+
+ if (options.display_help == TRUE)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.display_about == TRUE)
+ {
+ display_about (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.files_list == NULL)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ test_cr_input_read_char (options.files_list[0]) ;
+
+ return 0 ;
+}
diff --git a/tests/test2-main.c b/tests/test2-main.c
new file mode 100644
index 0000000..50a7d0a
--- /dev/null
+++ b/tests/test2-main.c
@@ -0,0 +1,640 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "cr-test-utils.h"
+#include "cr-parser.h"
+
+
+/**
+ *@file
+ *Some test facilities for the #CRParser class.
+ */
+
+CRDocHandler * gv_test_handler = {0} ;
+
+/**
+ *Displays the usage of the test
+ *facility.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_help (int a_argc, char ** a_argv)
+{
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"usage: %s <file-to-parse>\n", a_argv[0]) ;
+ fprintf (stdout,"\t <file-to-parse>: the file to parse\n") ;
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"Tests the cr_parser_parse () method.\n") ;
+ fprintf (stdout,"Returns OK if the status is CR_OK, KO otherwise\n") ;
+ fprintf (stdout,"\n\n") ;
+}
+
+/**
+ *Displays the about text.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_about (int a_argc, char ** a_argv)
+{
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"%s is a libcroco CRParser class test program.\n", a_argv[0]) ;
+ fprintf (stdout,"It should run on GNU compliants systems.\n") ;
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"Initial author: Dodji Seketeli <dodji@seketeli.org>.\n") ;
+ fprintf (stdout,"\n\n") ;
+}
+
+
+/***************************
+ *Some SAC document handlers
+ *for TEST PURPOSES.
+ ***************************/
+
+static void
+test_start_document (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_document\n") ;
+ fprintf (stdout,"***************\n\n") ;
+}
+
+static void
+test_end_document (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_document\n") ;
+ fprintf (stdout,"***************\n\n") ;
+}
+
+static void
+test_import_style (CRDocHandler *a_handler,
+ GList *a_media_list, GString *a_uri,
+ GString *a_uri_default_ns)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"****************\n") ;
+ fprintf (stdout,"import_style\n") ;
+
+ if (a_media_list)
+ {
+ GList *cur = NULL ;
+
+ fprintf (stdout,"\nmedia list:\n") ;
+ fprintf (stdout,"-------------\n") ;
+
+ for (cur = a_media_list ; cur ; cur = cur->next)
+ {
+ if (cur->data)
+ {
+ guchar *str =
+ g_strndup
+ (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+
+ if (str)
+ {
+ fprintf (stdout,str) ; fprintf (stdout,"\n") ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"\ndefault namespace:\n") ;
+ fprintf (stdout,"--------------------\n") ;
+
+ if (a_uri_default_ns && a_uri_default_ns->str)
+ {
+ guchar * str =
+ g_strndup (a_uri_default_ns->str,
+ a_uri_default_ns->len) ;
+ if (str)
+ {
+ fprintf (stdout,str) ; fprintf (stdout,"\n") ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"******************\n\n") ;
+
+
+}
+
+
+static void
+test_namespace_declaration (CRDocHandler *a_handler,
+ GString *a_prefix,
+ GString *a_uri)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"namespace_declaration:\n") ;
+
+ if (a_prefix && a_prefix->str)
+ {
+ guchar * prefix = NULL ;
+
+ prefix = g_strndup (a_prefix->str, a_prefix->len) ;
+
+ if (prefix)
+ {
+ fprintf (stdout,"prefix: %s\n", prefix) ;
+ g_free (prefix) ;
+ prefix = NULL ;
+ }
+ }
+
+ if (a_uri && a_uri->str)
+ {
+ guchar *uri = NULL ;
+
+ uri = g_strndup (a_uri->str, a_uri->len) ;
+
+ if (uri)
+ {
+ fprintf (stdout,"uri: %s\n", uri) ;
+ g_free (uri) ;
+ uri = NULL ;
+ }
+ }
+ fprintf (stdout,"\n") ;
+
+ fprintf (stdout,"***************\n\n") ;
+
+
+}
+
+
+static void
+test_comment (CRDocHandler *a_handler,
+ GString *a_comment)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"comment:\n") ;
+
+ if (a_comment && a_comment->str)
+ {
+ guchar *comment = NULL ;
+
+ comment = g_strndup (a_comment->str, a_comment->len) ;
+
+ if (comment)
+ {
+ fprintf (stdout,"\n/*----------------------\n") ;
+ fprintf (stdout,"%s\n", comment) ;
+ fprintf (stdout,"-------------------------*/\n") ;
+
+ g_free (comment) ;
+ comment = NULL ;
+ }
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+
+static void
+test_start_selector (CRDocHandler *a_handler,
+ CRSelector *a_selector_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_selector\n") ;
+
+ if (a_selector_list)
+ {
+ cr_selector_dump (a_selector_list, stdout) ;
+ fprintf (stdout, "\n") ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_end_selector (CRDocHandler *a_handler,
+ CRSelector *a_selector_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_selector\n") ;
+
+ if (a_selector_list)
+ {
+ cr_selector_dump (a_selector_list, stdout) ;
+ fprintf (stdout,"\n") ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_property (CRDocHandler *a_handler, GString *a_name, CRTerm *a_expr)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"property\n") ;
+
+ if (a_name && a_name->str)
+ {
+ guchar *name = g_strndup (a_name->str, a_name->len) ;
+
+ if (name)
+ {
+ fprintf (stdout,name) ;
+ }
+
+ if (a_expr)
+ {
+ fprintf (stdout,": ") ;
+ cr_term_dump (a_expr, stdout) ;
+ }
+
+ if (name)
+ {
+ g_free (name) ;
+ name = NULL ;
+ }
+
+ fprintf (stdout,"\n") ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_start_font_face (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_font_face\n") ;
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_end_font_face (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_font_face\n") ;
+ fprintf (stdout,"***************\n\n") ;
+
+}
+
+static void
+test_start_media (CRDocHandler *a_handler,
+ GList *a_media_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_media\n") ;
+
+ if (a_media_list)
+ {
+ GList *cur = NULL ;
+ guchar *medium = NULL ;
+
+ for (cur = a_media_list ; cur ; cur = cur->next)
+ {
+ if (cur->data == NULL)
+ continue ;
+
+ medium = g_strndup (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+
+ if (medium == NULL)
+ continue ;
+
+ fprintf (stdout,"medium: %s\n", medium) ;
+
+ if (medium)
+ {
+ g_free (medium) ;
+ medium = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_end_media (CRDocHandler *a_handler,
+ GList *a_media_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_media\n") ;
+
+ if (a_media_list)
+ {
+ GList *cur = NULL ;
+ guchar *medium = NULL ;
+
+ for (cur = a_media_list ; cur ; cur = cur->next)
+ {
+ if (cur->data == NULL)
+ continue ;
+
+ medium = g_strndup (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+
+ if (medium == NULL)
+ continue ;
+
+ fprintf (stdout,"medium: %s\n", medium) ;
+
+ if (medium)
+ {
+ g_free (medium) ;
+ medium = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+static void
+test_start_page (CRDocHandler *a_handler,
+ GString *a_name, GString *a_pseudo_page)
+{
+ guchar *name = NULL, *pseudo_page = NULL ;
+
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_page\n") ;
+
+ if (a_name && a_name->str)
+ {
+ name = g_strndup (a_name->str, a_name->len) ;
+ }
+
+ if (a_pseudo_page && a_pseudo_page->str)
+ {
+ pseudo_page = g_strndup (a_pseudo_page->str,
+ a_pseudo_page->len) ;
+ }
+
+ if (name)
+ {
+ fprintf (stdout,"%s", name) ;
+ }
+
+ if (pseudo_page)
+ {
+ fprintf (stdout,": %s\n", pseudo_page) ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+
+ if (name)
+ {
+ g_free (name) ;
+ name = NULL ;
+ }
+
+ if (pseudo_page)
+ {
+ g_free (pseudo_page) ;
+ pseudo_page = NULL ;
+ }
+}
+
+static void
+test_end_page (CRDocHandler *a_handler,
+ GString *a_name, GString *a_pseudo_page)
+{
+ guchar *name = NULL, *pseudo_page = NULL ;
+
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_page\n") ;
+
+ if (a_name && a_name->str)
+ {
+ name = g_strndup (a_name->str, a_name->len) ;
+ }
+
+ if (a_pseudo_page && a_pseudo_page->str)
+ {
+ pseudo_page = g_strndup (a_pseudo_page->str,
+ a_pseudo_page->len) ;
+ }
+
+ if (name)
+ {
+ fprintf (stdout,"%s", name) ;
+ }
+
+ if (pseudo_page)
+ {
+ fprintf (stdout,": %s\n", pseudo_page) ;
+
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+
+ if (name)
+ {
+ g_free (name) ;
+ name = NULL ;
+ }
+
+ if (pseudo_page)
+ {
+ g_free (pseudo_page) ;
+ pseudo_page = NULL ;
+ }
+}
+
+
+static void
+test_ignorable_at_rule (CRDocHandler *a_handler,
+ GString *a_name)
+{
+ guchar *name = NULL ;
+
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"*********************\n") ;
+ fprintf (stdout,"ignorable_at_rule\n") ;
+
+ if (a_name && a_name->str)
+ {
+ name = g_strndup (a_name->str, a_name->len) ;
+ }
+
+ if (name)
+ {
+ fprintf (stdout,"%s\n", name) ;
+ }
+
+ fprintf (stdout,"*********************\n\n") ;
+}
+
+
+static void
+init_test_sac_handler (CRDocHandler *a_handler)
+
+{
+ a_handler->start_document = test_start_document ;
+ a_handler->end_document = test_end_document ;
+ a_handler->import_style = test_import_style ;
+ a_handler->namespace_declaration = test_namespace_declaration ;
+ a_handler->comment = test_comment ;
+ a_handler->start_selector = test_start_selector ;
+ a_handler->end_selector = test_end_selector ;
+ a_handler->property = test_property ;
+ a_handler->start_font_face = test_start_font_face ;
+ a_handler->end_font_face = test_end_font_face ;
+ a_handler->start_media = test_start_media ;
+ a_handler->end_media = test_end_media ;
+ a_handler->start_page = test_start_page ;
+ a_handler->end_page = test_end_page ;
+ a_handler->ignorable_at_rule = test_ignorable_at_rule ;
+}
+
+/***************************
+ *END of TEST SAC document
+ *handlers.
+ ***************************/
+
+
+/**
+ *The test of the cr_input_read_byte() method.
+ *Reads the each byte of a_file_uri using the
+ *cr_input_read_byte() method. Each byte is send to
+ *stdout.
+ *@param a_file_uri the file to read.
+ *@return CR_OK upon successfull completion of the
+ *function, an error code otherwise.
+ */
+enum CRStatus
+test_cr_parser_parse (guchar * a_file_uri)
+{
+ enum CRStatus status = CR_OK ;
+ CRParser *parser = NULL ;
+
+ g_return_val_if_fail (a_file_uri, CR_BAD_PARAM_ERROR) ;
+
+ gv_test_handler = cr_doc_handler_new () ;
+ init_test_sac_handler (gv_test_handler) ;
+
+ parser = cr_parser_new (NULL) ;
+
+ status = cr_parser_set_sac_handler (parser, gv_test_handler) ;
+
+ if (status != CR_OK)
+ {
+ cr_parser_destroy (parser) ;
+ g_return_val_if_fail (status == CR_OK, CR_ERROR) ;
+ }
+
+ status = cr_parser_parse_from_file (parser, a_file_uri, CR_ASCII) ;
+
+ cr_parser_destroy (parser) ;
+
+ gv_test_handler = NULL ;
+
+ return status ;
+}
+
+
+/**
+ *The entry point of the testing routine.
+ */
+int
+main (int argc, char ** argv)
+{
+ struct Options options ;
+ enum CRStatus status = CR_OK ;
+
+ cr_test_utils_parse_cmd_line (argc, argv, &options) ;
+
+ if (options.display_help == TRUE)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.display_about == TRUE)
+ {
+ display_about (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.files_list == NULL)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ status = test_cr_parser_parse (options.files_list[0]) ;
+
+ if (status == CR_OK)
+ {
+ fprintf (stdout,"OK\n") ;
+ }
+ else
+ {
+ fprintf (stdout,"KO\n") ;
+ }
+
+ return 0 ;
+}
diff --git a/tests/test3-main.c b/tests/test3-main.c
new file mode 100644
index 0000000..19425f3
--- /dev/null
+++ b/tests/test3-main.c
@@ -0,0 +1,643 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "cr-test-utils.h"
+#include "cr-parser.h"
+
+
+/**
+ *@file
+ *Some test facilities for the #CRParser class.
+ */
+
+CRDocHandler * gv_test_handler = {0} ;
+
+/**
+ *Displays the usage of the test
+ *facility.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_help (int a_argc, char ** a_argv)
+{
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"usage: %s <file-to-parse>\n", a_argv[0]) ;
+ fprintf (stdout,"\t <file-to-parse>: the file to parse\n") ;
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"Tests the cr_parser_parse () method.\n") ;
+ fprintf (stdout,"Tests the parsing following the css core syntax\n") ;
+ fprintf (stdout,"Returns OK if the status is CR_OK, KO otherwise\n") ;
+ fprintf (stdout,"\n\n") ;
+}
+
+/**
+ *Displays the about text.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_about (int a_argc, char ** a_argv)
+{
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"%s is a libcroco CRParser class test program.\n", a_argv[0]) ;
+ fprintf (stdout,"It should run on GNU compliants systems.\n") ;
+ fprintf (stdout,"\n\n") ;
+ fprintf (stdout,"Initial author: Dodji Seketeli <dodji@seketeli.org>.\n") ;
+ fprintf (stdout,"\n\n") ;
+}
+
+
+/***************************
+ *Some SAC document handlers
+ *for TEST PURPOSES.
+ ***************************/
+
+static void
+test_start_document (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_document\n") ;
+ fprintf (stdout,"***************\n\n") ;
+}
+
+static void
+test_end_document (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_document\n") ;
+ fprintf (stdout,"***************\n\n") ;
+}
+
+static void
+test_import_style (CRDocHandler *a_handler,
+ GList *a_media_list, GString *a_uri,
+ GString *a_uri_default_ns)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"****************\n") ;
+ fprintf (stdout,"import_style\n") ;
+
+ if (a_media_list)
+ {
+ GList *cur = NULL ;
+
+ fprintf (stdout,"\nmedia list:\n") ;
+ fprintf (stdout,"-------------\n") ;
+
+ for (cur = a_media_list ; cur ; cur = cur->next)
+ {
+ if (cur->data)
+ {
+ guchar *str =
+ g_strndup
+ (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+
+ if (str)
+ {
+ fprintf (stdout,str) ; fprintf (stdout,"\n") ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"\ndefault namespace:\n") ;
+ fprintf (stdout,"--------------------\n") ;
+
+ if (a_uri_default_ns && a_uri_default_ns->str)
+ {
+ guchar * str =
+ g_strndup (a_uri_default_ns->str,
+ a_uri_default_ns->len) ;
+ if (str)
+ {
+ fprintf (stdout,str) ; fprintf (stdout,"\n") ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"******************\n\n") ;
+
+
+}
+
+
+static void
+test_namespace_declaration (CRDocHandler *a_handler,
+ GString *a_prefix,
+ GString *a_uri)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"namespace_declaration:\n") ;
+
+ if (a_prefix && a_prefix->str)
+ {
+ guchar * prefix = NULL ;
+
+ prefix = g_strndup (a_prefix->str, a_prefix->len) ;
+
+ if (prefix)
+ {
+ fprintf (stdout,"prefix: %s\n", prefix) ;
+ g_free (prefix) ;
+ prefix = NULL ;
+ }
+ }
+
+ if (a_uri && a_uri->str)
+ {
+ guchar *uri = NULL ;
+
+ uri = g_strndup (a_uri->str, a_uri->len) ;
+
+ if (uri)
+ {
+ fprintf (stdout,"uri: %s\n", uri) ;
+ g_free (uri) ;
+ uri = NULL ;
+ }
+ }
+ fprintf (stdout,"\n") ;
+
+ fprintf (stdout,"***************\n\n") ;
+
+
+}
+
+
+static void
+test_comment (CRDocHandler *a_handler,
+ GString *a_comment)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"comment:\n") ;
+
+ if (a_comment && a_comment->str)
+ {
+ guchar *comment = NULL ;
+
+ comment = g_strndup (a_comment->str, a_comment->len) ;
+
+ if (comment)
+ {
+ fprintf (stdout,"\n/*----------------------\n") ;
+ fprintf (stdout,"%s\n", comment) ;
+ fprintf (stdout,"-------------------------*/\n") ;
+
+ g_free (comment) ;
+ comment = NULL ;
+ }
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+
+
+static void
+test_start_selector (CRDocHandler *a_handler,
+ CRSelector *a_selector_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_selector\n") ;
+
+ if (a_selector_list)
+ {
+ cr_selector_dump (a_selector_list, stdout) ;
+ fprintf (stdout,"\n") ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_end_selector (CRDocHandler *a_handler,
+ CRSelector *a_selector_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_selector\n") ;
+
+ if (a_selector_list)
+ {
+ cr_selector_dump (a_selector_list, stdout) ;
+ fprintf (stdout,"\n") ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_property (CRDocHandler *a_handler, GString *a_name, CRTerm *a_expr)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"property\n") ;
+
+ if (a_name && a_name->str)
+ {
+ guchar *name = g_strndup (a_name->str, a_name->len) ;
+
+ if (name)
+ {
+ fprintf (stdout,name) ;
+ }
+
+ if (a_expr)
+ {
+ fprintf (stdout,": ") ;
+ cr_term_dump (a_expr, stdout) ;
+ }
+
+ if (name)
+ {
+ g_free (name) ;
+ name = NULL ;
+ }
+
+ fprintf (stdout,"\n") ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_start_font_face (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_font_face\n") ;
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_end_font_face (CRDocHandler *a_handler)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_font_face\n") ;
+ fprintf (stdout,"***************\n\n") ;
+
+}
+
+static void
+test_start_media (CRDocHandler *a_handler,
+ GList *a_media_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_media\n") ;
+
+ if (a_media_list)
+ {
+ GList *cur = NULL ;
+ guchar *medium = NULL ;
+
+ for (cur = a_media_list ; cur ; cur = cur->next)
+ {
+ if (cur->data == NULL)
+ continue ;
+
+ medium = g_strndup (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+
+ if (medium == NULL)
+ continue ;
+
+ fprintf (stdout,"medium: %s\n", medium) ;
+
+ if (medium)
+ {
+ g_free (medium) ;
+ medium = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+
+static void
+test_end_media (CRDocHandler *a_handler,
+ GList *a_media_list)
+{
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_media\n") ;
+
+ if (a_media_list)
+ {
+ GList *cur = NULL ;
+ guchar *medium = NULL ;
+
+ for (cur = a_media_list ; cur ; cur = cur->next)
+ {
+ if (cur->data == NULL)
+ continue ;
+
+ medium = g_strndup (((GString*)cur->data)->str,
+ ((GString*)cur->data)->len) ;
+
+ if (medium == NULL)
+ continue ;
+
+ fprintf (stdout,"medium: %s\n", medium) ;
+
+ if (medium)
+ {
+ g_free (medium) ;
+ medium = NULL ;
+ }
+ }
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+}
+
+static void
+test_start_page (CRDocHandler *a_handler,
+ GString *a_name, GString *a_pseudo_page)
+{
+ guchar *name = NULL, *pseudo_page = NULL ;
+
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"start_page\n") ;
+
+ if (a_name && a_name->str)
+ {
+ name = g_strndup (a_name->str, a_name->len) ;
+ }
+
+ if (a_pseudo_page && a_pseudo_page->str)
+ {
+ pseudo_page = g_strndup (a_pseudo_page->str,
+ a_pseudo_page->len) ;
+ }
+
+ if (name)
+ {
+ fprintf (stdout,"%s", name) ;
+ }
+
+ if (pseudo_page)
+ {
+ fprintf (stdout,": %s\n", pseudo_page) ;
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+
+ if (name)
+ {
+ g_free (name) ;
+ name = NULL ;
+ }
+
+ if (pseudo_page)
+ {
+ g_free (pseudo_page) ;
+ pseudo_page = NULL ;
+ }
+}
+
+static void
+test_end_page (CRDocHandler *a_handler,
+ GString *a_name, GString *a_pseudo_page)
+{
+ guchar *name = NULL, *pseudo_page = NULL ;
+
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"***************\n") ;
+ fprintf (stdout,"end_page\n") ;
+
+ if (a_name && a_name->str)
+ {
+ name = g_strndup (a_name->str, a_name->len) ;
+ }
+
+ if (a_pseudo_page && a_pseudo_page->str)
+ {
+ pseudo_page = g_strndup (a_pseudo_page->str,
+ a_pseudo_page->len) ;
+ }
+
+ if (name)
+ {
+ fprintf (stdout,"%s", name) ;
+ }
+
+ if (pseudo_page)
+ {
+ fprintf (stdout,": %s\n", pseudo_page) ;
+
+ }
+
+ fprintf (stdout,"***************\n\n") ;
+
+ if (name)
+ {
+ g_free (name) ;
+ name = NULL ;
+ }
+
+ if (pseudo_page)
+ {
+ g_free (pseudo_page) ;
+ pseudo_page = NULL ;
+ }
+}
+
+
+static void
+test_ignorable_at_rule (CRDocHandler *a_handler,
+ GString *a_name)
+{
+ guchar *name = NULL ;
+
+ g_return_if_fail (a_handler) ;
+
+ fprintf (stdout,"*********************\n") ;
+ fprintf (stdout,"ignorable_at_rule\n") ;
+
+ if (a_name && a_name->str)
+ {
+ name = g_strndup (a_name->str, a_name->len) ;
+ }
+
+ if (name)
+ {
+ fprintf (stdout,"%s\n", name) ;
+ }
+
+ fprintf (stdout,"*********************\n\n") ;
+}
+
+
+static void
+init_test_sac_handler (CRDocHandler *a_handler)
+
+{
+ a_handler->start_document = test_start_document ;
+ a_handler->end_document = test_end_document ;
+ a_handler->import_style = test_import_style ;
+ a_handler->namespace_declaration = test_namespace_declaration ;
+ a_handler->comment = test_comment ;
+ a_handler->start_selector = test_start_selector ;
+ a_handler->end_selector = test_end_selector ;
+ a_handler->property = test_property ;
+ a_handler->start_font_face = test_start_font_face ;
+ a_handler->end_font_face = test_end_font_face ;
+ a_handler->start_media = test_start_media ;
+ a_handler->end_media = test_end_media ;
+ a_handler->start_page = test_start_page ;
+ a_handler->end_page = test_end_page ;
+ a_handler->ignorable_at_rule = test_ignorable_at_rule ;
+}
+
+/***************************
+ *END of TEST SAC document
+ *handlers.
+ ***************************/
+
+
+/**
+ *The test of the cr_input_read_byte() method.
+ *Reads the each byte of a_file_uri using the
+ *cr_input_read_byte() method. Each byte is send to
+ *stdout.
+ *@param a_file_uri the file to read.
+ *@return CR_OK upon successfull completion of the
+ *function, an error code otherwise.
+ */
+enum CRStatus
+test_cr_parser_parse (guchar * a_file_uri)
+{
+ enum CRStatus status = CR_OK ;
+ CRParser *parser = NULL ;
+
+ g_return_val_if_fail (a_file_uri, CR_BAD_PARAM_ERROR) ;
+
+ gv_test_handler = cr_doc_handler_new () ;
+ init_test_sac_handler (gv_test_handler) ;
+
+ parser = cr_parser_new (NULL) ;
+
+ status = cr_parser_set_sac_handler (parser, gv_test_handler) ;
+
+ if (status != CR_OK)
+ {
+ cr_parser_destroy (parser) ;
+ g_return_val_if_fail (status == CR_OK, CR_ERROR) ;
+ }
+
+ status = cr_parser_set_use_core_grammar (parser, TRUE) ;
+ status = cr_parser_parse_from_file (parser, a_file_uri, CR_ASCII) ;
+
+ cr_parser_destroy (parser) ;
+
+ gv_test_handler = NULL ;
+
+ return status ;
+}
+
+
+/**
+ *The entry point of the testing routine.
+ */
+int
+main (int argc, char ** argv)
+{
+ struct Options options ;
+ enum CRStatus status = CR_OK ;
+
+ cr_test_utils_parse_cmd_line (argc, argv, &options) ;
+
+ if (options.display_help == TRUE)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.display_about == TRUE)
+ {
+ display_about (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.files_list == NULL)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ status = test_cr_parser_parse (options.files_list[0]) ;
+
+ if (status == CR_OK)
+ {
+ fprintf (stdout,"OK\n") ;
+ }
+ else
+ {
+ fprintf (stdout,"KO\n") ;
+ }
+
+ return 0 ;
+}
diff --git a/tests/test4-main.c b/tests/test4-main.c
new file mode 100644
index 0000000..66df6dc
--- /dev/null
+++ b/tests/test4-main.c
@@ -0,0 +1,154 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ *This file is part of the Croco Library
+ *
+ *The Croco Library 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.
+ *
+ *The Croco 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 General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with The Croco Library;
+ *see the file COPYING. If not, write to
+ *the Free Software Foundation, Inc.,
+ *59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *Copyright 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ */
+
+/*
+ *$Id$
+ */
+
+#include "cr-test-utils.h"
+#include "libcroco.h"
+
+
+/**
+ *@file
+ *Some test facilities for the #CRParser class.
+ */
+
+CRDocHandler * gv_test_handler = {0} ;
+
+/**
+ *Displays the usage of the test
+ *facility.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_help (int a_argc, char ** a_argv)
+{
+ g_print ("\n\n") ;
+ g_print ("usage: %s <file-to-parse>\n", a_argv[0]) ;
+ g_print ("\t <file-to-parse>: the file to parse\n") ;
+ g_print ("\n\n") ;
+ g_print ("Tests the cr_parser_parse () method.\n") ;
+ g_print ("Tests the parsing following the css core syntax\n") ;
+ g_print ("Returns OK if the status is CR_OK, KO otherwise\n") ;
+ g_print ("\n\n") ;
+}
+
+/**
+ *Displays the about text.
+ *@param a_argc the argc variable passed to the main function.
+ *@param a_argv the argv variable passed to the main function.
+ */
+void
+display_about (int a_argc, char ** a_argv)
+{
+ g_print ("\n\n") ;
+ g_print ("%s is a libcroco CROMParser class test program.\n",
+ a_argv[0]) ;
+ g_print ("%s Parses a file and builds a CSS object model",
+ a_argv[0]) ;
+ g_print ("It should run on GNU compliants systems.\n") ;
+ g_print ("\n\n") ;
+ g_print ("Initial author: Dodji Seketeli <dodji@seketeli.org>.\n") ;
+ g_print ("\n\n") ;
+}
+
+
+/**
+ *The test of the cr_input_read_byte() method.
+ *Reads the each byte of a_file_uri using the
+ *cr_input_read_byte() method. Each byte is send to
+ *stdout.
+ *@param a_file_uri the file to read.
+ *@return CR_OK upon successfull completion of the
+ *function, an error code otherwise.
+ */
+enum CRStatus
+test_cr_parser_parse (guchar * a_file_uri)
+{
+ enum CRStatus status = CR_OK ;
+ CROMParser *parser = NULL ;
+ CRStyleSheet *stylesheet = NULL ;
+
+ g_return_val_if_fail (a_file_uri, CR_BAD_PARAM_ERROR) ;
+
+ parser = cr_om_parser_new (NULL) ;
+ status = cr_om_parser_parse_file (parser, a_file_uri, CR_ASCII,
+ &stylesheet) ;
+ if (status == CR_OK && stylesheet)
+ {
+ cr_stylesheet_dump (stylesheet, stdout) ;
+ cr_stylesheet_destroy (stylesheet) ;
+ }
+ cr_om_parser_destroy (parser) ;
+
+ return status ;
+}
+
+
+/**
+ *The entry point of the testing routine.
+ */
+int
+main (int argc, char ** argv)
+{
+ struct Options options ;
+ enum CRStatus status = CR_OK ;
+
+ cr_test_utils_parse_cmd_line (argc, argv, &options) ;
+
+ if (options.display_help == TRUE)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.display_about == TRUE)
+ {
+ display_about (argc, argv) ;
+ return 0 ;
+ }
+
+ if (options.files_list == NULL)
+ {
+ display_help (argc, argv) ;
+ return 0 ;
+ }
+
+ status = test_cr_parser_parse (options.files_list[0]) ;
+
+ if (status == CR_OK)
+ {
+ g_print ("\nOK\n") ;
+ }
+ else
+ {
+ g_print ("\nKO\n") ;
+ }
+
+ return 0 ;
+}
diff --git a/tests/valgrind.log b/tests/valgrind.log
new file mode 100644
index 0000000..7e68e8f
--- /dev/null
+++ b/tests/valgrind.log
@@ -0,0 +1,144 @@
+==31389== valgrind-1.0.4, a memory error detector for x86 GNU/Linux.
+==31389== Copyright (C) 2000-2002, and GNU GPL'd, by Julian Seward.
+==31389== Startup, with flags:
+==31389== --suppressions=/usr/local/lib/valgrind/default.supp
+==31389== -v
+==31389== --num-callers=100
+==31389== --leak-check=yes
+==31389== --show-reachable=yes
+==31389== Reading suppressions file: /usr/local/lib/valgrind/default.supp
+==31389== Reading syms from /home/dodji/dev/libcroco/tests/.libs/test4
+==31389== Reading syms from /lib/ld-2.2.5.so
+==31389== Reading syms from /usr/local/lib/valgrind/valgrind.so
+==31389== Reading syms from /usr/lib/libglib-2.0.so.0.0.6
+==31389== object doesn't have any debug info
+==31389== Reading syms from /usr/local/lib/libcroco.so.0.0.1
+==31389== Reading syms from /lib/i686/libc-2.2.5.so
+==31389== object doesn't have any debug info
+==31389== Estimated CPU clock rate is 364 MHz
+==31389==
+==31389==
+==31389== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+==31389== malloc/free: in use at exit: 38298 bytes in 19 blocks.
+==31389== malloc/free: 2510 allocs, 2491 frees, 125800 bytes allocated.
+==31389==
+==31389== searching for pointers to 19 not-freed blocks.
+==31389== checked 4075548 bytes.
+==31389==
+==31389== definitely lost: 0 bytes in 0 blocks.
+==31389== possibly lost: 0 bytes in 0 blocks.
+==31389== still reachable: 38298 bytes in 19 blocks.
+==31389==
+==31389== 20 bytes in 1 blocks are still reachable in loss record 1 of 6
+==31389== at 0x4003BF5B: calloc (vg_clientfuncs.c:239)
+==31389== by 0x4025FF5D: g_allocator_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40254B16: (within /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40253F7F: g_list_append (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x402BB93D: cr_parser_parse_import (cr-parser.c:3170)
+==31389== by 0x402BD9A2: cr_parser_parse_stylesheet (cr-parser.c:4494)
+==31389== by 0x402BE6BF: cr_parser_parse (cr-parser.c:5086)
+==31389== by 0x402BE8B4: cr_parser_parse_from_file (cr-parser.c:5144)
+==31389== by 0x402C2E74: cr_om_parser_parse_file (cr-om-parser.c:847)
+==31389== by 0x804880E: test_cr_parser_parse (test4-main.c:100)
+==31389== by 0x80488DA: main (test4-main.c:142)
+==31389== by 0x402E1082: __libc_start_main (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x80485F1: cr_om_parser_parse_file (in /home/dodji/dev/libcroco/tests/.libs/test4)
+==31389==
+==31389== 80 bytes in 1 blocks are still reachable in loss record 2 of 6
+==31389== at 0x4003BAB5: malloc (vg_clientfuncs.c:100)
+==31389== by 0x402E1BFA: (within /lib/i686/libc-2.2.5.so)
+==31389== by 0x402E1865: iconv_open (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x402439E3: (within /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40241D2D: g_convert (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x4024221C: g_convert_with_fallback (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40261F26: g_print (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x402BF7EA: cr_statement_dump_charset (cr-statement.c:259)
+==31389== by 0x402C1226: cr_statement_dump (cr-statement.c:1196)
+==31389== by 0x402C14CF: cr_stylesheet_dump (cr-stylesheet.c:74)
+==31389== by 0x804882B: test_cr_parser_parse (test4-main.c:104)
+==31389== by 0x80488DA: main (test4-main.c:142)
+==31389== by 0x402E1082: __libc_start_main (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x80485F1: cr_om_parser_parse_file (in /home/dodji/dev/libcroco/tests/.libs/test4)
+==31389==
+==31389== 208 bytes in 4 blocks are still reachable in loss record 3 of 6
+==31389== at 0x4003BAB5: malloc (vg_clientfuncs.c:100)
+==31389== by 0x4025EAF2: g_mem_chunk_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40271523: g_string_sized_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40271588: g_string_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x402B021D: cr_tknzr_parse_string (cr-tknzr.c:768)
+==31389== by 0x402B44E5: cr_tknzr_get_next_token (cr-tknzr.c:2713)
+==31389== by 0x402B8247: cr_parser_try_to_skip_spaces_and_comments (cr-parser.c:832)
+==31389== by 0x402BB4A7: cr_parser_parse_charset (cr-parser.c:3026)
+==31389== by 0x402BD767: cr_parser_parse_stylesheet (cr-parser.c:4408)
+==31389== by 0x402BE6BF: cr_parser_parse (cr-parser.c:5086)
+==31389== by 0x402BE8B4: cr_parser_parse_from_file (cr-parser.c:5144)
+==31389== by 0x402C2E74: cr_om_parser_parse_file (cr-om-parser.c:847)
+==31389== by 0x804880E: test_cr_parser_parse (test4-main.c:100)
+==31389== by 0x80488DA: main (test4-main.c:142)
+==31389== by 0x402E1082: __libc_start_main (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x80485F1: cr_om_parser_parse_file (in /home/dodji/dev/libcroco/tests/.libs/test4)
+==31389==
+==31389== 230 bytes in 8 blocks are still reachable in loss record 4 of 6
+==31389== at 0x4003BAB5: malloc (vg_clientfuncs.c:100)
+==31389== by 0x4025F739: g_malloc (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x4027842A: g_tree_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x4025EC1E: g_mem_chunk_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40271523: g_string_sized_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40271588: g_string_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x402B021D: cr_tknzr_parse_string (cr-tknzr.c:768)
+==31389== by 0x402B44E5: cr_tknzr_get_next_token (cr-tknzr.c:2713)
+==31389== by 0x402B8247: cr_parser_try_to_skip_spaces_and_comments (cr-parser.c:832)
+==31389== by 0x402BB4A7: cr_parser_parse_charset (cr-parser.c:3026)
+==31389== by 0x402BD767: cr_parser_parse_stylesheet (cr-parser.c:4408)
+==31389== by 0x402BE6BF: cr_parser_parse (cr-parser.c:5086)
+==31389== by 0x402BE8B4: cr_parser_parse_from_file (cr-parser.c:5144)
+==31389== by 0x402C2E74: cr_om_parser_parse_file (cr-om-parser.c:847)
+==31389== by 0x804880E: test_cr_parser_parse (test4-main.c:100)
+==31389== by 0x80488DA: main (test4-main.c:142)
+==31389== by 0x402E1082: __libc_start_main (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x80485F1: cr_om_parser_parse_file (in /home/dodji/dev/libcroco/tests/.libs/test4)
+==31389==
+==31389== 5120 bytes in 4 blocks are still reachable in loss record 5 of 6
+==31389== at 0x4003BAB5: malloc (vg_clientfuncs.c:100)
+==31389== by 0x4025F05F: g_mem_chunk_alloc (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40271457: g_string_sized_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40271588: g_string_new (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x402B021D: cr_tknzr_parse_string (cr-tknzr.c:768)
+==31389== by 0x402B44E5: cr_tknzr_get_next_token (cr-tknzr.c:2713)
+==31389== by 0x402B8247: cr_parser_try_to_skip_spaces_and_comments (cr-parser.c:832)
+==31389== by 0x402BB4A7: cr_parser_parse_charset (cr-parser.c:3026)
+==31389== by 0x402BD767: cr_parser_parse_stylesheet (cr-parser.c:4408)
+==31389== by 0x402BE6BF: cr_parser_parse (cr-parser.c:5086)
+==31389== by 0x402BE8B4: cr_parser_parse_from_file (cr-parser.c:5144)
+==31389== by 0x402C2E74: cr_om_parser_parse_file (cr-om-parser.c:847)
+==31389== by 0x804880E: test_cr_parser_parse (test4-main.c:100)
+==31389== by 0x80488DA: main (test4-main.c:142)
+==31389== by 0x402E1082: __libc_start_main (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x80485F1: cr_om_parser_parse_file (in /home/dodji/dev/libcroco/tests/.libs/test4)
+==31389==
+==31389== 32640 bytes in 1 blocks are still reachable in loss record 6 of 6
+==31389== at 0x4003BAB5: malloc (vg_clientfuncs.c:100)
+==31389== by 0x402E1CFF: (within /lib/i686/libc-2.2.5.so)
+==31389== by 0x402E1865: iconv_open (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x402439E3: (within /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40241D2D: g_convert (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x4024221C: g_convert_with_fallback (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x40261F26: g_print (in /usr/lib/libglib-2.0.so.0.0.6)
+==31389== by 0x402BF7EA: cr_statement_dump_charset (cr-statement.c:259)
+==31389== by 0x402C1226: cr_statement_dump (cr-statement.c:1196)
+==31389== by 0x402C14CF: cr_stylesheet_dump (cr-stylesheet.c:74)
+==31389== by 0x804882B: test_cr_parser_parse (test4-main.c:104)
+==31389== by 0x80488DA: main (test4-main.c:142)
+==31389== by 0x402E1082: __libc_start_main (in /lib/i686/libc-2.2.5.so)
+==31389== by 0x80485F1: cr_om_parser_parse_file (in /home/dodji/dev/libcroco/tests/.libs/test4)
+==31389==
+==31389== LEAK SUMMARY:
+==31389== definitely lost: 0 bytes in 0 blocks.
+==31389== possibly lost: 0 bytes in 0 blocks.
+==31389== still reachable: 38298 bytes in 19 blocks.
+==31389==
+--31389-- lru: 50 epochs, 0 clearings.
+--31389-- translate: new 5784 (81473 -> 1079851), discard 0 (0 -> 0).
+--31389-- dispatch: 2500000 basic blocks, 52/15905 sched events, 10797 tt_fast misses.
+--31389-- reg-alloc: 1906 t-req-spill, 196526+11325 orig+spill uis, 29392 total-reg-r.
+--31389-- sanity: 53 cheap, 3 expensive checks.
diff --git a/tests/vg b/tests/vg
new file mode 100755
index 0000000..c7851b2
--- /dev/null
+++ b/tests/vg
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+OUTPUT_FILE=valgrind.log
+VG=`which valgrind`
+VG_OPTIONS="-v --num-callers=100 --leak-check=yes --show-reachable=yes"
+
+#Some sanity checks
+if test "empty$VG" = "empty" ; then
+ echo "You should install valgrind and set it binary into your"
+ echo "\$PATH env variable"
+ echo "go to http://developer.kde.org/~sewardj/ to dowload valgring"
+ exit
+fi
+
+exec $VG $VG_OPTIONS $@ 2>$OUTPUT_FILE \ No newline at end of file