diff options
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. + @@ -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
+-----------------------------
@@ -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 = @@ -0,0 +1 @@ + @@ -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: @@ -0,0 +1 @@ + @@ -0,0 +1,4 @@ +What is The GNU Croco Project ? +------------------------------ + +Initial Author: Dodji Seketeli. <dodji@seketeli.org>
\ No newline at end of file @@ -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, ¶m) ; + + 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 Binary files differnew file mode 100644 index 0000000..9839108 --- /dev/null +++ b/tests/core.17057 diff --git a/tests/core.17936 b/tests/core.17936 Binary files differnew file mode 100644 index 0000000..a57d90f --- /dev/null +++ b/tests/core.17936 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 |