presage-0.8.8/0000755000175000017500000000000011764714755010177 500000000000000presage-0.8.8/NEWS0000644000175000017500000011677511763441214010621 00000000000000Copyright (C) 2012 Matteo Vescovi ___________________ The Presage project ~~~~~~~~~~~~~~~~~~~ NEWS ---- Presage 0.8.8 ------------- Presage 0.8.8 is now available for download. Presage 0.8.8 allows to enabled multiple instances of the same predictor class at runtime through configuration. Each predictor instance is independently configured to allow greater flexibility. Predictive performance can be more finely tailor to the users' specific needs by tuning the resources and configuration of each predictor. The default configuration has been changed to add a custom user smoothed ngram predictor, which adaptively learns its language model. The user-specific default configuration file location is now ~/.presage/presage.xml (~/.presage.xml is no longer used). The configuration now supports and expands environment variables. Presage 0.8.8 adds support for filters to dictionary predictor, recency predictor, abbreviation expansion predictor, and dejavu predictor. The smoothed n-gram predictor will create and initialize a language model database if it does not already exist. Learning performance of the smoothed n-gram predictor has been improved. A new configuration variable has been added to control context tracking case sensitivity. Presage 0.8.8 fixes a bug that caused learning of spurious text. A bug affecting gprompter when learning is enabled was fixed. A memory allocation bug and a memory leak were fixed in the Notepad++ plugin. Presage 0.8.8 ships with an updated embedded XML configuration parser library and update text editing component. Presage 0.8.8 comes with a number of other enhancements and fixes. Please see the ChangeLog for more details. Presage 0.8.7 released ---------------------- Presage 0.8.7 is now available for download. Presage 0.8.7 now integrates into the Notepad++, a powerful Windows text editor, thanks to the new presage predictive Notepad++ plugin, NppPresage. NppPresage is able to detect a presage installation and dynamically load presage to add predictive text functionality to Notepad++. Presage 0.8.7 comes with improved configuration profile handling on Windows: presage now locates the system profile configuration directory from HKCU/Software/Presage registry key on Windows, and correctly locates the user profile directory. Presage 0.8.7 brings improvements to gprompter, including an updated text editing widget and a new invert colours feature. gprompter and pyprompter also come with new (and somewhat ugly) icons on the GNOME desktop. Presage 0.8.7 comes with a number of other enhancements and fixes. Please see the ChangeLog for more details. Presage 0.8.6 released ---------------------- Presage 0.8.6 is now available for download. Presage 0.8.6 brings improved support for Visual Studio compilers on Windows through the presage C API. Presage 0.8.6 also comes with improvements to the predictive text editor gprompter. Presage 0.8.6 comes with a number of other enhancements and fixes. Please see the ChangeLog for more details. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows (Cygwin and MinGW/MSYS), and MacOS X. If you encounter any issues while building or running presage, please report them to the author. Presage 0.8.5 released ---------------------- Presage 0.8.5 is now available for download. Presage 0.8.5 now offers a new C API to libpresage, in addition to the C++ and Python APIs. gprompter is now written in plain C and uses the new libpresage C API. Presage 0.8.5 brings improvements to the experimental D-BUS service interface and start-stop scripts. A D-BUS python example client is also provided. Presage 0.8.5 comes with a number of other enhancements and fixes. Please see the ChangeLog for more details. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.8.5 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows (Cygwin and MinGW/MSYS), and MacOS X. If you encounter any issues while building or running presage, please report them to the author. Presage 0.8.4 released ---------------------- Presage 0.8.4 is now available for download. Presage 0.8.4 comes with a number of improvements and fixes to its build system. Presage 0.8.4 adds shared library symbol versioning. Symbols exported by libpresage are limited to public API symbols and versioned. Presage 0.8.4 removes its dependency on embedded convenience copy of XML configuration parser library, when a system installed libtinyxml is available. Presage 0.8.4 also provides an experimental DBUS prediction service and Spanish language model generation. Presage 0.8.4 also includes other bug fixes and enhancements. Please see the ChangeLog for more details. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.8.4 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows (Cygwin and MinGW/MSYS), and MacOS X. If you encounter any issues while building or running presage, please report them to the author. Presage 0.8.3 released ---------------------- Presage 0.8.3 is now available for download. Presage 0.8.3 comes with a number of improvements and fixes to its build system. No major features were added in this release. Presage 0.8.3 is a minor mantainance release. Presage 0.8.3 also includes other bug fixes and enhancements. Please see the ChangeLog for more details. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.8.3 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows (Cygwin and MinGW/MSYS), and MacOS X. If you encounter any issues while building or running presage, please report them to the author. Presage 0.8.2 released ---------------------- Presage 0.8.2 is now available for download. Presage 0.8.2 comes with improved gprompter and pypresagemate demo applications. gprompter new features include autopunctuation implementation, support for keyboard accelerators to access menu items, bug fixes, and updates to the text editing component. pypresagemate now supports standard command line parameters. Presage 0.8.2 delivers a number of fixes and improvements to the core predictive engine, such as a fix for a defect in the learning code and the prediction with multimaps. The internal core predictor hierarchy has been refactored and the XML parsing code subsystem updated. Compilations issues on Solaris and various compilation warning have also been fixed. Presage 0.8.2 also includes other bug fixes and enhancements. Please see the ChangeLog for more details. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.8.2 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows (Cygwin and MinGW/MSYS), and MacOS X. If you encounter any issues while building or running presage, please report them to the author. Presage 0.8.1 released ---------------------- Presage 0.8.1 is now available for download. Presage 0.8.1 sports significant performance improvements in its smoothed n-gram predictor. Runtime execution was sped up by approximately a factor of 5 by tuning some expensive SQL queries to the embedded SQLite database. Presage 0.8.1 comes with refactored configuration and profile handling subsystems. Configuration is read from system-level, installation-level, user-level XML profiles and from an optional user-specified profile. Changes to configuration variables made at runtime through the config() API can now be persisted to file by calling the new save_profile() API method. Presage components are also immediately notified of configuration changes and adjust accordingly. Presage 0.8.1 also includes other bug fixes and enhancements. Compilation problems on recent stricter compilers, compilation warnings, and minor memory leaks were fixed in this release. Please see the ChangeLog for more details. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.8.1 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows (Cygwin and MinGW/MSYS), and MacOS X. If you encounter any issues while building or running presage, please report them to the author. Presage 0.8 released ---------------------- Presage 0.8 is now available for download. Presage 0.8 includes two new predictive applications, gprompter and pypresagemate. Gprompter is a cross-platform predictive text editor. Gprompter displays predictions in a contextual pop-up box as each letter is typed. Predictions can be easily selected and inserted in the document. Pypresagemate is a universal predictive text companion. Pypresagemate works alongside any AT-SPI aware application. The Assistive Technology Service Provider Interface (AT-SPI) is a toolkit-neutral way of providing accessibility facilities in applications. Pypresagemate works in the background by tracking what keystrokes are typed and displaying predictions in its window. When a prediction is selected, text is sent to the active application. Presage 0.8 provides a new callback-aware programming interface to make it easier to develop interactive presage applications. Presage applications no longer need to track user interaction by explicitly updating the context. Instead, a callback object decouples the user application from the chosen text buffer (which might be a simple string, a graphical text widget, a file stream, etc.) and frees the caller from having to explicitly notify of any updates to the context. with presage and this allows presage to retrieve contextual information from the application whenever needed. Presage 0.8 also includes other bug fixes and enhancements. Please see the ChangeLog for more details. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.8 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows (Cygwin and MinGW/MSYS), and MacOS X. If you encounter any issues while building or running presage, please report them to the author. Presage 0.7.3 released ---------------------- Presage 0.7.3 is now available for download. Presage 0.7.3 includes the new predictive ARPA plugin. The ARPA plugin enables the use of statistical language modelling data in the ARPA N-gram format. In the ARPA format each N-gram is stored with its discounted log probability and its Katz backoff weight. Probabilities are estimated by applying Katz backoff smoothing to the maximum likelihood estimates based on n-gram counts data. Presage 0.7.3 also provides (in a separate tarball) an extensive language model generated from the British National Corpus (BNC) containing 20.001 unigrams, 517.537 bigrams, and 1.648.226 trigrams. This language model was constructed by computing the smoothed Katz backoff trigram model using the CMU-Cambridge Statistical Language Modeling toolkit. Presage 0.7.3 also includes other bug fixes and enhancements. Please see the ChangeLog for more details. Presage 0.7.3 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.7.3 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows XP/Cygwin, and Windows XP/MinGW/MSYS. If you encounter any issues while building or running presage, please report them to the author. Presage 0.7.2 released ---------------------- Presage 0.7.2 is now available for download. Presage 0.7.2 adds support for predictive plugins filters and a new predict method returning an ordered multimap of probability-token pairs. The filters feature enables lookahead prediction. Presage 0.7.2 incorporates a number of bug fixes, such as handling of utf-8 encoded text, initialization bug in presage demo program, build problems fixes in gpresagemate. Prompter comes with user interface improvements, such as text size controls. Presage 0.7.2 also includes other bug fixes and enhancements. Please see the ChangeLog for more details. Presage 0.7.2 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage should follow the (easy) steps needed to build presage, as detailed in the README file and in the documentation available in the doc/ directory. Presage 0.7.2 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows XP/Cygwin, and Windows XP/MinGW/MSYS. If you encounter any issues while building or running presage, please report it to the author. As always, there is still a lot more work to be done. Currently, the installed presage system is trained on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins are also in the works, which will take advantage of the multiple predictive source architecture. Please refer to our TODO list for details on what needs to be done. Presage 0.7.1 released ---------------------- Presage 0.7.1 is now available for download. Presage 0.7.1 is able to learn "on the fly" from the context and the text currently being entered. The smoothed n-gram predictive plugin dynamically learns from the current context, while generating new predictions. An n-gram count consistency bug triggered by the dynamic learning capability of the smoothed n-gram predictive plugin has been fixed in this release. Presage 0.7.1 incorporates a number of bug fixes: completion validation routine case sensitiveness, fixed various compilation warnings, prompter UTF8 encoding. Presage 0.7.1 also includes other bug fixes and enhancements. Please see the ChangeLog for more details. Presage 0.7.1 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage will need to follow the (easy) steps required to build presage on their machine, as detailed in the README file. Please note that SQLite is required to build presage. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Presage 0.7.1 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows XP/Cygwin, and Windows XP/MinGW/MSYS. If you encounter any issues while building or running presage, please report it to the author. As always, there is still a lot more work to be done. Currently, the installed presage system is trained on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins are also in the works, which will take advantage of the multiple predictive source architecture. Please refer to our TODO list for details on what needs to be done. Presage 0.7 released -------------------- Presage 0.7 is now available for download. Presage 0.7 is the first release that uses the new project name. Presage was formerly known as Soothsayer. The Soothsayer project was renamed to Presage in order to avoid clashes with a similarly named commercial software product. Presage 0.7 is now able to learn "on the fly" from the context and the text currently being entered. The smoothed n-gram predictive plugin dynamically learns from the current context, while generating new predictions. Presage 0.7 also includes a new dejavu plugin, which reproduces previously entered text sequences once its memory trigger is activated. Presage 0.7 provides better predictions by incrementally increasing depth of prediction generation while previous predictions did not match desired token. Presage 0.7 delivers an improved Python GUI demo application, Prompter: * added prompt functionality, which allows user to request a new prediction on-demand * added function keys mode, which allows user to select desired prediction by pressing the corresponding function key * added ability to toggle autopunctuation functionality * added toolbar (can be hidden/shown) * added ability to toggle learning mode on or off * added edit menu with cut, copy, paste, undo, redo, select all operations * improved editor layout * added modern about dialog box Presage 0.7 incorporates several bug fixes to the context changes detection code, including fixing bugs triggered by empty string updates and bugs where multiple separators triggered spurious context changes. Presage 0.7 includes a new GTK application which aims to augment any other application with presage predictive functionality. Presage 0.7 also includes bug fixes and improvements to the build framework. See ChangeLog for more details. Presage 0.7 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Presage will need to follow the (easy) steps required to build presage on their machine, as detailed in the README file. Please note that SQLite is required to build presage. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Presage 0.7 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows XP/Cygwin, and Windows XP/MinGW/MSYS. If you encounter any issues while building or running presage, please report it to the author. As always, there is still a lot more work to be done. Currently, the installed presage system is trained on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins are also in the works, which will take advantage of the multiple predictive source architecture. Please refer to our TODO list for details on what needs to be done. Soothsayer 0.6.3 released ------------------------- Soothsayer 0.6.3 is now available for download. Soothsayer 0.6.3 comes with a number of packaging and distribution improvements. The build system has received minor fixes and configurability enhancements. Soothsayer 0.6.3 ships with improved demonstration programs. The existing C++ demonstration programs have been renamed from from capitalized style names to underscore separated style names. Python demonstration programs incorporate various improvements, including new command line switches and manual pages. Soothsayer 0.6.3 adds improved UTF-8 support. Distributed text resources used to generate sample statistical data are now UTF-8 encoded. Soothsayer 0.6.3 also includes a few bug fixes and documentation updates. See ChangeLog for more details. Soothsayer 0.6.3 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Soothsayer will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Soothsayer 0.6.3 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows XP/Cygwin, and Windows XP/MinGW/MSYS. If you encounter any issues while building or running soothsayer, please report it to the author. As always, there is still a lot more work to be done. Currently, the installed soothsayer system is trained on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins are also in the works, which will take advantage of the multiple predictive source architecture. Please refer to our TODO list for details on what needs to be done. Soothsayer 0.6.2 released ------------------------- Soothsayer 0.6.2 is now available for download. Soothsayer 0.6.2 comes with a number of new features. Most notably, a new statistical predictive plugin, based on recency promotion, is available. The new recency plugin generates predictions by assigning exponentially decaying probability values to previously encountered word tokens, thereby promoting context recency. Soothsayer 0.6.2 also ships a brand new simple GUI demonstration program, prompter. Prompter is a soothsayer-enabled text editor. Prompter displays predictions generated by soothsayer through a pop-up autocompletion list. Prompter also provides an autopunctuation feature that saves key pressing by intelligently handling punctuation and whitespace. Prompter is a Python application (wxPython) and uses soothsayer's python binding. Soothsayer 0.6.2 adds native Windows support by supporting the MinGW/MSYS platform. It is now possible to build soothsayer in native Win32 mode. Detailed instructions to build soothsayer on MinGW/MSYS are included in the doc/ directory. Soothsayer 0.6.2 includes enhancements to the build system, a restructured soothsayer exception hierarchy, additional range checking in core classes, and improved logging subsystem. Soothsayer 0.6.2 also includes a number of bug fixes. See ChangeLog for more details. Soothsayer 0.6.2 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Soothsayer will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Soothsayer 0.6.2 has been built and tested on various Linux platforms (including 32-bit and 64-bit architectures), Solaris 10, Windows XP/Cygwin, and Windows XP/MinGW/MSYS. If you encounter any issues while building or running soothsayer, please report it to the author. As always, there is still a lot more work to be done. Currently, the installed soothsayer system is trained on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins are also in the works, which will take advantage of the multiple predictive source architecture. Please refer to our TODO list for details on what needs to be done. Soothsayer 0.6.1 released ------------------------- Soothsayer 0.6.1 is now available for download. Soothsayer 0.6.1 includes a number of under-the-hood changes. The focus of this release has been on refactoring, restructuring, and cleaning up, rather than adding new functionality. The source directory layout was changed to better reflect the logical structure. Improvements were made to the configuration system and the logging subsystem, which underwent a complete overhaul and rewrite. Soothsayer 0.6.1 ships with man pages for the tools and demo programs. This release also includes bug fixes and improvements to the build system. All GCC generated compilation warnings were fixed. Library dependencies have been cleaned up. Soothsayer 0.6.1 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Soothsayer will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Soothsayer 0.6.1 has been built and tested on various Linux platforms (including 64 bit architectures) and Windows XP + Cygwin platform. If you encounter any issues while building or running soothsayer, please report it to the author. As always, there is still a lot of work to be done. Currently, Soothsayer is trained on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins will also be added to take advantage of the multiple predictive source architecture. Please refer to our TODO list for details on what needs to be done. Soothsayer 0.6 released ----------------------- Soothsayer 0.6 is now available for download. Soothsayer 0.6 includes a new Python binding module, which enables Python applications to natively call into soothsayer. Soothsayer 0.6 has also been ported to Solaris 10 platform, and built with Sun Studio 10 and 11 compilers. This release also includes bug fixes and improvements to the build system. Library dependencies have been cleaned up. Shared libraries are now built on all supported platforms, including Windows/Cygwin targets. Soothsayer 0.6 is a beta release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Soothsayer will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Soothsayer 0.6 has been built and tested on various Linux platforms (including 64 bit architectures) and Windows XP + Cygwin platform. If you encounter any issues while building or running soothsayer, please report it to the author. There is still a lot of work to be done. Currently, Soothsayer is training on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins should also be added to take advantage of the multiple predictive source architecture. Please refer to our TODO list for more details on what needs to be done. Soothsayer 0.5 released ----------------------- Soothsayer 0.5 is now available for download. Soothsayer 0.5 includes the new generalized smoothed n-gram statistical predictive plugin, which supports arbitrary order n-grams. Used in combination with the text2ngram tool, statistical predictions can be generated by n-gram language models of arbitrary cardinality. The new generalized smoothed n-gram predictive plugin also uses an improved heuristic to generate initial completion candidates, by using highest order n-gram statistics, and falling back on lower order n-grams if initial completion set is smaller than required. This release also includes notable bug fixes and improvements to soothsayer simulator. A bug in the simulator caused the reported Key Stroke Reduction rate to much much lower than the actual KSR achieved by soothsayer. Soothsayer 0.5 marks a change in project status from alpha to beta. However, it is still to be considered a developer's preview release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Soothsayer will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Soothsayer 0.5 has been built and tested on various Linux platforms (including 64 bit architectures) and Windows XP + Cygwin platform. If you encounter any issues while building or running soothsayer, please report it to the author. There is still a lot of work to be done. Currently, Soothsayer is training on a very small training corpus. Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate statistical predictive resources using the text2ngram tool on a custom training text corpus. New predictive plugins should also be added to take advantage of the multiple predictive source architecture. Please refer to our TODO list for more details on what needs to be done. Soothsayer 0.4 released ----------------------- Soothsayer 0.4 is now available for download. Soothsayer 0.4 includes the new abbreviation expansion predictive plugin. This plugin allows users to specify a file containing a list of abbreviations/expansions pairs. When an abbreviation is entered, the next generated prediction will contain the associated expansion, which is typically a commonly used word or phrase. This release also includes bug fixes and documentation improvements. Soothsayer 0.4 is a developer's preview release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try out Soothsayer will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but be aware that no unit tests will be built nor run when running `make check', unless CPPUnit is installed. Soothsayer 0.4 has been built and tested on various Linux platforms (including 64 bit architectures) and Windows XP + Cygwin platform. If you encounter any issues while building or running soothsayer, please report it to the author. There is still a lot of work to be done. Currently, the build process trains Soothsayer predictive plugin with a very limited training corpus (a single novel). Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate predictive resources using a custom text corpus and the extraction tools provided. Currently, the main predictive plugin is a smoothed uni-bi-tri-gram predictive plugin. The plugin should be extended to be able to support n-grams of any cardinality. More plugins should also be added to take advantage of the multiple predictive source architecture. Please refer to our TODO list for more details on what needs to be done. Soothsayer 0.3 released ----------------------- Soothsayer 0.3 is now available for download. Soothsayer 0.3 adds initial support for simultaneous use of multiple predictive plugins. Multiple predictions combination is carried out according to a meritocracy policy. This release also includes bug fixes, memory leak fixes, and improvements to the demo programs (visual context change cues). Soothsayer 0.3 adds new configuration variables to control its runtime predictive behaviour. Configuration handling has been refactored. Please consult the ChangeLog for more details. Soothsayer 0.3 is a developer's preview release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try Soothsayer out will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but no unit tests will be built when running `make check', unless CPPUnit is installed. Soothsayer 0.3 has been built and tested on various Linux platforms (including 64 bit architectures) and Windows XP + Cygwin platform. If you encounter any issues while building or running soothsayer, please report it to the author. There is still a lot of work to be done. Currently, the build process trains Soothsayer predictive plugin with a very limited training corpus (a single novel). Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate predictive resources using a custom text corpus and the extraction tools provided. Currently, only one predictive plugin is provided, a smoothed n-gram predictive plugin. The plugin should be extended to be able to support n-grams of any cardinality. More plugins should also be added to take advantage of the multiple predictive source architecture. Please refer to our TODO list for more details on what needs to be done. Soothsayer 0.2 released ----------------------- Soothsayer 0.2 is now available for download. Soothsayer 0.2 adds support for SQLite 2.x and SQLite 3.x. The soothsayer build system will autodetect which SQLite version is available and use the most recent version. This release also includes bug fixes and improvements to the command line utilities and demo programs. Please consult the ChangeLog for more details. Soothsayer 0.2 is a developer's preview release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try Soothsayer out will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README file. Please note that SQLite is required to build soothsayer. CPPUnit is optional, but no unit tests will be built when running `make check', unless CPPUnit is installed. Soothsayer 0.2 has been built and tested on various Linux platforms (including 64 bit architectures) and Windows XP + Cygwin platform. If you encounter any issues while building or running soothsayer, please report it to the author. There is still a lot of work to be done. Currently, the build process trains Soothsayer predictive plugin with a very limited training corpus (a single book). Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate predictive resources using a custom text corpus and the extraction tools provided. Currently, only one predictive plugin is provided, a smoothed n-gram predictive plugin. The plugin should be extended to be able to support n-grams of any cardinality. More plugins should also be added to take advantage of the multiple predictive source architecture. There is also more work to be done on various modules, including the combiner module and the configuration module. Please refer to our TODO list for more details on what needs to be done. Soothsayer 0.1.1 released ------------------------- Soothsayer 0.1.1 is now available for download. Soothsayer 0.1.1 fixes a problem that caused build failures in a Windows + Cygwin environment. Soothsayer 0.1.1 is a developer's preview release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try Soothsayer out will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README. Please note that Sqlite is required to build soothsayer. CPPUnit is optional, but no unit tests will be built when running `make test', unless CPPUnit is installed. Soothsayer 0.1.1 has been built and tested on various Linux platforms (including 64 bit architectures) and Windows XP + Cygwin platform. If you encounter any issues while building or running soothsayer, please report it to the author. There is still a lot of work to be done. Currently, the build process trains Soothsayer predictive plugin with a very limited training corpus (a single book). Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate predictive resources using a custom text corpus and the extraction tools provided. Currently, only one predictive plugin is provided, a smoothed n-gram predictive plugin. The plugin should be extended to be able to support n-grams of any cardinality. More plugins should also be added to take advantage of the multiple predictive source architecture. There is also more work to be done on various modules, including the combiner module and the configuration module. Please refer to our TODO file for more information on what needs to be done. Soothsayer 0.1 released ----------------------- I am proud to announce the first ever release of Soothsayer. Soothsayer 0.1 is now available for download. Soothsayer 0.1 is a developer's preview release. This is a source release only. No precompiled packages or installers are provided. Users wishing to try Soothsayer out will need to follow the (easy) steps required to build soothsayer on their machine, as detailed in the README. Please note that Sqlite is required to build soothsayer. CPPUnit is optional, but no unit tests will be built when running `make test', unless CPPUnit is installed. Soothsayer 0.1 has been built and tested on various Linux platforms (including 64 bit architectures). Building on Windows + Cygwin is temporarily broken. If you encounter any issues while building or running soothsayer, please report it to the author. There is still a lot of work to be done. Currently, the build process trains Soothsayer predictive plugin with a very limited training corpus (a single book). Predictive performance can be greatly increased by using a larger training corpus. Users can easily generate predictive resources using a custom text corpus and the extraction tools provided. Currently, only one predictive plugin is provided, a smoothed n-gram predictive plugin. The plugin should be extended to be able to support n-grams of any cardinality. More plugins should also be added to take advantage of the multiple predictive source architecture. There is also more work to be done on various modules, including the combiner module and the configuration module. Please refer to our TODO file for more information on what needs to be done. ########/ Copyright (C) 2008 Matteo Vescovi Soothsayer 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ########\ presage-0.8.8/missing0000755000175000017500000002623311737143301011503 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2009-04-28.21; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; tar*) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar*) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case $firstarg in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case $firstarg in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: presage-0.8.8/AUTHORS0000644000175000017500000000234511737142176011163 00000000000000Copyright (C) 2008 Matteo Vescovi ___________________ The Presage project ~~~~~~~~~~~~~~~~~~~ Presage was written by Matteo Vescovi It is currently maintained by Matteo Vescovi. It is released under the General Public License, version 2. For more information on the GPL licence, please see the COPYING file which should be included with this distribution. Individuals who have contributed code are listed in the THANKS file. ########/ Copyright (C) 2008 Matteo Vescovi Presage 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ########\ presage-0.8.8/INSTALL0000644000175000017500000004027211763437013011141 00000000000000Copyright (C) 2008 Matteo Vescovi ___________________ The Presage Project ~~~~~~~~~~~~~~~~~~~ Welcome to Presage. For installation instructions, please refer to the README file. Enjoy, - Matteo ########/ Copyright (C) 2008 Matteo Vescovi Presage 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ########\ Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. 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, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. 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 you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' 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. Running `configure' might take a while. 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, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. 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. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. 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 can use 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 `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer 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. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' 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. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= 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'. 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. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS 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 machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. 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. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--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. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. presage-0.8.8/FAQ0000644000175000017500000001703511763437013010443 00000000000000Copyright (C) 2008 Matteo Vescovi ___________________ The Presage project ~~~~~~~~~~~~~~~~~~~ Frequently Asked Questions -------------------------- How can I improve presage's predictive performance for user X? == Users' needs vary widly and there is not one sure way to improve predictive performance, but here is how I would approach the problem of configuring presage for a specific user's needs. First of all, let's state our goal in terms of something we can measure. The aim is to tune presage's predictions to minimize the number of keystrokes that a specific user is required to type to produce a given reference text. The reference text could be chosen from a collection of texts that the user has previously written, or it could be a collation of various texts (emails, text files in home directory, etc.). The chosen reference text will serve as the reference benchmark. Once we have a benchmark text, we can measure the effectiveness of the predictive resources used against the benchmark text. Presage provides tools to accomplish to generate custom predictive resources (in particular, language models for the smoothed n-gram predictor): - text2ngram tool generates n-gram language models from a given training text corpora. - presage_simulator tool computes the Keystroke Savings Rate on a benchmark text, given the current predictive resources and configuration in use (i.e. n-gram database, abbreviations, recency, etc.). Ideally, one would collect a vast amount of text that the user has produced and feed this training text to the text2ngram tool to generate a n-gram language model database (1-gram, 2-gram and 3-gram tables seem to work well, but one can also generate higher order n-gram language models and set the SmoothedNgram DELTAS variable value accordingly). Once the ngram language model is generated, its effectiveness can be validated by running the presage_simulator and observing the KSR. KSR's around 80% are very good. Higher values are obviously better. Obviously, the higher n-gram order used in the language model, the higher the risk of overtraining the model and overfitting the training corpora (wikipedia has good articles about machine learning and overfitting). Other things to look at are creating custom abbreviations for the abbreviation expansion plugin, or tweaking the weight DELTAS of the smoothed n-gram predictor, or providing a more suited dictionary file to the dictionary plugin. Regenerating n-gram language model from a representative training text corpus is probably the most effective way to significantly increase predictive performance. The default language model for the English language is generated from single novel "The picture of Dorian Gray" by Oscar Wilde, which might be turn out to be representative of a particular user's writing style or vocabulary. In conclusion, it is likely that the most effective way to achieve good predictive results is to generate predictive resources based on a "good" training corpus of text. All the predictive mechanisms currently used by presage are based on statistical/heuristic methods, so the more representative the resources are, the better the predictive performance will be. There are plans to work on syntactical/semantic predictors (able to take grammar or semantic context information into account), but I just haven't had time to work on those tasks yet. How can I configure presage to predict in a specific natural language? == Presage is designed to provide support for any natural language. One core design feature of presage is the ability to make use of different sources of information and predictive algorithms to generate predictions. The sources of information and predictive algorithms used to generate a prediction are controlled by presage configuration. The default build of presage, for example, is configured to use three predictors: - the smoothed n-gram predictive algorithm with a language model that is generated from a single training text (the novel "The picture of Dorian Gray" by Oscar Wilde) - the abbreviation expansion predictor - the recency predictor The Presage.PredictorRegistry.PREDICTORS configuration variable controls what predictors should be instantiated. The elements nested within the Presage.Predictors element control the configuration of each instance of the predictors. By default, presage currently builds language models for the English, Italian, and Spanish languages. These language models are generated during the build from source and are installed in the share/presage/ directory of your presage installation. In order to switch to a different language, you need to modify the configuration used by presage to suit your needs. You can achieve that by editing your presage.xml configuration file. The configuration file is read from the following locations: 1. /etc/presage.xml if it exists 2. /etc/presage.xml if it exists 3. ~/.presage/presage.xml if it exists ($HOME/.presage/presage.xml on Unix, %USERPROFILE%/.presage/presage.xml on Windows) Configuration values in 3. take priority over configuration values in 2. and 1. You can also modify the configuration programmatically through the Presage::config(...) calls or a variant of the Presage class constructor. The Predictor.SmoothedNgramPredictor.DBFILENAME config variable controls the language model database used by the Smoothed Ngram predictive plugin, i.e.: /home/matt/presage_local_install/share/presage/database_en.db For example, suppose that our goal is to enable support for the German language. In order to achieve that, you will want to modify this variable to point to a German language model. presage provides the tools to generate predictive resources required by the predictors to suit any natural language or specific users' needs. You can generate a German language model database using the text2ngram tool. The text2ngram tool generates n-gram language models from a given corpus of text. Ideally, you would collect a representative set of text (text that the user has produced or text that matches the writing style and context of the user) and then feed that to the text2ngram tool to generate a n-gram database (1-gram, 2-gram and 3-gram tables, but you can also generate higher order n-gram and set the SmoothedNgram DELTAS values accordingly). Obviously, the higher n-gram order used, the higher the risk of overtraining the model and overfitting the training corpus (wikipedia has good articles about machine learning and overfitting). Assuming you have a German training text corpus in a file named training_de.txt, you can generated a 3-gram language model database for use with the smoothed n-gram predictor by running the following commands: for i in 1 2 3; do text2ngram -n $i -l -f sqlite -o database_de.db training_de.txt; done ########/ Copyright (C) 2008 Matteo Vescovi Presage 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ########\ presage-0.8.8/py-compile0000755000175000017500000001013511737143302012103 00000000000000#!/bin/sh # py-compile - Compile a Python program scriptversion=2009-04-28.21; # UTC # Copyright (C) 2000, 2001, 2003, 2004, 2005, 2008, 2009 Free Software # Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . if [ -z "$PYTHON" ]; then PYTHON=python fi basedir= destdir= files= while test $# -ne 0; do case "$1" in --basedir) basedir=$2 if test -z "$basedir"; then echo "$0: Missing argument to --basedir." 1>&2 exit 1 fi shift ;; --destdir) destdir=$2 if test -z "$destdir"; then echo "$0: Missing argument to --destdir." 1>&2 exit 1 fi shift ;; -h|--h*) cat <<\EOF Usage: py-compile [--help] [--version] [--basedir DIR] [--destdir DIR] FILES..." Byte compile some python scripts FILES. Use --destdir to specify any leading directory path to the FILES that you don't want to include in the byte compiled file. Specify --basedir for any additional path information you do want to be shown in the byte compiled file. Example: py-compile --destdir /tmp/pkg-root --basedir /usr/share/test test.py test2.py Report bugs to . EOF exit $? ;; -v|--v*) echo "py-compile $scriptversion" exit $? ;; *) files="$files $1" ;; esac shift done if test -z "$files"; then echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 exit 1 fi # if basedir was given, then it should be prepended to filenames before # byte compilation. if [ -z "$basedir" ]; then pathtrans="path = file" else pathtrans="path = os.path.join('$basedir', file)" fi # if destdir was given, then it needs to be prepended to the filename to # byte compile but not go into the compiled file. if [ -z "$destdir" ]; then filetrans="filepath = path" else filetrans="filepath = os.path.normpath('$destdir' + os.sep + path)" fi $PYTHON -c " import sys, os, py_compile files = '''$files''' sys.stdout.write('Byte-compiling python modules...\n') for file in files.split(): $pathtrans $filetrans if not os.path.exists(filepath) or not (len(filepath) >= 3 and filepath[-3:] == '.py'): continue sys.stdout.write(file) sys.stdout.flush() py_compile.compile(filepath, filepath + 'c', path) sys.stdout.write('\n')" || exit $? # this will fail for python < 1.5, but that doesn't matter ... $PYTHON -O -c " import sys, os, py_compile files = '''$files''' sys.stdout.write('Byte-compiling python modules (optimized versions) ...\n') for file in files.split(): $pathtrans $filetrans if not os.path.exists(filepath) or not (len(filepath) >= 3 and filepath[-3:] == '.py'): continue sys.stdout.write(file) sys.stdout.flush() py_compile.compile(filepath, filepath + 'o', path) sys.stdout.write('\n')" 2>/dev/null || : # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: presage-0.8.8/src/0000755000175000017500000000000011764714755010766 500000000000000presage-0.8.8/src/tools/0000755000175000017500000000000011764714756012127 500000000000000presage-0.8.8/src/tools/ngram.h0000644000175000017500000000323311737142176013314 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_NGRAM #define PRESAGE_NGRAM #include #include #include #include class Ngram { friend std::ostream& operator<<( std::ostream&, const Ngram& ); public: Ngram(const int N); ~Ngram(); int getN() const; std::string getNgram(const int n) const; void setNgram(const int n, const std::string str); bool operator<( const Ngram& ) const; Ngram& operator=( const Ngram& ); std::string toString() const; private: int N; std::string* ngrams; }; #endif // PRESAGE_NGRAM presage-0.8.8/src/tools/text2ngram.cpp0000644000175000017500000002137411763437013014640 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #include #include #include "core/tokenizer/forwardTokenizer.h" #include "core/iso8859_1.h" #include "core/progress.h" #include "../lib/predictors/dbconnector/sqliteDatabaseConnector.h" const std::string PROGRAM_NAME = "text2ngram"; typedef std::list NgramList; void usage(); void version(); int main(int argc, char* argv[]) { int next_option; // Setup some defaults // - default to generating 1-gram counts int ngrams = 1; // - default output to stdout (empty string signifies stdout) std::string output; const std::string TABBED_SEPARATED_VALUES = "tsv"; const std::string SQLITE = "sqlite"; // - default format is tabbed separated values std::string format = TABBED_SEPARATED_VALUES; // - default to case sensitive bool lowercase = false; // - default to no append bool append = false; // getopt structures const char * const short_options = "n:o:f:alhv"; const struct option long_options[] = { { "ngrams", required_argument, 0, 'n' }, { "output", required_argument, 0, 'o' }, { "format", required_argument, 0, 'f' }, { "append", no_argument, 0, 'a' }, { "lowercase", no_argument, 0, 'l' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { 0, 0, 0, 0 } }; do { next_option = getopt_long(argc, argv, short_options, long_options, NULL); switch (next_option) { case 'n': // --ngrams or -n option if (atoi(optarg) > 0) { ngrams = atoi(optarg); } else { usage(); } break; case 'o': // --output or -o option output = optarg; break; case 'f': // --format or -f option if (optarg == SQLITE || optarg == TABBED_SEPARATED_VALUES) { format = optarg; } else { std::cerr << "Unknown format " << optarg << std::endl << std::endl; usage(); return -1; } break; case 'a': // --append or -a option // append mode append = true; break; case 'l': // --lowercase or -l option lowercase = true; break; case 'h': // --help or -h option usage(); exit (0); break; case 'v': // --version or -v option version(); exit (0); break; case '?': // unknown option usage(); exit (0); break; case -1: break; default: std::cerr << "Error: unhandled option." << std::endl; exit(0); } } while (next_option != -1); if ((argc - optind < 1)) { usage(); return -1; } // ngramMap stores pairs std::map ngramMap; for (int i = optind; i < argc; i++) { // do the actual processing file by file std::string token; NgramList ngram; // points to output file // print out file information std::cout << "Parsing " << argv[i] << "..." << std::endl; ProgressBar progressBar; // create tokenizer object and open input file stream std::ifstream infile(argv[i]); ForwardTokenizer tokenizer(infile, " \f\n\r\t\v", "`~!@#$%^&*()_-+=\\|]}[{'\";:/?.>,<"); tokenizer.lowercaseMode(lowercase); // take care of first N-1 tokens for (int i = 0; (i < ngrams - 1 && tokenizer.hasMoreTokens()); i++) { ngram.push_back(tokenizer.nextToken()); } while (tokenizer.hasMoreTokens()) { // extract token from input stream token = tokenizer.nextToken(); // update ngram with new token ngram.push_back(token); // update map with new token occurrence ngramMap[ngram] = ngramMap[ngram] + 1; // update progress bar //progressBar(tokenizer.progress()); progressBar.update(tokenizer.progress()); // remove front token from ngram ngram.pop_front(); } infile.close(); } std::cout << "Writing out to " << format << " format file " << output << "..." << std::endl; if (format == TABBED_SEPARATED_VALUES) { // output to tabbed separated values text file // std::ofstream *outstream = 0; std::ostream *prev_outstream = 0; if (output.c_str()) { // tie outstream to file outstream = new std::ofstream (output.c_str(), std::ios::out); assert(outstream); prev_outstream = std::cout.tie (outstream); } // write results to output stream ProgressBar progressBar; long total = ngramMap.size(); long count = 0; std::map::const_iterator it; for (it = ngramMap.begin(); it != ngramMap.end(); it++) { for (NgramList::const_iterator ngram_it = it->first.begin(); ngram_it != it->first.end(); ngram_it++) { std::cout << *ngram_it << '\t'; } std::cout << it->second << std::endl; progressBar.update(static_cast(count++)/total); } if (output.c_str()) { std::cout.tie (prev_outstream); outstream->close (); delete outstream; } } else if (format == SQLITE) { // output to SQLITE // SqliteDatabaseConnector sqliteDbCntr(output, ngrams, true); sqliteDbCntr.beginTransaction(); sqliteDbCntr.createNgramTable(ngrams); // write results to output stream ProgressBar progressBar; long total = ngramMap.size(); long count = 0; std::map::const_iterator it; for (it = ngramMap.begin(); it != ngramMap.end(); it++) { // convert from NgramList to Ngram Ngram ngram; for (NgramList::const_iterator jt = it->first.begin(); jt != it->first.end(); jt++) { ngram.push_back(*jt); } if (append) { // need to check whether ngram is already in database. // when appending to existing database int count = sqliteDbCntr.getNgramCount(ngram); if (count > 0) { // ngram already in database, update count sqliteDbCntr.updateNgram(ngram, count + it->second); } else { // ngram not in database, insert it sqliteDbCntr.insertNgram(ngram, it->second); } } else { // insert ngram sqliteDbCntr.insertNgram(ngram, it->second); } progressBar.update(static_cast(count++)/total); } sqliteDbCntr.endTransaction(); } else { abort(); } std::cout << std::endl; return 0; } void version() { std::cout << PROGRAM_NAME << " (" << PACKAGE << ") version " << VERSION << std::endl << "Copyright (C) Matteo Vescovi" << std::endl << "This is free software; see the source for copying conditions. There is NO" << std::endl << "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." << std::endl << std::endl; } void usage() { std::cout << "Usage: " << PROGRAM_NAME << " [OPTION]... infiles..." << std::endl << std::endl << " --output, -o O " << "Output file name O" << std::endl << " --ngrams, -n N " << "Specify ngram cardinality N" << std::endl << " --format, -f F " << "Output file format F: sqlite, tsv (tabbed separated values)" << std::endl << " --lowercase, -l " << "Enable lowercase conversion mode" << std::endl << " --append, -a " << "Open output file in append mode" << std::endl << " --help, -h " << "Display this information" << std::endl << " --version, -v " << "Show version information" << std::endl << std::endl << PROGRAM_NAME << " is free software distributed under the GPL." << std::endl << "Send bug reports to " << PACKAGE_BUGREPORT << std::endl << "Copyright (C) Matteo Vescovi" << std::endl; } presage-0.8.8/src/tools/presage_demo.10000644000175000017500000000205711764437330014555 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH PRESAGE_DEMO "1" "June 2012" "presage_demo (presage) version 0.8.8" "User Commands" .SH NAME presage_demo \- presage demo program (ncurses) .SH SYNOPSIS .B presage_demo [\fIOPTION\fR]... .SH DESCRIPTION Begin typing. presage will attempt to predict the desired word. After each keystroke, presage will return a number of predictions. If the desired word appears in the prediction list, select it by pressing the corresponding function key. .TP \fB\-c\fR, \fB\-\-config\fR CONFIG use config file CONFIG .TP \fB\-s\fR, \fB\-\-suggestions\fR N set prediction size to N suggestions .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit .TP \fB\-v\fR, \fB\-\-version\fR output version information and exit .PP Direct your bug reports to: matteo.vescovi@yahoo.co.uk .SH COPYRIGHT Copyright \(co 2004 Matteo Vescovi. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. presage-0.8.8/src/tools/presageDemoText.cpp0000644000175000017500000001314011737142176015641 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "presage.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STDLIB_H # include #endif #include #include #include const char PROGRAM_NAME[] = "presage_demo_text"; void disclaimer (); void parse_cmd_line_args (int argc, char** argv); void print_version (); void print_usage (); void print_prediction (const std::vector&); std::string config; int suggestions = 0; int main(int argc, char** argv) { parse_cmd_line_args (argc, argv); disclaimer (); // magic starts here... LegacyPresageCallback callback; Presage presage (&callback, config); if (suggestions) { // convert int to string using a stringstream std::stringstream ss; ss << suggestions; presage.config("Presage.Selector.SUGGESTIONS", ss.str()); } // buffer to read user input const int BUFFER_SIZE = 80; char buffer[ BUFFER_SIZE ]; for (;;) { std::cout << "> "; // prompt the user std::cin.getline (buffer, BUFFER_SIZE); // read in string (if any) callback.update(buffer); // update internal buffer print_prediction( presage.predict() // request new prediction ); std::cout << "-- Context: " << presage.context() << '|' << std::endl; if (presage.context_change()) { std::cout << "-- Context changed" << std::endl; } } return 0; } void disclaimer () { std::cout << "Presage Textual Demo\n" "--------------------\n" "\n" "This program is intended as a demonstration of Presage ONLY.\n" "\n" "The Presage project aims to provide an intelligent predictive text entry platform.\n" "\n" "Its intent is NOT to provide a predictive text entry user interface.\n" "Think of Presage as the predictive backend that sits behind a shiny user interface and does all the predictive heavy lifting.\n" "\n" << std::endl; } void parse_cmd_line_args (int argc, char* argv[]) { int next_option; // getopt structures const char* const short_options = "c:s:hv"; const struct option long_options[] = { { "config", required_argument, 0, 'c' }, { "suggestions", required_argument, 0, 's' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { 0, 0, 0, 0 } }; do { next_option = getopt_long( argc, argv, short_options, long_options, NULL ); switch( next_option ) { case 'c': // --config or -c option config = optarg; break; case 's': // --suggestions or -s option suggestions = atoi(optarg); break; case 'h': // --help or -h option print_usage (); exit (0); break; case 'v': // --version or -v option print_version (); exit (0); break; case '?': // unknown option print_usage(); exit (0); break; case -1: break; default: abort (); break; } } while (next_option != -1); } void print_prediction (const std::vector& words) { for( std::vector::const_iterator i = words.begin(); i != words.end(); i++ ) { std::cout << *i << std::endl; } } void print_version () { std::cout << PROGRAM_NAME << " (" << PACKAGE << ") version " << VERSION << std::endl << "Copyright (C) 2004 Matteo Vescovi." << std::endl << "This is free software; see the source for copying conditions. There is NO" << std::endl << "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE," << std::endl << "to the extent permitted by law." << std::endl; } void print_usage () { std::cout << "Usage: " << PROGRAM_NAME << " [OPTION]..." << std::endl << std::endl << "At the prompt, type in some text. Hit enter to generate a prediction." << std::endl << "Any text input is valid, including no text, a single character, or a long string." << std::endl << std::endl << " -c, --config CONFIG use config file CONFIG" << std::endl << " -s, --suggestions N set prediction size to N suggestions" << std::endl << " -h, --help display this help and exit" << std::endl << " -v, --version output version information and exit" << std::endl << std::endl << "Direct your bug reports to: " << PACKAGE_BUGREPORT << std::endl; } presage-0.8.8/src/tools/simulator/0000755000175000017500000000000011764714756014146 500000000000000presage-0.8.8/src/tools/simulator/simulator.cpp0000644000175000017500000001413611743227551016603 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "simulator.h" #include Simulator::Simulator(PresageCallback* callback, std::stringstream& sstream, const std::string config) : m_sstream(sstream) { presagePtr = new Presage(callback, config); autoSpace = true; ki = 0; ks = 1; kn = 0; silent_mode = false; } Simulator::~Simulator() { delete presagePtr; } void Simulator::simulate( std::string str ) { // Presage predicts a word even when the prefix // is a null string. This initial call to the predict // method simulates this condition. bool hit = find (presagePtr->predict(), str); // If the correct predicted word is returned, then // we've got a hit! If this happens when the prefix is // a null string, kudos to the developer (me)! // Presage predicted the word in one try! // We need to update the Presage object with the whole // string and take the trailing space into account. if (hit) { kn += str.size() + 1; ks++; //presagePtr->update (str + " "); m_sstream << str << ' '; if( !autoSpace ) { ki++; } } else { // If we didn't get it right on the first guess, // let's guess again until we get a hit or we // run out of characters that make up the current // word we're trying to predict. std::string::size_type i = 0; while( i < str.size() && !hit ) { // predict using new keystroke std::string up; up += str[i]; m_sstream << up; hit = find(presagePtr->predict(), str); // simulate character keystroke ki++; // position iterator on next character i++; } // If we got a hit, we've got the correct // predicted word after having used up some // of its characters to feed to Presage. if( hit ) { // presagePtr->complete(str); // presagePtr->update(" "); m_sstream << str.substr(i) << ' '; // THIS SHOULD REALLY BE STRING REMAINDER!!! kn += str.size() + 1; ki++; // To bad we were not able to get the right // prediction... no hit for us. // That means we ran each character of the // string through Presage. We only need // to cater for our beloved trailing // whitespace then. } else { // If we're positioned at the end of the // string, we've used all characters up // and got the right prediction right on // our last chance. // Selecting the prediction or entering // space is equivalent (supposing selecting // the prediction counts as one keystroke). // We'll simulate entering a whitespace. if( i == str.size() ) { // presagePtr->update( " " ); m_sstream << ' '; ki++; kn += str.size() + 1; } else { // Else we got the right prediction // b4 we got to the end of the string // Let's update Presage with // the remainder of the string we // didn't use and take care of our // trailing whitespace. // std::string suffix; // suffix.insert( suffix.begin(), i, str.end() ); // presagePtr->update( suffix + " " ); m_sstream << str.substr(i) << ' '; if( !autoSpace ) { ki++; } } } } } // void Simulator::reset() // { // delete presagePtr; // presagePtr = new Presage; // // ki = 0; // ks = 1; // kn = 0; // } void Simulator::results() const { std::cout << std::endl << "============================" << std::endl << "Keystroke Savings Rate (KSR)" << std::endl << " ki + ks " << std::endl << "KSR = (1 - ------- ) * 100" << std::endl << " kn " << std::endl << "where: " << std::endl << " ki = actual keystrokes" << std::endl << " ks = keystrokes required to select suggestion" << std::endl << " kn = keystrokes required with no prediction enabled" << std::endl << std::endl << "ki : " << ki << std::endl << "ks : " << ks << std::endl << "kn : " << kn << std::endl << std::endl << "KSR: " << getKSR() << std::endl; } int Simulator::getKi() const { return ki; } int Simulator::getKs() const { return ks; } int Simulator::getKn() const { return kn; } double Simulator::getKSR() const { return ( ( 1 - ( static_cast( ki + ks ) / static_cast( kn ) ) ) * 100 ); } void Simulator::setKs( int value ) { if( value > 0 ) ks = value; } bool Simulator::find( const std::vector& w, const std::string& t ) const { if (!silent_mode) { std::cout << "===> " << t << std::endl << " > " << presagePtr->prefix() << std::endl; } bool found = false; std::vector::const_iterator i = w.begin(); while( i != w.end() && !found ) { if (!silent_mode) { std::cout << *i << std::endl; } if( *i == t ) found = true; i++; } return found; } bool Simulator::getAutoSpace() const { return autoSpace; } void Simulator::setAutoSpace( bool b ) { autoSpace = b; } void Simulator::silentMode(bool mode) { silent_mode = mode; } presage-0.8.8/src/tools/simulator/Makefile.am0000644000175000017500000000211511743227551016106 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in noinst_LTLIBRARIES = libsimulator.la libsimulator_la_SOURCES = simulator.cpp simulator.h AM_CPPFLAGS = -I$(top_srcdir)/src/lib presage-0.8.8/src/tools/simulator/Makefile.in0000644000175000017500000004034111763440355016123 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/tools/simulator DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libsimulator_la_LIBADD = am_libsimulator_la_OBJECTS = simulator.lo libsimulator_la_OBJECTS = $(am_libsimulator_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libsimulator_la_SOURCES) DIST_SOURCES = $(libsimulator_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LTLIBRARIES = libsimulator.la libsimulator_la_SOURCES = simulator.cpp simulator.h AM_CPPFLAGS = -I$(top_srcdir)/src/lib all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tools/simulator/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tools/simulator/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libsimulator.la: $(libsimulator_la_OBJECTS) $(libsimulator_la_DEPENDENCIES) $(CXXLINK) $(libsimulator_la_OBJECTS) $(libsimulator_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simulator.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am # 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: presage-0.8.8/src/tools/simulator/simulator.h0000644000175000017500000000601311743227551016243 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SIMULATOR #define PRESAGE_SIMULATOR #include "presage.h" #include /** Evaluates how good Presage is at doing its job (in other words, its ability to reduce keystrokes the user is required to type). * * Simulator computes the KSR (Keystrokes Savings Rate) obtained by * using Presage preditive ability compared to manually entering * text. * * The KSR is computed as ( 1 - ( ki + ks ) / kn ) * 100, where * ki is the number of input characters actually typed * ks is the number of keystrokes needed to select among the predictions presented * kn is the number of keystrokes that would be needed if the whole text was typed without any prediction aid. * * The simulator is built with a reference to a Presage object * which simulates and takes a string holding the text to be run * through the simulation. Multiple calls to the simulate method can * take place. Each call runs the string through the simulator. The * results of each simulate call update the internal state of the * simulator object. The results of the simulation can be retrieved * at any time by invoking the results method or the get methods. * */ class Simulator { public: Simulator(PresageCallback* callback, std::stringstream& sstream, const std::string = ""); ~Simulator(); void simulate(std::string); // void reset(); void results() const; int getKi() const; int getKs() const; int getKn() const; double getKSR() const; bool getAutoSpace() const; void setAutoSpace( bool ); void setKs(int); void silentMode(bool); private: Presage* presagePtr; bool find( const std::vector&, const std::string& ) const; bool autoSpace; // determines whether predictive system is able to insert a space at the end of the word int ki; int ks; int kn; bool silent_mode; std::stringstream& m_sstream; }; #endif // PRESAGE_SIMULATOR presage-0.8.8/src/tools/ngram.cpp0000644000175000017500000000422311737142176013647 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "ngram.h" Ngram::Ngram(const int size) { assert(size > 0); N = size; ngrams = new std::string[N]; } Ngram::~Ngram() { delete[] ngrams; } Ngram& Ngram::operator=( const Ngram& other ) { if (&other != this) { for (int i = 0; i < N; i++) { ngrams[i] = other.ngrams[i]; } } return *this; } bool Ngram::operator<( const Ngram& other ) const { if (&other != this) { for (int i = N - 1; i >= 0; i--) { if (ngrams[i] < other.ngrams[i]) { return true; } } } return false; } std::string Ngram::toString() const { std::string str; for (int i = 0; i < N; i++) { str += "<" + ngrams[i] + "> "; } return str; } std::string Ngram::getNgram(const int n) const { assert(n >= 0 && n < N); return ngrams[n]; } void Ngram::setNgram(const int n, const std::string str) { assert(n >= 0 && n < N); ngrams[n] = str; } int Ngram::getN() const { return N; } std::ostream& operator<<( std::ostream& output, const Ngram& b ) { output << b.toString(); return output; } presage-0.8.8/src/tools/presageSimulator.cpp0000644000175000017500000001307711763442155016077 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #include #include #include #include #include "core/charsets.h" #include "core/tokenizer/forwardTokenizer.h" #include "simulator/simulator.h" const char PROGRAM_NAME[] = "presage_simulator"; void parseCommandLineArgs(int argc, char* argv[]); void printUsage(); void printVersion(); bool silent_mode = false; bool case_insensitive = false; std::string config; // Simple callback class, stores past context stream in a stringstream // passed in at construction time. // // getPastStream() returns a string of size() up to 'width'. // getFutureStream() return an empty string. // class SimulatorPresageCallback : public PresageCallback { public: SimulatorPresageCallback(std::stringstream& sstream) : m_sstream(sstream) { } ~SimulatorPresageCallback() { }; std::string get_past_stream() const { return m_sstream.str(); } std::string get_future_stream() const { return m_empty; } private: std::stringstream& m_sstream; const std::string m_empty; }; int main(int argc, char* argv[]) { parseCommandLineArgs(argc, argv); // check we have enough arguments if( argc - optind < 1 ) { printUsage(); exit (0); } // open infile for input std::ifstream infile( argv[ optind ], std::ios::in ); if( !infile ) { std::cerr << "\aError: could not open file " << argv[ optind ] << std::endl; return 1; } std::stringstream sstream; // stringstream to hold past context stream Simulator simulator(new SimulatorPresageCallback(sstream), sstream, config); simulator.silentMode(silent_mode); ForwardTokenizer tokenizer(infile, DEFAULT_BLANKSPACE_CHARS, DEFAULT_SEPARATOR_CHARS); tokenizer.lowercaseMode(case_insensitive); while(tokenizer.hasMoreTokens()) { simulator.simulate(tokenizer.nextToken()); } simulator.results(); infile.close(); return 0; } void parseCommandLineArgs(int argc, char* argv[]) { int next_option; // getopt structures const char* const short_options = "c:sqihv"; const struct option long_options[] = { { "config", required_argument, 0, 'c' }, { "silent", no_argument, 0, 's' }, { "quiet", no_argument, 0, 'q' }, { "insensitive", no_argument, 0, 'i' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { 0, 0, 0, 0 } }; do { next_option = getopt_long( argc, argv, short_options, long_options, NULL ); switch( next_option ) { case 'c': // -- config of -f option config = optarg; break; case 's': // --silent or -s option case 'q': // --quiet or -q option silent_mode = true; break; case 'i': // --insensitive or -i option case_insensitive = true; break; case 'h': // --help or -h option printUsage(); exit (0); break; case 'v': // --version or -v option printVersion(); exit (0); break; case '?': // unknown option printUsage(); exit (0); break; case -1: break; default: abort(); } } while( next_option != -1 ); } void printVersion() { std::cout << PROGRAM_NAME << " (" << PACKAGE << ") version " << VERSION << std::endl << "Copyright (C) Matteo Vescovi." << std::endl << "This is free software; see the source for copying conditions. There is NO" << std::endl << "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE," << std::endl << "to the extent permitted by law." << std::endl; } void printUsage() { std::cout << "Usage: " << PROGRAM_NAME << " [OPTION]... FILE" << std::endl << std::endl << " -c, --config CONFIG use config file CONFIG" << std::endl << " -i, --insensitive case insensitive mode" << std::endl << " -q, --quiet quiet mode, no verbose output, same as silent" << std::endl << " -s, --silent silent mode, no verbose output, same as quiet" << std::endl << " -h, --help display this help and exit" << std::endl << " -v, --version output version information and exit" << std::endl << std::endl << "Direct your bug reports to: " << PACKAGE_BUGREPORT << std::endl; } presage-0.8.8/src/tools/Makefile.am0000644000175000017500000000544411763437013014075 00000000000000 ########### # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = simulator noinst_LTLIBRARIES = libtools.la libtools_la_SOURCES = ngram.cpp ngram.h bin_PROGRAMS = presage_demo_text \ presage_simulator if USE_SQLITE bin_PROGRAMS += text2ngram text2ngram_SOURCES = text2ngram.cpp text2ngram_LDADD = libtools.la \ ../lib/predictors/dbconnector/libdbconnector.la \ ../lib/core/libcore.la \ ../lib/libpresage.la endif if HAVE_CURSES bin_PROGRAMS += presage_demo presage_demo_SOURCES = presageDemo.cpp presage_demo_LDADD = ../lib/libpresage.la presage_demo_LDFLAGS = -lcurses endif presage_demo_text_SOURCES = presageDemoText.cpp presage_demo_text_LDADD = ../lib/libpresage.la presage_simulator_SOURCES = presageSimulator.cpp presage_simulator_LDADD = simulator/libsimulator.la \ ../lib/core/libcore.la \ ../lib/libpresage.la AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_srcdir)/src if HAVE_HELP2MAN presage_demo_text.1: presage_demo_text$(EXEEXT) $(top_srcdir)/configure.ac help2man --output=$@ --no-info --name="presage demo program (text)" ./presage_demo_text$(EXEEXT) presage_simulator.1: presage_simulator$(EXEEXT) presageSimulator.cpp $(top_srcdir)/configure.ac help2man --output=$@ --no-info --name="presage simulator program" ./presage_simulator$(EXEEXT) dist_man_MANS = presage_demo_text.1 \ presage_simulator.1 DISTCLEANFILES = presage_demo_text.1 \ presage_simulator.1 if USE_SQLITE text2ngram.1: text2ngram$(EXEEXT) $(top_srcdir)/configure.ac help2man --output=$@ --no-info --name="generate statistical n-gram data from text" ./text2ngram$(EXEEXT) dist_man_MANS += text2ngram.1 DISTCLEANFILES += text2ngram.1 endif if HAVE_CURSES presage_demo.1: presage_demo$(EXEEXT) $(top_srcdir)/configure.ac help2man --output=$@ --no-info --name="presage demo program (ncurses)" ./presage_demo$(EXEEXT) dist_man_MANS += presage_demo.1 DISTCLEANFILES += presage_demo.1 endif endif presage-0.8.8/src/tools/presage_simulator.10000644000175000017500000000174111764437330015647 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH PRESAGE_SIMULATOR "1" "June 2012" "presage_simulator (presage) version 0.8.8" "User Commands" .SH NAME presage_simulator \- presage simulator program .SH SYNOPSIS .B presage_simulator [\fIOPTION\fR]... \fIFILE\fR .SH DESCRIPTION .TP \fB\-c\fR, \fB\-\-config\fR CONFIG use config file CONFIG .TP \fB\-i\fR, \fB\-\-insensitive\fR case insensitive mode .TP \fB\-q\fR, \fB\-\-quiet\fR quiet mode, no verbose output, same as silent .TP \fB\-s\fR, \fB\-\-silent\fR silent mode, no verbose output, same as quiet .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit .TP \fB\-v\fR, \fB\-\-version\fR output version information and exit .PP Direct your bug reports to: matteo.vescovi@yahoo.co.uk .SH COPYRIGHT Copyright \(co Matteo Vescovi. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. presage-0.8.8/src/tools/presageDemo.cpp0000644000175000017500000003164611737142176015007 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "presage.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif /* Solaris 10 needs to have NOMACROS defined to avoid conflict between curses and standard template library code. */ #ifndef NOMACROS # define NOMACROS # include # undef NOMACROS #else # include #endif #ifdef HAVE_STDLIB_H # include #endif #include #include #include #include const char PROGRAM_NAME[] = "presage_demo"; // prototypes // void parseCommandLineArgs(int argc, char** argv); void printUsage(); void printVersion(); void disclaimer(); void draw_title_win(WINDOW*); void draw_context_win(WINDOW*, std::string); void draw_function_keys(WINDOW*); void draw_previous_suggestions(std::vector, bool, const int, int); size_t getGreatestSuggestionLength(std::vector< std::string > suggestions); // globals std::string suggestions; std::string config; std::stringstream buffer; // text buffer, a real application would // use something a little more // sophisticated than a stringstream /** Callback object for presage demo application. * * We need to provide a callback class to allow presage to query the * application's text buffer. In a real world application, this would * fetch the text from whatever object stores the text composition * (i.e. a GUI widget in a graphical interface) * * For the purpose of this demonstration program, the callback class * will retrieve contextual data from a standard stringstream object. * */ class PresageDemoCallback : public PresageCallback { public: PresageDemoCallback(std::stringstream& buffer) : m_buffer(buffer) { } std::string get_past_stream() const { return m_buffer.str(); } std::string get_future_stream() const { return empty; } private: std::stringstream& m_buffer; const std::string empty; }; /** Demo program using curses. * * This demo displays the text entered in a top windows that stretches * across the screen. The current prediction is displayed immediately * underneath the text window, at the leftmost position. * * The previous predictions are displayed in cronological order to the * right of the current prediction. * * Subsequent predictions shifted to the right, so that the current * prediction is always on the left hand side. * Context switches are marked in some way (either a vertical bar or a * box enclosing the other prediction boxes). * */ int main(int argc, char** argv) { parseCommandLineArgs(argc, argv); // magic starts here PresageCallback* callback = new PresageDemoCallback(buffer); Presage presage(callback, config); // configuration variable may be read and written programmatically if (suggestions.empty()) { suggestions = presage.config("Presage.Selector.SUGGESTIONS"); } else { presage.config("Presage.Selector.SUGGESTIONS", suggestions); } // curses initscr(); noecho(); cbreak(); keypad(stdscr, TRUE); clear(); refresh(); disclaimer(); // curses title window const int TITLE_WIN_HEIGHT = 6; const int TITLE_WIN_WIDTH = COLS; const int TITLE_WIN_BEGIN_Y = 0; const int TITLE_WIN_BEGIN_X = 0; WINDOW* title_win = newwin(TITLE_WIN_HEIGHT, TITLE_WIN_WIDTH, TITLE_WIN_BEGIN_Y, TITLE_WIN_BEGIN_X); draw_title_win(title_win); // curses context window const int CONTEXT_WIN_HEIGHT = 5; const int CONTEXT_WIN_WIDTH = COLS; const int CONTEXT_WIN_BEGIN_Y = TITLE_WIN_BEGIN_Y + TITLE_WIN_HEIGHT + 1; const int CONTEXT_WIN_BEGIN_X = 0; WINDOW* context_win = newwin(CONTEXT_WIN_HEIGHT, CONTEXT_WIN_WIDTH, CONTEXT_WIN_BEGIN_Y, CONTEXT_WIN_BEGIN_X); draw_context_win(context_win, std::string("")); // curses function keys window const int FUNCTION_WIN_HEIGHT = atoi(suggestions.c_str()) + 2; const int FUNCTION_WIN_WIDTH = 4; const int FUNCTION_WIN_BEGIN_Y = CONTEXT_WIN_BEGIN_Y + CONTEXT_WIN_HEIGHT + 1; const int FUNCTION_WIN_BEGIN_X = 0; WINDOW* function_win = newwin(FUNCTION_WIN_HEIGHT, FUNCTION_WIN_WIDTH, FUNCTION_WIN_BEGIN_Y, FUNCTION_WIN_BEGIN_X); draw_function_keys(function_win); mvprintw(LINES - 1, 0, "Press F12 to quit."); refresh(); std::vector words; unsigned int c = ' '; do { size_t size = words.size(); if ((KEY_F0 < c) && (c <= KEY_F(size)) && (c - KEY_F0 <= size)) { // prediction was successful. user pressed the function // key corresponding to desired token. selecting // suggestion. std::string message = "Last selected word: " + words[c - KEY_F0 - 1]; mvprintw(LINES - 3, 0, message.c_str()); clrtoeol(); move(LINES, COLS); // update buffer with prediction completion buffer << presage.completion(words[c - KEY_F0 - 1]); // ask presage to predict next token words = presage.predict(); } else { // prediction unsuccessful. get next character from user // and elaborate a new prediction. buffer << static_cast(c); words = presage.predict(); // refresh curses screen refresh(); } draw_context_win(context_win, presage.context()); draw_previous_suggestions(words, presage.context_change(), CONTEXT_WIN_BEGIN_Y + CONTEXT_WIN_HEIGHT + 1, FUNCTION_WIN_BEGIN_X + FUNCTION_WIN_WIDTH + 1 ); c = getch(); } while( c != KEY_F(12) ); delwin(title_win); delwin(context_win); delwin(function_win); endwin(); return 0; } void draw_context_win(WINDOW* win, std::string str) { wclear( win ); box( win, 0, 0 ); mvwprintw( win, 1, 1, str.c_str() ); wrefresh( win ); } void drawMsgWin( WINDOW* win, std::vector words ) { wclear( win ); box( win, 0, 0 ); int i = 1; std::vector::const_iterator j = words.begin(); while( j != words.end() ) { mvwprintw( win, i, 1, j->c_str() ); i++; j++; } wrefresh( win ); } void draw_function_keys(WINDOW* win) { wclear(win); box(win, 0, 0); for (int i = 1; i <= atoi(suggestions.c_str()); i++) { std::stringstream ss; ss << 'F' << i; mvwprintw(win, i, 1, ss.str().c_str()); } wrefresh(win); } void draw_previous_suggestions(std::vector words, bool contextChange, const int starty, int startx) { static std::list< std::vector > previousSuggestions; static std::vector< WINDOW* > windows; // clear out existing windows for (std::vector< WINDOW* >::iterator winit = windows.begin(); winit != windows.end(); winit++) { wclear(*winit); wrefresh(*winit); delwin(*winit); } windows.clear(); if (contextChange) { // insert a context change marker in the list of previous // suggestions // std::vector< std::string > marker; for (int i = 0; i < atoi(suggestions.c_str()); i++) { marker.push_back("|"); } previousSuggestions.insert(previousSuggestions.begin(), marker); } previousSuggestions.insert(previousSuggestions.begin(), words); for (std::list< std::vector >::const_iterator listit = previousSuggestions.begin(); (listit != previousSuggestions.end() && startx < COLS); // don't draw window off the screen listit++) { int height = listit->size() + 2; int width = getGreatestSuggestionLength(*listit) + 2; WINDOW* win = newwin(height, width, starty, startx); wclear(win); box(win, 0, 0); int line = 1; for (std::vector::const_iterator strit = listit->begin(); strit != listit->end(); strit++) { mvwprintw(win, line, 1, strit->c_str()); line++; } wrefresh(win); windows.push_back(win); startx += width + 2; } } size_t getGreatestSuggestionLength(std::vector< std::string > suggestions) { size_t result = 0; for (std::vector< std::string >::const_iterator it = suggestions.begin(); it != suggestions.end(); it++) { if (it->size() > result) { result = it->size(); } } return result; } void disclaimer() { int topBottomBorder = (LINES/8); int borderWinHeight = 15; int borderWinWidth = 70; int sideBorder = (COLS - borderWinWidth) / 2; WINDOW* borderWin = newwin(borderWinHeight, borderWinWidth, topBottomBorder, sideBorder); WINDOW* disclaimerWin = newwin(borderWinHeight-2, borderWinWidth-2, topBottomBorder+1, sideBorder+1); box(borderWin, 0, 0); wrefresh(borderWin); wprintw(disclaimerWin, "Presage Demo\n" "------------\n" "This program is intended as a demonstration of Presage ONLY.\n" "\n" "The Presage project aims to provide an intelligent predictive\n" "text entry platform.\n" "\n" "Its intent is NOT to provide a predictive text entry user interface.\n" "Think of Presage as the predictive backend that sits behind a\n" "shiny user interface and does all the predictive heavy lifting.\n" ); mvwprintw(disclaimerWin, (borderWinHeight-2)-1, 1, "Press any key to continue..."); wrefresh(disclaimerWin); getch(); delwin(disclaimerWin); delwin(borderWin); clear(); refresh(); } void draw_title_win(WINDOW* title_win) { wclear(title_win); box(title_win, 0, 0); mvwprintw(title_win, 1, 1, "Presage Demo ", VERSION); mvwprintw(title_win, 2, 1, "Copyright (C) Matteo Vescovi"); mvwprintw(title_win, 3, 1, "This is free software; see the source for copying conditions. There is NO"); mvwprintw(title_win, 4, 1, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); wrefresh(title_win); } void parseCommandLineArgs(int argc, char* argv[]) { int next_option; // getopt structures const char* const short_options = "c:s:hv"; const struct option long_options[] = { { "config", required_argument, 0, 'c' }, { "suggestions", required_argument, 0, 's' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { 0, 0, 0, 0 } }; do { next_option = getopt_long( argc, argv, short_options, long_options, NULL ); switch( next_option ) { case 'c': // --config or -c option config = optarg; break; case 's': // --suggestions or -s option suggestions = optarg; break; case 'h': // --help or -h option printUsage(); exit (0); break; case 'v': // --version or -v option printVersion(); exit (0); break; case '?': // unknown option printUsage(); exit (0); break; case -1: break; default: abort(); } } while( next_option != -1 ); } void printVersion() { std::cout << PROGRAM_NAME << " (" << PACKAGE << ") version " << VERSION << std::endl << "Copyright (C) 2004 Matteo Vescovi." << std::endl << "This is free software; see the source for copying conditions. There is NO" << std::endl << "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE," << std::endl << "to the extent permitted by law." << std::endl; } void printUsage() { std::cout << "Usage: " << PROGRAM_NAME << " [OPTION]..." << std::endl << std::endl << "Begin typing. presage will attempt to predict the desired word." << std::endl << "After each keystroke, presage will return a number of predictions." << std::endl << "If the desired word appears in the prediction list, select it by pressing the" << std::endl << "corresponding function key." << std::endl << std::endl << " -c, --config CONFIG use config file CONFIG" << std::endl << " -s, --suggestions N set prediction size to N suggestions" << std::endl << " -h, --help display this help and exit" << std::endl << " -v, --version output version information and exit" << std::endl << std::endl << "Direct your bug reports to: " << PACKAGE_BUGREPORT << std::endl; } presage-0.8.8/src/tools/presage_demo_text.10000644000175000017500000000175311764437330015623 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH PRESAGE_DEMO_TEXT "1" "June 2012" "presage_demo_text (presage) version 0.8.8" "User Commands" .SH NAME presage_demo_text \- presage demo program (text) .SH SYNOPSIS .B presage_demo_text [\fIOPTION\fR]... .SH DESCRIPTION At the prompt, type in some text. Hit enter to generate a prediction. Any text input is valid, including no text, a single character, or a long string. .TP \fB\-c\fR, \fB\-\-config\fR CONFIG use config file CONFIG .TP \fB\-s\fR, \fB\-\-suggestions\fR N set prediction size to N suggestions .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit .TP \fB\-v\fR, \fB\-\-version\fR output version information and exit .PP Direct your bug reports to: matteo.vescovi@yahoo.co.uk .SH COPYRIGHT Copyright \(co 2004 Matteo Vescovi. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. presage-0.8.8/src/tools/Makefile.in0000644000175000017500000007757311763440355014125 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########### # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = presage_demo_text$(EXEEXT) presage_simulator$(EXEEXT) \ $(am__EXEEXT_1) $(am__EXEEXT_2) @USE_SQLITE_TRUE@am__append_1 = text2ngram @HAVE_CURSES_TRUE@am__append_2 = presage_demo @HAVE_HELP2MAN_TRUE@@USE_SQLITE_TRUE@am__append_3 = text2ngram.1 @HAVE_HELP2MAN_TRUE@@USE_SQLITE_TRUE@am__append_4 = text2ngram.1 @HAVE_CURSES_TRUE@@HAVE_HELP2MAN_TRUE@am__append_5 = presage_demo.1 @HAVE_CURSES_TRUE@@HAVE_HELP2MAN_TRUE@am__append_6 = presage_demo.1 subdir = src/tools DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtools_la_LIBADD = am_libtools_la_OBJECTS = ngram.lo libtools_la_OBJECTS = $(am_libtools_la_OBJECTS) @USE_SQLITE_TRUE@am__EXEEXT_1 = text2ngram$(EXEEXT) @HAVE_CURSES_TRUE@am__EXEEXT_2 = presage_demo$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) am__presage_demo_SOURCES_DIST = presageDemo.cpp @HAVE_CURSES_TRUE@am_presage_demo_OBJECTS = presageDemo.$(OBJEXT) presage_demo_OBJECTS = $(am_presage_demo_OBJECTS) @HAVE_CURSES_TRUE@presage_demo_DEPENDENCIES = ../lib/libpresage.la presage_demo_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(presage_demo_LDFLAGS) $(LDFLAGS) -o $@ am_presage_demo_text_OBJECTS = presageDemoText.$(OBJEXT) presage_demo_text_OBJECTS = $(am_presage_demo_text_OBJECTS) presage_demo_text_DEPENDENCIES = ../lib/libpresage.la am_presage_simulator_OBJECTS = presageSimulator.$(OBJEXT) presage_simulator_OBJECTS = $(am_presage_simulator_OBJECTS) presage_simulator_DEPENDENCIES = simulator/libsimulator.la \ ../lib/core/libcore.la ../lib/libpresage.la am__text2ngram_SOURCES_DIST = text2ngram.cpp @USE_SQLITE_TRUE@am_text2ngram_OBJECTS = text2ngram.$(OBJEXT) text2ngram_OBJECTS = $(am_text2ngram_OBJECTS) @USE_SQLITE_TRUE@text2ngram_DEPENDENCIES = libtools.la \ @USE_SQLITE_TRUE@ ../lib/predictors/dbconnector/libdbconnector.la \ @USE_SQLITE_TRUE@ ../lib/core/libcore.la ../lib/libpresage.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libtools_la_SOURCES) $(presage_demo_SOURCES) \ $(presage_demo_text_SOURCES) $(presage_simulator_SOURCES) \ $(text2ngram_SOURCES) DIST_SOURCES = $(libtools_la_SOURCES) $(am__presage_demo_SOURCES_DIST) \ $(presage_demo_text_SOURCES) $(presage_simulator_SOURCES) \ $(am__text2ngram_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' man1dir = $(mandir)/man1 NROFF = nroff MANS = $(dist_man_MANS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = simulator noinst_LTLIBRARIES = libtools.la libtools_la_SOURCES = ngram.cpp ngram.h @USE_SQLITE_TRUE@text2ngram_SOURCES = text2ngram.cpp @USE_SQLITE_TRUE@text2ngram_LDADD = libtools.la \ @USE_SQLITE_TRUE@ ../lib/predictors/dbconnector/libdbconnector.la \ @USE_SQLITE_TRUE@ ../lib/core/libcore.la \ @USE_SQLITE_TRUE@ ../lib/libpresage.la @HAVE_CURSES_TRUE@presage_demo_SOURCES = presageDemo.cpp @HAVE_CURSES_TRUE@presage_demo_LDADD = ../lib/libpresage.la @HAVE_CURSES_TRUE@presage_demo_LDFLAGS = -lcurses presage_demo_text_SOURCES = presageDemoText.cpp presage_demo_text_LDADD = ../lib/libpresage.la presage_simulator_SOURCES = presageSimulator.cpp presage_simulator_LDADD = simulator/libsimulator.la \ ../lib/core/libcore.la \ ../lib/libpresage.la AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_srcdir)/src @HAVE_HELP2MAN_TRUE@dist_man_MANS = presage_demo_text.1 \ @HAVE_HELP2MAN_TRUE@ presage_simulator.1 $(am__append_3) \ @HAVE_HELP2MAN_TRUE@ $(am__append_5) @HAVE_HELP2MAN_TRUE@DISTCLEANFILES = presage_demo_text.1 \ @HAVE_HELP2MAN_TRUE@ presage_simulator.1 $(am__append_4) \ @HAVE_HELP2MAN_TRUE@ $(am__append_6) all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tools/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/tools/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtools.la: $(libtools_la_OBJECTS) $(libtools_la_DEPENDENCIES) $(CXXLINK) $(libtools_la_OBJECTS) $(libtools_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list presage_demo$(EXEEXT): $(presage_demo_OBJECTS) $(presage_demo_DEPENDENCIES) @rm -f presage_demo$(EXEEXT) $(presage_demo_LINK) $(presage_demo_OBJECTS) $(presage_demo_LDADD) $(LIBS) presage_demo_text$(EXEEXT): $(presage_demo_text_OBJECTS) $(presage_demo_text_DEPENDENCIES) @rm -f presage_demo_text$(EXEEXT) $(CXXLINK) $(presage_demo_text_OBJECTS) $(presage_demo_text_LDADD) $(LIBS) presage_simulator$(EXEEXT): $(presage_simulator_OBJECTS) $(presage_simulator_DEPENDENCIES) @rm -f presage_simulator$(EXEEXT) $(CXXLINK) $(presage_simulator_OBJECTS) $(presage_simulator_LDADD) $(LIBS) text2ngram$(EXEEXT): $(text2ngram_OBJECTS) $(text2ngram_DEPENDENCIES) @rm -f text2ngram$(EXEEXT) $(CXXLINK) $(text2ngram_OBJECTS) $(text2ngram_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ngram.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/presageDemo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/presageDemoText.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/presageSimulator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text2ngram.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(dist_man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @list=''; test -n "$(man1dir)" || exit 0; \ { for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ test -z "$$files" || { \ echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-man install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-man1 install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man uninstall-man: uninstall-man1 .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-binPROGRAMS \ clean-generic clean-libtool clean-noinstLTLIBRARIES ctags \ ctags-recursive distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-binPROGRAMS uninstall-man \ uninstall-man1 @HAVE_HELP2MAN_TRUE@presage_demo_text.1: presage_demo_text$(EXEEXT) $(top_srcdir)/configure.ac @HAVE_HELP2MAN_TRUE@ help2man --output=$@ --no-info --name="presage demo program (text)" ./presage_demo_text$(EXEEXT) @HAVE_HELP2MAN_TRUE@presage_simulator.1: presage_simulator$(EXEEXT) presageSimulator.cpp $(top_srcdir)/configure.ac @HAVE_HELP2MAN_TRUE@ help2man --output=$@ --no-info --name="presage simulator program" ./presage_simulator$(EXEEXT) @HAVE_HELP2MAN_TRUE@@USE_SQLITE_TRUE@text2ngram.1: text2ngram$(EXEEXT) $(top_srcdir)/configure.ac @HAVE_HELP2MAN_TRUE@@USE_SQLITE_TRUE@ help2man --output=$@ --no-info --name="generate statistical n-gram data from text" ./text2ngram$(EXEEXT) @HAVE_CURSES_TRUE@@HAVE_HELP2MAN_TRUE@presage_demo.1: presage_demo$(EXEEXT) $(top_srcdir)/configure.ac @HAVE_CURSES_TRUE@@HAVE_HELP2MAN_TRUE@ help2man --output=$@ --no-info --name="presage demo program (ncurses)" ./presage_demo$(EXEEXT) # 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: presage-0.8.8/src/tools/text2ngram.10000644000175000017500000000207411764437330014215 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH TEXT2NGRAM "1" "June 2012" "text2ngram (presage) version 0.8.8" "User Commands" .SH NAME text2ngram \- generate statistical n-gram data from text .SH SYNOPSIS .B text2ngram [\fIOPTION\fR]... \fIinfiles\fR... .SH DESCRIPTION .TP \fB\-\-output\fR, \fB\-o\fR O Output file name O .TP \fB\-\-ngrams\fR, \fB\-n\fR N Specify ngram cardinality N .TP \fB\-\-format\fR, \fB\-f\fR F Output file format F: sqlite, tsv (tabbed separated values) .HP \fB\-\-lowercase\fR, \fB\-l\fR Enable lowercase conversion mode .TP \fB\-\-append\fR, \fB\-a\fR Open output file in append mode .TP \fB\-\-help\fR, \fB\-h\fR Display this information .TP \fB\-\-version\fR, \fB\-v\fR Show version information .PP text2ngram is free software distributed under the GPL. Send bug reports to matteo.vescovi@yahoo.co.uk Copyright \(co Matteo Vescovi .SH COPYRIGHT Copyright \(co Matteo Vescovi .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. presage-0.8.8/src/Makefile.am0000644000175000017500000000175011737142176012735 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = lib tools #plump presage-0.8.8/src/Makefile.in0000644000175000017500000004425211763440355012751 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = lib tools #plump all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # 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: presage-0.8.8/src/lib/0000755000175000017500000000000011764714755011534 500000000000000presage-0.8.8/src/lib/presage.cpp0000644000175000017500000003117211743227551013600 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "presage.h" #include "core/profileManager.h" #include "core/predictorRegistry.h" #include "core/context_tracker/contextTracker.h" #include "core/selector.h" #include "core/predictorActivator.h" Presage::Presage (PresageCallback* callback) throw (PresageException) { profileManager = new ProfileManager(); configuration = profileManager->get_configuration(); predictorRegistry = new PredictorRegistry(configuration); contextTracker = new ContextTracker(configuration, predictorRegistry, callback); predictorActivator = new PredictorActivator(configuration, predictorRegistry, contextTracker); selector = new Selector(configuration, contextTracker); } Presage::Presage (PresageCallback* callback, const std::string config_filename) throw (PresageException) { profileManager = new ProfileManager(config_filename); configuration = profileManager->get_configuration(); predictorRegistry = new PredictorRegistry(configuration); contextTracker = new ContextTracker(configuration, predictorRegistry, callback); predictorActivator = new PredictorActivator(configuration, predictorRegistry, contextTracker); selector = new Selector(configuration, contextTracker); } Presage::~Presage() { delete selector; delete predictorActivator; delete contextTracker; delete predictorRegistry; delete profileManager; } std::vector Presage::predict () throw (PresageException) { std::vector result; unsigned int multiplier = 1; Prediction prediction = predictorActivator->predict(multiplier++, 0); result = selector->select(prediction); Prediction previous_prediction = prediction; while ((result.size() < (selector->get_suggestions())) && (prediction = predictorActivator->predict(multiplier++, 0)).size() > previous_prediction.size()) { // while the number of predicted tokens is lower than desired, // search harder (i.e. higher multiplier) for a prediction of // sufficient size (i.e. that satisfies selector), as long as // the result of current prediction is greater than the // previous prediction (i.e. we are finding new tokens). result = selector->select(prediction); previous_prediction = prediction; } contextTracker->update(); return result; } std::multimap Presage::predict (std::vector filter) throw (PresageException) { std::multimap result; std::vector selection; const char** internal_filter = 0; if(filter.size()>0) { // convert filter to internal representation - currently a null // terminated const char** internal_filter = new const char*[filter.size() + 1]; for (std::vector::size_type i = 0; i < filter.size(); i++) { internal_filter[i] = filter[i].c_str(); } internal_filter[filter.size()] = 0; } unsigned int multiplier = 1; Prediction prediction = predictorActivator->predict(multiplier++, internal_filter); selection = selector->select(prediction); Prediction previous_prediction = prediction; while ((selection.size() < (selector->get_suggestions())) && (prediction = predictorActivator->predict(multiplier++, internal_filter)).size() > previous_prediction.size()) { // while the number of predicted tokens is lower than desired, // search harder (i.e. higher multiplier) for a prediction of // sufficient size (i.e. that satisfies selector), as long as // the selection of current prediction is greater than the // previous prediction (i.e. we are finding new tokens). selection = selector->select(prediction); previous_prediction = prediction; } delete[] internal_filter; for (std::vector::const_iterator it = selection.begin(); it != selection.end(); it++) { std::pair p(prediction.getSuggestion(*it).getProbability(), (*it)); result.insert(p); } contextTracker->update(); return result; } PresageCallback* Presage::callback (PresageCallback* callback) throw (PresageException) { return const_cast(contextTracker->callback(callback)); } std::string Presage::completion (const std::string str) throw (PresageException) { // There are two types of completions: normal and erasing. // normal_completion = prefix + remainder // erasing_completion = eraser + prefix + remainder // // or, given that token = prefix + remainder // normal_completion = token // erasing_completion = eraser + token // // where eraser = ^H+ (one or more backspace characters) // // offset to first non ^H character in completion (^H are inserted // by abbreviation expansion predictor to erase abbreviation from // stream) // std::string result; std::string::size_type offset = str.find_first_not_of('\b'); if (offset == 0) { // normal completion, // ensure that current prefix is a substring of completion // token and set result // if (contextTracker->isCompletionValid(str)) { std::string prefix = contextTracker->getPrefix(); result = str.substr(prefix.size()); } else { std::string message = "[Presage] Error: token '"; message += str; message += "' does not match prefix: "; message += contextTracker->getPrefix(); throw PresageException(PRESAGE_TOKEN_PREFIX_MISMATCH_ERROR, message); } } else { // erasing completion, // pass it to tracker in its entirety // result = str; } // if (append_trailing_space_is_on()) // TODO: make this configurable result += ' '; return result; } std::string Presage::context () const throw (PresageException) { return contextTracker->getPastStream(); } bool Presage::context_change () const throw (PresageException) { return contextTracker->contextChange(); } std::string Presage::prefix () const throw (PresageException) { return contextTracker->getPrefix(); } std::string Presage::config (const std::string variable) const throw (PresageException) { return configuration->find (variable)->get_value (); } void Presage::config (const std::string variable, const std::string value) const throw (PresageException) { configuration->find (variable)->set_value (value); } void Presage::save_config () const throw (PresageException) { profileManager->save_profile (); } struct _presage { PresageCallback* presage_callback_object; Presage* presage_object; }; class CPresageCallback : public PresageCallback { public: CPresageCallback (_presage_callback_get_past_stream past, void* past_arg, _presage_callback_get_future_stream future, void* future_arg) : m_get_past_stream_cb (past), m_get_past_stream_cb_arg (past_arg), m_get_future_stream_cb (future), m_get_future_stream_cb_arg (future_arg) { } virtual ~CPresageCallback() { } std::string get_past_stream() const { return (*m_get_past_stream_cb) (m_get_past_stream_cb_arg); } std::string get_future_stream() const { return (*m_get_future_stream_cb) (m_get_future_stream_cb_arg); } private: _presage_callback_get_past_stream m_get_past_stream_cb; void* m_get_past_stream_cb_arg; _presage_callback_get_future_stream m_get_future_stream_cb; void* m_get_future_stream_cb_arg; }; #define presage_exception_handler(CODE) \ try \ { \ CODE; \ } \ catch (PresageException& ex) \ { \ return ex.code (); \ } \ return PRESAGE_OK; #define presage_exception_handler_with_result(CODE) \ try \ { \ CODE; \ } \ catch (PresageException& ex) \ { \ (*result) = 0; \ return ex.code (); \ } \ return PRESAGE_OK; static char* alloc_c_str (const std::string& str) { char* result_c_str = (char*) malloc (str.size() + 1); if (result_c_str) strcpy (result_c_str, str.c_str()); return result_c_str; } presage_error_code_t presage_new (_presage_callback_get_past_stream past_stream_cb, void* past_stream_cb_arg, _presage_callback_get_future_stream future_stream_cb, void* future_stream_cb_arg, presage_t* result) { presage_exception_handler_with_result ( (*result) = (presage_t) malloc (sizeof (_presage)); (*result)->presage_callback_object = new CPresageCallback (past_stream_cb, past_stream_cb_arg, future_stream_cb, future_stream_cb_arg); (*result)->presage_object = new Presage ((*result)->presage_callback_object); ); } presage_error_code_t presage_new_with_config (_presage_callback_get_past_stream past_stream_cb, void* past_stream_cb_arg, _presage_callback_get_future_stream future_stream_cb, void* future_stream_cb_arg, const char* config, presage_t* result) { presage_exception_handler_with_result ( (*result) = (presage_t) malloc (sizeof (_presage)); (*result)->presage_callback_object = new CPresageCallback (past_stream_cb, past_stream_cb_arg, future_stream_cb, future_stream_cb_arg); (*result)->presage_object = new Presage ((*result)->presage_callback_object, config); ); } void presage_free (presage_t prsg) { if (prsg) { delete prsg->presage_object; delete prsg->presage_callback_object; free (prsg); } } void presage_free_string (char* str) { free (str); } void presage_free_string_array (char** strs) { if (strs) { for (size_t t = 0; strs[t] != 0; t++) { free (strs[t]); } free (strs); } } presage_error_code_t presage_predict (presage_t prsg, char*** result) { presage_exception_handler_with_result ( std::vector prediction = prsg->presage_object->predict(); size_t prediction_c_str_size = prediction.size() + 1; char** prediction_c_str = (char**) malloc (prediction_c_str_size * sizeof(char*)); memset (prediction_c_str, 0, prediction_c_str_size * sizeof(char*)); size_t i = 0; while (i < prediction_c_str_size - 1) { prediction_c_str[i] = (char*) malloc (prediction[i].size() + 1); strcpy (prediction_c_str[i], prediction[i].c_str()); i++; } prediction_c_str[i] = 0; *result = prediction_c_str; ); } presage_error_code_t presage_completion (presage_t prsg, const char* token, char** result) { presage_exception_handler_with_result ( *result = alloc_c_str (prsg->presage_object->completion (token)); ); } presage_error_code_t presage_context (presage_t prsg, char** result) { presage_exception_handler_with_result ( *result = alloc_c_str (prsg->presage_object->context ()); ); } presage_error_code_t presage_context_change (presage_t prsg, int* result) { presage_exception_handler_with_result ( *result = prsg->presage_object->context_change (); ); } presage_error_code_t presage_prefix (presage_t prsg, char** result) { presage_exception_handler_with_result ( *result = alloc_c_str (prsg->presage_object->prefix ()); ); } presage_error_code_t presage_config (presage_t prsg, const char* variable, char** result) { presage_exception_handler_with_result ( *result = alloc_c_str (prsg->presage_object->config (variable)); ); } presage_error_code_t presage_config_set (presage_t prsg, const char* variable, const char* value) { presage_exception_handler ( prsg->presage_object->config (variable, value) ); } presage_error_code_t presage_save_config (presage_t prsg) { presage_exception_handler ( prsg->presage_object->save_config () ); } presage-0.8.8/src/lib/presageException.h0000644000175000017500000000535711737142176015134 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_EXCEPTION #define PRESAGE_EXCEPTION #ifdef __cplusplus extern "C" { #endif typedef enum { PRESAGE_OK = 0, /* successful result */ PRESAGE_ERROR, /* generic/unknown presage error */ PRESAGE_TOKEN_PREFIX_MISMATCH_ERROR, PRESAGE_SMOOTHED_NGRAM_PREDICTOR_LEARN_ERROR, PRESAGE_CONFIG_VARIABLE_ERROR, PRESAGE_INVALID_CALLBACK_ERROR, PRESAGE_INVALID_SUGGESTION_ERROR, PRESAGE_INIT_PREDICTOR_ERROR, PRESAGE_SQLITE_OPEN_DATABASE_ERROR, PRESAGE_SQLITE_EXECUTE_SQL_ERROR } presage_error_code_t; #ifdef __cplusplus } #endif #ifdef __cplusplus #ifndef _MSC_VER #include #include /** When thrown, provides information about an error that has occurred within presage. * * If an error occurs within presage, an exception is thrown, and * this is the object that encapsulates the details of the problem. * * Application using presage should always ensure that exceptions * are caught by enclosing all presage methods within a try{} * catch(PresageException& e) {} block. * */ class PresageException : public std::exception { public: PresageException(presage_error_code_t code, const std::string& msg) throw() : m_details (msg), m_code (code) { // intentionally empty } virtual ~PresageException() throw() { // intentionally empty } virtual const char* what() const throw() { return m_details.c_str(); } virtual const presage_error_code_t code() const throw() { return m_code; } private: std::string m_details; presage_error_code_t m_code; }; #endif /* _MSC_VER */ #endif /* __cplusplus */ #endif /* PRESAGE_EXCEPTION */ presage-0.8.8/src/lib/Makefile.am0000644000175000017500000000332011743227551013474 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if BUILD_TINYXML MAYBE_TINYXML = tinyxml endif SUBDIRS = $(MAYBE_TINYXML) core predictors include_HEADERS = presage.h \ presageException.h \ presageCallback.h lib_LTLIBRARIES = libpresage.la libpresage_la_SOURCES = presage.cpp \ presage.h \ presageException.h \ presageCallback.h \ libpresage.map libpresage_la_LIBADD = core/libcore.la \ predictors/libpredictors.la libpresage_la_LDFLAGS = -no-undefined \ -version-info 2:1:1 if HAVE_LD_WITH_VERSION_SCRIPT libpresage_la_LDFLAGS += -Wl,--version-script,$(srcdir)/libpresage.map endif if BUILD_TINYXML libpresage_la_CPPFLAGS = -I$(top_srcdir)/src/lib/tinyxml libpresage_la_LIBADD += tinyxml/libtinyxml.la else libpresage_la_LIBADD += -ltinyxml endif EXTRA_DIST = libpresage.map presage-0.8.8/src/lib/core/0000755000175000017500000000000011764714755012464 500000000000000presage-0.8.8/src/lib/core/meritocracyCombiner.h0000644000175000017500000000342511737142176016551 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_MERITOCRACYCOMBINER #define PRESAGE_MERITOCRACYCOMBINER #include "combiner.h" /** MeritocracyCombiner. * * Meritocracy is a system of government or other organization based * on demonstrated ability (merit) and talent rather than by wealth * (plutocracy), family connections (nepotism), class privilege, * cronyism, popularity (as in democracy) or other historical * determinants of social position and political power. * */ class MeritocracyCombiner : public Combiner { public: MeritocracyCombiner(); virtual ~MeritocracyCombiner(); virtual Prediction combine(const std::vector< Prediction >&); private: }; #endif // PRESAGE_MERITOCRACYCOMBINER presage-0.8.8/src/lib/core/predictorRegistry.cpp0000644000175000017500000001413011763437013016617 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "predictorRegistry.h" #ifdef USE_SQLITE # include "predictors/smoothedNgramPredictor.h" #endif #include "predictors/ARPAPredictor.h" #include "predictors/abbreviationExpansionPredictor.h" #include "predictors/dummyPredictor.h" #include "predictors/dictionaryPredictor.h" #include "predictors/recencyPredictor.h" #include "predictors/dejavuPredictor.h" const char* PredictorRegistry::LOGGER = "Presage.PredictorRegistry.LOGGER"; const char* PredictorRegistry::PREDICTORS = "Presage.PredictorRegistry.PREDICTORS"; PredictorRegistry::PredictorRegistry(Configuration* configuration) : config(configuration), contextTracker(0), logger("PredictorRegistry", std::cerr), dispatcher(this) { // build notification dispatch map dispatcher.map (config->find (LOGGER), & PredictorRegistry::setLogger); dispatcher.map (config->find (PREDICTORS), & PredictorRegistry::setPredictors); } PredictorRegistry::~PredictorRegistry() { removePredictors(); } void PredictorRegistry::setLogger (const std::string& value) { logger << setlevel (value); logger << INFO << "LOGGER: " << value << endl; } void PredictorRegistry::setContextTracker(ContextTracker* ct) { if (contextTracker != ct) { contextTracker = ct; removePredictors (); setPredictors (predictors_list); } } void PredictorRegistry::setPredictors(const std::string& predictorList) { predictors_list = predictorList; logger << INFO << "PREDICTORS: " << predictors_list << endl; if (contextTracker) { // predictors need tracker, only initialize them if available removePredictors(); std::stringstream ss(predictors_list); std::string predictor; while (ss >> predictor) { logger << INFO << "Initializing predictor: " << predictor << endl; addPredictor(predictor); } } } void PredictorRegistry::addPredictor(const std::string& predictorName) { Predictor* predictor = 0; const char* name = predictorName.c_str(); std::string predictor_class_variable_key = "Presage.Predictors." + predictorName + ".PREDICTOR"; Variable* predictor_class_variable = 0; // TODO: this will have to do for now, until a proper predictor // framework (i.e. plump) is integrated into presage. Until then, // all known predictors have to be listed here and explicitly // created based on their name. // try { predictor_class_variable = config->find (predictor_class_variable_key); std::string predictor_class = predictor_class_variable->get_value(); if (predictor_class == "AbbreviationExpansionPredictor") { predictor = new AbbreviationExpansionPredictor(config, contextTracker, name); } else if (predictor_class == "DummyPredictor") { predictor = new DummyPredictor(config, contextTracker, name); } else if (predictor_class == "DictionaryPredictor" ) { predictor = new DictionaryPredictor(config, contextTracker, name); #ifdef USE_SQLITE } else if (predictor_class == "SmoothedNgramPredictor") { predictor = new SmoothedNgramPredictor(config, contextTracker, name); #endif } else if (predictor_class == "RecencyPredictor") { predictor = new RecencyPredictor(config, contextTracker, name); } else if (predictor_class == "DejavuPredictor") { predictor = new DejavuPredictor(config, contextTracker, name); } else if (predictor_class == "ARPAPredictor") { predictor = new ARPAPredictor(config, contextTracker, name); } else { logger << ERROR << predictor_class_variable_key << " class is unknown." << endl; } } catch (PresageException ex) { logger << ERROR << ex.what() << endl << ERROR << "Predictor " + predictorName + " failed to initialize." << endl; } if (predictor != 0) { predictors.push_back (predictor); logger << INFO << "Activated predictive predictor: " << predictorName << endl; } else { logger << FATAL << "Unable to initialize predictor: " << predictorName << endl; throw PredictorRegistryException(PRESAGE_INIT_PREDICTOR_ERROR, "Unable to initialize predictor: " + predictorName); } } void PredictorRegistry::removePredictors() { for (size_t i = 0; i < predictors.size(); i++) { logger << DEBUG << "Removing predictor: " << predictors[i]->getName() << endl; delete predictors[i]; } predictors.clear(); } PredictorRegistry::Iterator PredictorRegistry::iterator() { return Iterator(predictors); } //// // Iterator PredictorRegistry::Iterator::Iterator(std::vector& cont) : iter_end(cont.end()), iter_curr(cont.begin()) {} PredictorRegistry::Iterator::~Iterator() {} bool PredictorRegistry::Iterator::hasNext() const { bool result = (iter_end != iter_curr); return result; } Predictor* PredictorRegistry::Iterator::next() { Predictor* result = *iter_curr; iter_curr++; return result; } void PredictorRegistry::update (const Observable* variable) { logger << DEBUG << "About to invoke dispatcher: " << variable->get_name () << " - " << variable->get_value() << endl; dispatcher.dispatch (variable); } presage-0.8.8/src/lib/core/predictorActivator.h0000644000175000017500000001402711763436760016425 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTORACTIVATOR #define PRESAGE_PREDICTORACTIVATOR #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "configuration.h" #include "predictorRegistry.h" #include "context_tracker/contextTracker.h" #include "prediction.h" #include "logger.h" #include "dispatcher.h" #include "combiner.h" #include "meritocracyCombiner.h" #include "predictors/predictor.h" #ifdef STDC_HEADERS # include // needed for abort function #endif /** PredictorActivator, the heart of Presage system, coordinates the execution of predictors and returns the combination of their predictions. * * PredictorActivator starts the execution of the active predictors, * monitors their execution and collects the predictions returned, or * terminates a predictor's execution if it execedes its maximum * prediction time. * * The predictions returned by the individual predictors are combined * into a single prediction by the active Combiner. (please refer to * my thesis for a list of possible conbination strategies. * */ class PredictorActivator : public Observer { public: //PLUMP PredictorActivator(HistoryTracker&, //PLUMP plump::Plump&); /** Construct a PredictorActivator object. * * PredictorActivator needs a reference to the ContextTracker * object to forward to the predictors for context retrieval and * analysis. * * @param config pointer to configuration * @param registry pointer to predictor registry * @param contextTracker pointer to ContextTracker */ PredictorActivator(Configuration* config, PredictorRegistry* registry, ContextTracker* contextTracker); /** Destroy predictor activator. * */ ~PredictorActivator(); /** Runs the predictors, combine their predictions and return the resulting prediction. * * This is the heart of Presage. * * Plump will eventually provide the implementation of sequential or parallel execution of predictors. * * @return prediction produced by the active predictors and combined by the active combiner */ Prediction predict(unsigned int multiplier, const char** filter); /** Set active predictors. * * @param predictorList space separated list of predictors */ void setPredictors(const std::string& predictorList); /** Adds a predictor to the active runtime predictors list. * * @param predictorName predictor name string */ void addPredictor(const std::string& predictorName); /** Removes all predictors from the active predictors list. * */ void removePredictors(); /** Gets PREDICT_TIME option value. * * Returns the maximum time predictors are allowed to execute before * returning a prediction. * * @return value of PREDICT_TIME */ int getPredictTime() const; /** Sets PREDICT_TIME option, the maximum time allowed for a predictor to return its prediction. * * @param predictTime expressed in milliseconds * @return true if the supplied value is valid, false otherwise */ void setPredictTime(const std::string& predictTime); /** Gets COMBINATION_METHOD option value. * * Returns the active combination method used by predictor * activator to combine predictions returned by the active * predictors into one prediction. * * @return value of COMBINATION_METHOD */ std::string getCombinationPolicy() const; /** Sets combination policy. * * Sets the combination policy used by predictor activator to * combine predictions returned by the active predictors into one * prediction. * * The existing combiner object is first destroyed, then a new * combiner object created. * * @param policy combination policy */ void setCombinationPolicy(const std::string& policy); /** Sets maximum partial prediction size. * * @param size maximum partial prediction size */ void setMaxPartialPredictionSize (const std::string& size); /** Sets logger level. * * @param level logger level */ void setLogger (const std::string& level); void parse_internal_commands (Prediction& pred); virtual void update (const Observable* variable); static const char* LOGGER; static const char* PREDICT_TIME; static const char* MAX_PARTIAL_PREDICTION_SIZE; static const char* COMBINATION_POLICY; private: // execute predictor function (invoked in thread) void *execute(void *); Configuration* config; PredictorRegistry* predictorRegistry; ContextTracker* contextTracker; Logger logger; Combiner* combiner; std::string combinationPolicy; int max_partial_prediction_size; std::vector predictions; // predictions computed by each predictor are returned here int predict_time; Dispatcher dispatcher; }; #endif // PRESAGE_PREDICTORACTIVATOR presage-0.8.8/src/lib/core/meritocracyCombiner.cpp0000644000175000017500000000373211737142176017105 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "meritocracyCombiner.h" MeritocracyCombiner::MeritocracyCombiner() {} MeritocracyCombiner::~MeritocracyCombiner() {} /** Combine predictions based on each suggestion's individual merit. * * The merit associated to each suggestion is its probability. The * higher the probability associated with a suggestion, the higher the * merit. * * Of course, this combination strategy might introduce some imbalance * between different predictive methods that calculate probabilities * substantially differently. * */ Prediction MeritocracyCombiner::combine(const std::vector< Prediction >& predictions) { Prediction result; for (std::vector< Prediction >::const_iterator it = predictions.begin(); it != predictions.end(); it++) { for (size_t i = 0; i < it->size(); i++) { result.addSuggestion(it->getSuggestion(i)); } } return filter(result); } presage-0.8.8/src/lib/core/maxEntropyCombiner.h0000644000175000017500000000260711737142176016377 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_MAXENTROPYCOMBINER #define PRESAGE_MAXENTROPYCOMBINER #include "combiner.h" /** Maximum Entropy combiner * */ class MaxEntropyCombiner : public Combiner { private: MaxEntropyCombiner(); ~MaxEntropyCombiner(); public: }; #endif // PRESAGE_MAXENTROPYCOMBINER presage-0.8.8/src/lib/core/profileManager.cpp0000644000175000017500000001760211763437013016035 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "profileManager.h" #include "utility.h" // isYes isNo isTrue isFalse utility function #include "dirs.h" // sysconfdir macro define #include "configuration.h" #ifdef HAVE_PWD_H # include #endif #if HAVE_UNISTD_H # include # include #endif #if HAVE_STDLIB_H # include #endif #if defined(_WIN32) # include #endif const char* ProfileManager::LOGGER = "Presage.ProfileManager.LOGGER"; const char* ProfileManager::AUTOPERSIST = "Presage.ProfileManager.AUTOPERSIST"; /** Constructor. * * Initialises other modules. * */ ProfileManager::ProfileManager(const std::string profilename) : logger("ProfileManager", std::cerr) { config = new Configuration(); loaded_at_least_one_profile = false; rw_profile = 0; autopersist_config = false; init_profiles (profilename); } /** Destructor. * */ ProfileManager::~ProfileManager() { flush_cached_log_messages (); set_autopersist (config->find (AUTOPERSIST)->get_value ()); if (autopersist_config) { save_profile (); } delete config; delete rw_profile; } Profile* ProfileManager::create_profile_from_xml (const std::string& filename) { Profile* profile = new Profile (filename); std::string message; if (profile->file_read_ok ()) { // logger has not been init'd with configuration, because no // profile is known yet, hence caching this logging item, // which will be flushed when configuration is finally read in // message = "Loaded profile: " + filename; cache_log_message(logger.NOTICE, message); } else { // logger has not been init'd with configuration, because no // profile is known yet, hence caching this logging item, // which will be flushed when configuration is finally read in // message = "Failed to load profile: " + filename; cache_log_message(logger.NOTICE, message); } return profile; } void ProfileManager::init_profiles (const std::string& profilename) { std::list profiles; { // load default profile values DefaultProfile default_profile (""); default_profile.read_into_configuration (config); } // system etc directory profiles.push_back (get_system_etc_dir() + '/' + DefaultProfile::DEFAULT_PROFILE_FILENAME); // installation config directory profiles.push_back (static_cast(sysconfdir) + '/' + DefaultProfile::DEFAULT_PROFILE_FILENAME); // home dir dotfile profiles.push_back (get_user_home_dir() + "/.presage/" + DefaultProfile::DEFAULT_PROFILE_FILENAME); // user specified profile (if any) if (! profilename.empty()) { profiles.push_back(profilename); } // read data from each profile and write it to configuration Profile* profile = 0; for (std::list::const_iterator it = profiles.begin(); it != profiles.end(); it++ ) { delete profile; profile = create_profile_from_xml (*it); loaded_at_least_one_profile = loaded_at_least_one_profile || profile->file_read_ok (); profile->read_into_configuration (config); } // remember last profile as writable profile rw_profile = profile; } std::string ProfileManager::get_system_etc_dir() const { std::string result; #if defined(_WIN32) DWORD size; DWORD type; LONG res; HKEY reg_key = NULL; char *dst = NULL; res = RegOpenKeyExA (HKEY_CURRENT_USER, "Software\\Presage", 0, KEY_READ, ®_key); if (res == ERROR_SUCCESS) { size = 64; dst = (char*) malloc (size); res = RegQueryValueExA (reg_key, "", 0, &type, (LPBYTE) dst, &size); if (res == ERROR_MORE_DATA && type == REG_SZ) { dst = (char*) realloc (dst, size); res = RegQueryValueExA (reg_key, "", 0, &type, (LPBYTE) dst, &size); } if (type != REG_SZ || res != ERROR_SUCCESS) { result = "."; } else { result = dst; result += "\\etc"; } free (dst); dst = 0; RegCloseKey (reg_key); } #else result = "/etc"; #endif return result; } std::string ProfileManager::get_user_home_dir() const { std::string result; #ifdef _WIN32 const char* USERPROFILE = "USERPROFILE"; char* value = getenv(USERPROFILE); // check if USERPROFILE env var exists... if (value) { result = value; } #else # ifdef HAVE_PWD_H uid_t me; struct passwd *my_passwd; me = getuid (); my_passwd = getpwuid (me); if (!my_passwd) { // got passwd for user // read home dir from passwd struct result = my_passwd->pw_dir; } else // unable to get passwd struct, // read $HOME env variable # endif // HAVE_PWD_H { const char* HOME = "HOME"; char* value = getenv(HOME); // check if HOME env var exists, // assigning a null pointer to a string is // not such a good idea... if (value) { result = value; } } #endif return result; } /** Write profile to disk. * * Returns true is file was saved successfully, false otherwise. * */ void ProfileManager::save_profile() const { rw_profile->read_from_configuration (config); bool saveOk = rw_profile->write_to_file (); if (! saveOk) { logger << ERROR << "Failed to save configuration to profile " << endl; } } Configuration* ProfileManager::get_configuration() { // since a Profile is being returned, we know we have a valid // configuration object. Here, we obtain a temporary Configuration // object to read the this ProfileManager configuration. We could // not do this during profile manager construction because no // profile was available at that time. // refresh_config(); return config; } void ProfileManager::cache_log_message(Logger::Level level, const std::string& message) { static CachedLogMessage clm; //clm.level = level; clm.message = message; //std::cerr << "Caching message: " << message << std::endl; cached_log_messages.push_back(clm); } void ProfileManager::flush_cached_log_messages() { std::list::const_iterator it = cached_log_messages.begin(); while (it != cached_log_messages.end()) { //std::cerr << "Flushing message: " << it->message << std::endl; logger << NOTICE << it->message << endl; it++; } cached_log_messages.clear(); } void ProfileManager::refresh_config() { try { logger << setlevel(config->find (LOGGER)->get_value()); } catch (Configuration::ConfigurationException& ex) { // if no config is available, turn on full logging for profile // manager logger << setlevel("ALL"); } flush_cached_log_messages(); } void ProfileManager::set_autopersist (const std::string& value) { autopersist_config = Utility::isTrue (value); logger << INFO << "AUTOPERSIST: " << autopersist_config << endl; } presage-0.8.8/src/lib/core/observable.h0000644000175000017500000000321411737142176014671 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_OBSERVABLE #define PRESAGE_OBSERVABLE #if HAVE_CONFIG_H # include "config.h" #endif #include "observer.h" #include #include class Observable { public: virtual ~Observable (); virtual void attach (Observer* observer); virtual void detach (Observer* observer); virtual void notify (); virtual std::string get_name () const = 0; virtual std::string get_value () const = 0; protected: Observable (); private: std::list observers; }; #endif // PRESAGE_OBSERVABLE presage-0.8.8/src/lib/core/dispatcher.cpp0000644000175000017500000000224611737142176015232 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "dispatcher.h" // intentionally empty, template class presage-0.8.8/src/lib/core/defaultProfile.h0000644000175000017500000000331011743227551015505 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_DEFAULTPROFILE #define PRESAGE_DEFAULTPROFILE #include "profile.h" /** Default profile. * */ class DefaultProfile : public Profile { public: /** Profile constructor. * * \param filename where profile is saved to */ DefaultProfile(const std::string& filename); /** Profile destructor. * * Destructor deallocates the Configuration object passed in costructor. * */ ~DefaultProfile(); static const char* DEFAULT_PROFILE_FILENAME; private: void build_xml_document (const std::string&); }; #endif // PRESAGE_DEFAULTPROFILE presage-0.8.8/src/lib/core/linearCombiner.h0000644000175000017500000000254611737142176015505 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_LINEARCOMBINER #define PRESAGE_LINEARCOMBINER #include "combiner.h" /** Linear combiner * */ class LinearCombiner : public Combiner { public: LinearCombiner(); ~LinearCombiner(); private: }; #endif // PRESAGE_LINEARCOMBINER presage-0.8.8/src/lib/core/profile.h0000644000175000017500000000647011737142176014214 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PROFILE #define PRESAGE_PROFILE #include "config.h" #include #include #include #include typedef std::string Value; #include "configuration.h" #include "presageException.h" /** Profile provides access to the active profile configuration variables. * * Profile only provides an accessor method to read configuration * values. The class is immutable. It is not possible to modify * configuration values. Configuration values are set when the Profile * is constructed. * * Profile acts as an interface to ProfileManager. It converts simple * requests for configuration variable values from client objects * (such as Plugin objects) into requests to ProfileManager. There is * no need to have a map containing the variable, value pairs. It is * sufficient to keep a reference to ProfileManager and have * ProfileManager expose an interface that Profile can use to query * variable values. * */ class Profile { public: /** Profile constructor. * * \param filename where profile is saved to */ Profile(const std::string& filename); /** Profile destructor. * * Destructor deallocates the Configuration object passed in costructor. * */ virtual ~Profile(); /** Writes configuration from XML DOM document into configuration. * */ void read_into_configuration(Configuration* configuration); /* Reads from configuration and writes to XML DOM document. * */ void read_from_configuration (Configuration* configuration); bool file_read_ok () const; bool write_to_file () const; class ProfileException : public PresageException { public: ProfileException(presage_error_code_t code, const std::string& desc) throw() : PresageException(code, desc) { } virtual ~ProfileException() throw() { } private: ProfileException() throw() : PresageException(PRESAGE_ERROR, "") { } }; protected: void init_configuration(Configuration* config, TiXmlDocument* node); void visit_node(Configuration* config, TiXmlNode* node, std::vector variable); TiXmlDocument* xmlProfileDoc; std::string xml_filename; bool xml_profile_read_ok; }; #endif // PRESAGE_PROFILE presage-0.8.8/src/lib/core/tokenizer/0000755000175000017500000000000011764714755014476 500000000000000presage-0.8.8/src/lib/core/tokenizer/stringForwardTokenizer.h0000644000175000017500000000356111737142176021312 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_STRINGFORWARDTOKENIZER #define PRESAGE_STRINGFORWARDTOKENIZER #include "forwardTokenizer.h" class StringForwardTokenizer : public ForwardTokenizer { public: StringForwardTokenizer(std::string& toBeTokenized, const std::string blankspaces, const std::string separators); virtual ~StringForwardTokenizer(); // /** Returns the number of tokens left. // */ // virtual int countTokens(); // // /** Tests if there are more tokens. // */ // virtual bool hasMoreTokens() const; // // /** Returns the next token. // */ // virtual std::string nextToken(); // // /** Returns progress percentage. // */ // virtual double progress() const; protected: private: }; #endif // PRESAGE_STRINGFORWARDTOKENIZER presage-0.8.8/src/lib/core/tokenizer/forwardTokenizer.h0000644000175000017500000000371011737142176020117 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_FORWARDTOKENIZER #define PRESAGE_FORWARDTOKENIZER #include "tokenizer.h" /** Tokenizes a stream from the beginning to the end. * _ _ _ _ _ _ _ * |_|_|_|_|_|_|_| * | | | * | | offend * | offset * offbeg */ class ForwardTokenizer : public Tokenizer { public: ForwardTokenizer(std::istream& stream, const std::string blankspaces, const std::string separators); virtual ~ForwardTokenizer(); /** Returns the number of tokens left. */ virtual int countTokens(); /** Tests if there are more tokens. */ virtual bool hasMoreTokens() const; /** Returns the next token. */ virtual std::string nextToken(); /** Returns progress percentage. */ virtual double progress() const; protected: private: }; #endif // PRESAGE_FORWARDTOKENIZER presage-0.8.8/src/lib/core/tokenizer/reverseTokenizer.h0000644000175000017500000000370311737142176020130 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_REVERSETOKENIZER #define PRESAGE_REVERSETOKENIZER #include "tokenizer.h" /** Tokenizes a stream from the end to the beginning. * _ _ _ _ _ _ _ * |_|_|_|_|_|_|_| * | | | * | | offend * | offset * offbeg */ class ReverseTokenizer : public Tokenizer { public: ReverseTokenizer(std::istream& stream, const std::string blanks, const std::string separs); virtual ~ReverseTokenizer(); /** Returns the number of tokens left. */ virtual int countTokens(); /** Tests if there are more tokens. */ virtual bool hasMoreTokens() const; /** Returns the next token. */ virtual std::string nextToken(); /** Returns progress percentage. */ virtual double progress() const; protected: private: }; #endif // PRESAGE_REVERSETOKENIZER presage-0.8.8/src/lib/core/tokenizer/Makefile.am0000644000175000017500000000266211737142176016450 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in noinst_LTLIBRARIES = libtokenizer.la libtokenizer_la_SOURCES = tokenizer.h \ tokenizer.cpp \ forwardTokenizer.h \ forwardTokenizer.cpp \ reverseTokenizer.h \ reverseTokenizer.cpp \ stringForwardTokenizer.h \ stringForwardTokenizer.cpp # streamBufferTokenizer.h \ # streamBufferTokenizer.cpp \ # fileTokenizer.h \ # fileTokenizer.cpp AM_CPPFLAGS = -I$(top_srcdir)/src presage-0.8.8/src/lib/core/tokenizer/Makefile.in0000644000175000017500000004161211763440355016456 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib/core/tokenizer DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtokenizer_la_LIBADD = am_libtokenizer_la_OBJECTS = tokenizer.lo forwardTokenizer.lo \ reverseTokenizer.lo stringForwardTokenizer.lo libtokenizer_la_OBJECTS = $(am_libtokenizer_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libtokenizer_la_SOURCES) DIST_SOURCES = $(libtokenizer_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LTLIBRARIES = libtokenizer.la libtokenizer_la_SOURCES = tokenizer.h \ tokenizer.cpp \ forwardTokenizer.h \ forwardTokenizer.cpp \ reverseTokenizer.h \ reverseTokenizer.cpp \ stringForwardTokenizer.h \ stringForwardTokenizer.cpp # streamBufferTokenizer.h \ # streamBufferTokenizer.cpp \ # fileTokenizer.h \ # fileTokenizer.cpp AM_CPPFLAGS = -I$(top_srcdir)/src all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/core/tokenizer/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lib/core/tokenizer/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtokenizer.la: $(libtokenizer_la_OBJECTS) $(libtokenizer_la_DEPENDENCIES) $(CXXLINK) $(libtokenizer_la_OBJECTS) $(libtokenizer_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/forwardTokenizer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reverseTokenizer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringForwardTokenizer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokenizer.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am # 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: presage-0.8.8/src/lib/core/tokenizer/tokenizer.h0000644000175000017500000001115711737142176016576 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_TOKENIZER #define PRESAGE_TOKENIZER #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include /** The Tokenizer class takes an input stream and parses it into "tokens", allowing the tokens to be read one at a time. * * The parsing process is controlled by the character classification * sets: * * - blankspace characters: characters that mark a token boundary and * are not part of the token. * * - separator characters: characters that mark a token boundary and * might be considered tokens, depending on the * value of a flag (to be implemented). * * - valid characters: any non blankspace and non separator character. * * Each byte read from the input stream is regarded as a character in * the range '\\u0000' through '\\u00FF'. * * In addition, an instance has flags that control: * * - whether the characters of tokens are converted to lowercase. * - whether separator characters constitute tokens. (TBD) * * A typical application first constructs an instance of this class, * supplying the input stream to be tokenized, the set of blankspaces, * and the set of separators, and then repeatedly loops, while method * hasMoreTokens returns true, calling the nextToken method. */ class Tokenizer { public: Tokenizer(std::istream& stream, const std::string blankspaces, const std::string separators ); virtual ~Tokenizer(); /** Returns the number of tokens left. */ virtual int countTokens() = 0; /** Tests if there are more tokens. */ virtual bool hasMoreTokens() const = 0; /** Returns the next token. */ virtual std::string nextToken() = 0; /** Returns progress percentage. */ virtual double progress() const = 0; /** Sets blankspace characters. */ void blankspaceChars(const std::string); /** Gets blankspace characters. */ std::string blankspaceChars() const; /** Sets separator characters. */ void separatorChars(const std::string); /** Gets separator characters. */ std::string separatorChars() const; /** Sets lowercase mode. */ void lowercaseMode(const bool); /** Gets lowercase mode. */ bool lowercaseMode() const; std::string streamToString() const { std::streamoff offbackup = stream.tellg(); std::string str; std::streamoff curroff = offbeg; stream.seekg(curroff); while (curroff < offend) { stream.clear(); str.push_back(stream.peek()); curroff++; stream.seekg(curroff); } stream.seekg(offbackup); return str; } protected: class StreamGuard { public: StreamGuard(std::istream& so, std::streamoff& of) : guardedStream(so) { currstate = guardedStream.rdstate(); curroff = guardedStream.tellg(); guardedStream.seekg (of ); } ~StreamGuard() { guardedStream.seekg (curroff ); guardedStream.setstate(currstate); } private: std::istream& guardedStream; std::ios::iostate currstate; std::streamoff curroff; }; std::istream& stream; std::ios::iostate sstate; std::streamoff offbeg; std::streamoff offend; std::streamoff offset; bool isBlankspace(const int character) const; bool isSeparator (const int character) const; private: std::string blankspaces; std::string separators; bool lowercase; }; #endif // PRESAGE_TOKENIZER presage-0.8.8/src/lib/core/tokenizer/forwardTokenizer.cpp0000644000175000017500000000743611737142176020463 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "forwardTokenizer.h" ForwardTokenizer::ForwardTokenizer(std::istream& stream, const std::string blankspaces, const std::string separators) : Tokenizer(stream, blankspaces, separators) { //std::cerr << "ForwardTokenizer::ForwardTokenizer()" << std::endl; offset = offbeg; } ForwardTokenizer::~ForwardTokenizer() {} int ForwardTokenizer::countTokens() { StreamGuard guard(stream, offset); // store current seek pointer position std::streamoff curroff = offset; // position get pointer at beginning of stream offset = offbeg; int count = 0; while (hasMoreTokens()) { count++; nextToken(); } // reposition seek get pointer to original position offset = curroff; return count; } bool ForwardTokenizer::hasMoreTokens() const { //StreamGuard guard(stream, offset); if (offset >= offend) { return false; } else { return true; } } std::string ForwardTokenizer::nextToken() { StreamGuard guard(stream, offset); int current; std::string str; if (stream.good()) { // good() if bad,fail and eof bit are not set current = stream.peek(); if (offset < offend) { while (isBlankspace(current) || isSeparator(current)) { offset++; stream.seekg(offset); current = stream.peek(); } while (!isBlankspace(current) && !isSeparator(current) && offset < offend) { //std::cerr << "[DEBUG] read: " // << static_cast(current) // << std::endl; if( lowercaseMode() ) { current = tolower( current ); } str.push_back(current); //std::cerr << "[DEBUG] pushed: " // << static_cast(current) // << std::endl; offset++; stream.seekg(offset); current = stream.peek(); } } // do { // do { // current = stream.peek(); // offset++; // stream.seekg(offset); // // //std::cerr << "[DEBUG] read: " // // << static_cast(current) // // << std::endl; // // if ( !isBlankspace(current) // && !isSeparator(current) // && offset <= offend) { // // if( lowercaseMode() ) { // current = tolower( current ); // } // // str.push_back(current); // // //std::cerr << "[DEBUG] pushed: " // // << static_cast(current) // // << std::endl; // } // } while ( !isBlankspace(current) // && !isSeparator(current) // && offset < offend); // } while (str.empty() && (offset < offend)); } else { std::cerr << "stream is NOT good!" << std::endl; } //std::cerr << "[DEBUG] token: " << str << std::endl; return str; } double ForwardTokenizer::progress() const { return static_cast(offset) / offend; } presage-0.8.8/src/lib/core/tokenizer/stringForwardTokenizer.cpp0000644000175000017500000000270011737142176021637 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "stringForwardTokenizer.h" #include StringForwardTokenizer::StringForwardTokenizer(std::string& str, const std::string blankspaces, const std::string separators ) : ForwardTokenizer(*(new std::stringstream(str)), blankspaces, separators) {} StringForwardTokenizer::~StringForwardTokenizer() {} presage-0.8.8/src/lib/core/tokenizer/reverseTokenizer.cpp0000644000175000017500000001160011737142176020456 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "reverseTokenizer.h" ReverseTokenizer::ReverseTokenizer(std::istream& stream, const std::string blanks, const std::string separs) : Tokenizer(stream, blanks, separs) { offset = offend; //assert( stream.good()); //assert(!stream.fail()); //assert(!stream.bad() ); //assert(!stream.eof() ); // stream clearing needed because offset is positioned at end stream.clear(); //std::cerr << "ReverseTokenizer::ReverseTokenizer() offbeg: " << offbeg // << " offset: " << offset << " offend: " << offend << std::endl; } ReverseTokenizer::~ReverseTokenizer() {} int ReverseTokenizer::countTokens() { StreamGuard guard(stream, offset); // store current seek pointer position std::streamoff curroff = offset; // position get pointer at end of stream offset = offend; int count = 0; while (hasMoreTokens()) { nextToken(); count++; } // reposition seek get pointer to original position offset = curroff; return count; } bool ReverseTokenizer::hasMoreTokens() const { //std::cerr << "ReverseTokenizer::hasMoreTokens() offbeg: " << offbeg // << " offset: " << offset << " offend: " << offend << std::endl; if (offbeg < offset) { return true; } else { return false; } } std::string ReverseTokenizer::nextToken() { StreamGuard guard(stream, offset); int current; std::string str; if (stream.good()) { while (offbeg < offset && str.empty()) { stream.seekg(offset - 1); current = stream.peek(); if (offset == offend && (isSeparator(current) || isBlankspace(current))) { offset--; return str; } while ((isBlankspace(current) || isSeparator(current)) && offbeg < offset ) { offset--; stream.seekg(offset - 1); current = stream.peek(); } while (!isBlankspace(current) && !isSeparator(current) && offbeg < offset) { if( lowercaseMode() ) { current = tolower( current ); } // since the token is read backwards, the string // needs to be reversed by inserting the char at // the front str.insert(str.begin(), current); offset--; stream.seekg(offset - 1); current = stream.peek(); } } } // if (stream.good()) { // do { // do { // current = stream.peek(); // offset--; // stream.seekg(offset); // // // handle case where last character is a separator by // // returning an empty token // if (offset == offend - 2 // && isSeparator(current)) { // return ""; // } // // //std::cerr << "[DEBUG] read: " // // << static_cast(current) // // << std::endl; // // if (!isBlankspace(current) // && !isSeparator(current) // && offset >= offbeg - 1) { // // if( lowercaseMode() ) { // current = tolower( current ); // } // // // since the token is read backwards, the string // // needs to be reversed by inserting the char at // // the front // str.insert(str.begin(), current); // // //std::cerr << "[DEBUG] pushed: " // // << static_cast(current) // // << std::endl; // //std::cerr << "[DEBUG] partial string: " // // << str << std::endl; // } // } while (!isBlankspace(current) // && !isSeparator(current) // && (offset >= offbeg)); // } while (str.empty() && (offset >= offbeg)); // } //std::cerr << "[DEBUG] token: " << str << std::endl; return str; } double ReverseTokenizer::progress() const { return static_cast(offend - offset) / (offend - offbeg); } presage-0.8.8/src/lib/core/tokenizer/tokenizer.cpp0000644000175000017500000000533011753247310017117 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "tokenizer.h" Tokenizer::Tokenizer( std::istream& is, const std::string blankspaces, const std::string separators ) : stream(is), lowercase(false) { // this should be changed to deal with a !good() stream // appropriately //assert(stream.good()); offset = stream.tellg(); sstate = stream.rdstate(); StreamGuard(stream, offset); stream.seekg(0, std::ios::end); offend = stream.tellg(); stream.seekg(0, std::ios::beg); offbeg = stream.tellg(); blankspaceChars(blankspaces); separatorChars (separators ); } Tokenizer::~Tokenizer() { // reset stream state to enable repeatability // (see reverseTokenizerTest::testRepeatability()) stream.setstate(sstate); stream.clear(); } void Tokenizer::blankspaceChars(const std::string chars) { blankspaces = chars; } std::string Tokenizer::blankspaceChars() const { return blankspaces; } void Tokenizer::separatorChars(const std::string chars) { separators = chars; } std::string Tokenizer::separatorChars() const { return separators; } void Tokenizer::lowercaseMode(const bool value) { lowercase = value; } bool Tokenizer::lowercaseMode() const { return lowercase; } bool Tokenizer::isBlankspace(const int character) const { std::string::size_type ret = blankspaces.find(character); if (ret == std::string::npos) { return false; } else { return true; } } bool Tokenizer::isSeparator(const int character) const { std::string::size_type ret = separators.find(character); if (ret == std::string::npos) { return false; } else { return true; } } presage-0.8.8/src/lib/core/Makefile.am0000644000175000017500000000403211743227551014425 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = \ tokenizer \ context_tracker noinst_LTLIBRARIES = \ libcore.la libcore_la_SOURCES = \ prediction.cpp \ prediction.h \ suggestion.cpp \ suggestion.h \ utility.cpp \ utility.h \ iso8859_1.h \ charsets.h \ observable.cpp \ observable.h \ observer.cpp \ observer.h \ dispatcher.h \ dispatcher.cpp \ predictorActivator.cpp \ predictorActivator.h \ combiner.h \ combiner.cpp \ meritocracyCombiner.h \ meritocracyCombiner.cpp \ linearCombiner.h \ backoffCombiner.h \ maxEntropyCombiner.h \ selector.cpp \ selector.h \ variable.cpp \ variable.h \ configuration.cpp \ configuration.h \ profile.cpp \ profile.h \ defaultProfile.cpp \ defaultProfile.h \ profileManager.cpp \ profileManager.h \ logger.cpp \ logger.h \ presageException.cpp \ ../presageException.h \ predictorRegistry.cpp \ predictorRegistry.h \ progress.cpp \ progress.h libcore_la_LIBADD = \ tokenizer/libtokenizer.la \ context_tracker/libcontexttracker.la libcore_la_CPPFLAGS = -I$(top_srcdir)/src/lib if BUILD_TINYXML libcore_la_CPPFLAGS += -I$(top_srcdir)/src/lib/tinyxml endif presage-0.8.8/src/lib/core/dispatcher.h0000644000175000017500000000500511737142176014673 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_DISPATCHER #define PRESAGE_DISPATCHER #if HAVE_CONFIG_H # include #endif #include #include #include #include "observable.h" /** Dispatches observable notifications. * */ template class Dispatcher { public: typedef void (class_t::* mbr_func_ptr_t) (const std::string& value); typedef std::map dispatch_map_t; Dispatcher(class_t* obj) { object = obj; } ~Dispatcher() { for (std::list::iterator it = observables.begin(); it != observables.end(); it++) { (*it)->detach (object); } } void map (Observable* var, const mbr_func_ptr_t& ptr) { var->attach (object); observables.push_back (var); dispatch_map[var->get_name ()] = ptr; dispatch (var); //std::cerr << "[Dispatcher] mapped " << var->string() << " => " // << object << "->" << ptr << std::endl; } void dispatch (const Observable* var) { mbr_func_ptr_t handler_ptr = dispatch_map[var->get_name ()]; if (handler_ptr) { ((object)->*(handler_ptr)) (var->get_value ()); } else { std::cerr << "[Dispatcher] Unable to handle notification from observable: " << var->get_name () << " - " << var->get_value() << std::endl; } } private: class_t* object; dispatch_map_t dispatch_map; std::list observables; }; #endif // PRESAGE_DISPATCHER presage-0.8.8/src/lib/core/variable.h0000644000175000017500000000407011737142176014333 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_VARIABLE #define PRESAGE_VARIABLE #include #include #include "observable.h" class Variable : public Observable { public: Variable(const char* variable); Variable(const std::string& variable); Variable(const std::vector& variable); ~Variable(); std::string get_name () const; std::vector get_name_vector () const; std::string get_value () const; void set_value (std::string value); size_t size() const { return m_name_vector.size(); } bool operator<(const Variable& other) const { return (get_name () < other.get_name ()); } static std::vector string_to_vector(const std::string& str); static std::string vector_to_string(const std::vector& var); private: std::string m_name; std::vector m_name_vector; std::string m_value; }; #endif // PRESAGE_VARIABLE presage-0.8.8/src/lib/core/utility.cpp0000644000175000017500000001363411763437013014606 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "utility.h" #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_DIRENT_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif /** Convert string to lower case * */ char* Utility::strtolower(char* str) { for(int i = 0; str[i] != '\0'; i++) str[i] = tolower (str[i]); return str; } /** Convert string to lower case * */ std::string& Utility::strtolower(std::string& str) { for(std::string::iterator i = str.begin(); i != str.end(); i++ ) *i = tolower( *i ); return str; } /** Returns a lower case copy of a string * */ std::string Utility::strtolower(const std::string& str) { std::string lowstr = str; for(std::string::iterator i = lowstr.begin(); i != lowstr.end(); i++ ) *i = tolower( *i ); return lowstr; } /** Convert string to upper case * */ std::string Utility::strtoupper(const std::string& str) { std::string upstr = str; for(std::string::iterator i = upstr.begin(); i != upstr.end(); i++ ) *i = toupper( *i ); return upstr; } /** Is string either true or false * */ bool Utility::isTrueFalse(const char* str) { // TODO: manage yes/no with gettext? return (isTrue (str) || isFalse (str)); } /** Is string True * */ bool Utility::isTrue(const char* str) { bool result = false; char* workingStr = new char[strlen (str) + 1]; strcpy (workingStr, str); std::string lowstr = strtolower (workingStr); if( lowstr == "true" || lowstr == "1" ) result = true; delete[] workingStr; return result; } /** Is string False * */ bool Utility::isFalse(const char* str) { bool result = false; char* workingStr = new char[strlen(str) + 1]; strcpy (workingStr, str); std::string lowstr = strtolower (workingStr); if( lowstr == "false" || lowstr == "0" ) result = true; delete[] workingStr; return result; } /** Is string True * */ bool Utility::isTrue(const std::string& str) { return isTrue( str.c_str() ); } /** Is string False * */ bool Utility::isFalse(const std::string& str) { return isFalse( str.c_str() ); } /** Is string either true or false * */ bool Utility::isTrueFalse( const std::string& str ) { return isTrueFalse( str.c_str() ); } /** Is string either yes or no * */ bool Utility::isYesNo(const char* str) { return (isYes (str) || isNo (str)); } /** Is string Yes * */ bool Utility::isYes( const char* str ) { bool result = false; char* workingStr = new char[strlen(str) + 1]; strcpy (workingStr, str); std::string lowstr = strtolower (workingStr); if( lowstr == "yes" || lowstr == "yeah" || lowstr == "ye" || lowstr == "true") result = true; delete[] workingStr; return result; } /** Is string No * */ bool Utility::isNo( const char* str ) { bool result = false; char* workingStr = new char[strlen(str) + 1]; strcpy (workingStr, str); std::string lowstr = strtolower (workingStr); if( lowstr == "no" || lowstr == "nope" || lowstr == "nah" || lowstr == "nay" || lowstr == "false") result = true; delete[] workingStr; return result; } /** Is string either yes or no * */ bool Utility::isYesNo(const std::string& str) { return isYesNo (str.c_str()); } /** Is string Yes * */ bool Utility::isYes( const std::string& str ) { return isYes (str.c_str()); } /** Is string No * */ bool Utility::isNo(const std::string& str) { return isNo (str.c_str()); } /** Convert string to double. * */ double Utility::toDouble(const std::string str) { return atof(str.c_str()); } /** Convert string to int. * */ int Utility::toInt(const std::string str) { return atoi(str.c_str()); } /** Return directory name from filepath * */ std::string Utility::dirname (const std::string& filepath) { std::string result; std::string::size_type pos = filepath.find_last_of ("\\/"); if (std::string::npos != pos) { result = filepath.substr (0, pos); } return result; } /** Return file name from filepath * */ std::string Utility::filename (const std::string& filepath) { std::string result; std::string::size_type pos = filepath.find_last_of ("\\/"); if (std::string::npos != pos) { result = filepath.substr (pos + 1); } return result; } /** Attempt to open directory and return true if successful * */ bool Utility::is_directory_usable (const std::string& dir) { DIR *dp; #ifdef HAVE_DIRENT_H dp = opendir (dir.c_str()); if (dp != NULL) { closedir (dp); return true; } else { return false; } #else return true; #endif } /** Create directory * */ void Utility::create_directory (const std::string& dir) { #ifdef HAVE_SYS_STAT_H mkdir (dir.c_str() #ifndef _WIN32 , S_IRWXU #endif ); #endif } presage-0.8.8/src/lib/core/context_tracker/0000755000175000017500000000000011764714755015663 500000000000000presage-0.8.8/src/lib/core/context_tracker/contextChangeDetector.cpp0000644000175000017500000002065711763437013022571 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "contextChangeDetector.h" #include "../tokenizer/reverseTokenizer.h" #include #include #include // for atoi() #include const std::string::size_type ContextChangeDetector::DEFAULT_SLIDING_WINDOW_SIZE = 80; ContextChangeDetector::ContextChangeDetector(const std::string wChars, const std::string tChars, const std::string bChars, const std::string cChars, bool lowercase) : wordChars (wChars), separatorChars (tChars), blankspaceChars(bChars), controlChars (cChars), lowercase_mode (lowercase) { // intentionally empty } ContextChangeDetector::~ContextChangeDetector() { // intentionally empty } void ContextChangeDetector::set_sliding_window_size(const std::string& str) { if(!str.empty()) { SLIDING_WINDOW_SIZE = atoi(str.c_str()); } else { SLIDING_WINDOW_SIZE = DEFAULT_SLIDING_WINDOW_SIZE; } } void ContextChangeDetector::update_sliding_window(const std::string& str) { if (str.size() <= SLIDING_WINDOW_SIZE) { // past stream fits in sliding window sliding_window = str; } else { // trim past stream down to sliding window sliding_window = str.substr(str.size() - SLIDING_WINDOW_SIZE); assert(sliding_window.size() == SLIDING_WINDOW_SIZE); } } bool ContextChangeDetector::context_change(const std::string& past_stream) const { // Here's how this is going to be implemented... We'll keep a // sliding window on the last few chars seen by presage; the // buffer holding them is the sliding window. We'll search for the // last occurence of sliding_window in past_stream, if any. // If sliding_window is not found in past_stream, then it is not // possible to relate the current context to the previously seen // context, hence we assume a context change has occured. // If sliding_window is found, then we need to examine the chars // following the sliding window in the past stream. We call this // the remainder. If there are any non-word chars in the // remainder, then a context change has occurred. Else, no context // change occured. // The sliding window is never implicitly updated as part of // invoking this method. return context_change_helper(sliding_window, past_stream); } bool ContextChangeDetector::context_change_helper(const std::string& prev_context, const std::string& curr_context) const { bool result = false; if (prev_context.empty()) { if (curr_context.empty()) { // both contexts are empty, nothing has happened, no // change happened result = false; } else { // current context changed, previous context is empty, // first change happened result = true; } } else { // find position of previous context in current context // i.e. find index pointing to last char of last occurence of // prev_context in curr_context std::string::size_type ctx_idx = curr_context.rfind(prev_context); if (ctx_idx == std::string::npos) { // prev_context could not be found in curr_context, a lot // changed result = true; } else { // found prev_context, examine remainder string. // remainder string is substr(ctx_idx + // prev_context.size()); i.e. substring given by index // returned by rfind (which points at beginning of // prev_context string found in curr_context) plus size of // prev_context: this index points at end of prev_context // substring found in curr_context std::string remainder = curr_context.substr(ctx_idx + prev_context.size()); std::string::size_type idx = remainder.find_last_of(wordChars); if (idx == std::string::npos) { if (remainder.empty()) { result = false; } else { char last_char = curr_context[ctx_idx + prev_context.size() - 1]; idx = wordChars.find(last_char); if (idx == std::string::npos) { result = false; } else { result = true; } } } else { if (idx == remainder.size() - 1) { result = false; } else { result = true; } } /* * alternate implementation of the logic in the enclosing else * block. This uses tokenizers, which is not desirable as it makes * tokenizer a dependency of context change detector. std::string remainder = curr_context.substr(loc + prev_context.size()); std::stringstream curr_strstream(curr_context); std::stringstream prev_strstream(prev_context); ReverseTokenizer curr_tokenizer(curr_strstream, blankspaceChars, separatorChars); ReverseTokenizer prev_tokenizer(prev_strstream, blankspaceChars, separatorChars); std::string prev_token = prev_tokenizer.nextToken(); std::string curr_token = curr_tokenizer.nextToken(); if (curr_token.empty()) { if (prev_token.empty()) { result = false; loc = curr_context.find_first_of(wordChars, loc); if (loc == std::string::npos) { result = false; } else { result = true; } } else { result = true; } } else { loc = curr_token.find(prev_token); if (loc == std::string::npos) { result = true; } else { result = false; } } */ } } return result; } std::string ContextChangeDetector::change(const std::string& past_stream) const { const std::string& prev_context = sliding_window; // let's rename these const std::string& curr_context = past_stream; // for clarity's sake std::string result; if (sliding_window.empty()) { result = past_stream; } else { // find position of previous context in current context // i.e. find index pointing to last char of last occurence of // prev_context in curr_context std::string::size_type ctx_idx = curr_context.rfind(prev_context); if (ctx_idx == std::string::npos) { // prev_context could not be found in curr_context, a lot // changed result = past_stream; } else { // found prev_context, examine remainder string. // remainder string is substr(ctx_idx + // prev_context.size()); i.e. substring given by index // returned by rfind (which points at beginning of // prev_context string found in curr_context) plus size of // prev_context: this index points at end of prev_context // substring found in curr_context result = curr_context.substr(ctx_idx + prev_context.size()); // handle case where a context change has occured and // remainder string only contains part of the last token, // i.e.: // // sliding_window = "The quick bro"; // past_stream = "The quick brown "; // // In this case, the remainder will only contain "wn", and // the last token in the sliding window must be prepended // to the change to be learnt // if (context_change(past_stream)) { // prepend partially entered token to change if it // exists, need to look into sliding_window to get // previously partially entered token if it exists std::stringstream sliding_window_stream; sliding_window_stream << get_sliding_window(); ReverseTokenizer rTok(sliding_window_stream, blankspaceChars, separatorChars); rTok.lowercaseMode(lowercase_mode); std::string first_token = rTok.nextToken(); if (!first_token.empty()) { result = first_token + result; } } } } return result; } std::string ContextChangeDetector::get_sliding_window() const { return sliding_window; } presage-0.8.8/src/lib/core/context_tracker/contextChangeDetector.h0000644000175000017500000000436311763437013022232 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CONTEXTCHANGEDETECTOR #define PRESAGE_CONTEXTCHANGEDETECTOR #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "../configuration.h" class ContextChangeDetector { public: ContextChangeDetector(const std::string, const std::string, const std::string, const std::string, bool); ~ContextChangeDetector(); bool context_change(const std::string& past_stream) const; std::string change(const std::string& past_stream) const; std::string get_sliding_window() const; void set_sliding_window_size(const std::string& str); void update_sliding_window(const std::string& str); private: bool context_change_helper(const std::string& str1, const std::string& str2) const; static const std::string::size_type DEFAULT_SLIDING_WINDOW_SIZE; std::string::size_type SLIDING_WINDOW_SIZE; std::string sliding_window; const std::string wordChars; const std::string separatorChars; const std::string blankspaceChars; const std::string controlChars; bool lowercase_mode; }; #endif // PRESAGE_CONTEXTCHANGEDETECTOR presage-0.8.8/src/lib/core/context_tracker/Makefile.am0000644000175000017500000000217311737142176017632 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in noinst_LTLIBRARIES = \ libcontexttracker.la libcontexttracker_la_SOURCES = \ contextTracker.cpp \ contextTracker.h \ contextChangeDetector.cpp \ contextChangeDetector.h presage-0.8.8/src/lib/core/context_tracker/contextTracker.cpp0000644000175000017500000002266211763437013021303 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "contextTracker.h" #include "../utility.h" #include "../predictorRegistry.h" #include "../tokenizer/forwardTokenizer.h" #include // for atoi() const char* ContextTracker::LOGGER = "Presage.ContextTracker.LOGGER"; const char* ContextTracker::SLIDING_WINDOW_SIZE = "Presage.ContextTracker.SLIDING_WINDOW_SIZE"; const char* ContextTracker::LOWERCASE_MODE = "Presage.ContextTracker.LOWERCASE_MODE"; ContextTracker::ContextTracker(Configuration* config, PredictorRegistry* registry, PresageCallback* callback, const char wChars[], const char tChars[], const char bChars[], const char cChars[]) : wordChars (wChars), separatorChars (tChars), blankspaceChars(bChars), controlChars (cChars), predictorRegistry (registry), logger ("ContextTracker", std::cerr), //tokenizer (pastStream, blankspaceChars, separatorChars), lowercase_mode (true), dispatcher (this) { if (callback) { context_tracker_callback = callback; } else { throw new PresageException(PRESAGE_INVALID_CALLBACK_ERROR, "Invalid callback object"); } contextChangeDetector = new ContextChangeDetector(wordChars, separatorChars, blankspaceChars, controlChars, lowercase_mode); // set pointer to this context tracker in predictor registry so that // predictors can be constructed when next iterator is requested // if (predictorRegistry) { predictorRegistry->setContextTracker(this); } // build dispatch map dispatcher.map (config->find (LOGGER), & ContextTracker::set_logger); dispatcher.map (config->find (SLIDING_WINDOW_SIZE), & ContextTracker::set_sliding_window_size); dispatcher.map (config->find (LOWERCASE_MODE), & ContextTracker::set_lowercase_mode); } ContextTracker::~ContextTracker() { delete contextChangeDetector; } void ContextTracker::set_logger (const std::string& value) { logger << setlevel (value); logger << INFO << "LOGGER: " << value << endl; } void ContextTracker::set_sliding_window_size (const std::string& value) { contextChangeDetector->set_sliding_window_size (value); logger << INFO << "SLIDING_WINDOWS_SIZE: " << value << endl; } void ContextTracker::set_lowercase_mode (const std::string& value) { lowercase_mode = Utility::isYes(value); logger << INFO << "LOWERCASE_MODE: " << value << endl; } const PresageCallback* ContextTracker::callback(const PresageCallback* new_callback) { const PresageCallback* result = context_tracker_callback; if (new_callback) { context_tracker_callback = new_callback; } return result; } /** Returns true if a context change occured. * */ bool ContextTracker::contextChange() { return contextChangeDetector->context_change(getPastStream()); } void ContextTracker::update() { // the first step in the update procedure is to learn from the // newly entered text. std::stringstream change; // detect change that needs to be learned change << contextChangeDetector->change(getPastStream()); logger << INFO << "update(): change: " << change.str() << endl; // split change up into tokens std::vector change_tokens; ForwardTokenizer tok(change, blankspaceChars, separatorChars); tok.lowercaseMode(lowercase_mode); logger << INFO << "update(): tokenized change: "; while (tok.hasMoreTokens()) { std::string token = tok.nextToken(); change_tokens.push_back(token); logger << INFO << token << '|'; } logger << INFO << endl; if (! change_tokens.empty()) { // remove prefix (partially entered token or empty token) change_tokens.pop_back(); } logger << INFO << "update(): sanitized change tokens: "; for (std::vector::const_iterator it = change_tokens.begin(); it != change_tokens.end(); it++) { logger << INFO << *it << '|'; } logger << INFO << endl; // time to learn PredictorRegistry::Iterator it = predictorRegistry->iterator(); Predictor* predictor = 0; while (it.hasNext()) { predictor = it.next(); predictor->learn(change_tokens); } // update sliding window contextChangeDetector->update_sliding_window(getPastStream()); } std::string ContextTracker::getPrefix() const { return getToken(0); } std::string ContextTracker::getToken(const int index) const { std::stringstream pastStringStream(context_tracker_callback->get_past_stream()); ReverseTokenizer tokenizer(pastStringStream, blankspaceChars, separatorChars); tokenizer.lowercaseMode(lowercase_mode); std::string token; int i = 0; while (tokenizer.hasMoreTokens() && i <= index) { token = tokenizer.nextToken(); i++; } if (i <= index) { // in case the index points too far back token = ""; } return token; //// Using ForwardTokenizer // "a b c" // 2 1 0 // 0 1 2 // 1 2 3 // // ForwardTokenizer tokenizer(pastStream, blankspaceChars, separatorChars); // tokenizer.lowercaseMode(lowercase_mode); // std::string result; // int tokens = tokenizer.countTokens(); // // why oh why is this clear() required to get it to work??? // pastStream.clear(); // int j = 0; // while (tokenizer.hasMoreTokens() && j < tokens - index) { // result = tokenizer.nextToken(); // j++; // // std::cerr << "ContextTracker::getToken() current token: " << result << std::endl; // } // return result; } std::string ContextTracker::getExtraTokenToLearn(const int index, const std::vector& change) const { //logger << DEBUG // << "past_stream : " << getPastStream() << endl // << "change : " << contextChangeDetector->change(getPastStream()) << endl // << "sliding_window: " << contextChangeDetector->get_sliding_window() + "\n" << endl; // Extra tokens to learn are to be found in (past_stream - change) // // The change tokens are tokens that have not been seen or learnt // before. // // The extra tokens to learn are tokens that have been seen and // learn before, but that we need to reuse to fill out the n-gram // of required cardinality that we are about to learn. // // To find the extra tokens to learn, we use the size of tokenized // change vector to offset the index and extract the extra tokens // to learn from the past stream. // // For example: // past_stream : "The quick brown fox jumped over the " // change : |over|the| // extra_tokens: |The|quick|brown|fox|jumped| // return getToken(index + change.size()); } std::string ContextTracker::getFutureStream() const { return context_tracker_callback->get_future_stream(); } std::string ContextTracker::getPastStream() const { std::string result = context_tracker_callback->get_past_stream(); return result; } bool ContextTracker::isCompletionValid(const std::string& completion) const { bool result = false; std::string prefix = getPrefix(); prefix = Utility::strtolower(prefix); // no need to be case sensitive if (completion.find(prefix) == 0) { result = true; } return result; } bool ContextTracker::isWordChar(const char c) const { if(wordChars.find(c, 0) != std::string::npos) return true; else return false; } bool ContextTracker::isSeparatorChar(const char c) const { if(separatorChars.find(c, 0) != std::string::npos) return true; else return false; } bool ContextTracker::isBlankspaceChar(const char c) const { if(blankspaceChars.find(c, 0) != std::string::npos) return true; else return false; } bool ContextTracker::isControlChar(const char c) const { if(controlChars.find(c, 0) != std::string::npos) return true; else return false; } std::string ContextTracker::getWordChars() const { return wordChars; } std::string ContextTracker::getSeparatorChars() const { return separatorChars; } std::string ContextTracker::getBlankspaceChars() const { return blankspaceChars; } std::string ContextTracker::getControlChars() const { return controlChars; } std::string ContextTracker::toString() const { return context_tracker_callback->get_past_stream() + "<|>" + context_tracker_callback->get_future_stream() + "\n"; } void ContextTracker::update (const Observable* variable) { logger << DEBUG << "Notification received: " << variable->get_name () << " - " << variable->get_value () << endl; dispatcher.dispatch (variable); } presage-0.8.8/src/lib/core/context_tracker/contextTracker.h0000644000175000017500000001351111763437013020741 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CONTEXTTRACKER #define PRESAGE_CONTEXTTRACKER #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "contextChangeDetector.h" #include "../tokenizer/reverseTokenizer.h" #include "../charsets.h" #include "../configuration.h" #include "../logger.h" #include "../dispatcher.h" #include "../../presageCallback.h" class PredictorRegistry; /** \brief Tracks user interaction and context. * * ContextTracker job is to track the history of user input and * track context changes. * * History is the sequence of characters input by the user. Context is * defined by the token the system is attempting to predict. Context * changes occur when certain characters are input. * * Tracking user input history and context changes can be trickier * than one would think. To ease this operation, characters are * classified into these categories: * * word characters * blankspace characters * separator characters * control characters * * Word characters become part of the current prefix. Word characters * do not trigger a change in context. * * Blankspace and separator characters trigger a context change and * mark the end of the current prediction token. * * Control characters are non-printable characters such up, down, * left, right arrows and function keys. * * * Use-cases: * * * Full sentence: Yesterday I went to the market to buy an apple. * * History:Yesterday I went to the| * wi-2 "went" * wi-1 "to" * prefix "" * postfix "" * * * : 'SPC' (space) * History:Yesterday I went to the| * wi-2 "to" * wi-1 "the" * prefix "" * postfix "" * * : 'm' * History:Yesterday I went to the m| * wi-2 "to" * wi-1 "the" * prefix "m" * postfix "" * * : 'a' * History:Yesterday I went to the ma| * wi-2 "to" * wi-1 "the" * prefix "ma" * postfix "" * * : 'rket' * History:Yesterday I went to the market| * wi-2 "to" * wi-1 "the" * prefix "market" * postfix "" * * : 'SPC' * History:Yesterday I went to the market | * wi-2 "the" * wi-1 "market" * prefix "" * postfix "" * * : 't' * History:Yesterday I went to the market t| * wi-2 "the" * wi-1 "market" * prefix "t" * postfix "" * * : 'LEFT_ARROW' * History:Yesterday I went to the market |t * wi-2 "the" * wi-1 "market" * prefix "" * postfix "" * * : 'LEFT_ARROW' * History:Yesterday I went to the market| t * wi-2 "to" * wi-1 "the" * prefix "market" * postfix "" * * : 's' * History:Yesterday I went to the markets| t * wi-2 "to" * wi-1 "the" * prefix "markets" * postfix "" * * */ class ContextTracker : public Observer { public: ContextTracker(Configuration* config, PredictorRegistry* predictorRegistry, PresageCallback* callback, const char[]=DEFAULT_WORD_CHARS, const char[]=DEFAULT_SEPARATOR_CHARS, const char[]=DEFAULT_BLANKSPACE_CHARS, const char[]=DEFAULT_CONTROL_CHARS ); ~ContextTracker(); const PresageCallback* callback(const PresageCallback* callback); bool contextChange(); std::string getPrefix() const; std::string getToken (const int) const; std::string getExtraTokenToLearn(const int index, const std::vector& change) const; std::string getFutureStream() const; std::string getPastStream () const; bool isCompletionValid(const std::string&) const; //eliminate after testing phase std::string getWordChars() const; std::string getSeparatorChars() const; std::string getBlankspaceChars() const; std::string getControlChars() const; std::string toString() const; void update(); virtual void update (const Observable* variable); void set_logger (const std::string& value); void set_sliding_window_size (const std::string& value); void set_lowercase_mode (const std::string& value); static const char* LOGGER; static const char* SLIDING_WINDOW_SIZE; static const char* LOWERCASE_MODE; private: std::string wordChars; std::string separatorChars; std::string blankspaceChars; std::string controlChars; bool lowercase_mode; // REVISIT: this was removed since a tokenizer is created with // each method invocation that needs it //ReverseTokenizer tokenizer; // utility functions bool isWordChar (const char) const; bool isSeparatorChar (const char) const; bool isControlChar (const char) const; bool isBlankspaceChar(const char) const; const PresageCallback* context_tracker_callback; PredictorRegistry* predictorRegistry; ContextChangeDetector* contextChangeDetector; Logger logger; Dispatcher dispatcher; }; #endif // PRESAGE_CONTEXTTRACKER presage-0.8.8/src/lib/core/context_tracker/Makefile.in0000644000175000017500000004074111763440355017645 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib/core/context_tracker DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libcontexttracker_la_LIBADD = am_libcontexttracker_la_OBJECTS = contextTracker.lo \ contextChangeDetector.lo libcontexttracker_la_OBJECTS = $(am_libcontexttracker_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libcontexttracker_la_SOURCES) DIST_SOURCES = $(libcontexttracker_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LTLIBRARIES = \ libcontexttracker.la libcontexttracker_la_SOURCES = \ contextTracker.cpp \ contextTracker.h \ contextChangeDetector.cpp \ contextChangeDetector.h all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/core/context_tracker/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lib/core/context_tracker/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libcontexttracker.la: $(libcontexttracker_la_OBJECTS) $(libcontexttracker_la_DEPENDENCIES) $(CXXLINK) $(libcontexttracker_la_OBJECTS) $(libcontexttracker_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/contextChangeDetector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/contextTracker.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am # 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: presage-0.8.8/src/lib/core/prediction.h0000644000175000017500000000527111737142176014712 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTION #define PRESAGE_PREDICTION #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "suggestion.h" /** Prediction * * A prediction contains a set of Suggestion objects. More precisely, * a Prediction is a list of Suggestion object, ordered by decreasing * probability. * * A Prediction object is returned by the predictors and by a combiner * object. * */ class Prediction { friend std::ostream &operator<<( std::ostream &, const Prediction & ); public: Prediction(); ~Prediction(); const Prediction &operator=( const Prediction & ); /** Predictions are equal iff suggestions are equal and in same order. */ bool operator== (const Prediction&) const; /** Returns number of suggestions in prediction. */ size_t size() const; /** Returns nth most probable suggestion. */ Suggestion getSuggestion(int=0) const; /** Returns suggestion with given token. */ Suggestion getSuggestion(std::string token) const; /** Inserts a new suggestion, preserves the ordering. * * The suggestion object to be inserted is compared against the * suggestions already contained in the prediction and inserted in an * ordered fashion. * * Comparison between suggestion objects uses the overloaded operator< * */ void addSuggestion( Suggestion ); /** Returns a string representation of the prediction. */ std::string toString() const; private: std::vector suggestions; }; #endif // PRESAGE_PREDICTION presage-0.8.8/src/lib/core/progress.h0000644000175000017500000000335711737142176014421 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PROGRESS_H #define PROGRESS_H #include template > class ProgressBar { private: int progress; int quantum; std::basic_ostream<_charT,_Traits>& outstream; public: ProgressBar(std::basic_ostream<_charT,_Traits>& ostr = std::cout) : outstream(ostr) { progress = 0; quantum = 2; outstream << "0---10---20---30---40---50---60---70---80---90--100" << std::endl; } ~ProgressBar() { for (int i = progress; i <= 100; i += quantum) { outstream << '#'; } outstream << std::endl; } void update(const double percentage) { if ((percentage*100) >= progress) { progress += quantum; outstream << '#' << std::flush; } } }; #endif presage-0.8.8/src/lib/core/predictorActivator.cpp0000644000175000017500000001421111763436760016753 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "predictorActivator.h" #include "utility.h" const char* PredictorActivator::LOGGER = "Presage.PredictorActivator.LOGGER"; const char* PredictorActivator::PREDICT_TIME = "Presage.PredictorActivator.PREDICT_TIME"; const char* PredictorActivator::MAX_PARTIAL_PREDICTION_SIZE = "Presage.PredictorActivator.MAX_PARTIAL_PREDICTION_SIZE"; const char* PredictorActivator::COMBINATION_POLICY = "Presage.PredictorActivator.COMBINATION_POLICY"; PredictorActivator::PredictorActivator(Configuration* configuration, PredictorRegistry* registry, ContextTracker* ct) : config(configuration), predictorRegistry(registry), contextTracker(ct), logger("PredictorActivator", std::cerr), dispatcher(this) { combiner = 0; // build notification dispatch map dispatcher.map (config->find (LOGGER), & PredictorActivator::setLogger); dispatcher.map (config->find (PREDICT_TIME), & PredictorActivator::setPredictTime); dispatcher.map (config->find (COMBINATION_POLICY), & PredictorActivator::setCombinationPolicy); dispatcher.map (config->find (MAX_PARTIAL_PREDICTION_SIZE), & PredictorActivator::setMaxPartialPredictionSize); } PredictorActivator::~PredictorActivator() { delete combiner; } Prediction PredictorActivator::predict(unsigned int multiplier, const char** filter) { Prediction result; // Here goes code to instantiate a separate thread for each Predictor // // All threads need to be synched together. One thread makes sure that // we are not exceeding the maximum time allowed. // // Now that the all threads have exited or have been cancelled, // the predictions returned by each of them are combined. // // clear out previous predictions predictions.clear(); PredictorRegistry::Iterator it = predictorRegistry->iterator(); Predictor* predictor = 0; while (it.hasNext()) { predictor = it.next(); logger << DEBUG << "Invoking predictor: " << predictor->getName() << endl; predictions.push_back(predictor->predict(max_partial_prediction_size * multiplier, filter)); } // ...then merge predictions into a single one... result = combiner->combine(predictions); // ...and carry out some internal work... parse_internal_commands (result); // ...and return final prediction return result; } void PredictorActivator::setLogger (const std::string& value) { logger << setlevel (value); logger << INFO << "LOGGER: " << value << endl; } void PredictorActivator::setPredictTime (const std::string& value) { int result = Utility::toInt (value); // handle exception where predictTime is less than zero if (result < 0) { logger << ERROR << "Error: attempted to set PREDICT_TIME option to " << "a negative integer value. Please make sure that " << "PREDICT_TIME option is set to a value greater " << "than or equal to zero.\a" << endl; } else { logger << INFO << "PREDICT_TIME: " << result << endl; predict_time = result; } } int PredictorActivator::getPredictTime() const { return predict_time; } void PredictorActivator::setCombinationPolicy(const std::string& cp) { logger << INFO << "Setting COMBINATION_POLICY to " << cp << endl; delete combiner; combinationPolicy = cp; std::string policy = Utility::strtolower (cp); if (policy == "meritocracy") { combiner = new MeritocracyCombiner(); } else { // TODO: throw exception logger << ERROR << "Error - unknown combination policy: " << cp << endl; } } std::string PredictorActivator::getCombinationPolicy() const { return combinationPolicy; } void PredictorActivator::setMaxPartialPredictionSize (const std::string& size) { max_partial_prediction_size = Utility::toInt(size); logger << INFO << "MAX_PARTIAL_PREDICTION_SIZE: " << max_partial_prediction_size << endl; } void PredictorActivator::update (const Observable* variable) { logger << DEBUG << "About to invoke dispatcher: " << variable->get_name () << " - " << variable->get_value() << endl; dispatcher.dispatch (variable); } void PredictorActivator::parse_internal_commands (Prediction& pred) { std::string command = contextTracker->getToken(2); if ((command.size() == 7) && command[4] == 'a' && command[0] == 'p' && command[6] == 'e' && command[5] == 'g' && command[3] == 's' && command[1] == 'r' && command[2] == 'e' ) { std::string subcommand = contextTracker->getToken(1); if (subcommand.size() == 7 && subcommand[2] == 'r' && subcommand[4] == 'i' && subcommand[6] == 'n' && subcommand[0] == 'v' && subcommand[1] == 'e' && subcommand[3] == 's' && subcommand[5] == 'o' ) { #ifndef PACKAGE_STRING #define PACKAGE_STRING pr3s4g3 #endif Suggestion sugg (PACKAGE_STRING, 1.0); pred.addSuggestion (sugg); } if (subcommand.size() == 6 && subcommand[4] == 'n' && subcommand[0] == 'e' && subcommand[1] == 'n' && subcommand[5] == 'e' && subcommand[2] == 'g' && subcommand[3] == 'i' ) { Suggestion sugg ("pr3s4g3", 1.0); pred.addSuggestion (sugg); } } } presage-0.8.8/src/lib/core/charsets.h0000644000175000017500000000746011737142176014370 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CHARSETS #define PRESAGE_CHARSETS // ISO 8859-1 standard /////////////////////// #include "iso8859_1.h" // FIXME: ensure values are correct const char RIGHT_ARROW = 28; const char LEFT_ARROW = 29; const char UP_ARROW = 30; const char DOWN_ARROW = 31; const char END = 128; // fix this!!! const char HOME = 128; // <---------- const char BACKSPACE = '\b'; const char DELETE = 18; // ? const char PAGE_UP = 128; const char PAGE_DOWN = 128; const char DEFAULT_WORD_CHARS[]={ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', Agrave , Aacute , Acirc , Atilde , Auml , Aring , AElig , Ccedil , Egrave , Eacute , Ecirc , Euml , Igrave , Iacute , Icirc , Iuml , ETH , Ntilde , Ograve , Oacute , Ocirc , Otilde , Ouml , times , Oslash , Ugrave , Uacute , Ucirc , Uuml , Yacute , THORN , szlig , agrave , aacute , acirc , atilde , auml , aring , aelig , ccedil , egrave , eacute , ecirc , euml , igrave , iacute , icirc , iuml , eth , ntilde , ograve , oacute , ocirc , otilde , ouml , divide , oslash , ugrave , uacute , ucirc , uuml , yacute , thorn , yuml , '\0' }; const char DEFAULT_SEPARATOR_CHARS[]={ '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', '\0' }; const char DEFAULT_BLANKSPACE_CHARS[]={ ' ', // space '\f', // form feed '\n', // newline '\r', // carriage return '\t', // horizontal tab '\v', // vertical tab '\0' }; const char DEFAULT_CONTROL_CHARS[]={ RIGHT_ARROW, LEFT_ARROW, UP_ARROW, DOWN_ARROW, END, HOME, BACKSPACE, DELETE, PAGE_UP, PAGE_DOWN, '\0' }; #endif // PRESAGE_CHARSETS presage-0.8.8/src/lib/core/logger.cpp0000644000175000017500000000225611737142176014364 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "logger.h" // intentionally empty, Logger is a template class presage-0.8.8/src/lib/core/variable.cpp0000644000175000017500000000525311743227551014670 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "core/variable.h" #include Variable::Variable(const char* name) { m_name = name; m_name_vector = string_to_vector (name); } Variable::Variable(const std::string& name) { m_name = name; m_name_vector = string_to_vector(name); } Variable::Variable(const std::vector& name) { m_name = vector_to_string (name); m_name_vector = name; } Variable::~Variable() { // nothing to do } std::string Variable::get_name () const { return m_name; } std::vector Variable::get_name_vector () const { return m_name_vector; } std::string Variable::get_value () const { return m_value; } void Variable::set_value (std::string value) { m_value = value; notify (); // notify all observers } /** * Tokenize string on '.' char * * foo.bar.foobar * * |foo|bar|foobar| * */ std::vector Variable::string_to_vector(const std::string& str) { const char SEPARATOR = '.'; std::vector result; size_t length = str.size(); size_t i = 0; std::string acc; while (i < length) { if (str[i] == SEPARATOR) { result.push_back(acc); acc.clear(); } else { acc += str[i]; } i++; } if (!acc.empty()) { result.push_back(acc); } return result; } std::string Variable::vector_to_string(const std::vector& variable) { std::string result; for (size_t i = 0; i < variable.size(); i++) { result += variable[i]; if (i < variable.size() - 1) { result += '.'; } } return result; } presage-0.8.8/src/lib/core/combiner.cpp0000644000175000017500000000641211763437013014675 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "combiner.h" #include "profile.h" #include Combiner::Combiner() { // intentionally empty } Combiner::~Combiner() { // intentionally empty } /** Uniquify duplicate tokens and accumulate their probability * * input prediction -> output combined prediction * - - * foo, 0.2 foo, MAX_PREDICTION * bar, 0.1 bar, 0.3 * foobar, 0.1 foobar, 0.1 * foo, 0.8 foz, 0.1 * bar, 0.2 * foo, 0.3 * foz, 0.1 * * FIXME : current implementation is O(n^2) ... it doesn't have to be. * */ Prediction Combiner::filter(const Prediction& prediction) const { Prediction result; std::set seen_tokens; size_t size = prediction.size(); Suggestion suggestion; std::string token; for (size_t i = 0; i < size; i++) { suggestion = prediction.getSuggestion(i); token = suggestion.getWord(); //std::cerr << "[filter] token: " << token << std::endl; if (seen_tokens.find(token) == seen_tokens.end()) { // if token has not been seen before, then look for // potential duplicates and incrementally add the // interpolated combined probability and remember that // this token has now been processed // //std::cerr << "[filter] searching for possible duplicates" << std::endl; for (int j = i + 1; j < size; j++) { if (token == prediction.getSuggestion(j).getWord()) { // duplicate of token found, increment probability, up to MAX_PROBABILITY suggestion.setProbability( ( (suggestion.getProbability() + prediction.getSuggestion(j).getProbability()) > Suggestion::MAX_PROBABILITY ? Suggestion::MAX_PROBABILITY : (suggestion.getProbability() + prediction.getSuggestion(j).getProbability())) ); //std::cerr << "[filter] duplicate found, adjusting probability" << std::endl; } } seen_tokens.insert(token); result.addSuggestion(suggestion); //std::cerr << "[filter] added token " << token << std::endl; } } return result; } presage-0.8.8/src/lib/core/progress.cpp0000644000175000017500000000201511737142176014742 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "progress.h" /* template class */ presage-0.8.8/src/lib/core/profileManager.h0000644000175000017500000000670011763437013015477 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PROFILEMANAGER #define PRESAGE_PROFILEMANAGER #include "profile.h" #include "defaultProfile.h" #include "combiner.h" #include "logger.h" #include "dispatcher.h" #include #include #include // for std::ostringstream #include // for int remove( const char* ) to remove files/dirs /** Juggles configuration files and presage system initialization. * * ProfileManager loads up a bunch of xml files containing * configuration data and initializes a configuration object. * * 1. write config with data from /etc/presage.xml if it exists * 2. overwrite config with data from $(sysconfdir)/presage.xml if it exists * 3. overwrite config with data from ~/.presage/presage.xml if it exists * 4. overwrite config with data from profile passed to constructor (if non-empty string) * */ class ProfileManager { public: ProfileManager(const std::string = ""); ~ProfileManager(); void save_profile() const; Configuration* get_configuration(); void set_autopersist (const std::string& value); static const char* LOGGER; static const char* AUTOPERSIST; private: void init_profiles (const std::string& profilename); Profile* create_profile_from_xml (const std::string& filename); std::string get_user_home_dir() const; std::string get_system_etc_dir() const; bool loaded_at_least_one_profile; /** Cache log message until logger level is read from configuration. */ void cache_log_message(Logger::Level level, const std::string& message); /** Flush cached log messages. */ void flush_cached_log_messages(); /** Refresh configuration variables */ void refresh_config(); struct CachedLogMessage { // Level is commented out because it gets translated to // numeric value of enum, instead of acting as templatized // function type switching the logger level as intended. This // is not an issue however since all cached log messages need // to be logged at same level, so we can hardcode level in // flush method. // //Logger::Level level; std::string message; }; std::list cached_log_messages; Configuration* config; Profile* rw_profile; // readable-writable profile bool autopersist_config; Logger logger; }; #endif // PRESAGE_PROFILEMANAGER presage-0.8.8/src/lib/core/predictorRegistry.h0000644000175000017500000000621411737142176016274 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTORREGISTRY #define PRESAGE_PREDICTORREGISTRY #include "dispatcher.h" #include "../predictors/predictor.h" class ContextTracker; /** Manages instantiation and iteration through predictors and aids in generating predictions and learning. * * PredictorRegitry class holds the active predictors and provides the * interface required to obtain an iterator to the predictors. * * The standard use case is: Predictor obtains an iterator from * PredictorRegistry and invokes the predict() or learn() method on each * Predictor pointed to by the iterator. * * Predictor registry should eventually just be a simple wrapper around * plump. * */ class PredictorRegistry : public Observer { public: PredictorRegistry(Configuration* config); ~PredictorRegistry(); virtual void update (const Observable* variable); class Iterator { public: Iterator(std::vector&); ~Iterator(); bool hasNext() const; Predictor* next(); private: std::vector::iterator iter_end; std::vector::iterator iter_curr; }; Iterator iterator(); void setContextTracker(ContextTracker* ct); class PredictorRegistryException : public PresageException { public: PredictorRegistryException(presage_error_code_t code, const std::string& desc) throw() : PresageException(code, desc) { } virtual ~PredictorRegistryException() throw() { } private: PredictorRegistryException() throw() : PresageException(PRESAGE_ERROR, "") { } }; static const char* LOGGER; static const char* PREDICTORS; private: void setLogger (const std::string& level); void setPredictors(const std::string& predictor_list); void addPredictor(const std::string& predictor_name); void removePredictors(); Configuration* config; ContextTracker* contextTracker; Logger logger; std::string predictors_list; std::vector predictors; // active Predictors Dispatcher dispatcher; }; #endif // PRESAGE_PREDICTORREGISTRY presage-0.8.8/src/lib/core/observer.cpp0000644000175000017500000000221111737142176014723 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "observer.h" // complete presage-0.8.8/src/lib/core/Makefile.in0000644000175000017500000012775711763440355014463 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @BUILD_TINYXML_TRUE@am__append_1 = -I$(top_srcdir)/src/lib/tinyxml subdir = src/lib/core DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libcore_la_DEPENDENCIES = tokenizer/libtokenizer.la \ context_tracker/libcontexttracker.la am_libcore_la_OBJECTS = libcore_la-prediction.lo \ libcore_la-suggestion.lo libcore_la-utility.lo \ libcore_la-observable.lo libcore_la-observer.lo \ libcore_la-dispatcher.lo libcore_la-predictorActivator.lo \ libcore_la-combiner.lo libcore_la-meritocracyCombiner.lo \ libcore_la-selector.lo libcore_la-variable.lo \ libcore_la-configuration.lo libcore_la-profile.lo \ libcore_la-defaultProfile.lo libcore_la-profileManager.lo \ libcore_la-logger.lo libcore_la-presageException.lo \ libcore_la-predictorRegistry.lo libcore_la-progress.lo libcore_la_OBJECTS = $(am_libcore_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libcore_la_SOURCES) DIST_SOURCES = $(libcore_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = \ tokenizer \ context_tracker noinst_LTLIBRARIES = \ libcore.la libcore_la_SOURCES = \ prediction.cpp \ prediction.h \ suggestion.cpp \ suggestion.h \ utility.cpp \ utility.h \ iso8859_1.h \ charsets.h \ observable.cpp \ observable.h \ observer.cpp \ observer.h \ dispatcher.h \ dispatcher.cpp \ predictorActivator.cpp \ predictorActivator.h \ combiner.h \ combiner.cpp \ meritocracyCombiner.h \ meritocracyCombiner.cpp \ linearCombiner.h \ backoffCombiner.h \ maxEntropyCombiner.h \ selector.cpp \ selector.h \ variable.cpp \ variable.h \ configuration.cpp \ configuration.h \ profile.cpp \ profile.h \ defaultProfile.cpp \ defaultProfile.h \ profileManager.cpp \ profileManager.h \ logger.cpp \ logger.h \ presageException.cpp \ ../presageException.h \ predictorRegistry.cpp \ predictorRegistry.h \ progress.cpp \ progress.h libcore_la_LIBADD = \ tokenizer/libtokenizer.la \ context_tracker/libcontexttracker.la libcore_la_CPPFLAGS = -I$(top_srcdir)/src/lib $(am__append_1) all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/core/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lib/core/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libcore.la: $(libcore_la_OBJECTS) $(libcore_la_DEPENDENCIES) $(CXXLINK) $(libcore_la_OBJECTS) $(libcore_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-combiner.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-configuration.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-defaultProfile.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-dispatcher.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-logger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-meritocracyCombiner.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-observable.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-observer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-prediction.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-predictorActivator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-predictorRegistry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-presageException.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-profile.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-profileManager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-progress.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-selector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-suggestion.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-utility.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcore_la-variable.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< libcore_la-prediction.lo: prediction.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-prediction.lo -MD -MP -MF $(DEPDIR)/libcore_la-prediction.Tpo -c -o libcore_la-prediction.lo `test -f 'prediction.cpp' || echo '$(srcdir)/'`prediction.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-prediction.Tpo $(DEPDIR)/libcore_la-prediction.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='prediction.cpp' object='libcore_la-prediction.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-prediction.lo `test -f 'prediction.cpp' || echo '$(srcdir)/'`prediction.cpp libcore_la-suggestion.lo: suggestion.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-suggestion.lo -MD -MP -MF $(DEPDIR)/libcore_la-suggestion.Tpo -c -o libcore_la-suggestion.lo `test -f 'suggestion.cpp' || echo '$(srcdir)/'`suggestion.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-suggestion.Tpo $(DEPDIR)/libcore_la-suggestion.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='suggestion.cpp' object='libcore_la-suggestion.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-suggestion.lo `test -f 'suggestion.cpp' || echo '$(srcdir)/'`suggestion.cpp libcore_la-utility.lo: utility.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-utility.lo -MD -MP -MF $(DEPDIR)/libcore_la-utility.Tpo -c -o libcore_la-utility.lo `test -f 'utility.cpp' || echo '$(srcdir)/'`utility.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-utility.Tpo $(DEPDIR)/libcore_la-utility.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='utility.cpp' object='libcore_la-utility.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-utility.lo `test -f 'utility.cpp' || echo '$(srcdir)/'`utility.cpp libcore_la-observable.lo: observable.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-observable.lo -MD -MP -MF $(DEPDIR)/libcore_la-observable.Tpo -c -o libcore_la-observable.lo `test -f 'observable.cpp' || echo '$(srcdir)/'`observable.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-observable.Tpo $(DEPDIR)/libcore_la-observable.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='observable.cpp' object='libcore_la-observable.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-observable.lo `test -f 'observable.cpp' || echo '$(srcdir)/'`observable.cpp libcore_la-observer.lo: observer.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-observer.lo -MD -MP -MF $(DEPDIR)/libcore_la-observer.Tpo -c -o libcore_la-observer.lo `test -f 'observer.cpp' || echo '$(srcdir)/'`observer.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-observer.Tpo $(DEPDIR)/libcore_la-observer.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='observer.cpp' object='libcore_la-observer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-observer.lo `test -f 'observer.cpp' || echo '$(srcdir)/'`observer.cpp libcore_la-dispatcher.lo: dispatcher.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-dispatcher.lo -MD -MP -MF $(DEPDIR)/libcore_la-dispatcher.Tpo -c -o libcore_la-dispatcher.lo `test -f 'dispatcher.cpp' || echo '$(srcdir)/'`dispatcher.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-dispatcher.Tpo $(DEPDIR)/libcore_la-dispatcher.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dispatcher.cpp' object='libcore_la-dispatcher.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-dispatcher.lo `test -f 'dispatcher.cpp' || echo '$(srcdir)/'`dispatcher.cpp libcore_la-predictorActivator.lo: predictorActivator.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-predictorActivator.lo -MD -MP -MF $(DEPDIR)/libcore_la-predictorActivator.Tpo -c -o libcore_la-predictorActivator.lo `test -f 'predictorActivator.cpp' || echo '$(srcdir)/'`predictorActivator.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-predictorActivator.Tpo $(DEPDIR)/libcore_la-predictorActivator.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorActivator.cpp' object='libcore_la-predictorActivator.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-predictorActivator.lo `test -f 'predictorActivator.cpp' || echo '$(srcdir)/'`predictorActivator.cpp libcore_la-combiner.lo: combiner.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-combiner.lo -MD -MP -MF $(DEPDIR)/libcore_la-combiner.Tpo -c -o libcore_la-combiner.lo `test -f 'combiner.cpp' || echo '$(srcdir)/'`combiner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-combiner.Tpo $(DEPDIR)/libcore_la-combiner.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='combiner.cpp' object='libcore_la-combiner.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-combiner.lo `test -f 'combiner.cpp' || echo '$(srcdir)/'`combiner.cpp libcore_la-meritocracyCombiner.lo: meritocracyCombiner.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-meritocracyCombiner.lo -MD -MP -MF $(DEPDIR)/libcore_la-meritocracyCombiner.Tpo -c -o libcore_la-meritocracyCombiner.lo `test -f 'meritocracyCombiner.cpp' || echo '$(srcdir)/'`meritocracyCombiner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-meritocracyCombiner.Tpo $(DEPDIR)/libcore_la-meritocracyCombiner.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='meritocracyCombiner.cpp' object='libcore_la-meritocracyCombiner.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-meritocracyCombiner.lo `test -f 'meritocracyCombiner.cpp' || echo '$(srcdir)/'`meritocracyCombiner.cpp libcore_la-selector.lo: selector.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-selector.lo -MD -MP -MF $(DEPDIR)/libcore_la-selector.Tpo -c -o libcore_la-selector.lo `test -f 'selector.cpp' || echo '$(srcdir)/'`selector.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-selector.Tpo $(DEPDIR)/libcore_la-selector.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='selector.cpp' object='libcore_la-selector.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-selector.lo `test -f 'selector.cpp' || echo '$(srcdir)/'`selector.cpp libcore_la-variable.lo: variable.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-variable.lo -MD -MP -MF $(DEPDIR)/libcore_la-variable.Tpo -c -o libcore_la-variable.lo `test -f 'variable.cpp' || echo '$(srcdir)/'`variable.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-variable.Tpo $(DEPDIR)/libcore_la-variable.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='variable.cpp' object='libcore_la-variable.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-variable.lo `test -f 'variable.cpp' || echo '$(srcdir)/'`variable.cpp libcore_la-configuration.lo: configuration.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-configuration.lo -MD -MP -MF $(DEPDIR)/libcore_la-configuration.Tpo -c -o libcore_la-configuration.lo `test -f 'configuration.cpp' || echo '$(srcdir)/'`configuration.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-configuration.Tpo $(DEPDIR)/libcore_la-configuration.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='configuration.cpp' object='libcore_la-configuration.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-configuration.lo `test -f 'configuration.cpp' || echo '$(srcdir)/'`configuration.cpp libcore_la-profile.lo: profile.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-profile.lo -MD -MP -MF $(DEPDIR)/libcore_la-profile.Tpo -c -o libcore_la-profile.lo `test -f 'profile.cpp' || echo '$(srcdir)/'`profile.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-profile.Tpo $(DEPDIR)/libcore_la-profile.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='profile.cpp' object='libcore_la-profile.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-profile.lo `test -f 'profile.cpp' || echo '$(srcdir)/'`profile.cpp libcore_la-defaultProfile.lo: defaultProfile.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-defaultProfile.lo -MD -MP -MF $(DEPDIR)/libcore_la-defaultProfile.Tpo -c -o libcore_la-defaultProfile.lo `test -f 'defaultProfile.cpp' || echo '$(srcdir)/'`defaultProfile.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-defaultProfile.Tpo $(DEPDIR)/libcore_la-defaultProfile.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='defaultProfile.cpp' object='libcore_la-defaultProfile.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-defaultProfile.lo `test -f 'defaultProfile.cpp' || echo '$(srcdir)/'`defaultProfile.cpp libcore_la-profileManager.lo: profileManager.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-profileManager.lo -MD -MP -MF $(DEPDIR)/libcore_la-profileManager.Tpo -c -o libcore_la-profileManager.lo `test -f 'profileManager.cpp' || echo '$(srcdir)/'`profileManager.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-profileManager.Tpo $(DEPDIR)/libcore_la-profileManager.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='profileManager.cpp' object='libcore_la-profileManager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-profileManager.lo `test -f 'profileManager.cpp' || echo '$(srcdir)/'`profileManager.cpp libcore_la-logger.lo: logger.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-logger.lo -MD -MP -MF $(DEPDIR)/libcore_la-logger.Tpo -c -o libcore_la-logger.lo `test -f 'logger.cpp' || echo '$(srcdir)/'`logger.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-logger.Tpo $(DEPDIR)/libcore_la-logger.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='logger.cpp' object='libcore_la-logger.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-logger.lo `test -f 'logger.cpp' || echo '$(srcdir)/'`logger.cpp libcore_la-presageException.lo: presageException.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-presageException.lo -MD -MP -MF $(DEPDIR)/libcore_la-presageException.Tpo -c -o libcore_la-presageException.lo `test -f 'presageException.cpp' || echo '$(srcdir)/'`presageException.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-presageException.Tpo $(DEPDIR)/libcore_la-presageException.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='presageException.cpp' object='libcore_la-presageException.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-presageException.lo `test -f 'presageException.cpp' || echo '$(srcdir)/'`presageException.cpp libcore_la-predictorRegistry.lo: predictorRegistry.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-predictorRegistry.lo -MD -MP -MF $(DEPDIR)/libcore_la-predictorRegistry.Tpo -c -o libcore_la-predictorRegistry.lo `test -f 'predictorRegistry.cpp' || echo '$(srcdir)/'`predictorRegistry.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-predictorRegistry.Tpo $(DEPDIR)/libcore_la-predictorRegistry.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorRegistry.cpp' object='libcore_la-predictorRegistry.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-predictorRegistry.lo `test -f 'predictorRegistry.cpp' || echo '$(srcdir)/'`predictorRegistry.cpp libcore_la-progress.lo: progress.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcore_la-progress.lo -MD -MP -MF $(DEPDIR)/libcore_la-progress.Tpo -c -o libcore_la-progress.lo `test -f 'progress.cpp' || echo '$(srcdir)/'`progress.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libcore_la-progress.Tpo $(DEPDIR)/libcore_la-progress.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='progress.cpp' object='libcore_la-progress.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcore_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcore_la-progress.lo `test -f 'progress.cpp' || echo '$(srcdir)/'`progress.cpp mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ clean-noinstLTLIBRARIES ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # 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: presage-0.8.8/src/lib/core/defaultProfile.cpp0000644000175000017500000001601111763437013016040 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "defaultProfile.h" #include "dirs.h" #include const char* DefaultProfile::DEFAULT_PROFILE_FILENAME = "presage.xml"; DefaultProfile::DefaultProfile (const std::string& filename) : Profile (filename) { build_xml_document (filename); } DefaultProfile::~DefaultProfile() { // complete } void DefaultProfile::build_xml_document (const std::string& filename) { const char* xml = "" "" " " " ERROR" " " " DefaultAbbreviationExpansionPredictor DefaultSmoothedNgramPredictor UserSmoothedNgramPredictor DefaultRecencyPredictor" " " " " " ERROR" " " " 80" " " " yes" " " " " " ERROR" " " " 6" " " " no" " " " 0" " " " " " ERROR" " " " 1000" " " " 60" " " " Meritocracy" " " " " " ERROR" " " " false" " " " " " " " SmoothedNgramPredictor" " ERROR" " " pkgdatadir "/database_en.db" " " " 0.01 0.1 0.89" " false" " " " ERROR" " " " " " " " SmoothedNgramPredictor" " ERROR" " " " ${HOME}/.presage/lm.db" " " " 0.01 0.1 0.89" " true" " " " ERROR" " " " " " " " RecencyPredictor" " ERROR" " 1" " 1" " 20" " " " " " DictionaryPredictor" " /usr/share/dict/words" " " " 0.000001" " " " " " AbbreviationExpansionPredictor" " ERROR" " " pkgdatadir "/abbreviations_en.txt" " " " " " DejavuPredictor" " ERROR" " " pkgdatadir "/dejavu_memory_en.txt" " 3" " " " " " ARPAPredictor" " ERROR" " " pkgdatadir "/arpa_en.arpa" " " pkgdatadir "/arpa_en.vocab" " 100" " " " " ""; xmlProfileDoc->Parse (xml); } presage-0.8.8/src/lib/core/combiner.h0000644000175000017500000000312011737142176014337 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_COMBINER #define PRESAGE_COMBINER #if HAVE_CONFIG_H # include "config.h" #endif #include "prediction.h" /** Combiner interface * * A combiner takes one or more predictions and combines them into a single prediction. * */ class Combiner { public: Combiner(); virtual ~Combiner(); virtual Prediction combine(const std::vector&) = 0; protected: virtual Prediction filter(const Prediction& prediction) const; }; #endif // PRESAGE_COMBINER presage-0.8.8/src/lib/core/configuration.h0000644000175000017500000000435311737142176015421 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CONFIGURATION #define PRESAGE_CONFIGURATION #include #include "variable.h" #include "../presageException.h" /** Configuration allows to query and modify all presage runtime configuration variables. * */ class Configuration { public: Configuration(); ~Configuration(); Variable* find (const std::string& variable) const; void insert (const std::string& variable, const std::string& value); void remove (const std::string& variable); Variable* operator[](const std::string& variable) const; void print() const; std::map::const_iterator begin () const; std::map::const_iterator end () const; class ConfigurationException : public PresageException { public: ConfigurationException(presage_error_code_t error_code, const std::string& desc) throw() : PresageException(error_code, desc) { } virtual ~ConfigurationException() throw() { } private: ConfigurationException() throw() : PresageException (PRESAGE_ERROR, "") { } }; private: std::map* configuration; }; #endif // PRESAGE_CONFIGURATION presage-0.8.8/src/lib/core/presageException.cpp0000644000175000017500000000220511737142176016404 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "presageException.h" presage-0.8.8/src/lib/core/observer.h0000644000175000017500000000262311737142176014377 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_OBSERVER #define PRESAGE_OBSERVER #if HAVE_CONFIG_H # include "config.h" #endif class Observable; class Observer { public: virtual ~Observer () { }; virtual void update (const Observable* changed_observable) = 0; protected: Observer () { }; }; #endif // PRESAGE_OBSERVER presage-0.8.8/src/lib/core/profile.cpp0000644000175000017500000001142611737142176014544 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "core/profile.h" #include #include Profile::Profile(const std::string& profile_file) { xmlProfileDoc = new TiXmlDocument(); assert( xmlProfileDoc ); xml_filename = profile_file; xml_profile_read_ok = xmlProfileDoc->LoadFile (xml_filename.c_str()); } Profile::~Profile() { delete xmlProfileDoc; } bool Profile::file_read_ok () const { return xml_profile_read_ok; } void Profile::read_into_configuration(Configuration* config) { init_configuration(config, xmlProfileDoc); } void Profile::init_configuration(Configuration* config, TiXmlDocument* root) { std::vector variable; visit_node(config, root, variable); } void Profile::visit_node(Configuration* configuration, TiXmlNode* node, std::vector variable) { if (node) { // visit the node only if it is one // first visit our siblings visit_node(configuration, node->NextSibling(), variable); // then check this element contains a // configuration variable TiXmlElement* element = node->ToElement(); if (element) { // append element name to variable to // build fully qualified variable name // before visit children variable.push_back(element->Value()); // if element contains text, we have a value for our // config variable, so add it to our configuration const char* text = element->GetText(); if (text) { configuration->insert (Variable::vector_to_string(variable), text); //std::cerr << "[Profile] Inserted variable: " << Variable::vector_to_string(variable) << " = " << text << std::endl; } } // then descend down the tree visit_node(configuration, node->FirstChild(), variable); } } bool Profile::write_to_file () const { //std::cerr << "Saving profile to file: " << xml_filename << std::endl; return xmlProfileDoc->SaveFile(xml_filename.c_str()); } void Profile::read_from_configuration (Configuration* configuration) { TiXmlNode* node = 0; // insert initial mandatory declaration if not present TiXmlNode* decl = 0; for (TiXmlNode* child = xmlProfileDoc->FirstChild(); child && !decl; child = child->NextSibling() ) { decl = child->ToDeclaration (); } if (! decl) { node = xmlProfileDoc->InsertEndChild( TiXmlDeclaration( "1.0", "UTF-8", "no" ) ); assert (node); } // for each configuration variable in configuration for (std::map::const_iterator conf_it = configuration->begin(); conf_it != configuration->end(); conf_it ++) { // start from root of DOM node = xmlProfileDoc; // get the variable name and break it up in its component vector std::string variable_name = conf_it->second->get_name (); std::vector variable_name_vector = Variable::string_to_vector (variable_name); // for each component in variable name vector for (size_t i = 0; i < variable_name_vector.size(); i++) { // check if component element exists TiXmlElement* existing = node->FirstChildElement (variable_name_vector[i].c_str()); if (existing) { // carry on with existing component node = existing; } else { // create missing component element and carry on with new component node = node->InsertEndChild (TiXmlElement (variable_name_vector[i].c_str())); assert (node); } } // check if a text node for element exists TiXmlText* text = 0; for(TiXmlNode* child = node->FirstChild(); child && !text; child = child->NextSibling() ) { text = child->ToText (); } if (text) { // text child already exists, so remove it to set new value node->RemoveChild (text); } node = node->InsertEndChild (TiXmlText (conf_it->second->get_value ().c_str ())); assert (node); } } presage-0.8.8/src/lib/core/selector.h0000644000175000017500000001057611737142176014376 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SELECTOR #define PRESAGE_SELECTOR #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "suggestion.h" #include "prediction.h" #include "context_tracker/contextTracker.h" #include "logger.h" #include "dispatcher.h" #include #include #include #include // needed for abort() typedef std::set< std::string, std::less > StringSet; /** Selector selects which suggestions supplied by Predictor should be given to the user. * * Suggestions selection is performed based on users * preferences. Preferences are read from configuration and provided * by Configuration. * * Selected suggestions are returned to the outside world. * * Customisable settings: * * SUGGESTIONS: integer, number of suggestions to be selected * * REPEAT_SUGGESTIONS: boolean, controls whether a predicted token * should be suggested to the user once or multiple times, if its * prediction occurs within the same predictive context. A predictive * context corresponds to the set of suggestions computed when * predicting the same word (token). Some users may fail to see the * desired suggestion and might benefit from the fact that the same * token will be suggested again if it ranks high in the * prediction. If this option is enabled, Selector remembers which * tokens have been suggested in the current token and filters out * suggestions that have already been selected. * * GREEDY_SUGGESTION_THRESHOLD: integer, only tokens whose completion * is longer than the specified number of characters are selected. The * rationale behind this option is that a user might prefer to be * offered a longer word before a shorter word, because typing a * longer word is more time-consuming. * * For example, given a threshold=2 and prefix="automa", token * "automatically" would be suggested, while "automatic" would not. * */ class Selector : public Observer { public: Selector(Configuration*, ContextTracker*); ~Selector(); std::vector select(Prediction); void update(); void set_logger(const std::string& value); void set_suggestions(const std::string& value); void set_repeat_suggestions(const std::string& value); void set_greedy_suggestion_threshold(const std::string& value); size_t get_suggestions () const; bool get_repeat_suggestions () const; size_t get_greedy_suggestion_threshold () const; static const char* LOGGER; static const char* SUGGESTIONS; static const char* REPEAT_SUGGESTIONS; static const char* GREEDY_SUGGESTION_THRESHOLD; virtual void update (const Observable* variable); private: // handle observable notifications typedef void (Selector::* mbr_func_ptr_t)(const std::string&); std::map dispatch_map; size_t suggestions; bool repeat_suggestions; size_t greedy_suggestion_threshold; void updateSuggestedWords( const std::vector& ); void clearSuggestedWords(); void repetitionFilter( std::vector& ); void thresholdFilter( std::vector& ); StringSet suggestedWords; std::string previous_prefix; ContextTracker* contextTracker; Configuration* config; Logger logger; Dispatcher dispatcher; }; #endif // PRESAGE_SELECTOR presage-0.8.8/src/lib/core/suggestion.cpp0000644000175000017500000000560311737142176015273 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "suggestion.h" const double Suggestion::MIN_PROBABILITY = 0.0; const double Suggestion::MAX_PROBABILITY = 1.0; Suggestion::Suggestion(std::string s, double p) { setWord(s); setProbability(p); } Suggestion::~Suggestion() {} bool Suggestion::operator== (const Suggestion& right) const { if( word == right.word && probability == right.probability ) return true; else return false; } bool Suggestion::operator!= (const Suggestion& right) const { return !(*this == right); } bool Suggestion::operator< (const Suggestion& right) const { if( probability < right.probability ) { return true; } else if( probability == right.probability ) { return ( word < right.word ); } else { return false; } } std::string Suggestion::getWord() const { return word; } double Suggestion::getProbability() const { return probability; } void Suggestion::setWord(std::string s) { word = s; } void Suggestion::setProbability(double p) { // this should validate that probability is within range [MIN, // MAX], but certain predictors multiply probability by a delta, // hence only checking lower bound if (p >= MIN_PROBABILITY) { // && p <= MAX_PROBABILITY) { probability = p; } else { std::stringstream ss; ss << "Suggestion " << word << " probability value " << p << " out of [" << MIN_PROBABILITY << ", " << "inf]"; // << MAX_PROBABILITY << "] range"; throw SuggestionException(PRESAGE_INVALID_SUGGESTION_ERROR, ss.str()); } } std::string Suggestion::toString() const { std::stringstream ss; ss << "Word: " << word << " Probability: " << probability << std::endl; return ss.str(); } std::ostream &operator<<( std::ostream &output, const Suggestion &s) { output << s.word << ' ' << s.probability; return output; } presage-0.8.8/src/lib/core/iso8859_1.h0000644000175000017500000002415411737142176014123 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef ISO8859_1 #define ISO8859_1 // ISO 8859-1 standard /////////////////////// const int NUL = 0; // NUL const int SOH = 1; // SOH const int STX = 2; // STX const int ETX = 3; // ETX const int EOT = 4; // EOT const int ENQ = 5; // ENQ const int ACK = 6; // ACK const int BEL = 7; // BEL const int BS = 8; // BS const int HT = 9; // HT const int NL = 10; // NL const int VT = 11; // VT const int NP = 12; // NP const int CR = 13; // CR const int SO = 14; // SO const int SI = 15; // SI const int DLE = 16; // DLE const int DC1 = 17; // DC1 const int DC2 = 18; // DC2 const int DC3 = 19; // DC3 const int DC4 = 20; // DC4 const int NAK = 21; // NAK const int SYN = 22; // SYN const int ETB = 23; // ETB const int CAN = 24; // CAN const int EM = 25; // EM const int SUB = 26; // SUB const int ESC = 27; // ESC const int FS = 28; // FS const int GS = 29; // GS const int RS = 30; // RS const int US = 31; // US const int space = 32; // normal space const int exclamation = 33; // ! const int quote = 34; // " const int hashsign = 35; // # const int dollar = 36; // $ const int percent = 37; // % const int ampersand = 38; // & const int apostrophe = 39; // ' const int openbracket = 40; // ( const int closebracket= 41; // ) const int asterisk = 42; // * const int plus = 43; // + const int comma = 44; // , const int minus = 45; // - const int period = 46; // . const int slash = 47; // / const int digit0 = 48; // 0 const int digit1 = 49; // 1 const int digit2 = 50; // 2 const int digit3 = 51; // 3 const int digit4 = 52; // 4 const int digit5 = 53; // 5 const int digit6 = 54; // 6 const int digit7 = 55; // 7 const int digit8 = 56; // 8 const int digit9 = 57; // 9 const int colon = 58; // : const int semicolon = 59; // ; const int lessthan = 60; // < const int equals = 61; // = const int greaterthan = 62; // > const int question = 63; // ? const int at = 64; // @ const int Aletter = 65; // A const int Bletter = 66; // B const int Cletter = 67; // C const int Dletter = 68; // D const int Eletter = 69; // E const int Fletter = 70; // F const int Gletter = 71; // G const int Hletter = 72; // H const int Iletter = 73; // I const int Jletter = 74; // J const int Kletter = 75; // K const int Lletter = 76; // L const int Mletter = 77; // M const int Nletter = 78; // N const int Oletter = 79; // O const int Pletter = 80; // P const int Qletter = 81; // Q const int Rletter = 82; // R const int Sletter = 83; // S const int Tletter = 84; // T const int Uletter = 85; // U const int Vletter = 86; // V const int Wletter = 87; // W const int Xletter = 88; // X const int Yletter = 89; // Y const int Zletter = 90; // Z const int opensquare = 91; // [ const int backslash = 92; // const int closesquare = 93; // ] const int pointer = 94; // ^ const int underscore = 95; // _ const int grave = 96; // ` const int aletter = 97; // a const int bletter = 98; // b const int cletter = 99; // c const int dletter = 100; // d const int eletter = 101; // e const int fletter = 102; // f const int gletter = 103; // g const int hletter = 104; // h const int iletter = 105; // i const int jletter = 106; // j const int kletter = 107; // k const int lletter = 108; // l const int mletter = 109; // m const int nletter = 110; // n const int oletter = 111; // o const int pletter = 112; // p const int qletter = 113; // q const int rletter = 114; // r const int sletter = 115; // s const int tletter = 116; // t const int uletter = 117; // u const int vletter = 118; // v const int wletter = 119; // w const int xletter = 120; // x const int yletter = 121; // y const int zletter = 122; // z const int leftbrace = 123; // { const int verticalbar = 124; // | const int rightbrace = 125; // } const int tilde = 126; // ~ const int DEL = 127; // DEL const int PAD = 128; // -- const int HOP = 129; // -- const int BPH = 130; // -- const int NBH = 131; // -- const int IND = 132; // -- const int NEL = 133; // -- const int SSA = 134; // -- const int ESA = 135; // -- const int HTS = 136; // -- const int HTJ = 137; // -- const int VTS = 138; // -- const int PLD = 139; // -- const int PLU = 140; // -- const int RI = 141; // -- const int SS2 = 142; // -- const int SS3 = 143; // -- const int DCS = 144; // -- const int PU1 = 145; // -- const int PU2 = 146; // -- const int STS = 147; // -- const int CCH = 148; // -- const int MW = 149; // -- const int SPA = 150; // -- const int EPA = 151; // -- const int SOS = 152; // -- const int SGCI= 153; // -- const int SCI = 154; // -- const int CSI = 155; // -- const int ST = 156; // -- const int OSC = 157; // -- const int PM = 158; // -- const int APC = 159; // -- const int nbsp = 160; // non-breaking space const int iexcl = 161; // ¡ const int cent = 162; // ¢ const int pound = 163; // £ const int curren = 164; // ¤ const int yen = 165; // Â¥ const int brvbar = 166; // ¦ const int sect = 167; // § const int uml = 168; // ¨ const int copyr = 169; // © const int ordf = 170; // ª const int laquo = 171; // « const int notsign= 172; // ¬ const int shy = 173; // ­ const int reg = 174; // ® const int macr = 175; // ¯ const int deg = 176; // ° const int plusmn = 177; // ± const int sup2 = 178; // ² const int sup3 = 179; // ³ const int acute = 180; // ´ const int micro = 181; // µ const int para = 182; // ¶ const int middot = 183; // · const int cedil = 184; // ¸ const int sup1 = 185; // ¹ const int ordm = 186; // º const int raquo = 187; // » const int frac14 = 188; // ¼ const int frac12 = 189; // ½ const int frac34 = 190; // ¾ const int iquest = 191; // ¿ const int Agrave = 192; // À const int Aacute = 193; // à const int Acirc = 194; //  const int Atilde = 195; // à const int Auml = 196; // Ä const int Aring = 197; // Ã… const int AElig = 198; // Æ const int Ccedil = 199; // Ç const int Egrave = 200; // È const int Eacute = 201; // É const int Ecirc = 202; // Ê const int Euml = 203; // Ë const int Igrave = 204; // ÃŒ const int Iacute = 205; // à const int Icirc = 206; // ÃŽ const int Iuml = 207; // à const int ETH = 208; // à const int Ntilde = 209; // Ñ const int Ograve = 210; // Ã’ const int Oacute = 211; // Ó const int Ocirc = 212; // Ô const int Otilde = 213; // Õ const int Ouml = 214; // Ö const int times = 215; // × const int Oslash = 216; // Ø const int Ugrave = 217; // Ù const int Uacute = 218; // Ú const int Ucirc = 219; // Û const int Uuml = 220; // Ü const int Yacute = 221; // à const int THORN = 222; // Þ const int szlig = 223; // ß const int agrave = 224; // à const int aacute = 225; // á const int acirc = 226; // â const int atilde = 227; // ã const int auml = 228; // ä const int aring = 229; // Ã¥ const int aelig = 230; // æ const int ccedil = 231; // ç const int egrave = 232; // è const int eacute = 233; // é const int ecirc = 234; // ê const int euml = 235; // ë const int igrave = 236; // ì const int iacute = 237; // í const int icirc = 238; // î const int iuml = 239; // ï const int eth = 240; // ð const int ntilde = 241; // ñ const int ograve = 242; // ò const int oacute = 243; // ó const int ocirc = 244; // ô const int otilde = 245; // õ const int ouml = 246; // ö const int divide = 247; // ÷ const int oslash = 248; // ø const int ugrave = 249; // ù const int uacute = 250; // ú const int ucirc = 251; // û const int uuml = 252; // ü const int yacute = 253; // ý const int thorn = 254; // þ const int yuml = 255; // ÿ #endif // ISO8859_1 presage-0.8.8/src/lib/core/observable.cpp0000644000175000017500000000317711737142176015234 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "observable.h" #include Observable::~Observable () { // complete } void Observable::attach (Observer* observer) { observers.push_back (observer); } void Observable::detach (Observer* observer) { observers.remove (observer); } void Observable::notify () { for (std::list ::iterator it = observers.begin (); it != observers.end (); it++) { //std::cerr << "notify() observable: " << *it << std::endl; (*it)->update (this); } } Observable::Observable () { // complete } presage-0.8.8/src/lib/core/backoffCombiner.h0000644000175000017500000000255511737142176015626 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_BACKOFFCOMBINER #define PRESAGE_BACKOFFCOMBINER #include "combiner.h" /** Backoff combiner * */ class BackoffCombiner : public Combiner { public: BackoffCombiner(); ~BackoffCombiner(); private: }; #endif // PRESAGE_BACKOFFCOMBINER presage-0.8.8/src/lib/core/prediction.cpp0000644000175000017500000000616411737142176015247 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "prediction.h" #include Prediction::Prediction() {} Prediction::~Prediction() {} const Prediction &Prediction::operator=( const Prediction &right ) { if( &right != this ) { suggestions = right.suggestions; //assert( ( suggestions == right.suggestions ) ); } return *this; } bool Prediction::operator== (const Prediction& right) const { // same instance is obviously equal to itself if (&right == this) { return true; } else { if (size() != right.size()) { return false; } else { // need to compare each suggestion bool result = true; size_t i = 0; while (i < size() && result) { if (getSuggestion(i) != right.getSuggestion(i)) { result = false; } i++; } return result; } } } size_t Prediction::size() const { return suggestions.size(); } Suggestion Prediction::getSuggestion(int i) const { assert( i >= 0 && static_cast(i) < suggestions.size() ); return suggestions[i]; } Suggestion Prediction::getSuggestion(std::string token) const { for (size_t i = 0; i < suggestions.size(); i++) { if (suggestions[i].getWord() == token) { return suggestions[i]; } } return Suggestion(); } void Prediction::addSuggestion(Suggestion s) { // insert s so that suggestions vector is sorted // handle empty vector first if( suggestions.empty() ) { suggestions.push_back( s ); } else { std::vector< Suggestion >::iterator i = suggestions.begin(); while( i != suggestions.end() && s < *i ) { i++; } suggestions.insert( i, s ); } } std::string Prediction::toString() const { std::string str; std::vector::const_iterator i; for( i=suggestions.begin(); i!=suggestions.end(); i++ ) { str += i->toString(); } return str; } std::ostream &operator<<( std::ostream &output, const Prediction &p ) { std::vector::const_iterator i; for( i=p.suggestions.begin(); i!=p.suggestions.end(); i++ ) { output << *i << std::endl; } return output; } presage-0.8.8/src/lib/core/selector.cpp0000644000175000017500000001670611743227551014730 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "selector.h" #include "utility.h" const char* Selector::SUGGESTIONS = "Presage.Selector.SUGGESTIONS"; const char* Selector::REPEAT_SUGGESTIONS = "Presage.Selector.REPEAT_SUGGESTIONS"; const char* Selector::GREEDY_SUGGESTION_THRESHOLD = "Presage.Selector.GREEDY_SUGGESTION_THRESHOLD"; const char* Selector::LOGGER = "Presage.Selector.LOGGER"; Selector::Selector(Configuration* configuration, ContextTracker* ct) : contextTracker(ct), config(configuration), logger("Selector", std::cerr), dispatcher(this) { // build notification dispatch map dispatcher.map (config->find (LOGGER), & Selector::set_logger); dispatcher.map (config->find (SUGGESTIONS), & Selector::set_suggestions); dispatcher.map (config->find (REPEAT_SUGGESTIONS), & Selector::set_repeat_suggestions); dispatcher.map (config->find (GREEDY_SUGGESTION_THRESHOLD), & Selector::set_greedy_suggestion_threshold); // set prefix previous_prefix = contextTracker->getPrefix(); } Selector::~Selector() { // nothing to do here, move along } std::vector Selector::select( Prediction p ) { // copy words from Prediction.Suggestion.word in result vector std::vector result; std::string token; for (size_t i=0 ; icontextChange()) { logger << DEBUG << "Context change detected." << endl; clearSuggestedWords(); } else { logger << DEBUG << "No context change detected." << endl; } // filter out suggestions that do not satisfy repetition constraint if( !repeat_suggestions ) repetitionFilter( result ); // filter out suggestions that do not satisfy threshold constraint if( greedy_suggestion_threshold > 0 ) thresholdFilter( result ); // if more suggestions than required, trim suggestions down to requested number if( result.size() > suggestions ) { result.erase (result.begin() + suggestions, result.end()); } // update suggested words set updateSuggestedWords( result ); return result; } /** Trigger update of the suggested tokens cache * */ void Selector::update() { // check whether user has not moved on to a new word if (contextTracker->contextChange()) { clearSuggestedWords(); } } /** Adds suggestions to the set of previously selected suggestions. * */ void Selector::updateSuggestedWords( const std::vector& v ) { std::vector::const_iterator i = v.begin(); while( i != v.end() ) { logger << DEBUG << "Adding token to suggested token set: " << *i << endl; suggestedWords.insert( *i ); i++; } logger << DEBUG << "Suggested words: "; for (StringSet::const_iterator it = suggestedWords.begin(); it != suggestedWords.end(); it++) { logger << *it << ' '; } logger << endl; } /** Clear the set of previously selected suggestions. * */ void Selector::clearSuggestedWords() { logger << DEBUG << "Clearing previously suggested tokens set." << endl; suggestedWords.clear(); } /** Filters out suggestions that have previously been selected in the current context. * * This filter removes the suggestions that have previously been * selected. The set of suggestions that were previously selected is * stored in suggestedWords. This filters removes the words that are * contained in both @param v and suggestedWords. * */ void Selector::repetitionFilter( std::vector& v ) { std::vector< std::string > temp; for( std::vector::iterator i = v.begin(); i != v.end(); i++ ) { if( suggestedWords.find( *i ) == suggestedWords.end() ) { temp.push_back( *i ); logger << DEBUG << "Token passed repetition filter: " << *i << endl; } else { logger << DEBUG << "Token failed repetition filter: " << *i << endl; } } v = temp; } /** Filters out suggestions that could save fewer than THRESHOLD keystrokes. * * Assuming prefix.size() == n, suggestion.size() == m, and THRESHOLD * == t, then this filter removes those suggestions for which the * following condition is true: (m - n) < t * */ void Selector::thresholdFilter( std::vector& v ) { assert( greedy_suggestion_threshold >= 0 ); // zero threshold indicates feature is disabled if( greedy_suggestion_threshold != 0 ) { int length = contextTracker->getPrefix().size(); std::vector::iterator i = v.begin(); while (i != v.end()) { if( (i->size()-length) < greedy_suggestion_threshold) { logger << INFO << "Removing token: " << *i << endl; i = v.erase( i ); } else { i++; } } } } /** Set LOGGER option. * */ void Selector::set_logger (const std::string& value) { logger << setlevel (value); logger << INFO << "LOGGER: " << value << endl; } /** Set SUGGESTIONS option. * */ void Selector::set_suggestions(const std::string& value) { logger << INFO << "SUGGESTIONS: " << value << endl; int result = Utility::toInt(value); if (result < 0) { logger << ERROR << "Presage.Selector.SUGGESTIONS value out of range!/a" << endl; // REVISIT: throw exception abort(); } suggestions = result; } /** Set REPEAT_SUGGESTION option. * */ void Selector::set_repeat_suggestions(const std::string& value) { logger << INFO << "REPEAT_SUGGESTIONS: " << value << endl; bool result = Utility::isYes(value); repeat_suggestions = result; } /** Set SUGGESTION_THRESHOLD option. * */ void Selector::set_greedy_suggestion_threshold(const std::string& value) { logger << INFO << "GREEDY_SUGGESTION_THRESHOLD: " << value << endl; int result = Utility::toInt(value); if( result < 0 ) { logger << ERROR << "GREEDY_SUGGESTION_THRESHOLD value out of range." << value << endl; // REVISIT: throw exception abort(); } greedy_suggestion_threshold = result; } size_t Selector::get_suggestions () const { return suggestions; } bool Selector::get_repeat_suggestions () const { return repeat_suggestions; } size_t Selector::get_greedy_suggestion_threshold () const { return greedy_suggestion_threshold; } void Selector::update (const Observable* variable) { logger << DEBUG << "update(" << variable->get_name () << ") called" << endl; dispatcher.dispatch (variable); } presage-0.8.8/src/lib/core/utility.h0000644000175000017500000000455511763437013014255 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_UTILITY #define PRESAGE_UTILITY #ifdef HAVE_CONFIG_H # include "config.h" #endif #include // overload strtolower function class Utility { public: static char* strtolower( char* ); static std::string& strtolower( std::string& ); static std::string strtolower( const std::string& ); static std::string strtoupper( const std::string& ); static bool isTrueFalse( const char* ); static bool isTrueFalse( const std::string& ); static bool isTrue( const char* ); static bool isTrue( const std::string& ); static bool isFalse( const char* ); static bool isFalse( const std::string& ); static bool isYesNo( const char* ); static bool isYesNo( const std::string& ); static bool isYes( const char* ); static bool isYes( const std::string& ); static bool isNo( const char* ); static bool isNo( const std::string& ); static double toDouble(const std::string); static int toInt (const std::string); static std::string dirname (const std::string&); static std::string filename (const std::string&); static bool is_directory_usable (const std::string& dir); static void create_directory (const std::string& dir); }; #endif // PRESAGE_UTILITY presage-0.8.8/src/lib/core/logger.h0000644000175000017500000001342511737142176014031 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_LOGGER #define PRESAGE_LOGGER #if HAVE_CONFIG_H # include #endif #include // manipulators struct _SetLevel { std::string _level; }; /** * @brief Manipulator for @c level. * @param @__l The new logger level. * * Sent to a logger object, this manipulator calls @c setLevel(c) for that * object. */ inline _SetLevel setlevel(std::string __l) { _SetLevel __x; __x._level = __l; return __x; } template > class Logger { public: // type definitions enum Level { EMERG = 0, FATAL = 0, ALERT = 100, CRIT = 200, ERROR = 300, WARN = 400, NOTICE = 500, INFO = 600, DEBUG = 700, ALL = 800 }; // constructors inline Logger (std::string logger_name, std::basic_ostream<_charT,_Traits>& ostr) : outstream(ostr) { init(logger_name, "ERROR"); } inline Logger (std::string logger_name, std::basic_ostream<_charT,_Traits>& ostr, const std::string& lvl) : outstream(ostr) { init(logger_name, lvl); } inline void init(const std::string& name, const std::string& lvl) { set_name(name); state = new LoggerState(); set (state->loggerLevel, lvl); set (state->currentLevel, lvl); state->line_beginning = true; } // destructor inline ~Logger () { outstream.flush(); delete state; } // level getters/setters inline void setLevel(const std::string& lvl) const { set(state->loggerLevel, lvl); } inline void setLevel (Level lvl) const { state->loggerLevel = lvl; } inline Level getLevel () const { return state->loggerLevel; } inline void setCurrentLevel (Level lvl) const { state->currentLevel = lvl; } inline Level getCurrentLevel() const { return state->currentLevel; } inline bool shouldLog() const { return (state->loggerLevel >= state->currentLevel); } // logging method template friend inline const Logger& operator<< (const Logger& lgr, const T& msg) { //if (lgr.state->loggerLevel >= lgr.state->currentLevel) if (lgr.shouldLog()) { if (lgr.state->line_beginning) { lgr.outstream << lgr.name; lgr.state->line_beginning = false; } lgr.outstream << msg; } return lgr; } // this method is needed by the functions defined by macro // define_logger_level_manipulator(LEVEL) // friend inline const Logger& operator<< (const Logger& lgr, const Logger& (*fp)(const Logger&)) { (*fp)(lgr); return lgr; } inline const Logger& operator<< (_SetLevel __l) const { setLevel(__l._level); return *this; } inline void endl() const { //if (state->loggerLevel >= state->currentLevel) if (shouldLog()) { outstream << std::endl; state->line_beginning = true; } } private: inline void set(Level& level, const std::string& lvl) const { if (lvl == "EMERG") { level = EMERG; } else if (lvl == "FATAL") { level = FATAL; } else if (lvl == "ALERT") { level = ALERT; } else if (lvl == "CRIT") { level = CRIT; } else if (lvl == "ERROR") { level = ERROR; } else if (lvl == "WARN") { level = WARN; } else if (lvl == "NOTICE") { level = NOTICE; } else if (lvl == "INFO") { level = INFO; } else if (lvl == "DEBUG") { level = DEBUG; } else if (lvl == "ALL") { level = ALL; } else { level = ERROR; } } inline void set_name(const std::string& logger_name) { name = "[" + logger_name + "] "; } std::string name; std::basic_ostream <_charT, _Traits>& outstream; class LoggerState { public: bool line_beginning; Level loggerLevel; Level currentLevel; }; LoggerState* state; }; #define define_logger_level_manipulator(LEVEL) \ template \ inline const Logger<_charT, _Traits>& \ LEVEL (const Logger<_charT, _Traits>& lgr) \ { \ lgr.setCurrentLevel(Logger<_charT, _Traits>::LEVEL); \ return lgr; \ } define_logger_level_manipulator(EMERG ); define_logger_level_manipulator(FATAL ); define_logger_level_manipulator(ALERT ); define_logger_level_manipulator(CRIT ); define_logger_level_manipulator(ERROR ); define_logger_level_manipulator(WARN ); define_logger_level_manipulator(NOTICE); define_logger_level_manipulator(INFO ); define_logger_level_manipulator(DEBUG ); define_logger_level_manipulator(ALL ); template inline const Logger<_charT, _Traits>& endl (const Logger<_charT, _Traits>& lgr) { lgr.endl(); return lgr; } #endif // PRESAGE_LOGGER presage-0.8.8/src/lib/core/configuration.cpp0000644000175000017500000000740011737142176015750 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "configuration.h" #include Configuration::Configuration() { configuration = new std::map(); } Configuration::~Configuration() { for (std::map::iterator it = configuration->begin(); it != configuration->end(); it++) { //std::cerr << "[Configuration] Deleting variable: " << it->first << '\t' << it->second << std::endl; delete it->second; //std::cerr << "[Configuration] Deleted variable: " << it->first << std::endl; } delete configuration; } Variable* Configuration::find(const std::string& variable) const { std::map::const_iterator it = configuration->find (variable); if (it == configuration->end()) { // variable not found, create exception message std::string message = "[Configuration] Cannot find variable " + variable; // if we get here, variable was not found in the configuration, // hence we have a right to complain throw ConfigurationException(PRESAGE_CONFIG_VARIABLE_ERROR, message); } return it->second; } Variable* Configuration::operator[](const std::string& variable) const { return find(variable); } void Configuration::insert(const std::string& variable, const std::string& value) { std::map::const_iterator it = configuration->find (variable); if (it != configuration->end ()) { it->second->set_value (value); //std::cerr << "[Configuration] Modifying existing variable: " << variable << std::endl; } else { Variable* var = new Variable (variable); var->set_value (value); configuration->insert (std::pair (variable, var)); //std::cerr << "[Configuration] Adding new variable: " << variable << '\t' << var << std::endl; } //std::cerr << "[Configuration] Inserted variable: " << variable << std::endl; } void Configuration::remove(const std::string& variable) { std::map::iterator it = configuration->find (variable); if (it != configuration->end()) { delete it->second; configuration->erase (it); } } void Configuration::print() const { // iterate map for (std::map::const_iterator map_it = configuration->begin (); map_it != configuration->end (); map_it++) { // variable std::cout << map_it->first; // value std::cout << " = " << map_it->second->get_value () << std::endl; } } std::map::const_iterator Configuration::begin () const { return configuration->begin(); } std::map::const_iterator Configuration::end () const { return configuration->end(); } presage-0.8.8/src/lib/core/suggestion.h0000644000175000017500000000526211737142176014741 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SUGGESTION #define PRESAGE_SUGGESTION #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "../presageException.h" /** Suggestion * * A suggestion is a prediction token, probability pair. * * A prediction token is a string (word or single character). The * probability describes how likely the predictor estimated that the * associated predicted token is the desired token. * * Probability might have to be computed as logarithmic probability to * avoid buffer underflows. * */ class Suggestion { friend std::ostream &operator<<( std::ostream &, const Suggestion & ); public: Suggestion(std::string="",double=0.0); ~Suggestion(); bool operator== (const Suggestion&) const; bool operator!= (const Suggestion&) const; bool operator< (const Suggestion&) const; std::string getWord() const; double getProbability() const; void setWord(std::string); void setProbability(double); /** Returns a string representation of this suggestion. */ std::string toString() const; static const double MIN_PROBABILITY; static const double MAX_PROBABILITY; class SuggestionException : public PresageException { public: SuggestionException(presage_error_code_t code, const std::string& msg) throw() : PresageException(code, msg) { } virtual ~SuggestionException() throw() { } private: SuggestionException() throw() : PresageException(PRESAGE_ERROR, "") {}; }; private: std::string word; double probability; }; #endif // PRESAGE_SUGGESTION presage-0.8.8/src/lib/presageCallback.h0000644000175000017500000000747111737142176014671 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CALLBACK #define PRESAGE_CALLBACK #ifdef __cplusplus extern "C" { #endif typedef const char* (*_presage_callback_get_past_stream) (void*); typedef const char* (*_presage_callback_get_future_stream) (void*); #ifdef __cplusplus } #endif #ifdef __cplusplus #ifndef _MSC_VER #include #include /** Abstract callback object used to retrieve context from user application. * * A concrete callback implementation must implement the * getPastStream() and getFutureStream() method which are responsible * for retrieving the context from the user text buffer. * * Using a callback object decouples the user application from the * chosen text buffer (which could be a simple string, a graphical * text widget, a file stream, etc.) and frees the caller from having * to explicitly notify of any updates to the context. Presage will * invoke on the callback whenever access to contextual data is * required. * * getPastStream() must return a string containing the text preceding * the current insertion point. * * getFutureStream() must return a string containing the text * following the current insertion point. * */ class PresageCallback { public: virtual ~PresageCallback() { }; virtual std::string get_past_stream() const = 0; virtual std::string get_future_stream() const = 0; protected: PresageCallback() { }; }; /** DEPRECATED: simple context callback implementation to ease transition into presage callback refactor. * * This concrete callback object provides an update() method signature * that matches legacy Presage::update(std::string) method and is * designed to provide a simple upgrade path from previous presage * releases. * * Simply create a LegacyPresageCallback object, pass it as argument * to the new Presage object, and then replace all calls to * Presage::update(std::string) with a * LegacyPresageCallback::update(std::string) calls. * * WARNING: This class is deprecated and might be removed in future releases. * */ class LegacyPresageCallback : public PresageCallback { public: LegacyPresageCallback() { } ~LegacyPresageCallback() { } std::string get_past_stream() const { return m_stream; } std::string get_future_stream() const { return m_empty; } void update(std::string str) { for (size_t sz = 0; sz < str.size(); sz++) { update(str[sz]); } } private: void update(int character) { if (character == '\b' && ! m_stream.empty()) { m_stream.erase(m_stream.end() - 1); } else { m_stream.push_back(character); } } std::string m_stream; const std::string m_empty; }; #endif /* _MSC_VER */ #endif /* _cplusplus */ #endif /* PRESAGE_CALLBACK */ presage-0.8.8/src/lib/presage.h0000644000175000017500000002431011763437013013237 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE #define PRESAGE #include "presageException.h" #include "presageCallback.h" #ifdef __cplusplus extern "C" { #endif /* * Presage C API starts here */ typedef struct _presage* presage_t; presage_error_code_t presage_new (_presage_callback_get_past_stream past_stream_cb, void* past_stream_cb_arg, _presage_callback_get_future_stream future_stream_cb, void* future_stream_cb_arg, presage_t* result); presage_error_code_t presage_new_with_config (_presage_callback_get_past_stream past, void* past_stream_cb_arg, _presage_callback_get_future_stream future_stream_cb, void* future_stream_cb_arg, const char* config, presage_t* result); void presage_free (presage_t prsg); void presage_free_string (char* str); void presage_free_string_array (char** str); presage_error_code_t presage_predict (presage_t prsg, char*** result); presage_error_code_t presage_completion (presage_t prsg, const char* token, char** result); presage_error_code_t presage_context (presage_t prsg, char** result); presage_error_code_t presage_context_change (presage_t prsg, int* result); presage_error_code_t presage_prefix (presage_t prsg, char** result); presage_error_code_t presage_config (presage_t prsg, const char* variable, char** result); presage_error_code_t presage_config_set (presage_t prsg, const char* variable, const char* value); presage_error_code_t presage_save_config (presage_t prsg); /* * Presage C API ends here */ #ifdef __cplusplus } #endif #ifdef __cplusplus #ifndef _MSC_VER /* * Presage C++ API starts here */ #include #include #include /* Forward declarations, not part of presage C++ API */ class Configuration; class ProfileManager; class Profile; class ContextTracker; class PredictorRegistry; class PredictorActivator; class Selector; /** \brief Presage, the intelligent predictive text entry platform. */ class Presage { public: /** Creates and initializes presage. * * \param callback is a user-supplied implementation of PresageCallback interface * * Presage does not take ownership of the callback object. */ Presage(PresageCallback* callback) throw (PresageException); /** Creates and initializes presage with supplied configuration. * * \param callback is a user-supplied implementation of PresageCallback interface * \param config path to configuration file * * Presage does not take ownership of the callback object. */ Presage(PresageCallback* callback, const std::string config) throw (PresageException); /** Destroys presage. */ ~Presage(); /** \brief Obtain a prediction. * * This method requests that presage generates a prediction based * on the current context. * * \return prediction (vector of strings) based on the current * context. * */ std::vector predict() throw (PresageException); /** \brief Obtain a prediction that matches the supplied token * filter. * * \param filter a vector of strings to use to filter the * prediction for desired tokens. I.e. If the current prefix is * "gr" and the filter is ["ea", "an"], then only words starting * with "grea" or "gran" such as "great" or "grand" will be * returned in the prediction. * * \return prediction containing only tokens that begin with one * of the filter tokens. * */ std::multimap predict(std::vector filter) throw (PresageException); /** \brief Callback getter/setter. * * \param callback to be used by presage (pass a null pointer to * obtain callback to current callback without modifying it) * * \return pointer to previously used callback */ PresageCallback* callback(PresageCallback* callback) throw (PresageException); /** \brief Request presage to return the completion string for the given predicted token. * * Requests presage to return the completion string. The * completion string is defined as the string which, when appended * to the current prefix, forms the token passed as the str * argument. * * \param str successful prediction, for which a completion string * is requested * * \return completion string */ std::string completion(std::string str) throw (PresageException); /** \brief Returns the text entered so far. * * \return context, text entered so far. */ std::string context() const throw (PresageException); /** \brief Returns true if a context change occured. * * \return true if a context change occured after the last update * or predict calls, or false otherwise. */ bool context_change() const throw (PresageException); /** \brief Returns the current prefix. * * \return prefix */ std::string prefix() const throw (PresageException); /** \brief Gets the value of specified configuration variable. * * Programmatically get the value currently assigned to the * specified configuration \param variable * * \return value assigned to configuration variable. */ std::string config(const std::string variable) const throw (PresageException); /** \brief Sets the value of specified configuration variable. * * Programmatically set the specified configuration \param * variable to \param value . This will override the setting read * from the configuration file in use. * */ void config(const std::string variable, const std::string value) const throw (PresageException); /** \brief Save current configuration to file. * * Call this method to persist current presage configuration to * file. The configuration data will be saved to the currently * active XML profile. * */ void save_config() const throw (PresageException); /* * Presage public API ends here */ private: ProfileManager* profileManager; Configuration* configuration; PredictorRegistry* predictorRegistry; ContextTracker* contextTracker; PredictorActivator* predictorActivator; Selector* selector; }; /* * Presage C++ API ends here */ #endif /* _MSC_VER */ #endif /* __cplusplus */ /** \mainpage \section intro_section Introduction Presage is an intelligent predictive text entry platform. Presage exploits redundant information embedded in natural languages to generate predictions. Presage's modular and pluggable architecture allows its language model to be extended and customized to utilize statistical, syntactic, and semantic information sources. A predictive text entry system attempts to improve ease and speed of textual input. Word prediction consists in computing which word tokens or word completions are most likely to be entered next. The system analyses the text already entered and combines the information thus extracted with other information sources to calculate a set of most probable tokens. A typical presage-based application would display the set of most probable tokens (i.e. a list of suggestions) to the user and automatically enter the desired token after the user selects it. If the list of suggestions does not contain the desired word, the user continues entering text until the correct suggestion is offered or until the user is done entering text. Presage is fundamentally different from predictive input technologies commonly found on mobile phones, which might more accurately be described as 'disambiguating text entry' rather than 'predictive text entry' systems. Such systems do not try to guess what the user intends to write in the future, only to determine what they most-likely intend to write in the present, given their past input. Presage, on the other hand, actively predicts the what the user intends to write, and only reverts to word completion mode if the prediction did not contain the desired token. Presage is free software. It is distributed under the term of the General Public License. \author Matteo Vescovi \section getting_started_section Getting started \include getting_started.txt */ #endif /* PRESAGE */ presage-0.8.8/src/lib/Makefile.in0000644000175000017500000006511411763440355013517 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_LD_WITH_VERSION_SCRIPT_TRUE@am__append_1 = -Wl,--version-script,$(srcdir)/libpresage.map @BUILD_TINYXML_TRUE@am__append_2 = tinyxml/libtinyxml.la @BUILD_TINYXML_FALSE@am__append_3 = -ltinyxml subdir = src/lib DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libpresage_la_DEPENDENCIES = core/libcore.la \ predictors/libpredictors.la $(am__append_2) \ $(am__DEPENDENCIES_1) am_libpresage_la_OBJECTS = libpresage_la-presage.lo libpresage_la_OBJECTS = $(am_libpresage_la_OBJECTS) libpresage_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(libpresage_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libpresage_la_SOURCES) DIST_SOURCES = $(libpresage_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive HEADERS = $(include_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = tinyxml core predictors DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @BUILD_TINYXML_TRUE@MAYBE_TINYXML = tinyxml SUBDIRS = $(MAYBE_TINYXML) core predictors include_HEADERS = presage.h \ presageException.h \ presageCallback.h lib_LTLIBRARIES = libpresage.la libpresage_la_SOURCES = presage.cpp \ presage.h \ presageException.h \ presageCallback.h \ libpresage.map libpresage_la_LIBADD = core/libcore.la predictors/libpredictors.la \ $(am__append_2) $(am__append_3) libpresage_la_LDFLAGS = -no-undefined -version-info 2:1:1 \ $(am__append_1) @BUILD_TINYXML_TRUE@libpresage_la_CPPFLAGS = -I$(top_srcdir)/src/lib/tinyxml EXTRA_DIST = libpresage.map all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libpresage.la: $(libpresage_la_OBJECTS) $(libpresage_la_DEPENDENCIES) $(libpresage_la_LINK) -rpath $(libdir) $(libpresage_la_OBJECTS) $(libpresage_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpresage_la-presage.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< libpresage_la-presage.lo: presage.cpp @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpresage_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libpresage_la-presage.lo -MD -MP -MF $(DEPDIR)/libpresage_la-presage.Tpo -c -o libpresage_la-presage.lo `test -f 'presage.cpp' || echo '$(srcdir)/'`presage.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libpresage_la-presage.Tpo $(DEPDIR)/libpresage_la-presage.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='presage.cpp' object='libpresage_la-presage.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpresage_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libpresage_la-presage.lo `test -f 'presage.cpp' || echo '$(srcdir)/'`presage.cpp mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(includedir)" && rm -f $$files # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-includeHEADERS install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool ctags ctags-recursive \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am \ install-includeHEADERS install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-recursive uninstall uninstall-am \ uninstall-includeHEADERS uninstall-libLTLIBRARIES # 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: presage-0.8.8/src/lib/libpresage.map0000644000175000017500000000140011737142176014253 00000000000000PRESAGE_0.8.3 { global: extern "C++" { Presage::*Presage*; Presage::predict*; Presage::callback*; Presage::completion*; Presage::context*; Presage::context_change*; Presage::prefix*; Presage::config*; Presage::save_config*; PresageException::*PresageException*; PresageException::what*; typeinfo*PresageException; vtable*PresageException; }; local: *; }; PRESAGE_0.8.5 { global: presage_completion; presage_config; presage_config_set; presage_context; presage_context_change; presage_free; presage_free_string; presage_free_string_array; presage_new; presage_new_with_config; presage_predict; presage_prefix; presage_save_config; } PRESAGE_0.8.3; presage-0.8.8/src/lib/tinyxml/0000755000175000017500000000000011764714755013240 500000000000000presage-0.8.8/src/lib/tinyxml/utf8test.xml0000644000175000017500000000126211737142176015461 00000000000000 The world has many languages Мир имеет много Ñзыков el mundo tiene muchos idiomas 世界有很多语言 <РуÑÑкий название="name" ценноÑть="value"><имеет> <汉语 åå­—="name" 价值="value">世界有很多语言 "Mëtæl!" <ä>Umlaut Element presage-0.8.8/src/lib/tinyxml/changes.txt0000644000175000017500000003627211743227551015331 00000000000000Changes in version 1.0.1: - Fixed comment tags which were outputing as ' include. Thanks to Steve Lhomme for that. Changes in version 2.0.0 BETA - Made the ToXXX() casts safe if 'this' is null. When "LoadFile" is called with a filename, the value will correctly get set. Thanks to Brian Yoder. - Fixed bug where isalpha() and isalnum() would get called with a negative value for high ascii numbers. Thanks to Alesky Aksenov. - Fixed some errors codes that were not getting set. - Made methods "const" that were not. - Added a switch to enable or disable the ignoring of white space. ( TiXmlDocument::SetIgnoreWhiteSpace() ) - Greater standardization and code re-use in the parser. - Added a stream out operator. - Added a stream in operator. - Entity support, of predefined entites. &#x entities are untouched by input or output. - Improved text out formatting. - Fixed ReplaceChild bug, thanks to Tao Chen. Changes in version 2.0.1 - Fixed hanging on loading a 0 length file. Thanks to Jeff Scozzafava. - Fixed crashing on InsertBeforeChild and InsertAfterChild. Also possibility of bad links being created by same function. Thanks to Frank De prins. - Added missing licence text. Thanks to Lars Willemsens. - Added include, at the suggestion of Steve Walters. Changes in version 2.1.0 - Yves Berquin brings us the STL switch. The forum on SourceForge, and various emails to me, have long debated all out STL vs. no STL at all. And now you can have it both ways. TinyXml will compile either way. Changes in version 2.1.1 - Compilation warnings. Changes in version 2.1.2 - Uneeded code is not compiled in the STL case. - Changed headers so that STL can be turned on or off in tinyxml.h Changes in version 2.1.3 - Fixed non-const reference in API; now uses a pointer. - Copy constructor of TiXmlString not checking for assignment to self. - Nimrod Cohen found a truly evil bug in the STL implementation that occurs when a string is converted to a c_str and then assigned to self. Search for STL_STRING_BUG for a full description. I'm asserting this is a Microsoft STL bug, since &string and string.c_str() should never be the same. Nevertheless, the code works around it. - Urivan Saaib pointed out a compiler conflict, where the C headers define the isblank macro, which was wiping out the TiXmlString::isblank() method. The method was unused and has been removed. Changes in version 2.1.4 - Reworked the entity code. Entities were not correctly surving round trip input and output. Will now automatically create entities for high ascii in output. Changes in version 2.1.5 - Bug fix by kylotan : infinite loop on some input (tinyxmlparser.cpp rev 1.27) - Contributed by Ivica Aracic (bytelord) : 1 new VC++ project to compile versions as static libraries (tinyxml_lib.dsp), and an example usage in xmltest.dsp (Patch request ID 678605) - A suggestion by Ronald Fenner Jr (dormlock) to add #include and for Apple's Project Builder (Patch request ID 697642) - A patch from ohommes that allows to parse correctly dots in element names and attribute names (Patch request 602600 and kylotan 701728) - A patch from hermitgeek ( James ) and wasteland for improper error reporting - Reviewed by Lee, with the following changes: - Got sick of fighting the STL/non-STL thing in the windows build. Broke them out as seperate projects. - I have too long not included the dsw. Added. - TinyXmlText had a protected Print. Odd. - Made LinkEndChild public, with docs and appropriate warnings. - Updated the docs. 2.2.0 - Fixed an uninitialized pointer in the TiXmlAttributes - Fixed STL compilation problem in MinGW (and gcc 3?) - thanks Brian Yoder for finding this one - Fixed a syntax error in TiXmlDeclaration - thanks Brian Yoder - Fletcher Dunn proposed and submitted new error handling that tracked the row and column. Lee modified it to not have performance impact. - General cleanup suggestions from Fletcher Dunn. - In error handling, general errors will no longer clear the error state of specific ones. - Fix error in documentation : comments starting with ">) has now been fixed. 2.5.2 - Lieven, and others, pointed out a missing const-cast that upset the Open Watcom compiler. Should now be fixed. - ErrorRow and ErrorCol should have been const, and weren't. Fixed thanks to Dmitry Polutov. 2.5.3 - zloe_zlo identified a missing string specialization for QueryValueAttribute() [ 1695429 ]. Worked on this bug, but not sure how to fix it in a safe, cross-compiler way. - increased warning level to 4 and turned on detect 64 bit portability issues for VC2005. May address [ 1677737 ] VS2005: /Wp64 warnings - grosheck identified several problems with the Document copy. Many thanks for [ 1660367 ] - Nice catch, and suggested fix, be Gilad Novik on the Printer dropping entities. "[ 1600650 ] Bug when printing xml text" is now fixed. - A subtle fix from Nicos Gollan in the tinystring initializer: [ 1581449 ] Fix initialiser of TiXmlString::nullrep_ - Great catch, although there isn't a submitter for the bug. [ 1475201 ] TinyXML parses entities in comments. Comments should not, in fact, parse entities. Fixed the code path and added tests. - We were not catching all the returns from ftell. Thanks to Bernard for catching that. 2.5.4 - A TiXMLDocument can't be a sub-node. Block this from happening in the 'replace'. Thanks Noam. - [ 1714831 ] TiXmlBase::location is not copied by copy-ctors, fix reported and suggested by Nicola Civran. - Fixed possible memory overrun in the comment reading code - thanks gcarlton77 2.5.5 - Alex van der Wal spotted incorrect types (lf) being used in print and scan. robertnestor pointed out some problems with the simple solution. Types updated. - Johannes Hillert pointed out some bug typos. - Christian Mueller identified inconsistent error handling with Attributes. - olivier barthelemy also reported a problem with double truncation, also related to the %lf issue. - zaelsius came up with a great (and simple) suggestion to fix QueryValueAttribute truncating strings. - added some null pointer checks suggested by hansenk - Sami Väisänen found a (rare) buffer overrun that could occur in parsing. - vi tri filed a bug that led to a refactoring of the attribute setting mess (as well as adding a missing SetDoubleAttribute() ) - removed TIXML_ERROR_OUT_OF_MEMORY. TinyXML does not systematically address OOO, and the notion it does is misleading. - vanneto, keithmarshall, others all reported the warning from IsWhiteSpace() usage. Cleaned this up - many thanks to everyone who reported this one. - tibur found a bug in end tag parsing 2.6.2 - Switched over to VC 2010 - Fixed up all the build issues arising from that. (Lots of latent build problems.) - Removed the old, now unmaintained and likely not working, build files. - Fixed some static analysis issues reported by orbitcowboy from cppcheck. - Bayard 95 sent in analysis from a different analyzer - fixes applied from that as well. - Tim Kosse sent a patch fixing an infinite loop. - Ma Anguo identified a doc issue. - Eddie Cohen identified a missing qualifier resulting in a compilation error on some systems. - Fixed a line ending bug. (What year is this? Can we all agree on a format for text files? Please? ...oh well.) presage-0.8.8/src/lib/tinyxml/tinyxmlparser.cpp0000644000175000017500000011057211743227551016601 00000000000000/* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #include #include "tinyxml.h" //#define DEBUG_PARSER #if defined( DEBUG_PARSER ) # if defined( DEBUG ) && defined( _MSC_VER ) # include # define TIXML_LOG OutputDebugString # else # define TIXML_LOG printf # endif #endif // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries // or order will break putstring. TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, { ">", 4, '>' }, { """, 6, '\"' }, { "'", 6, '\'' } }; // Bunch of unicode info at: // http://www.unicode.org/faq/utf_bom.html // Including the basic of this table, which determines the #bytes in the // sequence from the lead byte. 1 placed for invalid sequences -- // although the result will be junk, pass it through as much as possible. // Beware of the non-characters in UTF-8: // ef bb bf (Microsoft "lead bytes") // ef bf be // ef bf bf const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; const int TiXmlBase::utf8ByteTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid }; void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) { const unsigned long BYTE_MASK = 0xBF; const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; if (input < 0x80) *length = 1; else if ( input < 0x800 ) *length = 2; else if ( input < 0x10000 ) *length = 3; else if ( input < 0x200000 ) *length = 4; else { *length = 0; return; } // This code won't covert this correctly anyway. output += *length; // Scary scary fall throughs. switch (*length) { case 4: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 3: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 2: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 1: --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); } } /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalpha( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalpha( anyByte ); // } } /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalnum( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalnum( anyByte ); // } } class TiXmlParsingData { friend class TiXmlDocument; public: void Stamp( const char* now, TiXmlEncoding encoding ); const TiXmlCursor& Cursor() const { return cursor; } private: // Only used by the document! TiXmlParsingData( const char* start, int _tabsize, int row, int col ) { assert( start ); stamp = start; tabsize = _tabsize; cursor.row = row; cursor.col = col; } TiXmlCursor cursor; const char* stamp; int tabsize; }; void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) { assert( now ); // Do nothing if the tabsize is 0. if ( tabsize < 1 ) { return; } // Get the current row, column. int row = cursor.row; int col = cursor.col; const char* p = stamp; assert( p ); while ( p < now ) { // Treat p as unsigned, so we have a happy compiler. const unsigned char* pU = (const unsigned char*)p; // Code contributed by Fletcher Dunn: (modified by lee) switch (*pU) { case 0: // We *should* never get here, but in case we do, don't // advance past the terminating null character, ever return; case '\r': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \r\n sequence, and treat this as a single character if (*p == '\n') { ++p; } break; case '\n': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \n\r sequence, and treat this as a single // character. (Yes, this bizarre thing does occur still // on some arcane platforms...) if (*p == '\r') { ++p; } break; case '\t': // Eat the character ++p; // Skip to next tab stop col = (col / tabsize + 1) * tabsize; break; case TIXML_UTF_LEAD_0: if ( encoding == TIXML_ENCODING_UTF8 ) { if ( *(p+1) && *(p+2) ) { // In these cases, don't advance the column. These are // 0-width spaces. if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) p += 3; else { p +=3; ++col; } // A normal character. } } else { ++p; ++col; } break; default: if ( encoding == TIXML_ENCODING_UTF8 ) { // Eat the 1 to 4 byte utf8 character. int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; if ( step == 0 ) step = 1; // Error case from bad encoding, but handle gracefully. p += step; // Just advance one column, of course. ++col; } else { ++p; ++col; } break; } } cursor.row = row; cursor.col = col; assert( cursor.row >= -1 ); assert( cursor.col >= -1 ); stamp = p; assert( stamp ); } const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) { if ( !p || !*p ) { return 0; } if ( encoding == TIXML_ENCODING_UTF8 ) { while ( *p ) { const unsigned char* pU = (const unsigned char*)p; // Skip the stupid Microsoft UTF-8 Byte order marks if ( *(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbeU ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbfU ) { p += 3; continue; } if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. ++p; else break; } } else { while ( *p && IsWhiteSpace( *p ) ) ++p; } return p; } #ifdef TIXML_USE_STL /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) { for( ;; ) { if ( !in->good() ) return false; int c = in->peek(); // At this scope, we can't get to a document. So fail silently. if ( !IsWhiteSpace( c ) || c <= 0 ) return true; *tag += (char) in->get(); } } /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) { //assert( character > 0 && character < 128 ); // else it won't work in utf-8 while ( in->good() ) { int c = in->peek(); if ( c == character ) return true; if ( c <= 0 ) // Silent failure: can't get document at this scope return false; in->get(); *tag += (char) c; } return false; } #endif // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The // "assign" optimization removes over 10% of the execution time. // const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) { // Oddly, not supported on some comilers, //name->clear(); // So use this: *name = ""; assert( p ); // Names start with letters or underscores. // Of course, in unicode, tinyxml has no idea what a letter *is*. The // algorithm is generous. // // After that, they can be letters, underscores, numbers, // hyphens, or colons. (Colons are valid ony for namespaces, // but tinyxml can't tell namespaces from names.) if ( p && *p && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) { const char* start = p; while( p && *p && ( IsAlphaNum( (unsigned char ) *p, encoding ) || *p == '_' || *p == '-' || *p == '.' || *p == ':' ) ) { //(*name) += *p; // expensive ++p; } if ( p-start > 0 ) { name->assign( start, p-start ); } return p; } return 0; } const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) { // Presume an entity, and pull it out. TIXML_STRING ent; int i; *length = 0; if ( *(p+1) && *(p+1) == '#' && *(p+2) ) { unsigned long ucs = 0; ptrdiff_t delta = 0; unsigned mult = 1; if ( *(p+2) == 'x' ) { // Hexadecimal. if ( !*(p+3) ) return 0; const char* q = p+3; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != 'x' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else if ( *q >= 'a' && *q <= 'f' ) ucs += mult * (*q - 'a' + 10); else if ( *q >= 'A' && *q <= 'F' ) ucs += mult * (*q - 'A' + 10 ); else return 0; mult *= 16; --q; } } else { // Decimal. if ( !*(p+2) ) return 0; const char* q = p+2; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != '#' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else return 0; mult *= 10; --q; } } if ( encoding == TIXML_ENCODING_UTF8 ) { // convert the UCS to UTF-8 ConvertUTF32ToUTF8( ucs, value, length ); } else { *value = (char)ucs; *length = 1; } return p + delta + 1; } // Now try to match it. for( i=0; iappend( cArr, len ); } } else { bool whitespace = false; // Remove leading white space: p = SkipWhiteSpace( p, encoding ); while ( p && *p && !StringEqual( p, endTag, caseInsensitive, encoding ) ) { if ( *p == '\r' || *p == '\n' ) { whitespace = true; ++p; } else if ( IsWhiteSpace( *p ) ) { whitespace = true; ++p; } else { // If we've found whitespace, add it before the // new character. Any whitespace just becomes a space. if ( whitespace ) { (*text) += ' '; whitespace = false; } int len; char cArr[4] = { 0, 0, 0, 0 }; p = GetChar( p, cArr, &len, encoding ); if ( len == 1 ) (*text) += cArr[0]; // more efficient else text->append( cArr, len ); } } } if ( p && *p ) p += strlen( endTag ); return ( p && *p ) ? p : 0; } #ifdef TIXML_USE_STL void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) { // The basic issue with a document is that we don't know what we're // streaming. Read something presumed to be a tag (and hope), then // identify it, and call the appropriate stream method on the tag. // // This "pre-streaming" will never read the closing ">" so the // sub-tag can orient itself. if ( !StreamTo( in, '<', tag ) ) { SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } while ( in->good() ) { int tagIndex = (int) tag->length(); while ( in->good() && in->peek() != '>' ) { int c = in->get(); if ( c <= 0 ) { SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); break; } (*tag) += (char) c; } if ( in->good() ) { // We now have something we presume to be a node of // some sort. Identify it, and call the node to // continue streaming. TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); if ( node ) { node->StreamIn( in, tag ); bool isElement = node->ToElement() != 0; delete node; node = 0; // If this is the root element, we're done. Parsing will be // done by the >> operator. if ( isElement ) { return; } } else { SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } } } // We should have returned sooner. SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); } #endif const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) { ClearError(); // Parse away, at the document level. Since a document // contains nothing but other tags, most of what happens // here is skipping white space. if ( !p || !*p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } // Note that, for a document, this needs to come // before the while space skip, so that parsing // starts from the pointer we are given. location.Clear(); if ( prevData ) { location.row = prevData->cursor.row; location.col = prevData->cursor.col; } else { location.row = 0; location.col = 0; } TiXmlParsingData data( p, TabSize(), location.row, location.col ); location = data.Cursor(); if ( encoding == TIXML_ENCODING_UNKNOWN ) { // Check for the Microsoft UTF-8 lead bytes. const unsigned char* pU = (const unsigned char*)p; if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) { encoding = TIXML_ENCODING_UTF8; useMicrosoftBOM = true; } } p = SkipWhiteSpace( p, encoding ); if ( !p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } while ( p && *p ) { TiXmlNode* node = Identify( p, encoding ); if ( node ) { p = node->Parse( p, &data, encoding ); LinkEndChild( node ); } else { break; } // Did we get encoding info? if ( encoding == TIXML_ENCODING_UNKNOWN && node->ToDeclaration() ) { TiXmlDeclaration* dec = node->ToDeclaration(); const char* enc = dec->Encoding(); assert( enc ); if ( *enc == 0 ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice else encoding = TIXML_ENCODING_LEGACY; } p = SkipWhiteSpace( p, encoding ); } // Was this empty? if ( !firstChild ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); return 0; } // All is well. return p; } void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) { // The first error in a chain is more accurate - don't set again! if ( error ) return; assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); error = true; errorId = err; errorDesc = errorString[ errorId ]; errorLocation.Clear(); if ( pError && data ) { data->Stamp( pError, encoding ); errorLocation = data->Cursor(); } } TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) { TiXmlNode* returnNode = 0; p = SkipWhiteSpace( p, encoding ); if( !p || !*p || *p != '<' ) { return 0; } p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { return 0; } // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: "; if ( !StringEqual( p, startTag, false, encoding ) ) { if ( document ) document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); // [ 1475201 ] TinyXML parses entities in comments // Oops - ReadText doesn't work, because we don't want to parse the entities. // p = ReadText( p, &value, false, endTag, false, encoding ); // // from the XML spec: /* [Definition: Comments may appear anywhere in a document outside other markup; in addition, they may appear within the document type declaration at places allowed by the grammar. They are not part of the document's character data; an XML processor MAY, but need not, make it possible for an application to retrieve the text of comments. For compatibility, the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity references MUST NOT be recognized within comments. An example of a comment: */ value = ""; // Keep all the white space. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value.append( p, 1 ); ++p; } if ( p && *p ) p += strlen( endTag ); return p; } const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) return 0; if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } // Read the name, the '=' and the value. const char* pErr = p; p = ReadName( p, &name, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); return 0; } p = SkipWhiteSpace( p, encoding ); if ( !p || !*p || *p != '=' ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } ++p; // skip '=' p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } const char* end; const char SINGLE_QUOTE = '\''; const char DOUBLE_QUOTE = '\"'; if ( *p == SINGLE_QUOTE ) { ++p; end = "\'"; // single quote in string p = ReadText( p, &value, false, end, false, encoding ); } else if ( *p == DOUBLE_QUOTE ) { ++p; end = "\""; // double quote in string p = ReadText( p, &value, false, end, false, encoding ); } else { // All attribute values should be in single or double quotes. // But this is such a common error that the parser will try // its best, even without them. value = ""; while ( p && *p // existence && !IsWhiteSpace( *p ) // whitespace && *p != '/' && *p != '>' ) // tag end { if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { // [ 1451649 ] Attribute values with trailing quotes not handled correctly // We did not have an opening quote but seem to have a // closing one. Give up and throw an error. if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } value += *p; ++p; } } return p; } #ifdef TIXML_USE_STL void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->peek(); if ( !cdata && (c == '<' ) ) { return; } if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; in->get(); // "commits" the peek made above if ( cdata && c == '>' && tag->size() >= 3 ) { size_t len = tag->size(); if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { // terminator of cdata. return; } } } } #endif const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { value = ""; TiXmlDocument* document = GetDocument(); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } const char* const startTag = ""; if ( cdata || StringEqual( p, startTag, false, encoding ) ) { cdata = true; if ( !StringEqual( p, startTag, false, encoding ) ) { if ( document ) document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); return 0; } p += strlen( startTag ); // Keep all the white space, ignore the encoding, etc. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value += *p; ++p; } TIXML_STRING dummy; p = ReadText( p, &dummy, false, endTag, false, encoding ); return p; } else { bool ignoreWhite = true; const char* end = "<"; p = ReadText( p, &value, ignoreWhite, end, false, encoding ); if ( p && *p ) return p-1; // don't truncate the '<' return 0; } } #ifdef TIXML_USE_STL void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->get(); if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; if ( c == '>' ) { // All is well. return; } } } #endif const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) { p = SkipWhiteSpace( p, _encoding ); // Find the beginning, find the end, and look for // the stuff in-between. TiXmlDocument* document = GetDocument(); if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); return 0; } if ( data ) { data->Stamp( p, _encoding ); location = data->Cursor(); } p += 5; version = ""; encoding = ""; standalone = ""; while ( p && *p ) { if ( *p == '>' ) { ++p; return p; } p = SkipWhiteSpace( p, _encoding ); if ( StringEqual( p, "version", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); version = attrib.Value(); } else if ( StringEqual( p, "encoding", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); encoding = attrib.Value(); } else if ( StringEqual( p, "standalone", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); standalone = attrib.Value(); } else { // Read over whatever it is. while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++p; } } return 0; } bool TiXmlText::Blank() const { for ( unsigned i=0; i}(‚8ql”`!q{rñ€J–ÜÄ¢ŒT±ŠMŒÚ˜J<:Ž ÉH\”ÄlEÇ’MRT Ç¥.BŽCWHµ˜¹…(\§  #IHLöAbºÉ ÝÞ³kw#)/QD¡ˆ£¥Ó«_ï„@Þ&&òQw!·DüŠÛö„ºÉkºæ$z˜9ÖEciWBx@‚û‘À“wEˆ—D|Ó)aVlìuèÿázî…†Ä]@á À·ßŠù%AqŽáS!s=Àøé'„ŒmIØŸŠ*ÞwLÈĆ&©äh§‰8#üÙ¢”?‘”ÆÝPUºpPä¨ÍTV¹åvOXHfš‡Þ’pÆ)“V ‚Gd øTæõXH‚ &øè“‰‚ô0¤ ¡ÆùÈgI6f%¦Idƒ É©é¦Ýô¦†¤‘^,Nia ˆ Û€Pö”]6Ž®Ãjƒîyi…^R)b!jœ+¬47=YÄ]®Á6¥™}Þª\5¡…”â@S|Z áœHôIGÝ£\XÔÜ’Ä¡¥FL5ÿìºìB#"Eb±Ä³:–9â¹.¤°Vfµƒ(>hÕYØ—ˆ-k¡¥[.ëåa¯¢[„“íF,ñÄWlñÅg¬ñÆwìñÇ ‡,òÈ$—lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8cÌ 9÷ìsÄ ±ó!C?üóÑHR,EÒôê&-õÔ•xªÄÓƒ`TÔTwíõ!tqÀ, p@Ó Œ]ö QÁ;+‚Ð<Ñôΰ³., ÀÞE¼½7v³@Þ,ðM÷ÎŒñ°_G.9M"¡À!AÑ pá 0@Û.\¾€æ ÐMÄÝ,4Ð6e»îì qÿ9á üM¸ {·] µ«®açMnüñp„˜ÄÙ§.ÄÙ™k¼ Ìñ4ë«×-ôϳм $.üöÎù¾È§¯>*´ï¾ I(ÙEMÿêÜßoÄõÚóŸ½úžÿƧ¡ó­ï€lÂûܧ„ÊíO{„ ïx¦5b¯|dœ-Ø? ÁM ¡±¶ÿ™0€¼ËŸ9ˆÁ žp…,$ ã25ÂÚP V‚Þ¢'¼êI¯v>BÁ Æ0ˆõ+b­Äµ:ñ‰KXX €¶Q œèD×¶Î  y!¨ÛÙ†Èĵp€¥†°€Ô¹ƒc<ä HÇ:ÿ*ø[⦨½´‘Íl¤{ÜÇó%.|K<#+ ÇÖ ñT[Ù”cÇJZò’˜Ì¤&7ÉÉNzò“  ¥(GIÊRšò”¨L¥*WÉÊVºò•°Œ¥,9VÁ«Á°ÜpVrÙ…Zª£KTh0µÀK.³8¦”yfr™­P–|É´[Š&4ÜàŒ˜j¢èK<ü±onœY€¦Ð9%óï‚:õ0O"ÔÓ÷´D>?ᤤ¸d‚Ù´¦¸YM Uei2ÌA­'PAüäå‚9µÑ+ì LJώÊs˜~Øç=/: ’j¡C GŽ YÎDÚR ÿM,H[¨…‰špCN±`S,ìt &mBN4Ž‚ÔžGåƒH“ŠTdv"¨–˜i[8ÔÓ'T•¥LÜh4J˜ÄjpDP›ÙŒØ4`±lhÞξ*¾nqŠÓá /0·Âå p~ë·ÇÇDf5ÇŒ@ ЂX€ @À1pX£¶€f\ Xa~ p€0°”þ5 ºÂ ×Ñõ¦ht_ °»'lÆ1ŠmÁ†0‚Í !±‹m,> Mhfv³ Ëgð¸¢Î3°ƒ-¬n…ðÛp ± ® ûX!lÀ¶B°€f[à€å*3¹»uê’[€ŒT˜‚%ÿ¬a[ç.w8&4„cBV²”5o .;Þö2Ö±éU®b;Ûì ÍL*n7«[äªw¹.H®ôëÔÞuÁî-‚„)L„æ>wð•/}†‘:ÁŸ7M"[ãú¼?ƒe=ëÒJ·#¡¸Þp C«ißMO—‹ÞÈZ7Ú‰‹të±jÌP%ÿ.x.h@ôž\8ÙÁnVfòí\;´öL\ªoG…9âð¾³Ìcv.uñ;àŽJ· °{äïÖå)3™›MÛr—¿ fge».ˆm> Ï;ÓÂâmï1ß|$â}ŠÐFHs ʬha2Zµ´þLfæ ³À•v®cÿ×^"„š©Ží(šUm`"!ÍXs &Kè3׺Ð.à´†°ÝAG:©c6tšË,ëx–Ú±©>&±Ó<„P×c&‚Ž‘•bµpNÖ2æ„0d—ÍÈ.€’'˜m(ÐÑÑŸ[jAîQÏ{¨M$Ö‚w=wïØnöîj É÷îï…ÅÁ¦¯¡]X^·‡f\p]…3\˜¸­Ã9è&0€Š@fA ã­Èîù»­V n( qƒ á M¸x­ß…S\ÔQ@RŽ+ðVG<¯ø" Ì]» ¾=ÂvG®_ZÐ G¶Ä;òcÿº/¹ÐÎÌÀnÚç nÁ®ÿõ‡|ê'¯zÍ]@ð›Swá(Çú̓ꪧ|ìe_:š.ö•;³ía©~çiœwýå tÓ3€uu'á9Id7K'ÙoŽG°ô.b¾ sgþÞ|¡¾!Y4,6`Øüµ;.Ú4€lxV"Ep»•À€¬•îtfª:¬È!`zÔ{[õ.@áU N_ÓB€½ì­ò¦ áö¨6¾hîz§Bå¦F/Ïg-Ll?ðÓE¯¶su:Sä´_{õ‡ üÙ‡Ÿ» AÓ_ÍÛú‹·ýÌ6H >YýúúéD€uç|ï7H{Rè×w×÷|=óï¡ÿò*µ4@Â÷{Bày 'zÞTyÎ0m¬GzXCdC I‡´o™W>C¦z©gBÕ8*fî¤NÅi®V{öwkÆöC&›Ó<-ø‚œçRo4ƒMÓgº´}»6t›Æl<¸~fOPB¨~(iHi#P[GXÀi†h}G{f˜u¨ƒV˜kõY8…QmNwlÛ×ä'fâņùG…i˜†|x€}Ç…nOp(‚D° #C%¨-Æ8z‹wKXH,%†y¨{d‚DÀ 7 ‚™HDƒåƒBZ†Ô%rx†¶}Q0!öF6¥èˆÂƒŠZtÇ_ÿïÇŠ‚¨Š°È8FØW‡¯xŒH°} Yôe^Yxè€ÓøQåÇT燃ÆH€«8rÎÐŒR§†®¨€ŸæoG…. Ûaø‹èXaÚø~[8ÝxlÔÅÃŽâøuwt‰F +8I¸‰¸(žŠ¢ˆ)Zå. ñ)|;äxodn)´$|“hBH”Šóh_.€râÕ|}§_0xjçp ehÔ4T4©\giŽÅ!)ˆÔÕX\·t'yuL@T7xŒih’(™ŠE]8Ùp„~~gtlf~G%´Ö“ä8ˆÝ—“ …¾–‡ÛXŽòX]"y†N'’â÷•ÿá…“c‰Œ E•Ö•Œ—Cg}ãFV†Ò¸ƒ$ét§&|ÔZœÉež9>qTFy¦FlDšW°]ÜE§Ù†Ît|thÁ9" ùŽéçL«Ù…Ç„uºY`mON)•÷×€Wyl½Ù‡¶†–$y‚X‡ºIkhÉéH€/G‡ÀéjâéT幃ÉlÃñab C >’y„BÓ– o‚ùÅ Ø4ƒû&zÄZœø‰¨g<”˜)Ö4p…HŸÉRÿŒÄ8 ðH¥9~W:ˆ†=8Ð^àœPp¡HÊM†‰O3¡;S¡Z@p²¥a·¡u¨ê•wH*_"JyO@}ƹ£Ö£Dp‡Î œF ]=ç]ؘTt\y^ê¨_ÊL#t-€p‡©I¥4š†­V]zˆX3ÚÎÔÒ¥Ge£……£Îä¥gš¦4š] Z`W*_[ZP#(Ù£xhD ƒs   š™E,p³”1Òˆ`hàÿw|¾˜›‘jYd€ ³‰*3Ÿ‡XÔZ‹š1w˜tg0f€“éÔQ§JØÂ ›^Æ©¨7c’ª£_)YÐ^ÿW°«Ë‰£ep]pz;C«¶š¬Êº¬ÌÚ¬Îú¬Ð­Ò:­ÔZ­Öz­Øš­QLŸÀiŽj@·¥ÜZS ELÖp00® $MË Œ£ßãçìä @X¹JšUX¯äjþŠ þz¨Ž‡Vù5ý…ó®ñÚKåz$„ИÚs6u%¯ë?• áªÞJ[ó:; SO÷­ëˆ{5ƒRaa²Éë°Y`²z U‹7y¹0²•à„l…L¡•¢P{: CE³µ†ªw¨Œ?c³ÆAU’Ç‹Y³9ŠûfVÇJc³#cZë s³kW¶dcC`ÿ_›=w%>yrB4H¬åW.Àl)^ö_Ì…¥°jð„wý•[Ç9žo™TöfWfNg•òÅ›oz{˜%LºõZ «á†qƒy¶…™b«ªM¹`‰YÛõasK–Ф¤ÜåŽBú_\xOœ;CõN´£#yTˆki±ºq8»Yª¸‚û¹Œ6¸>XO‰;§)ºIEºÝÕTmHvÛu¼J\É{‹¥·_ÉLOZ¼Ëˤ{{iôQµ'¦°Ÿ‰FX‹V;3†™ek¹5&¶GPŒv€ˆ>¤9@à&n<3¿ãÖ4R&Dw–8>f‘ÙSnC¿Kæ’­ó:±cÀP¦g¡Uƒg2”ïèžÿUˆ]ivs¿+l~R@jÏùNÒt¤zl\w1j—N•žE€r( g, g,@gLe“©‘ ,¹ÚÑÀËÔ¡¼hÄ–ïjN)œV˜ºÃØ•Hhñõ|Xªt!œŽõÁä©ÁïT`5ÙlnFÅðÔY„¨~#<Å¡›Ã€&…>œ&ü»à'¥}×^VüNÑiª'&ÅYm7¿¤g¿õûcô;>/¼¿\èF—·‚¹3µ:@ó†U‘WPíæVøƒÈýy‘'ÿ†`Ê·k ©É'uÌô}D@Éf ¸ºy—9sôH€Ÿ\küú~鈪4GÁNpq¤U:‡y¦D‘lQ8Ür.xÿ;¼ËO¹tP™¥#×? ¦U‚ÇôgðgsÊL¥^Á¥_“JÊØyÊî‡Ëºìw.WqKq#ç~EÉfGW‡¾<ÎY§ÊGeɹŒÉ°8€çIÎáœÉ÷Çy.œs9ƒ |…\È£‡ŸøE4òܧǺqĵe­Ó7Å{ÆjŠ˜Ø4 í{j?)ÉYœ€ÕÇ]æ O«Ê~±çÍ„¨LI™Œ¨Ù¤È4Òé¨YP|ºI‡O 7BWMƒüœ‹m˱+^Ô)iaI‡ è• Óª žWøÏV {rˆÒ<œ~ÎçÔ„¦Ò,MÒmHdùtTÍ]"ìjA­ÎÇøÕþXÿJ™Õïä}ÖÕÕ¢\€ãÖïÔÑ/1IP‰7Ð Z7M{½Ð½gÓ ú0H-îÛC-œ×'è{‘øˆ{#‰ES„0ˆ„¾4@}Ó‚©„ÚÄCI‡ˆƒÜ•t’ækýÓ®vLúUž¿‹Ã„vÚug–kyž?ÕM„CÈmTd„œ˜AŠWà sÃ;lØYÚ!ý‘ÈhðdÔV<Îw|ô¥r¬ ¸YíXÏ–®ÍÖÖ¡YWÝL,ÜL”ØÝaR˜jÚÃvl¬ö·¤ýN‡èÆE¥ˆyØŸ‰‚‹M=ŠíØuSÙ}nÊm\uSsÏ)ÆeŸÈ%Š^¢}‹jµ¶x¹ÿ¤§‹M…÷8O/wâ…rfwŽæMÜÇŒÃ˜È uŽLÒxYo:œÖ8²H‹CÐà1üàCû£8 âD Ý^»•á8®…JTìë|ÛÉ6h‚ȳYWsXâ7Ž4^¨äl}g™ãÑ=Ô|)£;€`=cYw™ÖuÔh€_w¦W¾½[q¹yÿ½à Iàxà8­àùãx`³h#:-|‡É={þx>ŸŒ¨‘©%“üiL>— …ÎkI橬•O•Q©wv”BàÁÈKkX>ÔeâL…ÂS°’-ù½Ú“bTè[Ð¥“ž—8áüê«.ÌÆI½enS Óÿ`9k>~±e¸—¾ëÓµé~÷“¹æsxYìÆ™…šì% Α~Œ°®ëLn©wçk‹~T>â)[XM혎í÷$Uõ1^”çY?|Žî~þâ4uë| ±D°9¯<›’Y™Bp™¼£Ÿ÷Ο›¹Â°*Ù·4@¯É±Ùȵ)šmá8Æ,i#Æðþ­Èœ…ÛToãgtâ||îØ­Y¶þNðFDíÉá=ÜQ?üÉØ]Þ0õŸ@jÄJkzxñN{É ÄÉ+Î<^êÆÑÍó‹…”¯rÙ)i‡u€Ÿ›ÆEŸÚÈÇÇð òÉRòÞ=dTïúîønï\Ïïu3ðÿŸZHûîÃ) ¡.€ {=lOHt¢¯Èqߨù½¢ä¢:ýŽp RwÊ`À]ºdZX_JÜj7ºuºsÿQ‡ñ¥Fa/½ÉS$ZrßBi÷j¡UàÓ:šø]LÌÆkº±å†kÜK ±L0ó»ÕøaI^Ƚv®݈ϣŸoû²ìÚž~£¯ûÙu½Iùgø÷Fƾv€å ž½øÌE{ЉÜ=‡T4o¯ š3¨m_÷Ó?÷í­›ûLC| *{2˜ª­ƒp¯cmê嫘Pþ¯ÿ%Óªè/á®c73òO2Ä .áX4‘Iå’Ùt>¡Qé”Zµ^±ÿYí–Ûõ~Áañ˜\6ŸÑiõšÝv¿áqùœ^·ßñyýžß÷ÿ !#%')+-/13579;=?ACEGIKMOQS™XX\^Zhçh[¸de¹XÍta›n¿„­~¹ˆñ³”™Áœ‰ˆ¡øz1ˆ(X$ư•È ¬Ñgk妩ÔÕy[Ëà­ƒÙ»Üꉴ­ôáT¢Là¡‚XôIÃ×Ç‘ L áæ8qbÌ!ÉX¤a"ì¹P‚ æ…Ùhd¥¡\¼\‡«ÝB,2eÊ3ƒæ=šùlJáI„@€ŽQ²Ijd©¢¦ažÆùÿrÈ'L’4‰r\Ê$-…=:hê"X0(r XBC}Ú jî·\ê.‰Êdï¼.&ˆÒ·L_„oIœ¦ì‘jCЪ%ÂÎÝÀF } à¥×Î xSpÑ…´,.„  4+«S‚hÀj€BXp]ŽEk¯‡˜f•6Ý¿],@‰œH…ÓJByðÀÅô"ÐB°aˆ»[hQÀB Ù[8(‡´¸OëCwZó[l·+üOìÚ¹Â:ë@):*B8ÔT‚sÌqεèž:"þË/@¦A€–†A;!ðP»õ8´éùšlAÈ*]$ÂXï»%»|²E"6Àà 4@‚™%ˤ‰9»¼Å½1ƒ$¢Ä[Ú¤ÓNZð4B3ÎŽx("Ü<+"7ÑH[8{;8J‡6Û(õíSmd0;b6$묒0Pˆ.ª€Ê\pM-]yÅ„]…€`6Jauد~û•Ø[s}¶WPkتuaX^€V[…xEÜqQÂÄ)ônÊ)óâ\D]\ñn‰¯Jzoé`Èñÿˆy—0™¶!tZ‚¥}Ð+rºý– É%— [Hw.2Ñ]Z2Ø—Ý}‰ ýð}â#Ì yÝŠANbeíðý±å–_¦¥](ÆGd—WFsŠ-~ùf y^yÞ)í%Hçž«\yh£‡°àe=ÊÙϪ¡ÞOÞ˜ímú–v¥fZˆU[E¢„«†x5VK©u8:\¶YežgÛb6Ùe‘89å=xàF‰–£ö€Û8%b¤SÕÁψ2!×háÊ;kÜqÜ*?€Ä] €9+ÊÔ—Õm¡cÂ.€Ä1](³ë|]Ø€vÛÇÛ7À2…¤}ˆÒ]8=?(HДÿÖÖ\aØ„ðtÑŸxáGöùz#×…p ÀŠüvÙ÷Õw izÔ/.¿öÛ·ŸÙç[Voýõü²÷™üØaÓJdÖ7¼*Õ/~üké4æ?}áî€ïËõôǨìu zô‚ý h¯ý}GpÕ~R&ä/|÷Ó`ÿàG‹ÐÞøØÁAŒ}0,‚c ¨BÂ5àpÌÂ⎰¼ÇEÎ3“»ÜÐG<npŠ«€–3 lÎq8@(’iq³iÀ¦èC*²MŒVÄ"+¸(Æi Ád¼B̨Á"(&ØBXˆ =ÆH|´’ àØÝàæSfÌÿ¢ò66ª‘ ôc4`3/IRÐb63;jï}Iâyµ?Î{eš HŒMúl“x| ÿP ÈšÉO•³á~p™Jv¬2—-keé倌 °Â*K(K#Ý1¥tæO,‰É8s˜Åt—à”ÀxbØlš[£ã¼F7ŽÑQéëÙšhÏ]`Œ½X@E$0E!nŽÝ@£™Hfùðž£Ñg͉ 4.”—^l™:TÒ±—¦¤å#ãµ®(ÜS#A\AóyN‘n‘R m¨CwQ4¦¹Ã•DOþ265ëQTŽNð[FãÈ£ŸXT—§Ì%MÿijÌ™Õ̧4³¥Py Ô¹(õìˆé”VÇ”gNtª­ªÏžªQŒ­,ª€aUÏ©$̳ž­éAŠPøÓ5ed?€2@<Ê õ çXís¤ža€tCO‘vçÔ+"ÕˆEv^·t¬/ïcîÍ´ªÈh©ü”‰…„ ˜;,?ÕjØJe¡±B=¢Âv&zs~ø@f'Û‡„• ”Ó©U‹ÚÚ¦Ö±¼]æ&+ÕÝÖv”õíxª[TòҸnj,p‡ |=Áeiú“×N6¹µlk-;Ýê:ê%b% HлZ*¯iAì{‡ð×ÀRq%³§3ÿ^Å—ZT¼'[HJ_„î·W• p:X¾Øy^(`JC‰ærû£ìN1%Í&ްpp¤Us‹=gƒ»àáJ8¶ ü×~8àµÂ°KÊe§âb–”ö±s[°6×>²×3h¢m€\1‘uìÁ¢áÈB&†Š)åñÁ«s¥u{id! ¹É2KòP+Û÷ËË,äHþæls-F(^üK¬ïyÆ«€‹€cDLÅAdN"EJ]DP€‚X00Ì&´Bl›Bð9@[·º‘4¥I¬¹nL À3rÆã^ZogTή¼V½1±ÿ=A N¤]0é}zNÒǨ‡`ê,¤º¦E@Ozˆà£•b Öª>‚`Ì%ÓÛ¢™&‘Œho+ÊŸe ‹†2ˆTb#µªÖ–i —=\YO©z^£¤p‡ÀmC°ÕÔÎ¥²µ*4%Z&€y{ehDw+ Œv4¤?½`„^Ú™FܯIÛAK$”fÐ^wåì×S¢«4BKâ…%GÇ®Æ ìp`YXÓ@Tl"_=srµn}ĤXªé\ˆy. Ø[ÿÆãæôÑ#Är-¼œQ1Hؾ«¤í=³€Úù¾ÀôøÜÙöž™”WæXT—Tó.¡ÿ?ÈþSÏŽí¨Á}Ê^÷RØÇÎsµ+¨¬S;Fàm tµÇD0»v¨.G«Ç2¹e*@â'Â÷mHo(Pq4¦ãþÜ8PþñÆ…Ü5$O°î;‰»¨‚õ­wýëaŸ‡Ð9 «½]F{{Ýïž÷½÷ýüçºæþ÷X°}ñ‘Ÿ|å/(ŽÏ|éOŸúÕ·þõ±Ÿ}íoŸûÝ÷þ÷Á~ñŸüå7ÿùÑŸ~õ¯Ÿýíwÿûáù+¦¸<óD‘[„`xHþ#ê@ô=¤ ¶ª€¨pþPÀ¢³¢Áž UÁ¨)ôOqÏ`!¥ìCkêîb, œ©ÿ¤ÿjEpùþO¸âh‹ à "¬ ú 0ó #&âÂÁœ.pst¥åkøŠ€BìB@2À¢;üO«<ÆÙ { ¤ùÈS„¯)¨"õJð Y0 KÐÝ PÅP Ѱ}j᨞° ™`,$E"ØÊ"xP öéëP½üª+âÙ)ËÀ mõ@⇴B$¸âO­Ðâ­ôÀÑ-o’øLá/Æp 0ñ ”p þ 3± 0&`"'ÂBâÂÄ ‹ õoùÏ ­  ø¬+DâO"´¦—À"q4L‚‰ï±Úÿ±oàì,Ük2È %”QŒ`„N¿Q÷B1(l… gÐñâ{b½ñðï M±‚{Ì›J m«³p êÛPÐIñ¡ ¿Šà] 2ê¬+8mã åiß@К®6#sŠRŒc7”c7840彊Š$ä7(d­4îèôKÓ,ÇTÄ(70r>:B…ÒjtZ2$Ù%ƒã46…"=%9–ƒqf2 ,—öH¥f-FŒ²@lÍäÑJ'´Tî9h’ ‚RkêoÙ°*QE¿ðjV±+AèÜð¯RpÉpÉ+"#"„±¯*9.rt¦E#ñÿ‰#Ê#¥r2F²ŸLÁl´“`öRD¯H…0'äìë!á Ôæ §%[®…2ëfVr \öéÀ&3“²[ £Áö¦n8¥4¹Å[<³$îF)ó¦3k%);5Ó&ZäÆ2±ÅZ¤6Á%Pêù|Âe1 aH nèFnBíxT36!æ7O0ÓÑ+ÑЦâJøÎÐ,­R,cE,U-WP;©à1“àltÑ"Ó)7-ó6Ý*79ã“9C3%Òrh´ö“>WS[žÅXæ7eóÍä*±) txtú*±0Ç€èA7 ÅB9,”B%³Àà‹C×ê/¡ÿ‡°ØÂBC”=9G2!îÏ>ôyèR žB8 x˜yL4åVT"Zt0†Ò;sŠ;MÆd‘<ÍP !ûÑÇvK-³Ó+aÔT phv¨‡:”rÌiB73ÁHCÿRCMÔC½TE·ô5$çF… DûHçïI“À› ˆ6Üj>½ôœ²Ô‡Ll$R>L‘îªÒ)ŒØèO7”ÈÉF'OÉ‘ù±ð¬`z¥®èøT´ ‹ Æ“:IIµ”(½s8—jÙ°µB yÔãÑGÙ”1iωÞ¯â´OS’P54ÀÕr•!ù,Ôr5P‰`WÓT‰âÏ<›€¬ÂôôÄÿiꔈLª–2FsOo5ÁžØŠè¦åY uÎ*Y}èZSâ73,SU©€£<ªÔð ­*Õ®¸5\ óYñ+×ñ¯3 ‹ò ùµ^7•ïQSuë ŒÕÂj Qçt½Þ•Y¯•°D3yK­L\›'‹j[MÊtéêÁµC=´Y5÷¢µyºÔä,6ÁîÔÎ 5tuQ}u4V±hvññ+Ó²T›`³:k>«Zí4guÔ_ÿÕg• 1y¢¨£†“`Ÿ¶HõQI|XdòZæØ®¶²'“  ›ÊÛ¼;‰¤Ó»òbJ•дÆ;GoWÇéöÈÜn‚ÜS_œZU"gƒBb:/%Z-ñÀø¼j .ë¥:èÚ8¾ãKwßÎÓCΫ¤L„G”fì€ <ߨP½Ɔà aç5ôýsúý©¾(>¦> nªÞ¢¼†2àœwÝ-瞺”ì´Êþà7mh7b$¬;TúKíÿyZÎg‡AîV+{º«ª°k ¬ÓÙºh…ÝïÇ<—Q‹>ˆ ¼ –¦ö ˜ö\ìVµcÂÇGêû`ñÃÛÎæTû¸öRÏ¢ë¿~´:ÄÞAÉÞÀ¸hîG«ñ±ÞâíµA'CÆöAåô9压x/Vq‰ˆy€½¯~q}sÕMP¢<æy*ÊhH5çpÿ¾ËÃWYø{ˆ°ÀÅXf_b,Í­‡^¬Œ Ÿ š 6`³£ i²ë˜¸çÊœlÇ ž,Ö2à´Ù›¼&®¡K(‰,V² \ÄKJ¬¸¨Ö!Öµt-–Ûetø5³Ê^frBšÿò9½n¿ãóú=¿ïÿ ö $ѱ $1 X…0=FM¢ …U¡5(±­yf.‚® °`14œ@p±ˆ*Vĺ ª²‚*šv~) €-ˆ ¶'· }(;/)IG#!<[ëíî kÊ–*r³U¾B@2¸TJŠ»O±„9(;$5gCS»hèkcËvçM>4Ц Ã4küBsð‘‰Î’i«V@C„B‡ˆ˜àAÎ.’ˆ°»D R»Q›¬,)6®Ö¨!çáÌ©s'Ïž>â,XsÎ…r\Xb@”¤,–Ö|¹F]Í%TyÍ!GÕS gB( cÍ’4ÿòN)õªëš«»*„ÙÅXF~ ŽÈÀo¯ÂŒ&bÁ§,á²WâÆê¢u¨"0:p5‹S¨¾>•½0—e‚“Üm‘—ÚC„¢Dxøwáç:Bÿd@ÐðÄjkY},pÝ-x㮘AP$²–’Sôhe¦C*u®HªÕËS­ª};÷îÞ¿ƒw‚BøòæÏ£÷S2=ûöîßó9qĈñðïãϯ?ÐG ø €X X Ö’|ø‡ ƒB¡ ¨l!¡…b˜¡†€n¢ˆ#’X¢‰'¢˜¢Š+²Ø¢‹/£Œ3ÒX£7☣Ž;òØ£?ÿ¤CY¤‘G"™¤’K2Ù¤“O²—ÜRƘ•‹ðØW5süsQ}y›`âÔ%™P¢™fŽWzÑ›ÚñfVƒàaùÝy甉´IŠ‚äé!!j§ }h陉**fgÊL—\ Di˜Žþ"bÉg멪¨;½ÆKaë±qªœ‰¨Êªª§òA"²æG+­{šÁ)Ižæ묛Bh ¶›]‰.£šéå–>êh]˜nùO´ÍBÚD©.L€ ¬’EØ®k&Ƕ£¢›n†릻¸îA¥8y¬šD¸po~úê§®½ºùj½Mð‹ï ÙöQp7Ýÿ,¦Ø†‰Ç²Ðb¤,µt L»r<À þ ² «[²ÉI°»à®ó~Újœò¾ o ãGó§óŠsŸ;ïa3]'Œo¿D¸ÆØ>Ä(¤C+©µ¶5 tÅ•uˆÊIh:'ˤÀÚDÑçž6”†0RÀ¹n}³ÎgȦÀ<ð€ qCA `h! 7Dä“€ vóAÔÓA7Ý-óóÎ_ˆÛ‡ãrKtLk##› ðí7³ÁNâ3>Äåsxp/Ø[ú,Å‘NJûì²_‹{Ä·Côôd›-G·ßŽÂDÚ ³ÙºÑb3ïä",¯µ®Vròž ú+ÿGÛsèÑúhл2áÛö  )#ø5Ù¤ïÖRŽ#¹ Ýwo‡^ŠWtÌpÌ:C>_·ñÃ"Çhߺ ‚«ÉÎ!k¥¤å@Ý‘ÉKÉ‚!ž½9”Àc|ÒEÈ 3½;â€Í!’ð°Å,U"ã`äüÔ‡íAûëŒhˆà€ÔuàpÁ”±ÃÖðsÇØ!:7ž±ðOk)×<ÐבÔÑ7Bh1Z#4D4b!Ð. MwS³]´ÊG‘òMP°cZLˆB" ]Sáœ>ØB”y‘„z’ñÀ²+•Ë0Ø× aÃiE„ÀúúrEÜ4òŒÛ@¢õ&'ÿ¿@ø£áË$ù\ HFJБB$µä# ã*[YF3å.jcÂâµ`™Fª¡vðÀ|$GG’ˆKrB¥÷hLYðÔS[[&°7½‰~Ük"‡p?ªý7µ;¢S(?inïP¼Gâ:â‚kž1›Úô]EXF3.4¦T Ñ(KÞ‘.‚Ôbã’Y‡ ¯ƒncæï ˆÀc"TGÀÙÚ¦×5ä4trϬÜÏFéô #ê,]éÐGˆ÷5ÓeóÀÀ1hh8RjN£V̧5<úå½Një|–°ôIF+:Ði¬Ä©)‰s¯€Âñ8ãÊY Ú˜&4©?JÙ%=¸²ÈÿÕ ÙÛIÒ¬ÈTñ‘PÛjh0`ΠІ›s é%De´OWÍêV/ZÒ!œu]ýjXëð5;ðS•¬¼eO)¶R‰ žzåk_µe5”õ’¨äÂ’ñ.yW¥BÖGëàP.c%z1´¬Ã"4òMQ¶U€yíæ—HÑy$®uõl:µ‘I}ä—s Ùîø0±zº²•·mà¥ngSܺæ#C P¡ZÙâɶ‘]îŽ^“6TQÖ™Uì<ª‘ÐŒ´U `Z¯ÁLg†Ä [à]!ŠæšmíÞPÃ]Ö€p–ˆ¢%^øNŠd«°zp÷ú»\ Õ—„äÕeQÆÜ )ÿUò¤Q)Ò€·D¿lhÑf#¤½3·±³ç-c)ÛcÁ¶–!ŽOb=*ì=Á*NðŠ I¹`¶xC "hŒklãã˜CÞË1{ìã9ÈB2‘‹lä##9ÉJ^2“›ìä'C9ÊRž2•«lå+c9ËZf‘4 âexaݘïµ-£9ÍLrî2ËóÆõÉž³Íþàj]Žây¾œÍ_œñ‡‡m ;pòΛÕlèC»Y¸•¤v”Û’2Òc<{H™ö68’–´&›„Ž}lÑƉ£mêSk‡©>®w+‡fÖS»êàôË[1W“-ˆõ®ƒK€ƒÎ¯X%ÿa´v\êc#{ &Û¸P™WœÂ)8ËÂm°à?.‹s$m9 µ ÑÛ¸§¦¾òŠétŠKk¥@§ŒdÀ‰[éêÖr—Û\?¥C ý–goEÚÔÞ6 ®ým‚wûàIw²îð<øÓ…ÖÆ+`í!4À9´‹ êÓZ|# g™D…PfÐK“””$͈hSb¤¹<#œ†8ôÞ˜ÁP‹ú¨øÅ]qXpÜã°y´A©‘`š§±(xÃ0xÂ-¬C.4¶\VôŸM\ÆÒúPÍÊIk‰éÉÓž‚§³ Ø‚ÃìáBIx!´¹IºJ᪛…\”EtW€Z(ÇÐÁrhK°è“˜øpÈúÐFh8ùŒÇ€¢\ EW¬Ç0"Q¸`¡b+ºâÔÇó‰|a{Äâ+âb.Bƒ ÉŒµ/êb0 £€H ízã0*ã22c3:ã3Bc4Jã4Rc5Zã5bc6jãÿ6rc7zã7‚#‹œ™†c9šc‹š· žƒ¬+žã;j#ªŽ…"‚¬‡Âc>Z£ bM1±š€Š êã@J£üy:Nd €‚c(¤d$A8…œÅb¬ "ÄEí9›RèáP@F†‹ì¹€äI.£÷}=nÛ$\9@Á9¤CµY‚ H@8 XL¨C} @ì¤åéÏ}á€:lœ é›û¡äRæbêM ° !/PsØ$PF%vÌĪ1 JÝS0FàÛdS’¥+:åQ%ÒŸ•4‚ZbåZhå¶™E†eì^Yâåªd€_ÎUá 1\¾åHVù]SôåebF¡AÕª­åº€[æ`^†dNæ?–ä*æfJ!?A-ÎUJ%' ·ETvf%e^%e¦@rfl¾Š„úe›:P®$Èä¨CJ¸&dA*¬W¸&VÐ!à¤uPÁfôáÊftÂ_qTà@ÀFz!J-ºg|ʧNøâ|Úç}öA‡àç~ògúçh€ è€hè"h‚*è‚2hƒ:èƒBh„Jè„Rh…Zè…bh†jè†rh‡z臂hˆŠèˆ’h‰šè‰¢è†;presage-0.8.8/src/lib/tinyxml/tinystr.cpp0000644000175000017500000000471311743227551015373 00000000000000/* www.sourceforge.net/projects/tinyxml This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TIXML_USE_STL #include "tinystr.h" // Error value for find primitive const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); // Null rep. TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; void TiXmlString::reserve (size_type cap) { if (cap > capacity()) { TiXmlString tmp; tmp.init(length(), cap); memcpy(tmp.start(), data(), length()); swap(tmp); } } TiXmlString& TiXmlString::assign(const char* str, size_type len) { size_type cap = capacity(); if (len > cap || cap > 3*(len + 8)) { TiXmlString tmp; tmp.init(len); memcpy(tmp.start(), str, len); swap(tmp); } else { memmove(start(), str, len); set_size(len); } return *this; } TiXmlString& TiXmlString::append(const char* str, size_type len) { size_type newsize = length() + len; if (newsize > capacity()) { reserve (newsize + capacity()); } memmove(finish(), str, len); set_size(newsize); return *this; } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) { TiXmlString tmp; tmp.reserve(a.length() + b.length()); tmp += a; tmp += b; return tmp; } TiXmlString operator + (const TiXmlString & a, const char* b) { TiXmlString tmp; TiXmlString::size_type b_len = static_cast( strlen(b) ); tmp.reserve(a.length() + b_len); tmp += a; tmp.append(b, b_len); return tmp; } TiXmlString operator + (const char* a, const TiXmlString & b) { TiXmlString tmp; TiXmlString::size_type a_len = static_cast( strlen(a) ); tmp.reserve(a_len + b.length()); tmp.append(a, a_len); tmp += b; return tmp; } #endif // TIXML_USE_STL presage-0.8.8/src/lib/tinyxml/Makefile.am0000644000175000017500000000312411737142176015204 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in EXTRA_DIST = changes.txt \ readme.txt \ utf8test.gif \ utf8test.xml \ utf8testverify.xml TESTS = xmltest check_PROGRAMS = xmltest xmltest_SOURCES = xmltest.cpp xmltest_LDADD = libtinyxml.la #xmltest_CXXFLAGS = -DTIXML_USE_STL noinst_LTLIBRARIES = libtinyxml.la libtinyxml_la_SOURCES = tinyxml.cpp tinyxml.h \ tinyxmlparser.cpp \ tinyxmlerror.cpp \ tinystr.cpp tinystr.h #libtinyxml_la_CXXFLAGS = -DTIXML_USE_STL # Clean out files created during tests. # Required to make distcheck happy. DISTCLEANFILES = utf8testout.xml \ demotest.xml \ textfile.txt \ test5.xml \ test6.xml \ test7.xml presage-0.8.8/src/lib/tinyxml/utf8testverify.xml0000644000175000017500000000126411737142176016710 00000000000000 The world has many languages Мир имеет много Ñзыков el mundo tiene muchos idiomas 世界有很多语言 <РуÑÑкий название="name" ценноÑть="value"><имеет> <汉语 åå­—="name" 价值="value">世界有很多语言 "Mëtæl!" <ä>Umlaut Element presage-0.8.8/src/lib/tinyxml/tinystr.h0000644000175000017500000002000611743227551015031 00000000000000/* www.sourceforge.net/projects/tinyxml This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TIXML_USE_STL #ifndef TIXML_STRING_INCLUDED #define TIXML_STRING_INCLUDED #include #include /* The support for explicit isn't that universal, and it isn't really required - it is used to check that the TiXmlString class isn't incorrectly used. Be nice to old compilers and macro it here: */ #if defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. #define TIXML_EXPLICIT explicit #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s #define TIXML_EXPLICIT explicit #else #define TIXML_EXPLICIT #endif /* TiXmlString is an emulation of a subset of the std::string template. Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. Only the member functions relevant to the TinyXML project have been implemented. The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase a string and there's no more room, we allocate a buffer twice as big as we need. */ class TiXmlString { public : // The size type used typedef size_t size_type; // Error value for find primitive static const size_type npos; // = -1; // TiXmlString empty constructor TiXmlString () : rep_(&nullrep_) { } // TiXmlString copy constructor TiXmlString ( const TiXmlString & copy) : rep_(0) { init(copy.length()); memcpy(start(), copy.data(), length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) { init( static_cast( strlen(copy) )); memcpy(start(), copy, length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) { init(len); memcpy(start(), str, len); } // TiXmlString destructor ~TiXmlString () { quit(); } TiXmlString& operator = (const char * copy) { return assign( copy, (size_type)strlen(copy)); } TiXmlString& operator = (const TiXmlString & copy) { return assign(copy.start(), copy.length()); } // += operator. Maps to append TiXmlString& operator += (const char * suffix) { return append(suffix, static_cast( strlen(suffix) )); } // += operator. Maps to append TiXmlString& operator += (char single) { return append(&single, 1); } // += operator. Maps to append TiXmlString& operator += (const TiXmlString & suffix) { return append(suffix.data(), suffix.length()); } // Convert a TiXmlString into a null-terminated char * const char * c_str () const { return rep_->str; } // Convert a TiXmlString into a char * (need not be null terminated). const char * data () const { return rep_->str; } // Return the length of a TiXmlString size_type length () const { return rep_->size; } // Alias for length() size_type size () const { return rep_->size; } // Checks if a TiXmlString is empty bool empty () const { return rep_->size == 0; } // Return capacity of string size_type capacity () const { return rep_->capacity; } // single char extraction const char& at (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // [] operator char& operator [] (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // find a char in a string. Return TiXmlString::npos if not found size_type find (char lookup) const { return find(lookup, 0); } // find a char in a string from an offset. Return TiXmlString::npos if not found size_type find (char tofind, size_type offset) const { if (offset >= length()) return npos; for (const char* p = c_str() + offset; *p != '\0'; ++p) { if (*p == tofind) return static_cast< size_type >( p - c_str() ); } return npos; } void clear () { //Lee: //The original was just too strange, though correct: // TiXmlString().swap(*this); //Instead use the quit & re-init: quit(); init(0,0); } /* Function to reserve a big amount of data when we know we'll need it. Be aware that this function DOES NOT clear the content of the TiXmlString if any exists. */ void reserve (size_type cap); TiXmlString& assign (const char* str, size_type len); TiXmlString& append (const char* str, size_type len); void swap (TiXmlString& other) { Rep* r = rep_; rep_ = other.rep_; other.rep_ = r; } private: void init(size_type sz) { init(sz, sz); } void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } char* start() const { return rep_->str; } char* finish() const { return rep_->str + rep_->size; } struct Rep { size_type size, capacity; char str[1]; }; void init(size_type sz, size_type cap) { if (cap) { // Lee: the original form: // rep_ = static_cast(operator new(sizeof(Rep) + cap)); // doesn't work in some cases of new being overloaded. Switching // to the normal allocation, although use an 'int' for systems // that are overly picky about structure alignment. const size_type bytesNeeded = sizeof(Rep) + cap; const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); rep_ = reinterpret_cast( new int[ intsNeeded ] ); rep_->str[ rep_->size = sz ] = '\0'; rep_->capacity = cap; } else { rep_ = &nullrep_; } } void quit() { if (rep_ != &nullrep_) { // The rep_ is really an array of ints. (see the allocator, above). // Cast it back before delete, so the compiler won't incorrectly call destructors. delete [] ( reinterpret_cast( rep_ ) ); } } Rep * rep_; static Rep nullrep_; } ; inline bool operator == (const TiXmlString & a, const TiXmlString & b) { return ( a.length() == b.length() ) // optimization on some platforms && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare } inline bool operator < (const TiXmlString & a, const TiXmlString & b) { return strcmp(a.c_str(), b.c_str()) < 0; } inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); TiXmlString operator + (const TiXmlString & a, const char* b); TiXmlString operator + (const char* a, const TiXmlString & b); /* TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. Only the operators that we need for TinyXML have been developped. */ class TiXmlOutStream : public TiXmlString { public : // TiXmlOutStream << operator. TiXmlOutStream & operator << (const TiXmlString & in) { *this += in; return *this; } // TiXmlOutStream << operator. TiXmlOutStream & operator << (const char * in) { *this += in; return *this; } } ; #endif // TIXML_STRING_INCLUDED #endif // TIXML_USE_STL presage-0.8.8/src/lib/tinyxml/Makefile.in0000644000175000017500000005102711763440355015221 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ TESTS = xmltest$(EXEEXT) check_PROGRAMS = xmltest$(EXEEXT) subdir = src/lib/tinyxml DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtinyxml_la_LIBADD = am_libtinyxml_la_OBJECTS = tinyxml.lo tinyxmlparser.lo tinyxmlerror.lo \ tinystr.lo libtinyxml_la_OBJECTS = $(am_libtinyxml_la_OBJECTS) am_xmltest_OBJECTS = xmltest.$(OBJEXT) xmltest_OBJECTS = $(am_xmltest_OBJECTS) xmltest_DEPENDENCIES = libtinyxml.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libtinyxml_la_SOURCES) $(xmltest_SOURCES) DIST_SOURCES = $(libtinyxml_la_SOURCES) $(xmltest_SOURCES) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = changes.txt \ readme.txt \ utf8test.gif \ utf8test.xml \ utf8testverify.xml xmltest_SOURCES = xmltest.cpp xmltest_LDADD = libtinyxml.la #xmltest_CXXFLAGS = -DTIXML_USE_STL noinst_LTLIBRARIES = libtinyxml.la libtinyxml_la_SOURCES = tinyxml.cpp tinyxml.h \ tinyxmlparser.cpp \ tinyxmlerror.cpp \ tinystr.cpp tinystr.h #libtinyxml_la_CXXFLAGS = -DTIXML_USE_STL # Clean out files created during tests. # Required to make distcheck happy. DISTCLEANFILES = utf8testout.xml \ demotest.xml \ textfile.txt \ test5.xml \ test6.xml \ test7.xml all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/tinyxml/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lib/tinyxml/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libtinyxml.la: $(libtinyxml_la_OBJECTS) $(libtinyxml_la_DEPENDENCIES) $(CXXLINK) $(libtinyxml_la_OBJECTS) $(libtinyxml_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list xmltest$(EXEEXT): $(xmltest_OBJECTS) $(xmltest_DEPENDENCIES) @rm -f xmltest$(EXEEXT) $(CXXLINK) $(xmltest_OBJECTS) $(xmltest_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tinystr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tinyxml.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tinyxmlerror.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tinyxmlparser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmltest.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstLTLIBRARIES ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am # 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: presage-0.8.8/src/lib/tinyxml/tinyxmlerror.cpp0000644000175000017500000000337711743227551016442 00000000000000/* www.sourceforge.net/projects/tinyxml Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "tinyxml.h" // The goal of the seperate error file is to make the first // step towards localization. tinyxml (currently) only supports // english error messages, but the could now be translated. // // It also cleans up the code a bit. // const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = { "No error", "Error", "Failed to open file", "Error parsing Element.", "Failed to read Element name", "Error reading Element value.", "Error reading Attributes.", "Error: empty tag.", "Error reading end tag.", "Error parsing Unknown.", "Error parsing Comment.", "Error parsing Declaration.", "Error document empty.", "Error null (0) or unexpected EOF found in input stream.", "Error parsing CDATA.", "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", }; presage-0.8.8/src/lib/tinyxml/tinyxml.cpp0000644000175000017500000011132711743227551015363 00000000000000/* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #ifdef TIXML_USE_STL #include #include #endif #include "tinyxml.h" FILE* TiXmlFOpen( const char* filename, const char* mode ); bool TiXmlBase::condenseWhiteSpace = true; // Microsoft compiler security FILE* TiXmlFOpen( const char* filename, const char* mode ) { #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) FILE* fp = 0; errno_t err = fopen_s( &fp, filename, mode ); if ( !err && fp ) return fp; return 0; #else return fopen( filename, mode ); #endif } void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) { int i=0; while( i<(int)str.length() ) { unsigned char c = (unsigned char) str[i]; if ( c == '&' && i < ( (int)str.length() - 2 ) && str[i+1] == '#' && str[i+2] == 'x' ) { // Hexadecimal character reference. // Pass through unchanged. // © -- copyright symbol, for example. // // The -1 is a bug fix from Rob Laveaux. It keeps // an overflow from happening if there is no ';'. // There are actually 2 ways to exit this loop - // while fails (error case) and break (semicolon found). // However, there is no mechanism (currently) for // this function to return an error. while ( i<(int)str.length()-1 ) { outString->append( str.c_str() + i, 1 ); ++i; if ( str[i] == ';' ) break; } } else if ( c == '&' ) { outString->append( entity[0].str, entity[0].strLength ); ++i; } else if ( c == '<' ) { outString->append( entity[1].str, entity[1].strLength ); ++i; } else if ( c == '>' ) { outString->append( entity[2].str, entity[2].strLength ); ++i; } else if ( c == '\"' ) { outString->append( entity[3].str, entity[3].strLength ); ++i; } else if ( c == '\'' ) { outString->append( entity[4].str, entity[4].strLength ); ++i; } else if ( c < 32 ) { // Easy pass at non-alpha/numeric/symbol // Below 32 is symbolic. char buf[ 32 ]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); #else sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); #endif //*ME: warning C4267: convert 'size_t' to 'int' //*ME: Int-Cast to make compiler happy ... outString->append( buf, (int)strlen( buf ) ); ++i; } else { //char realc = (char) c; //outString->append( &realc, 1 ); *outString += (char) c; // somewhat more efficient function call. ++i; } } } TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() { parent = 0; type = _type; firstChild = 0; lastChild = 0; prev = 0; next = 0; } TiXmlNode::~TiXmlNode() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } } void TiXmlNode::CopyTo( TiXmlNode* target ) const { target->SetValue (value.c_str() ); target->userData = userData; target->location = location; } void TiXmlNode::Clear() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } firstChild = 0; lastChild = 0; } TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) { assert( node->parent == 0 || node->parent == this ); assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) { delete node; if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } node->parent = this; node->prev = lastChild; node->next = 0; if ( lastChild ) lastChild->next = node; else firstChild = node; // it was an empty list. lastChild = node; return node; } TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) { if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; return LinkEndChild( node ); } TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) { if ( !beforeThis || beforeThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->next = beforeThis; node->prev = beforeThis->prev; if ( beforeThis->prev ) { beforeThis->prev->next = node; } else { assert( firstChild == beforeThis ); firstChild = node; } beforeThis->prev = node; return node; } TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) { if ( !afterThis || afterThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->prev = afterThis; node->next = afterThis->next; if ( afterThis->next ) { afterThis->next->prev = node; } else { assert( lastChild == afterThis ); lastChild = node; } afterThis->next = node; return node; } TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) { if ( !replaceThis ) return 0; if ( replaceThis->parent != this ) return 0; if ( withThis.ToDocument() ) { // A document can never be a child. Thanks to Noam. TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = withThis.Clone(); if ( !node ) return 0; node->next = replaceThis->next; node->prev = replaceThis->prev; if ( replaceThis->next ) replaceThis->next->prev = node; else lastChild = node; if ( replaceThis->prev ) replaceThis->prev->next = node; else firstChild = node; delete replaceThis; node->parent = this; return node; } bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) { if ( !removeThis ) { return false; } if ( removeThis->parent != this ) { assert( 0 ); return false; } if ( removeThis->next ) removeThis->next->prev = removeThis->prev; else lastChild = removeThis->prev; if ( removeThis->prev ) removeThis->prev->next = removeThis->next; else firstChild = removeThis->next; delete removeThis; return true; } const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const { const TiXmlNode* node; for ( node = firstChild; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const { const TiXmlNode* node; for ( node = lastChild; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild(); } else { assert( previous->parent == this ); return previous->NextSibling(); } } const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild( val ); } else { assert( previous->parent == this ); return previous->NextSibling( val ); } } const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const { const TiXmlNode* node; for ( node = next; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const { const TiXmlNode* node; for ( node = prev; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } void TiXmlElement::RemoveAttribute( const char * name ) { #ifdef TIXML_USE_STL TIXML_STRING str( name ); TiXmlAttribute* node = attributeSet.Find( str ); #else TiXmlAttribute* node = attributeSet.Find( name ); #endif if ( node ) { attributeSet.Remove( node ); delete node; } } const TiXmlElement* TiXmlNode::FirstChildElement() const { const TiXmlNode* node; for ( node = FirstChild(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const { const TiXmlNode* node; for ( node = FirstChild( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement() const { const TiXmlNode* node; for ( node = NextSibling(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const { const TiXmlNode* node; for ( node = NextSibling( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlDocument* TiXmlNode::GetDocument() const { const TiXmlNode* node; for( node = this; node; node = node->parent ) { if ( node->ToDocument() ) return node->ToDocument(); } return 0; } TiXmlElement::TiXmlElement (const char * _value) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; } #ifdef TIXML_USE_STL TiXmlElement::TiXmlElement( const std::string& _value ) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; } #endif TiXmlElement::TiXmlElement( const TiXmlElement& copy) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; copy.CopyTo( this ); } TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) { ClearThis(); base.CopyTo( this ); return *this; } TiXmlElement::~TiXmlElement() { ClearThis(); } void TiXmlElement::ClearThis() { Clear(); while( attributeSet.First() ) { TiXmlAttribute* node = attributeSet.First(); attributeSet.Remove( node ); delete node; } } const char* TiXmlElement::Attribute( const char* name ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( node ) return node->Value(); return 0; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( attrib ) return &attrib->ValueStr(); return 0; } #endif const char* TiXmlElement::Attribute( const char* name, int* i ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const char* result = 0; if ( attrib ) { result = attrib->Value(); if ( i ) { attrib->QueryIntValue( i ); } } return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const std::string* result = 0; if ( attrib ) { result = &attrib->ValueStr(); if ( i ) { attrib->QueryIntValue( i ); } } return result; } #endif const char* TiXmlElement::Attribute( const char* name, double* d ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const char* result = 0; if ( attrib ) { result = attrib->Value(); if ( d ) { attrib->QueryDoubleValue( d ); } } return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const std::string* result = 0; if ( attrib ) { result = &attrib->ValueStr(); if ( d ) { attrib->QueryDoubleValue( d ); } } return result; } #endif int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryIntValue( ival ); } int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; int ival = 0; int result = node->QueryIntValue( &ival ); *value = (unsigned)ival; return result; } int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; int result = TIXML_WRONG_TYPE; if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) { *bval = true; result = TIXML_SUCCESS; } else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) { *bval = false; result = TIXML_SUCCESS; } return result; } #ifdef TIXML_USE_STL int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryIntValue( ival ); } #endif int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryDoubleValue( dval ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryDoubleValue( dval ); } #endif void TiXmlElement::SetAttribute( const char * name, int val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetIntValue( val ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, int val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetIntValue( val ); } } #endif void TiXmlElement::SetDoubleAttribute( const char * name, double val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetDoubleValue( val ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetDoubleValue( val ); } } #endif void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); if ( attrib ) { attrib->SetValue( cvalue ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); if ( attrib ) { attrib->SetValue( _value ); } } #endif void TiXmlElement::Print( FILE* cfile, int depth ) const { int i; assert( cfile ); for ( i=0; iNext() ) { fprintf( cfile, " " ); attrib->Print( cfile, depth ); } // There are 3 different formatting approaches: // 1) An element without children is printed as a node // 2) An element with only a text child is printed as text // 3) An element with children is printed on multiple lines. TiXmlNode* node; if ( !firstChild ) { fprintf( cfile, " />" ); } else if ( firstChild == lastChild && firstChild->ToText() ) { fprintf( cfile, ">" ); firstChild->Print( cfile, depth + 1 ); fprintf( cfile, "", value.c_str() ); } else { fprintf( cfile, ">" ); for ( node = firstChild; node; node=node->NextSibling() ) { if ( !node->ToText() ) { fprintf( cfile, "\n" ); } node->Print( cfile, depth+1 ); } fprintf( cfile, "\n" ); for( i=0; i", value.c_str() ); } } void TiXmlElement::CopyTo( TiXmlElement* target ) const { // superclass: TiXmlNode::CopyTo( target ); // Element class: // Clone the attributes, then clone the children. const TiXmlAttribute* attribute = 0; for( attribute = attributeSet.First(); attribute; attribute = attribute->Next() ) { target->SetAttribute( attribute->Name(), attribute->Value() ); } TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } } bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this, attributeSet.First() ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } TiXmlNode* TiXmlElement::Clone() const { TiXmlElement* clone = new TiXmlElement( Value() ); if ( !clone ) return 0; CopyTo( clone ); return clone; } const char* TiXmlElement::GetText() const { const TiXmlNode* child = this->FirstChild(); if ( child ) { const TiXmlText* childText = child->ToText(); if ( childText ) { return childText->Value(); } } return 0; } TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; ClearError(); } TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #ifdef TIXML_USE_STL TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #endif TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { copy.CopyTo( this ); } TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) { Clear(); copy.CopyTo( this ); return *this; } bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) { return LoadFile( Value(), encoding ); } bool TiXmlDocument::SaveFile() const { return SaveFile( Value() ); } bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) { TIXML_STRING filename( _filename ); value = filename; // reading in binary mode so that tinyxml can normalize the EOL FILE* file = TiXmlFOpen( value.c_str (), "rb" ); if ( file ) { bool result = LoadFile( file, encoding ); fclose( file ); return result; } else { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } } bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) { if ( !file ) { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Delete the existing data: Clear(); location.Clear(); // Get the file size, so we can pre-allocate the string. HUGE speed impact. long length = 0; fseek( file, 0, SEEK_END ); length = ftell( file ); fseek( file, 0, SEEK_SET ); // Strange case, but good to handle up front. if ( length <= 0 ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Subtle bug here. TinyXml did use fgets. But from the XML spec: // 2.11 End-of-Line Handling // // // ...the XML processor MUST behave as if it normalized all line breaks in external // parsed entities (including the document entity) on input, before parsing, by translating // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to // a single #xA character. // // // It is not clear fgets does that, and certainly isn't clear it works cross platform. // Generally, you expect fgets to translate from the convention of the OS to the c/unix // convention, and not work generally. /* while( fgets( buf, sizeof(buf), file ) ) { data += buf; } */ char* buf = new char[ length+1 ]; buf[0] = 0; if ( fread( buf, length, 1, file ) != 1 ) { delete [] buf; SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Process the buffer in place to normalize new lines. (See comment above.) // Copies from the 'p' to 'q' pointer, where p can advance faster if // a newline-carriage return is hit. // // Wikipedia: // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 const char* p = buf; // the read head char* q = buf; // the write head const char CR = 0x0d; const char LF = 0x0a; buf[length] = 0; while( *p ) { assert( p < (buf+length) ); assert( q <= (buf+length) ); assert( q <= p ); if ( *p == CR ) { *q++ = LF; p++; if ( *p == LF ) { // check for CR+LF (and skip LF) p++; } } else { *q++ = *p++; } } assert( q <= (buf+length) ); *q = 0; Parse( buf, 0, encoding ); delete [] buf; return !Error(); } bool TiXmlDocument::SaveFile( const char * filename ) const { // The old c stuff lives on... FILE* fp = TiXmlFOpen( filename, "w" ); if ( fp ) { bool result = SaveFile( fp ); fclose( fp ); return result; } return false; } bool TiXmlDocument::SaveFile( FILE* fp ) const { if ( useMicrosoftBOM ) { const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; fputc( TIXML_UTF_LEAD_0, fp ); fputc( TIXML_UTF_LEAD_1, fp ); fputc( TIXML_UTF_LEAD_2, fp ); } Print( fp, 0 ); return (ferror(fp) == 0); } void TiXmlDocument::CopyTo( TiXmlDocument* target ) const { TiXmlNode::CopyTo( target ); target->error = error; target->errorId = errorId; target->errorDesc = errorDesc; target->tabsize = tabsize; target->errorLocation = errorLocation; target->useMicrosoftBOM = useMicrosoftBOM; TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } } TiXmlNode* TiXmlDocument::Clone() const { TiXmlDocument* clone = new TiXmlDocument(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlDocument::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { node->Print( cfile, depth ); fprintf( cfile, "\n" ); } } bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } const TiXmlAttribute* TiXmlAttribute::Next() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } /* TiXmlAttribute* TiXmlAttribute::Next() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } */ const TiXmlAttribute* TiXmlAttribute::Previous() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } /* TiXmlAttribute* TiXmlAttribute::Previous() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } */ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { TIXML_STRING n, v; EncodeString( name, &n ); EncodeString( value, &v ); if (value.find ('\"') == TIXML_STRING::npos) { if ( cfile ) { fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; } } else { if ( cfile ) { fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; } } } int TiXmlAttribute::QueryIntValue( int* ival ) const { if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } int TiXmlAttribute::QueryDoubleValue( double* dval ) const { if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } void TiXmlAttribute::SetIntValue( int _value ) { char buf [64]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); #else sprintf (buf, "%d", _value); #endif SetValue (buf); } void TiXmlAttribute::SetDoubleValue( double _value ) { char buf [256]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); #else sprintf (buf, "%g", _value); #endif SetValue (buf); } int TiXmlAttribute::IntValue() const { return atoi (value.c_str ()); } double TiXmlAttribute::DoubleValue() const { return atof (value.c_str ()); } TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { copy.CopyTo( this ); } TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) { Clear(); base.CopyTo( this ); return *this; } void TiXmlComment::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( int i=0; i", value.c_str() ); } void TiXmlComment::CopyTo( TiXmlComment* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlComment::Clone() const { TiXmlComment* clone = new TiXmlComment(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlText::Print( FILE* cfile, int depth ) const { assert( cfile ); if ( cdata ) { int i; fprintf( cfile, "\n" ); for ( i=0; i\n", value.c_str() ); // unformatted output } else { TIXML_STRING buffer; EncodeString( value, &buffer ); fprintf( cfile, "%s", buffer.c_str() ); } } void TiXmlText::CopyTo( TiXmlText* target ) const { TiXmlNode::CopyTo( target ); target->cdata = cdata; } bool TiXmlText::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlText::Clone() const { TiXmlText* clone = 0; clone = new TiXmlText( "" ); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlDeclaration::TiXmlDeclaration( const char * _version, const char * _encoding, const char * _standalone ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #ifdef TIXML_USE_STL TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #endif TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { copy.CopyTo( this ); } TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) { Clear(); copy.CopyTo( this ); return *this; } void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { if ( cfile ) fprintf( cfile, "" ); if ( str ) (*str) += "?>"; } void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const { TiXmlNode::CopyTo( target ); target->version = version; target->encoding = encoding; target->standalone = standalone; } bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlDeclaration::Clone() const { TiXmlDeclaration* clone = new TiXmlDeclaration(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlUnknown::Print( FILE* cfile, int depth ) const { for ( int i=0; i", value.c_str() ); } void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlUnknown::Clone() const { TiXmlUnknown* clone = new TiXmlUnknown(); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlAttributeSet::TiXmlAttributeSet() { sentinel.next = &sentinel; sentinel.prev = &sentinel; } TiXmlAttributeSet::~TiXmlAttributeSet() { assert( sentinel.next == &sentinel ); assert( sentinel.prev == &sentinel ); } void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) { #ifdef TIXML_USE_STL assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. #else assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. #endif addMe->next = &sentinel; addMe->prev = sentinel.prev; sentinel.prev->next = addMe; sentinel.prev = addMe; } void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) { TiXmlAttribute* node; for( node = sentinel.next; node != &sentinel; node = node->next ) { if ( node == removeMe ) { node->prev->next = node->next; node->next->prev = node->prev; node->next = 0; node->prev = 0; return; } } assert( 0 ); // we tried to remove a non-linked attribute. } #ifdef TIXML_USE_STL TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( node->name == name ) return node; } return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) { TiXmlAttribute* attrib = Find( _name ); if ( !attrib ) { attrib = new TiXmlAttribute(); Add( attrib ); attrib->SetName( _name ); } return attrib; } #endif TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( strcmp( node->name.c_str(), name ) == 0 ) return node; } return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) { TiXmlAttribute* attrib = Find( _name ); if ( !attrib ) { attrib = new TiXmlAttribute(); Add( attrib ); attrib->SetName( _name ); } return attrib; } #ifdef TIXML_USE_STL std::istream& operator>> (std::istream & in, TiXmlNode & base) { TIXML_STRING tag; tag.reserve( 8 * 1000 ); base.StreamIn( &in, &tag ); base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); return in; } #endif #ifdef TIXML_USE_STL std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out << printer.Str(); return out; } std::string& operator<< (std::string& out, const TiXmlNode& base ) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out.append( printer.Str() ); return out; } #endif TiXmlHandle TiXmlHandle::FirstChild() const { if ( node ) { TiXmlNode* child = node->FirstChild(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const { if ( node ) { TiXmlNode* child = node->FirstChild( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement() const { if ( node ) { TiXmlElement* child = node->FirstChildElement(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const { if ( node ) { TiXmlElement* child = node->FirstChildElement( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild(); for ( i=0; child && iNextSibling(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild( value ); for ( i=0; child && iNextSibling( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement(); for ( i=0; child && iNextSiblingElement(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement( value ); for ( i=0; child && iNextSiblingElement( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { DoIndent(); buffer += "<"; buffer += element.Value(); for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) { buffer += " "; attrib->Print( 0, 0, &buffer ); } if ( !element.FirstChild() ) { buffer += " />"; DoLineBreak(); } else { buffer += ">"; if ( element.FirstChild()->ToText() && element.LastChild() == element.FirstChild() && element.FirstChild()->ToText()->CDATA() == false ) { simpleTextPrint = true; // no DoLineBreak()! } else { DoLineBreak(); } } ++depth; return true; } bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) { --depth; if ( !element.FirstChild() ) { // nothing. } else { if ( simpleTextPrint ) { simpleTextPrint = false; } else { DoIndent(); } buffer += ""; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlText& text ) { if ( text.CDATA() ) { DoIndent(); buffer += ""; DoLineBreak(); } else if ( simpleTextPrint ) { TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; } else { DoIndent(); TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) { DoIndent(); declaration.Print( 0, 0, &buffer ); DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlComment& comment ) { DoIndent(); buffer += ""; DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) { DoIndent(); buffer += "<"; buffer += unknown.Value(); buffer += ">"; DoLineBreak(); return true; } presage-0.8.8/src/lib/tinyxml/readme.txt0000644000175000017500000004656711737142176015170 00000000000000/** @mainpage

TinyXML

TinyXML is a simple, small, C++ XML parser that can be easily integrated into other programs.

What it does.

In brief, TinyXML parses an XML document, and builds from that a Document Object Model (DOM) that can be read, modified, and saved. XML stands for "eXtensible Markup Language." It allows you to create your own document markups. Where HTML does a very good job of marking documents for browsers, XML allows you to define any kind of document markup, for example a document that describes a "to do" list for an organizer application. XML is a very structured and convenient format. All those random file formats created to store application data can all be replaced with XML. One parser for everything. The best place for the complete, correct, and quite frankly hard to read spec is at http://www.w3.org/TR/2004/REC-xml-20040204/. An intro to XML (that I really like) can be found at http://skew.org/xml/tutorial. There are different ways to access and interact with XML data. TinyXML uses a Document Object Model (DOM), meaning the XML data is parsed into a C++ objects that can be browsed and manipulated, and then written to disk or another output stream. You can also construct an XML document from scratch with C++ objects and write this to disk or another output stream. TinyXML is designed to be easy and fast to learn. It is two headers and four cpp files. Simply add these to your project and off you go. There is an example file - xmltest.cpp - to get you started. TinyXML is released under the ZLib license, so you can use it in open source or commercial code. The details of the license are at the top of every source file. TinyXML attempts to be a flexible parser, but with truly correct and compliant XML output. TinyXML should compile on any reasonably C++ compliant system. It does not rely on exceptions or RTTI. It can be compiled with or without STL support. TinyXML fully supports the UTF-8 encoding, and the first 64k character entities.

What it doesn't do.

TinyXML doesn't parse or use DTDs (Document Type Definitions) or XSLs (eXtensible Stylesheet Language.) There are other parsers out there (check out www.sourceforge.org, search for XML) that are much more fully featured. But they are also much bigger, take longer to set up in your project, have a higher learning curve, and often have a more restrictive license. If you are working with browsers or have more complete XML needs, TinyXML is not the parser for you. The following DTD syntax will not parse at this time in TinyXML: @verbatim ]> @endverbatim because TinyXML sees this as a !DOCTYPE node with an illegally embedded !ELEMENT node. This may be addressed in the future.

Tutorials.

For the impatient, here is a tutorial to get you going. A great way to get started, but it is worth your time to read this (very short) manual completely. - @subpage tutorial0

Code Status.

TinyXML is mature, tested code. It is very stable. If you find bugs, please file a bug report on the sourceforge web site (www.sourceforge.net/projects/tinyxml). We'll get them straightened out as soon as possible. There are some areas of improvement; please check sourceforge if you are interested in working on TinyXML.

Related Projects

TinyXML projects you may find useful! (Descriptions provided by the projects.)
  • TinyXPath (http://tinyxpath.sourceforge.net). TinyXPath is a small footprint XPath syntax decoder, written in C++.
  • TinyXML++ (http://code.google.com/p/ticpp/). TinyXML++ is a completely new interface to TinyXML that uses MANY of the C++ strengths. Templates, exceptions, and much better error handling.

Features

Using STL

TinyXML can be compiled to use or not use STL. When using STL, TinyXML uses the std::string class, and fully supports std::istream, std::ostream, operator<<, and operator>>. Many API methods have both 'const char*' and 'const std::string&' forms. When STL support is compiled out, no STL files are included whatsoever. All the string classes are implemented by TinyXML itself. API methods all use the 'const char*' form for input. Use the compile time #define: TIXML_USE_STL to compile one version or the other. This can be passed by the compiler, or set as the first line of "tinyxml.h". Note: If compiling the test code in Linux, setting the environment variable TINYXML_USE_STL=YES/NO will control STL compilation. In the Windows project file, STL and non STL targets are provided. In your project, It's probably easiest to add the line "#define TIXML_USE_STL" as the first line of tinyxml.h.

UTF-8

TinyXML supports UTF-8 allowing to manipulate XML files in any language. TinyXML also supports "legacy mode" - the encoding used before UTF-8 support and probably best described as "extended ascii". Normally, TinyXML will try to detect the correct encoding and use it. However, by setting the value of TIXML_DEFAULT_ENCODING in the header file, TinyXML can be forced to always use one encoding. TinyXML will assume Legacy Mode until one of the following occurs:
  1. If the non-standard but common "UTF-8 lead bytes" (0xef 0xbb 0xbf) begin the file or data stream, TinyXML will read it as UTF-8.
  2. If the declaration tag is read, and it has an encoding="UTF-8", then TinyXML will read it as UTF-8.
  3. If the declaration tag is read, and it has no encoding specified, then TinyXML will read it as UTF-8.
  4. If the declaration tag is read, and it has an encoding="something else", then TinyXML will read it as Legacy Mode. In legacy mode, TinyXML will work as it did before. It's not clear what that mode does exactly, but old content should keep working.
  5. Until one of the above criteria is met, TinyXML runs in Legacy Mode.
What happens if the encoding is incorrectly set or detected? TinyXML will try to read and pass through text seen as improperly encoded. You may get some strange results or mangled characters. You may want to force TinyXML to the correct mode. You may force TinyXML to Legacy Mode by using LoadFile( TIXML_ENCODING_LEGACY ) or LoadFile( filename, TIXML_ENCODING_LEGACY ). You may force it to use legacy mode all the time by setting TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY. Likewise, you may force it to TIXML_ENCODING_UTF8 with the same technique. For English users, using English XML, UTF-8 is the same as low-ASCII. You don't need to be aware of UTF-8 or change your code in any way. You can think of UTF-8 as a "superset" of ASCII. UTF-8 is not a double byte format - but it is a standard encoding of Unicode! TinyXML does not use or directly support wchar, TCHAR, or Microsoft's _UNICODE at this time. It is common to see the term "Unicode" improperly refer to UTF-16, a wide byte encoding of unicode. This is a source of confusion. For "high-ascii" languages - everything not English, pretty much - TinyXML can handle all languages, at the same time, as long as the XML is encoded in UTF-8. That can be a little tricky, older programs and operating systems tend to use the "default" or "traditional" code page. Many apps (and almost all modern ones) can output UTF-8, but older or stubborn (or just broken) ones still output text in the default code page. For example, Japanese systems traditionally use SHIFT-JIS encoding. Text encoded as SHIFT-JIS can not be read by TinyXML. A good text editor can import SHIFT-JIS and then save as UTF-8. The Skew.org link does a great job covering the encoding issue. The test file "utf8test.xml" is an XML containing English, Spanish, Russian, and Simplified Chinese. (Hopefully they are translated correctly). The file "utf8test.gif" is a screen capture of the XML file, rendered in IE. Note that if you don't have the correct fonts (Simplified Chinese or Russian) on your system, you won't see output that matches the GIF file even if you can parse it correctly. Also note that (at least on my Windows machine) console output is in a Western code page, so that Print() or printf() cannot correctly display the file. This is not a bug in TinyXML - just an OS issue. No data is lost or destroyed by TinyXML. The console just doesn't render UTF-8.

Entities

TinyXML recognizes the pre-defined "character entities", meaning special characters. Namely: @verbatim & & < < > > " " ' ' @endverbatim These are recognized when the XML document is read, and translated to there UTF-8 equivalents. For instance, text with the XML of: @verbatim Far & Away @endverbatim will have the Value() of "Far & Away" when queried from the TiXmlText object, and will be written back to the XML stream/file as an ampersand. Older versions of TinyXML "preserved" character entities, but the newer versions will translate them into characters. Additionally, any character can be specified by its Unicode code point: The syntax " " or " " are both to the non-breaking space characher.

Printing

TinyXML can print output in several different ways that all have strengths and limitations. - Print( FILE* ). Output to a std-C stream, which includes all C files as well as stdout. - "Pretty prints", but you don't have control over printing options. - The output is streamed directly to the FILE object, so there is no memory overhead in the TinyXML code. - used by Print() and SaveFile() - operator<<. Output to a c++ stream. - Integrates with standart C++ iostreams. - Outputs in "network printing" mode without line breaks. Good for network transmission and moving XML between C++ objects, but hard for a human to read. - TiXmlPrinter. Output to a std::string or memory buffer. - API is less concise - Future printing options will be put here. - Printing may change slightly in future versions as it is refined and expanded.

Streams

With TIXML_USE_STL on TinyXML supports C++ streams (operator <<,>>) streams as well as C (FILE*) streams. There are some differences that you may need to be aware of. C style output: - based on FILE* - the Print() and SaveFile() methods Generates formatted output, with plenty of white space, intended to be as human-readable as possible. They are very fast, and tolerant of ill formed XML documents. For example, an XML document that contains 2 root elements and 2 declarations, will still print. C style input: - based on FILE* - the Parse() and LoadFile() methods A fast, tolerant read. Use whenever you don't need the C++ streams. C++ style output: - based on std::ostream - operator<< Generates condensed output, intended for network transmission rather than readability. Depending on your system's implementation of the ostream class, these may be somewhat slower. (Or may not.) Not tolerant of ill formed XML: a document should contain the correct one root element. Additional root level elements will not be streamed out. C++ style input: - based on std::istream - operator>> Reads XML from a stream, making it useful for network transmission. The tricky part is knowing when the XML document is complete, since there will almost certainly be other data in the stream. TinyXML will assume the XML data is complete after it reads the root element. Put another way, documents that are ill-constructed with more than one root element will not read correctly. Also note that operator>> is somewhat slower than Parse, due to both implementation of the STL and limitations of TinyXML.

White space

The world simply does not agree on whether white space should be kept, or condensed. For example, pretend the '_' is a space, and look at "Hello____world". HTML, and at least some XML parsers, will interpret this as "Hello_world". They condense white space. Some XML parsers do not, and will leave it as "Hello____world". (Remember to keep pretending the _ is a space.) Others suggest that __Hello___world__ should become Hello___world. It's an issue that hasn't been resolved to my satisfaction. TinyXML supports the first 2 approaches. Call TiXmlBase::SetCondenseWhiteSpace( bool ) to set the desired behavior. The default is to condense white space. If you change the default, you should call TiXmlBase::SetCondenseWhiteSpace( bool ) before making any calls to Parse XML data, and I don't recommend changing it after it has been set.

Handles

Where browsing an XML document in a robust way, it is important to check for null returns from method calls. An error safe implementation can generate a lot of code like: @verbatim TiXmlElement* root = document.FirstChildElement( "Document" ); if ( root ) { TiXmlElement* element = root->FirstChildElement( "Element" ); if ( element ) { TiXmlElement* child = element->FirstChildElement( "Child" ); if ( child ) { TiXmlElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. @endverbatim Handles have been introduced to clean this up. Using the TiXmlHandle class, the previous code reduces to: @verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // do something useful @endverbatim Which is much easier to deal with. See TiXmlHandle for more information.

Row and Column tracking

Being able to track nodes and attributes back to their origin location in source files can be very important for some applications. Additionally, knowing where parsing errors occured in the original source can be very time saving. TinyXML can tracks the row and column origin of all nodes and attributes in a text file. The TiXmlBase::Row() and TiXmlBase::Column() methods return the origin of the node in the source text. The correct tabs can be configured in TiXmlDocument::SetTabSize().

Using and Installing

To Compile and Run xmltest: A Linux Makefile and a Windows Visual C++ .dsw file is provided. Simply compile and run. It will write the file demotest.xml to your disk and generate output on the screen. It also tests walking the DOM by printing out the number of nodes found using different techniques. The Linux makefile is very generic and runs on many systems - it is currently tested on mingw and MacOSX. You do not need to run 'make depend'. The dependecies have been hard coded.

Windows project file for VC6

  • tinyxml: tinyxml library, non-STL
  • tinyxmlSTL: tinyxml library, STL
  • tinyXmlTest: test app, non-STL
  • tinyXmlTestSTL: test app, STL

Makefile

At the top of the makefile you can set: PROFILE, DEBUG, and TINYXML_USE_STL. Details (such that they are) are in the makefile. In the tinyxml directory, type "make clean" then "make". The executable file 'xmltest' will be created.

To Use in an Application:

Add tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp, and tinystr.h to your project or make file. That's it! It should compile on any reasonably compliant C++ system. You do not need to enable exceptions or RTTI for TinyXML.

How TinyXML works.

An example is probably the best way to go. Take: @verbatim Go to the Toy store! Do bills @endverbatim Its not much of a To Do list, but it will do. To read this file (say "demo.xml") you would create a document, and parse it in: @verbatim TiXmlDocument doc( "demo.xml" ); doc.LoadFile(); @endverbatim And its ready to go. Now lets look at some lines and how they relate to the DOM. @verbatim @endverbatim The first line is a declaration, and gets turned into the TiXmlDeclaration class. It will be the first child of the document node. This is the only directive/special tag parsed by TinyXML. Generally directive tags are stored in TiXmlUnknown so the commands wont be lost when it is saved back to disk. @verbatim @endverbatim A comment. Will become a TiXmlComment object. @verbatim @endverbatim The "ToDo" tag defines a TiXmlElement object. This one does not have any attributes, but does contain 2 other elements. @verbatim @endverbatim Creates another TiXmlElement which is a child of the "ToDo" element. This element has 1 attribute, with the name "priority" and the value "1". @verbatim Go to the @endverbatim A TiXmlText. This is a leaf node and cannot contain other nodes. It is a child of the "Item" TiXmlElement. @verbatim @endverbatim Another TiXmlElement, this one a child of the "Item" element. Etc. Looking at the entire object tree, you end up with: @verbatim TiXmlDocument "demo.xml" TiXmlDeclaration "version='1.0'" "standalone=no" TiXmlComment " Our to do list data" TiXmlElement "ToDo" TiXmlElement "Item" Attribtutes: priority = 1 TiXmlText "Go to the " TiXmlElement "bold" TiXmlText "Toy store!" TiXmlElement "Item" Attributes: priority=2 TiXmlText "Do bills" @endverbatim

Documentation

The documentation is build with Doxygen, using the 'dox' configuration file.

License

TinyXML is released under the zlib license: This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.

References

The World Wide Web Consortium is the definitive standard body for XML, and their web pages contain huge amounts of information. The definitive spec: http://www.w3.org/TR/2004/REC-xml-20040204/ I also recommend "XML Pocket Reference" by Robert Eckstein and published by OReilly...the book that got the whole thing started.

Contributors, Contacts, and a Brief History

Thanks very much to everyone who sends suggestions, bugs, ideas, and encouragement. It all helps, and makes this project fun. A special thanks to the contributors on the web pages that keep it lively. So many people have sent in bugs and ideas, that rather than list here we try to give credit due in the "changes.txt" file. TinyXML was originally written by Lee Thomason. (Often the "I" still in the documentation.) Lee reviews changes and releases new versions, with the help of Yves Berquin, Andrew Ellerton, and the tinyXml community. We appreciate your suggestions, and would love to know if you use TinyXML. Hopefully you will enjoy it and find it useful. Please post questions, comments, file bugs, or contact us at: www.sourceforge.net/projects/tinyxml Lee Thomason, Yves Berquin, Andrew Ellerton */ presage-0.8.8/src/lib/tinyxml/tinyxml.h0000644000175000017500000017650211743227551015036 00000000000000/* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TINYXML_INCLUDED #define TINYXML_INCLUDED #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4530 ) #pragma warning( disable : 4786 ) #endif #include #include #include #include #include // Help out windows: #if defined( _DEBUG ) && !defined( DEBUG ) #define DEBUG #endif #ifdef TIXML_USE_STL #include #include #include #define TIXML_STRING std::string #else #include "tinystr.h" #define TIXML_STRING TiXmlString #endif // Deprecated library function hell. Compilers want to use the // new safe versions. This probably doesn't fully address the problem, // but it gets closer. There are too many compilers for me to fully // test. If you get compilation troubles, undefine TIXML_SAFE #define TIXML_SAFE #ifdef TIXML_SAFE #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) // Microsoft visual studio, version 2005 and higher. #define TIXML_SNPRINTF _snprintf_s #define TIXML_SSCANF sscanf_s #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. //#pragma message( "Using _sn* functions." ) #define TIXML_SNPRINTF _snprintf #define TIXML_SSCANF sscanf #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #else #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #endif #endif class TiXmlDocument; class TiXmlElement; class TiXmlComment; class TiXmlUnknown; class TiXmlAttribute; class TiXmlText; class TiXmlDeclaration; class TiXmlParsingData; const int TIXML_MAJOR_VERSION = 2; const int TIXML_MINOR_VERSION = 6; const int TIXML_PATCH_VERSION = 2; /* Internal structure for tracking location of items in the XML file. */ struct TiXmlCursor { TiXmlCursor() { Clear(); } void Clear() { row = col = -1; } int row; // 0 based. int col; // 0 based. }; /** Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a TiXmlVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves are simply called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its sibilings will be Visited. All flavors of Visit methods have a default implementation that returns 'true' (continue visiting). You need to only override methods that are interesting to you. Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. You should never change the document from a callback. @sa TiXmlNode::Accept() */ class TiXmlVisitor { public: virtual ~TiXmlVisitor() {} /// Visit a document. virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit a document. virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit an element. virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } /// Visit an element. virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } /// Visit a declaration virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } /// Visit a text node virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } /// Visit a comment node virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } /// Visit an unknown node virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } }; // Only used by Attribute::Query functions enum { TIXML_SUCCESS, TIXML_NO_ATTRIBUTE, TIXML_WRONG_TYPE }; // Used by the parsing routines. enum TiXmlEncoding { TIXML_ENCODING_UNKNOWN, TIXML_ENCODING_UTF8, TIXML_ENCODING_LEGACY }; const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; /** TiXmlBase is a base class for every class in TinyXml. It does little except to establish that TinyXml classes can be printed and provide some utility functions. In XML, the document and elements can contain other elements and other types of nodes. @verbatim A Document can contain: Element (container or leaf) Comment (leaf) Unknown (leaf) Declaration( leaf ) An Element can contain: Element (container or leaf) Text (leaf) Attributes (not on tree) Comment (leaf) Unknown (leaf) A Decleration contains: Attributes (not on tree) @endverbatim */ class TiXmlBase { friend class TiXmlNode; friend class TiXmlElement; friend class TiXmlDocument; public: TiXmlBase() : userData(0) {} virtual ~TiXmlBase() {} /** All TinyXml classes can print themselves to a filestream or the string class (TiXmlString in non-STL mode, std::string in STL mode.) Either or both cfile and str can be null. This is a formatted print, and will insert tabs and newlines. (For an unformatted stream, use the << operator.) */ virtual void Print( FILE* cfile, int depth ) const = 0; /** The world does not agree on whether white space should be kept or not. In order to make everyone happy, these global, static functions are provided to set whether or not TinyXml will condense all white space into a single space or not. The default is to condense. Note changing this value is not thread safe. */ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } /// Return the current white space setting. static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } /** Return the position, in the original source file, of this node or attribute. The row and column are 1-based. (That is the first row and first column is 1,1). If the returns values are 0 or less, then the parser does not have a row and column value. Generally, the row and column value will be set when the TiXmlDocument::Load(), TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set when the DOM was created from operator>>. The values reflect the initial load. Once the DOM is modified programmatically (by adding or changing nodes and attributes) the new values will NOT update to reflect changes in the document. There is a minor performance cost to computing the row and column. Computation can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. @sa TiXmlDocument::SetTabSize() */ int Row() const { return location.row + 1; } int Column() const { return location.col + 1; } ///< See Row() void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. // Table that returs, for a given lead byte, the total number of bytes // in the UTF-8 sequence. static const int utf8ByteTable[256]; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, or they will be transformed into entities! */ static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); enum { TIXML_NO_ERROR = 0, TIXML_ERROR, TIXML_ERROR_OPENING_FILE, TIXML_ERROR_PARSING_ELEMENT, TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, TIXML_ERROR_READING_ELEMENT_VALUE, TIXML_ERROR_READING_ATTRIBUTES, TIXML_ERROR_PARSING_EMPTY, TIXML_ERROR_READING_END_TAG, TIXML_ERROR_PARSING_UNKNOWN, TIXML_ERROR_PARSING_COMMENT, TIXML_ERROR_PARSING_DECLARATION, TIXML_ERROR_DOCUMENT_EMPTY, TIXML_ERROR_EMBEDDED_NULL, TIXML_ERROR_PARSING_CDATA, TIXML_ERROR_DOCUMENT_TOP_ONLY, TIXML_ERROR_STRING_COUNT }; protected: static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); inline static bool IsWhiteSpace( char c ) { return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); } inline static bool IsWhiteSpace( int c ) { if ( c < 256 ) return IsWhiteSpace( (char) c ); return false; // Again, only truly correct for English/Latin...but usually works. } #ifdef TIXML_USE_STL static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); #endif /* Reads an XML name into the string provided. Returns a pointer just past the last character of the name, or 0 if the function has an error. */ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); /* Reads text. Returns a pointer past the given end tag. Wickedly complex options, but it keeps the (sensitive) code in one place. */ static const char* ReadText( const char* in, // where to start TIXML_STRING* text, // the string read bool ignoreWhiteSpace, // whether to keep the white space const char* endTag, // what ends this text bool ignoreCase, // whether to ignore case in the end tag TiXmlEncoding encoding ); // the current encoding // If an entity has been found, transform it into a character. static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); // Get a character, while interpreting entities. // The length can be from 0 to 4 bytes. inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) { assert( p ); if ( encoding == TIXML_ENCODING_UTF8 ) { *length = utf8ByteTable[ *((const unsigned char*)p) ]; assert( *length >= 0 && *length < 5 ); } else { *length = 1; } if ( *length == 1 ) { if ( *p == '&' ) return GetEntity( p, _value, length, encoding ); *_value = *p; return p+1; } else if ( *length ) { //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), // and the null terminator isn't needed for( int i=0; p[i] && i<*length; ++i ) { _value[i] = p[i]; } return p + (*length); } else { // Not valid text. return 0; } } // Return true if the next characters in the stream are any of the endTag sequences. // Ignore case only works for english, and should only be relied on when comparing // to English words: StringEqual( p, "version", true ) is fine. static bool StringEqual( const char* p, const char* endTag, bool ignoreCase, TiXmlEncoding encoding ); static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; TiXmlCursor location; /// Field containing a generic user pointer void* userData; // None of these methods are reliable for any language except English. // Good for approximation, not great for accuracy. static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); inline static int ToLower( int v, TiXmlEncoding encoding ) { if ( encoding == TIXML_ENCODING_UTF8 ) { if ( v < 128 ) return tolower( v ); return v; } else { return tolower( v ); } } static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); private: TiXmlBase( const TiXmlBase& ); // not implemented. void operator=( const TiXmlBase& base ); // not allowed. struct Entity { const char* str; unsigned int strLength; char chr; }; enum { NUM_ENTITY = 5, MAX_ENTITY_LENGTH = 6 }; static Entity entity[ NUM_ENTITY ]; static bool condenseWhiteSpace; }; /** The parent class for everything in the Document Object Model. (Except for attributes). Nodes have siblings, a parent, and children. A node can be in a document, or stand on its own. The type of a TiXmlNode can be queried, and it can be cast to its more defined type. */ class TiXmlNode : public TiXmlBase { friend class TiXmlDocument; friend class TiXmlElement; public: #ifdef TIXML_USE_STL /** An input stream operator, for every class. Tolerant of newlines and formatting, but doesn't expect them. */ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); /** An output stream operator, for every class. Note that this outputs without any newlines or formatting, as opposed to Print(), which includes tabs and new lines. The operator<< and operator>> are not completely symmetric. Writing a node to a stream is very well defined. You'll get a nice stream of output, without any extra whitespace or newlines. But reading is not as well defined. (As it always is.) If you create a TiXmlElement (for example) and read that from an input stream, the text needs to define an element or junk will result. This is true of all input streams, but it's worth keeping in mind. A TiXmlDocument will read nodes until it reads a root element, and all the children of that root element. */ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); /// Appends the XML node or attribute to a std::string. friend std::string& operator<< (std::string& out, const TiXmlNode& base ); #endif /** The types of XML nodes supported by TinyXml. (All the unsupported types are picked up by UNKNOWN.) */ enum NodeType { TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, TINYXML_UNKNOWN, TINYXML_TEXT, TINYXML_DECLARATION, TINYXML_TYPECOUNT }; virtual ~TiXmlNode(); /** The meaning of 'value' changes for the specific type of TiXmlNode. @verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim The subclasses will wrap this function. */ const char *Value() const { return value.c_str (); } #ifdef TIXML_USE_STL /** Return Value() as a std::string. If you only use STL, this is more efficient than calling Value(). Only available in STL mode. */ const std::string& ValueStr() const { return value; } #endif const TIXML_STRING& ValueTStr() const { return value; } /** Changes the value of the node. Defined as: @verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim */ void SetValue(const char * _value) { value = _value;} #ifdef TIXML_USE_STL /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Delete all the children of this node. Does not affect 'this'. void Clear(); /// One step up the DOM. TiXmlNode* Parent() { return parent; } const TiXmlNode* Parent() const { return parent; } const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. TiXmlNode* FirstChild() { return firstChild; } const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. /// The first child of this node with the matching 'value'. Will be null if none found. TiXmlNode* FirstChild( const char * _value ) { // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) // call the method, cast the return back to non-const. return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); } const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. TiXmlNode* LastChild() { return lastChild; } const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. TiXmlNode* LastChild( const char * _value ) { return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); } #ifdef TIXML_USE_STL const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. #endif /** An alternate way to walk the children of a node. One way to iterate over nodes is: @verbatim for( child = parent->FirstChild(); child; child = child->NextSibling() ) @endverbatim IterateChildren does the same thing with the syntax: @verbatim child = 0; while( child = parent->IterateChildren( child ) ) @endverbatim IterateChildren takes the previous child as input and finds the next one. If the previous child is null, it returns the first. IterateChildren will return null when done. */ const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); } /// This flavor of IterateChildren searches for children with a particular 'value' const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); } #ifdef TIXML_USE_STL const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. #endif /** Add a new node related to this. Adds a child past the LastChild. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child past the LastChild. NOTE: the node to be added is passed by pointer, and will be henceforth owned (and deleted) by tinyXml. This method is efficient and avoids an extra copy, but should be used with care as it uses a different memory model than the other insert functions. @sa InsertEndChild */ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); /** Add a new node related to this. Adds a child before the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child after the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); /** Replace a child of this node. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); /// Delete a child of this node. bool RemoveChild( TiXmlNode* removeThis ); /// Navigate to a sibling node. const TiXmlNode* PreviousSibling() const { return prev; } TiXmlNode* PreviousSibling() { return prev; } /// Navigate to a sibling node. const TiXmlNode* PreviousSibling( const char * ) const; TiXmlNode* PreviousSibling( const char *_prev ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); } #ifdef TIXML_USE_STL const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. #endif /// Navigate to a sibling node. const TiXmlNode* NextSibling() const { return next; } TiXmlNode* NextSibling() { return next; } /// Navigate to a sibling node with the given 'value'. const TiXmlNode* NextSibling( const char * ) const; TiXmlNode* NextSibling( const char* _next ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement() const; TiXmlElement* NextSiblingElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement( const char * ) const; TiXmlElement* NextSiblingElement( const char *_next ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); } #ifdef TIXML_USE_STL const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. #endif /// Convenience function to get through elements. const TiXmlElement* FirstChildElement() const; TiXmlElement* FirstChildElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); } /// Convenience function to get through elements. const TiXmlElement* FirstChildElement( const char * _value ) const; TiXmlElement* FirstChildElement( const char * _value ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); } #ifdef TIXML_USE_STL const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. #endif /** Query the type (as an enumerated value, above) of this node. The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. */ int Type() const { return type; } /** Return a pointer to the Document this node lives in. Returns null if not in a document. */ const TiXmlDocument* GetDocument() const; TiXmlDocument* GetDocument() { return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); } /// Returns true if this node has no children. bool NoChildren() const { return !firstChild; } virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. /** Create an exact duplicate of this node and return it. The memory must be deleted by the caller. */ virtual TiXmlNode* Clone() const = 0; /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the TiXmlVisitor interface. This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML is unchanged by using this interface versus any other.) The interface has been based on ideas from: - http://www.saxproject.org/ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern Which are both good references for "visiting". An example of using Accept(): @verbatim TiXmlPrinter printer; tinyxmlDoc.Accept( &printer ); const char* xmlcstr = printer.CStr(); @endverbatim */ virtual bool Accept( TiXmlVisitor* visitor ) const = 0; protected: TiXmlNode( NodeType _type ); // Copy to the allocated object. Shared functionality between Clone, Copy constructor, // and the assignment operator. void CopyTo( TiXmlNode* target ) const; #ifdef TIXML_USE_STL // The real work of the input operator. virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; #endif // Figure out what is at *p, and parse it. Returns null if it is not an xml node. TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); TiXmlNode* parent; NodeType type; TiXmlNode* firstChild; TiXmlNode* lastChild; TIXML_STRING value; TiXmlNode* prev; TiXmlNode* next; private: TiXmlNode( const TiXmlNode& ); // not implemented. void operator=( const TiXmlNode& base ); // not allowed. }; /** An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name. @note The attributes are not TiXmlNodes, since they are not part of the tinyXML document object model. There are other suggested ways to look at this problem. */ class TiXmlAttribute : public TiXmlBase { friend class TiXmlAttributeSet; public: /// Construct an empty attribute. TiXmlAttribute() : TiXmlBase() { document = 0; prev = next = 0; } #ifdef TIXML_USE_STL /// std::string constructor. TiXmlAttribute( const std::string& _name, const std::string& _value ) { name = _name; value = _value; document = 0; prev = next = 0; } #endif /// Construct an attribute with a name and value. TiXmlAttribute( const char * _name, const char * _value ) { name = _name; value = _value; document = 0; prev = next = 0; } const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. #ifdef TIXML_USE_STL const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. #endif int IntValue() const; ///< Return the value of this attribute, converted to an integer. double DoubleValue() const; ///< Return the value of this attribute, converted to a double. // Get the tinyxml string representation const TIXML_STRING& NameTStr() const { return name; } /** QueryIntValue examines the value string. It is an alternative to the IntValue() method with richer error checking. If the value is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. A specialized but useful call. Note that for success it returns 0, which is the opposite of almost all other TinyXml calls. */ int QueryIntValue( int* _value ) const; /// QueryDoubleValue examines the value string. See QueryIntValue(). int QueryDoubleValue( double* _value ) const; void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. void SetValue( const char* _value ) { value = _value; } ///< Set the value. void SetIntValue( int _value ); ///< Set the value from an integer. void SetDoubleValue( double _value ); ///< Set the value from a double. #ifdef TIXML_USE_STL /// STL std::string form. void SetName( const std::string& _name ) { name = _name; } /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Get the next sibling attribute in the DOM. Returns null at end. const TiXmlAttribute* Next() const; TiXmlAttribute* Next() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); } /// Get the previous sibling attribute in the DOM. Returns null at beginning. const TiXmlAttribute* Previous() const; TiXmlAttribute* Previous() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); } bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } /* Attribute parsing starts: first letter of the name returns: the next char after the value end quote */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); // Prints this Attribute to a FILE stream. virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; // [internal use] // Set the document pointer so the attribute can report errors. void SetDocument( TiXmlDocument* doc ) { document = doc; } private: TiXmlAttribute( const TiXmlAttribute& ); // not implemented. void operator=( const TiXmlAttribute& base ); // not allowed. TiXmlDocument* document; // A pointer back to a document, for error reporting. TIXML_STRING name; TIXML_STRING value; TiXmlAttribute* prev; TiXmlAttribute* next; }; /* A class used to manage a group of attributes. It is only used internally, both by the ELEMENT and the DECLARATION. The set can be changed transparent to the Element and Declaration classes that use it, but NOT transparent to the Attribute which has to implement a next() and previous() method. Which makes it a bit problematic and prevents the use of STL. This version is implemented with circular lists because: - I like circular lists - it demonstrates some independence from the (typical) doubly linked list. */ class TiXmlAttributeSet { public: TiXmlAttributeSet(); ~TiXmlAttributeSet(); void Add( TiXmlAttribute* attribute ); void Remove( TiXmlAttribute* attribute ); const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Find( const char* _name ) const; TiXmlAttribute* FindOrCreate( const char* _name ); # ifdef TIXML_USE_STL TiXmlAttribute* Find( const std::string& _name ) const; TiXmlAttribute* FindOrCreate( const std::string& _name ); # endif private: //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), //*ME: this class must be also use a hidden/disabled copy-constructor !!! TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) TiXmlAttribute sentinel; }; /** The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes. */ class TiXmlElement : public TiXmlNode { public: /// Construct an element. TiXmlElement (const char * in_value); #ifdef TIXML_USE_STL /// std::string constructor. TiXmlElement( const std::string& _value ); #endif TiXmlElement( const TiXmlElement& ); TiXmlElement& operator=( const TiXmlElement& base ); virtual ~TiXmlElement(); /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. */ const char* Attribute( const char* name ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an integer, the integer value will be put in the return 'i', if 'i' is non-null. */ const char* Attribute( const char* name, int* i ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an double, the double value will be put in the return 'd', if 'd' is non-null. */ const char* Attribute( const char* name, double* d ) const; /** QueryIntAttribute examines the attribute - it is an alternative to the Attribute() method with richer error checking. If the attribute is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. If the attribute does not exist, then TIXML_NO_ATTRIBUTE is returned. */ int QueryIntAttribute( const char* name, int* _value ) const; /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). Note that '1', 'true', or 'yes' are considered true, while '0', 'false' and 'no' are considered false. */ int QueryBoolAttribute( const char* name, bool* _value ) const; /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). int QueryDoubleAttribute( const char* name, double* _value ) const; /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). int QueryFloatAttribute( const char* name, float* _value ) const { double d; int result = QueryDoubleAttribute( name, &d ); if ( result == TIXML_SUCCESS ) { *_value = (float)d; } return result; } #ifdef TIXML_USE_STL /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). int QueryStringAttribute( const char* name, std::string* _value ) const { const char* cstr = Attribute( name ); if ( cstr ) { *_value = std::string( cstr ); return TIXML_SUCCESS; } return TIXML_NO_ATTRIBUTE; } /** Template form of the attribute query which will try to read the attribute into the specified type. Very easy, very powerful, but be careful to make sure to call this with the correct type. NOTE: This method doesn't work correctly for 'string' types that contain spaces. @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE */ template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; std::stringstream sstream( node->ValueStr() ); sstream >> *outValue; if ( !sstream.fail() ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } int QueryValueAttribute( const std::string& name, std::string* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; *outValue = node->ValueStr(); return TIXML_SUCCESS; } #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char* name, const char * _value ); #ifdef TIXML_USE_STL const std::string* Attribute( const std::string& name ) const; const std::string* Attribute( const std::string& name, int* i ) const; const std::string* Attribute( const std::string& name, double* d ) const; int QueryIntAttribute( const std::string& name, int* _value ) const; int QueryDoubleAttribute( const std::string& name, double* _value ) const; /// STL std::string form. void SetAttribute( const std::string& name, const std::string& _value ); ///< STL std::string form. void SetAttribute( const std::string& name, int _value ); ///< STL std::string form. void SetDoubleAttribute( const std::string& name, double value ); #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char * name, int value ); /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetDoubleAttribute( const char * name, double value ); /** Deletes an attribute with the given name. */ void RemoveAttribute( const char * name ); #ifdef TIXML_USE_STL void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. #endif const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } /** Convenience function for easy access to the text inside an element. Although easy and concise, GetText() is limited compared to getting the TiXmlText child and accessing it directly. If the first child of 'this' is a TiXmlText, the GetText() returns the character string of the Text node, else null is returned. This is a convenient method for getting the text of simple contained text: @verbatim This is text const char* str = fooElement->GetText(); @endverbatim 'str' will be a pointer to "This is text". Note that this function can be misleading. If the element foo was created from this XML: @verbatim This is text @endverbatim then the value of str would be null. The first child node isn't a text node, it is another element. From this XML: @verbatim This is text @endverbatim GetText() will return "This is ". WARNING: GetText() accesses a child node - don't become confused with the similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are safe type casts on the referenced node. */ const char* GetText() const; /// Creates a new Element and returns it - the returned element is a copy. virtual TiXmlNode* Clone() const; // Print the Element to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: next char past '<' returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlElement* target ) const; void ClearThis(); // like clear, but initializes 'this' object as well // Used to be public [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif /* [internal use] Reads the "value" of the element -- another element, or text. This should terminate with the current end tag. */ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); private: TiXmlAttributeSet attributeSet; }; /** An XML comment. */ class TiXmlComment : public TiXmlNode { public: /// Constructs an empty comment. TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} /// Construct a comment from text. TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { SetValue( _value ); } TiXmlComment( const TiXmlComment& ); TiXmlComment& operator=( const TiXmlComment& base ); virtual ~TiXmlComment() {} /// Returns a copy of this Comment. virtual TiXmlNode* Clone() const; // Write this Comment to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: at the ! of the !-- returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlComment* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif // virtual void StreamOut( TIXML_OSTREAM * out ) const; private: }; /** XML text. A text node can have 2 ways to output the next. "normal" output and CDATA. It will default to the mode it was parsed from the XML file and you generally want to leave it alone, but you can change the output mode with SetCDATA() and query it with CDATA(). */ class TiXmlText : public TiXmlNode { friend class TiXmlElement; public: /** Constructor for text element. By default, it is treated as normal, encoded text. If you want it be output as a CDATA text element, set the parameter _cdata to 'true' */ TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } virtual ~TiXmlText() {} #ifdef TIXML_USE_STL /// Constructor. TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } #endif TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } // Write this text object to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /// Queries whether this represents text using a CDATA section. bool CDATA() const { return cdata; } /// Turns on or off a CDATA representation of text. void SetCDATA( bool _cdata ) { cdata = _cdata; } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : /// [internal use] Creates a new Element and returns it. virtual TiXmlNode* Clone() const; void CopyTo( TiXmlText* target ) const; bool Blank() const; // returns true if all white space and new lines // [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: bool cdata; // true if this should be input and output as a CDATA style text element }; /** In correct XML the declaration is the first entry in the file. @verbatim @endverbatim TinyXml will happily read or write files without a declaration, however. There are 3 possible attributes to the declaration: version, encoding, and standalone. Note: In this version of the code, the attributes are handled as special cases, not generic attributes, simply because there can only be at most 3 and they are always the same. */ class TiXmlDeclaration : public TiXmlNode { public: /// Construct an empty declaration. TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} #ifdef TIXML_USE_STL /// Constructor. TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ); #endif /// Construct. TiXmlDeclaration( const char* _version, const char* _encoding, const char* _standalone ); TiXmlDeclaration( const TiXmlDeclaration& copy ); TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); virtual ~TiXmlDeclaration() {} /// Version. Will return an empty string if none was found. const char *Version() const { return version.c_str (); } /// Encoding. Will return an empty string if none was found. const char *Encoding() const { return encoding.c_str (); } /// Is this a standalone document? const char *Standalone() const { return standalone.c_str (); } /// Creates a copy of this Declaration and returns it. virtual TiXmlNode* Clone() const; // Print this declaration to a FILE stream. virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlDeclaration* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: TIXML_STRING version; TIXML_STRING encoding; TIXML_STRING standalone; }; /** Any tag that tinyXml doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved. DTD tags get thrown into TiXmlUnknowns. */ class TiXmlUnknown : public TiXmlNode { public: TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} virtual ~TiXmlUnknown() {} TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } /// Creates a copy of this Unknown and returns it. virtual TiXmlNode* Clone() const; // Print this Unknown to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected: void CopyTo( TiXmlUnknown* target ) const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: }; /** Always the top level node. A document binds together all the XML pieces. It can be saved, loaded, and printed to the screen. The 'value' of a document node is the xml file name. */ class TiXmlDocument : public TiXmlNode { public: /// Create an empty document, that has no name. TiXmlDocument(); /// Create a document with a name. The name of the document is also the filename of the xml. TiXmlDocument( const char * documentName ); #ifdef TIXML_USE_STL /// Constructor. TiXmlDocument( const std::string& documentName ); #endif TiXmlDocument( const TiXmlDocument& copy ); TiXmlDocument& operator=( const TiXmlDocument& copy ); virtual ~TiXmlDocument() {} /** Load a file using the current document value. Returns true if successful. Will delete any existing document data before loading. */ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the current document value. Returns true if successful. bool SaveFile() const; /// Load a file using the given filename. Returns true if successful. bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given filename. Returns true if successful. bool SaveFile( const char * filename ) const; /** Load a file using the given FILE*. Returns true if successful. Note that this method doesn't stream - the entire object pointed at by the FILE* will be interpreted as an XML file. TinyXML doesn't stream in XML from the current file location. Streaming may be added in the future. */ bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given FILE*. Returns true if successful. bool SaveFile( FILE* ) const; #ifdef TIXML_USE_STL bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. { return LoadFile( filename.c_str(), encoding ); } bool SaveFile( const std::string& filename ) const ///< STL std::string version. { return SaveFile( filename.c_str() ); } #endif /** Parse the given null terminated block of xml data. Passing in an encoding to this method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml to use that encoding, regardless of what TinyXml might otherwise try to detect. */ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /** Get the root element -- the only top level element -- of the document. In well formed XML, there should only be one. TinyXml is tolerant of multiple elements at the document level. */ const TiXmlElement* RootElement() const { return FirstChildElement(); } TiXmlElement* RootElement() { return FirstChildElement(); } /** If an error occurs, Error will be set to true. Also, - The ErrorId() will contain the integer identifier of the error (not generally useful) - The ErrorDesc() method will return the name of the error. (very useful) - The ErrorRow() and ErrorCol() will return the location of the error (if known) */ bool Error() const { return error; } /// Contains a textual (english) description of the error if one occurs. const char * ErrorDesc() const { return errorDesc.c_str (); } /** Generally, you probably want the error string ( ErrorDesc() ). But if you prefer the ErrorId, this function will fetch it. */ int ErrorId() const { return errorId; } /** Returns the location (if known) of the error. The first column is column 1, and the first row is row 1. A value of 0 means the row and column wasn't applicable (memory errors, for example, have no row/column) or the parser lost the error. (An error in the error reporting, in that case.) @sa SetTabSize, Row, Column */ int ErrorRow() const { return errorLocation.row+1; } int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) to report the correct values for row and column. It does not change the output or input in any way. By calling this method, with a tab size greater than 0, the row and column of each node and attribute is stored when the file is loaded. Very useful for tracking the DOM back in to the source file. The tab size is required for calculating the location of nodes. If not set, the default of 4 is used. The tabsize is set per document. Setting the tabsize to 0 disables row/column tracking. Note that row and column tracking is not supported when using operator>>. The tab size needs to be enabled before the parse or load. Correct usage: @verbatim TiXmlDocument doc; doc.SetTabSize( 8 ); doc.Load( "myfile.xml" ); @endverbatim @sa Row, Column */ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } int TabSize() const { return tabsize; } /** If you have handled the error, it can be reset with this call. The error state is automatically cleared if you Parse a new XML block. */ void ClearError() { error = false; errorId = 0; errorDesc = ""; errorLocation.row = errorLocation.col = 0; //errorLocation.last = 0; } /** Write the document to standard out using formatted printing ("pretty print"). */ void Print() const { Print( stdout, 0 ); } /* Write the document to a string using formatted printing ("pretty print"). This will allocate a character array (new char[]) and return it as a pointer. The calling code pust call delete[] on the return char* to avoid a memory leak. */ //char* PrintToMemory() const; /// Print this Document to a FILE stream. virtual void Print( FILE* cfile, int depth = 0 ) const; // [internal use] void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : // [internal use] virtual TiXmlNode* Clone() const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: void CopyTo( TiXmlDocument* target ) const; bool error; int errorId; TIXML_STRING errorDesc; int tabsize; TiXmlCursor errorLocation; bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. }; /** A TiXmlHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml DOM structure. It is a separate utility class. Take an example: @verbatim @endverbatim Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very easy to write a *lot* of code that looks like: @verbatim TiXmlElement* root = document.FirstChildElement( "Document" ); if ( root ) { TiXmlElement* element = root->FirstChildElement( "Element" ); if ( element ) { TiXmlElement* child = element->FirstChildElement( "Child" ); if ( child ) { TiXmlElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. @endverbatim And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity of such code. A TiXmlHandle checks for null pointers so it is perfectly safe and correct to use: @verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // do something useful @endverbatim Which is MUCH more concise and useful. It is also safe to copy handles - internally they are nothing more than node pointers. @verbatim TiXmlHandle handleCopy = handle; @endverbatim What they should not be used for is iteration: @verbatim int i=0; while ( true ) { TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); if ( !child ) break; // do something ++i; } @endverbatim It seems reasonable, but it is in fact two embedded while loops. The Child method is a linear walk to find the element, so this code would iterate much more than it needs to. Instead, prefer: @verbatim TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); for( child; child; child=child->NextSiblingElement() ) { // do something } @endverbatim */ class TiXmlHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } /// Copy constructor TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } /// Return a handle to the first child node. TiXmlHandle FirstChild() const; /// Return a handle to the first child node with the given name. TiXmlHandle FirstChild( const char * value ) const; /// Return a handle to the first child element. TiXmlHandle FirstChildElement() const; /// Return a handle to the first child element with the given name. TiXmlHandle FirstChildElement( const char * value ) const; /** Return a handle to the "index" child with the given name. The first child is 0, the second 1, etc. */ TiXmlHandle Child( const char* value, int index ) const; /** Return a handle to the "index" child. The first child is 0, the second 1, etc. */ TiXmlHandle Child( int index ) const; /** Return a handle to the "index" child element with the given name. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( const char* value, int index ) const; /** Return a handle to the "index" child element. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( int index ) const; #ifdef TIXML_USE_STL TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } #endif /** Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* ToNode() const { return node; } /** Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } /** Return the handle as a TiXmlText. This may return null. */ TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } /** Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } /** @deprecated use ToNode. Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* Node() const { return ToNode(); } /** @deprecated use ToElement. Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* Element() const { return ToElement(); } /** @deprecated use ToText() Return the handle as a TiXmlText. This may return null. */ TiXmlText* Text() const { return ToText(); } /** @deprecated use ToUnknown() Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* Unknown() const { return ToUnknown(); } private: TiXmlNode* node; }; /** Print to memory functionality. The TiXmlPrinter is useful when you need to: -# Print to memory (especially in non-STL mode) -# Control formatting (line endings, etc.) When constructed, the TiXmlPrinter is in its default "pretty printing" mode. Before calling Accept() you can call methods to control the printing of the XML document. After TiXmlNode::Accept() is called, the printed document can be accessed via the CStr(), Str(), and Size() methods. TiXmlPrinter uses the Visitor API. @verbatim TiXmlPrinter printer; printer.SetIndent( "\t" ); doc.Accept( &printer ); fprintf( stdout, "%s", printer.CStr() ); @endverbatim */ class TiXmlPrinter : public TiXmlVisitor { public: TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), buffer(), indent( " " ), lineBreak( "\n" ) {} virtual bool VisitEnter( const TiXmlDocument& doc ); virtual bool VisitExit( const TiXmlDocument& doc ); virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); virtual bool VisitExit( const TiXmlElement& element ); virtual bool Visit( const TiXmlDeclaration& declaration ); virtual bool Visit( const TiXmlText& text ); virtual bool Visit( const TiXmlComment& comment ); virtual bool Visit( const TiXmlUnknown& unknown ); /** Set the indent characters for printing. By default 4 spaces but tab (\t) is also useful, or null/empty string for no indentation. */ void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } /// Query the indention string. const char* Indent() { return indent.c_str(); } /** Set the line breaking string. By default set to newline (\n). Some operating systems prefer other characters, or can be set to the null/empty string for no indenation. */ void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } /// Query the current line breaking string. const char* LineBreak() { return lineBreak.c_str(); } /** Switch over to "stream printing" which is the most dense formatting without linebreaks. Common when the XML is needed for network transmission. */ void SetStreamPrinting() { indent = ""; lineBreak = ""; } /// Return the result. const char* CStr() { return buffer.c_str(); } /// Return the length of the result string. size_t Size() { return buffer.size(); } #ifdef TIXML_USE_STL /// Return the result. const std::string& Str() { return buffer; } #endif private: void DoIndent() { for( int i=0; i #include using namespace std; #else #include #endif #if defined( WIN32 ) && defined( TUNE ) #include _CrtMemState startMemState; _CrtMemState endMemState; #endif #include "tinyxml.h" bool XmlTest (const char* testString, const char* expected, const char* found, bool noEcho = false); bool XmlTest( const char* testString, int expected, int found, bool noEcho = false ); static int gPass = 0; static int gFail = 0; bool XmlTest (const char* testString, const char* expected, const char* found, bool noEcho ) { bool pass = !strcmp( expected, found ); if ( pass ) printf ("[pass]"); else printf ("[fail]"); if ( noEcho ) printf (" %s\n", testString); else printf (" %s [%s][%s]\n", testString, expected, found); if ( pass ) ++gPass; else ++gFail; return pass; } bool XmlTest( const char* testString, int expected, int found, bool noEcho ) { bool pass = ( expected == found ); if ( pass ) printf ("[pass]"); else printf ("[fail]"); if ( noEcho ) printf (" %s\n", testString); else printf (" %s [%d][%d]\n", testString, expected, found); if ( pass ) ++gPass; else ++gFail; return pass; } void NullLineEndings( char* p ) { while( p && *p ) { if ( *p == '\n' || *p == '\r' ) { *p = 0; return; } ++p; } } // // This file demonstrates some basic functionality of TinyXml. // Note that the example is very contrived. It presumes you know // what is in the XML file. But it does test the basic operations, // and show how to add and remove nodes. // int main() { // // We start with the 'demoStart' todo list. Process it. And // should hopefully end up with the todo list as illustrated. // const char* demoStart = "\n" "" "\n" "\n" " Go to the Toy store!" " Do bills " " Look for Evil Dinosaurs! " ""; { #ifdef TIXML_USE_STL // What the todo list should look like after processing. // In stream (no formatting) representation. const char* demoEnd = "" "" "" "" "Go to the" "Toy store!" "" "" "Talk to:" "" "" "" "" "" "" "Do bills" "" ""; #endif // The example parses from the character string (above): #if defined( WIN32 ) && defined( TUNE ) _CrtMemCheckpoint( &startMemState ); #endif { // Write to a file and read it back, to check file I/O. TiXmlDocument doc( "demotest.xml" ); doc.Parse( demoStart ); if ( doc.Error() ) { printf( "Error in %s: %s\n", doc.Value(), doc.ErrorDesc() ); exit( 1 ); } doc.SaveFile(); } TiXmlDocument doc( "demotest.xml" ); bool loadOkay = doc.LoadFile(); if ( !loadOkay ) { printf( "Could not load test file 'demotest.xml'. Error='%s'. Exiting.\n", doc.ErrorDesc() ); exit( 1 ); } printf( "** Demo doc read from disk: ** \n\n" ); printf( "** Printing via doc.Print **\n" ); doc.Print( stdout ); { printf( "** Printing via TiXmlPrinter **\n" ); TiXmlPrinter printer; doc.Accept( &printer ); fprintf( stdout, "%s", printer.CStr() ); } #ifdef TIXML_USE_STL { printf( "** Printing via operator<< **\n" ); std::cout << doc; } #endif TiXmlNode* node = 0; TiXmlElement* todoElement = 0; TiXmlElement* itemElement = 0; // -------------------------------------------------------- // An example of changing existing attributes, and removing // an element from the document. // -------------------------------------------------------- // Get the "ToDo" element. // It is a child of the document, and can be selected by name. node = doc.FirstChild( "ToDo" ); assert( node ); todoElement = node->ToElement(); assert( todoElement ); // Going to the toy store is now our second priority... // So set the "priority" attribute of the first item in the list. node = todoElement->FirstChildElement(); // This skips the "PDA" comment. assert( node ); itemElement = node->ToElement(); assert( itemElement ); itemElement->SetAttribute( "priority", 2 ); // Change the distance to "doing bills" from // "none" to "here". It's the next sibling element. itemElement = itemElement->NextSiblingElement(); assert( itemElement ); itemElement->SetAttribute( "distance", "here" ); // Remove the "Look for Evil Dinosaurs!" item. // It is 1 more sibling away. We ask the parent to remove // a particular child. itemElement = itemElement->NextSiblingElement(); todoElement->RemoveChild( itemElement ); itemElement = 0; // -------------------------------------------------------- // What follows is an example of created elements and text // nodes and adding them to the document. // -------------------------------------------------------- // Add some meetings. TiXmlElement item( "Item" ); item.SetAttribute( "priority", "1" ); item.SetAttribute( "distance", "far" ); TiXmlText text( "Talk to:" ); TiXmlElement meeting1( "Meeting" ); meeting1.SetAttribute( "where", "School" ); TiXmlElement meeting2( "Meeting" ); meeting2.SetAttribute( "where", "Lunch" ); TiXmlElement attendee1( "Attendee" ); attendee1.SetAttribute( "name", "Marple" ); attendee1.SetAttribute( "position", "teacher" ); TiXmlElement attendee2( "Attendee" ); attendee2.SetAttribute( "name", "Voel" ); attendee2.SetAttribute( "position", "counselor" ); // Assemble the nodes we've created: meeting1.InsertEndChild( attendee1 ); meeting1.InsertEndChild( attendee2 ); item.InsertEndChild( text ); item.InsertEndChild( meeting1 ); item.InsertEndChild( meeting2 ); // And add the node to the existing list after the first child. node = todoElement->FirstChild( "Item" ); assert( node ); itemElement = node->ToElement(); assert( itemElement ); todoElement->InsertAfterChild( itemElement, item ); printf( "\n** Demo doc processed: ** \n\n" ); doc.Print( stdout ); #ifdef TIXML_USE_STL printf( "** Demo doc processed to stream: ** \n\n" ); cout << doc << endl << endl; #endif // -------------------------------------------------------- // Different tests...do we have what we expect? // -------------------------------------------------------- int count = 0; TiXmlElement* element; ////////////////////////////////////////////////////// #ifdef TIXML_USE_STL cout << "** Basic structure. **\n"; ostringstream outputStream( ostringstream::out ); outputStream << doc; XmlTest( "Output stream correct.", string( demoEnd ).c_str(), outputStream.str().c_str(), true ); #endif node = doc.RootElement(); assert( node ); XmlTest( "Root element exists.", true, ( node != 0 && node->ToElement() ) ); XmlTest ( "Root element value is 'ToDo'.", "ToDo", node->Value()); node = node->FirstChild(); XmlTest( "First child exists & is a comment.", true, ( node != 0 && node->ToComment() ) ); node = node->NextSibling(); XmlTest( "Sibling element exists & is an element.", true, ( node != 0 && node->ToElement() ) ); XmlTest ( "Value is 'Item'.", "Item", node->Value() ); node = node->FirstChild(); XmlTest ( "First child exists.", true, ( node != 0 && node->ToText() ) ); XmlTest ( "Value is 'Go to the'.", "Go to the", node->Value() ); ////////////////////////////////////////////////////// printf ("\n** Iterators. **\n"); // Walk all the top level nodes of the document. count = 0; for( node = doc.FirstChild(); node; node = node->NextSibling() ) { count++; } XmlTest( "Top level nodes, using First / Next.", 3, count ); count = 0; for( node = doc.LastChild(); node; node = node->PreviousSibling() ) { count++; } XmlTest( "Top level nodes, using Last / Previous.", 3, count ); // Walk all the top level nodes of the document, // using a different syntax. count = 0; for( node = doc.IterateChildren( 0 ); node; node = doc.IterateChildren( node ) ) { count++; } XmlTest( "Top level nodes, using IterateChildren.", 3, count ); // Walk all the elements in a node. count = 0; for( element = todoElement->FirstChildElement(); element; element = element->NextSiblingElement() ) { count++; } XmlTest( "Children of the 'ToDo' element, using First / Next.", 3, count ); // Walk all the elements in a node by value. count = 0; for( node = todoElement->FirstChild( "Item" ); node; node = node->NextSibling( "Item" ) ) { count++; } XmlTest( "'Item' children of the 'ToDo' element, using First/Next.", 3, count ); count = 0; for( node = todoElement->LastChild( "Item" ); node; node = node->PreviousSibling( "Item" ) ) { count++; } XmlTest( "'Item' children of the 'ToDo' element, using Last/Previous.", 3, count ); #ifdef TIXML_USE_STL { cout << "\n** Parsing. **\n"; istringstream parse0( "" ); TiXmlElement element0( "default" ); parse0 >> element0; XmlTest ( "Element parsed, value is 'Element0'.", "Element0", element0.Value() ); XmlTest ( "Reads attribute 'attribute0=\"foo0\"'.", "foo0", element0.Attribute( "attribute0" )); XmlTest ( "Reads incorrectly formatted 'attribute1=noquotes'.", "noquotes", element0.Attribute( "attribute1" ) ); XmlTest ( "Read attribute with entity value '>'.", ">", element0.Attribute( "attribute2" ) ); } #endif { const char* error = "\n" "\n" " \n" ""; TiXmlDocument docTest; docTest.Parse( error ); XmlTest( "Error row", docTest.ErrorRow(), 3 ); XmlTest( "Error column", docTest.ErrorCol(), 17 ); //printf( "error=%d id='%s' row %d col%d\n", (int) doc.Error(), doc.ErrorDesc(), doc.ErrorRow()+1, doc.ErrorCol() + 1 ); } #ifdef TIXML_USE_STL { ////////////////////////////////////////////////////// cout << "\n** Streaming. **\n"; // Round trip check: stream in, then stream back out to verify. The stream // out has already been checked, above. We use the output istringstream inputStringStream( outputStream.str() ); TiXmlDocument document0; inputStringStream >> document0; ostringstream outputStream0( ostringstream::out ); outputStream0 << document0; XmlTest( "Stream round trip correct.", string( demoEnd ).c_str(), outputStream0.str().c_str(), true ); std::string str; str << document0; XmlTest( "String printing correct.", string( demoEnd ).c_str(), str.c_str(), true ); } #endif } { const char* str = ""; TiXmlDocument doc; doc.Parse( str ); TiXmlElement* ele = doc.FirstChildElement(); int iVal, result; double dVal; result = ele->QueryDoubleAttribute( "attr0", &dVal ); XmlTest( "Query attribute: int as double", result, TIXML_SUCCESS ); XmlTest( "Query attribute: int as double", (int)dVal, 1 ); result = ele->QueryDoubleAttribute( "attr1", &dVal ); XmlTest( "Query attribute: double as double", (int)dVal, 2 ); result = ele->QueryIntAttribute( "attr1", &iVal ); XmlTest( "Query attribute: double as int", result, TIXML_SUCCESS ); XmlTest( "Query attribute: double as int", iVal, 2 ); result = ele->QueryIntAttribute( "attr2", &iVal ); XmlTest( "Query attribute: not a number", result, TIXML_WRONG_TYPE ); result = ele->QueryIntAttribute( "bar", &iVal ); XmlTest( "Query attribute: does not exist", result, TIXML_NO_ATTRIBUTE ); } { const char* str = ""; TiXmlDocument doc; doc.Parse( str ); TiXmlElement* ele = doc.FirstChildElement(); int iVal; double dVal; ele->SetAttribute( "str", "strValue" ); ele->SetAttribute( "int", 1 ); ele->SetDoubleAttribute( "double", -1.0 ); const char* cStr = ele->Attribute( "str" ); ele->QueryIntAttribute( "int", &iVal ); ele->QueryDoubleAttribute( "double", &dVal ); XmlTest( "Attribute round trip. c-string.", "strValue", cStr ); XmlTest( "Attribute round trip. int.", 1, iVal ); XmlTest( "Attribute round trip. double.", -1, (int)dVal ); } { const char* str = "\t\t\n" ""; TiXmlDocument doc; doc.SetTabSize( 8 ); doc.Parse( str ); TiXmlHandle docHandle( &doc ); TiXmlHandle roomHandle = docHandle.FirstChildElement( "room" ); assert( docHandle.Node() ); assert( roomHandle.Element() ); TiXmlElement* room = roomHandle.Element(); assert( room ); TiXmlAttribute* doors = room->FirstAttribute(); assert( doors ); XmlTest( "Location tracking: Tab 8: room row", room->Row(), 1 ); XmlTest( "Location tracking: Tab 8: room col", room->Column(), 49 ); XmlTest( "Location tracking: Tab 8: doors row", doors->Row(), 1 ); XmlTest( "Location tracking: Tab 8: doors col", doors->Column(), 55 ); } { const char* str = "\t\t\n" " \n" " A great door!\n" "\t" ""; TiXmlDocument doc; doc.Parse( str ); TiXmlHandle docHandle( &doc ); TiXmlHandle roomHandle = docHandle.FirstChildElement( "room" ); TiXmlHandle commentHandle = docHandle.FirstChildElement( "room" ).FirstChild(); TiXmlHandle textHandle = docHandle.FirstChildElement( "room" ).ChildElement( "door", 0 ).FirstChild(); TiXmlHandle door0Handle = docHandle.FirstChildElement( "room" ).ChildElement( 0 ); TiXmlHandle door1Handle = docHandle.FirstChildElement( "room" ).ChildElement( 1 ); assert( docHandle.Node() ); assert( roomHandle.Element() ); assert( commentHandle.Node() ); assert( textHandle.Text() ); assert( door0Handle.Element() ); assert( door1Handle.Element() ); TiXmlDeclaration* declaration = doc.FirstChild()->ToDeclaration(); assert( declaration ); TiXmlElement* room = roomHandle.Element(); assert( room ); TiXmlAttribute* doors = room->FirstAttribute(); assert( doors ); TiXmlText* text = textHandle.Text(); TiXmlComment* comment = commentHandle.Node()->ToComment(); assert( comment ); TiXmlElement* door0 = door0Handle.Element(); TiXmlElement* door1 = door1Handle.Element(); XmlTest( "Location tracking: Declaration row", declaration->Row(), 1 ); XmlTest( "Location tracking: Declaration col", declaration->Column(), 5 ); XmlTest( "Location tracking: room row", room->Row(), 1 ); XmlTest( "Location tracking: room col", room->Column(), 45 ); XmlTest( "Location tracking: doors row", doors->Row(), 1 ); XmlTest( "Location tracking: doors col", doors->Column(), 51 ); XmlTest( "Location tracking: Comment row", comment->Row(), 2 ); XmlTest( "Location tracking: Comment col", comment->Column(), 3 ); XmlTest( "Location tracking: text row", text->Row(), 3 ); XmlTest( "Location tracking: text col", text->Column(), 24 ); XmlTest( "Location tracking: door0 row", door0->Row(), 3 ); XmlTest( "Location tracking: door0 col", door0->Column(), 5 ); XmlTest( "Location tracking: door1 row", door1->Row(), 4 ); XmlTest( "Location tracking: door1 col", door1->Column(), 5 ); } // -------------------------------------------------------- // UTF-8 testing. It is important to test: // 1. Making sure name, value, and text read correctly // 2. Row, Col functionality // 3. Correct output // -------------------------------------------------------- printf ("\n** UTF-8 **\n"); { TiXmlDocument doc( "utf8test.xml" ); doc.LoadFile(); if ( doc.Error() && doc.ErrorId() == TiXmlBase::TIXML_ERROR_OPENING_FILE ) { printf( "WARNING: File 'utf8test.xml' not found.\n" "(Are you running the test from the wrong directory?)\n" "Could not test UTF-8 functionality.\n" ); } else { TiXmlHandle docH( &doc ); // Get the attribute "value" from the "Russian" element and check it. TiXmlElement* element = docH.FirstChildElement( "document" ).FirstChildElement( "Russian" ).Element(); const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU, 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 }; XmlTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ), true ); XmlTest( "UTF-8: Russian value row.", 4, element->Row() ); XmlTest( "UTF-8: Russian value column.", 5, element->Column() ); const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U, 0xd1U, 0x81U, 0xd1U, 0x81U, 0xd0U, 0xbaU, 0xd0U, 0xb8U, 0xd0U, 0xb9U, 0 }; const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>"; TiXmlText* text = docH.FirstChildElement( "document" ).FirstChildElement( (const char*) russianElementName ).Child( 0 ).Text(); XmlTest( "UTF-8: Browsing russian element name.", russianText, text->Value(), true ); XmlTest( "UTF-8: Russian element name row.", 7, text->Row() ); XmlTest( "UTF-8: Russian element name column.", 47, text->Column() ); TiXmlDeclaration* dec = docH.Child( 0 ).Node()->ToDeclaration(); XmlTest( "UTF-8: Declaration column.", 1, dec->Column() ); XmlTest( "UTF-8: Document column.", 1, doc.Column() ); // Now try for a round trip. doc.SaveFile( "utf8testout.xml" ); // Check the round trip. char savedBuf[256]; char verifyBuf[256]; int okay = 1; FILE* saved = fopen( "utf8testout.xml", "r" ); FILE* verify = fopen( "utf8testverify.xml", "r" ); //bool firstLineBOM=true; if ( saved && verify ) { while ( fgets( verifyBuf, 256, verify ) ) { fgets( savedBuf, 256, saved ); NullLineEndings( verifyBuf ); NullLineEndings( savedBuf ); if ( /*!firstLineBOM && */ strcmp( verifyBuf, savedBuf ) ) { printf( "verify:%s<\n", verifyBuf ); printf( "saved :%s<\n", savedBuf ); okay = 0; break; } //firstLineBOM = false; } } if ( saved ) fclose( saved ); if ( verify ) fclose( verify ); XmlTest( "UTF-8: Verified multi-language round trip.", 1, okay ); // On most Western machines, this is an element that contains // the word "resume" with the correct accents, in a latin encoding. // It will be something else completely on non-wester machines, // which is why TinyXml is switching to UTF-8. const char latin[] = "r\x82sum\x82"; TiXmlDocument latinDoc; latinDoc.Parse( latin, 0, TIXML_ENCODING_LEGACY ); text = latinDoc.FirstChildElement()->FirstChild()->ToText(); XmlTest( "Legacy encoding: Verify text element.", "r\x82sum\x82", text->Value() ); } } ////////////////////// // Copy and assignment ////////////////////// printf ("\n** Copy and Assignment **\n"); { TiXmlElement element( "foo" ); element.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); TiXmlElement elementCopy( element ); TiXmlElement elementAssign( "foo" ); elementAssign.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); elementAssign = element; XmlTest( "Copy/Assign: element copy #1.", "element", elementCopy.Value() ); XmlTest( "Copy/Assign: element copy #2.", "value", elementCopy.Attribute( "name" ) ); XmlTest( "Copy/Assign: element assign #1.", "element", elementAssign.Value() ); XmlTest( "Copy/Assign: element assign #2.", "value", elementAssign.Attribute( "name" ) ); XmlTest( "Copy/Assign: element assign #3.", true, ( 0 == elementAssign.Attribute( "foo" )) ); TiXmlComment comment; comment.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); TiXmlComment commentCopy( comment ); TiXmlComment commentAssign; commentAssign = commentCopy; XmlTest( "Copy/Assign: comment copy.", "comment", commentCopy.Value() ); XmlTest( "Copy/Assign: comment assign.", "comment", commentAssign.Value() ); TiXmlUnknown unknown; unknown.Parse( "<[unknown]>", 0, TIXML_ENCODING_UNKNOWN ); TiXmlUnknown unknownCopy( unknown ); TiXmlUnknown unknownAssign; unknownAssign.Parse( "incorrect", 0, TIXML_ENCODING_UNKNOWN ); unknownAssign = unknownCopy; XmlTest( "Copy/Assign: unknown copy.", "[unknown]", unknownCopy.Value() ); XmlTest( "Copy/Assign: unknown assign.", "[unknown]", unknownAssign.Value() ); TiXmlText text( "TextNode" ); TiXmlText textCopy( text ); TiXmlText textAssign( "incorrect" ); textAssign = text; XmlTest( "Copy/Assign: text copy.", "TextNode", textCopy.Value() ); XmlTest( "Copy/Assign: text assign.", "TextNode", textAssign.Value() ); TiXmlDeclaration dec; dec.Parse( "", 0, TIXML_ENCODING_UNKNOWN ); TiXmlDeclaration decCopy( dec ); TiXmlDeclaration decAssign; decAssign = dec; XmlTest( "Copy/Assign: declaration copy.", "UTF-8", decCopy.Encoding() ); XmlTest( "Copy/Assign: text assign.", "UTF-8", decAssign.Encoding() ); TiXmlDocument doc; elementCopy.InsertEndChild( textCopy ); doc.InsertEndChild( decAssign ); doc.InsertEndChild( elementCopy ); doc.InsertEndChild( unknownAssign ); TiXmlDocument docCopy( doc ); TiXmlDocument docAssign; docAssign = docCopy; #ifdef TIXML_USE_STL std::string original, copy, assign; original << doc; copy << docCopy; assign << docAssign; XmlTest( "Copy/Assign: document copy.", original.c_str(), copy.c_str(), true ); XmlTest( "Copy/Assign: document assign.", original.c_str(), assign.c_str(), true ); #endif } ////////////////////////////////////////////////////// #ifdef TIXML_USE_STL printf ("\n** Parsing, no Condense Whitespace **\n"); TiXmlBase::SetCondenseWhiteSpace( false ); { istringstream parse1( "This is \ntext" ); TiXmlElement text1( "text" ); parse1 >> text1; XmlTest ( "Condense white space OFF.", "This is \ntext", text1.FirstChild()->Value(), true ); } TiXmlBase::SetCondenseWhiteSpace( true ); #endif ////////////////////////////////////////////////////// // GetText(); { const char* str = "This is text"; TiXmlDocument doc; doc.Parse( str ); const TiXmlElement* element = doc.RootElement(); XmlTest( "GetText() normal use.", "This is text", element->GetText() ); str = "This is text"; doc.Clear(); doc.Parse( str ); element = doc.RootElement(); XmlTest( "GetText() contained element.", element->GetText() == 0, true ); str = "This is text"; doc.Clear(); TiXmlBase::SetCondenseWhiteSpace( false ); doc.Parse( str ); TiXmlBase::SetCondenseWhiteSpace( true ); element = doc.RootElement(); XmlTest( "GetText() partial.", "This is ", element->GetText() ); } ////////////////////////////////////////////////////// // CDATA { const char* str = "" " the rules!\n" "...since I make symbolic puns" "]]>" ""; TiXmlDocument doc; doc.Parse( str ); doc.Print(); XmlTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", true ); #ifdef TIXML_USE_STL //cout << doc << '\n'; doc.Clear(); istringstream parse0( str ); parse0 >> doc; //cout << doc << '\n'; XmlTest( "CDATA stream.", doc.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", true ); #endif TiXmlDocument doc1 = doc; //doc.Print(); XmlTest( "CDATA copy.", doc1.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", true ); } { // [ 1482728 ] Wrong wide char parsing char buf[256]; buf[255] = 0; for( int i=0; i<255; ++i ) { buf[i] = (char)((i>=32) ? i : 32); } TIXML_STRING str( ""; TiXmlDocument doc; doc.Parse( str.c_str() ); TiXmlPrinter printer; printer.SetStreamPrinting(); doc.Accept( &printer ); XmlTest( "CDATA with all bytes #1.", str.c_str(), printer.CStr(), true ); #ifdef TIXML_USE_STL doc.Clear(); istringstream iss( printer.Str() ); iss >> doc; std::string out; out << doc; XmlTest( "CDATA with all bytes #2.", out.c_str(), printer.CStr(), true ); #endif } { // [ 1480107 ] Bug-fix for STL-streaming of CDATA that contains tags // CDATA streaming had a couple of bugs, that this tests for. const char* str = "" "I am > the rules!\n" "...since I make symbolic puns" "]]>" ""; TiXmlDocument doc; doc.Parse( str ); doc.Print(); XmlTest( "CDATA parse. [ 1480107 ]", doc.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", true ); #ifdef TIXML_USE_STL doc.Clear(); istringstream parse0( str ); parse0 >> doc; XmlTest( "CDATA stream. [ 1480107 ]", doc.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", true ); #endif TiXmlDocument doc1 = doc; //doc.Print(); XmlTest( "CDATA copy. [ 1480107 ]", doc1.FirstChildElement()->FirstChild()->Value(), "I am > the rules!\n...since I make symbolic puns", true ); } ////////////////////////////////////////////////////// // Visit() ////////////////////////////////////////////////////// printf( "\n** Fuzzing... **\n" ); const int FUZZ_ITERATION = 300; // The only goal is not to crash on bad input. int len = (int) strlen( demoStart ); for( int i=0; i" "" " " ""; TiXmlDocument doc( "passages.xml" ); doc.Parse( passages ); TiXmlElement* psg = doc.RootElement()->FirstChildElement(); const char* context = psg->Attribute( "context" ); const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9."; XmlTest( "Entity transformation: read. ", expected, context, true ); FILE* textfile = fopen( "textfile.txt", "w" ); if ( textfile ) { psg->Print( textfile, 0 ); fclose( textfile ); } textfile = fopen( "textfile.txt", "r" ); assert( textfile ); if ( textfile ) { char buf[ 1024 ]; fgets( buf, 1024, textfile ); XmlTest( "Entity transformation: write. ", "", buf, true ); } fclose( textfile ); } { FILE* textfile = fopen( "test5.xml", "w" ); if ( textfile ) { fputs("", textfile); fclose(textfile); TiXmlDocument doc; doc.LoadFile( "test5.xml" ); XmlTest( "dot in element attributes and names", doc.Error(), 0); } } { FILE* textfile = fopen( "test6.xml", "w" ); if ( textfile ) { fputs("1.1 Start easy ignore fin thickness ", textfile ); fclose(textfile); TiXmlDocument doc; bool result = doc.LoadFile( "test6.xml" ); XmlTest( "Entity with one digit.", result, true ); TiXmlText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText(); XmlTest( "Entity with one digit.", text->Value(), "1.1 Start easy ignore fin thickness\n" ); } } { // DOCTYPE not preserved (950171) // const char* doctype = "" "" "" "" ""; TiXmlDocument doc; doc.Parse( doctype ); doc.SaveFile( "test7.xml" ); doc.Clear(); doc.LoadFile( "test7.xml" ); TiXmlHandle docH( &doc ); TiXmlUnknown* unknown = docH.Child( 1 ).Unknown(); XmlTest( "Correct value of unknown.", "!DOCTYPE PLAY SYSTEM 'play.dtd'", unknown->Value() ); #ifdef TIXML_USE_STL TiXmlNode* node = docH.Child( 2 ).Node(); std::string str; str << (*node); XmlTest( "Correct streaming of unknown.", "", str.c_str() ); #endif } { // [ 791411 ] Formatting bug // Comments do not stream out correctly. const char* doctype = ""; TiXmlDocument doc; doc.Parse( doctype ); TiXmlHandle docH( &doc ); TiXmlComment* comment = docH.Child( 0 ).Node()->ToComment(); XmlTest( "Comment formatting.", " Somewhat ", comment->Value() ); #ifdef TIXML_USE_STL std::string str; str << (*comment); XmlTest( "Comment streaming.", "", str.c_str() ); #endif } { // [ 870502 ] White space issues TiXmlDocument doc; TiXmlText* text; TiXmlHandle docH( &doc ); const char* doctype0 = " This has leading and trailing space "; const char* doctype1 = "This has internal space"; const char* doctype2 = " This has leading, trailing, and internal space "; TiXmlBase::SetCondenseWhiteSpace( false ); doc.Clear(); doc.Parse( doctype0 ); text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); XmlTest( "White space kept.", " This has leading and trailing space ", text->Value() ); doc.Clear(); doc.Parse( doctype1 ); text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); XmlTest( "White space kept.", "This has internal space", text->Value() ); doc.Clear(); doc.Parse( doctype2 ); text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); XmlTest( "White space kept.", " This has leading, trailing, and internal space ", text->Value() ); TiXmlBase::SetCondenseWhiteSpace( true ); doc.Clear(); doc.Parse( doctype0 ); text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); XmlTest( "White space condensed.", "This has leading and trailing space", text->Value() ); doc.Clear(); doc.Parse( doctype1 ); text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); XmlTest( "White space condensed.", "This has internal space", text->Value() ); doc.Clear(); doc.Parse( doctype2 ); text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); XmlTest( "White space condensed.", "This has leading, trailing, and internal space", text->Value() ); } { // Double attributes const char* doctype = ""; TiXmlDocument doc; doc.Parse( doctype ); XmlTest( "Parsing repeated attributes.", true, doc.Error() ); // is an error to tinyxml (didn't use to be, but caused issues) //XmlTest( "Parsing repeated attributes.", "blue", doc.FirstChildElement( "element" )->Attribute( "attr" ) ); } { // Embedded null in stream. const char* doctype = ""; TiXmlDocument doc; doc.Parse( doctype ); XmlTest( "Embedded null throws error.", true, doc.Error() ); #ifdef TIXML_USE_STL istringstream strm( doctype ); doc.Clear(); doc.ClearError(); strm >> doc; XmlTest( "Embedded null throws error.", true, doc.Error() ); #endif } { // Legacy mode test. (This test may only pass on a western system) const char* str = "" "<ä>" "CöntäntßäöüÄÖÜ" ""; TiXmlDocument doc; doc.Parse( str ); TiXmlHandle docHandle( &doc ); TiXmlHandle aHandle = docHandle.FirstChildElement( "ä" ); TiXmlHandle tHandle = aHandle.Child( 0 ); assert( aHandle.Element() ); assert( tHandle.Text() ); XmlTest( "ISO-8859-1 Parsing.", "CöntäntßäöüÄÖÜ", tHandle.Text()->Value() ); } { // Empty documents should return TIXML_ERROR_PARSING_EMPTY, bug 1070717 const char* str = " "; TiXmlDocument doc; doc.Parse( str ); XmlTest( "Empty document error TIXML_ERROR_DOCUMENT_EMPTY", TiXmlBase::TIXML_ERROR_DOCUMENT_EMPTY, doc.ErrorId() ); } #ifndef TIXML_USE_STL { // String equality. [ 1006409 ] string operator==/!= no worky in all cases TiXmlString temp; XmlTest( "Empty tinyxml string compare equal", ( temp == "" ), true ); TiXmlString foo; TiXmlString bar( "" ); XmlTest( "Empty tinyxml string compare equal", ( foo == bar ), true ); } #endif { // Bug [ 1195696 ] from marlonism TiXmlBase::SetCondenseWhiteSpace(false); TiXmlDocument xml; xml.Parse("This hangs"); XmlTest( "Test safe error return.", xml.Error(), false ); } { // Bug [ 1243992 ] - another infinite loop TiXmlDocument doc; doc.SetCondenseWhiteSpace(false); doc.Parse("

test

"); } { // Low entities TiXmlDocument xml; xml.Parse( "" ); const char result[] = { 0x0e, 0 }; XmlTest( "Low entities.", xml.FirstChildElement()->GetText(), result ); xml.Print(); } { // Bug [ 1451649 ] Attribute values with trailing quotes not handled correctly TiXmlDocument xml; xml.Parse( "" ); XmlTest( "Throw error with bad end quotes.", xml.Error(), true ); } #ifdef TIXML_USE_STL { // Bug [ 1449463 ] Consider generic query TiXmlDocument xml; xml.Parse( "" ); TiXmlElement* ele = xml.FirstChildElement(); double d; int i; float f; bool b; std::string str; XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &d ), TIXML_SUCCESS ); XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &i ), TIXML_SUCCESS ); XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &f ), TIXML_SUCCESS ); XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "bar", &b ), TIXML_WRONG_TYPE ); XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "nobar", &b ), TIXML_NO_ATTRIBUTE ); XmlTest( "QueryValueAttribute", ele->QueryValueAttribute( "barStr", &str ), TIXML_SUCCESS ); XmlTest( "QueryValueAttribute", (d==3.0), true ); XmlTest( "QueryValueAttribute", (i==3), true ); XmlTest( "QueryValueAttribute", (f==3.0f), true ); XmlTest( "QueryValueAttribute", (str==std::string( "a string" )), true ); } #endif #ifdef TIXML_USE_STL { // [ 1505267 ] redundant malloc in TiXmlElement::Attribute TiXmlDocument xml; xml.Parse( "" ); TiXmlElement* ele = xml.FirstChildElement(); double d; int i; std::string bar = "bar"; const std::string* atrrib = ele->Attribute( bar ); ele->Attribute( bar, &d ); ele->Attribute( bar, &i ); XmlTest( "Attribute", atrrib->empty(), false ); XmlTest( "Attribute", (d==3.0), true ); XmlTest( "Attribute", (i==3), true ); } #endif { // [ 1356059 ] Allow TiXMLDocument to only be at the top level TiXmlDocument xml, xml2; xml.InsertEndChild( xml2 ); XmlTest( "Document only at top level.", xml.Error(), true ); XmlTest( "Document only at top level.", xml.ErrorId(), TiXmlBase::TIXML_ERROR_DOCUMENT_TOP_ONLY ); } { // [ 1663758 ] Failure to report error on bad XML TiXmlDocument xml; xml.Parse(""); XmlTest("Missing end tag at end of input", xml.Error(), true); xml.Parse(" "); XmlTest("Missing end tag with trailing whitespace", xml.Error(), true); } { // [ 1635701 ] fail to parse files with a tag separated into two lines // I'm not sure this is a bug. Marked 'pending' for feedback. TiXmlDocument xml; xml.Parse( "<p>text</p\n><title>" ); //xml.Print(); //XmlTest( "Tag split by newline", xml.Error(), false ); } #ifdef TIXML_USE_STL { // [ 1475201 ] TinyXML parses entities in comments TiXmlDocument xml; istringstream parse1( "<!-- declarations for <head> & <body> -->" "<!-- far & away -->" ); parse1 >> xml; TiXmlNode* e0 = xml.FirstChild(); TiXmlNode* e1 = e0->NextSibling(); TiXmlComment* c0 = e0->ToComment(); TiXmlComment* c1 = e1->ToComment(); XmlTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true ); XmlTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); } #endif { // [ 1475201 ] TinyXML parses entities in comments TiXmlDocument xml; xml.Parse("<!-- declarations for <head> & <body> -->" "<!-- far & away -->" ); TiXmlNode* e0 = xml.FirstChild(); TiXmlNode* e1 = e0->NextSibling(); TiXmlComment* c0 = e0->ToComment(); TiXmlComment* c1 = e1->ToComment(); XmlTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true ); XmlTest( "Comments ignore entities.", " far & away ", c1->Value(), true ); } { TiXmlDocument xml; xml.Parse( "<Parent>" "<child1 att=''/>" "<!-- With this comment, child2 will not be parsed! -->" "<child2 att=''/>" "</Parent>" ); int count = 0; TiXmlNode* ele = 0; while ( (ele = xml.FirstChildElement( "Parent" )->IterateChildren( ele ) ) != 0 ) { ++count; } XmlTest( "Comments iterate correctly.", 3, count ); } { // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well. unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl"; buf[60] = 239; buf[61] = 0; TiXmlDocument doc; doc.Parse( (const char*)buf); } { // bug 1827248 Error while parsing a little bit malformed file // Actually not malformed - should work. TiXmlDocument xml; xml.Parse( "<attributelist> </attributelist >" ); XmlTest( "Handle end tag whitespace", false, xml.Error() ); } { // This one must not result in an infinite loop TiXmlDocument xml; xml.Parse( "<infinite>loop" ); XmlTest( "Infinite loop test.", true, true ); } { // 1709904 - can not repro the crash { TiXmlDocument xml; xml.Parse( "<tag>/</tag>" ); XmlTest( "Odd XML parsing.", xml.FirstChild()->Value(), "tag" ); } /* Could not repro. { TiXmlDocument xml; xml.LoadFile( "EQUI_Inventory.xml" ); //XmlTest( "Odd XML parsing.", xml.FirstChildElement()->Value(), "XML" ); TiXmlPrinter printer; xml.Accept( &printer ); fprintf( stdout, "%s", printer.CStr() ); }*/ } /* 1417717 experiment { TiXmlDocument xml; xml.Parse("<text>Dan & Tracie</text>"); xml.Print(stdout); } { TiXmlDocument xml; xml.Parse("<text>Dan &foo; Tracie</text>"); xml.Print(stdout); } */ #if defined( WIN32 ) && defined( TUNE ) _CrtMemCheckpoint( &endMemState ); //_CrtMemDumpStatistics( &endMemState ); _CrtMemState diffMemState; _CrtMemDifference( &diffMemState, &startMemState, &endMemState ); _CrtMemDumpStatistics( &diffMemState ); #endif printf ("\nPass %d, Fail %d\n", gPass, gFail); return gFail; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/�������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714755�013712� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/ARPAPredictor.cpp��������������������������������������������������0000644�0001750�0001750�00000030444�11743227551�016730� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "ARPAPredictor.h" #include <sstream> #include <algorithm> #include <cmath> #define OOV "<UNK>" ARPAPredictor::ARPAPredictor(Configuration* config, ContextTracker* ct, const char* name) : Predictor(config, ct, name, "ARPAPredictor, a predictor relying on an ARPA language model", "ARPAPredictor, long description." ), dispatcher (this) { LOGGER = PREDICTORS + name + ".LOGGER"; ARPAFILENAME = PREDICTORS + name + ".ARPAFILENAME"; VOCABFILENAME = PREDICTORS + name + ".VOCABFILENAME"; TIMEOUT = PREDICTORS + name + ".TIMEOUT"; // build notification dispatch map dispatcher.map (config->find (LOGGER), & ARPAPredictor::set_logger); dispatcher.map (config->find (VOCABFILENAME), & ARPAPredictor::set_vocab_filename); dispatcher.map (config->find (ARPAFILENAME), & ARPAPredictor::set_arpa_filename); dispatcher.map (config->find (TIMEOUT), & ARPAPredictor::set_timeout); loadVocabulary(); createARPATable(); } void ARPAPredictor::set_vocab_filename (const std::string& value) { logger << INFO << "VOCABFILENAME: " << value << endl; vocabFilename = value; } void ARPAPredictor::set_arpa_filename (const std::string& value) { logger << INFO << "ARPAFILENAME: " << value << endl; arpaFilename = value; } void ARPAPredictor::set_timeout (const std::string& value) { logger << INFO << "TIMEOUT: " << value << endl; timeout = atoi(value.c_str()); } void ARPAPredictor::loadVocabulary() { std::ifstream vocabFile; vocabFile.open(vocabFilename.c_str()); if(!vocabFile) logger << ERROR << "Error opening vocabulary file: " << vocabFilename << endl; assert(vocabFile); std::string row; int code = 0; while(std::getline(vocabFile,row)) { if(row[0]=='#') continue; vocabCode[row]=code; vocabDecode[code]=row; logger << DEBUG << "["<<row<<"] -> "<< code<<endl; code++; } logger << DEBUG << "Loaded "<<code<<" words from vocabulary" <<endl; } void ARPAPredictor::createARPATable() { std::ifstream arpaFile; arpaFile.open(arpaFilename.c_str()); if(!arpaFile) logger << ERROR << "Error opening ARPA model file: " << arpaFilename << endl; assert(arpaFile); std::string row; int currOrder = 0; unigramCount = 0; bigramCount = 0; trigramCount = 0; int lineNum =0; bool startData = false; while(std::getline(arpaFile,row)) { lineNum++; if(row.empty()) continue; if(row == "\\end\\") break; if(row == "\\data\\") { startData = true; continue; } if( startData == true && currOrder == 0) { if( row.find("ngram 1")==0 ) { unigramTot = atoi(row.substr(8).c_str()); logger << DEBUG << "tot unigram = "<<unigramTot<<endl; continue; } if( row.find("ngram 2")==0) { bigramTot = atoi(row.substr(8).c_str()); logger << DEBUG << "tot bigram = "<<bigramTot<<endl; continue; } if( row.find("ngram 3")==0) { trigramTot = atoi(row.substr(8).c_str()); logger << DEBUG << "tot trigram = "<<trigramTot<<endl; continue; } } if( row == "\\1-grams:" && startData) { currOrder = 1; std::cerr << std::endl << "ARPA loading unigrams:" << std::endl; unigramProg = new ProgressBar<char>(std::cerr); continue; } if( row == "\\2-grams:" && startData) { currOrder = 2; std::cerr << std::endl << std::endl << "ARPA loading bigrams:" << std::endl; bigramProg = new ProgressBar<char>(std::cerr); continue; } if( row == "\\3-grams:" && startData) { currOrder = 3; std::cerr << std::endl << std::endl << "ARPA loading trigrams:" << std::endl; trigramProg = new ProgressBar<char>(std::cerr); continue; } if(currOrder == 0) continue; switch(currOrder) { case 1: addUnigram(row); break; case 2: addBigram(row); break; case 3: addTrigram(row); break; } } std::cerr << std::endl << std::endl; logger << DEBUG << "loaded unigrams: "<< unigramCount << endl; logger << DEBUG << "loaded bigrams: " << bigramCount << endl; logger << DEBUG << "loaded trigrams: "<< trigramCount << endl; } void ARPAPredictor::addUnigram(std::string row) { std::stringstream str(row); float logProb = 0; float logAlfa = 0; std::string wd1Str; str >> logProb; str >> wd1Str; str >> logAlfa; if(wd1Str != OOV ) { int wd1 = vocabCode[wd1Str]; unigramMap[wd1]= ARPAData(logProb,logAlfa); logger << DEBUG << "adding unigram ["<<wd1Str<< "] -> "<<logProb<<" "<<logAlfa<<endl; } unigramCount++; unigramProg->update((float)unigramCount/(float)unigramTot); } void ARPAPredictor::addBigram(std::string row) { std::stringstream str(row); float logProb = 0; float logAlfa = 0; std::string wd1Str; std::string wd2Str; str >> logProb; str >> wd1Str; str >> wd2Str; str >> logAlfa; if(wd1Str != OOV && wd2Str != OOV) { int wd1 = vocabCode[wd1Str]; int wd2 = vocabCode[wd2Str]; bigramMap[BigramKey(wd1,wd2)]=ARPAData(logProb,logAlfa); logger << DEBUG << "adding bigram ["<<wd1Str<< "] ["<<wd2Str<< "] -> "<<logProb<<" "<<logAlfa<<endl; } bigramCount++; bigramProg->update((float)bigramCount/(float)bigramTot); } void ARPAPredictor::addTrigram(std::string row) { std::stringstream str(row); float logProb = 0; std::string wd1Str; std::string wd2Str; std::string wd3Str; str >> logProb; str >> wd1Str; str >> wd2Str; str >> wd3Str; if(wd1Str != OOV && wd2Str != OOV && wd3Str != OOV) { int wd1 = vocabCode[wd1Str]; int wd2 = vocabCode[wd2Str]; int wd3 = vocabCode[wd3Str]; trigramMap[TrigramKey(wd1,wd2,wd3)]=logProb; logger << DEBUG << "adding trigram ["<<wd1Str<< "] ["<<wd2Str<< "] ["<<wd3Str<< "] -> "<<logProb <<endl; } trigramCount++; trigramProg->update((float)trigramCount/(float)trigramTot); } ARPAPredictor::~ARPAPredictor() { delete unigramProg; delete bigramProg; delete trigramProg; } bool ARPAPredictor::matchesPrefixAndFilter(std::string word, std::string prefix, const char** filter ) const { if(filter == 0) return word.find(prefix)==0; for(int j = 0; filter[j] != 0; j++) { std::string pattern = prefix+std::string(filter[j]); if(word.find(pattern)==0) return true; } return false; } Prediction ARPAPredictor::predict(const size_t max_partial_prediction_size, const char** filter) const { logger << DEBUG << "predict()" << endl; Prediction prediction; int cardinality = 3; std::vector<std::string> tokens(cardinality); std::string prefix = Utility::strtolower(contextTracker->getToken(0)); std::string wd2Str = Utility::strtolower(contextTracker->getToken(1)); std::string wd1Str = Utility::strtolower(contextTracker->getToken(2)); std::multimap< float, std::string, cmp > result; logger << DEBUG << "["<<wd1Str<<"]"<<" ["<<wd2Str<<"] "<<"["<<prefix<<"]"<<endl; //search for the past tokens in the vocabulary std::map<std::string,int>::const_iterator wd1It,wd2It; wd1It = vocabCode.find(wd1Str); wd2It = vocabCode.find(wd2Str); /** * note if we have not tokens to compute 3-gram probabilities we compute 2-gram or 1-gram probabilities. * the following code might be repetitive but more efficient than having the main loop outside. */ //we have two valid past tokens available if(wd1It!=vocabCode.end() && wd2It!=vocabCode.end()) { //iterate over all vocab words for(std::map<int,std::string>::const_iterator it = vocabDecode.begin(); it!=vocabDecode.end(); it++) { //if wd3 matches prefix and filter -> compute its backoff probability and add to the result set if(matchesPrefixAndFilter(it->second,prefix,filter)) { std::pair<const float,std::string> p (computeTrigramBackoff(wd1It->second,wd2It->second,it->first), it->second); result.insert(p); } } } //we have one valid past token available else if(wd2It!=vocabCode.end()) { //iterate over all vocab words for(std::map<int,std::string>::const_iterator it = vocabDecode.begin(); it!=vocabDecode.end(); it++) { //if wd3 matches prefix and filter -> compute its backoff probability and add to the result set if(matchesPrefixAndFilter(it->second,prefix,filter)) { std::pair<const float,std::string> p(computeBigramBackoff(wd2It->second,it->first), it->second); result.insert(p); } } } //we have no valid past token available else { //iterate over all vocab words for(std::map<int,std::string>::const_iterator it = vocabDecode.begin(); it!=vocabDecode.end(); it++) { //if wd3 matches prefix and filter -> compute its backoff probability and add to the result set if(matchesPrefixAndFilter(it->second,prefix,filter)) { std::pair<const float,std::string> p (unigramMap.find(it->first)->second.logProb, it->second); result.insert(p); } } } size_t numSuggestions = 0; for(std::multimap< float, std::string, cmp >::const_iterator it = result.begin(); it != result.end() && numSuggestions < max_partial_prediction_size; it++) { prediction.addSuggestion(Suggestion(it->second,exp(it->first))); numSuggestions++; } return prediction; } /** * Computes P(wd3 | wd1 wd2) */ float ARPAPredictor::computeTrigramBackoff(int wd1,int wd2,int wd3) const { logger << DEBUG << "computing P( ["<<vocabDecode.find(wd3)->second<< "] | ["<<vocabDecode.find(wd1)->second<<"] ["<<vocabDecode.find(wd2)->second<<"] )"<<endl; //trigram exist std::map<TrigramKey,float>::const_iterator trigramIt =trigramMap.find(TrigramKey(wd1,wd2,wd3)); if(trigramIt!=trigramMap.end()) { logger << DEBUG << "trigram ["<<vocabDecode.find(wd1)->second<< "] ["<<vocabDecode.find(wd2)->second<< "] ["<<vocabDecode.find(wd3)->second<< "] exists" <<endl; logger << DEBUG << "returning "<<trigramIt->second <<endl; return trigramIt->second; } //bigram exist std::map<BigramKey,ARPAData>::const_iterator bigramIt =bigramMap.find(BigramKey(wd1,wd2)); if(bigramIt!=bigramMap.end()) { logger << DEBUG << "bigram ["<<vocabDecode.find(wd1)->second<< "] ["<<vocabDecode.find(wd2)->second<< "] exists" <<endl; float prob = bigramIt->second.logAlfa + computeBigramBackoff(wd2,wd3); logger << DEBUG << "returning "<<prob<<endl; return prob; } //else logger << DEBUG << "no bigram w1,w2 exist" <<endl; float prob = computeBigramBackoff(wd2,wd3); logger << DEBUG << "returning "<<prob<<endl; return prob; } /** * Computes P( wd2 | wd1 ) */ float ARPAPredictor::computeBigramBackoff(int wd1, int wd2) const { //bigram exist std::map<BigramKey,ARPAData>::const_iterator bigramIt =bigramMap.find(BigramKey(wd1,wd2)); if(bigramIt!=bigramMap.end()) return bigramIt->second.logProb; //else return unigramMap.find(wd1)->second.logAlfa +unigramMap.find(wd2)->second.logProb; } void ARPAPredictor::learn(const std::vector<std::string>& change) { logger << DEBUG << "learn() method called" << endl; logger << DEBUG << "learn() method exited" << endl; } void ARPAPredictor::update (const Observable* var) { logger << DEBUG << "About to invoke dispatcher: " << var->get_name () << " - " << var->get_value() << endl; dispatcher.dispatch (var); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dummyPredictor.cpp�������������������������������������������������0000644�0001750�0001750�00000006054�11743227551�017340� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "dummyPredictor.h" DummyPredictor::DummyPredictor(Configuration* config, ContextTracker* ct, const char* name) : Predictor(config, ct, name, "DummyPredictor, a fake predictor", "DummyPredictor is a fake predictor.\n" "It does not perform any actual computation nor implement any prediction mechanism.\n" "It always returns the same sample prediction.\n") {} DummyPredictor::~DummyPredictor() {} Prediction DummyPredictor::predict(const size_t max_partial_predictions_size, const char** filter) const { // A real predictor would query its resources to retrieve the most // probable completion of the prefix based on the current history, // but this is just a dummy predictor that returns random suggestions. // Prediction result; result.addSuggestion (Suggestion("foo1", 0.99)); result.addSuggestion (Suggestion("foo2", 0.98)); result.addSuggestion (Suggestion("foo3", 0.97)); result.addSuggestion (Suggestion("foo4", 0.96)); result.addSuggestion (Suggestion("foo5", 0.95)); result.addSuggestion (Suggestion("foo6", 0.94)); result.addSuggestion (Suggestion("bar1", 0.89)); result.addSuggestion (Suggestion("bar2", 0.88)); result.addSuggestion (Suggestion("bar3", 0.87)); result.addSuggestion (Suggestion("bar4", 0.86)); result.addSuggestion (Suggestion("bar5", 0.85)); result.addSuggestion (Suggestion("bar6", 0.84)); result.addSuggestion (Suggestion("foobar1", 0.79)); result.addSuggestion (Suggestion("foobar2", 0.78)); result.addSuggestion (Suggestion("foobar3", 0.77)); result.addSuggestion (Suggestion("foobar4", 0.76)); result.addSuggestion (Suggestion("foobar5", 0.75)); result.addSuggestion (Suggestion("foobar6", 0.74)); return result; } void DummyPredictor::learn(const std::vector<std::string>& change) { std::cout << "DummyPredictor::learn() method called" << std::endl; std::cout << "DummyPredictor::learn() method exited" << std::endl; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dummyPredictor.h���������������������������������������������������0000644�0001750�0001750�00000003140�11743227551�016776� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_DUMMYPREDICTOR #define PRESAGE_DUMMYPREDICTOR #include "predictor.h" /** Dummy predictor is provided here to show how to implement real predictors. * */ class DummyPredictor : public Predictor { public: DummyPredictor(Configuration*, ContextTracker*, const char*); ~DummyPredictor(); virtual Prediction predict(const size_t size, const char** filter) const; virtual void learn(const std::vector<std::string>& change); private: }; #endif // PRESAGE_DUMMYPREDICTOR ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/smoothedNgramPredictor.h�������������������������������������������0000644�0001750�0001750�00000005537�11763437013�020464� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SMOOTHEDNGRAMPREDICTOR #define PRESAGE_SMOOTHEDNGRAMPREDICTOR #include "predictor.h" #include "../core/logger.h" #include "../core/dispatcher.h" #include "dbconnector/sqliteDatabaseConnector.h" #include <assert.h> #if defined(HAVE_SQLITE3_H) # include <sqlite3.h> #elif defined(HAVE_SQLITE_H) # include <sqlite.h> #else # error "SQLite is required. Please install SQLite." #endif /** Smoothed n-gram statistical predictor. * */ class SmoothedNgramPredictor : public Predictor, public Observer { public: SmoothedNgramPredictor(Configuration*, ContextTracker*, const char*); ~SmoothedNgramPredictor(); virtual Prediction predict(const size_t size, const char** filter) const; virtual void learn(const std::vector<std::string>& change); virtual void update (const Observable* variable); private: std::string LOGGER; std::string DBFILENAME; std::string DELTAS; std::string LEARN; std::string DATABASE_LOGGER; unsigned int count(const std::vector<std::string>& tokens, int offset, int ngram_size) const; void check_learn_consistency(const Ngram& name) const; void set_dbfilename (const std::string& filename); void set_deltas (const std::string& deltas); void set_database_logger_level (const std::string& level); void set_learn (const std::string& learn_mode); void init_database_connector_if_ready (); DatabaseConnector* db; std::string dbfilename; std::string dbloglevel; std::vector<double> deltas; size_t cardinality; // cardinality == what is the n in n-gram? bool wanna_learn; bool learn_mode_set; Dispatcher<SmoothedNgramPredictor> dispatcher; }; #endif // PRESAGE_SMOOTHEDNGRAMPREDICTOR �����������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dejavuPredictor.h��������������������������������������������������0000644�0001750�0001750�00000005520�11743227551�017125� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_DEJAVUPREDICTOR #define PRESAGE_DEJAVUPREDICTOR #include "predictor.h" #include "../core/dispatcher.h" #include <list> #include <string> #include <fstream> /** Dejavu predictor learns and reproduces previously seen text tokens, once its memory is triggered by a known token sequence. * * Dejavu predictor is able to learn and then later reproduce previously * seen text sequences. The goal of dejavu predictor is to write a simple * predictor that demonstrates how learning can be implemented in the * presage system and exposes what functionality is required for * learning predictors to work within the presage framework. * */ class DejavuPredictor : public Predictor, public Observer { public: DejavuPredictor(Configuration*, ContextTracker*, const char*); ~DejavuPredictor(); virtual Prediction predict(const size_t size, const char** filter) const; virtual void learn(const std::vector<std::string>& change); virtual void update (const Observable* variable); private: typedef void (DejavuPredictor::* mbr_func_ptr_t) (const std::string& value); std::map<std::string, mbr_func_ptr_t> dispatch_map; bool init_memory_trigger(std::list<std::string>&) const; bool match(const std::list<std::string>&, const std::list<std::string>&) const; bool init_rolling_window(std::list<std::string>&, std::ifstream&) const; void update_rolling_window(std::list<std::string>&, const std::string&) const; void set_memory (const std::string& filename); void set_trigger (const std::string& number); std::string LOGGER; std::string MEMORY; std::string TRIGGER; std::string memory; int trigger; Dispatcher<DejavuPredictor> dispatcher; }; #endif // SOOTH_DEJAVUPREDICTOR ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/abbreviationExpansionPredictor.cpp���������������������������������0000644�0001750�0001750�00000011200�11763437013�022522� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "abbreviationExpansionPredictor.h" #include <fstream> AbbreviationExpansionPredictor::AbbreviationExpansionPredictor(Configuration* config, ContextTracker* ct, const char* name) : Predictor(config, ct, name, "AbbreviationExpansionPredictor, maps abbreviations to the corresponding fully expanded token.", "AbbreviationExpansionPredictor maps abbreviations to the corresponding fully expanded token (i.e. word or phrase).\n\nThe mapping between abbreviations and expansions is stored in the file specified by the predictor configuration section.\n\nThe format for the abbreviation-expansion database is a simple tab separated text file format, with each abbreviation-expansion pair per line." ), dispatcher (this) { LOGGER = PREDICTORS + name + ".LOGGER"; ABBREVIATIONS = PREDICTORS + name + ".ABBREVIATIONS"; // build notification dispatch map dispatcher.map (config->find (LOGGER), & AbbreviationExpansionPredictor::set_logger); dispatcher.map (config->find (ABBREVIATIONS), & AbbreviationExpansionPredictor::set_abbreviations); } AbbreviationExpansionPredictor::~AbbreviationExpansionPredictor() { // complete } void AbbreviationExpansionPredictor::set_abbreviations (const std::string& filename) { abbreviations = filename; logger << INFO << "ABBREVIATIONS: " << abbreviations << endl; cacheAbbreviationsExpansions(); } Prediction AbbreviationExpansionPredictor::predict(const size_t max_partial_predictions_size, const char** filter) const { Prediction result; std::string prefix = contextTracker->getPrefix(); std::map< std::string, std::string >::const_iterator it = cache.find(prefix); if (it != cache.end()) { // prepend expansion with enough backspaces to erase // abbreviation std::string expansion(prefix.size(), '\b'); // concatenate actual expansion expansion += it->second; result.addSuggestion(Suggestion(expansion, 1.0)); } else { logger << NOTICE << "Could not find expansion for abbreviation: " << prefix << endl; } return result; } void AbbreviationExpansionPredictor::learn (const std::vector<std::string>& change) { // intentionally empty } void AbbreviationExpansionPredictor::cacheAbbreviationsExpansions() { cache.clear(); std::ifstream abbr_file(abbreviations.c_str()); if (!abbr_file) { logger << ERROR << "Could not open abbreviations file: " << abbreviations << endl; // TODO: throw exception here // } else { logger << INFO << "Caching abbreviations/expansions from file: " << abbreviations << endl; std::string buffer; std::string abbreviation; std::string expansion; std::string::size_type tab_pos; while (getline(abbr_file, buffer)) { tab_pos = buffer.find_first_of('\t'); if (tab_pos == std::string::npos) { logger << ERROR << "Error reading abbreviations/expansions from file: " << abbreviations << endl; } else { abbreviation = buffer.substr(0, tab_pos); expansion = buffer.substr(tab_pos + 1, std::string::npos); logger << INFO << "Caching abbreviation: " << abbreviation << " - expansion: " << expansion << endl; cache[abbreviation] = expansion; } } abbr_file.close(); } } void AbbreviationExpansionPredictor::update (const Observable* var) { logger << DEBUG << "About to invoke dispatcher: " << var->get_name () << " - " << var->get_value() << endl; dispatcher.dispatch (var); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/Makefile.am��������������������������������������������������������0000644�0001750�0001750�00000004212�11737142176�015655� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = dbconnector PREDICTORS = \ libpredictor.la \ libDummyPredictor.la \ libDictionaryPredictor.la \ libAbbreviationExpansionPredictor.la \ libRecencyPredictor.la \ libDejavuPredictor.la \ libARPAPredictor.la if USE_SQLITE PREDICTORS += \ libSmoothedNgramPredictor.la DBCONNECTOR = \ dbconnector/libdbconnector.la endif noinst_LTLIBRARIES = \ libpredictors.la \ $(PREDICTORS) libpredictors_la_SOURCES = libpredictors_la_LIBADD = $(PREDICTORS) $(DBCONNECTOR) libpredictor_la_SOURCES = predictor.cpp predictor.h libSmoothedNgramPredictor_la_SOURCES = smoothedNgramPredictor.cpp \ smoothedNgramPredictor.h libAbbreviationExpansionPredictor_la_SOURCES = abbreviationExpansionPredictor.h \ abbreviationExpansionPredictor.cpp libDictionaryPredictor_la_SOURCES = dictionaryPredictor.cpp \ dictionaryPredictor.h libDummyPredictor_la_SOURCES = dummyPredictor.cpp \ dummyPredictor.h libRecencyPredictor_la_SOURCES = recencyPredictor.cpp \ recencyPredictor.h libRecencyPredictor_la_LDFLAGS = -lm libDejavuPredictor_la_SOURCES = dejavuPredictor.cpp \ dejavuPredictor.h libARPAPredictor_la_SOURCES = ARPAPredictor.cpp \ ARPAPredictor.h ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/ARPAPredictor.h����������������������������������������������������0000644�0001750�0001750�00000010365�11743227551�016375� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_ARPAPREDICTOR #define PRESAGE_ARPAPREDICTOR #include "predictor.h" #include "../core/logger.h" #include "../core/progress.h" #include "../core/dispatcher.h" #include <assert.h> #include <fstream> #include <iomanip> class cmp { public: bool operator() (const float& f1, const float& f2 ) const { return f2 < f1; } }; class ARPAData { public: ARPAData() {}; ARPAData(float lp,float la) : logProb(lp), logAlfa(la) {}; float logProb; float logAlfa; }; class TrigramKey { public: TrigramKey(int wd1, int wd2, int wd3) : key1(wd1), key2(wd2), key3(wd3) {}; bool operator<(const TrigramKey &right) const { if(key1 < right.key1) return true; if(key1 == right.key1) if(key2 < right.key2 ) return true; if(key1 == right.key1 && key2 == right.key2) if(key3 < right.key3) return true; return false; } bool operator==(const TrigramKey &right) const { return (key1 == right.key1 && key2 == right.key2 && key3 == right.key3 ); } int key1; int key2; int key3; }; class BigramKey { public: BigramKey(int wd1, int wd2) : key1(wd1), key2(wd2) {}; bool operator<(const BigramKey &right) const { if(key1 < right.key1) return true; if(key1 == right.key1) if(key2 < right.key2 ) return true; return false; } bool operator==(const TrigramKey &right) const { return (key1 == right.key1 && key2 == right.key2); } int key1; int key2; }; /** Smoothed n-gram statistical predictor. * */ class ARPAPredictor : public Predictor, public Observer { public: ARPAPredictor(Configuration*, ContextTracker*, const char*); ~ARPAPredictor(); virtual Prediction predict(const size_t size, const char** filter) const; virtual void learn(const std::vector<std::string>& change); virtual void update (const Observable* variable); void set_vocab_filename (const std::string& value); void set_arpa_filename (const std::string& value); void set_timeout (const std::string& value); private: std::string LOGGER; std::string ARPAFILENAME; std::string VOCABFILENAME; std::string TIMEOUT; std::string arpaFilename; std::string vocabFilename; int timeout; std::map<std::string,int> vocabCode; std::map<int,std::string> vocabDecode; std::map<int,ARPAData> unigramMap; std::map<BigramKey,ARPAData>bigramMap; std::map<TrigramKey,float>trigramMap; void loadVocabulary(); void createARPATable(); bool matchesPrefixAndFilter(std::string , std::string , const char** ) const; void addUnigram(std::string); void addBigram(std::string); void addTrigram(std::string); inline float computeTrigramBackoff(int,int,int) const; inline float computeBigramBackoff(int,int) const; int unigramCount; int bigramCount; int trigramCount; int unigramTot; int bigramTot; int trigramTot; ProgressBar<char>* unigramProg; ProgressBar<char>* bigramProg; ProgressBar<char>* trigramProg; Dispatcher<ARPAPredictor> dispatcher; }; #endif // PRESAGE_ARPAPREDICTOR ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/smoothedNgramPredictor.cpp�����������������������������������������0000644�0001750�0001750�00000036041�11763437013�021011� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "smoothedNgramPredictor.h" #include <sstream> #include <algorithm> SmoothedNgramPredictor::SmoothedNgramPredictor(Configuration* config, ContextTracker* ct, const char* name) : Predictor(config, ct, name, "SmoothedNgramPredictor, a linear interpolating n-gram predictor", "SmoothedNgramPredictor, long description." ), db (0), cardinality (0), learn_mode_set (false), dispatcher (this) { LOGGER = PREDICTORS + name + ".LOGGER"; DBFILENAME = PREDICTORS + name + ".DBFILENAME"; DELTAS = PREDICTORS + name + ".DELTAS"; LEARN = PREDICTORS + name + ".LEARN"; DATABASE_LOGGER = PREDICTORS + name + ".DatabaseConnector.LOGGER"; // build notification dispatch map dispatcher.map (config->find (LOGGER), & SmoothedNgramPredictor::set_logger); dispatcher.map (config->find (DATABASE_LOGGER), & SmoothedNgramPredictor::set_database_logger_level); dispatcher.map (config->find (DBFILENAME), & SmoothedNgramPredictor::set_dbfilename); dispatcher.map (config->find (DELTAS), & SmoothedNgramPredictor::set_deltas); dispatcher.map (config->find (LEARN), & SmoothedNgramPredictor::set_learn); } SmoothedNgramPredictor::~SmoothedNgramPredictor() { delete db; } void SmoothedNgramPredictor::set_dbfilename (const std::string& filename) { dbfilename = filename; logger << INFO << "DBFILENAME: " << dbfilename << endl; init_database_connector_if_ready (); } void SmoothedNgramPredictor::set_database_logger_level (const std::string& value) { dbloglevel = value; } void SmoothedNgramPredictor::set_deltas (const std::string& value) { std::stringstream ss_deltas(value); cardinality = 0; std::string delta; while (ss_deltas >> delta) { logger << DEBUG << "Pushing delta: " << delta << endl; deltas.push_back (Utility::toDouble (delta)); cardinality++; } logger << INFO << "DELTAS: " << value << endl; logger << INFO << "CARDINALITY: " << cardinality << endl; init_database_connector_if_ready (); } void SmoothedNgramPredictor::set_learn (const std::string& value) { wanna_learn = Utility::isTrue (value); logger << INFO << "LEARN: " << value << endl; learn_mode_set = true; init_database_connector_if_ready (); } void SmoothedNgramPredictor::init_database_connector_if_ready () { // we can only init the sqlite database connector once we know the // following: // - what database file we need to open // - what cardinality we expect the database file to be // - whether we need to open the database in read only or // read/write mode (learning requires read/write access) // if (! dbfilename.empty() && cardinality > 0 && learn_mode_set ) { delete db; if (dbloglevel.empty ()) { // open database connector db = new SqliteDatabaseConnector(dbfilename, cardinality, wanna_learn); } else { // open database connector with logger lever db = new SqliteDatabaseConnector(dbfilename, cardinality, wanna_learn, dbloglevel); } } } // convenience function to convert ngram to string // static std::string ngram_to_string(const Ngram& ngram) { const char separator[] = "|"; std::string result = separator; for (Ngram::const_iterator it = ngram.begin(); it != ngram.end(); it++) { result += *it + separator; } return result; } /** \brief Builds the required n-gram and returns its count. * * \param tokens tokens[i] contains ContextTracker::getToken(i) * \param offset entry point into tokens, must be a non-positive number * \param ngram_size size of the ngram whose count is returned, must not be greater than tokens size * \return count of the ngram built based on tokens, offset and ngram_size * * \verbatim Let tokens = [ "how", "are", "you", "today" ]; count(tokens, 0, 3) returns the count associated with 3-gram [ "are", "you", "today" ]. count(tokens, -1, 2) returns the count associated with 2-gram [ "are", "you" ]; * \endverbatim * */ unsigned int SmoothedNgramPredictor::count(const std::vector<std::string>& tokens, int offset, int ngram_size) const { unsigned int result = 0; assert(offset <= 0); // TODO: handle this better assert(ngram_size >= 0); if (ngram_size > 0) { Ngram ngram(ngram_size); copy(tokens.end() - ngram_size + offset , tokens.end() + offset, ngram.begin()); result = db->getNgramCount(ngram); logger << DEBUG << "count ngram: " << ngram_to_string (ngram) << " : " << result << endl; } else { result = db->getUnigramCountsSum(); logger << DEBUG << "unigram counts sum: " << result << endl; } return result; } Prediction SmoothedNgramPredictor::predict(const size_t max_partial_prediction_size, const char** filter) const { logger << DEBUG << "predict()" << endl; // Result prediction Prediction prediction; // Cache all the needed tokens. // tokens[k] corresponds to w_{i-k} in the generalized smoothed // n-gram probability formula // std::vector<std::string> tokens(cardinality); for (int i = 0; i < cardinality; i++) { tokens[cardinality - 1 - i] = contextTracker->getToken(i); logger << DEBUG << "Cached tokens[" << cardinality - 1 - i << "] = " << tokens[cardinality - 1 - i] << endl; } // Generate list of prefix completition candidates. // // The prefix completion candidates used to be obtained from the // _1_gram table because in a well-constructed ngram database the // _1_gram table (which contains all known tokens). However, this // introduced a skew, since the unigram counts will take // precedence over the higher-order counts. // // The current solution retrieves candidates from the highest // n-gram table, falling back on lower order n-gram tables if // initial completion set is smaller than required. // std::vector<std::string> prefixCompletionCandidates; for (size_t k = cardinality; (k > 0 && prefixCompletionCandidates.size() < max_partial_prediction_size); k--) { logger << DEBUG << "Building partial prefix completion table of cardinality: " << k << endl; // create n-gram used to retrieve initial prefix completion table Ngram prefix_ngram(k); copy(tokens.end() - k, tokens.end(), prefix_ngram.begin()); if (logger.shouldLog()) { logger << DEBUG << "prefix_ngram: "; for (size_t r = 0; r < prefix_ngram.size(); r++) { logger << DEBUG << prefix_ngram[r] << ' '; } logger << DEBUG << endl; } // obtain initial prefix completion candidates db->beginTransaction(); NgramTable partial; if (filter == 0) { partial = db->getNgramLikeTable(prefix_ngram,max_partial_prediction_size - prefixCompletionCandidates.size()); } else { partial = db->getNgramLikeTableFiltered(prefix_ngram,filter, max_partial_prediction_size - prefixCompletionCandidates.size()); } db->endTransaction(); if (logger.shouldLog()) { logger << DEBUG << "partial prefixCompletionCandidates" << endl << DEBUG << "----------------------------------" << endl; for (size_t j = 0; j < partial.size(); j++) { for (size_t k = 0; k < partial[j].size(); k++) { logger << DEBUG << partial[j][k] << " "; } logger << endl; } } logger << DEBUG << "Partial prefix completion table contains " << partial.size() << " potential completions." << endl; // append newly discovered potential completions to prefix // completion candidates array to fill it up to // max_partial_prediction_size // std::vector<Ngram>::const_iterator it = partial.begin(); while (it != partial.end() && prefixCompletionCandidates.size() < max_partial_prediction_size) { // only add new candidates, iterator it points to Ngram, // it->end() - 2 points to the token candidate // std::string candidate = *(it->end() - 2); if (find(prefixCompletionCandidates.begin(), prefixCompletionCandidates.end(), candidate) == prefixCompletionCandidates.end()) { prefixCompletionCandidates.push_back(candidate); } it++; } } if (logger.shouldLog()) { logger << DEBUG << "prefixCompletionCandidates" << endl << DEBUG << "--------------------------" << endl; for (size_t j = 0; j < prefixCompletionCandidates.size(); j++) { logger << DEBUG << prefixCompletionCandidates[j] << endl; } } // compute smoothed probabilities for all candidates // db->beginTransaction(); // getUnigramCountsSum is an expensive SQL query // caching it here saves much time later inside the loop int unigrams_counts_sum = db->getUnigramCountsSum(); for (size_t j = 0; (j < prefixCompletionCandidates.size() && j < max_partial_prediction_size); j++) { // store w_i candidate at end of tokens tokens[cardinality - 1] = prefixCompletionCandidates[j]; logger << DEBUG << "------------------" << endl; logger << DEBUG << "w_i: " << tokens[cardinality - 1] << endl; double probability = 0; for (int k = 0; k < cardinality; k++) { double numerator = count(tokens, 0, k+1); // reuse cached unigrams_counts_sum to speed things up double denominator = (k == 0 ? unigrams_counts_sum : count(tokens, -1, k)); double frequency = ((denominator > 0) ? (numerator / denominator) : 0); probability += deltas[k] * frequency; logger << DEBUG << "numerator: " << numerator << endl; logger << DEBUG << "denominator: " << denominator << endl; logger << DEBUG << "frequency: " << frequency << endl; logger << DEBUG << "delta: " << deltas[k] << endl; // for some sanity checks assert(numerator <= denominator); assert(frequency <= 1); } logger << DEBUG << "____________" << endl; logger << DEBUG << "probability: " << probability << endl; if (probability > 0) { prediction.addSuggestion(Suggestion(tokens[cardinality - 1], probability)); } } db->endTransaction(); logger << DEBUG << "Prediction:" << endl; logger << DEBUG << "-----------" << endl; logger << DEBUG << prediction << endl; return prediction; } void SmoothedNgramPredictor::learn(const std::vector<std::string>& change) { logger << INFO << "learn(\"" << ngram_to_string(change) << "\")" << endl; if (wanna_learn) { // learning is turned on try { db->beginTransaction(); for (size_t curr_cardinality = 1; curr_cardinality < cardinality + 1; curr_cardinality++) { logger << DEBUG << "Learning for n-gram cardinality: " << curr_cardinality << endl; // idx walks the change vector back to front for (std::vector<std::string>::const_reverse_iterator idx = change.rbegin(); idx != change.rend(); idx++) { Ngram ngram; // try to fill in the ngram to be learnt with change // tokens first for (std::vector<std::string>::const_reverse_iterator inner_idx = idx; inner_idx != change.rend() && ngram.size() < curr_cardinality; inner_idx++) { ngram.insert(ngram.begin(), *inner_idx); } logger << DEBUG << "After filling n-gram with change tokens: " << ngram_to_string(ngram) << endl; // then use (past stream - change) if ngram not filled in yet for (int tk_idx = 1; ngram.size() < curr_cardinality; tk_idx++) { // getExtraTokenToLearn returns tokens from // past stream that come before and are not in // change vector // std::string extra_token = contextTracker->getExtraTokenToLearn(tk_idx, change); logger << DEBUG << "Adding extra token: " << extra_token << endl; ngram.insert(ngram.begin(), extra_token); } // now we have built the ngram we have to learn logger << INFO << "Considering to learn ngram: |"; for (size_t j = 0; j < ngram.size(); j++) { logger << INFO << ngram[j] << '|'; } logger << INFO << endl; if (ngram.end() == find(ngram.begin(), ngram.end(), "")) { // only learn ngram if it doesn't contain empty strings db->incrementNgramCount(ngram); check_learn_consistency(ngram); logger << INFO << "Learnt ngram" << endl; } else { logger << INFO << "Discarded ngram" << endl; } } } db->endTransaction(); logger << INFO << "Committed learning update to database" << endl; } catch (SqliteDatabaseConnector::SqliteDatabaseConnectorException& ex) { db->rollbackTransaction(); logger << ERROR << "Rolling back learning update : " << ex.what() << endl; throw; } } logger << DEBUG << "end learn()" << endl; } void SmoothedNgramPredictor::check_learn_consistency(const Ngram& ngram) const { // no need to begin a new transaction, as we'll be called from // within an existing transaction from learn() // BEWARE: if the previous sentence is not true, then performance // WILL suffer! size_t size = ngram.size(); for (size_t i = 0; i < size; i++) { if (count(ngram, -i, size - i) > count(ngram, -(i + 1), size - (i + 1))) { logger << INFO << "consistency adjustment needed!" << endl; int offset = -(i + 1); int sub_ngram_size = size - (i + 1); logger << DEBUG << "i: " << i << " | offset: " << offset << " | sub_ngram_size: " << sub_ngram_size << endl; Ngram sub_ngram(sub_ngram_size); // need to init to right size for sub_ngram copy(ngram.end() - sub_ngram_size + offset, ngram.end() + offset, sub_ngram.begin()); if (logger.shouldLog()) { logger << "ngram to be count adjusted is: "; for (size_t i = 0; i < sub_ngram.size(); i++) { logger << sub_ngram[i] << ' '; } logger << endl; } db->incrementNgramCount(sub_ngram); logger << DEBUG << "consistency adjusted" << endl; } } } void SmoothedNgramPredictor::update (const Observable* var) { logger << DEBUG << "About to invoke dispatcher: " << var->get_name () << " - " << var->get_value() << endl; dispatcher.dispatch (var); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/recencyPredictor.h�������������������������������������������������0000644�0001750�0001750�00000006514�11763437013�017301� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_RECENCYPREDICTOR #define PRESAGE_RECENCYPREDICTOR #include "predictor.h" #include "../core/logger.h" #include "../core/dispatcher.h" /** Recency predictor, a recency promotion statistical predictor. * * RecencyPredictor, based on recency promotion principle, generates * predictions by assigning exponentially decaying probability values * to previously encountered tokens. Tokens are assigned a probability * value that decays exponentially with their distance from the * current token, thereby promoting context recency * (from Wikipedia) A quantity is said to be subject to exponential * decay if it decreases at a rate proportional to its * value. Symbolically, this can be expressed as the following * differential equation, where N is the quantity and λ is a positive * number called the decay constant. * * frac{dN}{dt} = -lambda N. * * The solution to this equation is below: * * N(t) = N_0 e^{-lambda t} * * Here N(t) is the quantity at time t, and N0 = N(0) is the (initial) * quantity, at time t = 0. * * This is the form of the equation that is most commonly used to * describe exponential decay. The constant of integration N0 denotes * the original quantity at t = 0. (The notation λ for the decay * constant is a remnant of the usual notation for an eigenvalue. In * this case, λ is the eigenvalue of the opposite of the * differentiation operator with N(t) as the corresponding * eigenfunction). * */ class RecencyPredictor : public Predictor, public Observer { public: RecencyPredictor (Configuration*, ContextTracker*, const char*); ~RecencyPredictor(); virtual Prediction predict (const size_t size, const char** filter) const; virtual void learn (const std::vector<std::string>& change); virtual void update (const Observable* variable); private: void set_lambda (const std::string& value); void set_n_0 (const std::string& value); void set_cutoff_threshold (const std::string& value); std::string LOGGER; std::string LAMBDA; std::string N_0; std::string CUTOFF_THRESHOLD; double lambda; double n_0; size_t cutoff_threshold; Dispatcher<RecencyPredictor> dispatcher; }; #endif // PRESAGE_RECENCYPREDICTOR ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/Makefile.in��������������������������������������������������������0000644�0001750�0001750�00000065717�11763440355�015706� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @USE_SQLITE_TRUE@am__append_1 = \ @USE_SQLITE_TRUE@ libSmoothedNgramPredictor.la subdir = src/lib/predictors DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libARPAPredictor_la_LIBADD = am_libARPAPredictor_la_OBJECTS = ARPAPredictor.lo libARPAPredictor_la_OBJECTS = $(am_libARPAPredictor_la_OBJECTS) libAbbreviationExpansionPredictor_la_LIBADD = am_libAbbreviationExpansionPredictor_la_OBJECTS = \ abbreviationExpansionPredictor.lo libAbbreviationExpansionPredictor_la_OBJECTS = \ $(am_libAbbreviationExpansionPredictor_la_OBJECTS) libDejavuPredictor_la_LIBADD = am_libDejavuPredictor_la_OBJECTS = dejavuPredictor.lo libDejavuPredictor_la_OBJECTS = $(am_libDejavuPredictor_la_OBJECTS) libDictionaryPredictor_la_LIBADD = am_libDictionaryPredictor_la_OBJECTS = dictionaryPredictor.lo libDictionaryPredictor_la_OBJECTS = \ $(am_libDictionaryPredictor_la_OBJECTS) libDummyPredictor_la_LIBADD = am_libDummyPredictor_la_OBJECTS = dummyPredictor.lo libDummyPredictor_la_OBJECTS = $(am_libDummyPredictor_la_OBJECTS) libRecencyPredictor_la_LIBADD = am_libRecencyPredictor_la_OBJECTS = recencyPredictor.lo libRecencyPredictor_la_OBJECTS = $(am_libRecencyPredictor_la_OBJECTS) libRecencyPredictor_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(libRecencyPredictor_la_LDFLAGS) $(LDFLAGS) -o $@ libSmoothedNgramPredictor_la_LIBADD = am_libSmoothedNgramPredictor_la_OBJECTS = smoothedNgramPredictor.lo libSmoothedNgramPredictor_la_OBJECTS = \ $(am_libSmoothedNgramPredictor_la_OBJECTS) @USE_SQLITE_TRUE@am_libSmoothedNgramPredictor_la_rpath = libpredictor_la_LIBADD = am_libpredictor_la_OBJECTS = predictor.lo libpredictor_la_OBJECTS = $(am_libpredictor_la_OBJECTS) libpredictors_la_DEPENDENCIES = $(PREDICTORS) $(DBCONNECTOR) am_libpredictors_la_OBJECTS = libpredictors_la_OBJECTS = $(am_libpredictors_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libARPAPredictor_la_SOURCES) \ $(libAbbreviationExpansionPredictor_la_SOURCES) \ $(libDejavuPredictor_la_SOURCES) \ $(libDictionaryPredictor_la_SOURCES) \ $(libDummyPredictor_la_SOURCES) \ $(libRecencyPredictor_la_SOURCES) \ $(libSmoothedNgramPredictor_la_SOURCES) \ $(libpredictor_la_SOURCES) $(libpredictors_la_SOURCES) DIST_SOURCES = $(libARPAPredictor_la_SOURCES) \ $(libAbbreviationExpansionPredictor_la_SOURCES) \ $(libDejavuPredictor_la_SOURCES) \ $(libDictionaryPredictor_la_SOURCES) \ $(libDummyPredictor_la_SOURCES) \ $(libRecencyPredictor_la_SOURCES) \ $(libSmoothedNgramPredictor_la_SOURCES) \ $(libpredictor_la_SOURCES) $(libpredictors_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = dbconnector PREDICTORS = libpredictor.la libDummyPredictor.la \ libDictionaryPredictor.la libAbbreviationExpansionPredictor.la \ libRecencyPredictor.la libDejavuPredictor.la \ libARPAPredictor.la $(am__append_1) @USE_SQLITE_TRUE@DBCONNECTOR = \ @USE_SQLITE_TRUE@ dbconnector/libdbconnector.la noinst_LTLIBRARIES = \ libpredictors.la \ $(PREDICTORS) libpredictors_la_SOURCES = libpredictors_la_LIBADD = $(PREDICTORS) $(DBCONNECTOR) libpredictor_la_SOURCES = predictor.cpp predictor.h libSmoothedNgramPredictor_la_SOURCES = smoothedNgramPredictor.cpp \ smoothedNgramPredictor.h libAbbreviationExpansionPredictor_la_SOURCES = abbreviationExpansionPredictor.h \ abbreviationExpansionPredictor.cpp libDictionaryPredictor_la_SOURCES = dictionaryPredictor.cpp \ dictionaryPredictor.h libDummyPredictor_la_SOURCES = dummyPredictor.cpp \ dummyPredictor.h libRecencyPredictor_la_SOURCES = recencyPredictor.cpp \ recencyPredictor.h libRecencyPredictor_la_LDFLAGS = -lm libDejavuPredictor_la_SOURCES = dejavuPredictor.cpp \ dejavuPredictor.h libARPAPredictor_la_SOURCES = ARPAPredictor.cpp \ ARPAPredictor.h all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/predictors/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lib/predictors/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libARPAPredictor.la: $(libARPAPredictor_la_OBJECTS) $(libARPAPredictor_la_DEPENDENCIES) $(CXXLINK) $(libARPAPredictor_la_OBJECTS) $(libARPAPredictor_la_LIBADD) $(LIBS) libAbbreviationExpansionPredictor.la: $(libAbbreviationExpansionPredictor_la_OBJECTS) $(libAbbreviationExpansionPredictor_la_DEPENDENCIES) $(CXXLINK) $(libAbbreviationExpansionPredictor_la_OBJECTS) $(libAbbreviationExpansionPredictor_la_LIBADD) $(LIBS) libDejavuPredictor.la: $(libDejavuPredictor_la_OBJECTS) $(libDejavuPredictor_la_DEPENDENCIES) $(CXXLINK) $(libDejavuPredictor_la_OBJECTS) $(libDejavuPredictor_la_LIBADD) $(LIBS) libDictionaryPredictor.la: $(libDictionaryPredictor_la_OBJECTS) $(libDictionaryPredictor_la_DEPENDENCIES) $(CXXLINK) $(libDictionaryPredictor_la_OBJECTS) $(libDictionaryPredictor_la_LIBADD) $(LIBS) libDummyPredictor.la: $(libDummyPredictor_la_OBJECTS) $(libDummyPredictor_la_DEPENDENCIES) $(CXXLINK) $(libDummyPredictor_la_OBJECTS) $(libDummyPredictor_la_LIBADD) $(LIBS) libRecencyPredictor.la: $(libRecencyPredictor_la_OBJECTS) $(libRecencyPredictor_la_DEPENDENCIES) $(libRecencyPredictor_la_LINK) $(libRecencyPredictor_la_OBJECTS) $(libRecencyPredictor_la_LIBADD) $(LIBS) libSmoothedNgramPredictor.la: $(libSmoothedNgramPredictor_la_OBJECTS) $(libSmoothedNgramPredictor_la_DEPENDENCIES) $(CXXLINK) $(am_libSmoothedNgramPredictor_la_rpath) $(libSmoothedNgramPredictor_la_OBJECTS) $(libSmoothedNgramPredictor_la_LIBADD) $(LIBS) libpredictor.la: $(libpredictor_la_OBJECTS) $(libpredictor_la_DEPENDENCIES) $(CXXLINK) $(libpredictor_la_OBJECTS) $(libpredictor_la_LIBADD) $(LIBS) libpredictors.la: $(libpredictors_la_OBJECTS) $(libpredictors_la_DEPENDENCIES) $(LINK) $(libpredictors_la_OBJECTS) $(libpredictors_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ARPAPredictor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/abbreviationExpansionPredictor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dejavuPredictor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dictionaryPredictor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummyPredictor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/predictor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recencyPredictor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smoothedNgramPredictor.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ clean-noinstLTLIBRARIES ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # 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: �������������������������������������������������presage-0.8.8/src/lib/predictors/predictor.cpp������������������������������������������������������0000644�0001750�0001750�00000006236�11763437013�016324� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "predictor.h" #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif /** Creates a predictor object. * * @param config pointer to configuration * @param ct is a reference to HistoryTracker * @param predictorName is the predictor name * @param shortDesc is a short description of the predictor's functionality * @param longDesc is a long description of the predictor's functionality */ Predictor::Predictor(Configuration* config, ContextTracker* ct, const char* predictorName, const char* shortDesc, const char* longDesc) : name (predictorName), shortDescription(shortDesc ), longDescription (longDesc ), contextTracker (ct ), configuration (config ), PREDICTORS ("Presage.Predictors."), logger (predictorName, std::cerr) { // NOTE: predictor implementations deriving from this class should // use profile to query the value of needed configuration // variables. } /** Virtual predictor destructor. * */ Predictor::~Predictor() {} /** Get predictor name. * */ const std::string Predictor::getName() const { return name; } /** Get predictor short description. * */ const std::string Predictor::getShortDescription() const { return shortDescription; } /** Get predictor long description. * */ const std::string Predictor::getLongDescription() const { return longDescription; } void Predictor::set_logger (const std::string& level) { logger << setlevel (level); logger << INFO << "LOGGER: " << level << endl; } bool Predictor::token_satisfies_filter (const std::string& token, const std::string& prefix, const char** filter) const { bool result = false; if (filter) { // filter is not empty, examine each filter token int i = 0; while (filter[i] && !result) { std::string candidate = prefix + filter[i]; // if token starts with candidate if (token.find (candidate) == 0) { result = true; } i++; } } else { // filter is empty, token matches result = true; } return result; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/abbreviationExpansionPredictor.h�����������������������������������0000644�0001750�0001750�00000004654�11763437013�022206� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_ABBREVIATIONEXPANSIONPREDICTOR #define PRESAGE_ABBREVIATIONEXPANSIONPREDICTOR #include "predictor.h" #include "../core/dispatcher.h" /** Abbreviation expansion predictor. * * This predictor maps abbreviations to the corresponding fully expanded * token (i.e. word or phrase). * * The mapping between abbreviations and expansions is stored in the * file specified by the predictor configuration section. * * The format for the abbreviation-expansion database is a simple tab * separated text file format, with each abbreviation-expansion pair * per line. * */ class AbbreviationExpansionPredictor : public Predictor, public Observer { public: AbbreviationExpansionPredictor(Configuration*, ContextTracker*, const char*); ~AbbreviationExpansionPredictor(); virtual Prediction predict(const size_t size, const char** filter) const; virtual void learn(const std::vector<std::string>& change); virtual void update (const Observable* variable); private: std::string LOGGER; std::string ABBREVIATIONS; void set_abbreviations (const std::string& filename); void cacheAbbreviationsExpansions(); std::string abbreviations; std::map< std::string, std::string> cache; Dispatcher<AbbreviationExpansionPredictor> dispatcher; }; #endif // PRESAGE_ABBREVIATIONEXPANSIONPREDICTOR ������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/recencyPredictor.cpp�����������������������������������������������0000644�0001750�0001750�00000011424�11763437013�017630� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "recencyPredictor.h" #include <math.h> // for exp() RecencyPredictor::RecencyPredictor(Configuration* config, ContextTracker* ct, const char* name) : Predictor(config, ct, name, "RecencyPredictor, a statistical recency promotion predictor", "RecencyPredictor, based on a recency promotion principle, generates predictions by assigning exponentially decaying probability values to previously encountered tokens. Tokens are assigned a probability value that decays exponentially with their distance from the current token, thereby promoting context recency." ), dispatcher (this) { // RecencyPredictor config variables LOGGER = PREDICTORS + name + ".LOGGER"; LAMBDA = PREDICTORS + name + ".LAMBDA"; N_0 = PREDICTORS + name + ".N_0"; CUTOFF_THRESHOLD = PREDICTORS + name + ".CUTOFF_THRESHOLD"; // init default values lambda = 1; n_0 = 1; cutoff_threshold = 20; dispatcher.map(config->find (LOGGER), &RecencyPredictor::set_logger); dispatcher.map(config->find (LAMBDA), &RecencyPredictor::set_lambda); dispatcher.map(config->find (N_0), &RecencyPredictor::set_n_0); dispatcher.map(config->find (CUTOFF_THRESHOLD), &RecencyPredictor::set_cutoff_threshold); } RecencyPredictor::~RecencyPredictor() { // complete } void RecencyPredictor::set_lambda (const std::string& value) { lambda = Utility::toDouble(value); logger << INFO << "LAMBDA: " << value << endl; } void RecencyPredictor::set_n_0 (const std::string& value) { n_0 = Utility::toDouble (value); logger << INFO << "N_0: " << value << endl; } void RecencyPredictor::set_cutoff_threshold (const std::string& value) { cutoff_threshold = Utility::toInt (value); logger << INFO << "CUTOFF_THRESHOLD: " << value << endl; } Prediction RecencyPredictor::predict (const size_t max, const char** filter) const { Prediction result; std::string prefix = contextTracker->getPrefix(); logger << INFO << "prefix: " << prefix << endl; if (!prefix.empty()) { // Only build recency prediction if prefix is not empty: when // prefix is empty, all previosly seen tokens are candidates // for prediction. This is not desirable, because it means // that recency prediction reduces to repetion of max previous // tokens (i.e. the prediction would contain the most recent // tokens in reverse order). // Suggestion suggestion; size_t index = 1; std::string token = contextTracker->getToken(index); double prob = 0; while (!token.empty() // context history exhausted && result.size() < max // need only max suggestions && index <= cutoff_threshold // look back only as far as cutoff ) { logger << INFO << "token: " << token << endl; if (token.find(prefix) == 0) { // if token starts with prefix if (token_satisfies_filter (token, prefix, filter)) { // compute probability according to exponential decay // formula // prob = n_0 * exp(-(lambda * (index - 1))); logger << INFO << "probability: " << prob << endl; suggestion.setWord(token); suggestion.setProbability(prob); result.addSuggestion(suggestion); } } index++; token = contextTracker->getToken(index); } } return result; } void RecencyPredictor::learn(const std::vector<std::string>& change) {} void RecencyPredictor::update (const Observable* var) { logger << DEBUG << "About to invoke dispatcher: " << var->get_name () << " - " << var->get_value() << endl; dispatcher.dispatch (var); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/predictor.h��������������������������������������������������������0000644�0001750�0001750�00000005770�11763437013�015773� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTOR #define PRESAGE_PREDICTOR #include "../core/prediction.h" #include "../core/context_tracker/contextTracker.h" #include "../core/configuration.h" #include "../core/utility.h" #include <string> #include <vector> /** Predictor is an abstract class that defines the interface implemented by concrete predictors. * * The prediction algorithm implemented by predictors is at the heart * of presage. The predictor-based architecture allows new prediction * methods to be easily and transparently added to the system. * * Predictors have access to and rely on the services provided by core * components of the presage system. * */ class Predictor { public: Predictor(Configuration* configuration, ContextTracker* contextTracker, const char* predictorName = "Predictor", const char* shortDescription = "", const char* longDescription = ""); virtual ~Predictor(); /** \brief Generate prediction. * * \param size desired prediction size * \param filter filter * */ virtual Prediction predict(const size_t size, const char** filter) const = 0; virtual void learn(const std::vector<std::string>& change) = 0; const std::string getName() const; const std::string getShortDescription() const; const std::string getLongDescription() const; protected: virtual bool token_satisfies_filter (const std::string& token, const std::string& prefix, const char** filter) const; virtual void set_logger (const std::string& level); const std::string name; const std::string shortDescription; // predictor's descriptive name const std::string longDescription; // predictor's exhaustive description const std::string PREDICTORS; ContextTracker* contextTracker; Configuration* configuration; Logger<char> logger; private: }; #endif // PRESAGE_PREDICTOR ��������presage-0.8.8/src/lib/predictors/dbconnector/�������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�016213� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dbconnector/Makefile.am��������������������������������������������0000644�0001750�0001750�00000002352�11737142176�020160� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if USE_SQLITE noinst_LTLIBRARIES = libdbconnector.la libdbconnector_la_SOURCES = databaseConnector.cpp \ databaseConnector.h \ sqliteDatabaseConnector.cpp \ sqliteDatabaseConnector.h libdbconnector_la_LIBADD = $(SQLITE_LIBS) endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dbconnector/Makefile.in��������������������������������������������0000644�0001750�0001750�00000041746�11763440355�020202� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/lib/predictors/dbconnector DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = @USE_SQLITE_TRUE@libdbconnector_la_DEPENDENCIES = \ @USE_SQLITE_TRUE@ $(am__DEPENDENCIES_1) am__libdbconnector_la_SOURCES_DIST = databaseConnector.cpp \ databaseConnector.h sqliteDatabaseConnector.cpp \ sqliteDatabaseConnector.h @USE_SQLITE_TRUE@am_libdbconnector_la_OBJECTS = databaseConnector.lo \ @USE_SQLITE_TRUE@ sqliteDatabaseConnector.lo libdbconnector_la_OBJECTS = $(am_libdbconnector_la_OBJECTS) @USE_SQLITE_TRUE@am_libdbconnector_la_rpath = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libdbconnector_la_SOURCES) DIST_SOURCES = $(am__libdbconnector_la_SOURCES_DIST) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @USE_SQLITE_TRUE@noinst_LTLIBRARIES = libdbconnector.la @USE_SQLITE_TRUE@libdbconnector_la_SOURCES = databaseConnector.cpp \ @USE_SQLITE_TRUE@ databaseConnector.h \ @USE_SQLITE_TRUE@ sqliteDatabaseConnector.cpp \ @USE_SQLITE_TRUE@ sqliteDatabaseConnector.h @USE_SQLITE_TRUE@libdbconnector_la_LIBADD = $(SQLITE_LIBS) all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/predictors/dbconnector/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/lib/predictors/dbconnector/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libdbconnector.la: $(libdbconnector_la_OBJECTS) $(libdbconnector_la_DEPENDENCIES) $(CXXLINK) $(am_libdbconnector_la_rpath) $(libdbconnector_la_OBJECTS) $(libdbconnector_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/databaseConnector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqliteDatabaseConnector.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am # 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: ��������������������������presage-0.8.8/src/lib/predictors/dbconnector/sqliteDatabaseConnector.h������������������������������0000644�0001750�0001750�00000005066�11763437013�023077� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef SQLITEDATABASECONNECTOR_H #define SQLITEDATABASECONNECTOR_H #ifdef HAVE_CONFIG_H # include "config.h" #endif #if defined(HAVE_SQLITE3_H) # include <sqlite3.h> #elif defined(HAVE_SQLITE_H) # include <sqlite.h> #else # error "SQLite is required. Please install SQLite." #endif #include "databaseConnector.h" #include "../../presageException.h" class SqliteDatabaseConnector : public DatabaseConnector { public: SqliteDatabaseConnector(const std::string db, const size_t cardinality, const bool read_write); SqliteDatabaseConnector(const std::string db, const size_t cardinality, const bool read_write, const std::string logger_level); ~SqliteDatabaseConnector(); virtual void openDatabase(); virtual void closeDatabase(); virtual NgramTable executeSql(const std::string query) const; class SqliteDatabaseConnectorException : public PresageException { public: SqliteDatabaseConnectorException(presage_error_code_t code, const std::string& errormsg) throw() : PresageException(code, errormsg) { } virtual ~SqliteDatabaseConnectorException() throw() { } private: SqliteDatabaseConnectorException() throw() : PresageException(PRESAGE_ERROR, "") {}; }; protected: private: static int callback(void *pArg, int argc, char **argv, char **columnNames); #if defined(HAVE_SQLITE3_H) sqlite3* db; #elif defined(HAVE_SQLITE_H) sqlite* db; #endif }; #endif // SQLITEDATABASECONNECTOR_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dbconnector/sqliteDatabaseConnector.cpp����������������������������0000644�0001750�0001750�00000012467�11763437013�023435� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "sqliteDatabaseConnector.h" #ifdef HAVE_STDLIB_H # include <stdlib.h> // for free() #endif SqliteDatabaseConnector::SqliteDatabaseConnector(const std::string database_name, const size_t cardinality, const bool read_write) : DatabaseConnector(database_name, cardinality, read_write) { openDatabase(); } SqliteDatabaseConnector::SqliteDatabaseConnector(const std::string database_name, const size_t cardinality, const bool read_write, const std::string logger_level) : DatabaseConnector(database_name, cardinality, read_write, logger_level) { openDatabase(); } SqliteDatabaseConnector::~SqliteDatabaseConnector() { closeDatabase(); } void SqliteDatabaseConnector::openDatabase() { #if defined(HAVE_SQLITE3_H) int rc; // attempt to connect to existing database if (! get_read_write_mode()) { // attempt to open read-only, no create rc = sqlite3_open_v2(get_database_filename().c_str(), &db, SQLITE_OPEN_READONLY, NULL); } else { // attempt to open read-write, no create rc = sqlite3_open_v2(get_database_filename().c_str(), &db, SQLITE_OPEN_READWRITE, NULL); } // if database no-create open connection operation failed, open // database read-write/create mode and create tables if (rc != SQLITE_OK) { // attempt to open read-write, create rc = sqlite3_open_v2(get_database_filename().c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); // throw exception if database cannot be opened/created if (rc != SQLITE_OK) { std::string error = sqlite3_errmsg(db); logger << ERROR << "Unable to open database: " << get_database_filename() << endl; throw SqliteDatabaseConnectorException(PRESAGE_SQLITE_OPEN_DATABASE_ERROR, error); } else { logger << WARN << "Creating new language model database: " << get_database_filename() << endl; } // create n-gram tables up to specified cardinality for (size_t cardinality = 1; cardinality <= get_cardinality (); cardinality++) { createNgramTable(cardinality); } } #elif defined(HAVE_SQLITE_H) char* errormsg = 0; db = sqlite_open(get_database_filename().c_str(), 0, &errormsg); if (db == 0) { std::string error; if (errormsg != 0) { error = errormsg; } #ifdef HAVE_STDLIB_H free(errormsg); #endif logger << ERROR << "Unable to open database: " << get_database_filename() << " : " << endl; throw SqliteDatabaseConnectorException(error); } #endif } void SqliteDatabaseConnector::closeDatabase() { if (db) { #if defined(HAVE_SQLITE3_H) sqlite3_close(db); #elif defined(HAVE_SQLITE_H) sqlite_close(db); #endif } } NgramTable SqliteDatabaseConnector::executeSql(const std::string query) const { NgramTable answer; char* sqlite_error_msg = 0; logger << DEBUG << "executing query: " << query << endl; #if defined(HAVE_SQLITE3_H) int result = sqlite3_exec( #elif defined(HAVE_SQLITE_H) int result = sqlite_exec( #endif db, query.c_str(), callback, &answer, &sqlite_error_msg ); if (result != SQLITE_OK) { std::string error; if (sqlite_error_msg != 0) { error = sqlite_error_msg; } #if defined(HAVE_SQLITE3_H) sqlite3_free(sqlite_error_msg); #elif defined(HAVE_SQLITE_H) # ifdef HAVE_STDLIB_H free(sqlite_error_msg); # endif #endif logger << ERROR << "Error executing SQL: '" << query << "' on database: '" << get_database_filename() << "' : " << error << endl; throw SqliteDatabaseConnectorException(PRESAGE_SQLITE_EXECUTE_SQL_ERROR, error); } return answer; } int SqliteDatabaseConnector::callback( void *pArg, int argc, char **argv, char **columnNames) { NgramTable& query_result = *static_cast<NgramTable*>(pArg); //std::cerr << "building ngram: "; Ngram ngram; for (int i = 0; i < argc; i++) { if (argv[i] != NULL) { //std::cerr << "(" << columnNames[i] << ":" << argv[i] << ")" << '\t'; ngram.push_back(argv[i]); } else { //std::cerr << "argv[" << i << "] is NULL" << std::endl; ngram.push_back(""); // empty string to represent NULL value } } //std::cerr << std::endl; query_result.push_back(ngram); return SQLITE_OK; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dbconnector/databaseConnector.cpp����������������������������������0000644�0001750�0001750�00000032136�11763437013�022246� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "databaseConnector.h" #include "../../core/utility.h" #include <list> #include <sstream> #include <stdlib.h> #include <assert.h> DatabaseConnector::DatabaseConnector(const std::string database_name, const size_t cardinality, const bool read_write) : logger("DatabaseConnector", std::cerr) { set_database_filename (database_name); set_cardinality (cardinality); set_read_write_mode (read_write); } DatabaseConnector::DatabaseConnector(const std::string database_name, const size_t cardinality, const bool read_write, const std::string& log_level) : logger("DatabaseConnector", std::cerr, log_level) { set_database_filename (database_name); set_cardinality (cardinality); set_read_write_mode (read_write); } DatabaseConnector::~DatabaseConnector() {} void DatabaseConnector::createNgramTable(const size_t n) const { if (n > 0) { std::stringstream query; std::stringstream unique; query << "CREATE TABLE"; // This #ifdef does not belong here, but unfortunately SQLite 2.x does // not support the IF NOT EXISTS SQL clause. #ifndef HAVE_SQLITE_H query << " IF NOT EXISTS"; #endif query << " _" << n << "_gram ("; for (int i = n - 1; i >= 0; i--) { if (i != 0) { unique << "word_" << i << ", "; query << "word_" << i << " TEXT, "; } else { unique << "word"; query << "word TEXT, count INTEGER, UNIQUE(" << unique.str() << ") );"; } } executeSql(query.str()); } else { // TODO // throw exception } } int DatabaseConnector::getUnigramCountsSum() const { std::string query = "SELECT SUM(count) FROM _1_gram;"; NgramTable result = executeSql(query); logger << DEBUG << "NgramTable:"; for (size_t i = 0; i < result.size(); i++) { for (size_t j = 0; j < result[i].size(); j++) { logger << DEBUG << result[i][j] << '\t'; } logger << DEBUG << endl; } return extractFirstInteger(result); } int DatabaseConnector::getNgramCount(const Ngram ngram) const { std::stringstream query; query << "SELECT count " << "FROM _" << ngram.size() << "_gram" << buildWhereClause(ngram) << ";"; NgramTable result = executeSql(query.str()); logger << DEBUG << "NgramTable:"; for (size_t i = 0; i < result.size(); i++) { for (size_t j = 0; j < result[i].size(); j++) { logger << DEBUG << result[i][j] << '\t'; } logger << DEBUG << endl; } return extractFirstInteger(result); } NgramTable DatabaseConnector::getNgramLikeTable(const Ngram ngram, int limit) const { std::stringstream query; query << "SELECT " << buildSelectLikeClause(ngram.size()) << " " << "FROM _" << ngram.size() << "_gram" << buildWhereLikeClause(ngram) << " ORDER BY count DESC"; if (limit < 0) { query << ";"; } else { query << " LIMIT " << limit << ';'; } return executeSql(query.str()); } NgramTable DatabaseConnector::getNgramLikeTableFiltered(const Ngram ngram, const char** filter, int limit) const { std::stringstream query; query << "SELECT " << buildSelectLikeClause(ngram.size()) << " " << "FROM _" << ngram.size() << "_gram" << buildWhereLikeClauseFiltered(ngram,filter) << " ORDER BY count DESC"; if (limit < 0) { query << ";"; } else { query << " LIMIT " << limit << ';'; } return executeSql(query.str()); } int DatabaseConnector::incrementNgramCount(const Ngram ngram) const { int count = getNgramCount(ngram); if (count > 0) { // the ngram was found in the database updateNgram(ngram, ++count); logger << DEBUG << "Updated ngram to " << count << endl; } else { // the ngram was not found in the database count = 1; insertNgram(ngram, count); logger << DEBUG << "Inserted ngram" << endl; } return count; } void DatabaseConnector::removeNgram(const Ngram ngram) const {} void DatabaseConnector::insertNgram(const Ngram ngram, const int count) const { std::stringstream query; query << "INSERT INTO _" << ngram.size() << "_gram " << buildValuesClause(ngram, count) << ";"; executeSql(query.str()); } void DatabaseConnector::updateNgram(const Ngram ngram, const int count) const { std::stringstream query; query << "UPDATE _" << ngram.size() << "_gram " << "SET count = " << count << buildWhereClause(ngram) << ";"; executeSql(query.str()); } std::string DatabaseConnector::buildWhereClause(const Ngram ngram) const { std::stringstream where_clause; where_clause << " WHERE"; for (size_t i = 0; i < ngram.size(); i++) { if (i < ngram.size() - 1) { where_clause << " word_" << ngram.size() - i - 1 << " = '" << sanitizeString(ngram[i]) << "' AND"; } else { where_clause << " word = '" << sanitizeString(ngram[ngram.size() - 1]) << "'"; } } return where_clause.str(); } // TODO REVISIT refactor: this is same as buildWhereClause, except for // "word = " instead of "word LIKE " std::string DatabaseConnector::buildWhereLikeClause(const Ngram ngram) const { std::stringstream where_clause; where_clause << " WHERE"; for (size_t i = 0; i < ngram.size(); i++) { if (i < ngram.size() - 1) { where_clause << " word_" << ngram.size() - i - 1 << " = '" << sanitizeString(ngram[i]) << "' AND"; } else { where_clause << " word LIKE '" << sanitizeString(ngram[ngram.size() - 1]) << "%'"; } } return where_clause.str(); } std::string DatabaseConnector::buildWhereLikeClauseFiltered(const Ngram ngram, const char** filter) const { std::stringstream where_clause; where_clause << " WHERE"; for (size_t i = 0; i < ngram.size(); i++) { if (i < ngram.size() - 1) { where_clause << " word_" << ngram.size() - i - 1 << " = '" << sanitizeString(ngram[i]) << "' AND"; } else { if(filter == 0) where_clause << " word LIKE '" << sanitizeString(ngram[ngram.size() - 1]) << "%'"; else { std::string true_prefix = sanitizeString(ngram[ngram.size() - 1]); where_clause << " ("; for (int j = 0; filter[j] != 0; j++) { // for(size_t j=0; j < filter.size()-1; j++) if (j) { where_clause << " OR "; } where_clause << " word LIKE '" << true_prefix << filter[j] << "%'"; } // where_clause << " word LIKE '" << true_prefix <<"%' )"; where_clause << ')'; } } } return where_clause.str(); } std::string DatabaseConnector::buildSelectLikeClause(const int cardinality) const { assert(cardinality > 0); std::stringstream result; for (int i = cardinality - 1; i >= 0; i--) { if (i != 0) { result << "word_" << i << ", "; } else { result << "word, count"; } } return result.str(); } std::string DatabaseConnector::buildValuesClause(const Ngram ngram, const int count) const { std::stringstream values_clause; values_clause << "VALUES("; for (size_t i = 0; i < ngram.size(); i++) { if (i < ngram.size() - 1) { values_clause << "'" << sanitizeString(ngram[i]) << "', "; } else { values_clause << "'" << sanitizeString(ngram[i]) << "', " << count << ")"; } } return values_clause.str(); } std::string DatabaseConnector::sanitizeString(const std::string str) const { // TODO // just return the string for the time being // REVISIT // TO BE DONE // TBD return str; } int DatabaseConnector::extractFirstInteger(const NgramTable& table) const { // Initialize count to zero and then check that we have at least // an entry in the table of ngram counts returned by the // executeSql() method. If so, convert it into an integer and // return it. // // REVISIT: make conversion to integer more robust (strtol ??) // int count = 0; if (table.size() > 0) { if (table[0].size() > 0) { count = atoi(table[0][0].c_str()); } } logger << DEBUG << "table: "; for (size_t i = 0; i < table.size(); i++) { for (size_t j = 0; j < table[i].size(); j++) { logger << DEBUG << table[i][j] << '\t'; } logger << DEBUG << endl; } return (count > 0 ? count : 0); } void DatabaseConnector::beginTransaction() const { executeSql("BEGIN TRANSACTION;"); } void DatabaseConnector::endTransaction() const { executeSql("END TRANSACTION;"); } void DatabaseConnector::rollbackTransaction() const { executeSql("ROLLBACK TRANSACTION;"); } std::string DatabaseConnector::get_database_filename () const { return database_filename; } std::string DatabaseConnector::set_database_filename (const std::string& filename) { std::string prev_filename = database_filename; database_filename = expand_variables (filename); // make an attempt at determining whether directory where language // model database is located exists and try to create it if it // does not... only cater for one directory level to create it. // std::string dir = Utility::dirname (database_filename); if (! dir.empty()) { // check that specified directory exists and accessible if (! Utility::is_directory_usable (dir)) { // create it if not Utility::create_directory (dir); } } return prev_filename; } std::string DatabaseConnector::expand_variables (std::string filepath) const { // scan the filepath for variables, which follow the same pattern // as shell variables - strings enclosed in '${' and '}' // const std::string start_marker = "${"; const std::string end_marker = "}"; std::list<std::string> variables; std::string::size_type pos_start = filepath.find (start_marker); while (pos_start != std::string::npos) { std::string::size_type pos_end = filepath.find (end_marker, pos_start); if (pos_end != std::string::npos) { variables.push_back (filepath.substr(pos_start + start_marker.size(), pos_end - end_marker.size() - pos_start - 1)); } pos_start = filepath.find (start_marker, pos_end); } for (std::list<std::string>::const_iterator it = variables.begin(); it != variables.end(); it++) { substitute_variable_in_string(*it, filepath); } return filepath; } void DatabaseConnector::substitute_variable_in_string (const std::string& variable_name, std::string& filepath) const { std::string variable_token = "${" + variable_name + "}"; for (std::string::size_type pos = filepath.find (variable_token); pos != std::string::npos; pos = filepath.find (variable_token, pos)) { const char* value = getenv(variable_name.c_str()); if (value) { filepath.replace (pos, variable_token.size(), value); } else { // handle "special" variables if (variable_name == "HOME") { value = getenv("USERPROFILE"); if (value) { filepath.replace (pos, variable_token.size(), value); } } else { // FIXME: maybe throw exception instead of leaving // variable name in string? // filepath.replace (pos, variable_token.size(), variable_name); } } } } void DatabaseConnector::set_cardinality (const size_t card) { cardinality = card; } size_t DatabaseConnector::get_cardinality () const { return cardinality; } void DatabaseConnector::set_read_write_mode (const bool read_write) { read_write_mode = read_write; } bool DatabaseConnector::get_read_write_mode () const { return read_write_mode; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dbconnector/databaseConnector.h������������������������������������0000644�0001750�0001750�00000013164�11763437013�021713� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef DATABASECONNECTOR_H #define DATABASECONNECTOR_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "../../core/logger.h" #include <map> #include <vector> #include <string> typedef std::vector<std::string> Ngram; typedef std::vector<Ngram> NgramTable; /** Provides the interface to database creation, updating and querying operations. * */ class DatabaseConnector { public: DatabaseConnector(const std::string database_name, const size_t cardinality, const bool read_write); DatabaseConnector(const std::string database_name, const size_t cardinality, const bool read_write, const std::string& log_level); virtual ~DatabaseConnector(); /** Creates a table to store N-grams. */ void createNgramTable(const size_t cardinality) const; void createUnigramTable() const { createNgramTable(1); } void createBigramTable() const { createNgramTable(2); } void createTrigramTable() const { createNgramTable(3); } /** Returns an integer equal to the sum of the counts of all unigrams. */ int getUnigramCountsSum() const; /** Returns an integer equal to the specified ngram count. */ int getNgramCount(const Ngram ngram) const; /** Returns a table of ngrams matching the specified ngram-like query. */ NgramTable getNgramLikeTable(const Ngram ngram, int limit = -1) const; /** Returns a table of ngrams matching the specified ngram-like query and satisfying the given filter. */ NgramTable getNgramLikeTableFiltered(const Ngram ngram, const char** filter, int limit = -1) const; /** Increments the specified ngram count and returns the updated count. * * If the ngram does not yet exit in the database, it is created * and its count is set to one. */ int incrementNgramCount(const Ngram ngram) const; /** Insert ngram into database and sets its count. */ void insertNgram(const Ngram ngram, const int count) const; /** Updates ngram count. */ void updateNgram(const Ngram ngram, const int count) const; /** Removes the ngram from the database */ void removeNgram(const Ngram ngram) const; /** Marks the beginning of an SQL transaction. * */ virtual void beginTransaction() const; /** Marks the end of an SQL transaction. * */ virtual void endTransaction() const; /** Rolls back an SQL transaction. * */ virtual void rollbackTransaction() const; protected: // Following functions to be overridden by derived classes. virtual void openDatabase() = 0; virtual void closeDatabase() = 0; virtual NgramTable executeSql(const std::string query) const = 0; std::string get_database_filename () const; std::string set_database_filename (const std::string& filename); void set_cardinality (const size_t cardinality); size_t get_cardinality () const; void set_read_write_mode (const bool read_write); bool get_read_write_mode () const; Logger<char> logger; private: /** Returns a string containing the column specifiers for the SQL * SELECT clause built for an ngram of specified cardinality. */ std::string buildSelectLikeClause(const int cardinality) const; /** Returns a string containing an SQL WHERE clause built for the ngram. */ std::string buildWhereClause(const Ngram ngram) const; /** Returns a string containing an SQL WHERE clause built for the ngram, * where the last comparison is a LIKE clauses instead of = clause. */ std::string buildWhereLikeClause(const Ngram ngram) const; /** Same as buildWhereLikeClause but considers also a filter on the subsequent letter */ std::string buildWhereLikeClauseFiltered(const Ngram ngram,const char** filter) const; /** Returns a string containing an SQL VALUES clause built for the ngram. */ std::string buildValuesClause(const Ngram ngram, const int count) const; /** Sanitizes ngram, guards against SQL code injection. */ std::string sanitizeString(const std::string) const; /** Returns the first element of the ngramtable as an integer. */ int extractFirstInteger(const NgramTable&) const; std::string expand_variables (std::string filename) const; void substitute_variable_in_string (const std::string& variable_name, std::string& filepath) const; std::string database_filename; size_t cardinality; bool read_write_mode; }; #endif // DATABASECONNECTOR_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dejavuPredictor.cpp������������������������������������������������0000644�0001750�0001750�00000016445�11763437013�017466� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "dejavuPredictor.h" #include <algorithm> /* * Implementation idea: predictor remembers previously entered text (by * storing it in a config defined file); when current token is found * in the remembered text, the tokens following the current token are * suggested; this requires "learning" previously entered text. * */ DejavuPredictor::DejavuPredictor(Configuration* config, ContextTracker* ct, const char* name) : Predictor(config, ct, name, "DejavuPredictor, a parrot predictor", "DejavuPredictor is a parrot predictor.\n" "It always returns what it has heard before.\n"), dispatcher (this) { LOGGER = PREDICTORS + name + ".LOGGER"; MEMORY = PREDICTORS + name + ".MEMORY"; TRIGGER = PREDICTORS + name + ".TRIGGER"; // build notification dispatch map dispatcher.map (config->find (LOGGER), & DejavuPredictor::set_logger); dispatcher.map (config->find (MEMORY), & DejavuPredictor::set_memory); dispatcher.map (config->find (TRIGGER), & DejavuPredictor::set_trigger); } DejavuPredictor::~DejavuPredictor() {} void DejavuPredictor::set_memory (const std::string& filename) { memory = filename; logger << INFO << "MEMORY: " << filename << endl; } void DejavuPredictor::set_trigger (const std::string& number) { trigger = Utility::toInt (number); logger << INFO << "TRIGGER: " << number << endl; } Prediction DejavuPredictor::predict(const size_t max_partial_predictions_size, const char** filter) const { Prediction result; std::list<std::string> memory_trigger; std::ifstream memory_file(memory.c_str()); if (!memory_file) { logger << ERROR << "Error opening memory file: " << memory << endl; } else { if (init_memory_trigger(memory_trigger)) { logger << INFO << "Memory trigger init'ed" << endl; std::list<std::string> rolling_window; if (init_rolling_window(rolling_window, memory_file)) { logger << INFO << "Rolling window init'ed" << endl; std::string token; while (memory_file >> token) { logger << INFO << "Analyzing token: " << token << endl; if (match(memory_trigger, rolling_window)) { logger << INFO << "Token triggered memory: " << token << endl; if (token_satisfies_filter (token, contextTracker->getPrefix(), filter)) { logger << INFO << "Adding suggestion: " << token << endl; result.addSuggestion(Suggestion(token, 1.0)); } } update_rolling_window(rolling_window, token); } } else { logger << INFO << "Rolling window initialization failed." << endl; } } else { logger << INFO << "Memory trigger initialization failed." << endl; } memory_file.close(); } return result; } void DejavuPredictor::learn(const std::vector<std::string>& change) { // loop through all tokens in change vector for (std::vector<std::string>::const_iterator it = change.begin(); it != change.end(); it++) { std::string new_token = *it; logger << INFO << "Committing new token to memory: " << new_token << endl; std::ofstream memory_file(memory.c_str(), std::ios::app); if (!memory_file) { logger << ERROR << "Error opening memory file: " << memory << endl; } else { memory_file << new_token << std::endl; memory_file.close(); } } } /** Tests two list arguments match. * * @return true if lists contain the same tokens in the same order, * false otherwise */ bool DejavuPredictor::match(const std::list<std::string>& l1, const std::list<std::string>& l2) const { return equal(l1.begin(), l1.end(), l2.begin()); } /** Initialize memory trigger. * * @param memory_trigger contains tokens that will trigger a memory * recollection * * @return true if memory trigger has been populated with enough * tokens to trigger a memory recollection, false otherwise * */ bool DejavuPredictor::init_memory_trigger(std::list<std::string>& memory_trigger) const { bool result = false; // fill up the token window list that contains the tokens that // will trigger a recollection for (int i = trigger; i > 0; i--) { logger << INFO << "Memory trigger list: " << contextTracker->getToken(i) << endl; memory_trigger.push_back(contextTracker->getToken(i)); } // check that the current context is rich enough to trigger a // recollection if (memory_trigger.end() == find(memory_trigger.begin(), memory_trigger.end(), "")) { result = true; } logger << INFO << "Memory trigger valid: " << result << endl; return result; } /** Initialize rolling window. * * @return true if initialized rolling window has been populated with * enough tokens to trigger a memory recollection, false otherwise * */ bool DejavuPredictor::init_rolling_window(std::list<std::string>& rolling_window, std::ifstream& memory_file) const { std::string token; int count = 0; // following while test relies on the fact that if first condition // is true, then the second condition will not be evaluated: in // other words, a token will not be read from file if count is not // less than trigger. while (count < trigger && memory_file >> token) { logger << INFO << "Rolling window list: " << token << endl; rolling_window.push_back(token); count++; } return (count == trigger); } /** Update rolling window. * * Pop front token and push back new token to list. */ void DejavuPredictor::update_rolling_window(std::list<std::string>& rolling_window, const std::string& token) const { rolling_window.pop_front(); logger << INFO << "Pushing back on memory list: " << token << endl; rolling_window.push_back(token); } void DejavuPredictor::update (const Observable* var) { logger << DEBUG << "About to invoke dispatcher: " << var->get_name () << " - " << var->get_value() << endl; dispatcher.dispatch (var); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dictionaryPredictor.h����������������������������������������������0000644�0001750�0001750�00000004150�11763437013�020010� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_DICTIONARYPREDICTOR #define PRESAGE_DICTIONARYPREDICTOR #include "predictor.h" #include "../core/dispatcher.h" #include <fstream> /** Dictionary predictive predictor. * * Generates a prediction by extracting tokens that start with the * current prefix from a given dictionary. * */ class DictionaryPredictor : public Predictor, public Observer { public: DictionaryPredictor (Configuration*, ContextTracker*, const char*); ~DictionaryPredictor(); virtual Prediction predict (const size_t size, const char** filter) const; virtual void learn (const std::vector<std::string>& change); virtual void update (const Observable* variable); void set_dictionary (const std::string& value); void set_probability (const std::string& value); private: std::string LOGGER; std::string DICTIONARY; std::string PROBABILITY; std::string dictionary_path; double probability; Dispatcher<DictionaryPredictor> dispatcher; }; #endif // PRESAGE_DICTIONARYPREDICTOR ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/src/lib/predictors/dictionaryPredictor.cpp��������������������������������������������0000644�0001750�0001750�00000010034�11763437013�020341� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "dictionaryPredictor.h" #include <assert.h> DictionaryPredictor::DictionaryPredictor (Configuration* config, ContextTracker* ht, const char* name) : Predictor(config, ht, name, "DictionaryPredictor, dictionary lookup", "DictionaryPredictor, a dictionary based predictor that generates a prediction by extracting tokens that start with the current prefix from a given dictionary" ), dispatcher (this) { LOGGER = PREDICTORS + name + ".LOGGER"; DICTIONARY = PREDICTORS + name + ".DICTIONARY"; PROBABILITY = PREDICTORS + name + ".PROBABILITY"; // build notification dispatch map dispatcher.map (config->find (LOGGER), & DictionaryPredictor::set_logger); dispatcher.map (config->find (DICTIONARY), & DictionaryPredictor::set_dictionary); dispatcher.map (config->find (PROBABILITY), & DictionaryPredictor::set_probability); } DictionaryPredictor::~DictionaryPredictor() { // intentionally empty } void DictionaryPredictor::set_dictionary (const std::string& value) { dictionary_path = value; logger << INFO << "DICTIONARY: " << value << endl; } void DictionaryPredictor::set_probability (const std::string& value) { probability = Utility::toDouble (value); logger << INFO << "PROBABILITY: " << value << endl; } Prediction DictionaryPredictor::predict(const size_t max_partial_predictions_size, const char** filter) const { Prediction result; std::string candidate; std::string prefix = contextTracker->getPrefix(); std::ifstream dictionary_file; dictionary_file.open(dictionary_path.c_str()); if(!dictionary_file) logger << ERROR << "Error opening dictionary: " << dictionary_path << endl; assert(dictionary_file); // REVISIT: handle with exceptions // scan file entries until we get enough suggestions unsigned int count = 0; while(dictionary_file >> candidate && count < max_partial_predictions_size) { if(candidate.find(prefix) == 0) { // candidate starts with prefix logger << NOTICE << "Found valid token: " << candidate << endl; if (token_satisfies_filter (candidate, prefix, filter)) { logger << NOTICE << "Filter check satisfied by token: " << candidate << endl; result.addSuggestion(Suggestion(candidate,probability)); count++; } else { logger << NOTICE << "Filter check failed, discarding token: " << candidate << endl; } } else { logger << INFO << "Discarding invalid token: " << candidate << endl; } } dictionary_file.close(); return result; } void DictionaryPredictor::learn(const std::vector<std::string>& change) { std::cout << "DictionaryPredictor::learn() method called" << std::endl; std::cout << "DictionaryPredictor::learn() method exited" << std::endl; } void DictionaryPredictor::update (const Observable* var) { logger << DEBUG << "About to invoke dispatcher: " << var->get_name () << " - " << var->get_value() << endl; dispatcher.dispatch (var); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/aclocal.m4����������������������������������������������������������������������������0000644�0001750�0001750�00000142406�11763440350�011750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# generated automatically by aclocal 1.11.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file 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. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],, [m4_warning([this file was generated for autoconf 2.67. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant <scott@netsplit.com>. # # 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # # This file 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file 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. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 # Free Software Foundation, Inc. # # This file 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. # serial 10 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file 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. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file 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. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file 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. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file 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. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file 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. # serial 6 # AM_PROG_CC_C_O # -------------- # Like AC_PROG_CC_C_O, but changed for automake. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file 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. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # # This file 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. # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file 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. # serial 4 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 # Free Software Foundation, Inc. # # This file 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. # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python3 python3.0 python2.5 python2.4 python2.3 python2.2 dnl python2.1 python2.0]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT(yes)], [AC_MSG_ERROR(too old)]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(0,0,prefix='$am_py_prefix'))" 2>/dev/null || echo "$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. distutils does not exist in dnl Python 1.5, so we fall back to the hardcoded directory if it dnl doesn't work. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(1,0,prefix='$am_py_exec_prefix'))" 2>/dev/null || echo "$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file 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. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file 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. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008 Free Software Foundation, Inc. # # This file 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. # serial 2 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # This file 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. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar <conftest.tar]) grep GrepMe conftest.dir/file >/dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/cppunit.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/m4/�����������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714755�010517� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/m4/cppunit.m4�������������������������������������������������������������������������0000644�0001750�0001750�00000006151�11737142176�012356� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl dnl AM_PATH_CPPUNIT(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) dnl AC_DEFUN([AM_PATH_CPPUNIT], [ AC_ARG_WITH(cppunit-prefix,[ --with-cppunit-prefix=PFX Prefix where CppUnit is installed (optional)], cppunit_config_prefix="$withval", cppunit_config_prefix="") AC_ARG_WITH(cppunit-exec-prefix,[ --with-cppunit-exec-prefix=PFX Exec prefix where CppUnit is installed (optional)], cppunit_config_exec_prefix="$withval", cppunit_config_exec_prefix="") if test x$cppunit_config_exec_prefix != x ; then cppunit_config_args="$cppunit_config_args --exec-prefix=$cppunit_config_exec_prefix" if test x${CPPUNIT_CONFIG+set} != xset ; then CPPUNIT_CONFIG=$cppunit_config_exec_prefix/bin/cppunit-config fi fi if test x$cppunit_config_prefix != x ; then cppunit_config_args="$cppunit_config_args --prefix=$cppunit_config_prefix" if test x${CPPUNIT_CONFIG+set} != xset ; then CPPUNIT_CONFIG=$cppunit_config_prefix/bin/cppunit-config fi fi AC_PATH_PROG(CPPUNIT_CONFIG, cppunit-config, no) cppunit_version_min=$1 AC_MSG_CHECKING(for Cppunit - version >= $cppunit_version_min) no_cppunit="" if test "$CPPUNIT_CONFIG" = "no" ; then AC_MSG_RESULT(no) no_cppunit=yes else CPPUNIT_CFLAGS=`$CPPUNIT_CONFIG --cflags` CPPUNIT_LIBS=`$CPPUNIT_CONFIG --libs` cppunit_version=`$CPPUNIT_CONFIG --version` cppunit_major_version=`echo $cppunit_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` cppunit_minor_version=`echo $cppunit_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` cppunit_micro_version=`echo $cppunit_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` cppunit_major_min=`echo $cppunit_version_min | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` if test "x${cppunit_major_min}" = "x" ; then cppunit_major_min=0 fi cppunit_minor_min=`echo $cppunit_version_min | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` if test "x${cppunit_minor_min}" = "x" ; then cppunit_minor_min=0 fi cppunit_micro_min=`echo $cppunit_version_min | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x${cppunit_micro_min}" = "x" ; then cppunit_micro_min=0 fi cppunit_version_proper=`expr \ $cppunit_major_version \> $cppunit_major_min \| \ $cppunit_major_version \= $cppunit_major_min \& \ $cppunit_minor_version \> $cppunit_minor_min \| \ $cppunit_major_version \= $cppunit_major_min \& \ $cppunit_minor_version \= $cppunit_minor_min \& \ $cppunit_micro_version \>= $cppunit_micro_min ` if test "$cppunit_version_proper" = "1" ; then AC_MSG_RESULT([$cppunit_major_version.$cppunit_minor_version.$cppunit_micro_version]) else AC_MSG_RESULT(no) no_cppunit=yes fi fi if test "x$no_cppunit" = x ; then ifelse([$2], , :, [$2]) else CPPUNIT_CFLAGS="" CPPUNIT_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(CPPUNIT_CFLAGS) AC_SUBST(CPPUNIT_LIBS) ]) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/m4/ltoptions.m4�����������������������������������������������������������������������0000644�0001750�0001750�00000027242�11737143276�012735� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file 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. # serial 6 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [0], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/m4/libtool.m4�������������������������������������������������������������������������0000644�0001750�0001750�00000774647�11737143276�012370� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file 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. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 56 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl _LT_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Fix-up fallback echo if it was mangled by the above quoting rules. case \$lt_ECHO in *'\\\[$]0 --fallback-echo"')dnl " lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` ;; esac _LT_OUTPUT_LIBTOOL_INIT ]) # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) cat >"$CONFIG_LT" <<_LTEOF #! $SHELL # Generated by $as_me. # Run this file to recreate a libtool stub with the current configuration. lt_cl_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to <bug-libtool@gnu.org>." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2008 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. if test "$no_create" != yes; then lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) fi ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_XSI_SHELLFNS sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES # -------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(whole_archive_flag_spec, $1)='' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX # ----------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl AC_LINK_IFELSE(AC_LANG_PROGRAM,[ lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. m4_defun([_LT_PROG_ECHO_BACKSLASH], [_LT_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$lt_ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac ECHO=${lt_ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then # Yippee, $ECHO works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat <<_LT_EOF [$]* _LT_EOF exit 0 fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null then break fi done fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL ECHO="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. ECHO=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. lt_ECHO=$ECHO if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(lt_ECHO) ]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that does not interpret backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [AC_CHECK_TOOL(AR, ar, false) test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1]) AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line __oline__ "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` else lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib<name>.so # instead of lib<name>.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[123]]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[[3-9]]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$lt_save_ifs" else lt_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$lt_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) _LT_PATH_LD_GNU AC_SUBST([LD]) _LT_TAGDECL([], [LD], [1], [The linker used to build libraries]) ])# LT_PATH_LD # Old names: AU_ALIAS([AM_PROG_LD], [LT_PATH_LD]) AU_ALIAS([AC_PROG_LD], [LT_PATH_LD]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_LD], []) dnl AC_DEFUN([AC_PROG_LD], []) # _LT_PATH_LD_GNU #- -------------- m4_defun([_LT_PATH_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 </dev/null` in *GNU* | *'with BFD'*) lt_cv_prog_gnu_ld=yes ;; *) lt_cv_prog_gnu_ld=no ;; esac]) with_gnu_ld=$lt_cv_prog_gnu_ld ])# _LT_PATH_LD_GNU # _LT_CMD_RELOAD # -------------- # find reload flag for linker # -- PORTME Some linkers may need a different reload flag. m4_defun([_LT_CMD_RELOAD], [AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag, [lt_cv_ld_reload_flag='-r']) reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac _LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl _LT_DECL([], [reload_cmds], [2])dnl ])# _LT_CMD_RELOAD # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method == "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC*) # IBM XL 8.0 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl*) # IBM XL C 8.0/Fortran 10.1 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Sun\ F*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' ;; linux* | k*bsd*-gnu) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach <jrb3@best.com> says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE(int foo(void) {}, _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' ) LDFLAGS="$save_LDFLAGS" else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then _LT_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], [[If ld is used when linking, flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [fix_srcfile_path], [1], [Fix the shell variable $srcfile for the compiler]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_PROG_CXX # ------------ # Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ # compiler, we have our own version here. m4_defun([_LT_PROG_CXX], [ pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) AC_PROG_CXX if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_CXX dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_CXX], []) # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [AC_REQUIRE([_LT_PROG_CXX])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach <jrb3@best.com> says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[[12]]*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 will use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; xl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=echo else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ]) dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_PROG_F77 # ------------ # Since AC_PROG_F77 is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_F77], [ pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) AC_PROG_F77 if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_F77 dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_F77], []) # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_REQUIRE([_LT_PROG_F77])dnl AC_LANG_PUSH(Fortran 77) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${F77-"f77"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_PROG_FC # ----------- # Since AC_PROG_FC is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_FC], [ pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) AC_PROG_FC if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_FC dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_FC], []) # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_REQUIRE([_LT_PROG_FC])dnl AC_LANG_PUSH(Fortran) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${FC-"f95"} compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC="$lt_save_CC" ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC= CC=${RC-"windres"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC="$lt_save_CC" ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_XSI_SHELLFNS # --------------------- # Bourne and XSI compatible variants of some useful shell functions. m4_defun([_LT_PROG_XSI_SHELLFNS], [case $xsi_shell in yes) cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $[*] )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } _LT_EOF ;; *) # Bourne compatible functions. cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_basename file func_basename () { func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } dnl func_dirname_and_basename dnl A portable version of this function is already defined in general.m4sh dnl so there is no need for it here. # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; esac } # sed scripts: my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' my_sed_long_arg='1s/^-[[^=]]*=//' # func_opt_split func_opt_split () { func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` } # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` } # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` } # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "$[@]"` } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` } _LT_EOF esac case $lt_shell_append in yes) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]+=\$[2]" } _LT_EOF ;; *) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]=\$$[1]\$[2]" } _LT_EOF ;; esac ]) �����������������������������������������������������������������������������������������presage-0.8.8/m4/lt~obsolete.m4���������������������������������������������������������������������0000644�0001750�0001750�00000013113�11737143277�013245� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file 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. # serial 4 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/m4/ltsugar.m4�������������������������������������������������������������������������0000644�0001750�0001750�00000010424�11737143277�012356� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file 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. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/m4/ltversion.m4�����������������������������������������������������������������������0000644�0001750�0001750�00000001277�11737143277�012730� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file 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. # Generated from ltversion.in. # serial 3017 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.2.6b]) m4_define([LT_PACKAGE_REVISION], [1.3017]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.2.6b' macro_revision='1.3017' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/install-sh����������������������������������������������������������������������������0000755�0001750�0001750�00000032537�11737143301�012114� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: �����������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/configure.ac��������������������������������������������������������������������������0000644�0001750�0001750�00000037025�11763440316�012400� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl configure.ac for Presage dnl Presage, an extensible predictive text entry system dnl --------------------------------------------------- dnl dnl Copyright (C) 2012 Matteo Vescovi <matteo.vescovi\@yahoo.co.uk> dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License along dnl with this program; if not, write to the Free Software Foundation, Inc., dnl 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. dnl Process this file with autoconf to produce a configure script. AC_INIT([presage],[0.8.8],[matteo.vescovi@yahoo.co.uk]) AM_INIT_AUTOMAKE([-Wall -Werror]) AC_CONFIG_SRCDIR([src/lib/presage.cpp]) AC_CONFIG_HEADERS([config.h:config.hin]) AC_CONFIG_MACRO_DIR([m4]) dnl Checks for programs. AC_PROG_INSTALL AC_PROG_CXX AC_PROG_CXXCPP AC_PROG_CC AC_PROG_CPP AM_PROG_CC_C_O AC_LANG([C++]) AM_CONDITIONAL([USE_GCC], [test "x$GCC" = "xyes"]) dnl ================== dnl Checks for libtool dnl ================== LT_INIT([win32-dll]) dnl ============================ dnl Checks for ld version script dnl ============================ AC_MSG_CHECKING([whether linker supports version scripts]) cat > conftest.map <<EOF VERSION_1 { global: main; local: *; }; VERSION_2 { global: main; hello_world; } VERSION_1; EOF save_ldflags="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--version-script,conftest.map" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[const char hello_world[] = "Hello, World\n";]], [[]])], [have_ld_with_version_script=yes], [have_ld_with_version_script=no] ) LDFLAGS="$save_ldflags" if test "x$have_ld_with_version_script" = "xyes" then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) AC_MSG_WARN([Linker does not support version scripts.]) fi AM_CONDITIONAL([HAVE_LD_WITH_VERSION_SCRIPT], [test "x$have_ld_with_version_script" = "xyes"]) dnl Cygwin windows specific flag LDFLAGS="-L/usr/local/lib $LDFLAGS" dnl ==================== dnl Checks for libraries dnl ==================== dnl ======================= dnl Checks for header files dnl ======================= AC_HEADER_STDC AC_HEADER_DIRENT AC_CHECK_HEADERS([pwd.h]) dnl ================== dnl Checks for ncurses dnl ================== AC_CHECK_LIB([curses], [initscr], [have_curses_library=true], [AC_MSG_WARN([curses library not found. curses demo programs will not be built.])]) AC_CHECK_HEADERS([curses.h], [have_curses_header=true], [AC_MSG_WARN([curses header file not found. curses demo programs will not be built.])], []) AM_CONDITIONAL([HAVE_CURSES], [test "x$have_curses_library" = "xtrue" -a "x$have_curses_header" = "xtrue"]) dnl ================== dnl Checks for tinyxml dnl ================== AC_CHECK_LIB([tinyxml], [main], [have_tinyxml_library=true], [AC_MSG_WARN([tinyxml library not found. Embedded tinyxml library will be built.])]) AC_CHECK_HEADERS([tinyxml.h], [have_tinyxml_header=true], [AC_MSG_WARN([tinyxml library not found. Embedded tinyxml library will be built.])], []) if test "x$have_tinyxml_library" != "xtrue" -o "x$have_tinyxml_header" != "xtrue" then build_tinyxml=yes else build_tinyxml=no AC_DEFINE([TIXML_USE_STL], [1], [Define to 1 to use STL string in TinyXML]) fi AM_CONDITIONAL([BUILD_TINYXML], [test "x$build_tinyxml" = "xyes"]) dnl ================= dnl Checks for SQLite dnl ================= AC_ARG_ENABLE([sqlite], AS_HELP_STRING([--disable-sqlite],[disable use of SQLite (default: enabled)]), [enable_sqlite=$enableval], [enable_sqlite=yes]) dnl check for libsqlite3 dnl if (libsqlite3 found) { dnl set SQLITE_LIBS to -lsqlite3 dnl check for sqlite3.h dnl if (sqlite3.h found) { dnl using sqlite3 dnl } else { dnl error dnl } dnl } else { dnl check for libsqlite2 dnl if (libsqlite2 found) { dnl set SQLITE_LIBS to -lsqlite dnl check for sqlite2.h dnl if (sqlite2.h found) { dnl using sqlite2 dnl } else dnl error dnl } dnl } else { dnl error dnl } dnl } if test "x$enable_sqlite" = "xyes" then AC_CHECK_LIB([sqlite3], [sqlite3_open], [SQLITE_LIBS="-lsqlite3" && \ AC_CHECK_HEADERS([sqlite3.h], [have_sqlite=yes && AC_MSG_NOTICE([using sqlite 3])], [AC_MSG_ERROR([Found sqlite3 library, but cannot find matching sqlite3.h header.])], [])], [AC_CHECK_LIB([sqlite], [sqlite_open], [SQLITE_LIBS="-lsqlite" && \ AC_CHECK_HEADERS([sqlite.h], [have_sqlite=yes && AC_MSG_NOTICE([using sqlite 2])], [AC_MSG_ERROR([Found sqlite 2 library, but cannot find matching sqlite.h header.])], [])], [SQLITE_LIBS= && \ have_sqlite=no && \ AC_MSG_ERROR([SQLite library not found. SQLite can be obtained from http://sqlite.org.])])]) AC_SUBST([SQLITE_LIBS], ["$SQLITE_LIBS"]) fi if test "x$enable_sqlite" = "xyes" -a "x$have_sqlite" = "xyes" then use_sqlite=yes AC_DEFINE([USE_SQLITE], [1], [Define to 1 if you want to use SQLite]) else use_sqlite=no fi AM_CONDITIONAL([USE_SQLITE], [test "x$use_sqlite" = "xyes"]) dnl ================== dnl Checks for CppUnit dnl ================== AM_PATH_CPPUNIT([1.9.6], [], [AC_MSG_WARN([CppUnit not found. Unit tests will not be built. CppUnit can be obtained from http://cppunit.sourceforge.net.])]) AM_CONDITIONAL([HAVE_CPPUNIT], [test "$CPPUNIT_LIBS"]) dnl ============================ dnl Bindings for other languages dnl == dnl =============== dnl Checks for SWIG dnl =============== AC_PATH_PROG([SWIG], [swig]) if test ! "$SWIG" then AC_PATH_PROG([SWIG], [swig2.0]) fi AM_CONDITIONAL([HAVE_SWIG], [test "$SWIG"]) dnl ================= dnl Checks for Python dnl ================= AM_PATH_PYTHON([2.0], [], [AC_MSG_WARN([Python not found. Python is required to build presage python binding. Python can be obtained from http://www.python.org])]) if test "$PYTHON" then python_include_path=`$PYTHON -c "import distutils.sysconfig; print distutils.sysconfig.get_python_inc();"` AC_CHECK_HEADERS([${python_include_path}/Python.h], [have_python_header=true], [AC_MSG_WARN([Python.h header file not found. Python development files are required to build presage python binding. Python can be obtained from http://www.python.org])], []) fi AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" -a "x$have_python_header" = "xtrue"]) AC_ARG_ENABLE([python-binding], AS_HELP_STRING([--disable-python-binding], [build python binding (default=enabled)]), [ac_enable_python_binding=$enableval], [ac_enable_python_binding=yes]) if test "x$ac_enable_python_binding" = "xyes" then if test ! "$SWIG" -o ! "$PYTHON" -o ! "x$have_python_header" = "xtrue" then AC_MSG_WARN([Python binding for presage cannot be built. Ensure that SWIG and Python packages are available.]) fi else AC_MSG_NOTICE([Python binding for presage will not be built.]) AC_MSG_NOTICE([Enable Python binding module building with --enable-python-binding]) fi AM_CONDITIONAL([ENABLE_PYTHON_BINDING], [test "x$ac_enable_python_binding" = "xyes"]) dnl ====================== dnl Checks for dbus python dnl ====================== have_dbus_python=no AC_MSG_CHECKING(for python dbus module) $PYTHON -c "import dbus" 2&>/dev/null if test $? -eq 0; then have_dbus_python=yes else have_dbus_python=no fi AC_MSG_RESULT($have_dbus_python) AM_CONDITIONAL([HAVE_DBUS_PYTHON], [test "x$have_dbus_python" = "xyes"]) dnl ======================== dnl Checks for documentation dnl ======================== AC_ARG_ENABLE([documentation], AS_HELP_STRING([--disable-documentation],[disable documentation generation (default: enabled)]), [enable_documentation=$enableval], [enable_documentation=yes]) AM_CONDITIONAL([BUILD_DOCUMENTATION], [test "x$enable_documentation" = "xyes"]) dnl =================== dnl Checks for unix2dos dnl =================== AC_PATH_PROG([UNIX2DOS], [unix2dos]) AM_CONDITIONAL([HAVE_UNIX2DOS], [test "$UNIX2DOS"]) dnl ================== dnl Checks for Doxygen dnl ================== AC_CHECK_PROG([HAVE_DOXYGEN], [doxygen], [yes], [no]) if test "x$HAVE_DOXYGEN" = "xno" then AC_MSG_NOTICE([Doxygen not found. API documentation will not be built.]) fi AM_CONDITIONAL([HAVE_DOXYGEN], [test "x$HAVE_DOXYGEN" = "xyes"]) if test "x$enable_documentation" = "xyes" -a "x$HAVE_DOXYGEN" = "xyes" then build_documentation=yes else build_documentation=no fi dnl ============== dnl Checks for dot dnl ============== AC_CHECK_PROG([HAVE_DOT], [dot], [yes], [no]) if test "x$HAVE_DOT" = "xno" then AC_MSG_NOTICE([dot not found. Documentation graphs and diagrams will not be generated.]) fi AC_SUBST([HAVE_DOT], ["$HAVE_DOT"]) if test "x$enable_documentation" = "xyes" -a "x$HAVE_DOXYGEN" = "xyes" -a "x$HAVE_DOT" = "xyes" then build_documentation_diagrams=yes else build_documentation_diagrams=no fi dnl =================== dnl Checks for help2man dnl =================== AC_CHECK_PROG([HAVE_HELP2MAN], [help2man], [yes], [no]) if test "x$HAVE_HELP2MAN" = "xno" then AC_MSG_NOTICE([help2man not found. Man documentation pages will not be built.]) fi AM_CONDITIONAL([HAVE_HELP2MAN], [test "x$HAVE_HELP2MAN" = "xyes"]) dnl ==================== dnl Checks for GTK tools dnl ==================== AC_ARG_ENABLE([gpresagemate], AS_HELP_STRING([--disable-gpresagemate],[build gpresagemate (default: enabled)]), [enable_gpresagemate=$enableval], [enable_gpresagemate=yes]) AC_ARG_ENABLE([gprompter], AS_HELP_STRING([--disable-gprompter],[build gprompter (default: enabled)]), [enable_gprompter=$enableval], [enable_gprompter=yes]) if test "x$enable_gpresagemate" = "xyes" then AC_CHECK_HEADERS([X11/Xlib.h X11/Xproto.h X11/X.h X11/Xutil.h X11/keysymdef.h pthread.h], [have_x11_headers=yes], [have_x11_headers=no], []) AC_CHECK_HEADERS([X11/extensions/Xevie.h], [have_x11_extension_xevie=yes], [have_x11_extension_xevie=no], [[#if HAVE_X11_XLIB_H # include <X11/Xlib.h> #endif]]) fi if test "x$enable_gpresagemate" = "xyes" -o "x$enable_gprompter" = "xyes" then PKG_CHECK_MODULES([GNOME], [gtk+-2.0], [have_gtk=yes], [have_gtk=no]) AC_SUBST([GNOME_CFLAGS]) AC_SUBST([GNOME_LIBS]) PKG_CHECK_MODULES([GTHREAD], [gthread-2.0], [have_gthread=yes], [have_gthread=no]) AC_SUBST([GTHREAD_CFLAGS]) AC_SUBST([GTHREAD_LIBS]) fi if test "x$enable_gpresagemate" = "xyes" -a \ "x$have_x11_headers" = "xyes" -a \ "x$have_x11_extension_xevie" = "xyes" -a \ "x$have_gtk" = "xyes" -a \ "x$have_gthread" = "xyes" then build_gtk_presage_mate=yes else build_gtk_presage_mate=no fi AM_CONDITIONAL([BUILD_GTK_PRESAGE_MATE], [test "x$build_gtk_presage_mate" = "xyes"]) if test "x$enable_gprompter" = "xyes" -a \ "x$have_gtk" = "xyes" -a \ "x$have_gthread" = "xyes" then build_gtk_prompter=yes else build_gtk_prompter=no fi AM_CONDITIONAL([BUILD_GTK_PROMPTER], [test "x$build_gtk_prompter" = "xyes"]) dnl =================================================== dnl Checks for CMU-Statistical Language Modelling tools dnl =================================================== AC_PATH_PROG([TEXT2WFREQ], [text2wfreq]) AC_PATH_PROG([TEXT2IDNGRAM], [text2idngram]) AC_PATH_PROG([WFREQ2VOCAB], [wfreq2vocab]) AC_PATH_PROG([IDNGRAM2LM], [idngram2lm]) if test "$TEXT2WFREQ" -a \ "$WFREQ2VOCAB" -a \ "$IDNGRAM2LM" -a \ "$TEXT2IDNGRAM" then build_arpa_ngram_resources=yes else build_arpa_ngram_resources=no AC_MSG_NOTICE([CMU-Cambridge SLM tools not found. ARPA ngram language model will not be built.]) fi AM_CONDITIONAL([BUILD_ARPA_NGRAM], [test "x$build_arpa_ngram_resources" = "xyes"]) ############################ # Temporarily disabling this #AC_CONFIG_SUBDIRS(src/plump) AC_CONFIG_FILES([ Makefile src/Makefile src/lib/Makefile src/lib/core/Makefile src/lib/core/tokenizer/Makefile src/lib/core/context_tracker/Makefile src/lib/tinyxml/Makefile src/lib/predictors/Makefile src/lib/predictors/dbconnector/Makefile src/tools/Makefile src/tools/simulator/Makefile test/Makefile test/lib/Makefile test/lib/common/Makefile test/lib/core/Makefile test/lib/core/tokenizer/Makefile test/lib/core/context_tracker/Makefile test/lib/predictors/Makefile test/lib/predictors/dbconnector/Makefile test/tools/Makefile test/integration/Makefile resources/Makefile resources/arpa/Makefile resources/profiles/Makefile bindings/Makefile bindings/c/Makefile bindings/python/setup.py bindings/python/Makefile apps/Makefile apps/gtk/Makefile apps/gtk/gpresagemate/Makefile apps/gtk/gprompter/Makefile apps/python/Makefile apps/python/pyprompter apps/python/pypresagemate apps/python/setup.py apps/dbus/Makefile apps/dbus/setup.py apps/dbus/presage_dbus_python_demo doc/Doxyfile doc/Makefile bindings/python/presage_python_demo ]) AC_OUTPUT if test "x$have_curses_library" = "xtrue" -a "x$have_curses_header" = "xtrue" then build_demo_application="yes" else build_demo_application="no" fi if test "$CPPUNIT_LIBS" then build_unit_tests="yes" else build_unit_tests="no" fi if test "$SWIG" -a "$PYTHON" -a "x$have_python_header" = "xtrue" -a "x$ac_enable_python_binding" = "xyes" then build_python_binding="yes" else build_python_binding="no" fi AC_MSG_RESULT([ $PACKAGE $VERSION configured successfully. General configuration: Compiler: ................... ${CXX} Curses demo application: .... ${build_demo_application} Unit tests: ................. ${build_unit_tests} Python binding: ............. ${build_python_binding} Man pages: .................. ${HAVE_HELP2MAN} API documentation: .......... ${build_documentation} API documentation diagrams: . ${build_documentation_diagrams} Predictors: Smoothed n-gram: ............ ${use_sqlite} Recency promotion: .......... yes Abbreviation expansion: ..... yes Smoothed count: ............. ${use_sqlite} Dictionary: ................. yes Deja-vu: .................... yes ARPA: ....................... yes Additional applications: wxPython prompter: .......... ${build_python_binding} GTK+ presage mate: .......... ${build_gtk_presage_mate} GTK+ prompter: .............. ${build_gtk_prompter} D-BUS presage service: ...... ${have_dbus_python} Additional resources: ARPA format ngram: .......... ${build_arpa_ngram_resources} Building: Type `make' to build $PACKAGE. Type `make check' to test $PACKAGE. Type `make install' to install $PACKAGE. ]) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/Makefile.am���������������������������������������������������������������������������0000644�0001750�0001750�00000006657�11737142176�012161� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # --------------------------------------------------- # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = src test resources bindings apps doc BUILT_SOURCES = dirs.h CLEANFILES = dirs.h dirs.h: Makefile @echo_win_native () { \ location="$$1"; \ unix_path="$$2"; \ \ native_windows_path="`mkdir -p $$unix_path && cd $$unix_path && pwd -W`"; \ native_windows_path="`echo $$native_windows_path | sed -e 's|/|\\\\\\\\|g'`"; \ \ echo "#define $$location \"$$native_windows_path\"" >> $@; \ }; \ \ case "`uname`" in \ MINGW*) \ echo "// $@ generated by Makefile" > $@; \ echo_win_native "prefix" "$(prefix)"; \ echo_win_native "bindir" "$(bindir)"; \ echo_win_native "libdir" "$(libdir)"; \ echo_win_native "sysconfdir" "$(sysconfdir)"; \ echo_win_native "datadir" "$(datadir)"; \ echo_win_native "pkgdatadir" "$(pkgdatadir)"; \ echo_win_native "localstatedir" "$(localstatedir)"; \ ;; \ *) \ echo "// $@ generated by Makefile" > $@; \ echo '#define prefix "$(prefix)"' >> $@; \ echo '#define bindir "$(bindir)"' >> $@; \ echo '#define libdir "$(libdir)"' >> $@; \ echo '#define sysconfdir "$(sysconfdir)"' >> $@; \ echo '#define datadir "$(datadir)"' >> $@; \ echo '#define pkgdatadir "$(pkgdatadir)"' >> $@; \ echo '#define localstatedir "$(localstatedir)"' >> $@; \ ;; \ esac; EXTRA_DIST = FAQ # Ensure local m4 macros are included during autoreconf and automatic # aclocal.m4 remaking ACLOCAL_AMFLAGS = -I m4 # Build Debian package debian: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.tar.gz ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.tar.bz2 ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.tar.Z ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.shar.gz ;;\ *.zip*) \ unzip $(distdir).zip && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.zip ;;\ esac mkdir $(distdir)/debian cp -R $(srcdir)/debian/* $(distdir)/debian/ (cd $(distdir) && \ dpkg-buildpackage -us -uc -rfakeroot) debiancheck: @echo @echo "==== Begin lintian check ====" lintian $(PACKAGE)_$(VERSION)*.changes @echo "==== End lintian check ====" debianclean: rm -f *.deb rm -f $(PACKAGE)_$(VERSION)*.dsc rm -f $(PACKAGE)_$(VERSION)*.changes rm -f $(PACKAGE)_$(VERSION).orig.* rm -f $(PACKAGE)_$(VERSION)*.diff.* ���������������������������������������������������������������������������������presage-0.8.8/config.sub����������������������������������������������������������������������������0000755�0001750�0001750�00000103445�11737143301�012070� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 # Free Software Foundation, Inc. timestamp='2010-01-22' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to <config-patches@gnu.org>. Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | ubicom32 \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile-* | tilegx-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; # This must be matched before tile*. tilegx*) basic_machine=tilegx-unknown os=-linux-gnu ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/���������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�011157� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/tools/���������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�012317� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/tools/Makefile.am����������������������������������������������������������������0000644�0001750�0001750�00000002453�11737142176�014266� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if HAVE_CPPUNIT TESTS = toolsTestRunner check_PROGRAMS = $(TESTS) toolsTestRunner_SOURCES = toolsTestRunner.cpp \ nGramTest.h nGramTest.cpp toolsTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) toolsTestRunner_LDFLAGS = $(CPPUNIT_LIBS) toolsTestRunner_LDADD = $(top_builddir)/src/tools/libtools.la toolsTestRunner_CPPFLAGS = -I$(top_srcdir)/src endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/tools/nGramTest.h����������������������������������������������������������������0000644�0001750�0001750�00000003425�11737142176�014307� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_NGRAMTEST #define PRESAGE_NGRAMTEST #include <cppunit/extensions/HelperMacros.h> #include "tools/ngram.h" class NgramTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testConstructor(); void testLessOperator(); void testToString(); private: Ngram* unigramFoo; Ngram* unigramBar; Ngram* bigramFooBar; Ngram* bigramBarFoo; Ngram* trigramFooBarFoobar; Ngram* trigramBarFooBarfoo; CPPUNIT_TEST_SUITE( NgramTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testLessOperator); CPPUNIT_TEST( testToString ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_NGRAMTEST �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/tools/nGramTest.cpp��������������������������������������������������������������0000644�0001750�0001750�00000005420�11737142176�014637� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "nGramTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( NgramTest ); void NgramTest::setUp() { unigramFoo = new Ngram(1); unigramFoo->setNgram(0, "foo"); unigramBar = new Ngram(1); unigramBar->setNgram(0, "bar"); bigramFooBar = new Ngram(2); bigramFooBar->setNgram(0, "foo"); bigramFooBar->setNgram(1, "bar"); bigramBarFoo = new Ngram(2); bigramBarFoo->setNgram(0, "bar"); bigramBarFoo->setNgram(1, "foo"); trigramFooBarFoobar = new Ngram(3); trigramFooBarFoobar->setNgram(0, "foo"); trigramFooBarFoobar->setNgram(1, "bar"); trigramFooBarFoobar->setNgram(2, "foobar"); trigramBarFooBarfoo = new Ngram(3); trigramBarFooBarfoo->setNgram(0, "bar"); trigramBarFooBarfoo->setNgram(1, "foo"); trigramBarFooBarfoo->setNgram(2, "barfoo"); } void NgramTest::tearDown() { delete unigramFoo; delete unigramBar; delete bigramFooBar; delete bigramBarFoo; delete trigramFooBarFoobar; delete trigramBarFooBarfoo; } void NgramTest::testConstructor() {} void NgramTest::testLessOperator() { CPPUNIT_ASSERT( *unigramBar < *unigramFoo ); CPPUNIT_ASSERT( *bigramBarFoo < *bigramFooBar ); CPPUNIT_ASSERT( *trigramBarFooBarfoo < *trigramFooBarFoobar ); } void NgramTest::testToString() { CPPUNIT_ASSERT( "<foo> " == unigramFoo->toString() ); CPPUNIT_ASSERT( "<bar> " == unigramBar->toString() ); CPPUNIT_ASSERT( "<foo> <bar> " == bigramFooBar->toString() ); CPPUNIT_ASSERT( "<bar> <foo> " == bigramBarFoo->toString() ); CPPUNIT_ASSERT( "<foo> <bar> <foobar> " == trigramFooBarFoobar->toString() ); CPPUNIT_ASSERT( "<bar> <foo> <barfoo> " == trigramBarFooBarfoo->toString() ); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/tools/toolsTestRunner.cpp��������������������������������������������������������0000644�0001750�0001750�00000002661�11737142176�016131� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> int main() { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest( registry.makeTest() ); bool success = runner.run(); return success ? 0 : 1; } �������������������������������������������������������������������������������presage-0.8.8/test/tools/Makefile.in����������������������������������������������������������������0000644�0001750�0001750�00000060114�11763440356�014275� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_CPPUNIT_TRUE@TESTS = toolsTestRunner$(EXEEXT) @HAVE_CPPUNIT_TRUE@check_PROGRAMS = $(am__EXEEXT_1) subdir = test/tools DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_CPPUNIT_TRUE@am__EXEEXT_1 = toolsTestRunner$(EXEEXT) am__toolsTestRunner_SOURCES_DIST = toolsTestRunner.cpp nGramTest.h \ nGramTest.cpp @HAVE_CPPUNIT_TRUE@am_toolsTestRunner_OBJECTS = \ @HAVE_CPPUNIT_TRUE@ toolsTestRunner-toolsTestRunner.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ toolsTestRunner-nGramTest.$(OBJEXT) toolsTestRunner_OBJECTS = $(am_toolsTestRunner_OBJECTS) @HAVE_CPPUNIT_TRUE@toolsTestRunner_DEPENDENCIES = \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/tools/libtools.la toolsTestRunner_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) \ $(toolsTestRunner_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(toolsTestRunner_SOURCES) DIST_SOURCES = $(am__toolsTestRunner_SOURCES_DIST) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @HAVE_CPPUNIT_TRUE@toolsTestRunner_SOURCES = toolsTestRunner.cpp \ @HAVE_CPPUNIT_TRUE@ nGramTest.h nGramTest.cpp @HAVE_CPPUNIT_TRUE@toolsTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@toolsTestRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@toolsTestRunner_LDADD = $(top_builddir)/src/tools/libtools.la @HAVE_CPPUNIT_TRUE@toolsTestRunner_CPPFLAGS = -I$(top_srcdir)/src all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/tools/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/tools/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list toolsTestRunner$(EXEEXT): $(toolsTestRunner_OBJECTS) $(toolsTestRunner_DEPENDENCIES) @rm -f toolsTestRunner$(EXEEXT) $(toolsTestRunner_LINK) $(toolsTestRunner_OBJECTS) $(toolsTestRunner_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/toolsTestRunner-nGramTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/toolsTestRunner-toolsTestRunner.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< toolsTestRunner-toolsTestRunner.o: toolsTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT toolsTestRunner-toolsTestRunner.o -MD -MP -MF $(DEPDIR)/toolsTestRunner-toolsTestRunner.Tpo -c -o toolsTestRunner-toolsTestRunner.o `test -f 'toolsTestRunner.cpp' || echo '$(srcdir)/'`toolsTestRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/toolsTestRunner-toolsTestRunner.Tpo $(DEPDIR)/toolsTestRunner-toolsTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='toolsTestRunner.cpp' object='toolsTestRunner-toolsTestRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o toolsTestRunner-toolsTestRunner.o `test -f 'toolsTestRunner.cpp' || echo '$(srcdir)/'`toolsTestRunner.cpp toolsTestRunner-toolsTestRunner.obj: toolsTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT toolsTestRunner-toolsTestRunner.obj -MD -MP -MF $(DEPDIR)/toolsTestRunner-toolsTestRunner.Tpo -c -o toolsTestRunner-toolsTestRunner.obj `if test -f 'toolsTestRunner.cpp'; then $(CYGPATH_W) 'toolsTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/toolsTestRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/toolsTestRunner-toolsTestRunner.Tpo $(DEPDIR)/toolsTestRunner-toolsTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='toolsTestRunner.cpp' object='toolsTestRunner-toolsTestRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o toolsTestRunner-toolsTestRunner.obj `if test -f 'toolsTestRunner.cpp'; then $(CYGPATH_W) 'toolsTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/toolsTestRunner.cpp'; fi` toolsTestRunner-nGramTest.o: nGramTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT toolsTestRunner-nGramTest.o -MD -MP -MF $(DEPDIR)/toolsTestRunner-nGramTest.Tpo -c -o toolsTestRunner-nGramTest.o `test -f 'nGramTest.cpp' || echo '$(srcdir)/'`nGramTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/toolsTestRunner-nGramTest.Tpo $(DEPDIR)/toolsTestRunner-nGramTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='nGramTest.cpp' object='toolsTestRunner-nGramTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o toolsTestRunner-nGramTest.o `test -f 'nGramTest.cpp' || echo '$(srcdir)/'`nGramTest.cpp toolsTestRunner-nGramTest.obj: nGramTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT toolsTestRunner-nGramTest.obj -MD -MP -MF $(DEPDIR)/toolsTestRunner-nGramTest.Tpo -c -o toolsTestRunner-nGramTest.obj `if test -f 'nGramTest.cpp'; then $(CYGPATH_W) 'nGramTest.cpp'; else $(CYGPATH_W) '$(srcdir)/nGramTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/toolsTestRunner-nGramTest.Tpo $(DEPDIR)/toolsTestRunner-nGramTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='nGramTest.cpp' object='toolsTestRunner-nGramTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(toolsTestRunner_CPPFLAGS) $(CPPFLAGS) $(toolsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o toolsTestRunner-nGramTest.obj `if test -f 'nGramTest.cpp'; then $(CYGPATH_W) 'nGramTest.cpp'; else $(CYGPATH_W) '$(srcdir)/nGramTest.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool ctags \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am # 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: ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/Makefile.am����������������������������������������������������������������������0000644�0001750�0001750�00000002307�11737142176�013124� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = lib tools integration if HAVE_CPPUNIT TESTS = testRunner check_PROGRAMS = $(TESTS) testRunner_SOURCES = testRunner.cpp testRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) testRunner_LDFLAGS = $(CPPUNIT_LIBS) AM_CPPFLAGS = -I$(top_srcdir)/src endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/integration/���������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�013502� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/integration/integration.sh�������������������������������������������������������0000755�0001750�0001750�00000007252�11743227551�016277� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #### # Integration tests # TEXT2NGRAM=../../src/tools/text2ngram SIMULATOR=../../src/tools/presage_simulator TRAINING_CORPUS=${srcdir}/../../COPYING CONTROL_CORPUS=`basename ${TRAINING_CORPUS}_excerpt.txt` CONFIG_TEMPLATE=${srcdir}/../../resources/profiles/presage.xml.template CONFIG=presage.xml NGRAM_CARDINALITY=3 DATABASE=database.db ERROR_CODE=1 #### # Generate resources for statistical predictive plugins # # arg1 n-gram order of statistical resources # arg2 database name generate_resources() { if [ -z "$1" -o -z "$2" ] then echo "Error: generate_resources() requires two arguments" exit $ERROR_CODE fi i=1 while [ "$i" -le "$1" ] do execute "$TEXT2NGRAM -o $DATABASE -n $i -f sqlite -l $2" i=`expr $i + 1` done } #### # Tweak configuration file # generate_config() { # # use generate_presage_config script from src/resources/profiles # ${srcdir}/../../resources/profiles/generate_presage_config.sh ${srcdir}/../../resources/profiles/presage.xml.template presage.xml . # cp -f ${CONFIG_TEMPLATE} ${CONFIG} replace_config_entry PREDICTORS DefaultSmoothedNgramPredictor replace_config_entry DBFILENAME ${DATABASE} NGRAM_DELTAS="" COUNTER=1 DELTA=10 while [ "$COUNTER" -le "$NGRAM_CARDINALITY" ] do NGRAM_DELTAS="${NGRAM_DELTAS} ${DELTA}" DELTA=`expr ${DELTA} \* 10` COUNTER=`expr $COUNTER + 1` done replace_config_entry DELTAS "${NGRAM_DELTAS}" } replace_config_entry() { rm -f ${CONFIG}.tmp sed -e "s|<$1>.*</$1>|<$1>$2</$1>|" ${CONFIG} > ${CONFIG}.tmp mv -f ${CONFIG}.tmp ${CONFIG} } #### # Restore configuration file # restore_config() { rm -f ${CONFIG} ${CONFIG}.bak } #### # Generate control corpus # generate_control_corpus() { # just extract some text from the training # corpus for the time being # REVISIT cat $TRAINING_CORPUS | head -n 20 | tail -n 10 > $CONTROL_CORPUS } #### # simulate # # arg1 control corpus file # simulate() { if [ -z "$1" ] then echo "Error: simulate requires an argument" exit $ERROR_CODE else execute "$SIMULATOR -i -q -c $CONFIG $CONTROL_CORPUS" fi } #### # execute() # # arg1 command line argument to execute # execute() { if [ -z "$1" ] then echo "Error: invoked execute() with no argument." exit $ERROR_CODE else $1 if [ $? -ne 0 ] then echo "Error executing command: $1" exit $ERROR_CODE fi fi } #### # clean_up() # # cleans up after itself # clean_up() { if [ -f "$DATABASE" ] then rm $DATABASE fi if [ -f "$CONTROL_CORPUS" ] then rm $CONTROL_CORPUS fi } #### # Mainline # clean_up generate_config generate_resources $NGRAM_CARDINALITY $TRAINING_CORPUS generate_control_corpus simulate $CONTROL_CORPUS restore_config clean_up ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/integration/Makefile.am����������������������������������������������������������0000644�0001750�0001750�00000002063�11737142176�015446� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in TESTS_ENVIRONMENT = $(SHELL) -x if USE_SQLITE TESTS = integration.sh endif EXTRA_DIST = integration.sh�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/integration/Makefile.in����������������������������������������������������������0000644�0001750�0001750�00000033754�11763440355�015471� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = test/integration DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ TESTS_ENVIRONMENT = $(SHELL) -x @USE_SQLITE_TRUE@TESTS = integration.sh EXTRA_DIST = integration.sh all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/integration/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/integration/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: CTAGS CTAGS: check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: all all-am check check-TESTS check-am clean clean-generic \ clean-libtool distclean distclean-generic distclean-libtool \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ uninstall uninstall-am # 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: ��������������������presage-0.8.8/test/Makefile.in����������������������������������������������������������������������0000644�0001750�0001750�00000064315�11763440355�013143� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_CPPUNIT_TRUE@TESTS = testRunner$(EXEEXT) @HAVE_CPPUNIT_TRUE@check_PROGRAMS = $(am__EXEEXT_1) subdir = test DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_CPPUNIT_TRUE@am__EXEEXT_1 = testRunner$(EXEEXT) am__testRunner_SOURCES_DIST = testRunner.cpp @HAVE_CPPUNIT_TRUE@am_testRunner_OBJECTS = \ @HAVE_CPPUNIT_TRUE@ testRunner-testRunner.$(OBJEXT) testRunner_OBJECTS = $(am_testRunner_OBJECTS) testRunner_LDADD = $(LDADD) testRunner_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(testRunner_CXXFLAGS) \ $(CXXFLAGS) $(testRunner_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(testRunner_SOURCES) DIST_SOURCES = $(am__testRunner_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = lib tools integration @HAVE_CPPUNIT_TRUE@testRunner_SOURCES = testRunner.cpp @HAVE_CPPUNIT_TRUE@testRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@testRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@AM_CPPFLAGS = -I$(top_srcdir)/src all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list testRunner$(EXEEXT): $(testRunner_OBJECTS) $(testRunner_DEPENDENCIES) @rm -f testRunner$(EXEEXT) $(testRunner_LINK) $(testRunner_OBJECTS) $(testRunner_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testRunner-testRunner.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< testRunner-testRunner.o: testRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testRunner_CXXFLAGS) $(CXXFLAGS) -MT testRunner-testRunner.o -MD -MP -MF $(DEPDIR)/testRunner-testRunner.Tpo -c -o testRunner-testRunner.o `test -f 'testRunner.cpp' || echo '$(srcdir)/'`testRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/testRunner-testRunner.Tpo $(DEPDIR)/testRunner-testRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testRunner.cpp' object='testRunner-testRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testRunner_CXXFLAGS) $(CXXFLAGS) -c -o testRunner-testRunner.o `test -f 'testRunner.cpp' || echo '$(srcdir)/'`testRunner.cpp testRunner-testRunner.obj: testRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testRunner_CXXFLAGS) $(CXXFLAGS) -MT testRunner-testRunner.obj -MD -MP -MF $(DEPDIR)/testRunner-testRunner.Tpo -c -o testRunner-testRunner.obj `if test -f 'testRunner.cpp'; then $(CYGPATH_W) 'testRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/testRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/testRunner-testRunner.Tpo $(DEPDIR)/testRunner-testRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testRunner.cpp' object='testRunner-testRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testRunner_CXXFLAGS) $(CXXFLAGS) -c -o testRunner-testRunner.obj `if test -f 'testRunner.cpp'; then $(CYGPATH_W) 'testRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/testRunner.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool ctags \ ctags-recursive distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-recursive uninstall uninstall-am # 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: �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/testRunner.cpp�������������������������������������������������������������������0000644�0001750�0001750�00000002661�11737142176�013750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> int main() { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest( registry.makeTest() ); bool success = runner.run(); return success ? 0 : 1; } �������������������������������������������������������������������������������presage-0.8.8/test/lib/�����������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�011725� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/Makefile.am������������������������������������������������������������������0000644�0001750�0001750�00000001754�11743227551�013675� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = common core predictors ��������������������presage-0.8.8/test/lib/core/������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�012655� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/profileTest.cpp���������������������������������������������������������0000644�0001750�0001750�00000006457�11737142176�015604� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "profileTest.h" #ifdef STDC_HEADERS # include <stdlib.h> // for getenv() #endif CPPUNIT_TEST_SUITE_REGISTRATION( ProfileTest ); void ProfileTest::setUp() { std::string profileFile = static_cast<std::string>(getenv("srcdir")) + '/' + "profileTest.xml"; profile = new Profile(profileFile); configuration = new Configuration(); profile->read_into_configuration(configuration); } void ProfileTest::tearDown() { delete configuration; delete profile; } void ProfileTest::testGetConfig() { Variable* var; var = configuration->find ("Presage.ContextTracker.MAX_BUFFER_SIZE"); CPPUNIT_ASSERT(var->get_value() == "1024"); var = configuration->find ("Presage.Selector.SUGGESTIONS"); CPPUNIT_ASSERT(var->get_value() == "6"); var = configuration->find ("Presage.Selector.GREEDY_SUGGESTION_THRESHOLD"); CPPUNIT_ASSERT(var->get_value() == "0"); var = configuration->find ("Presage.Selector.REPEAT_SUGGESTIONS"); CPPUNIT_ASSERT(var->get_value() == "no"); var = configuration->find ("Presage.Predictors.SmoothedNgramPredictor.DBFILENAME"); CPPUNIT_ASSERT(var->get_value() == "database_en.db"); var = configuration->find ("Presage.Predictors.SmoothedNgramPredictor.MAX_PARTIAL_PREDICTION_SIZE"); CPPUNIT_ASSERT(var->get_value() == "40"); } void ProfileTest::testGetNonExistantConfig() { std::cout << "void ProfileTest::testGetNonExistantConfig()" << std::endl; CPPUNIT_ASSERT_THROW(configuration->find (""), Configuration::ConfigurationException); CPPUNIT_ASSERT_THROW(configuration->find ("foo"), Configuration::ConfigurationException); CPPUNIT_ASSERT_THROW(configuration->find ("bar"), Configuration::ConfigurationException); } void ProfileTest::testNonExistantProfile() { std::cout << "ProfileTest::testNonExistantProfile()" << std::endl; // hopefully a file with the following name will not exists const std::string wacky_profile("this_IS_a_wAckY_profileName.xml"); Profile* local_profile = new Profile (wacky_profile); Configuration* local_config = new Configuration (); CPPUNIT_ASSERT_NO_THROW( local_profile->read_into_configuration (local_config) ); delete local_config; delete local_profile; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/meritocracyCombinerTest.cpp���������������������������������������������0000644�0001750�0001750�00000014774�11737142176�020145� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "meritocracyCombinerTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( MeritocracyCombinerTest ); void MeritocracyCombinerTest::setUp() { combiner = new MeritocracyCombiner(); p1 = new Prediction(); p1->addSuggestion(Suggestion("foo1", 1.0)); p1->addSuggestion(Suggestion("foo2", 0.8)); p1->addSuggestion(Suggestion("foo3", 0.6)); p1->addSuggestion(Suggestion("foo4", 0.4)); p1->addSuggestion(Suggestion("foo5", 0.2)); p1->addSuggestion(Suggestion("foo6", 0.0)); p2 = new Prediction(); p2->addSuggestion(Suggestion("bar1", 0.9)); p2->addSuggestion(Suggestion("bar2", 0.7)); p2->addSuggestion(Suggestion("bar3", 0.5)); p2->addSuggestion(Suggestion("bar4", 0.3)); p2->addSuggestion(Suggestion("bar5", 0.1)); p2->addSuggestion(Suggestion("bar6", 0.0)); p3 = new Prediction(); p3->addSuggestion(Suggestion("foobar1", 0.95)); p3->addSuggestion(Suggestion("foobar2", 0.75)); p3->addSuggestion(Suggestion("foobar3", 0.55)); p3->addSuggestion(Suggestion("foobar4", 0.35)); p3->addSuggestion(Suggestion("foobar5", 0.15)); p3->addSuggestion(Suggestion("foobar6", 0.05)); p12 = new Prediction(); p12->addSuggestion(Suggestion("foo1", 1.0)); p12->addSuggestion(Suggestion("foo2", 0.8)); p12->addSuggestion(Suggestion("foo3", 0.6)); p12->addSuggestion(Suggestion("foo4", 0.4)); p12->addSuggestion(Suggestion("foo5", 0.2)); p12->addSuggestion(Suggestion("foo6", 0.0)); p12->addSuggestion(Suggestion("bar1", 0.9)); p12->addSuggestion(Suggestion("bar2", 0.7)); p12->addSuggestion(Suggestion("bar3", 0.5)); p12->addSuggestion(Suggestion("bar4", 0.3)); p12->addSuggestion(Suggestion("bar5", 0.1)); p12->addSuggestion(Suggestion("bar6", 0.0)); p13 = new Prediction(); p13->addSuggestion(Suggestion("foo1", 1.0)); p13->addSuggestion(Suggestion("foo2", 0.8)); p13->addSuggestion(Suggestion("foo3", 0.6)); p13->addSuggestion(Suggestion("foo4", 0.4)); p13->addSuggestion(Suggestion("foo5", 0.2)); p13->addSuggestion(Suggestion("foo6", 0.0)); p13->addSuggestion(Suggestion("foobar1", 0.95)); p13->addSuggestion(Suggestion("foobar2", 0.75)); p13->addSuggestion(Suggestion("foobar3", 0.55)); p13->addSuggestion(Suggestion("foobar4", 0.35)); p13->addSuggestion(Suggestion("foobar5", 0.15)); p13->addSuggestion(Suggestion("foobar6", 0.05)); p23 = new Prediction(); p23->addSuggestion(Suggestion("bar1", 0.9)); p23->addSuggestion(Suggestion("bar2", 0.7)); p23->addSuggestion(Suggestion("bar3", 0.5)); p23->addSuggestion(Suggestion("bar4", 0.3)); p23->addSuggestion(Suggestion("bar5", 0.1)); p23->addSuggestion(Suggestion("bar6", 0.0)); p23->addSuggestion(Suggestion("foobar1", 0.95)); p23->addSuggestion(Suggestion("foobar2", 0.75)); p23->addSuggestion(Suggestion("foobar3", 0.55)); p23->addSuggestion(Suggestion("foobar4", 0.35)); p23->addSuggestion(Suggestion("foobar5", 0.15)); p23->addSuggestion(Suggestion("foobar6", 0.05)); p123 = new Prediction(); p123->addSuggestion(Suggestion("foo1", 1.0)); p123->addSuggestion(Suggestion("foo2", 0.8)); p123->addSuggestion(Suggestion("foo3", 0.6)); p123->addSuggestion(Suggestion("foo4", 0.4)); p123->addSuggestion(Suggestion("foo5", 0.2)); p123->addSuggestion(Suggestion("foo6", 0.0)); p123->addSuggestion(Suggestion("bar1", 0.9)); p123->addSuggestion(Suggestion("bar2", 0.7)); p123->addSuggestion(Suggestion("bar3", 0.5)); p123->addSuggestion(Suggestion("bar4", 0.3)); p123->addSuggestion(Suggestion("bar5", 0.1)); p123->addSuggestion(Suggestion("bar6", 0.0)); p123->addSuggestion(Suggestion("foobar1", 0.95)); p123->addSuggestion(Suggestion("foobar2", 0.75)); p123->addSuggestion(Suggestion("foobar3", 0.55)); p123->addSuggestion(Suggestion("foobar4", 0.35)); p123->addSuggestion(Suggestion("foobar5", 0.15)); p123->addSuggestion(Suggestion("foobar6", 0.05)); } void MeritocracyCombinerTest::tearDown() { delete combiner; delete p1; delete p2; delete p3; delete p12; delete p23; delete p13; delete p123; } void MeritocracyCombinerTest::testCombineSinglePrediction() { std::vector< Prediction > predictions; predictions.push_back(*p1); CPPUNIT_ASSERT_EQUAL(*p1, combiner->combine(predictions)); predictions.clear(); predictions.push_back(*p2); CPPUNIT_ASSERT_EQUAL(*p2, combiner->combine(predictions)); predictions.clear(); predictions.push_back(*p3); CPPUNIT_ASSERT_EQUAL(*p3, combiner->combine(predictions)); predictions.clear(); } void MeritocracyCombinerTest::testCombineTwoPredictions() { std::vector< Prediction > predictions; predictions.push_back(*p1); predictions.push_back(*p2); CPPUNIT_ASSERT_EQUAL(*p12, combiner->combine(predictions)); predictions.clear(); predictions.push_back(*p2); predictions.push_back(*p3); CPPUNIT_ASSERT_EQUAL(*p23, combiner->combine(predictions)); predictions.clear(); predictions.push_back(*p1); predictions.push_back(*p3); CPPUNIT_ASSERT_EQUAL(*p13, combiner->combine(predictions)); predictions.clear(); } void MeritocracyCombinerTest::testCombineThreePredictions() { std::vector< Prediction > predictions; predictions.push_back(*p1); predictions.push_back(*p2); predictions.push_back(*p3); CPPUNIT_ASSERT_EQUAL(*p123, combiner->combine(predictions)); } ����presage-0.8.8/test/lib/core/predictorRegistryTest.cpp�����������������������������������������������0000644�0001750�0001750�00000006725�11743227551�017664� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "predictorRegistryTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( PredictorRegistryTest ); void PredictorRegistryTest::setUp() { config = new Configuration; config->insert ("Presage.PredictorRegistry.LOGGER", "ALL"); config->insert ("Presage.PredictorRegistry.PREDICTORS", "DummyPredictor1 DummyPredictor2 DummyPredictor3 DummyPredictor4"); config->insert ("Presage.Predictors.DummyPredictor1.PREDICTOR", "DummyPredictor"); config->insert ("Presage.Predictors.DummyPredictor2.PREDICTOR", "DummyPredictor"); config->insert ("Presage.Predictors.DummyPredictor3.PREDICTOR", "DummyPredictor"); config->insert ("Presage.Predictors.DummyPredictor4.PREDICTOR", "DummyPredictor"); registry = new PredictorRegistry(config); } void PredictorRegistryTest::tearDown() { delete registry; delete config; } void PredictorRegistryTest::testHasNext() { // test that no predictors are init'd if tracker is null PredictorRegistry::Iterator it = registry->iterator(); int count = 0; while (it.hasNext()) { count++; it.next(); } CPPUNIT_ASSERT_EQUAL(0, count); // test that predictors are init'd if tracker is not null ContextTracker* pointer = static_cast<ContextTracker*>((void*)0xdeadbeef); registry->setContextTracker(pointer); it = registry->iterator(); count = 0; while (it.hasNext()) { count++; it.next(); } CPPUNIT_ASSERT_EQUAL(4, count); } void PredictorRegistryTest::testNext() { ContextTracker* pointer = static_cast<ContextTracker*>((void*)0xdeadbeef); registry->setContextTracker(pointer); PredictorRegistry::Iterator it = registry->iterator(); Predictor* predictor = 0; while (it.hasNext()) { std::cerr << "entered testNext() hasNext() while" << std::endl; predictor = it.next(); } std::cerr << "predictor: " << (void*) predictor << std::endl; // since we've iterated till the end of the predictors list, predictor // is now pointing to the DummyPredictor, so let's test we got the // dummy prediction back Prediction prediction = predictor->predict(20, 0); CPPUNIT_ASSERT(predictor != 0); size_t expected_size = 18; CPPUNIT_ASSERT_EQUAL(expected_size, prediction.size()); CPPUNIT_ASSERT_EQUAL(Suggestion("foo1", 0.99), prediction.getSuggestion(0)); CPPUNIT_ASSERT_EQUAL(Suggestion("foobar6", 0.74), prediction.getSuggestion(17)); } �������������������������������������������presage-0.8.8/test/lib/core/predictorRegistryTest.h�������������������������������������������������0000644�0001750�0001750�00000003245�11737142176�017325� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTORREGISTRYTEST #define PRESAGE_PREDICTORREGISTRYTEST #include <cppunit/extensions/HelperMacros.h> #include <core/predictorRegistry.h> class PredictorRegistryTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testHasNext(); void testNext(); private: Configuration* config; PredictorRegistry* registry; CPPUNIT_TEST_SUITE( PredictorRegistryTest ); CPPUNIT_TEST( testHasNext ); CPPUNIT_TEST( testNext ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_PREDICTORREGISTRYTEST �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/configurationTest.cpp���������������������������������������������������0000644�0001750�0001750�00000003432�11737142176�017001� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "configurationTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( ConfigurationTest ); void ConfigurationTest::setUp() { configuration = new Configuration(); } void ConfigurationTest::tearDown() { delete configuration; } void ConfigurationTest::test_get_set() { const unsigned int SIZE = 3; const char* test_variables[SIZE] = { "foo", "foo.bar", "foo.bar.foobar" }; for (int loop = 0; loop < 3; loop++) { for (unsigned int i = 0; i < SIZE; i++) { configuration->insert (test_variables[i], test_variables[i]); CPPUNIT_ASSERT(configuration->find (test_variables[i])->get_value ().compare(test_variables[i]) == 0); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/profileTest.h�����������������������������������������������������������0000644�0001750�0001750�00000003356�11737142176�015244� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PROFILETEST #define PRESAGE_PROFILETEST #include <cppunit/extensions/HelperMacros.h> #include "core/profile.h" class ProfileTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testGetConfig(); void testGetNonExistantConfig(); void testNonExistantProfile(); private: Profile* profile; Configuration* configuration; CPPUNIT_TEST_SUITE( ProfileTest ); CPPUNIT_TEST( testGetConfig ); CPPUNIT_TEST( testGetNonExistantConfig ); CPPUNIT_TEST( testNonExistantProfile ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_PROFILETEST ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/profileTest.xml���������������������������������������������������������0000644�0001750�0001750�00000004150�11737142176�015606� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- Presage, an extensible predictive text entry system ------------------------------------------------------ Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --> <?xml version="1.0" encoding="UTF-8" standalone="no" ?> <Presage> <ContextTracker> <MAX_BUFFER_SIZE>1024</MAX_BUFFER_SIZE> </ContextTracker> <Selector> <SUGGESTIONS>6</SUGGESTIONS> <REPEAT_SUGGESTIONS>no</REPEAT_SUGGESTIONS> <GREEDY_SUGGESTION_THRESHOLD>0</GREEDY_SUGGESTION_THRESHOLD> </Selector> <Predictor> <PREDICT_TIME>1000</PREDICT_TIME> <COMBINATION_METHOD>0</COMBINATION_METHOD> </Predictor> <ProfileManager> <DUMMY_OPTION>very dummy</DUMMY_OPTION> </ProfileManager> <Predictors> <DummyPredictor> <ACTIVE>no</ACTIVE> </DummyPredictor> <DictionaryPredictor> <ACTIVE>no</ACTIVE> <DICTIONARY_PATH>/usr/share/dict/american-english</DICTIONARY_PATH> </DictionaryPredictor> <SmoothedNgramPredictor> <ACTIVE>yes</ACTIVE> <UNIGRAM_WEIGHT>.1</UNIGRAM_WEIGHT> <BIGRAM_WEIGHT>.3</BIGRAM_WEIGHT> <TRIGRAM_WEIGHT>.6</TRIGRAM_WEIGHT> <DBFILENAME>database_en.db</DBFILENAME> <MAX_PARTIAL_PREDICTION_SIZE>40</MAX_PARTIAL_PREDICTION_SIZE> </SmoothedNgramPredictor> </Predictors> </Presage> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/loggerTest.cpp����������������������������������������������������������0000644�0001750�0001750�00000011113�11737142176�015404� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "loggerTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( LoggerTest ); void LoggerTest::setUp() { } void LoggerTest::tearDown() { } void LoggerTest::testStandardErrorOutput() { Logger<char>* logger = new Logger<char>("LoggerTest", std::cerr); *logger << "[LoggerTest] testStandardErrorOutput" << endl; } void LoggerTest::testFileOutput() { } void LoggerTest::testSetLevelManipulator() { Logger<char> logger("LoggerTest", std::cerr); logger << setlevel("EMERG") << "[LoggerTest] testSetLevelManipulator: EMERG\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::EMERG, logger.getLevel()); logger << setlevel("FATAL") << "[LoggerTest] testSetLevelManipulator: FATAL\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::FATAL, logger.getLevel()); logger << setlevel("ALERT") << "[LoggerTest] testSetLevelManipulator: ALERT\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::ALERT, logger.getLevel()); logger << setlevel("CRIT") << "[LoggerTest] testSetLevelManipulator: CRIT\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::CRIT, logger.getLevel()); logger << setlevel("ERROR") << "[LoggerTest] testSetLevelManipulator: ERROR\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::ERROR, logger.getLevel()); logger << setlevel("WARN") << "[LoggerTest] testSetLevelManipulator: WARN\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::WARN, logger.getLevel()); logger << setlevel("NOTICE")<< "[LoggerTest] testSetLevelManipulator: WARN\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::NOTICE, logger.getLevel()); logger << setlevel("INFO") << "[LoggerTest] testSetLevelManipulator: NOTICE\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::INFO, logger.getLevel()); logger << setlevel("DEBUG") << "[LoggerTest] testSetLevelManipulator: DEBUG\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::DEBUG, logger.getLevel()); logger << setlevel("ALL") << "[LoggerTest] testSetLevelManipulator: ALL\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::ALL, logger.getLevel()); } void LoggerTest::testCurrentLevelManipulator() { Logger<char> logger("LoggerTest", std::cerr); logger << EMERG << "[LoggerTest] testCurrentLevelManipulator: EMERG\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::EMERG, logger.getCurrentLevel()); logger << FATAL << "[LoggerTest] testCurrentLevelManipulator: FATAL\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::FATAL, logger.getCurrentLevel()); logger << ALERT << "[LoggerTest] testCurrentLevelManipulator: ALERT\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::ALERT, logger.getCurrentLevel()); logger << CRIT << "[LoggerTest] testCurrentLevelManipulator: CRIT\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::CRIT, logger.getCurrentLevel()); logger << ERROR << "[LoggerTest] testCurrentLevelManipulator: ERROR\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::ERROR, logger.getCurrentLevel()); logger << WARN << "[LoggerTest] testCurrentLevelManipulator: WARN\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::WARN, logger.getCurrentLevel()); logger << NOTICE<< "[LoggerTest] testCurrentLevelManipulator: WARN\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::NOTICE, logger.getCurrentLevel()); logger << INFO << "[LoggerTest] testCurrentLevelManipulator: NOTICE\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::INFO, logger.getCurrentLevel()); logger << DEBUG << "[LoggerTest] testCurrentLevelManipulator: DEBUG\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::DEBUG, logger.getCurrentLevel()); logger << ALL << "[LoggerTest] testCurrentLevelManipulator: ALL\n"; CPPUNIT_ASSERT_EQUAL( Logger<char>::ALL, logger.getCurrentLevel()); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/selectorTest.h����������������������������������������������������������0000644�0001750�0001750�00000007026�11737142176�015422� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SELECTORTEST #define PRESAGE_SELECTORTEST #include <cppunit/extensions/HelperMacros.h> #include "core/profileManager.h" #include "core/predictorRegistry.h" #include "core/selector.h" #include "../common/testStringSuite.h" class SelectorTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); // R = repeat // NR = no repeat // Tn = threshold set to n // Sn = suggestions set to n void testSelect_S6_R_T0(); void testSelect_S6_NR_T0(); void testSelect_S6_R_T3(); void testSelect_S6_NR_T3(); private: class TestDataSuite { public: TestDataSuite(); virtual ~TestDataSuite(); virtual void init(); virtual bool hasMoreTestData() const; virtual void nextTestData(); virtual std::string getUpdateString() const { return iter->updateString; } virtual Prediction getInputPrediction() const { return iter->inputPrediction; } virtual Prediction getOutputPrediction() const { return iter->outputPrediction; } protected: struct TestData { std::string updateString; Prediction inputPrediction; Prediction outputPrediction; }; std::vector<TestData> testData; std::vector<TestData>::const_iterator iter; }; class TestDataSuite_S6_NR_T0 : public TestDataSuite { public: TestDataSuite_S6_NR_T0(); virtual void init(); }; class TestDataSuite_S6_R_T0 : public TestDataSuite { public: TestDataSuite_S6_R_T0(); virtual void init(); }; class TestDataSuite_S6_NR_T3 : public TestDataSuite { public: TestDataSuite_S6_NR_T3(); virtual void init(); }; class TestDataSuite_S6_R_T3 : public TestDataSuite { public: TestDataSuite_S6_R_T3(); virtual void init(); }; void testSelect(TestDataSuite*); TestStringSuite* testStringSuite; TestDataSuite* tds_S6_NR_T0; TestDataSuite* tds_S6_R_T0; TestDataSuite* tds_S6_NR_T3; TestDataSuite* tds_S6_R_T3; Configuration* configuration; PredictorRegistry* predictorRegistry; std::stringstream* strstream; PresageCallback* callback; ContextTracker* contextTracker; Selector* selector; CPPUNIT_TEST_SUITE( SelectorTest ); CPPUNIT_TEST( testSelect_S6_R_T0 ); CPPUNIT_TEST( testSelect_S6_NR_T0); CPPUNIT_TEST( testSelect_S6_R_T3 ); CPPUNIT_TEST( testSelect_S6_NR_T3); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_SELECTORTEST ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/variableTest.cpp��������������������������������������������������������0000644�0001750�0001750�00000007200�11737142176�015714� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "variableTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( VariableTest ); void VariableTest::setUp() { } void VariableTest::tearDown() { } void VariableTest::test_string_to_variable() { std::cout << "void VariableTest::test_string_to_variable()" << std::endl; Variable* variable = new Variable(""); size_t expected_size = 0; CPPUNIT_ASSERT_EQUAL(expected_size, variable->size()); delete variable; variable = new Variable("foo"); expected_size = 1; CPPUNIT_ASSERT_EQUAL(expected_size, variable->size()); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("foo"), (variable->get_name_vector ())[0]); delete variable; variable = new Variable("foo.bar"); expected_size = 2; CPPUNIT_ASSERT_EQUAL(expected_size, variable->size()); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("foo"), (variable->get_name_vector ())[0]); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("bar"), (variable->get_name_vector ())[1]); delete variable; variable = new Variable("foo.bar.foobar"); expected_size = 3; CPPUNIT_ASSERT_EQUAL(expected_size, variable->size()); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("foo"), (variable->get_name_vector ())[0]); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("bar"), (variable->get_name_vector ())[1]); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("foobar"), (variable->get_name_vector ())[2]); delete variable; } void VariableTest::test_variable_to_string() { std::cout << "void VariableTest::test_variable_to_string()" << std::endl; std::vector<std::string>* expected = new std::vector<std::string>(); Variable* var = new Variable(*expected); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>(""), var->get_name ()); delete expected; delete var; expected = new std::vector<std::string>(); expected->push_back("foo"); var = new Variable(*expected); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("foo"), var->get_name ()); delete expected; delete var; expected = new std::vector<std::string>(); expected->push_back("foo"); expected->push_back("bar"); var = new Variable(*expected); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("foo.bar"), var->get_name ()); delete expected; delete var; expected = new std::vector<std::string>(); expected->push_back("foo"); expected->push_back("bar"); expected->push_back("foobar"); var = new Variable(*expected); CPPUNIT_ASSERT_EQUAL(static_cast<std::string>("foo.bar.foobar"), var->get_name ()); delete expected; delete var; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/predictionTest.h��������������������������������������������������������0000644�0001750�0001750�00000004052�11737142176�015736� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTIONTEST #define PRESAGE_PREDICTIONTEST #include <cppunit/extensions/HelperMacros.h> #include <core/prediction.h> class PredictionTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testAssignmentOperator(); void testGetSize(); void testGetSuggestion(); void testAddSuggestion(); private: Suggestion* sugg1Ptr; Suggestion* sugg2Ptr; Suggestion* sugg3Ptr; Prediction* empty_prediction; Prediction* prediction1; Prediction* prediction2; Prediction* prediction3; Prediction* prediction23; Prediction* prediction13; Prediction* prediction12; Prediction* prediction123; CPPUNIT_TEST_SUITE( PredictionTest ); CPPUNIT_TEST( testAssignmentOperator ); CPPUNIT_TEST( testGetSize ); CPPUNIT_TEST( testGetSuggestion ); CPPUNIT_TEST( testAddSuggestion ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_PREDICTIONTEST ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/��������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�014667� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/stringForwardTokenizerTest.h����������������������������������0000644�0001750�0001750�00000003367�11737142176�022346� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_STRINGFORWARDTOKENIZERTEST #define PRESAGE_STRINGFORWARDTOKENIZERTEST #include <cppunit/extensions/HelperMacros.h> #include "core/tokenizer/stringForwardTokenizer.h" #include "../../common/testStringSuite.h" class StringForwardTokenizerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testNextToken(); private: std::string blankspaces; std::string separators; TestStringSuite* stringSuite; CPPUNIT_TEST_SUITE( StringForwardTokenizerTest ); CPPUNIT_TEST( testNextToken ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_STRINGFORWARDTOKENIZERTEST �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/stringForwardTokenizerTest.cpp��������������������������������0000644�0001750�0001750�00000004145�11753247310�022666� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "stringForwardTokenizerTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( StringForwardTokenizerTest ); void StringForwardTokenizerTest::setUp() { blankspaces = " \n\t"; separators = ".,!"; stringSuite = new TestStringSuite(); } void StringForwardTokenizerTest::tearDown() { delete stringSuite; } void StringForwardTokenizerTest::testNextToken() { int i; while (stringSuite->hasMoreTestStrings()) { //std::stringstream ss; //ss << stringSuite->currentTestString()->getstr(); //ForwardTokenizer tok(ss, blankspaces, separators); std::stringbuf sb; sb.str(stringSuite->currentTestString()->getstr()); std::stringstream ss(sb.str()); ForwardTokenizer tok(ss, blankspaces, separators); for (i = 0; tok.hasMoreTokens(); i++) { CPPUNIT_ASSERT_EQUAL( stringSuite->currentTestString()->token(i), tok.nextToken() ); } CPPUNIT_ASSERT_EQUAL( stringSuite->currentTestString()->tokencount(), i ); stringSuite->nextTestString(); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/tokenizerTestRunner.cpp���������������������������������������0000644�0001750�0001750�00000002661�11737142176�021353� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> int main() { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest( registry.makeTest() ); bool success = runner.run(); return success ? 0 : 1; } �������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/Makefile.am���������������������������������������������������0000644�0001750�0001750�00000003174�11737142176�016637� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if HAVE_CPPUNIT TESTS = tokenizerTestRunner check_PROGRAMS = $(TESTS) tokenizerTestRunner_SOURCES = tokenizerTestRunner.cpp \ forwardTokenizerTest.h \ forwardTokenizerTest.cpp \ reverseTokenizerTest.h \ reverseTokenizerTest.cpp \ crossCheckTokenizerTest.h \ crossCheckTokenizerTest.cpp \ stringForwardTokenizerTest.h \ stringForwardTokenizerTest.cpp tokenizerTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) tokenizerTestRunner_LDFLAGS = $(CPPUNIT_LIBS) tokenizerTestRunner_LDADD = $(top_builddir)/src/lib/core/tokenizer/libtokenizer.la \ ../../common/libcommon.la AM_CPPFLAGS = -I$(top_srcdir)/src/lib endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/reverseTokenizerTest.h����������������������������������������0000644�0001750�0001750�00000004112�11737142176�021153� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_REVERSETOKENIZERTEST #define PRESAGE_REVERSETOKENIZERTEST #include <cppunit/extensions/HelperMacros.h> #include "core/tokenizer/reverseTokenizer.h" #include "../../common/testStringSuite.h" class ReverseTokenizerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testConstructor(); void testNextToken(); void testCountTokens(); void testLowercaseMode(); void testProgress(); void testRepeatability(); private: std::string blankspaces; std::string separators; TestStringSuite* stringSuite; CPPUNIT_TEST_SUITE( ReverseTokenizerTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testNextToken ); CPPUNIT_TEST( testCountTokens ); CPPUNIT_TEST( testLowercaseMode ); CPPUNIT_TEST( testProgress ); CPPUNIT_TEST( testRepeatability ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_REVERSETOKENIZERTEST ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/forwardTokenizerTest.h����������������������������������������0000644�0001750�0001750�00000004112�11737142176�021144� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_FORWARDTOKENIZERTEST #define PRESAGE_FORWARDTOKENIZERTEST #include <cppunit/extensions/HelperMacros.h> #include "core/tokenizer/forwardTokenizer.h" #include "../../common/testStringSuite.h" class ForwardTokenizerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testConstructor(); void testNextToken(); void testCountTokens(); void testLowercaseMode(); void testProgress(); void testRepeatability(); private: std::string blankspaces; std::string separators; TestStringSuite* stringSuite; CPPUNIT_TEST_SUITE( ForwardTokenizerTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testNextToken ); CPPUNIT_TEST( testCountTokens ); CPPUNIT_TEST( testLowercaseMode ); CPPUNIT_TEST( testProgress ); CPPUNIT_TEST( testRepeatability ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_FORWARDTOKENIZERTEST ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/Makefile.in���������������������������������������������������0000644�0001750�0001750�00000102176�11763440356�016652� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_CPPUNIT_TRUE@TESTS = tokenizerTestRunner$(EXEEXT) @HAVE_CPPUNIT_TRUE@check_PROGRAMS = $(am__EXEEXT_1) subdir = test/lib/core/tokenizer DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_CPPUNIT_TRUE@am__EXEEXT_1 = tokenizerTestRunner$(EXEEXT) am__tokenizerTestRunner_SOURCES_DIST = tokenizerTestRunner.cpp \ forwardTokenizerTest.h forwardTokenizerTest.cpp \ reverseTokenizerTest.h reverseTokenizerTest.cpp \ crossCheckTokenizerTest.h crossCheckTokenizerTest.cpp \ stringForwardTokenizerTest.h stringForwardTokenizerTest.cpp @HAVE_CPPUNIT_TRUE@am_tokenizerTestRunner_OBJECTS = tokenizerTestRunner-tokenizerTestRunner.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ tokenizerTestRunner-forwardTokenizerTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ tokenizerTestRunner-reverseTokenizerTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ tokenizerTestRunner-crossCheckTokenizerTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ tokenizerTestRunner-stringForwardTokenizerTest.$(OBJEXT) tokenizerTestRunner_OBJECTS = $(am_tokenizerTestRunner_OBJECTS) @HAVE_CPPUNIT_TRUE@tokenizerTestRunner_DEPENDENCIES = $(top_builddir)/src/lib/core/tokenizer/libtokenizer.la \ @HAVE_CPPUNIT_TRUE@ ../../common/libcommon.la tokenizerTestRunner_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) \ $(tokenizerTestRunner_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(tokenizerTestRunner_SOURCES) DIST_SOURCES = $(am__tokenizerTestRunner_SOURCES_DIST) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @HAVE_CPPUNIT_TRUE@tokenizerTestRunner_SOURCES = tokenizerTestRunner.cpp \ @HAVE_CPPUNIT_TRUE@ forwardTokenizerTest.h \ @HAVE_CPPUNIT_TRUE@ forwardTokenizerTest.cpp \ @HAVE_CPPUNIT_TRUE@ reverseTokenizerTest.h \ @HAVE_CPPUNIT_TRUE@ reverseTokenizerTest.cpp \ @HAVE_CPPUNIT_TRUE@ crossCheckTokenizerTest.h \ @HAVE_CPPUNIT_TRUE@ crossCheckTokenizerTest.cpp \ @HAVE_CPPUNIT_TRUE@ stringForwardTokenizerTest.h \ @HAVE_CPPUNIT_TRUE@ stringForwardTokenizerTest.cpp @HAVE_CPPUNIT_TRUE@tokenizerTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@tokenizerTestRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@tokenizerTestRunner_LDADD = $(top_builddir)/src/lib/core/tokenizer/libtokenizer.la \ @HAVE_CPPUNIT_TRUE@ ../../common/libcommon.la @HAVE_CPPUNIT_TRUE@AM_CPPFLAGS = -I$(top_srcdir)/src/lib all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lib/core/tokenizer/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/lib/core/tokenizer/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list tokenizerTestRunner$(EXEEXT): $(tokenizerTestRunner_OBJECTS) $(tokenizerTestRunner_DEPENDENCIES) @rm -f tokenizerTestRunner$(EXEEXT) $(tokenizerTestRunner_LINK) $(tokenizerTestRunner_OBJECTS) $(tokenizerTestRunner_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokenizerTestRunner-crossCheckTokenizerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokenizerTestRunner-forwardTokenizerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokenizerTestRunner-reverseTokenizerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokenizerTestRunner-stringForwardTokenizerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokenizerTestRunner-tokenizerTestRunner.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< tokenizerTestRunner-tokenizerTestRunner.o: tokenizerTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-tokenizerTestRunner.o -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-tokenizerTestRunner.Tpo -c -o tokenizerTestRunner-tokenizerTestRunner.o `test -f 'tokenizerTestRunner.cpp' || echo '$(srcdir)/'`tokenizerTestRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-tokenizerTestRunner.Tpo $(DEPDIR)/tokenizerTestRunner-tokenizerTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tokenizerTestRunner.cpp' object='tokenizerTestRunner-tokenizerTestRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-tokenizerTestRunner.o `test -f 'tokenizerTestRunner.cpp' || echo '$(srcdir)/'`tokenizerTestRunner.cpp tokenizerTestRunner-tokenizerTestRunner.obj: tokenizerTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-tokenizerTestRunner.obj -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-tokenizerTestRunner.Tpo -c -o tokenizerTestRunner-tokenizerTestRunner.obj `if test -f 'tokenizerTestRunner.cpp'; then $(CYGPATH_W) 'tokenizerTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/tokenizerTestRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-tokenizerTestRunner.Tpo $(DEPDIR)/tokenizerTestRunner-tokenizerTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tokenizerTestRunner.cpp' object='tokenizerTestRunner-tokenizerTestRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-tokenizerTestRunner.obj `if test -f 'tokenizerTestRunner.cpp'; then $(CYGPATH_W) 'tokenizerTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/tokenizerTestRunner.cpp'; fi` tokenizerTestRunner-forwardTokenizerTest.o: forwardTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-forwardTokenizerTest.o -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-forwardTokenizerTest.Tpo -c -o tokenizerTestRunner-forwardTokenizerTest.o `test -f 'forwardTokenizerTest.cpp' || echo '$(srcdir)/'`forwardTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-forwardTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-forwardTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='forwardTokenizerTest.cpp' object='tokenizerTestRunner-forwardTokenizerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-forwardTokenizerTest.o `test -f 'forwardTokenizerTest.cpp' || echo '$(srcdir)/'`forwardTokenizerTest.cpp tokenizerTestRunner-forwardTokenizerTest.obj: forwardTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-forwardTokenizerTest.obj -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-forwardTokenizerTest.Tpo -c -o tokenizerTestRunner-forwardTokenizerTest.obj `if test -f 'forwardTokenizerTest.cpp'; then $(CYGPATH_W) 'forwardTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/forwardTokenizerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-forwardTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-forwardTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='forwardTokenizerTest.cpp' object='tokenizerTestRunner-forwardTokenizerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-forwardTokenizerTest.obj `if test -f 'forwardTokenizerTest.cpp'; then $(CYGPATH_W) 'forwardTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/forwardTokenizerTest.cpp'; fi` tokenizerTestRunner-reverseTokenizerTest.o: reverseTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-reverseTokenizerTest.o -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-reverseTokenizerTest.Tpo -c -o tokenizerTestRunner-reverseTokenizerTest.o `test -f 'reverseTokenizerTest.cpp' || echo '$(srcdir)/'`reverseTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-reverseTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-reverseTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='reverseTokenizerTest.cpp' object='tokenizerTestRunner-reverseTokenizerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-reverseTokenizerTest.o `test -f 'reverseTokenizerTest.cpp' || echo '$(srcdir)/'`reverseTokenizerTest.cpp tokenizerTestRunner-reverseTokenizerTest.obj: reverseTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-reverseTokenizerTest.obj -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-reverseTokenizerTest.Tpo -c -o tokenizerTestRunner-reverseTokenizerTest.obj `if test -f 'reverseTokenizerTest.cpp'; then $(CYGPATH_W) 'reverseTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/reverseTokenizerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-reverseTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-reverseTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='reverseTokenizerTest.cpp' object='tokenizerTestRunner-reverseTokenizerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-reverseTokenizerTest.obj `if test -f 'reverseTokenizerTest.cpp'; then $(CYGPATH_W) 'reverseTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/reverseTokenizerTest.cpp'; fi` tokenizerTestRunner-crossCheckTokenizerTest.o: crossCheckTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-crossCheckTokenizerTest.o -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-crossCheckTokenizerTest.Tpo -c -o tokenizerTestRunner-crossCheckTokenizerTest.o `test -f 'crossCheckTokenizerTest.cpp' || echo '$(srcdir)/'`crossCheckTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-crossCheckTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-crossCheckTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='crossCheckTokenizerTest.cpp' object='tokenizerTestRunner-crossCheckTokenizerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-crossCheckTokenizerTest.o `test -f 'crossCheckTokenizerTest.cpp' || echo '$(srcdir)/'`crossCheckTokenizerTest.cpp tokenizerTestRunner-crossCheckTokenizerTest.obj: crossCheckTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-crossCheckTokenizerTest.obj -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-crossCheckTokenizerTest.Tpo -c -o tokenizerTestRunner-crossCheckTokenizerTest.obj `if test -f 'crossCheckTokenizerTest.cpp'; then $(CYGPATH_W) 'crossCheckTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/crossCheckTokenizerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-crossCheckTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-crossCheckTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='crossCheckTokenizerTest.cpp' object='tokenizerTestRunner-crossCheckTokenizerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-crossCheckTokenizerTest.obj `if test -f 'crossCheckTokenizerTest.cpp'; then $(CYGPATH_W) 'crossCheckTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/crossCheckTokenizerTest.cpp'; fi` tokenizerTestRunner-stringForwardTokenizerTest.o: stringForwardTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-stringForwardTokenizerTest.o -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-stringForwardTokenizerTest.Tpo -c -o tokenizerTestRunner-stringForwardTokenizerTest.o `test -f 'stringForwardTokenizerTest.cpp' || echo '$(srcdir)/'`stringForwardTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-stringForwardTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-stringForwardTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='stringForwardTokenizerTest.cpp' object='tokenizerTestRunner-stringForwardTokenizerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-stringForwardTokenizerTest.o `test -f 'stringForwardTokenizerTest.cpp' || echo '$(srcdir)/'`stringForwardTokenizerTest.cpp tokenizerTestRunner-stringForwardTokenizerTest.obj: stringForwardTokenizerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT tokenizerTestRunner-stringForwardTokenizerTest.obj -MD -MP -MF $(DEPDIR)/tokenizerTestRunner-stringForwardTokenizerTest.Tpo -c -o tokenizerTestRunner-stringForwardTokenizerTest.obj `if test -f 'stringForwardTokenizerTest.cpp'; then $(CYGPATH_W) 'stringForwardTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/stringForwardTokenizerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/tokenizerTestRunner-stringForwardTokenizerTest.Tpo $(DEPDIR)/tokenizerTestRunner-stringForwardTokenizerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='stringForwardTokenizerTest.cpp' object='tokenizerTestRunner-stringForwardTokenizerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tokenizerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o tokenizerTestRunner-stringForwardTokenizerTest.obj `if test -f 'stringForwardTokenizerTest.cpp'; then $(CYGPATH_W) 'stringForwardTokenizerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/stringForwardTokenizerTest.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool ctags \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am # 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: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/crossCheckTokenizerTest.cpp�����������������������������������0000644�0001750�0001750�00000010555�11737142176�022132� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "crossCheckTokenizerTest.h" #include <list> #include <iostream> #include <assert.h> CPPUNIT_TEST_SUITE_REGISTRATION( CrossCheckTokenizerTest ); void CrossCheckTokenizerTest::setUp() { blankspaces = " \n\t"; separators = ".,!"; stringSuite = new TestStringSuite(); } void CrossCheckTokenizerTest::tearDown() { delete stringSuite; } void CrossCheckTokenizerTest::runCrossCheck( ForwardTokenizer& forTok, ReverseTokenizer& revTok) { std::cerr << "CrossCheckTokenizerTest::runCrossCheck()" << std::endl; while (stringSuite->hasMoreTestStrings()) { std::list<std::string> forwardTokenization; std::list<std::string> reverseTokenization; while (forTok.hasMoreTokens()) { forwardTokenization.push_back(forTok.nextToken()); } while (revTok.hasMoreTokens()) { reverseTokenization.push_front(revTok.nextToken()); } CPPUNIT_ASSERT( forwardTokenization.size() == reverseTokenization.size() ); std::list<std::string>::const_iterator forit = forwardTokenization.begin(); std::list<std::string>::const_iterator revit = reverseTokenization.begin(); while (forit != forwardTokenization.end() && revit != reverseTokenization.end()) { CPPUNIT_ASSERT( *forit == *revit ); forit++; revit++; } stringSuite->nextTestString(); } } void CrossCheckTokenizerTest::testNextToken() { std::cerr << "CrossCheckTokenizerTest::testNextToken()" << std::endl; assert(stringSuite->currentTestString() != 0); std::stringstream forss; std::stringstream revss; assert(stringSuite->currentTestString() != 0); forss << stringSuite->currentTestString()->getstr(); revss << stringSuite->currentTestString()->getstr(); ForwardTokenizer forTok(forss, blankspaces, separators); ReverseTokenizer revTok(revss, blankspaces, separators); runCrossCheck(forTok, revTok); } void CrossCheckTokenizerTest::testLowercaseMode() { std::cerr << "CrossCheckTokenizerTest::testLowercaseMode()" << std::endl; assert(stringSuite->currentTestString() != 0); std::stringstream forss; std::stringstream revss; forss << stringSuite->currentTestString()->getstr(); revss << stringSuite->currentTestString()->getstr(); ForwardTokenizer forTok(forss, blankspaces, separators); ReverseTokenizer revTok(revss, blankspaces, separators); forTok.lowercaseMode(true); revTok.lowercaseMode(true); runCrossCheck(forTok, revTok); } void CrossCheckTokenizerTest::testProgress() { std::cerr << "CrossCheckTokenizerTest::testProgress()" << std::endl; std::stringstream forss; std::stringstream revss; const std::string str("01 02 03 04 05 06 07 08 09 10"); forss << str; revss << str; ForwardTokenizer forTok(forss, blankspaces, separators); ReverseTokenizer revTok(revss, blankspaces, separators); //forTok.lowercaseMode(true); //revTok.lowercaseMode(true); const double delta = 0.3; while (forTok.hasMoreTokens() && revTok.hasMoreTokens()) { CPPUNIT_ASSERT( (-delta < (forTok.progress() - revTok.progress())) && ((forTok.progress() - revTok.progress()) < delta)); //std::cerr << forTok.nextToken() << ' ' << forTok.progress() << '-' // << revTok.nextToken() << ' ' << revTok.progress() << std::endl; forTok.nextToken(); revTok.nextToken(); } } ���������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/crossCheckTokenizerTest.h�������������������������������������0000644�0001750�0001750�00000004327�11737142176�021577� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CROSSCHECKTOKENIZERTEST #define PRESAGE_CROSSCHECKTOKENIZERTEST #include <cppunit/extensions/HelperMacros.h> #include "../../common/testStringSuite.h" #include "core/tokenizer/forwardTokenizer.h" #include "core/tokenizer/reverseTokenizer.h" /** Validates ForwardTokenizer and ReverseTokenizer tokenization. * * Cross-checks ForwardTokenizer and ReverseTokenizer by comparing the * output of the ForwardTokenizer and ReverseTokenizer tokenization on * the same strings set. */ class CrossCheckTokenizerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testNextToken(); void testLowercaseMode(); void testProgress(); void runCrossCheck(ForwardTokenizer&, ReverseTokenizer&); private: std::string blankspaces; std::string separators; TestStringSuite* stringSuite; CPPUNIT_TEST_SUITE( CrossCheckTokenizerTest ); CPPUNIT_TEST( testNextToken ); CPPUNIT_TEST( testLowercaseMode ); CPPUNIT_TEST( testProgress ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_CROSSCHECKTOKENIZERTEST ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/reverseTokenizerTest.cpp��������������������������������������0000644�0001750�0001750�00000014552�11753247310�021511� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "reverseTokenizerTest.h" #include <iostream> #include <assert.h> CPPUNIT_TEST_SUITE_REGISTRATION( ReverseTokenizerTest ); void ReverseTokenizerTest::setUp() { std::cerr << "ReverseTokenizerTest::setUp()" << std::endl; blankspaces = " \n\t"; separators = ".,!"; stringSuite = new TestStringSuite(); } void ReverseTokenizerTest::tearDown() { std::cerr << "ReverseTokenizerTest::tearDown()" << std::endl; delete stringSuite; } void ReverseTokenizerTest::testConstructor() { std::cerr << "ReverseTokenizerTest::testConstructor()" << std::endl; std::stringstream ss; ReverseTokenizer tok1(ss, blankspaces, separators); CPPUNIT_ASSERT( tok1.blankspaceChars() == blankspaces ); CPPUNIT_ASSERT( tok1.separatorChars() == separators ); } void ReverseTokenizerTest::testNextToken() { std::cerr << "ReverseTokenizerTest::testNextToken()" << std::endl; int i; while (stringSuite->hasMoreTestStrings()) { std::stringstream ss; assert(stringSuite->currentTestString() != 0); ss << stringSuite->currentTestString()->getstr(); ReverseTokenizer tok(ss, blankspaces, separators); int tokenCount = stringSuite->currentTestString()->tokencount(); std::cerr << "[string] " << ss.str() << std::endl; for (i = 0; tok.hasMoreTokens(); i++) { //CPPUNIT_ASSERT_EQUAL( stringSuite->currentTestString()->token(tokenCount-1-i), //tok.nextToken() ); std::string token = tok.nextToken(); std::cerr << "[token] " << token << " [expected] " << stringSuite->currentTestString()->token(tokenCount-1-i) << std::endl; CPPUNIT_ASSERT_EQUAL( stringSuite->currentTestString()->token(tokenCount-1-i), token ); } stringSuite->nextTestString(); } } void ReverseTokenizerTest::testCountTokens() { std::cerr << "ReverseTokenizerTest::testCountTokens()" << std::endl; while (stringSuite->hasMoreTestStrings()) { std::stringstream ss; assert(stringSuite->currentTestString() != 0); ss << stringSuite->currentTestString()->getstr(); ReverseTokenizer tok(ss, blankspaces, separators); CPPUNIT_ASSERT_EQUAL(stringSuite->currentTestString()->tokencount(), tok.countTokens()); stringSuite->nextTestString(); } } void ReverseTokenizerTest::testLowercaseMode() { std::cerr << "ReverseTokenizerTest::testLowercaseMode()" << std::endl; int i; while (stringSuite->hasMoreTestStrings()) { std::stringstream ss; assert(stringSuite->currentTestString() != 0); ss << stringSuite->currentTestString()->getstr(); ReverseTokenizer tok(ss, blankspaces, separators); tok.lowercaseMode(true); int tokenCount = stringSuite->currentTestString()->tokencount(); std::string str; for (i = 0; tok.hasMoreTokens(); i++) { str = stringSuite->currentTestString()->token(tokenCount - 1 - i); // convert string to lowercase for (std::string::iterator it = str.begin(); it != str.end(); it++) { *it = tolower(*it); } CPPUNIT_ASSERT_EQUAL( str, tok.nextToken() ); } stringSuite->nextTestString(); } } void ReverseTokenizerTest::testProgress() { std::cerr << "ReverseTokenizerTest::testProgress()" << std::endl; std::stringstream ss; ss << "01 02 03 04 05 06 07 08 09 10"; ReverseTokenizer tok(ss, " ", " "); double expectedProgress = 0.0; const double expectedProgressIncrement = 0.1; const double delta = 0.07; while (tok.hasMoreTokens()) { expectedProgress += expectedProgressIncrement; tok.nextToken(); std::cerr << "[expected] " << expectedProgress << " [progress] " << tok.progress() << std::endl; CPPUNIT_ASSERT( (expectedProgress - delta) < tok.progress() ); CPPUNIT_ASSERT( tok.progress() < (expectedProgress + delta) ); } } void ReverseTokenizerTest::testRepeatability() { std::cerr << "ReverseTokenizerTest::testRepeatability()" << std::endl; const int REPETITIONS = 3; std::stringstream ss; std::streambuf* sb = ss.rdbuf(); int index = 0; std::string str = "foo bar foobar"; const int TOKENS = 3; std::string tokens[3]; tokens[0] = "foobar"; tokens[1] = "bar"; tokens[2] = "foo"; // insert test string into stream's streambuf std::string::const_iterator str_it = str.begin(); while (str_it != str.end()) { sb->sputc(*str_it); str_it++; } // build expected stringstream std::stringstream expected_ss; while (index < REPETITIONS) { for (int i = 0; i < TOKENS; i++) { expected_ss << tokens[i] << std::endl; } index++; } // tokenize the same stream REPETITIONS times and store the resuls // in actual_ss for later comparison with expected_ss std::stringstream actual_ss; for (int i = 0; i < REPETITIONS; i++ ) { index = 0; ReverseTokenizer rT(ss, blankspaces, separators); std::cerr << "[stream] " << rT.streamToString() << std::endl; while (rT.hasMoreTokens()) { std::string token = rT.nextToken(); std::cerr << "[repeatability] " << token << std::endl; actual_ss << token << std::endl; CPPUNIT_ASSERT_EQUAL( tokens[index], token ); index++; } std::cerr << "ss.str() " << ss.str() << std::endl; } CPPUNIT_ASSERT_EQUAL( expected_ss.str(), actual_ss.str() ); } ������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/tokenizer/forwardTokenizerTest.cpp��������������������������������������0000644�0001750�0001750�00000013122�11753247310�021472� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "forwardTokenizerTest.h" #include <iostream> #include <assert.h> CPPUNIT_TEST_SUITE_REGISTRATION( ForwardTokenizerTest ); void ForwardTokenizerTest::setUp() { blankspaces = " \n\t"; separators = ".,!"; stringSuite = new TestStringSuite(); } void ForwardTokenizerTest::tearDown() { delete stringSuite; } void ForwardTokenizerTest::testConstructor() { std::stringstream ss; ForwardTokenizer tok1(ss, blankspaces, separators); CPPUNIT_ASSERT( tok1.blankspaceChars() == blankspaces ); CPPUNIT_ASSERT( tok1.separatorChars() == separators ); } void ForwardTokenizerTest::testNextToken() { //std::cerr << "ForwardTokenizerTest::testNextToken()" << std::endl; int i; while (stringSuite->hasMoreTestStrings()) { //std::cerr << "Entered loop!" << std::endl; std::stringstream ss; assert(stringSuite->currentTestString() != 0); //std::cerr << "stringSuite->currentTestString():" << stringSuite->currentTestString() << std::endl; ss << stringSuite->currentTestString()->getstr(); //std::cerr << "Tokenizing string: " << ss.str() << std::endl; ForwardTokenizer tok(ss, blankspaces, separators); for (i = 0; tok.hasMoreTokens(); i++) { CPPUNIT_ASSERT_EQUAL( stringSuite->currentTestString()->token(i), tok.nextToken() ); } stringSuite->nextTestString(); } } void ForwardTokenizerTest::testCountTokens() { //std::cerr << "ForwardTokenizerTest::testCountTokens()" << std::endl; while (stringSuite->hasMoreTestStrings()) { std::stringstream ss; assert(stringSuite->currentTestString() != 0); ss << stringSuite->currentTestString()->getstr(); ForwardTokenizer tok(ss, blankspaces, separators); CPPUNIT_ASSERT_EQUAL(stringSuite->currentTestString()->tokencount(), tok.countTokens()); stringSuite->nextTestString(); } } void ForwardTokenizerTest::testLowercaseMode() { //std::cerr << "ForwardTokenizerTest::testLowercaseMode()" << std::endl; int i; while (stringSuite->hasMoreTestStrings()) { std::stringstream ss; assert(stringSuite->currentTestString() != 0); ss << stringSuite->currentTestString()->getstr(); ForwardTokenizer tok(ss, blankspaces, separators); tok.lowercaseMode(true); std::string str; for (i = 0; tok.hasMoreTokens(); i++) { str = stringSuite->currentTestString()->token(i); // convert string to lowercase for (std::string::iterator it = str.begin(); it != str.end(); it++) { *it = tolower(*it); } CPPUNIT_ASSERT_EQUAL( str, tok.nextToken() ); } stringSuite->nextTestString(); } } void ForwardTokenizerTest::testProgress() { //std::cerr << "ForwardTokenizerTest::testProgress()" << std::endl; std::stringstream ss; ss << "01 02 03 04 05 06 07 08 09 10"; ForwardTokenizer tok(ss, " ", " "); double expectedProgress = 0.0; const double expectedProgressIncrement = 0.1; const double delta = 0.035; while (tok.hasMoreTokens()) { expectedProgress += expectedProgressIncrement; tok.nextToken(); //std::cerr << "[expected] " << expectedProgress // << " [progress] " << tok.progress() << std::endl; CPPUNIT_ASSERT( (expectedProgress - delta) < tok.progress() ); CPPUNIT_ASSERT( tok.progress() < (expectedProgress + delta) ); } } void ForwardTokenizerTest::testRepeatability() { //std::cerr << "ForwardTokenizerTest::testRepeatability()" << std::endl; const int REPETITIONS = 3; std::stringstream ss; std::streambuf* sb = ss.rdbuf(); int index = 0; std::string str = "foo bar foobar"; const int TOKENS = 3; std::string tokens[3]; tokens[0] = "foo"; tokens[1] = "bar"; tokens[2] = "foobar"; std::string::const_iterator str_it = str.begin(); while (str_it != str.end()) { sb->sputc(*str_it); str_it++; } // build expected stringstream std::stringstream expected_ss; while (index < REPETITIONS) { for (int i = 0; i < TOKENS; i++) { expected_ss << tokens[i] << std::endl; } index++; } std::stringstream actual_ss; for (int i = 0; i < REPETITIONS; i++ ) { index = 0; ForwardTokenizer fT(ss, blankspaces, separators); //std::cerr << "[stream] " << fT.streamToString() << std::endl; while (fT.hasMoreTokens()) { std::string token = fT.nextToken(); //std::cerr << "[repeatability] " << token << std::endl; actual_ss << token << std::endl; CPPUNIT_ASSERT_EQUAL( tokens[index], token ); index++; } } CPPUNIT_ASSERT_EQUAL( expected_ss.str(), actual_ss.str() ); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/Makefile.am�������������������������������������������������������������0000644�0001750�0001750�00000004221�11737142176�014617� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = tokenizer context_tracker EXTRA_DIST = profileTest.xml if HAVE_CPPUNIT TESTS = coreTestRunner check_PROGRAMS = $(TESTS) coreTestRunner_SOURCES = \ coreTestRunner.cpp \ suggestionTest.h suggestionTest.cpp \ predictionTest.h predictionTest.cpp \ selectorTest.h selectorTest.cpp \ profileTest.h profileTest.cpp \ profileManagerTest.h profileManagerTest.cpp \ meritocracyCombinerTest.h meritocracyCombinerTest.cpp \ loggerTest.h loggerTest.cpp \ variableTest.h variableTest.cpp \ configurationTest.h configurationTest.cpp \ combinerTest.h combinerTest.cpp \ predictorRegistryTest.h predictorRegistryTest.cpp coreTestRunner_CPPFLAGS = -I$(top_srcdir)/src/lib coreTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) coreTestRunner_LDFLAGS = $(CPPUNIT_LIBS) coreTestRunner_LDADD = libcoretest.la check_LTLIBRARIES = \ libcoretest.la libcoretest_la_SOURCES = libcoretest_la_LIBADD = \ ../common/libcommon.la \ $(top_builddir)/src/lib/core/libcore.la \ $(top_builddir)/src/lib/predictors/libpredictors.la if BUILD_TINYXML coreTestRunner_CPPFLAGS += -I$(top_srcdir)/src/lib/tinyxml libcoretest_la_LIBADD += $(top_builddir)/src/lib/tinyxml/libtinyxml.la else libcoretest_la_LIBADD += -ltinyxml endif endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/meritocracyCombinerTest.h�����������������������������������������������0000644�0001750�0001750�00000004141�11737142176�017575� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_MERITOCRACYCOMBINERTEST #define PRESAGE_MERITOCRACYCOMBINERTEST #include <cppunit/extensions/HelperMacros.h> #include <core/meritocracyCombiner.h> class MeritocracyCombinerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testCombineSinglePrediction(); void testCombineTwoPredictions(); void testCombineThreePredictions(); private: Combiner* combiner; Prediction* p1; Prediction* p2; Prediction* p3; Prediction* p12; // expected combination of p1 and p2 Prediction* p23; // expected combination of p2 and p3 Prediction* p13; // expected combination of p1 and p3 Prediction* p123; // expected combination of p1, p2, and p3 CPPUNIT_TEST_SUITE( MeritocracyCombinerTest ); CPPUNIT_TEST( testCombineSinglePrediction ); CPPUNIT_TEST( testCombineTwoPredictions ); CPPUNIT_TEST( testCombineThreePredictions ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_MERITOCRACYCOMBINERTEST �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/coreTestRunner.cpp������������������������������������������������������0000644�0001750�0001750�00000002661�11737142176�016257� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> int main() { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest( registry.makeTest() ); bool success = runner.run(); return success ? 0 : 1; } �������������������������������������������������������������������������������presage-0.8.8/test/lib/core/context_tracker/��������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�016054� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/context_tracker/contextTrackerTest.cpp����������������������������������0000644�0001750�0001750�00000016133�11763437013�022327� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "contextTrackerTest.h" #include "../../common/stringstreamPresageCallback.h" #include <string> #include <assert.h> CPPUNIT_TEST_SUITE_REGISTRATION( ContextTrackerTest ); void ContextTrackerTest::setUp() { testStringSuite = new TestStringSuite(); configuration = new Configuration(); configuration->insert (PredictorRegistry::LOGGER, "ALL"); configuration->insert (PredictorRegistry::PREDICTORS, ""); configuration->insert (ContextTracker::LOGGER, "ALL"); configuration->insert (ContextTracker::SLIDING_WINDOW_SIZE, "80"); configuration->insert (ContextTracker::LOWERCASE_MODE, "no"); predictorRegistry = new PredictorRegistry(configuration); } void ContextTrackerTest::tearDown() { delete testStringSuite; delete predictorRegistry; delete configuration; } void ContextTrackerTest::testConstructor() {} void ContextTrackerTest::testGetPrefix() { std::cerr << "ContextTrackerTest::testGetPrefix()" << std::endl; while (testStringSuite->hasMoreTestStrings()) { std::stringstream buffer; StringstreamPresageCallback callback(buffer); ContextTracker hT(configuration, predictorRegistry, &callback); buffer << testStringSuite->currentTestString()->getstr(); assert(testStringSuite->currentTestString() != 0); std::cerr << "Test getting prefix from string: " << testStringSuite->currentTestString()->getstr() << std::endl; std::string actual_prefix = hT.getPrefix(); std::string expected_prefix = testStringSuite->currentTestString()->token(testStringSuite->currentTestString()->tokencount() - 1); std::cerr << "actual_prefix : " << actual_prefix << std::endl; std::cerr << "expected_prefix: " << expected_prefix << std::endl; CPPUNIT_ASSERT_EQUAL( expected_prefix, actual_prefix ); std::cerr << "past assert" << std::endl; testStringSuite->nextTestString(); } } void ContextTrackerTest::testGetToken() { std::cerr << "ContextTrackerTest::testGetToken()" << std::endl; while (testStringSuite->hasMoreTestStrings()) { std::stringstream buffer; StringstreamPresageCallback callback(buffer); ContextTracker hT(configuration, predictorRegistry, &callback); buffer << testStringSuite->currentTestString()->getstr(); assert(testStringSuite->currentTestString() != 0); std::cerr << "pastStream: " << hT.getPastStream() << std::endl; const int TOKENS = testStringSuite->currentTestString()->tokencount(); for (int i = 0; i < TOKENS; i++) { std::string actual_token = hT.getToken(i); std::string expected_token = testStringSuite->currentTestString()->token(TOKENS - i - 1); std::cerr << "expected_token: " << expected_token << std::endl; std::cerr << "actual_token : " << actual_token << std::endl; CPPUNIT_ASSERT_EQUAL( expected_token, actual_token ); } testStringSuite->nextTestString(); } } void ContextTrackerTest::testGetFutureStream() {} void ContextTrackerTest::testGetPastStream() { std::cerr << "ContextTrackerTest::testGetPastBuffer()" << std::endl; while (testStringSuite->hasMoreTestStrings()) { std::stringstream buffer; StringstreamPresageCallback callback(buffer); ContextTracker hT(configuration, predictorRegistry, &callback); std::string str = testStringSuite->currentTestString()->getstr(); std::string partial_str; for (size_t i = 0; i < str.size(); i++) { std::string strchar; strchar.push_back(str[i]); buffer << strchar; partial_str.push_back(str[i]); CPPUNIT_ASSERT_EQUAL( partial_str, hT.getPastStream() ); } testStringSuite->nextTestString(); } } void ContextTrackerTest::testToString() {} void ContextTrackerTest::testContextChange() { std::stringstream buffer; PresageCallback* callback = new StringstreamPresageCallback(buffer); ContextTracker* contextTracker = new ContextTracker(configuration, predictorRegistry, callback); const std::string line = "foo bar foobar, foo bar! Foobar foo bar... foobar. "; const std::string change = "10010001000000100001000001000000010001000100000000010"; for (size_t i = 0; i < line.size(); i++) { std::string temp; temp.push_back(line[i]); buffer << temp; bool expected = (change[i] == '0' ? false : true); std::cerr << "contextChange: " << expected << " - context: " << contextTracker->getPastStream() << '|' << std::endl; std::stringstream ss; ss << "Error detected at: " << line.substr(0, i) << '|'; CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str().c_str(), expected, contextTracker->contextChange()); contextTracker->update(); } delete contextTracker; delete callback; } void ContextTrackerTest::testCumulativeContextChange() { std::stringstream buffer; PresageCallback* callback = new StringstreamPresageCallback(buffer); ContextTracker* contextTracker = new ContextTracker(configuration, predictorRegistry, callback); const char* TRUE = "true"; const char* FALSE = "false"; const char* dataSuite[] = { "f", TRUE, // f| "o", FALSE, // fo| "o", FALSE, // foo| " ", TRUE, // foo | "ba", FALSE, // foo ba| "r", FALSE, // foo bar| " ", TRUE, // foo bar | "foo", FALSE, // foo bar foo| "bar ", TRUE, // foo bar foobar | "foo ", TRUE, // foo bar foobar foo | "b", FALSE, // foo bar foobar foo b| "ar ", TRUE, // foo bar foobar foo bar | "foobar ", TRUE, // foo bar foobar foo bar foobar | 0, 0 }; int i = 0; while (dataSuite[i] != 0 && dataSuite[i+1] != 0) { buffer << dataSuite[i]; bool expected = (dataSuite[i+1] == FALSE ? false : true); std::stringstream ss; ss << "cumulativeContextChange: " << expected << " - context: " << contextTracker->getPastStream() << '|' << std::endl; CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str().c_str(), expected, contextTracker->contextChange()); contextTracker->update(); i += 2; } delete contextTracker; std::cerr << "ContextTrackerTest::testCumulativeContextChange() completed" << std::endl; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/context_tracker/contextChangeDetectorTest.h�����������������������������0000644�0001750�0001750�00000003474�11763437013�023264� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CONTEXTCHANGEDETECTORTEST #define PRESAGE_CONTEXTCHANGEDETECTORTEST #include <cppunit/extensions/HelperMacros.h> #include "core/context_tracker/contextChangeDetector.h" class ContextChangeDetectorTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testCharChanges(); void testBlockChanges(); void testGetChange(); private: CPPUNIT_TEST_SUITE( ContextChangeDetectorTest ); CPPUNIT_TEST( testCharChanges ); CPPUNIT_TEST( testBlockChanges ); CPPUNIT_TEST( testGetChange ); CPPUNIT_TEST_SUITE_END(); ContextChangeDetector* detector; }; #endif // PRESAGE_CONTEXTCHANGEDETECTORTEST ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/context_tracker/Makefile.am���������������������������������������������0000644�0001750�0001750�00000003625�11737142176�020025� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if HAVE_CPPUNIT TESTS = contextTrackerTestRunner check_PROGRAMS = $(TESTS) contextTrackerTestRunner_SOURCES = ../coreTestRunner.cpp \ contextChangeDetectorTest.h \ contextChangeDetectorTest.cpp \ contextTrackerTest.h \ contextTrackerTest.cpp contextTrackerTestRunner_CPPFLAGS = -I$(top_srcdir)/src/lib contextTrackerTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) contextTrackerTestRunner_LDFLAGS = $(CPPUNIT_LIBS) contextTrackerTestRunner_LDADD = libcontexttrackertest.la check_LTLIBRARIES = \ libcontexttrackertest.la libcontexttrackertest_la_SOURCES = libcontexttrackertest_la_LIBADD = \ ../../common/libcommon.la \ $(top_builddir)/src/lib/core/libcore.la \ $(top_builddir)/src/lib/predictors/libpredictors.la if BUILD_TINYXML contextTrackerTestRunner_CPPFLAGS += -I$(top_srcdir)/src/lib/tinyxml libcontexttrackertest_la_LIBADD += $(top_builddir)/src/lib/tinyxml/libtinyxml.la else libcontexttrackertest_la_LIBADD += -ltinyxml endif endif �����������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/context_tracker/Makefile.in���������������������������������������������0000644�0001750�0001750�00000073737�11763440356�020051� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_CPPUNIT_TRUE@TESTS = contextTrackerTestRunner$(EXEEXT) @HAVE_CPPUNIT_TRUE@check_PROGRAMS = $(am__EXEEXT_1) @BUILD_TINYXML_TRUE@@HAVE_CPPUNIT_TRUE@am__append_1 = -I$(top_srcdir)/src/lib/tinyxml @BUILD_TINYXML_TRUE@@HAVE_CPPUNIT_TRUE@am__append_2 = $(top_builddir)/src/lib/tinyxml/libtinyxml.la @BUILD_TINYXML_FALSE@@HAVE_CPPUNIT_TRUE@am__append_3 = -ltinyxml subdir = test/lib/core/context_tracker DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__DEPENDENCIES_1 = @HAVE_CPPUNIT_TRUE@libcontexttrackertest_la_DEPENDENCIES = \ @HAVE_CPPUNIT_TRUE@ ../../common/libcommon.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/core/libcore.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/predictors/libpredictors.la \ @HAVE_CPPUNIT_TRUE@ $(am__append_2) $(am__DEPENDENCIES_1) am_libcontexttrackertest_la_OBJECTS = libcontexttrackertest_la_OBJECTS = \ $(am_libcontexttrackertest_la_OBJECTS) @HAVE_CPPUNIT_TRUE@am_libcontexttrackertest_la_rpath = @HAVE_CPPUNIT_TRUE@am__EXEEXT_1 = contextTrackerTestRunner$(EXEEXT) am__contextTrackerTestRunner_SOURCES_DIST = ../coreTestRunner.cpp \ contextChangeDetectorTest.h contextChangeDetectorTest.cpp \ contextTrackerTest.h contextTrackerTest.cpp @HAVE_CPPUNIT_TRUE@am_contextTrackerTestRunner_OBJECTS = contextTrackerTestRunner-coreTestRunner.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ contextTrackerTestRunner-contextChangeDetectorTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ contextTrackerTestRunner-contextTrackerTest.$(OBJEXT) contextTrackerTestRunner_OBJECTS = \ $(am_contextTrackerTestRunner_OBJECTS) @HAVE_CPPUNIT_TRUE@contextTrackerTestRunner_DEPENDENCIES = \ @HAVE_CPPUNIT_TRUE@ libcontexttrackertest.la contextTrackerTestRunner_LINK = $(LIBTOOL) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) \ $(contextTrackerTestRunner_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libcontexttrackertest_la_SOURCES) \ $(contextTrackerTestRunner_SOURCES) DIST_SOURCES = $(libcontexttrackertest_la_SOURCES) \ $(am__contextTrackerTestRunner_SOURCES_DIST) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @HAVE_CPPUNIT_TRUE@contextTrackerTestRunner_SOURCES = ../coreTestRunner.cpp \ @HAVE_CPPUNIT_TRUE@ contextChangeDetectorTest.h \ @HAVE_CPPUNIT_TRUE@ contextChangeDetectorTest.cpp \ @HAVE_CPPUNIT_TRUE@ contextTrackerTest.h \ @HAVE_CPPUNIT_TRUE@ contextTrackerTest.cpp @HAVE_CPPUNIT_TRUE@contextTrackerTestRunner_CPPFLAGS = \ @HAVE_CPPUNIT_TRUE@ -I$(top_srcdir)/src/lib $(am__append_1) @HAVE_CPPUNIT_TRUE@contextTrackerTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@contextTrackerTestRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@contextTrackerTestRunner_LDADD = libcontexttrackertest.la @HAVE_CPPUNIT_TRUE@check_LTLIBRARIES = \ @HAVE_CPPUNIT_TRUE@ libcontexttrackertest.la @HAVE_CPPUNIT_TRUE@libcontexttrackertest_la_SOURCES = @HAVE_CPPUNIT_TRUE@libcontexttrackertest_la_LIBADD = \ @HAVE_CPPUNIT_TRUE@ ../../common/libcommon.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/core/libcore.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/predictors/libpredictors.la \ @HAVE_CPPUNIT_TRUE@ $(am__append_2) $(am__append_3) all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lib/core/context_tracker/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/lib/core/context_tracker/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkLTLIBRARIES: -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES) @list='$(check_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libcontexttrackertest.la: $(libcontexttrackertest_la_OBJECTS) $(libcontexttrackertest_la_DEPENDENCIES) $(LINK) $(am_libcontexttrackertest_la_rpath) $(libcontexttrackertest_la_OBJECTS) $(libcontexttrackertest_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list contextTrackerTestRunner$(EXEEXT): $(contextTrackerTestRunner_OBJECTS) $(contextTrackerTestRunner_DEPENDENCIES) @rm -f contextTrackerTestRunner$(EXEEXT) $(contextTrackerTestRunner_LINK) $(contextTrackerTestRunner_OBJECTS) $(contextTrackerTestRunner_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/contextTrackerTestRunner-contextChangeDetectorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/contextTrackerTestRunner-contextTrackerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/contextTrackerTestRunner-coreTestRunner.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< contextTrackerTestRunner-coreTestRunner.o: ../coreTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT contextTrackerTestRunner-coreTestRunner.o -MD -MP -MF $(DEPDIR)/contextTrackerTestRunner-coreTestRunner.Tpo -c -o contextTrackerTestRunner-coreTestRunner.o `test -f '../coreTestRunner.cpp' || echo '$(srcdir)/'`../coreTestRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/contextTrackerTestRunner-coreTestRunner.Tpo $(DEPDIR)/contextTrackerTestRunner-coreTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../coreTestRunner.cpp' object='contextTrackerTestRunner-coreTestRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o contextTrackerTestRunner-coreTestRunner.o `test -f '../coreTestRunner.cpp' || echo '$(srcdir)/'`../coreTestRunner.cpp contextTrackerTestRunner-coreTestRunner.obj: ../coreTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT contextTrackerTestRunner-coreTestRunner.obj -MD -MP -MF $(DEPDIR)/contextTrackerTestRunner-coreTestRunner.Tpo -c -o contextTrackerTestRunner-coreTestRunner.obj `if test -f '../coreTestRunner.cpp'; then $(CYGPATH_W) '../coreTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/../coreTestRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/contextTrackerTestRunner-coreTestRunner.Tpo $(DEPDIR)/contextTrackerTestRunner-coreTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../coreTestRunner.cpp' object='contextTrackerTestRunner-coreTestRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o contextTrackerTestRunner-coreTestRunner.obj `if test -f '../coreTestRunner.cpp'; then $(CYGPATH_W) '../coreTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/../coreTestRunner.cpp'; fi` contextTrackerTestRunner-contextChangeDetectorTest.o: contextChangeDetectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT contextTrackerTestRunner-contextChangeDetectorTest.o -MD -MP -MF $(DEPDIR)/contextTrackerTestRunner-contextChangeDetectorTest.Tpo -c -o contextTrackerTestRunner-contextChangeDetectorTest.o `test -f 'contextChangeDetectorTest.cpp' || echo '$(srcdir)/'`contextChangeDetectorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/contextTrackerTestRunner-contextChangeDetectorTest.Tpo $(DEPDIR)/contextTrackerTestRunner-contextChangeDetectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='contextChangeDetectorTest.cpp' object='contextTrackerTestRunner-contextChangeDetectorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o contextTrackerTestRunner-contextChangeDetectorTest.o `test -f 'contextChangeDetectorTest.cpp' || echo '$(srcdir)/'`contextChangeDetectorTest.cpp contextTrackerTestRunner-contextChangeDetectorTest.obj: contextChangeDetectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT contextTrackerTestRunner-contextChangeDetectorTest.obj -MD -MP -MF $(DEPDIR)/contextTrackerTestRunner-contextChangeDetectorTest.Tpo -c -o contextTrackerTestRunner-contextChangeDetectorTest.obj `if test -f 'contextChangeDetectorTest.cpp'; then $(CYGPATH_W) 'contextChangeDetectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/contextChangeDetectorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/contextTrackerTestRunner-contextChangeDetectorTest.Tpo $(DEPDIR)/contextTrackerTestRunner-contextChangeDetectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='contextChangeDetectorTest.cpp' object='contextTrackerTestRunner-contextChangeDetectorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o contextTrackerTestRunner-contextChangeDetectorTest.obj `if test -f 'contextChangeDetectorTest.cpp'; then $(CYGPATH_W) 'contextChangeDetectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/contextChangeDetectorTest.cpp'; fi` contextTrackerTestRunner-contextTrackerTest.o: contextTrackerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT contextTrackerTestRunner-contextTrackerTest.o -MD -MP -MF $(DEPDIR)/contextTrackerTestRunner-contextTrackerTest.Tpo -c -o contextTrackerTestRunner-contextTrackerTest.o `test -f 'contextTrackerTest.cpp' || echo '$(srcdir)/'`contextTrackerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/contextTrackerTestRunner-contextTrackerTest.Tpo $(DEPDIR)/contextTrackerTestRunner-contextTrackerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='contextTrackerTest.cpp' object='contextTrackerTestRunner-contextTrackerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o contextTrackerTestRunner-contextTrackerTest.o `test -f 'contextTrackerTest.cpp' || echo '$(srcdir)/'`contextTrackerTest.cpp contextTrackerTestRunner-contextTrackerTest.obj: contextTrackerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -MT contextTrackerTestRunner-contextTrackerTest.obj -MD -MP -MF $(DEPDIR)/contextTrackerTestRunner-contextTrackerTest.Tpo -c -o contextTrackerTestRunner-contextTrackerTest.obj `if test -f 'contextTrackerTest.cpp'; then $(CYGPATH_W) 'contextTrackerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/contextTrackerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/contextTrackerTestRunner-contextTrackerTest.Tpo $(DEPDIR)/contextTrackerTestRunner-contextTrackerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='contextTrackerTest.cpp' object='contextTrackerTestRunner-contextTrackerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(contextTrackerTestRunner_CPPFLAGS) $(CPPFLAGS) $(contextTrackerTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o contextTrackerTestRunner-contextTrackerTest.obj `if test -f 'contextTrackerTest.cpp'; then $(CYGPATH_W) 'contextTrackerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/contextTrackerTest.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \ clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \ clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am # 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: ���������������������������������presage-0.8.8/test/lib/core/context_tracker/contextChangeDetectorTest.cpp���������������������������0000644�0001750�0001750�00000011673�11763437013�023617� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "contextChangeDetectorTest.h" #include "core/charsets.h" CPPUNIT_TEST_SUITE_REGISTRATION( ContextChangeDetectorTest ); void ContextChangeDetectorTest::setUp() { detector = new ContextChangeDetector(DEFAULT_WORD_CHARS, DEFAULT_SEPARATOR_CHARS, DEFAULT_BLANKSPACE_CHARS, DEFAULT_CONTROL_CHARS, false); } void ContextChangeDetectorTest::tearDown() { delete detector; } void ContextChangeDetectorTest::testCharChanges() { std::cerr << "ContextChangeDetectorTest::testCharChanges()" << std::endl; detector->set_sliding_window_size("10"); const std::string line = "foo bar foobar, foo bar! Foobar foo bar... foobar. "; const std::string change = "10010001000000100001000001000000010001000100000000010"; for (size_t i = 0; i < line.size(); i++) { bool expected = (change[i] == '0' ? false : true); std::string stream = line.substr(0, i+1); std::cerr << "Stream: " << stream << std::endl; std::stringstream ss; ss << "Error detected at: " << stream << '|'; CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str().c_str(), expected, detector->context_change(stream)); detector->update_sliding_window(stream); } } void ContextChangeDetectorTest::testBlockChanges() { std::cerr << "ContextChangeDetectorTest::testBlockChanges()" << std::endl; std::string str = "The quick brown fox jumped over the lazy dog"; detector->set_sliding_window_size("10"); // sliding window is now empty, so new string will trigger a context change CPPUNIT_ASSERT_EQUAL(true, detector->context_change("The quick")); // update detector detector->update_sliding_window("The quick"); // there was no change since last time, should be false CPPUNIT_ASSERT_EQUAL(false, detector->context_change("The quick")); // no changes, should be false CPPUNIT_ASSERT_EQUAL(false, detector->context_change("The quick")); // still no changes, should still be false CPPUNIT_ASSERT_EQUAL(false, detector->context_change("The quick")); } void ContextChangeDetectorTest::testGetChange() { std::string str = "The quick brown fox jumped over the lazy dog"; detector->set_sliding_window_size("10"); // when sliding window is empty, change is equal to stream CPPUNIT_ASSERT_EQUAL(detector->change(str), str); // when sliding window contains part of stream, change is equal to text that is in stream and not in sliding window detector->update_sliding_window ("The quick bro"); CPPUNIT_ASSERT_EQUAL(detector->get_sliding_window(), std::string(" quick bro")); CPPUNIT_ASSERT_EQUAL(detector->change(str), std::string("wn fox jumped over the lazy dog")); detector->update_sliding_window ("The quick brow"); CPPUNIT_ASSERT_EQUAL(detector->get_sliding_window(), std::string("quick brow")); CPPUNIT_ASSERT_EQUAL(detector->change(str), std::string("n fox jumped over the lazy dog")); detector->update_sliding_window ("The quick brown"); CPPUNIT_ASSERT_EQUAL(detector->get_sliding_window(), std::string("uick brown")); CPPUNIT_ASSERT_EQUAL(detector->change(str), std::string(" fox jumped over the lazy dog")); detector->update_sliding_window ("The quick brown "); CPPUNIT_ASSERT_EQUAL(detector->get_sliding_window(), std::string("ick brown ")); CPPUNIT_ASSERT_EQUAL(detector->change(str), std::string("fox jumped over the lazy dog")); // remove last char from stream detector->update_sliding_window ("The quick brown"); CPPUNIT_ASSERT_EQUAL(detector->get_sliding_window(), std::string("uick brown")); CPPUNIT_ASSERT_EQUAL(detector->change(str), std::string(" fox jumped over the lazy dog")); // remove last char from stream again detector->update_sliding_window ("The quick brow"); CPPUNIT_ASSERT_EQUAL(detector->get_sliding_window(), std::string("quick brow")); CPPUNIT_ASSERT_EQUAL(detector->change(str), std::string("n fox jumped over the lazy dog")); } ���������������������������������������������������������������������presage-0.8.8/test/lib/core/context_tracker/contextTrackerTest.h������������������������������������0000644�0001750�0001750�00000004555�11737142176�022005� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CONTEXTTRACKERTEST #define PRESAGE_CONTEXTTRACKERTEST #include <cppunit/extensions/HelperMacros.h> #include "core/profileManager.h" #include "core/context_tracker/contextTracker.h" #include "core/predictorRegistry.h" #include "../../common/testStringSuite.h" class ContextTrackerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testConstructor(); void testGetPrefix(); void testGetToken(); void testGetFutureStream(); void testGetPastStream(); void testToString(); void testContextChange(); void testCumulativeContextChange(); private: TestStringSuite* testStringSuite; ContextTracker* contextTracker; Configuration* configuration; PredictorRegistry* predictorRegistry; CPPUNIT_TEST_SUITE( ContextTrackerTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testGetPrefix ); CPPUNIT_TEST( testGetToken ); CPPUNIT_TEST( testGetFutureStream ); CPPUNIT_TEST( testGetPastStream ); CPPUNIT_TEST( testToString ); CPPUNIT_TEST( testContextChange ); CPPUNIT_TEST( testCumulativeContextChange ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_CONTEXTTRACKERTEST ���������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/combinerTest.cpp��������������������������������������������������������0000644�0001750�0001750�00000010707�11737142176�015733� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "combinerTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( CombinerTest ); void CombinerTest::setUp() { sugg1Ptr = new Suggestion("foo", 0.1); sugg2Ptr = new Suggestion("foo", 0.3); sugg3Ptr = new Suggestion("foo", 0.5); sugg123Ptr = new Suggestion("foo", 0.9); sugg4Ptr = new Suggestion("bar", 0.2); sugg5Ptr = new Suggestion("bar", 0.4); sugg6Ptr = new Suggestion("bar", 0.6); sugg456Ptr = new Suggestion("bar", 1.0); prediction1 = new Prediction(); prediction1->addSuggestion(*sugg1Ptr); prediction1->addSuggestion(*sugg4Ptr); // same as prediction1 expected_prediction1 = new Prediction(); expected_prediction1->addSuggestion(*sugg1Ptr); expected_prediction1->addSuggestion(*sugg4Ptr); prediction2 = new Prediction(); prediction2->addSuggestion(*sugg1Ptr); prediction2->addSuggestion(*sugg2Ptr); prediction2->addSuggestion(*sugg3Ptr); // only one foo suggestion, sum of probs expected_prediction2 = new Prediction(); expected_prediction2->addSuggestion(*sugg123Ptr); prediction3 = new Prediction(); prediction3->addSuggestion(*sugg1Ptr); prediction3->addSuggestion(*sugg2Ptr); prediction3->addSuggestion(*sugg3Ptr); prediction3->addSuggestion(*sugg4Ptr); // only one foo suggestion, sum of probs and one bar suggestion expected_prediction3 = new Prediction(); expected_prediction3->addSuggestion(*sugg123Ptr); expected_prediction3->addSuggestion(*sugg4Ptr); prediction4 = new Prediction(); prediction4->addSuggestion(*sugg3Ptr); prediction4->addSuggestion(*sugg4Ptr); prediction4->addSuggestion(*sugg5Ptr); prediction4->addSuggestion(*sugg6Ptr); // only one bar suggestion, sum of probs and one foo suggestion expected_prediction4 = new Prediction(); expected_prediction4->addSuggestion(*sugg3Ptr); expected_prediction4->addSuggestion(*sugg456Ptr); prediction5 = new Prediction(); prediction5->addSuggestion(*sugg1Ptr); prediction5->addSuggestion(*sugg2Ptr); prediction5->addSuggestion(*sugg3Ptr); prediction5->addSuggestion(*sugg4Ptr); prediction5->addSuggestion(*sugg5Ptr); prediction5->addSuggestion(*sugg6Ptr); // one foo suggestion and one bar suggestion, both with sum of // probs expected_prediction5 = new Prediction(); expected_prediction5->addSuggestion(*sugg123Ptr); expected_prediction5->addSuggestion(*sugg456Ptr); } void CombinerTest::tearDown() { delete sugg1Ptr; delete sugg2Ptr; delete sugg3Ptr; delete sugg4Ptr; delete sugg5Ptr; delete sugg6Ptr; delete sugg123Ptr; delete sugg456Ptr; delete prediction1; delete prediction2; delete prediction3; delete prediction4; delete prediction5; delete expected_prediction1; delete expected_prediction2; delete expected_prediction3; delete expected_prediction4; delete expected_prediction5; } void CombinerTest::testFilter() { ConcreteCombiner combiner; CPPUNIT_ASSERT_EQUAL(*expected_prediction1, combiner.filter(*prediction1)); CPPUNIT_ASSERT_EQUAL(*expected_prediction2, combiner.filter(*prediction2)); CPPUNIT_ASSERT_EQUAL(*expected_prediction3, combiner.filter(*prediction3)); CPPUNIT_ASSERT_EQUAL(*expected_prediction4, combiner.filter(*prediction4)); CPPUNIT_ASSERT_EQUAL(*expected_prediction5, combiner.filter(*prediction5)); } ���������������������������������������������������������presage-0.8.8/test/lib/core/profileManagerTest.h����������������������������������������������������0000644�0001750�0001750�00000003315�11737142176�016532� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PROFILEMANAGERTEST #define PRESAGE_PROFILEMANAGERTEST #include <cppunit/extensions/HelperMacros.h> #include "core/profileManager.h" class ProfileManagerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testProfile(); void testCustomProfile(); private: ProfileManager* profileManager; Configuration* configuration; CPPUNIT_TEST_SUITE( ProfileManagerTest ); CPPUNIT_TEST( testProfile ); CPPUNIT_TEST( testCustomProfile ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_PROFILEMANAGERTEST �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/suggestionTest.cpp������������������������������������������������������0000644�0001750�0001750�00000007142�11737142176�016323� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "suggestionTest.h" #include "core/suggestion.h" #include <string> CPPUNIT_TEST_SUITE_REGISTRATION( SuggestionTest ); void SuggestionTest::setUp() { sugg1Ptr = new Suggestion(); sugg2Ptr = new Suggestion( "test" ); sugg3Ptr = new Suggestion( "test", 0.5 ); sugg4Ptr = new Suggestion( "case", 0.7 ); sugg5Ptr = new Suggestion( "foo", 0.1 ); sugg6Ptr = new Suggestion( "bar", 0.3 ); sugg7Ptr = new Suggestion( "base", 0.7 ); sugg8Ptr = new Suggestion( "base", 0.7 ); } void SuggestionTest::tearDown() { delete sugg1Ptr; delete sugg2Ptr; delete sugg3Ptr; delete sugg4Ptr; delete sugg5Ptr; delete sugg6Ptr; delete sugg7Ptr; delete sugg8Ptr; } void SuggestionTest::testConstructor() { CPPUNIT_ASSERT( sugg1Ptr->getWord() == "" ); CPPUNIT_ASSERT( sugg1Ptr->getProbability() == 0.0 ); CPPUNIT_ASSERT( sugg2Ptr->getWord() == "test" ); CPPUNIT_ASSERT( sugg2Ptr->getProbability() == 0.0 ); CPPUNIT_ASSERT( sugg3Ptr->getWord() == "test" ); CPPUNIT_ASSERT( sugg3Ptr->getProbability() == 0.5 ); CPPUNIT_ASSERT( sugg4Ptr->getWord() == "case" ); CPPUNIT_ASSERT( sugg4Ptr->getProbability() == 0.7 ); } void SuggestionTest::testOperatorEqual() { //CPPUNIT_ASSERT( *sugg2Ptr == *sugg3Ptr ); CPPUNIT_ASSERT( !( *sugg3Ptr == *sugg4Ptr ) ); CPPUNIT_ASSERT_EQUAL(*sugg7Ptr, *sugg8Ptr); CPPUNIT_ASSERT_EQUAL(*sugg5Ptr, *sugg5Ptr); } void SuggestionTest::testOperatorNotEqual() { CPPUNIT_ASSERT(*sugg2Ptr != *sugg3Ptr); CPPUNIT_ASSERT(*sugg3Ptr != *sugg4Ptr); CPPUNIT_ASSERT(*sugg4Ptr != *sugg5Ptr); CPPUNIT_ASSERT(*sugg5Ptr != *sugg6Ptr); CPPUNIT_ASSERT(!(*sugg7Ptr != *sugg8Ptr)); CPPUNIT_ASSERT(!(*sugg5Ptr != *sugg5Ptr)); } void SuggestionTest::testOperatorMinus() { CPPUNIT_ASSERT( *sugg1Ptr < *sugg2Ptr ); CPPUNIT_ASSERT( !( *sugg1Ptr < *sugg1Ptr ) ); CPPUNIT_ASSERT( *sugg2Ptr < *sugg3Ptr ); CPPUNIT_ASSERT( *sugg7Ptr < *sugg4Ptr ); CPPUNIT_ASSERT( !( *sugg4Ptr < *sugg3Ptr ) ); } void SuggestionTest::testGetSetMethods() { CPPUNIT_ASSERT( sugg5Ptr->getWord() == "foo" ); CPPUNIT_ASSERT( sugg6Ptr->getWord() == "bar" ); CPPUNIT_ASSERT( sugg5Ptr->getProbability() == 0.1 ); CPPUNIT_ASSERT( sugg6Ptr->getProbability() == 0.3 ); sugg5Ptr->setWord( sugg6Ptr->getWord() ); CPPUNIT_ASSERT( sugg5Ptr->getWord() == sugg6Ptr->getWord() ); sugg5Ptr->setProbability( sugg6Ptr->getProbability() ); CPPUNIT_ASSERT( sugg5Ptr->getProbability() == sugg6Ptr->getProbability() ); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/variableTest.h����������������������������������������������������������0000644�0001750�0001750�00000003154�11737142176�015365� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_VARIABLETEST #define PRESAGE_VARIABLETEST #include <cppunit/extensions/HelperMacros.h> #include "core/profile.h" class VariableTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void test_string_to_variable(); void test_variable_to_string(); private: CPPUNIT_TEST_SUITE( VariableTest ); CPPUNIT_TEST( test_string_to_variable ); CPPUNIT_TEST( test_variable_to_string ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_VARIABLETEST ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/Makefile.in�������������������������������������������������������������0000644�0001750�0001750�00000155405�11763440356�014643� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_CPPUNIT_TRUE@TESTS = coreTestRunner$(EXEEXT) @HAVE_CPPUNIT_TRUE@check_PROGRAMS = $(am__EXEEXT_1) @BUILD_TINYXML_TRUE@@HAVE_CPPUNIT_TRUE@am__append_1 = -I$(top_srcdir)/src/lib/tinyxml @BUILD_TINYXML_TRUE@@HAVE_CPPUNIT_TRUE@am__append_2 = $(top_builddir)/src/lib/tinyxml/libtinyxml.la @BUILD_TINYXML_FALSE@@HAVE_CPPUNIT_TRUE@am__append_3 = -ltinyxml subdir = test/lib/core DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__DEPENDENCIES_1 = @HAVE_CPPUNIT_TRUE@libcoretest_la_DEPENDENCIES = \ @HAVE_CPPUNIT_TRUE@ ../common/libcommon.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/core/libcore.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/predictors/libpredictors.la \ @HAVE_CPPUNIT_TRUE@ $(am__append_2) $(am__DEPENDENCIES_1) am_libcoretest_la_OBJECTS = libcoretest_la_OBJECTS = $(am_libcoretest_la_OBJECTS) @HAVE_CPPUNIT_TRUE@am_libcoretest_la_rpath = @HAVE_CPPUNIT_TRUE@am__EXEEXT_1 = coreTestRunner$(EXEEXT) am__coreTestRunner_SOURCES_DIST = coreTestRunner.cpp suggestionTest.h \ suggestionTest.cpp predictionTest.h predictionTest.cpp \ selectorTest.h selectorTest.cpp profileTest.h profileTest.cpp \ profileManagerTest.h profileManagerTest.cpp \ meritocracyCombinerTest.h meritocracyCombinerTest.cpp \ loggerTest.h loggerTest.cpp variableTest.h variableTest.cpp \ configurationTest.h configurationTest.cpp combinerTest.h \ combinerTest.cpp predictorRegistryTest.h \ predictorRegistryTest.cpp @HAVE_CPPUNIT_TRUE@am_coreTestRunner_OBJECTS = \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-coreTestRunner.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-suggestionTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-predictionTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-selectorTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-profileTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-profileManagerTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-meritocracyCombinerTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-loggerTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-variableTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-configurationTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-combinerTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ coreTestRunner-predictorRegistryTest.$(OBJEXT) coreTestRunner_OBJECTS = $(am_coreTestRunner_OBJECTS) @HAVE_CPPUNIT_TRUE@coreTestRunner_DEPENDENCIES = libcoretest.la coreTestRunner_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) \ $(coreTestRunner_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libcoretest_la_SOURCES) $(coreTestRunner_SOURCES) DIST_SOURCES = $(libcoretest_la_SOURCES) \ $(am__coreTestRunner_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = tokenizer context_tracker EXTRA_DIST = profileTest.xml @HAVE_CPPUNIT_TRUE@coreTestRunner_SOURCES = \ @HAVE_CPPUNIT_TRUE@ coreTestRunner.cpp \ @HAVE_CPPUNIT_TRUE@ suggestionTest.h suggestionTest.cpp \ @HAVE_CPPUNIT_TRUE@ predictionTest.h predictionTest.cpp \ @HAVE_CPPUNIT_TRUE@ selectorTest.h selectorTest.cpp \ @HAVE_CPPUNIT_TRUE@ profileTest.h profileTest.cpp \ @HAVE_CPPUNIT_TRUE@ profileManagerTest.h profileManagerTest.cpp \ @HAVE_CPPUNIT_TRUE@ meritocracyCombinerTest.h meritocracyCombinerTest.cpp \ @HAVE_CPPUNIT_TRUE@ loggerTest.h loggerTest.cpp \ @HAVE_CPPUNIT_TRUE@ variableTest.h variableTest.cpp \ @HAVE_CPPUNIT_TRUE@ configurationTest.h configurationTest.cpp \ @HAVE_CPPUNIT_TRUE@ combinerTest.h combinerTest.cpp \ @HAVE_CPPUNIT_TRUE@ predictorRegistryTest.h predictorRegistryTest.cpp @HAVE_CPPUNIT_TRUE@coreTestRunner_CPPFLAGS = -I$(top_srcdir)/src/lib \ @HAVE_CPPUNIT_TRUE@ $(am__append_1) @HAVE_CPPUNIT_TRUE@coreTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@coreTestRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@coreTestRunner_LDADD = libcoretest.la @HAVE_CPPUNIT_TRUE@check_LTLIBRARIES = \ @HAVE_CPPUNIT_TRUE@ libcoretest.la @HAVE_CPPUNIT_TRUE@libcoretest_la_SOURCES = @HAVE_CPPUNIT_TRUE@libcoretest_la_LIBADD = ../common/libcommon.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/core/libcore.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/predictors/libpredictors.la \ @HAVE_CPPUNIT_TRUE@ $(am__append_2) $(am__append_3) all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lib/core/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/lib/core/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkLTLIBRARIES: -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES) @list='$(check_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libcoretest.la: $(libcoretest_la_OBJECTS) $(libcoretest_la_DEPENDENCIES) $(LINK) $(am_libcoretest_la_rpath) $(libcoretest_la_OBJECTS) $(libcoretest_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list coreTestRunner$(EXEEXT): $(coreTestRunner_OBJECTS) $(coreTestRunner_DEPENDENCIES) @rm -f coreTestRunner$(EXEEXT) $(coreTestRunner_LINK) $(coreTestRunner_OBJECTS) $(coreTestRunner_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-combinerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-configurationTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-coreTestRunner.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-loggerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-meritocracyCombinerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-predictionTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-predictorRegistryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-profileManagerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-profileTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-selectorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-suggestionTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coreTestRunner-variableTest.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< coreTestRunner-coreTestRunner.o: coreTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-coreTestRunner.o -MD -MP -MF $(DEPDIR)/coreTestRunner-coreTestRunner.Tpo -c -o coreTestRunner-coreTestRunner.o `test -f 'coreTestRunner.cpp' || echo '$(srcdir)/'`coreTestRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-coreTestRunner.Tpo $(DEPDIR)/coreTestRunner-coreTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='coreTestRunner.cpp' object='coreTestRunner-coreTestRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-coreTestRunner.o `test -f 'coreTestRunner.cpp' || echo '$(srcdir)/'`coreTestRunner.cpp coreTestRunner-coreTestRunner.obj: coreTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-coreTestRunner.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-coreTestRunner.Tpo -c -o coreTestRunner-coreTestRunner.obj `if test -f 'coreTestRunner.cpp'; then $(CYGPATH_W) 'coreTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/coreTestRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-coreTestRunner.Tpo $(DEPDIR)/coreTestRunner-coreTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='coreTestRunner.cpp' object='coreTestRunner-coreTestRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-coreTestRunner.obj `if test -f 'coreTestRunner.cpp'; then $(CYGPATH_W) 'coreTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/coreTestRunner.cpp'; fi` coreTestRunner-suggestionTest.o: suggestionTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-suggestionTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-suggestionTest.Tpo -c -o coreTestRunner-suggestionTest.o `test -f 'suggestionTest.cpp' || echo '$(srcdir)/'`suggestionTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-suggestionTest.Tpo $(DEPDIR)/coreTestRunner-suggestionTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='suggestionTest.cpp' object='coreTestRunner-suggestionTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-suggestionTest.o `test -f 'suggestionTest.cpp' || echo '$(srcdir)/'`suggestionTest.cpp coreTestRunner-suggestionTest.obj: suggestionTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-suggestionTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-suggestionTest.Tpo -c -o coreTestRunner-suggestionTest.obj `if test -f 'suggestionTest.cpp'; then $(CYGPATH_W) 'suggestionTest.cpp'; else $(CYGPATH_W) '$(srcdir)/suggestionTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-suggestionTest.Tpo $(DEPDIR)/coreTestRunner-suggestionTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='suggestionTest.cpp' object='coreTestRunner-suggestionTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-suggestionTest.obj `if test -f 'suggestionTest.cpp'; then $(CYGPATH_W) 'suggestionTest.cpp'; else $(CYGPATH_W) '$(srcdir)/suggestionTest.cpp'; fi` coreTestRunner-predictionTest.o: predictionTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-predictionTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-predictionTest.Tpo -c -o coreTestRunner-predictionTest.o `test -f 'predictionTest.cpp' || echo '$(srcdir)/'`predictionTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-predictionTest.Tpo $(DEPDIR)/coreTestRunner-predictionTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictionTest.cpp' object='coreTestRunner-predictionTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-predictionTest.o `test -f 'predictionTest.cpp' || echo '$(srcdir)/'`predictionTest.cpp coreTestRunner-predictionTest.obj: predictionTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-predictionTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-predictionTest.Tpo -c -o coreTestRunner-predictionTest.obj `if test -f 'predictionTest.cpp'; then $(CYGPATH_W) 'predictionTest.cpp'; else $(CYGPATH_W) '$(srcdir)/predictionTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-predictionTest.Tpo $(DEPDIR)/coreTestRunner-predictionTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictionTest.cpp' object='coreTestRunner-predictionTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-predictionTest.obj `if test -f 'predictionTest.cpp'; then $(CYGPATH_W) 'predictionTest.cpp'; else $(CYGPATH_W) '$(srcdir)/predictionTest.cpp'; fi` coreTestRunner-selectorTest.o: selectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-selectorTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-selectorTest.Tpo -c -o coreTestRunner-selectorTest.o `test -f 'selectorTest.cpp' || echo '$(srcdir)/'`selectorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-selectorTest.Tpo $(DEPDIR)/coreTestRunner-selectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='selectorTest.cpp' object='coreTestRunner-selectorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-selectorTest.o `test -f 'selectorTest.cpp' || echo '$(srcdir)/'`selectorTest.cpp coreTestRunner-selectorTest.obj: selectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-selectorTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-selectorTest.Tpo -c -o coreTestRunner-selectorTest.obj `if test -f 'selectorTest.cpp'; then $(CYGPATH_W) 'selectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/selectorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-selectorTest.Tpo $(DEPDIR)/coreTestRunner-selectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='selectorTest.cpp' object='coreTestRunner-selectorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-selectorTest.obj `if test -f 'selectorTest.cpp'; then $(CYGPATH_W) 'selectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/selectorTest.cpp'; fi` coreTestRunner-profileTest.o: profileTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-profileTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-profileTest.Tpo -c -o coreTestRunner-profileTest.o `test -f 'profileTest.cpp' || echo '$(srcdir)/'`profileTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-profileTest.Tpo $(DEPDIR)/coreTestRunner-profileTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='profileTest.cpp' object='coreTestRunner-profileTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-profileTest.o `test -f 'profileTest.cpp' || echo '$(srcdir)/'`profileTest.cpp coreTestRunner-profileTest.obj: profileTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-profileTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-profileTest.Tpo -c -o coreTestRunner-profileTest.obj `if test -f 'profileTest.cpp'; then $(CYGPATH_W) 'profileTest.cpp'; else $(CYGPATH_W) '$(srcdir)/profileTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-profileTest.Tpo $(DEPDIR)/coreTestRunner-profileTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='profileTest.cpp' object='coreTestRunner-profileTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-profileTest.obj `if test -f 'profileTest.cpp'; then $(CYGPATH_W) 'profileTest.cpp'; else $(CYGPATH_W) '$(srcdir)/profileTest.cpp'; fi` coreTestRunner-profileManagerTest.o: profileManagerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-profileManagerTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-profileManagerTest.Tpo -c -o coreTestRunner-profileManagerTest.o `test -f 'profileManagerTest.cpp' || echo '$(srcdir)/'`profileManagerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-profileManagerTest.Tpo $(DEPDIR)/coreTestRunner-profileManagerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='profileManagerTest.cpp' object='coreTestRunner-profileManagerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-profileManagerTest.o `test -f 'profileManagerTest.cpp' || echo '$(srcdir)/'`profileManagerTest.cpp coreTestRunner-profileManagerTest.obj: profileManagerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-profileManagerTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-profileManagerTest.Tpo -c -o coreTestRunner-profileManagerTest.obj `if test -f 'profileManagerTest.cpp'; then $(CYGPATH_W) 'profileManagerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/profileManagerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-profileManagerTest.Tpo $(DEPDIR)/coreTestRunner-profileManagerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='profileManagerTest.cpp' object='coreTestRunner-profileManagerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-profileManagerTest.obj `if test -f 'profileManagerTest.cpp'; then $(CYGPATH_W) 'profileManagerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/profileManagerTest.cpp'; fi` coreTestRunner-meritocracyCombinerTest.o: meritocracyCombinerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-meritocracyCombinerTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-meritocracyCombinerTest.Tpo -c -o coreTestRunner-meritocracyCombinerTest.o `test -f 'meritocracyCombinerTest.cpp' || echo '$(srcdir)/'`meritocracyCombinerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-meritocracyCombinerTest.Tpo $(DEPDIR)/coreTestRunner-meritocracyCombinerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='meritocracyCombinerTest.cpp' object='coreTestRunner-meritocracyCombinerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-meritocracyCombinerTest.o `test -f 'meritocracyCombinerTest.cpp' || echo '$(srcdir)/'`meritocracyCombinerTest.cpp coreTestRunner-meritocracyCombinerTest.obj: meritocracyCombinerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-meritocracyCombinerTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-meritocracyCombinerTest.Tpo -c -o coreTestRunner-meritocracyCombinerTest.obj `if test -f 'meritocracyCombinerTest.cpp'; then $(CYGPATH_W) 'meritocracyCombinerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/meritocracyCombinerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-meritocracyCombinerTest.Tpo $(DEPDIR)/coreTestRunner-meritocracyCombinerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='meritocracyCombinerTest.cpp' object='coreTestRunner-meritocracyCombinerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-meritocracyCombinerTest.obj `if test -f 'meritocracyCombinerTest.cpp'; then $(CYGPATH_W) 'meritocracyCombinerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/meritocracyCombinerTest.cpp'; fi` coreTestRunner-loggerTest.o: loggerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-loggerTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-loggerTest.Tpo -c -o coreTestRunner-loggerTest.o `test -f 'loggerTest.cpp' || echo '$(srcdir)/'`loggerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-loggerTest.Tpo $(DEPDIR)/coreTestRunner-loggerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='loggerTest.cpp' object='coreTestRunner-loggerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-loggerTest.o `test -f 'loggerTest.cpp' || echo '$(srcdir)/'`loggerTest.cpp coreTestRunner-loggerTest.obj: loggerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-loggerTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-loggerTest.Tpo -c -o coreTestRunner-loggerTest.obj `if test -f 'loggerTest.cpp'; then $(CYGPATH_W) 'loggerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/loggerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-loggerTest.Tpo $(DEPDIR)/coreTestRunner-loggerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='loggerTest.cpp' object='coreTestRunner-loggerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-loggerTest.obj `if test -f 'loggerTest.cpp'; then $(CYGPATH_W) 'loggerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/loggerTest.cpp'; fi` coreTestRunner-variableTest.o: variableTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-variableTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-variableTest.Tpo -c -o coreTestRunner-variableTest.o `test -f 'variableTest.cpp' || echo '$(srcdir)/'`variableTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-variableTest.Tpo $(DEPDIR)/coreTestRunner-variableTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='variableTest.cpp' object='coreTestRunner-variableTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-variableTest.o `test -f 'variableTest.cpp' || echo '$(srcdir)/'`variableTest.cpp coreTestRunner-variableTest.obj: variableTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-variableTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-variableTest.Tpo -c -o coreTestRunner-variableTest.obj `if test -f 'variableTest.cpp'; then $(CYGPATH_W) 'variableTest.cpp'; else $(CYGPATH_W) '$(srcdir)/variableTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-variableTest.Tpo $(DEPDIR)/coreTestRunner-variableTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='variableTest.cpp' object='coreTestRunner-variableTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-variableTest.obj `if test -f 'variableTest.cpp'; then $(CYGPATH_W) 'variableTest.cpp'; else $(CYGPATH_W) '$(srcdir)/variableTest.cpp'; fi` coreTestRunner-configurationTest.o: configurationTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-configurationTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-configurationTest.Tpo -c -o coreTestRunner-configurationTest.o `test -f 'configurationTest.cpp' || echo '$(srcdir)/'`configurationTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-configurationTest.Tpo $(DEPDIR)/coreTestRunner-configurationTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='configurationTest.cpp' object='coreTestRunner-configurationTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-configurationTest.o `test -f 'configurationTest.cpp' || echo '$(srcdir)/'`configurationTest.cpp coreTestRunner-configurationTest.obj: configurationTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-configurationTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-configurationTest.Tpo -c -o coreTestRunner-configurationTest.obj `if test -f 'configurationTest.cpp'; then $(CYGPATH_W) 'configurationTest.cpp'; else $(CYGPATH_W) '$(srcdir)/configurationTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-configurationTest.Tpo $(DEPDIR)/coreTestRunner-configurationTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='configurationTest.cpp' object='coreTestRunner-configurationTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-configurationTest.obj `if test -f 'configurationTest.cpp'; then $(CYGPATH_W) 'configurationTest.cpp'; else $(CYGPATH_W) '$(srcdir)/configurationTest.cpp'; fi` coreTestRunner-combinerTest.o: combinerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-combinerTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-combinerTest.Tpo -c -o coreTestRunner-combinerTest.o `test -f 'combinerTest.cpp' || echo '$(srcdir)/'`combinerTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-combinerTest.Tpo $(DEPDIR)/coreTestRunner-combinerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='combinerTest.cpp' object='coreTestRunner-combinerTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-combinerTest.o `test -f 'combinerTest.cpp' || echo '$(srcdir)/'`combinerTest.cpp coreTestRunner-combinerTest.obj: combinerTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-combinerTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-combinerTest.Tpo -c -o coreTestRunner-combinerTest.obj `if test -f 'combinerTest.cpp'; then $(CYGPATH_W) 'combinerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/combinerTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-combinerTest.Tpo $(DEPDIR)/coreTestRunner-combinerTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='combinerTest.cpp' object='coreTestRunner-combinerTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-combinerTest.obj `if test -f 'combinerTest.cpp'; then $(CYGPATH_W) 'combinerTest.cpp'; else $(CYGPATH_W) '$(srcdir)/combinerTest.cpp'; fi` coreTestRunner-predictorRegistryTest.o: predictorRegistryTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-predictorRegistryTest.o -MD -MP -MF $(DEPDIR)/coreTestRunner-predictorRegistryTest.Tpo -c -o coreTestRunner-predictorRegistryTest.o `test -f 'predictorRegistryTest.cpp' || echo '$(srcdir)/'`predictorRegistryTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-predictorRegistryTest.Tpo $(DEPDIR)/coreTestRunner-predictorRegistryTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorRegistryTest.cpp' object='coreTestRunner-predictorRegistryTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-predictorRegistryTest.o `test -f 'predictorRegistryTest.cpp' || echo '$(srcdir)/'`predictorRegistryTest.cpp coreTestRunner-predictorRegistryTest.obj: predictorRegistryTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -MT coreTestRunner-predictorRegistryTest.obj -MD -MP -MF $(DEPDIR)/coreTestRunner-predictorRegistryTest.Tpo -c -o coreTestRunner-predictorRegistryTest.obj `if test -f 'predictorRegistryTest.cpp'; then $(CYGPATH_W) 'predictorRegistryTest.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorRegistryTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/coreTestRunner-predictorRegistryTest.Tpo $(DEPDIR)/coreTestRunner-predictorRegistryTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorRegistryTest.cpp' object='coreTestRunner-predictorRegistryTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(coreTestRunner_CPPFLAGS) $(CPPFLAGS) $(coreTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o coreTestRunner-predictorRegistryTest.obj `if test -f 'predictorRegistryTest.cpp'; then $(CYGPATH_W) 'predictorRegistryTest.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorRegistryTest.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \ clean-libtool mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-TESTS check-am clean \ clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \ clean-libtool ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # 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: �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/loggerTest.h������������������������������������������������������������0000644�0001750�0001750�00000003373�11737142176�015062� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_LOGGERTEST #define PRESAGE_LOGGERTEST #include <cppunit/extensions/HelperMacros.h> #include "core/logger.h" class LoggerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testStandardErrorOutput(); void testFileOutput(); void testSetLevelManipulator(); void testCurrentLevelManipulator(); private: CPPUNIT_TEST_SUITE( LoggerTest ); CPPUNIT_TEST( testStandardErrorOutput ); CPPUNIT_TEST( testFileOutput ); CPPUNIT_TEST( testSetLevelManipulator ); CPPUNIT_TEST( testCurrentLevelManipulator ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_LOGGERTEST ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/combinerTest.h����������������������������������������������������������0000644�0001750�0001750�00000004730�11737142176�015377� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_COMBINERTEST #define PRESAGE_COMBINERTEST #include <cppunit/extensions/HelperMacros.h> #include <core/combiner.h> class CombinerTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); class ConcreteCombiner : public Combiner { public: // provide dummy implementation of pure virtual method Prediction combine(const std::vector<Prediction>&) { Prediction result; return result; } // wrap around base class protected method filter Prediction filter(const Prediction& prediction) const { return Combiner::filter(prediction); } }; void testFilter(); private: Suggestion* sugg1Ptr; Suggestion* sugg2Ptr; Suggestion* sugg3Ptr; Suggestion* sugg4Ptr; Suggestion* sugg5Ptr; Suggestion* sugg6Ptr; Suggestion* sugg123Ptr; Suggestion* sugg456Ptr; Prediction* prediction1; Prediction* prediction2; Prediction* prediction3; Prediction* prediction4; Prediction* prediction5; Prediction* expected_prediction1; Prediction* expected_prediction2; Prediction* expected_prediction3; Prediction* expected_prediction4; Prediction* expected_prediction5; CPPUNIT_TEST_SUITE( CombinerTest ); CPPUNIT_TEST( testFilter ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_COMBINERTEST ����������������������������������������presage-0.8.8/test/lib/core/configurationTest.h�����������������������������������������������������0000644�0001750�0001750�00000003113�11737142176�016442� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_CONFIGURATIONTEST #define PRESAGE_CONFIGURATIONTEST #include <cppunit/extensions/HelperMacros.h> #include "core/configuration.h" class ConfigurationTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void test_get_set(); private: Configuration* configuration; CPPUNIT_TEST_SUITE( ConfigurationTest ); CPPUNIT_TEST( test_get_set ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_CONFIGURATIONTEST �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/profileManagerTest.cpp��������������������������������������������������0000644�0001750�0001750�00000006526�11763734722�017077� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "profileManagerTest.h" #include "../common/stringstreamPresageCallback.h" #include "core/predictorRegistry.h" #include "core/context_tracker/contextTracker.h" #include "core/predictorActivator.h" #include "core/selector.h" #include <fstream> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif CPPUNIT_TEST_SUITE_REGISTRATION( ProfileManagerTest ); void ProfileManagerTest::setUp() { profileManager = new ProfileManager("non-existant-profile.xml"); configuration = profileManager->get_configuration (); } void ProfileManagerTest::tearDown() { delete profileManager; } void ProfileManagerTest::testProfile() { // test that some default variables are there in retrieved config CPPUNIT_ASSERT(configuration->find (ProfileManager::LOGGER) != 0); CPPUNIT_ASSERT(configuration->find (PredictorRegistry::PREDICTORS) != 0); CPPUNIT_ASSERT(configuration->find (ContextTracker::LOGGER) != 0); CPPUNIT_ASSERT(configuration->find (Selector::LOGGER) != 0); CPPUNIT_ASSERT(configuration->find (PredictorActivator::LOGGER) != 0); } void ProfileManagerTest::testCustomProfile() { std::cout << "ProfileManagerTest::testCustomProfile()" << std::endl; // create custom profile const std::string custom_profile = "custom_profile.xml"; std::ofstream profile_stream(custom_profile.c_str()); profile_stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n" << "<Presage>\n" << " <ProfileManager>\n" << " <LOGGER>ERROR</LOGGER>\n" << " <AUTOPERSIST>false</AUTOPERSIST>\n" << " </ProfileManager>\n" << " <Custom>CUSTOM</Custom>\n" << "</Presage>\n"; profile_stream.close(); delete profileManager; profileManager = new ProfileManager (custom_profile); configuration = profileManager->get_configuration(); Value value = configuration->find ("Presage.Custom")->get_value (); CPPUNIT_ASSERT_EQUAL(std::string("CUSTOM"), value); #ifdef HAVE_UNISTD_H // remove file int result = unlink(custom_profile.c_str()); assert(result == 0); #else // fail test std::string message = "Unable to remove custom profile file " + custom_profile; CPPUNIT_FAIL(message.c_str()); #endif } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/selectorTest.cpp��������������������������������������������������������0000644�0001750�0001750�00000041720�11763437013�015750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "selectorTest.h" #include "../common/stringstreamPresageCallback.h" CPPUNIT_TEST_SUITE_REGISTRATION( SelectorTest ); SelectorTest::TestDataSuite::TestDataSuite() {} SelectorTest::TestDataSuite::~TestDataSuite() {} void SelectorTest::TestDataSuite::init() {} bool SelectorTest::TestDataSuite::hasMoreTestData() const { if (iter != testData.end()) { return true; } else { return false; } } void SelectorTest::TestDataSuite::nextTestData() { iter++; } SelectorTest::TestDataSuite_S6_NR_T0::TestDataSuite_S6_NR_T0() { init(); } void SelectorTest::TestDataSuite_S6_NR_T0::init() { TestData* td; Prediction* ip; Prediction* op; td = new TestData; ip = new Prediction; op = new Prediction; ip->addSuggestion(Suggestion("foo", 0.9)); ip->addSuggestion(Suggestion("foo1", 0.8)); ip->addSuggestion(Suggestion("foo2", 0.7)); ip->addSuggestion(Suggestion("foo3", 0.6)); ip->addSuggestion(Suggestion("foo4", 0.5)); ip->addSuggestion(Suggestion("foo5", 0.4)); ip->addSuggestion(Suggestion("foo6", 0.3)); ip->addSuggestion(Suggestion("foobar", 0.2)); ip->addSuggestion(Suggestion("foobar1", 0.1)); ip->addSuggestion(Suggestion("foobar2", 0.09)); ip->addSuggestion(Suggestion("foobar3", 0.08)); ip->addSuggestion(Suggestion("foobar4", 0.07)); ip->addSuggestion(Suggestion("foobar5", 0.06)); ip->addSuggestion(Suggestion("foobar6", 0.05)); ip->addSuggestion(Suggestion("foobar7", 0.04)); ip->addSuggestion(Suggestion("foobar8", 0.03)); ip->addSuggestion(Suggestion("foobar9", 0.02)); ip->addSuggestion(Suggestion("foobarfoo", 0.01)); ip->addSuggestion(Suggestion("foobarfoo1", 0.009)); ip->addSuggestion(Suggestion("foobarfoo2", 0.008)); ip->addSuggestion(Suggestion("foobarfoo3", 0.007)); op->addSuggestion(Suggestion("foo", 0.9)); op->addSuggestion(Suggestion("foo1", 0.8)); op->addSuggestion(Suggestion("foo2", 0.7)); op->addSuggestion(Suggestion("foo3", 0.6)); op->addSuggestion(Suggestion("foo4", 0.5)); op->addSuggestion(Suggestion("foo5", 0.4)); td->updateString = "f"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foo6", 0.3)); op->addSuggestion(Suggestion("foobar", 0.2)); op->addSuggestion(Suggestion("foobar1", 0.1)); op->addSuggestion(Suggestion("foobar2", 0.09)); op->addSuggestion(Suggestion("foobar3", 0.08)); op->addSuggestion(Suggestion("foobar4", 0.07)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foobar5", 0.06)); op->addSuggestion(Suggestion("foobar6", 0.05)); op->addSuggestion(Suggestion("foobar7", 0.04)); op->addSuggestion(Suggestion("foobar8", 0.03)); op->addSuggestion(Suggestion("foobar9", 0.02)); op->addSuggestion(Suggestion("foobarfoo", 0.01)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; iter = testData.begin(); } SelectorTest::TestDataSuite_S6_R_T0::TestDataSuite_S6_R_T0() { init(); } void SelectorTest::TestDataSuite_S6_R_T0::init() { TestData* td; Prediction* ip; Prediction* op; td = new TestData; ip = new Prediction; op = new Prediction; ip->addSuggestion(Suggestion("foo", 0.9)); ip->addSuggestion(Suggestion("foo1", 0.8)); ip->addSuggestion(Suggestion("foo2", 0.7)); ip->addSuggestion(Suggestion("foo3", 0.6)); ip->addSuggestion(Suggestion("foo4", 0.5)); ip->addSuggestion(Suggestion("foo5", 0.4)); ip->addSuggestion(Suggestion("foo6", 0.3)); ip->addSuggestion(Suggestion("foobar", 0.2)); ip->addSuggestion(Suggestion("foobar1", 0.1)); ip->addSuggestion(Suggestion("foobar2", 0.09)); ip->addSuggestion(Suggestion("foobar3", 0.08)); ip->addSuggestion(Suggestion("foobar4", 0.07)); ip->addSuggestion(Suggestion("foobar5", 0.06)); ip->addSuggestion(Suggestion("foobar6", 0.05)); ip->addSuggestion(Suggestion("foobar7", 0.04)); ip->addSuggestion(Suggestion("foobar8", 0.03)); ip->addSuggestion(Suggestion("foobar9", 0.02)); ip->addSuggestion(Suggestion("foobarfoo", 0.01)); ip->addSuggestion(Suggestion("foobarfoo1", 0.009)); ip->addSuggestion(Suggestion("foobarfoo2", 0.008)); ip->addSuggestion(Suggestion("foobarfoo3", 0.007)); op->addSuggestion(Suggestion("foo", 0.9)); op->addSuggestion(Suggestion("foo1", 0.8)); op->addSuggestion(Suggestion("foo2", 0.7)); op->addSuggestion(Suggestion("foo3", 0.6)); op->addSuggestion(Suggestion("foo4", 0.5)); op->addSuggestion(Suggestion("foo5", 0.4)); td->updateString = "f"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foo", 0.9)); op->addSuggestion(Suggestion("foo1", 0.8)); op->addSuggestion(Suggestion("foo2", 0.7)); op->addSuggestion(Suggestion("foo3", 0.6)); op->addSuggestion(Suggestion("foo4", 0.5)); op->addSuggestion(Suggestion("foo5", 0.4)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foo", 0.9)); op->addSuggestion(Suggestion("foo1", 0.8)); op->addSuggestion(Suggestion("foo2", 0.7)); op->addSuggestion(Suggestion("foo3", 0.6)); op->addSuggestion(Suggestion("foo4", 0.5)); op->addSuggestion(Suggestion("foo5", 0.4)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; iter = testData.begin(); } SelectorTest::TestDataSuite_S6_NR_T3::TestDataSuite_S6_NR_T3() { init(); } void SelectorTest::TestDataSuite_S6_NR_T3::init() { TestData* td; Prediction* ip; Prediction* op; td = new TestData; ip = new Prediction; op = new Prediction; ip->addSuggestion(Suggestion("foo", 0.9)); ip->addSuggestion(Suggestion("foo1", 0.8)); ip->addSuggestion(Suggestion("foo2", 0.7)); ip->addSuggestion(Suggestion("foo3", 0.6)); ip->addSuggestion(Suggestion("foo4", 0.5)); ip->addSuggestion(Suggestion("foo5", 0.4)); ip->addSuggestion(Suggestion("foo6", 0.3)); ip->addSuggestion(Suggestion("foobar", 0.2)); ip->addSuggestion(Suggestion("foobar1", 0.1)); ip->addSuggestion(Suggestion("foobar2", 0.09)); ip->addSuggestion(Suggestion("foobar3", 0.08)); ip->addSuggestion(Suggestion("foobar4", 0.07)); ip->addSuggestion(Suggestion("foobar5", 0.06)); ip->addSuggestion(Suggestion("foobar6", 0.05)); ip->addSuggestion(Suggestion("foobar7", 0.04)); ip->addSuggestion(Suggestion("foobar8", 0.03)); ip->addSuggestion(Suggestion("foobar9", 0.02)); ip->addSuggestion(Suggestion("foobarfoo", 0.01)); ip->addSuggestion(Suggestion("foobarfoo1", 0.009)); ip->addSuggestion(Suggestion("foobarfoo2", 0.008)); ip->addSuggestion(Suggestion("foobarfoo3", 0.007)); op->addSuggestion(Suggestion("foo1", 0.8)); op->addSuggestion(Suggestion("foo2", 0.7)); op->addSuggestion(Suggestion("foo3", 0.6)); op->addSuggestion(Suggestion("foo4", 0.5)); op->addSuggestion(Suggestion("foo5", 0.4)); op->addSuggestion(Suggestion("foo6", 0.3)); td->updateString = "f"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foobar", 0.2)); op->addSuggestion(Suggestion("foobar1", 0.1)); op->addSuggestion(Suggestion("foobar2", 0.09)); op->addSuggestion(Suggestion("foobar3", 0.08)); op->addSuggestion(Suggestion("foobar4", 0.07)); op->addSuggestion(Suggestion("foobar5", 0.06)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foobar6", 0.05)); op->addSuggestion(Suggestion("foobar7", 0.04)); op->addSuggestion(Suggestion("foobar8", 0.03)); op->addSuggestion(Suggestion("foobar9", 0.02)); op->addSuggestion(Suggestion("foobarfoo", 0.01)); op->addSuggestion(Suggestion("foobarfoo1", 0.009)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; iter = testData.begin(); } SelectorTest::TestDataSuite_S6_R_T3::TestDataSuite_S6_R_T3() { init(); } void SelectorTest::TestDataSuite_S6_R_T3::init() { TestData* td; Prediction* ip; Prediction* op; td = new TestData; ip = new Prediction; op = new Prediction; ip->addSuggestion(Suggestion("foo", 0.9)); ip->addSuggestion(Suggestion("foo1", 0.8)); ip->addSuggestion(Suggestion("foo2", 0.7)); ip->addSuggestion(Suggestion("foo3", 0.6)); ip->addSuggestion(Suggestion("foo4", 0.5)); ip->addSuggestion(Suggestion("foo5", 0.4)); ip->addSuggestion(Suggestion("foo6", 0.3)); ip->addSuggestion(Suggestion("foobar", 0.2)); ip->addSuggestion(Suggestion("foobar1", 0.1)); ip->addSuggestion(Suggestion("foobar2", 0.09)); ip->addSuggestion(Suggestion("foobar3", 0.08)); ip->addSuggestion(Suggestion("foobar4", 0.07)); ip->addSuggestion(Suggestion("foobar5", 0.06)); ip->addSuggestion(Suggestion("foobar6", 0.05)); ip->addSuggestion(Suggestion("foobar7", 0.04)); ip->addSuggestion(Suggestion("foobar8", 0.03)); ip->addSuggestion(Suggestion("foobar9", 0.02)); ip->addSuggestion(Suggestion("foobarfoo", 0.01)); ip->addSuggestion(Suggestion("foobarfoo1", 0.009)); ip->addSuggestion(Suggestion("foobarfoo2", 0.008)); ip->addSuggestion(Suggestion("foobarfoo3", 0.007)); op->addSuggestion(Suggestion("foo1", 0.8)); op->addSuggestion(Suggestion("foo2", 0.7)); op->addSuggestion(Suggestion("foo3", 0.6)); op->addSuggestion(Suggestion("foo4", 0.5)); op->addSuggestion(Suggestion("foo5", 0.4)); op->addSuggestion(Suggestion("foo6", 0.3)); td->updateString = "f"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foobar", 0.2)); op->addSuggestion(Suggestion("foobar1", 0.1)); op->addSuggestion(Suggestion("foobar2", 0.09)); op->addSuggestion(Suggestion("foobar3", 0.08)); op->addSuggestion(Suggestion("foobar4", 0.07)); op->addSuggestion(Suggestion("foobar5", 0.06)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; td = new TestData; op = new Prediction; op->addSuggestion(Suggestion("foobar", 0.2)); op->addSuggestion(Suggestion("foobar1", 0.1)); op->addSuggestion(Suggestion("foobar2", 0.09)); op->addSuggestion(Suggestion("foobar3", 0.08)); op->addSuggestion(Suggestion("foobar4", 0.07)); op->addSuggestion(Suggestion("foobar5", 0.06)); td->updateString = "o"; td->inputPrediction = *ip; td->outputPrediction = *op; testData.push_back(*td); delete td; delete op; iter = testData.begin(); } void SelectorTest::setUp() { testStringSuite = new TestStringSuite(); tds_S6_NR_T0 = new TestDataSuite_S6_NR_T0(); tds_S6_R_T0 = new TestDataSuite_S6_R_T0(); tds_S6_NR_T3 = new TestDataSuite_S6_NR_T3(); tds_S6_R_T3 = new TestDataSuite_S6_R_T3(); configuration = new Configuration(); configuration->insert (PredictorRegistry::LOGGER, "ALL"); configuration->insert (PredictorRegistry::PREDICTORS, ""); configuration->insert (ContextTracker::LOGGER, "ALL"); configuration->insert (ContextTracker::SLIDING_WINDOW_SIZE, "80"); configuration->insert (ContextTracker::LOWERCASE_MODE, "no"); configuration->insert (Selector::LOGGER, "ALL"); configuration->insert (Selector::SUGGESTIONS, "6"); configuration->insert (Selector::REPEAT_SUGGESTIONS, "no"); configuration->insert (Selector::GREEDY_SUGGESTION_THRESHOLD, "0"); predictorRegistry = new PredictorRegistry(configuration); strstream = new std::stringstream(); callback = new StringstreamPresageCallback(*strstream); contextTracker = new ContextTracker(configuration, predictorRegistry, callback); selector = new Selector(configuration, contextTracker); } void SelectorTest::tearDown() { delete testStringSuite; delete tds_S6_NR_T0; delete tds_S6_R_T0; delete tds_S6_NR_T3; delete tds_S6_R_T3; delete selector; delete contextTracker; delete strstream; delete callback; delete configuration; } void SelectorTest::testSelect(TestDataSuite* tds) { while (tds->hasMoreTestData()) { std::cerr << "Updating strstream: " << strstream->str() << '|' << std::endl << " with: " << tds->getUpdateString() << '|' << std::endl; *strstream << tds->getUpdateString(); std::vector<std::string> selectedTokens; selectedTokens = selector->select(tds->getInputPrediction()); Prediction expected = tds->getOutputPrediction(); CPPUNIT_ASSERT_EQUAL( (size_t)expected.size(), selectedTokens.size() ); std::vector<std::string>::const_iterator actual_it = selectedTokens.begin(); int index = 0; while (actual_it != selectedTokens.end()) { std::cerr << "[expected] " << expected.getSuggestion(index).getWord() << " [actual] " << *actual_it << std::endl; CPPUNIT_ASSERT_EQUAL(expected.getSuggestion(index).getWord(), *actual_it); index++; actual_it++; } contextTracker->update(); tds->nextTestData(); } } void SelectorTest::testSelect_S6_R_T0() { std::cerr << "SelectorTest::testSelect_S6_R_T0()" << std::endl; configuration->find (Selector::SUGGESTIONS)->set_value ("6"); configuration->find (Selector::REPEAT_SUGGESTIONS)->set_value ("true"); configuration->find (Selector::GREEDY_SUGGESTION_THRESHOLD)->set_value ("0"); testSelect(tds_S6_R_T0); } void SelectorTest::testSelect_S6_NR_T0() { std::cerr << "SelectorTest::testSelect_S6_NR_T0()" << std::endl; configuration->find (Selector::SUGGESTIONS)->set_value ("6"); configuration->find (Selector::REPEAT_SUGGESTIONS)->set_value ("false"); configuration->find (Selector::GREEDY_SUGGESTION_THRESHOLD)->set_value ("0"); testSelect(tds_S6_NR_T0); } void SelectorTest::testSelect_S6_R_T3() { std::cerr << "SelectorTest::testSelect_S6_R_T3()" << std::endl; configuration->find (Selector::SUGGESTIONS)->set_value ("6"); configuration->find (Selector::REPEAT_SUGGESTIONS)->set_value ("true"); configuration->find (Selector::GREEDY_SUGGESTION_THRESHOLD)->set_value ("3"); testSelect(tds_S6_R_T3); } void SelectorTest::testSelect_S6_NR_T3() { std::cerr << "SelectorTest::testSelect_S6_NR_T3()" << std::endl; configuration->find (Selector::SUGGESTIONS)->set_value ("6"); configuration->find (Selector::REPEAT_SUGGESTIONS)->set_value ("false"); configuration->find (Selector::GREEDY_SUGGESTION_THRESHOLD)->set_value ("3"); testSelect(tds_S6_NR_T3); } ������������������������������������������������presage-0.8.8/test/lib/core/suggestionTest.h��������������������������������������������������������0000644�0001750�0001750�00000004010�11737142176�015757� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SUGGESTIONTEST #define PRESAGE_SUGGESTIONTEST #include <cppunit/extensions/HelperMacros.h> #include <core/suggestion.h> class SuggestionTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testConstructor(); void testOperatorEqual(); void testOperatorNotEqual(); void testOperatorMinus(); void testGetSetMethods(); private: Suggestion* sugg1Ptr; Suggestion* sugg2Ptr; Suggestion* sugg3Ptr; Suggestion* sugg4Ptr; Suggestion* sugg5Ptr; Suggestion* sugg6Ptr; Suggestion* sugg7Ptr; Suggestion* sugg8Ptr; CPPUNIT_TEST_SUITE( SuggestionTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testOperatorEqual ); CPPUNIT_TEST( testOperatorNotEqual ); CPPUNIT_TEST( testOperatorMinus ); CPPUNIT_TEST( testGetSetMethods ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_SUGGESTIONTEST ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/core/predictionTest.cpp������������������������������������������������������0000644�0001750�0001750�00000011253�11737142176�016272� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "predictionTest.h" #include "core/prediction.h" #include <string> CPPUNIT_TEST_SUITE_REGISTRATION( PredictionTest ); void PredictionTest::setUp() { sugg1Ptr = new Suggestion(); sugg2Ptr = new Suggestion( "foo", 0.1 ); sugg3Ptr = new Suggestion( "bar", 0.3 ); empty_prediction = new Prediction(); prediction1 = new Prediction(); prediction1->addSuggestion(*sugg1Ptr); prediction2 = new Prediction(); prediction2->addSuggestion(*sugg2Ptr); prediction3 = new Prediction(); prediction3->addSuggestion(*sugg3Ptr); prediction23 = new Prediction(); prediction23->addSuggestion(*sugg2Ptr); prediction23->addSuggestion(*sugg3Ptr); prediction13 = new Prediction(); prediction13->addSuggestion(*sugg1Ptr); prediction13->addSuggestion(*sugg3Ptr); prediction12 = new Prediction(); prediction12->addSuggestion(*sugg1Ptr); prediction12->addSuggestion(*sugg2Ptr); prediction123 = new Prediction(); prediction123->addSuggestion(*sugg1Ptr); prediction123->addSuggestion(*sugg2Ptr); prediction123->addSuggestion(*sugg3Ptr); } void PredictionTest::tearDown() { delete sugg1Ptr; delete sugg2Ptr; delete sugg3Ptr; delete empty_prediction; delete prediction1; delete prediction2; delete prediction3; delete prediction23; delete prediction13; delete prediction12; delete prediction123; } void PredictionTest::testAssignmentOperator() { Prediction* prediction = new Prediction(); const int PREDICTIONS_SIZE = 7; Prediction* predictions[PREDICTIONS_SIZE] = { prediction1, prediction2, prediction3, prediction12, prediction23, prediction13, prediction123 }; for (int i = 0; i < PREDICTIONS_SIZE; i++) { *prediction = *(predictions[i]); //std::cout << prediction->toString() << ' ' << (predictions[i])->toString() << std::endl; CPPUNIT_ASSERT_EQUAL( prediction->toString(), (predictions[i])->toString() ); } } void PredictionTest::testGetSize() { CPPUNIT_ASSERT( empty_prediction->size() == 0 ); CPPUNIT_ASSERT( prediction1->size() == 1 ); CPPUNIT_ASSERT( prediction2->size() == 1 ); CPPUNIT_ASSERT( prediction3->size() == 1 ); CPPUNIT_ASSERT( prediction23->size() == 2 ); CPPUNIT_ASSERT( prediction13->size() == 2 ); CPPUNIT_ASSERT( prediction12->size() == 2 ); CPPUNIT_ASSERT( prediction123->size() == 3 ); Prediction* pred = new Prediction(); const size_t total = 100; for (size_t i = 0; i < total; i++) { pred->addSuggestion(*sugg3Ptr); } CPPUNIT_ASSERT( pred->size() == total ); delete pred; } void PredictionTest::testGetSuggestion() { const int SUGGESTIONS_SIZE = 3; // be sure that suggestions array contains // suggestions in order of probability or // this test will fail. Suggestion* suggestions[SUGGESTIONS_SIZE] = { sugg3Ptr, sugg2Ptr, sugg1Ptr }; for (int i = 0; i < SUGGESTIONS_SIZE; i++) { //std::cout << prediction123->getSuggestion(i) << ' ' << *(suggestions[i]) << std::endl; CPPUNIT_ASSERT_EQUAL( prediction123->getSuggestion(i), *(suggestions[i]) ); } } void PredictionTest::testAddSuggestion() { // test that added suggestions are ordered correctly Prediction* pred = new Prediction(); pred->addSuggestion(*sugg3Ptr); pred->addSuggestion(*sugg2Ptr); pred->addSuggestion(*sugg1Ptr); CPPUNIT_ASSERT( pred->size() == 3 ); CPPUNIT_ASSERT( pred->getSuggestion(0) == *sugg3Ptr ); CPPUNIT_ASSERT( pred->getSuggestion(1) == *sugg2Ptr ); CPPUNIT_ASSERT( pred->getSuggestion(2) == *sugg1Ptr ); delete pred; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/Makefile.in������������������������������������������������������������������0000644�0001750�0001750�00000044277�11763440355�013716� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = test/lib DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = common core predictors all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/lib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # 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: ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�014103� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dejavuPredictorTest.cpp�������������������������������������������0000644�0001750�0001750�00000013616�11763437013�020513� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "dejavuPredictorTest.h" #include "../common/stringstreamPresageCallback.h" #include "core/predictorRegistry.h" #include <math.h> // for exp() #include <cstdio> // for remove() CPPUNIT_TEST_SUITE_REGISTRATION( DejavuPredictorTest ); const int DejavuPredictorTest::SIZE = 20; const char* DejavuPredictorTest::NAME = "DejavuPredictor"; const char* DejavuPredictorTest::PREDICTOR = "Presage.Predictors.DejavuPredictor.PREDICTOR"; const char* DejavuPredictorTest::LOGGER = "Presage.Predictors.DejavuPredictor.LOGGER"; const char* DejavuPredictorTest::TRIGGER = "Presage.Predictors.DejavuPredictor.TRIGGER"; const char* DejavuPredictorTest::MEMORY = "Presage.Predictors.DejavuPredictor.MEMORY"; const char* DejavuPredictorTest::MEMORY_FILENAME = "memory.txt"; void DejavuPredictorTest::setUp() { config = new Configuration(); // set context tracker config variables config->insert ("Presage.ContextTracker.LOGGER", "ERROR"); config->insert ("Presage.ContextTracker.SLIDING_WINDOW_SIZE", "80"); config->insert ("Presage.ContextTracker.LOWERCASE_MODE", "no"); // set predictor registry config variables config->insert ("Presage.PredictorRegistry.LOGGER", "ERROR"); config->insert ("Presage.PredictorRegistry.PREDICTORS", "DejavuPredictor"); // set dejavu predictor config variables config->insert (PREDICTOR, NAME); config->insert (LOGGER, "ALL"); config->insert (TRIGGER, "3"); config->insert (MEMORY, MEMORY_FILENAME); predictorRegistry = new PredictorRegistry(config); stream = new std::stringstream(); callback = new StringstreamPresageCallback(*stream); ct = new ContextTracker(config, predictorRegistry, callback); remove(MEMORY_FILENAME); } void DejavuPredictorTest::tearDown() { delete ct; delete callback; delete stream; delete predictorRegistry; delete config; remove(MEMORY_FILENAME); } void DejavuPredictorTest::testPredict() { *stream << "polly wants a cracker "; ct->update(); // get pointer to dejavu predictor Predictor* predictor = predictorRegistry->iterator().next(); { *stream << "polly "; Prediction expected; CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } { *stream << "wants "; Prediction expected; CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } { *stream << "a "; Prediction expected; expected.addSuggestion(Suggestion("cracker", 1.0)); CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } *stream << "soda "; ct->update(); { *stream << "polly "; Prediction expected; CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } { *stream << "wants "; Prediction expected; CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } { *stream << "a "; Prediction expected; expected.addSuggestion(Suggestion("cracker", 1.0)); expected.addSuggestion(Suggestion("soda", 1.0)); CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } *stream << "cake "; ct->update(); { *stream << "polly "; Prediction expected; CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } { *stream << "wants "; Prediction expected; CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } { *stream << "a "; Prediction expected; expected.addSuggestion(Suggestion("cake", 1.0)); expected.addSuggestion(Suggestion("cracker", 1.0)); expected.addSuggestion(Suggestion("soda", 1.0)); CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, 0)); ct->update(); } *stream << "crumble "; ct->update(); { // test filter const char* filter[] = { "cra", "so", 0 }; *stream << "polly wants a "; Prediction expected; expected.addSuggestion(Suggestion("cracker", 1.0)); expected.addSuggestion(Suggestion("soda", 1.0)); CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, filter)); ct->update(); } *stream << "break "; ct->update(); { // test filter const char* filter[] = { "r", 0 }; *stream << "polly wants a c"; Prediction expected; expected.addSuggestion(Suggestion("cracker", 1.0)); expected.addSuggestion(Suggestion("crumble", 1.0)); CPPUNIT_ASSERT_EQUAL(expected, predictor->predict(SIZE, filter)); ct->update(); } *stream << "uddle "; ct->update(); } ������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/predictorsTestFixture.h�������������������������������������������0000644�0001750�0001750�00000005373�11737142176�020560� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTORSTESTFIXTURE #define PRESAGE_PREDICTORSTESTFIXTURE #include <cppunit/extensions/HelperMacros.h> #include "predictorsTestMockObjects.h" class PredictorsTestFixture : public CppUnit::TestFixture { public: PredictorsTestFixture(); virtual ~PredictorsTestFixture(); virtual void setUp() = 0; virtual void tearDown() = 0; /** \brief Returns prediction computed by predictor.predict() method * using given config and profile. * * \param config configuration used by predictor. * \param history current context used by predictor. * \param maximum partial prediction size (default 100). * \return prediction computed by predictor method predict(). */ virtual Prediction runPredict(const char** config, const char** history, const int max_partial_prediction_size = 100) const; private: /** \brief Converts array of configuration values config to a * configuration map. * * \note To be overridden by actual test class inheriting from *this. * * \param config array of configuration variables and values. * \return cocnfiguration map. */ virtual Configuration* prepareConfiguration(const char* config[]) const = 0; /** \brief Creates a predictor instance for testing. * * \note To be overridden by actual test class inheriting from *this. * * \param config configuration * \param ct context tracker * \return instance of predictor to be tested */ virtual Predictor* createPredictor(Configuration* config, ContextTracker* ct) const = 0; }; #endif // PRESAGE_PREDICTORSTESTFIXTURE ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/smoothedNgramPredictorTest.h��������������������������������������0000644�0001750�0001750�00000006250�11763437013�021505� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SMOOTHEDNGRAMPREDICTORTEST #define PRESAGE_SMOOTHEDNGRAMPREDICTORTEST #include <cppunit/extensions/HelperMacros.h> #include <predictors/smoothedNgramPredictor.h> #include "predictorsTestFixture.h" /** Test SmoothedNgramPredictor. * * The idea is to provide mock HistoryTracker and mock Profile classes * to supply controlled values to the predictor and test that the * returned predictions are as expected. * * This test also creates a sqlite database with controlled values * necessary to generate predictions. * */ class SmoothedNgramPredictorTest : public PredictorsTestFixture { public: void setUp(); void tearDown(); void testUnigramWeight(); void testBigramWeight(); void testTrigramWeight(); void testUnigramBigramWeight(); void testUnigramTrigramWeight(); void testBigramTrigramWeight(); void testUnigramBigramTrigramWeight(); void testMaxPartialPredictionSize(); private: Configuration* prepareConfiguration(const char* config[]) const; Predictor* createPredictor(Configuration*, ContextTracker*) const; /** Asserts prediction is as expected. */ void assertCorrectPrediction(const char** config, const char** history, const size_t expected_prediction_size, const std::string* expected_prediction_words) const; static const std::string DATABASE; static const size_t CARDINALITY; static const bool READ_WRITE_MODE; static const std::string FOO; static const std::string BAR; static const std::string FOOBAR; CPPUNIT_TEST_SUITE( SmoothedNgramPredictorTest ); CPPUNIT_TEST( testUnigramWeight ); CPPUNIT_TEST( testBigramWeight ); CPPUNIT_TEST( testTrigramWeight ); CPPUNIT_TEST( testUnigramBigramWeight ); CPPUNIT_TEST( testUnigramTrigramWeight ); CPPUNIT_TEST( testBigramTrigramWeight ); CPPUNIT_TEST( testUnigramBigramTrigramWeight); CPPUNIT_TEST( testMaxPartialPredictionSize ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_SMOOTHEDNGRAMPREDICTORTEST ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/smoothedNgramPredictorTest.cpp������������������������������������0000644�0001750�0001750�00000035001�11763734722�022043� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "smoothedNgramPredictorTest.h" // for unlink(), getcwd() #ifdef HAVE_UNISTD_H # include <unistd.h> #endif CPPUNIT_TEST_SUITE_REGISTRATION( SmoothedNgramPredictorTest ); const std::string SmoothedNgramPredictorTest::DATABASE = "database.db"; const size_t SmoothedNgramPredictorTest::CARDINALITY = 3; const bool SmoothedNgramPredictorTest::READ_WRITE_MODE = true; const std::string SmoothedNgramPredictorTest::FOO("foo"); const std::string SmoothedNgramPredictorTest::BAR("bar"); const std::string SmoothedNgramPredictorTest::FOOBAR("foobar"); void SmoothedNgramPredictorTest::setUp() { // prepare database SqliteDatabaseConnector db(DATABASE, CARDINALITY, READ_WRITE_MODE); // unigrams db.createUnigramTable(); { Ngram ngram; ngram.push_back(FOO); db.insertNgram(ngram, 100000000); } { Ngram ngram; ngram.push_back(BAR); db.insertNgram(ngram, 10000000); } { Ngram ngram; ngram.push_back(FOOBAR); db.insertNgram(ngram, 1000000); } // bigrams db.createBigramTable(); { Ngram ngram; ngram.push_back(FOO); ngram.push_back(BAR); db.insertNgram(ngram, 100000); } { Ngram ngram; ngram.push_back(BAR); ngram.push_back(FOOBAR); db.insertNgram(ngram, 10000); } { Ngram ngram; ngram.push_back(FOOBAR); ngram.push_back(FOO); db.insertNgram(ngram, 1000); } // trigrams db.createTrigramTable(); { Ngram ngram; ngram.push_back(FOO); ngram.push_back(BAR); ngram.push_back(FOOBAR); db.insertNgram(ngram, 100); } { Ngram ngram; ngram.push_back(BAR); ngram.push_back(FOOBAR); ngram.push_back(FOO); db.insertNgram(ngram, 10); } { Ngram ngram; ngram.push_back(FOOBAR); ngram.push_back(FOO); ngram.push_back(BAR); db.insertNgram(ngram, 1); } // Now the database should look like this: // foo 100000000 // bar 10000000 // foobar 1000000 // foo bar 100000 // bar foobar 10000 // foobar foo 1000 // foo bar foobar 100 // bar foobar foo 10 // foobar foo bar 1 } void SmoothedNgramPredictorTest::tearDown() { #ifdef HAVE_UNISTD_H // remove file int result = unlink(DATABASE.c_str()); assert(result == 0); #else // fail test std::string message = "Unable to remove database file " + DATABASE; CPPUNIT_FAIL( message.c_str() ); #endif } Configuration* SmoothedNgramPredictorTest::prepareConfiguration(const char* config[]) const { Configuration* configuration = new Configuration(); configuration->insert ("Presage.Predictors.TestSmoothedNgramPredictor.PREDICTOR", "TestSmoothedNgramPredictor"); configuration->insert ("Presage.Predictors.TestSmoothedNgramPredictor.LOGGER", "ERROR"); configuration->insert ("Presage.Predictors.TestSmoothedNgramPredictor.DELTAS", config[0]); configuration->insert ("Presage.Predictors.TestSmoothedNgramPredictor.DBFILENAME", config[1]); configuration->insert ("Presage.Predictors.TestSmoothedNgramPredictor.DatabaseConnector.LOGGER", "ERROR"); configuration->insert ("Presage.Predictors.TestSmoothedNgramPredictor.LEARN", "FALSE"); return configuration; } void SmoothedNgramPredictorTest::assertCorrectPrediction(const char** config, const char** history, const size_t expected_prediction_size, const std::string* expected_prediction_words) const { Prediction prediction = runPredict(config, history); std::cout << "assertCorrectPrediction: " << prediction << std::endl; CPPUNIT_ASSERT_EQUAL(expected_prediction_size, prediction.size()); for (size_t i = 0; i < expected_prediction_size; i++) { CPPUNIT_ASSERT_EQUAL(expected_prediction_words[i], prediction.getSuggestion(i).getWord()); } } Predictor* SmoothedNgramPredictorTest::createPredictor(Configuration* config, ContextTracker* contextTracker) const { return new SmoothedNgramPredictor(config, contextTracker, "TestSmoothedNgramPredictor"); } void SmoothedNgramPredictorTest::testUnigramWeight() { const char* config[] = { "1.0 0.0 0.0", DATABASE.c_str() }; { const char* history[] = { "foo", "bar", "" }; const std::string expected_prediction_words[] = { FOO, BAR, FOOBAR }; unsigned int expected_prediction_size = 3; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "f" }; const std::string expected_prediction_words[] = { FOO, FOOBAR }; unsigned int expected_prediction_size = 2; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "ba" }; const std::string expected_prediction_words[] = { BAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "", "", "ba" }; const std::string expected_prediction_words[] = { BAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foobar" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foobarwoz" }; const std::string expected_prediction_words[] = { }; unsigned int expected_prediction_size = 0; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } } void SmoothedNgramPredictorTest::testBigramWeight() { const char* config[] = { "0.0 1.0 0.0", DATABASE.c_str() }; { const char* history[] = { "foo", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foobar", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foobar", "bar", "fo" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foobar", "foo", "" }; const std::string expected_prediction_words[] = { BAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "bar", "foobar", "" }; const std::string expected_prediction_words[] = { FOO }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } } void SmoothedNgramPredictorTest::testTrigramWeight() { const char* config[] = { "0.0 0.0 1.0", DATABASE.c_str() }; { const char* history[] = { "foo", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foo" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foobar" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foobar", "foo", "ba" }; const std::string expected_prediction_words[] = { BAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "bar", "foobar", "" }; const std::string expected_prediction_words[] = { FOO }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } } void SmoothedNgramPredictorTest::testUnigramBigramWeight() { const char* config[] = { "0.0001 0.9999 0.0", DATABASE.c_str() }; // unigram weight is much lower han bigram weight in order to // ensure that results are not masked by unigram results. { const char* history[] = { "foo", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR, FOO, BAR }; unsigned int expected_prediction_size = 3; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "fo" }; const std::string expected_prediction_words[] = { FOOBAR, FOO }; unsigned int expected_prediction_size = 2; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foob" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } } void SmoothedNgramPredictorTest::testUnigramTrigramWeight() { const char* config[] = { "0.0001 0.0 0.9999", DATABASE.c_str() }; // unigram weight is much lower han trigram weight in order to // ensure that results are not masked by unigram results. { const char* history[] = { "foo", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR, FOO, BAR }; unsigned int expected_prediction_size = 3; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "fo" }; const std::string expected_prediction_words[] = { FOOBAR, FOO }; unsigned int expected_prediction_size = 2; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foob" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } } void SmoothedNgramPredictorTest::testBigramTrigramWeight() { const char* config[] = { "0.0 0.0001 0.9999", DATABASE.c_str() }; // unigram weight is much lower han trigram weight in order to // ensure that results are not masked by unigram results. { const char* history[] = { "foo", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "fo" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foob" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } } void SmoothedNgramPredictorTest::testUnigramBigramTrigramWeight() { const char* config[] = { "0.000001 0.001 0.998999", DATABASE.c_str() }; // unigram weight is much lower han trigram weight in order to // ensure that results are not masked by unigram results. { const char* history[] = { "foo", "bar", "" }; const std::string expected_prediction_words[] = { FOOBAR, FOO, BAR }; unsigned int expected_prediction_size = 3; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "fo" }; const std::string expected_prediction_words[] = { FOOBAR, FOO }; unsigned int expected_prediction_size = 2; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } { const char* history[] = { "foo", "bar", "foob" }; const std::string expected_prediction_words[] = { FOOBAR }; unsigned int expected_prediction_size = 1; assertCorrectPrediction(config, history, expected_prediction_size, expected_prediction_words); } } void SmoothedNgramPredictorTest::testMaxPartialPredictionSize() { // test that maximum partial prediction size config value is // honoured by checking that returned prediction size does not // exceed specified partial prediction size. for (size_t size = 0; size <= 3; size++) { // assign equal weight to uni/bi/tri-grams; only vary maximum // partial prediction size. const char* config[] = { "0.33 0.33 0.33", DATABASE.c_str() }; const char* history[] = { "", "", "" }; Prediction prediction = runPredict(config, history, size); CPPUNIT_ASSERT_EQUAL(size, prediction.size()); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/abbreviationExpansionPredictorTest.cpp����������������������������0000644�0001750�0001750�00000007076�11743227551�023574� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "abbreviationExpansionPredictorTest.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif CPPUNIT_TEST_SUITE_REGISTRATION( AbbreviationExpansionPredictorTest ); AbbreviationExpansionPredictorTest::AbbreviationExpansionPredictorTest() { STANDARD_ABBREVIATION_FILE = static_cast<std::string>(getenv("srcdir")) + "/../../../resources/abbreviations_en.txt"; } void AbbreviationExpansionPredictorTest::setUp() {} void AbbreviationExpansionPredictorTest::tearDown() {} void AbbreviationExpansionPredictorTest::testSimpleExpansion() { const char* config[] = { STANDARD_ABBREVIATION_FILE.c_str() }; const char* history[] = { "foo", "bar", "2moro" }; Prediction prediction = runPredict(config, history); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), prediction.size()); CPPUNIT_ASSERT_EQUAL(std::string("\b\b\b\b\btomorrow"), prediction.getSuggestion(0).getWord()); } void AbbreviationExpansionPredictorTest::testLongExpansion() { const char* config[] = { STANDARD_ABBREVIATION_FILE.c_str() }; const char* history[] = { "foo", "bar", "ianal" }; Prediction prediction = runPredict(config, history); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), prediction.size()); CPPUNIT_ASSERT_EQUAL(std::string("\b\b\b\b\bI am not a lawyer"), prediction.getSuggestion(0).getWord()); } void AbbreviationExpansionPredictorTest::testUnknownAbbreviation() { const char* config[] = { STANDARD_ABBREVIATION_FILE.c_str() }; const char* history[] = { "foo", "bar", "foobar" }; Prediction prediction = runPredict(config, history); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), prediction.size()); } Configuration* AbbreviationExpansionPredictorTest::prepareConfiguration(const char* config[]) const { std::cerr << "AbbreviationExpansionPredictorTest::prepareConfigMap" << std::endl; Configuration* result = new Configuration(); result->insert ("Presage.Predictors.AbbreviationExpansionPredictor.PREDICTOR", "AbbreviationExpansionPredictor"); result->insert ("Presage.Predictors.AbbreviationExpansionPredictor.LOGGER", "ALL"); result->insert ("Presage.Predictors.AbbreviationExpansionPredictor.ABBREVIATIONS", config[0]); return result; } Predictor* AbbreviationExpansionPredictorTest::createPredictor(Configuration* configuration, ContextTracker* ct) const { std::cerr << "AbbreviationExpansionPredictorTest::createPredictor" << std::endl; return new AbbreviationExpansionPredictor(configuration, ct, "AbbreviationExpansionPredictor"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/predictorsTestMockObjects.cpp�������������������������������������0000644�0001750�0001750�00000006445�11763437013�021665� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "predictorsTestMockObjects.h" //////////////////////////// // Mock HistoryTracker class ContextTracker::ContextTracker(Configuration* config, PredictorRegistry* predictorRegistry, PresageCallback* callback, const char wc[], const char sc[], const char bc[], const char cc[]) : logger ("MockContextTracker", std::cerr), dispatcher (this) { const char** history = (const char**) config; wordChars = history[2]; // getPrefix() separatorChars = history[1]; // getToken(1) blankspaceChars = history[0]; // getToken(2) } ContextTracker::~ContextTracker() {} void ContextTracker::update() {} std::string ContextTracker::getPrefix() const { return wordChars; } std::string ContextTracker::getToken(const int index) const { std::string result; switch (index) { case 0: result = wordChars; break; case 1: result = separatorChars; break; case 2: result = blankspaceChars; break; default: break; } return result; } std::string ContextTracker::getExtraTokenToLearn(const int index, const std::vector<std::string>& change) const { std::string result; return result; } std::string ContextTracker::getFutureStream() const { std::string result; return result; } std::string ContextTracker::getPastStream() const { std::string result; return result; } std::string ContextTracker::getWordChars() const { std::string result; return result; } std::string ContextTracker::getSeparatorChars() const { std::string result; return result; } std::string ContextTracker::getBlankspaceChars() const { std::string result; return result; } std::string ContextTracker::getControlChars() const { std::string result; return result; } std::string ContextTracker::toString() const { std::string result; return result; } bool ContextTracker::isWordChar (const char) const { return true; } bool ContextTracker::isSeparatorChar (const char) const { return true; } bool ContextTracker::isControlChar (const char) const { return true; } bool ContextTracker::isBlankspaceChar(const char) const { return true; } void ContextTracker::update (const Observable* variable) { /* intentionally empty */ } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/Makefile.am�������������������������������������������������������0000644�0001750�0001750�00000004647�11737142176�016061� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = dbconnector check_PROGRAMS = $(TESTS) if HAVE_CPPUNIT TESTS = predictorsTestRunner newPredictorsTestRunner predictorsTestRunner_SOURCES = predictorsTestRunner.cpp \ predictorsTestMockObjects.h \ predictorsTestMockObjects.cpp \ predictorsTestFixture.h \ predictorsTestFixture.cpp \ abbreviationExpansionPredictorTest.h \ abbreviationExpansionPredictorTest.cpp predictorsTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) predictorsTestRunner_LDFLAGS = $(CPPUNIT_LIBS) predictorsTestRunner_LDADD = libpredictorstest.la if USE_SQLITE predictorsTestRunner_SOURCES += smoothedNgramPredictorTest.h \ smoothedNgramPredictorTest.cpp endif newPredictorsTestRunner_SOURCES = predictorsTestRunner.cpp \ recencyPredictorTest.h \ recencyPredictorTest.cpp \ dejavuPredictorTest.h \ dejavuPredictorTest.cpp newPredictorsTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) newPredictorsTestRunner_LDFLAGS = $(CPPUNIT_LIBS) newPredictorsTestRunner_LDADD = libpredictorstest.la check_LTLIBRARIES = libpredictorstest.la libpredictorstest_la_SOURCES = libpredictorstest_la_LIBADD = $(top_builddir)/src/lib/predictors/libpredictors.la \ $(top_builddir)/src/lib/core/libcore.la if USE_SQLITE newPredictorsTestRunner_SOURCES += newSmoothedNgramPredictorTest.h \ newSmoothedNgramPredictorTest.cpp libpredictorstest_la_LIBADD += $(top_builddir)/src/lib/predictors/dbconnector/libdbconnector.la endif endif # HAVE_CPPUNIT AM_CPPFLAGS = -I$(top_srcdir)/src/lib �����������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/predictorsTestFixture.cpp�����������������������������������������0000644�0001750�0001750�00000004557�11737142176�021116� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "predictorsTestFixture.h" PredictorsTestFixture::PredictorsTestFixture() { // intentionally empty } PredictorsTestFixture::~PredictorsTestFixture() { // intentionally empty } Prediction PredictorsTestFixture::runPredict(const char** config, const char** history, const int max_partial_prediction_size) const { // convert configuration details into a Configuration object // Configuration* configuration = prepareConfiguration(config); // The cast to Configuration* is necessary since only the // implementation of the mock ContextTracker class is different - // the interface cannot be changed. // // Using argument to pass an array of history tokens. // ContextTracker contextTracker((Configuration*) history, 0, 0); // creating predictor object to test using the mock ContextTracker // and Profile objects. Predictor* predictor = createPredictor(configuration, &contextTracker); // generate prediction. Prediction result = predictor->predict(max_partial_prediction_size, 0); // predictor object is no longer needed. delete predictor; // same for configuration delete configuration; // return the prediction for comparison with expected results. return result; } �������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/recencyPredictorTest.cpp������������������������������������������0000644�0001750�0001750�00000014576�11763437013�020673� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "recencyPredictorTest.h" #include "../common/stringstreamPresageCallback.h" #include "core/predictorRegistry.h" #include <math.h> // for exp() CPPUNIT_TEST_SUITE_REGISTRATION( RecencyPredictorTest ); const int RecencyPredictorTest::SIZE = 20; const char* RecencyPredictorTest::NAME = "RecencyPredictor"; const char* RecencyPredictorTest::PREDICTOR = "Presage.Predictors.RecencyPredictor.PREDICTOR"; const char* RecencyPredictorTest::LOGGER = "Presage.Predictors.RecencyPredictor.LOGGER"; const char* RecencyPredictorTest::LAMBDA = "Presage.Predictors.RecencyPredictor.LAMBDA"; const char* RecencyPredictorTest::CUTOFF = "Presage.Predictors.RecencyPredictor.CUTOFF_THRESHOLD"; const char* RecencyPredictorTest::N_0 = "Presage.Predictors.RecencyPredictor.N_0"; void RecencyPredictorTest::setUp() { //std::cerr << "RecencyPredictorTest::setUp()" << std::endl; config = new Configuration(); // set context tracker config variables config->insert ("Presage.ContextTracker.LOGGER", "ERROR"); config->insert ("Presage.ContextTracker.SLIDING_WINDOW_SIZE", "80"); config->insert ("Presage.ContextTracker.LOWERCASE_MODE", "no"); // set predictor registry config variables config->insert ("Presage.PredictorRegistry.LOGGER", "ERROR"); config->insert ("Presage.PredictorRegistry.PREDICTORS", ""); // set recency predictor config variables config->insert (PREDICTOR, NAME); config->insert (LOGGER, "ALL"); config->insert (LAMBDA, "1"); config->insert (N_0, "1"); config->insert (CUTOFF, "20"); predictorRegistry = new PredictorRegistry(config); stream = new std::stringstream(); callback = new StringstreamPresageCallback(*stream); ct = new ContextTracker(config, predictorRegistry, callback); } void RecencyPredictorTest::tearDown() { //std::cerr << "RecencyPredictorTest::tearDown()" << std::endl; delete ct; delete callback; delete stream; delete predictorRegistry; delete config; } void RecencyPredictorTest::testMaxPartialPredictionSize() { std::cerr << "RecencyPredictorTest::testMaxPartialPredictionSize()" << std::endl; RecencyPredictor* predictor = new RecencyPredictor(config, ct, NAME); *stream << "foo foobar foobaz foo"; for (size_t i = 1; i <= 3; i++) { Prediction prediction = predictor->predict(i, 0); CPPUNIT_ASSERT_EQUAL(i, prediction.size()); std::cout << prediction << std::endl; } delete predictor; } void RecencyPredictorTest::testCutoffThreshold() { std::cerr << "RecencyPredictorTest::testCutoffThreshold()" << std::endl; *stream << "foo bar foobar baz f"; { config->insert (CUTOFF, "0"); Prediction expected; RecencyPredictor predictor(config, ct, NAME); CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, 0)); } { config->insert (CUTOFF, "1"); Prediction expected; RecencyPredictor predictor(config, ct, NAME); CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, 0)); } { config->insert (CUTOFF, "2"); Prediction expected; RecencyPredictor predictor(config, ct, NAME); expected.addSuggestion(Suggestion("foobar", 1.0 * exp(-1.0 * 1))); // foobar is second token (offset 1) CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, 0)); } { config->insert (CUTOFF, "3"); Prediction expected; RecencyPredictor predictor(config, ct, NAME); expected.addSuggestion(Suggestion("foobar", 1.0 * exp(-1.0 * 1))); // foobar is second token (offset 1) CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, 0)); } { config->insert (CUTOFF, "4"); Prediction expected; RecencyPredictor predictor(config, ct, NAME); expected.addSuggestion(Suggestion("foobar", 1.0 * exp(-1.0 * 1))); // foobar is second token (offset 1) expected.addSuggestion(Suggestion("foo", 1.0 * exp(-1.0 * 3))); // skip bar, foo is fourth token (offset 3) CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, 0)); } } void RecencyPredictorTest::testFilter() { std::cerr << "RecencyPredictorTest::testFilter()" << std::endl; *stream << "foo bar foobar baz f"; { const char* filter[] = {"oob", 0}; Prediction expected; expected.addSuggestion(Suggestion("foobar", 1.0 * exp(-1.0 * 1))); // foobar is second token (offset 1) RecencyPredictor predictor(config, ct, NAME); CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, filter)); } { const char* filter[] = {"oo", 0}; Prediction expected; expected.addSuggestion(Suggestion("foobar", 1.0 * exp(-1.0 * 1))); // foobar is second token (offset 1) expected.addSuggestion(Suggestion("foo", 1.0 * exp(-1.0 * 3))); // skip bar, foo is fourth token (offset 3) RecencyPredictor predictor(config, ct, NAME); CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, filter)); } { const char* filter[] = {"ar", 0}; Prediction expected; RecencyPredictor predictor(config, ct, NAME); CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, filter)); } { const char** filter = 0; Prediction expected; expected.addSuggestion(Suggestion("foobar", 1.0 * exp(-1.0 * 1))); // foobar is second token (offset 1) expected.addSuggestion(Suggestion("foo", 1.0 * exp(-1.0 * 3))); // skip bar, foo is fourth token (offset 3) RecencyPredictor predictor(config, ct, NAME); CPPUNIT_ASSERT_EQUAL(expected, predictor.predict(SIZE, filter)); } } ����������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/abbreviationExpansionPredictorTest.h������������������������������0000644�0001750�0001750�00000005101�11737142176�023226� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_ABBREVIATIONEXPANSIONPREDICTORTEST #define PRESAGE_ABBREVIATIONEXPANSIONPREDICTORTEST #include <cppunit/extensions/HelperMacros.h> #include <predictors/abbreviationExpansionPredictor.h> #include "predictorsTestMockObjects.h" #include "predictorsTestFixture.h" /** Test abbreviationExpansionPredictor. * * The idea is to provide mock HistoryTracker and mock Profile classes * to supply controlled values to the predictor and test that the * returned predictions are as expected. * */ //class AbbreviationExpansionPredictorTest : public CppUnit::TestFixture { class AbbreviationExpansionPredictorTest : public PredictorsTestFixture { public: AbbreviationExpansionPredictorTest(); void setUp(); void tearDown(); void testSimpleExpansion(); void testLongExpansion(); void testUnknownAbbreviation(); private: /** Converts array of configuration values config to a configuration map. */ Configuration* prepareConfiguration(const char* config[]) const; Predictor* createPredictor(Configuration* configuration, ContextTracker* ct) const; std::string STANDARD_ABBREVIATION_FILE; CPPUNIT_TEST_SUITE( AbbreviationExpansionPredictorTest ); CPPUNIT_TEST( testSimpleExpansion ); CPPUNIT_TEST( testLongExpansion ); CPPUNIT_TEST( testUnknownAbbreviation ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_ABBREVIATIONEXPANSIONPREDICTORTEST ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/newSmoothedNgramPredictorTest.cpp���������������������������������0000644�0001750�0001750�00000020123�11763437013�022505� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "newSmoothedNgramPredictorTest.h" #include "../common/stringstreamPresageCallback.h" #include "core/predictorRegistry.h" #include <cstdio> // for remove() CPPUNIT_TEST_SUITE_REGISTRATION( NewSmoothedNgramPredictorTest ); const char* NewSmoothedNgramPredictorTest::DATABASE = "database.db"; const size_t NewSmoothedNgramPredictorTest::CARDINALITY = 3; const bool NewSmoothedNgramPredictorTest::READ_WRITE_MODE = true; const int NewSmoothedNgramPredictorTest::SIZE = 20; void NewSmoothedNgramPredictorTest::setUp() { remove(DATABASE); // prepare database SqliteDatabaseConnector db(DATABASE, CARDINALITY, READ_WRITE_MODE); db.createUnigramTable(); db.createBigramTable(); db.createTrigramTable(); config = new Configuration(); // set context tracker config variables config->insert ("Presage.ContextTracker.LOGGER", "ALL"); config->insert ("Presage.ContextTracker.SLIDING_WINDOW_SIZE", "80"); config->insert ("Presage.ContextTracker.LOWERCASE_MODE", "no"); // set predictor registry config variables config->insert ("Presage.PredictorRegistry.LOGGER", "ERROR"); config->insert ("Presage.PredictorRegistry.PREDICTORS", "SmoothedNgramPredictor"); // set predictor config variables config->insert ("Presage.Predictors.SmoothedNgramPredictor.PREDICTOR", "SmoothedNgramPredictor"); config->insert ("Presage.Predictors.SmoothedNgramPredictor.LOGGER", "ALL"); config->insert ("Presage.Predictors.SmoothedNgramPredictor.DELTAS", "0.001 0.01 0.889"); config->insert ("Presage.Predictors.SmoothedNgramPredictor.DBFILENAME", DATABASE); config->insert ("Presage.Predictors.SmoothedNgramPredictor.LEARN", "true"); config->insert ("Presage.Predictors.SmoothedNgramPredictor.DatabaseConnector.LOGGER", "ERROR"); predictorRegistry = new PredictorRegistry(config); stream = new std::stringstream(); callback = new StringstreamPresageCallback(*stream); ct = new ContextTracker(config, predictorRegistry, callback); } void NewSmoothedNgramPredictorTest::tearDown() { delete ct; delete callback; delete predictorRegistry; delete config; remove(DATABASE); } void NewSmoothedNgramPredictorTest::testLearning() { // get pointer to predictor Predictor* predictor = predictorRegistry->iterator().next(); { *stream << "f"; ct->update(); Prediction actual = predictor->predict(SIZE, 0); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), actual.size()); } { *stream << "o"; ct->update(); Prediction actual = predictor->predict(SIZE, 0); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), actual.size()); } { *stream << "o "; ct->update(); Prediction actual = predictor->predict(SIZE, 0); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), actual.size()); CPPUNIT_ASSERT_EQUAL(std::string("foo"), actual.getSuggestion(0).getWord()); ct->update(); } { *stream << "bar"; ct->update(); Prediction actual = predictor->predict(SIZE, 0); } { *stream << " "; ct->update(); Prediction actual = predictor->predict(SIZE, 0); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), actual.size()); CPPUNIT_ASSERT_EQUAL(std::string("foo"), actual.getSuggestion(0).getWord()); CPPUNIT_ASSERT_EQUAL(std::string("bar"), actual.getSuggestion(1).getWord()); } { *stream << "foobar "; ct->update(); Prediction actual = predictor->predict(SIZE, 0); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), actual.size()); CPPUNIT_ASSERT_EQUAL(std::string("foobar"), actual.getSuggestion(0).getWord()); CPPUNIT_ASSERT_EQUAL(std::string("foo"), actual.getSuggestion(1).getWord()); CPPUNIT_ASSERT_EQUAL(std::string("bar"), actual.getSuggestion(2).getWord()); } { *stream << "f"; ct->update(); Prediction actual = predictor->predict(SIZE, 0); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), actual.size()); CPPUNIT_ASSERT_EQUAL(std::string("foobar"), actual.getSuggestion(0).getWord()); CPPUNIT_ASSERT_EQUAL(std::string("foo"), actual.getSuggestion(1).getWord()); } } void NewSmoothedNgramPredictorTest::testFilter() { // get pointer to predictor Predictor* predictor = predictorRegistry->iterator().next(); std::vector<std::string> change; change.push_back("foo"); change.push_back("bar"); change.push_back("foobar"); change.push_back("foz"); change.push_back("baz"); change.push_back("fozbaz"); change.push_back("roo"); change.push_back("rar"); change.push_back("roobar"); // Learn some context so that we have data to create non-empty // predictions // predictor->learn(change); // Alternatively, predictor could have learnt thus... // *stream << "foo bar foobar foz baz fozbaz roo rar roobar "; // ct->update(); { Prediction actual = predictor->predict(SIZE, 0); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(9), actual.size()); } { const char* filters[] = {"f", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), actual.size()); } { const char* filters[] = {"b", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), actual.size()); } { const char* filters[] = {"r", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), actual.size()); } { const char* filters[] = {"f", "b", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(6), actual.size()); } { const char* filters[] = {"f", "r", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(7), actual.size()); } { const char* filters[] = {"f", "b", "r", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(9), actual.size()); } { const char* filters[] = {"fo", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), actual.size()); } { const char* filters[] = {"foo", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), actual.size()); } { const char* filters[] = {"fo", "ba", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(6), actual.size()); } { const char* filters[] = {"fo", "ba", "ro", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(8), actual.size()); } { const char* filters[] = {"foo", "bar", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), actual.size()); } { const char* filters[] = {"foobar", "fozba", "roo", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), actual.size()); } { const char* filters[] = {"foobar", "fozbaz", "roobar", 0}; Prediction actual = predictor->predict(SIZE, filters); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), actual.size()); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/Makefile.in�������������������������������������������������������0000644�0001750�0001750�00000151617�11763440356�016072� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ check_PROGRAMS = $(am__EXEEXT_1) @HAVE_CPPUNIT_TRUE@TESTS = predictorsTestRunner$(EXEEXT) \ @HAVE_CPPUNIT_TRUE@ newPredictorsTestRunner$(EXEEXT) @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@am__append_1 = smoothedNgramPredictorTest.h \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ smoothedNgramPredictorTest.cpp @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@am__append_2 = newSmoothedNgramPredictorTest.h \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ newSmoothedNgramPredictorTest.cpp @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@am__append_3 = $(top_builddir)/src/lib/predictors/dbconnector/libdbconnector.la subdir = test/lib/predictors DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_CPPUNIT_TRUE@libpredictorstest_la_DEPENDENCIES = $(top_builddir)/src/lib/predictors/libpredictors.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/core/libcore.la \ @HAVE_CPPUNIT_TRUE@ $(am__append_3) am_libpredictorstest_la_OBJECTS = libpredictorstest_la_OBJECTS = $(am_libpredictorstest_la_OBJECTS) @HAVE_CPPUNIT_TRUE@am_libpredictorstest_la_rpath = @HAVE_CPPUNIT_TRUE@am__EXEEXT_1 = predictorsTestRunner$(EXEEXT) \ @HAVE_CPPUNIT_TRUE@ newPredictorsTestRunner$(EXEEXT) am__newPredictorsTestRunner_SOURCES_DIST = predictorsTestRunner.cpp \ recencyPredictorTest.h recencyPredictorTest.cpp \ dejavuPredictorTest.h dejavuPredictorTest.cpp \ newSmoothedNgramPredictorTest.h \ newSmoothedNgramPredictorTest.cpp @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@am__objects_1 = newPredictorsTestRunner-newSmoothedNgramPredictorTest.$(OBJEXT) @HAVE_CPPUNIT_TRUE@am_newPredictorsTestRunner_OBJECTS = newPredictorsTestRunner-predictorsTestRunner.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ newPredictorsTestRunner-recencyPredictorTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ newPredictorsTestRunner-dejavuPredictorTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ $(am__objects_1) newPredictorsTestRunner_OBJECTS = \ $(am_newPredictorsTestRunner_OBJECTS) @HAVE_CPPUNIT_TRUE@newPredictorsTestRunner_DEPENDENCIES = \ @HAVE_CPPUNIT_TRUE@ libpredictorstest.la newPredictorsTestRunner_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) \ $(newPredictorsTestRunner_LDFLAGS) $(LDFLAGS) -o $@ am__predictorsTestRunner_SOURCES_DIST = predictorsTestRunner.cpp \ predictorsTestMockObjects.h predictorsTestMockObjects.cpp \ predictorsTestFixture.h predictorsTestFixture.cpp \ abbreviationExpansionPredictorTest.h \ abbreviationExpansionPredictorTest.cpp \ smoothedNgramPredictorTest.h smoothedNgramPredictorTest.cpp @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@am__objects_2 = predictorsTestRunner-smoothedNgramPredictorTest.$(OBJEXT) @HAVE_CPPUNIT_TRUE@am_predictorsTestRunner_OBJECTS = predictorsTestRunner-predictorsTestRunner.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ predictorsTestRunner-predictorsTestMockObjects.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ predictorsTestRunner-predictorsTestFixture.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ predictorsTestRunner-abbreviationExpansionPredictorTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@ $(am__objects_2) predictorsTestRunner_OBJECTS = $(am_predictorsTestRunner_OBJECTS) @HAVE_CPPUNIT_TRUE@predictorsTestRunner_DEPENDENCIES = \ @HAVE_CPPUNIT_TRUE@ libpredictorstest.la predictorsTestRunner_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) \ $(predictorsTestRunner_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libpredictorstest_la_SOURCES) \ $(newPredictorsTestRunner_SOURCES) \ $(predictorsTestRunner_SOURCES) DIST_SOURCES = $(libpredictorstest_la_SOURCES) \ $(am__newPredictorsTestRunner_SOURCES_DIST) \ $(am__predictorsTestRunner_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = dbconnector @HAVE_CPPUNIT_TRUE@predictorsTestRunner_SOURCES = \ @HAVE_CPPUNIT_TRUE@ predictorsTestRunner.cpp \ @HAVE_CPPUNIT_TRUE@ predictorsTestMockObjects.h \ @HAVE_CPPUNIT_TRUE@ predictorsTestMockObjects.cpp \ @HAVE_CPPUNIT_TRUE@ predictorsTestFixture.h \ @HAVE_CPPUNIT_TRUE@ predictorsTestFixture.cpp \ @HAVE_CPPUNIT_TRUE@ abbreviationExpansionPredictorTest.h \ @HAVE_CPPUNIT_TRUE@ abbreviationExpansionPredictorTest.cpp \ @HAVE_CPPUNIT_TRUE@ $(am__append_1) @HAVE_CPPUNIT_TRUE@predictorsTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@predictorsTestRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@predictorsTestRunner_LDADD = libpredictorstest.la @HAVE_CPPUNIT_TRUE@newPredictorsTestRunner_SOURCES = \ @HAVE_CPPUNIT_TRUE@ predictorsTestRunner.cpp \ @HAVE_CPPUNIT_TRUE@ recencyPredictorTest.h \ @HAVE_CPPUNIT_TRUE@ recencyPredictorTest.cpp \ @HAVE_CPPUNIT_TRUE@ dejavuPredictorTest.h \ @HAVE_CPPUNIT_TRUE@ dejavuPredictorTest.cpp $(am__append_2) @HAVE_CPPUNIT_TRUE@newPredictorsTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@newPredictorsTestRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@newPredictorsTestRunner_LDADD = libpredictorstest.la @HAVE_CPPUNIT_TRUE@check_LTLIBRARIES = libpredictorstest.la @HAVE_CPPUNIT_TRUE@libpredictorstest_la_SOURCES = @HAVE_CPPUNIT_TRUE@libpredictorstest_la_LIBADD = $(top_builddir)/src/lib/predictors/libpredictors.la \ @HAVE_CPPUNIT_TRUE@ $(top_builddir)/src/lib/core/libcore.la \ @HAVE_CPPUNIT_TRUE@ $(am__append_3) AM_CPPFLAGS = -I$(top_srcdir)/src/lib all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lib/predictors/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/lib/predictors/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkLTLIBRARIES: -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES) @list='$(check_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libpredictorstest.la: $(libpredictorstest_la_OBJECTS) $(libpredictorstest_la_DEPENDENCIES) $(LINK) $(am_libpredictorstest_la_rpath) $(libpredictorstest_la_OBJECTS) $(libpredictorstest_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list newPredictorsTestRunner$(EXEEXT): $(newPredictorsTestRunner_OBJECTS) $(newPredictorsTestRunner_DEPENDENCIES) @rm -f newPredictorsTestRunner$(EXEEXT) $(newPredictorsTestRunner_LINK) $(newPredictorsTestRunner_OBJECTS) $(newPredictorsTestRunner_LDADD) $(LIBS) predictorsTestRunner$(EXEEXT): $(predictorsTestRunner_OBJECTS) $(predictorsTestRunner_DEPENDENCIES) @rm -f predictorsTestRunner$(EXEEXT) $(predictorsTestRunner_LINK) $(predictorsTestRunner_OBJECTS) $(predictorsTestRunner_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newPredictorsTestRunner-dejavuPredictorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newPredictorsTestRunner-newSmoothedNgramPredictorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newPredictorsTestRunner-predictorsTestRunner.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newPredictorsTestRunner-recencyPredictorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/predictorsTestRunner-abbreviationExpansionPredictorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/predictorsTestRunner-predictorsTestFixture.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/predictorsTestRunner-predictorsTestMockObjects.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/predictorsTestRunner-predictorsTestRunner.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/predictorsTestRunner-smoothedNgramPredictorTest.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< newPredictorsTestRunner-predictorsTestRunner.o: predictorsTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-predictorsTestRunner.o -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-predictorsTestRunner.Tpo -c -o newPredictorsTestRunner-predictorsTestRunner.o `test -f 'predictorsTestRunner.cpp' || echo '$(srcdir)/'`predictorsTestRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-predictorsTestRunner.Tpo $(DEPDIR)/newPredictorsTestRunner-predictorsTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestRunner.cpp' object='newPredictorsTestRunner-predictorsTestRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-predictorsTestRunner.o `test -f 'predictorsTestRunner.cpp' || echo '$(srcdir)/'`predictorsTestRunner.cpp newPredictorsTestRunner-predictorsTestRunner.obj: predictorsTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-predictorsTestRunner.obj -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-predictorsTestRunner.Tpo -c -o newPredictorsTestRunner-predictorsTestRunner.obj `if test -f 'predictorsTestRunner.cpp'; then $(CYGPATH_W) 'predictorsTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-predictorsTestRunner.Tpo $(DEPDIR)/newPredictorsTestRunner-predictorsTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestRunner.cpp' object='newPredictorsTestRunner-predictorsTestRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-predictorsTestRunner.obj `if test -f 'predictorsTestRunner.cpp'; then $(CYGPATH_W) 'predictorsTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestRunner.cpp'; fi` newPredictorsTestRunner-recencyPredictorTest.o: recencyPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-recencyPredictorTest.o -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-recencyPredictorTest.Tpo -c -o newPredictorsTestRunner-recencyPredictorTest.o `test -f 'recencyPredictorTest.cpp' || echo '$(srcdir)/'`recencyPredictorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-recencyPredictorTest.Tpo $(DEPDIR)/newPredictorsTestRunner-recencyPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='recencyPredictorTest.cpp' object='newPredictorsTestRunner-recencyPredictorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-recencyPredictorTest.o `test -f 'recencyPredictorTest.cpp' || echo '$(srcdir)/'`recencyPredictorTest.cpp newPredictorsTestRunner-recencyPredictorTest.obj: recencyPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-recencyPredictorTest.obj -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-recencyPredictorTest.Tpo -c -o newPredictorsTestRunner-recencyPredictorTest.obj `if test -f 'recencyPredictorTest.cpp'; then $(CYGPATH_W) 'recencyPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/recencyPredictorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-recencyPredictorTest.Tpo $(DEPDIR)/newPredictorsTestRunner-recencyPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='recencyPredictorTest.cpp' object='newPredictorsTestRunner-recencyPredictorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-recencyPredictorTest.obj `if test -f 'recencyPredictorTest.cpp'; then $(CYGPATH_W) 'recencyPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/recencyPredictorTest.cpp'; fi` newPredictorsTestRunner-dejavuPredictorTest.o: dejavuPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-dejavuPredictorTest.o -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-dejavuPredictorTest.Tpo -c -o newPredictorsTestRunner-dejavuPredictorTest.o `test -f 'dejavuPredictorTest.cpp' || echo '$(srcdir)/'`dejavuPredictorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-dejavuPredictorTest.Tpo $(DEPDIR)/newPredictorsTestRunner-dejavuPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dejavuPredictorTest.cpp' object='newPredictorsTestRunner-dejavuPredictorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-dejavuPredictorTest.o `test -f 'dejavuPredictorTest.cpp' || echo '$(srcdir)/'`dejavuPredictorTest.cpp newPredictorsTestRunner-dejavuPredictorTest.obj: dejavuPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-dejavuPredictorTest.obj -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-dejavuPredictorTest.Tpo -c -o newPredictorsTestRunner-dejavuPredictorTest.obj `if test -f 'dejavuPredictorTest.cpp'; then $(CYGPATH_W) 'dejavuPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/dejavuPredictorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-dejavuPredictorTest.Tpo $(DEPDIR)/newPredictorsTestRunner-dejavuPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dejavuPredictorTest.cpp' object='newPredictorsTestRunner-dejavuPredictorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-dejavuPredictorTest.obj `if test -f 'dejavuPredictorTest.cpp'; then $(CYGPATH_W) 'dejavuPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/dejavuPredictorTest.cpp'; fi` newPredictorsTestRunner-newSmoothedNgramPredictorTest.o: newSmoothedNgramPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-newSmoothedNgramPredictorTest.o -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-newSmoothedNgramPredictorTest.Tpo -c -o newPredictorsTestRunner-newSmoothedNgramPredictorTest.o `test -f 'newSmoothedNgramPredictorTest.cpp' || echo '$(srcdir)/'`newSmoothedNgramPredictorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-newSmoothedNgramPredictorTest.Tpo $(DEPDIR)/newPredictorsTestRunner-newSmoothedNgramPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='newSmoothedNgramPredictorTest.cpp' object='newPredictorsTestRunner-newSmoothedNgramPredictorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-newSmoothedNgramPredictorTest.o `test -f 'newSmoothedNgramPredictorTest.cpp' || echo '$(srcdir)/'`newSmoothedNgramPredictorTest.cpp newPredictorsTestRunner-newSmoothedNgramPredictorTest.obj: newSmoothedNgramPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT newPredictorsTestRunner-newSmoothedNgramPredictorTest.obj -MD -MP -MF $(DEPDIR)/newPredictorsTestRunner-newSmoothedNgramPredictorTest.Tpo -c -o newPredictorsTestRunner-newSmoothedNgramPredictorTest.obj `if test -f 'newSmoothedNgramPredictorTest.cpp'; then $(CYGPATH_W) 'newSmoothedNgramPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/newSmoothedNgramPredictorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/newPredictorsTestRunner-newSmoothedNgramPredictorTest.Tpo $(DEPDIR)/newPredictorsTestRunner-newSmoothedNgramPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='newSmoothedNgramPredictorTest.cpp' object='newPredictorsTestRunner-newSmoothedNgramPredictorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(newPredictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o newPredictorsTestRunner-newSmoothedNgramPredictorTest.obj `if test -f 'newSmoothedNgramPredictorTest.cpp'; then $(CYGPATH_W) 'newSmoothedNgramPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/newSmoothedNgramPredictorTest.cpp'; fi` predictorsTestRunner-predictorsTestRunner.o: predictorsTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-predictorsTestRunner.o -MD -MP -MF $(DEPDIR)/predictorsTestRunner-predictorsTestRunner.Tpo -c -o predictorsTestRunner-predictorsTestRunner.o `test -f 'predictorsTestRunner.cpp' || echo '$(srcdir)/'`predictorsTestRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-predictorsTestRunner.Tpo $(DEPDIR)/predictorsTestRunner-predictorsTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestRunner.cpp' object='predictorsTestRunner-predictorsTestRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-predictorsTestRunner.o `test -f 'predictorsTestRunner.cpp' || echo '$(srcdir)/'`predictorsTestRunner.cpp predictorsTestRunner-predictorsTestRunner.obj: predictorsTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-predictorsTestRunner.obj -MD -MP -MF $(DEPDIR)/predictorsTestRunner-predictorsTestRunner.Tpo -c -o predictorsTestRunner-predictorsTestRunner.obj `if test -f 'predictorsTestRunner.cpp'; then $(CYGPATH_W) 'predictorsTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-predictorsTestRunner.Tpo $(DEPDIR)/predictorsTestRunner-predictorsTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestRunner.cpp' object='predictorsTestRunner-predictorsTestRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-predictorsTestRunner.obj `if test -f 'predictorsTestRunner.cpp'; then $(CYGPATH_W) 'predictorsTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestRunner.cpp'; fi` predictorsTestRunner-predictorsTestMockObjects.o: predictorsTestMockObjects.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-predictorsTestMockObjects.o -MD -MP -MF $(DEPDIR)/predictorsTestRunner-predictorsTestMockObjects.Tpo -c -o predictorsTestRunner-predictorsTestMockObjects.o `test -f 'predictorsTestMockObjects.cpp' || echo '$(srcdir)/'`predictorsTestMockObjects.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-predictorsTestMockObjects.Tpo $(DEPDIR)/predictorsTestRunner-predictorsTestMockObjects.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestMockObjects.cpp' object='predictorsTestRunner-predictorsTestMockObjects.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-predictorsTestMockObjects.o `test -f 'predictorsTestMockObjects.cpp' || echo '$(srcdir)/'`predictorsTestMockObjects.cpp predictorsTestRunner-predictorsTestMockObjects.obj: predictorsTestMockObjects.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-predictorsTestMockObjects.obj -MD -MP -MF $(DEPDIR)/predictorsTestRunner-predictorsTestMockObjects.Tpo -c -o predictorsTestRunner-predictorsTestMockObjects.obj `if test -f 'predictorsTestMockObjects.cpp'; then $(CYGPATH_W) 'predictorsTestMockObjects.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestMockObjects.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-predictorsTestMockObjects.Tpo $(DEPDIR)/predictorsTestRunner-predictorsTestMockObjects.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestMockObjects.cpp' object='predictorsTestRunner-predictorsTestMockObjects.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-predictorsTestMockObjects.obj `if test -f 'predictorsTestMockObjects.cpp'; then $(CYGPATH_W) 'predictorsTestMockObjects.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestMockObjects.cpp'; fi` predictorsTestRunner-predictorsTestFixture.o: predictorsTestFixture.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-predictorsTestFixture.o -MD -MP -MF $(DEPDIR)/predictorsTestRunner-predictorsTestFixture.Tpo -c -o predictorsTestRunner-predictorsTestFixture.o `test -f 'predictorsTestFixture.cpp' || echo '$(srcdir)/'`predictorsTestFixture.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-predictorsTestFixture.Tpo $(DEPDIR)/predictorsTestRunner-predictorsTestFixture.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestFixture.cpp' object='predictorsTestRunner-predictorsTestFixture.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-predictorsTestFixture.o `test -f 'predictorsTestFixture.cpp' || echo '$(srcdir)/'`predictorsTestFixture.cpp predictorsTestRunner-predictorsTestFixture.obj: predictorsTestFixture.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-predictorsTestFixture.obj -MD -MP -MF $(DEPDIR)/predictorsTestRunner-predictorsTestFixture.Tpo -c -o predictorsTestRunner-predictorsTestFixture.obj `if test -f 'predictorsTestFixture.cpp'; then $(CYGPATH_W) 'predictorsTestFixture.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestFixture.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-predictorsTestFixture.Tpo $(DEPDIR)/predictorsTestRunner-predictorsTestFixture.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='predictorsTestFixture.cpp' object='predictorsTestRunner-predictorsTestFixture.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-predictorsTestFixture.obj `if test -f 'predictorsTestFixture.cpp'; then $(CYGPATH_W) 'predictorsTestFixture.cpp'; else $(CYGPATH_W) '$(srcdir)/predictorsTestFixture.cpp'; fi` predictorsTestRunner-abbreviationExpansionPredictorTest.o: abbreviationExpansionPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-abbreviationExpansionPredictorTest.o -MD -MP -MF $(DEPDIR)/predictorsTestRunner-abbreviationExpansionPredictorTest.Tpo -c -o predictorsTestRunner-abbreviationExpansionPredictorTest.o `test -f 'abbreviationExpansionPredictorTest.cpp' || echo '$(srcdir)/'`abbreviationExpansionPredictorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-abbreviationExpansionPredictorTest.Tpo $(DEPDIR)/predictorsTestRunner-abbreviationExpansionPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='abbreviationExpansionPredictorTest.cpp' object='predictorsTestRunner-abbreviationExpansionPredictorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-abbreviationExpansionPredictorTest.o `test -f 'abbreviationExpansionPredictorTest.cpp' || echo '$(srcdir)/'`abbreviationExpansionPredictorTest.cpp predictorsTestRunner-abbreviationExpansionPredictorTest.obj: abbreviationExpansionPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-abbreviationExpansionPredictorTest.obj -MD -MP -MF $(DEPDIR)/predictorsTestRunner-abbreviationExpansionPredictorTest.Tpo -c -o predictorsTestRunner-abbreviationExpansionPredictorTest.obj `if test -f 'abbreviationExpansionPredictorTest.cpp'; then $(CYGPATH_W) 'abbreviationExpansionPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/abbreviationExpansionPredictorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-abbreviationExpansionPredictorTest.Tpo $(DEPDIR)/predictorsTestRunner-abbreviationExpansionPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='abbreviationExpansionPredictorTest.cpp' object='predictorsTestRunner-abbreviationExpansionPredictorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-abbreviationExpansionPredictorTest.obj `if test -f 'abbreviationExpansionPredictorTest.cpp'; then $(CYGPATH_W) 'abbreviationExpansionPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/abbreviationExpansionPredictorTest.cpp'; fi` predictorsTestRunner-smoothedNgramPredictorTest.o: smoothedNgramPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-smoothedNgramPredictorTest.o -MD -MP -MF $(DEPDIR)/predictorsTestRunner-smoothedNgramPredictorTest.Tpo -c -o predictorsTestRunner-smoothedNgramPredictorTest.o `test -f 'smoothedNgramPredictorTest.cpp' || echo '$(srcdir)/'`smoothedNgramPredictorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-smoothedNgramPredictorTest.Tpo $(DEPDIR)/predictorsTestRunner-smoothedNgramPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='smoothedNgramPredictorTest.cpp' object='predictorsTestRunner-smoothedNgramPredictorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-smoothedNgramPredictorTest.o `test -f 'smoothedNgramPredictorTest.cpp' || echo '$(srcdir)/'`smoothedNgramPredictorTest.cpp predictorsTestRunner-smoothedNgramPredictorTest.obj: smoothedNgramPredictorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -MT predictorsTestRunner-smoothedNgramPredictorTest.obj -MD -MP -MF $(DEPDIR)/predictorsTestRunner-smoothedNgramPredictorTest.Tpo -c -o predictorsTestRunner-smoothedNgramPredictorTest.obj `if test -f 'smoothedNgramPredictorTest.cpp'; then $(CYGPATH_W) 'smoothedNgramPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/smoothedNgramPredictorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/predictorsTestRunner-smoothedNgramPredictorTest.Tpo $(DEPDIR)/predictorsTestRunner-smoothedNgramPredictorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='smoothedNgramPredictorTest.cpp' object='predictorsTestRunner-smoothedNgramPredictorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(predictorsTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o predictorsTestRunner-smoothedNgramPredictorTest.obj `if test -f 'smoothedNgramPredictorTest.cpp'; then $(CYGPATH_W) 'smoothedNgramPredictorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/smoothedNgramPredictorTest.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \ clean-libtool mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-TESTS check-am clean \ clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \ clean-libtool ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # 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: �����������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/recencyPredictorTest.h��������������������������������������������0000644�0001750�0001750�00000004154�11763437013�020327� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_RECENCYPREDICTORTEST #define PRESAGE_RECENCYPREDICTORTEST #include <cppunit/extensions/HelperMacros.h> #include <predictors/recencyPredictor.h> /** Test RecencyPredictor. * */ class RecencyPredictorTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testMaxPartialPredictionSize(); void testCutoffThreshold(); void testFilter(); private: Configuration* config; PredictorRegistry* predictorRegistry; std::stringstream* stream; PresageCallback* callback; ContextTracker* ct; static const int SIZE; static const char* NAME; static const char* PREDICTOR; static const char* LOGGER; static const char* LAMBDA; static const char* CUTOFF; static const char* N_0; CPPUNIT_TEST_SUITE( RecencyPredictorTest ); CPPUNIT_TEST( testMaxPartialPredictionSize ); CPPUNIT_TEST( testCutoffThreshold ); CPPUNIT_TEST( testFilter ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_RECENCYPREDICTORTEST ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/predictorsTestMockObjects.h���������������������������������������0000644�0001750�0001750�00000002504�11737142176�021326� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_PREDICTORSTESTMOCKOBJECTS #define PRESAGE_PREDICTORSTESTMOCKOBJECTS #include "predictors/predictor.h" typedef std::map< std::string, std::string > ConfigMap; #endif // PRESAGE_PREDICTORSTESTMOCKOBJECTS ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/predictorsTestRunner.cpp������������������������������������������0000644�0001750�0001750�00000002661�11737142176�020733� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> int main() { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest( registry.makeTest() ); bool success = runner.run(); return success ? 0 : 1; } �������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dbconnector/������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�016403� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dbconnector/sqliteDatabaseConnectorTest.cpp�����������������������0000644�0001750�0001750�00000051631�11763437013�024461� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "sqliteDatabaseConnectorTest.h" // for unlink(), getcwd() #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #ifdef HAVE_STRING_H # include <string.h> #endif // for opendir(), readdir(), closedir(), DIR, dirent #if HAVE_DIRENT_H # include <dirent.h> # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # if HAVE_SYS_NDIR_H # include <sys/ndir.h> # endif # if HAVE_SYS_DIR_H # include <sys/dir.h> # endif # if HAVE_NDIR_H # include <ndir.h> # endif #endif #include <stdio.h> #include <stdlib.h> #include <fstream> #include <assert.h> CPPUNIT_TEST_SUITE_REGISTRATION( SqliteDatabaseConnectorTest ); void SqliteDatabaseConnectorTest::setUp() { CPPUNIT_ASSERT_NO_THROW ( sqliteDatabaseConnector = new SqliteDatabaseConnector(DEFAULT_DATABASE_FILENAME, DEFAULT_DATABASE_CARDINALITY, DEFAULT_DATABASE_READ_WRITE_MODE) ); unigram = new Ngram; unigram->push_back("foo"); bigram = new Ngram; bigram->push_back("foo"); bigram->push_back("bar"); trigram = new Ngram; trigram->push_back("foo"); trigram->push_back("bar"); trigram->push_back("foobar"); unigram1 = new Ngram; unigram1->push_back("foo1"); bigram1 = new Ngram; bigram1->push_back("foo"); bigram1->push_back("bar1"); trigram1 = new Ngram; trigram1->push_back("foo"); trigram1->push_back("bar"); trigram1->push_back("foobar1"); } void SqliteDatabaseConnectorTest::tearDown() { delete sqliteDatabaseConnector; delete unigram; delete bigram; delete trigram; delete unigram1; delete bigram1; delete trigram1; assertExistsAndRemoveFile(DEFAULT_DATABASE_FILENAME); } void SqliteDatabaseConnectorTest::testConstructor() { std::cout << "SqliteDatabaseConnectorTest::testConstructor()" << std::endl; // This tests that an empty database is created when an instance // of SqliteDatabaseConstructor is created. The SqliteDatabase // instantiation is done in the setUp() method and the testing is // actually done in the tearDown() method. } void SqliteDatabaseConnectorTest::testInsertNgram() { std::cout << "SqliteDatabaseConnectorTest::testInsertNgram()" << std::endl; // populate database CPPUNIT_ASSERT_NO_THROW(sqliteDatabaseConnector->insertNgram(*unigram, MAGIC_NUMBER)); CPPUNIT_ASSERT_NO_THROW(sqliteDatabaseConnector->insertNgram(*bigram, MAGIC_NUMBER)); CPPUNIT_ASSERT_NO_THROW(sqliteDatabaseConnector->insertNgram(*trigram, MAGIC_NUMBER)); // test no exception occurs when attempting to recreate existing tables CPPUNIT_ASSERT_NO_THROW(sqliteDatabaseConnector->createNgramTable(1)); CPPUNIT_ASSERT_NO_THROW(sqliteDatabaseConnector->createNgramTable(2)); CPPUNIT_ASSERT_NO_THROW(sqliteDatabaseConnector->createNgramTable(3)); // compare database dump with benchmark string std::stringstream benchmark; benchmark #if defined(HAVE_SQLITE3_H) << "BEGIN TRANSACTION;" << std::endl << "CREATE TABLE _1_gram (word TEXT, count INTEGER, UNIQUE(word) );" << std::endl << "INSERT INTO \"_1_gram\" VALUES('foo', 1337);" << std::endl << "CREATE TABLE _2_gram (word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_1, word) );" << std::endl << "INSERT INTO \"_2_gram\" VALUES('foo', 'bar', 1337);" << std::endl << "CREATE TABLE _3_gram (word_2 TEXT, word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_2, word_1, word) );" << std::endl << "INSERT INTO \"_3_gram\" VALUES('foo', 'bar', 'foobar', 1337);" << std::endl << "COMMIT;" << std::endl; #elif defined(HAVE_SQLITE_H) << "BEGIN TRANSACTION;" << std::endl << "CREATE TABLE _1_gram (word TEXT, count INTEGER, UNIQUE(word) );" << std::endl << "INSERT INTO _1_gram VALUES('foo',1337);" << std::endl << "CREATE TABLE _2_gram (word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_1, word) );" << std::endl << "INSERT INTO _2_gram VALUES('foo','bar',1337);" << std::endl << "CREATE TABLE _3_gram (word_2 TEXT, word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_2, word_1, word) );" << std::endl << "INSERT INTO _3_gram VALUES('foo','bar','foobar',1337);" << std::endl << "COMMIT;" << std::endl; #endif assertDatabaseDumpEqualsBenchmark(benchmark); } void SqliteDatabaseConnectorTest::testUpdateNgram() { std::cout << "SqliteDatabaseConnectorTest::testUpdateNgram()" << std::endl; // populate database sqliteDatabaseConnector->createNgramTable(1); sqliteDatabaseConnector->insertNgram(*unigram, MAGIC_NUMBER); sqliteDatabaseConnector->updateNgram(*unigram, MAGIC_NUMBER * 2); sqliteDatabaseConnector->createNgramTable(2); sqliteDatabaseConnector->insertNgram(*bigram, MAGIC_NUMBER); sqliteDatabaseConnector->updateNgram(*bigram, MAGIC_NUMBER * 2); sqliteDatabaseConnector->createNgramTable(3); sqliteDatabaseConnector->insertNgram(*trigram, MAGIC_NUMBER); sqliteDatabaseConnector->updateNgram(*trigram, MAGIC_NUMBER * 2); // compare database dump with benchmark string std::stringstream benchmark; benchmark << "BEGIN TRANSACTION;" << std::endl << "CREATE TABLE _1_gram (word TEXT, count INTEGER, UNIQUE(word) );" << std::endl #if defined(HAVE_SQLITE3_H) << "INSERT INTO \"_1_gram\" VALUES('foo', 2674);" << std::endl #elif defined(HAVE_SQLITE_H) << "INSERT INTO _1_gram VALUES('foo',2674);" << std::endl #endif << "CREATE TABLE _2_gram (word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_1, word) );" << std::endl #if defined(HAVE_SQLITE3_H) << "INSERT INTO \"_2_gram\" VALUES('foo', 'bar', 2674);" << std::endl #elif defined(HAVE_SQLITE_H) << "INSERT INTO _2_gram VALUES('foo','bar',2674);" << std::endl #endif << "CREATE TABLE _3_gram (word_2 TEXT, word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_2, word_1, word) );" << std::endl #if defined(HAVE_SQLITE3_H) << "INSERT INTO \"_3_gram\" VALUES('foo', 'bar', 'foobar', 2674);" << std::endl #elif defined(HAVE_SQLITE_H) << "INSERT INTO _3_gram VALUES('foo','bar','foobar',2674);" << std::endl #endif << "COMMIT;" << std::endl; assertDatabaseDumpEqualsBenchmark(benchmark); } void SqliteDatabaseConnectorTest::testRemoveNgram() { //CPPUNIT_FAIL("Test not written yet!"); } void SqliteDatabaseConnectorTest::testGetNgramCount() { std::cout << "SqliteDatabaseConnectorTest::testGetNgramCount()" << std::endl; // populate database sqliteDatabaseConnector->createNgramTable(1); sqliteDatabaseConnector->insertNgram(*unigram, MAGIC_NUMBER); sqliteDatabaseConnector->createNgramTable(2); sqliteDatabaseConnector->insertNgram(*bigram, MAGIC_NUMBER); sqliteDatabaseConnector->createNgramTable(3); sqliteDatabaseConnector->insertNgram(*trigram, MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( MAGIC_NUMBER, sqliteDatabaseConnector->getNgramCount(*unigram) ); CPPUNIT_ASSERT_EQUAL( MAGIC_NUMBER, sqliteDatabaseConnector->getNgramCount(*bigram) ); CPPUNIT_ASSERT_EQUAL( MAGIC_NUMBER, sqliteDatabaseConnector->getNgramCount(*trigram) ); // Add crafted unigram to database to test that WHERE word = // "word" bug has been fixed. Fix is using WHERE word = 'word' // clause. // A keyword in single quotes is interpreted as a literal string // if it occurs in a context where a string literal is allowed, // otherwise it is understood as an identifier, whereas a // keyword in double-quotes is interpreted as an identifier if // it matches a known identifier - otherwise it is interpreted // as a string literal. The following WHERE word = "word" is a // no-op, the correct clause is WHERE word = 'word'. Ngram* ngram = new Ngram(); ngram->push_back("word"); sqliteDatabaseConnector->insertNgram(*ngram, MAGIC_NUMBER + 1); CPPUNIT_ASSERT_EQUAL( MAGIC_NUMBER + 1, sqliteDatabaseConnector->getNgramCount(*ngram) ); delete ngram; } void SqliteDatabaseConnectorTest::testIncrementNgramCount() { std::cout << "SqliteDatabaseConnectorTest::testIncrementNgramCount()" << std::endl; // populate database sqliteDatabaseConnector->incrementNgramCount(*unigram); sqliteDatabaseConnector->incrementNgramCount(*unigram); sqliteDatabaseConnector->incrementNgramCount(*unigram); sqliteDatabaseConnector->incrementNgramCount(*bigram); sqliteDatabaseConnector->incrementNgramCount(*bigram); sqliteDatabaseConnector->incrementNgramCount(*bigram); sqliteDatabaseConnector->incrementNgramCount(*trigram); sqliteDatabaseConnector->incrementNgramCount(*trigram); sqliteDatabaseConnector->incrementNgramCount(*trigram); // compare database dump with benchmark string std::stringstream benchmark; benchmark << "BEGIN TRANSACTION;" << std::endl << "CREATE TABLE _1_gram (word TEXT, count INTEGER, UNIQUE(word) );" << std::endl #if defined(HAVE_SQLITE3_H) << "INSERT INTO \"_1_gram\" VALUES('foo', 3);" << std::endl #elif defined(HAVE_SQLITE_H) << "INSERT INTO _1_gram VALUES('foo',3);" << std::endl #endif << "CREATE TABLE _2_gram (word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_1, word) );" << std::endl #if defined(HAVE_SQLITE3_H) << "INSERT INTO \"_2_gram\" VALUES('foo', 'bar', 3);" << std::endl #elif defined(HAVE_SQLITE_H) << "INSERT INTO _2_gram VALUES('foo','bar',3);" << std::endl #endif << "CREATE TABLE _3_gram (word_2 TEXT, word_1 TEXT, word TEXT, count INTEGER, UNIQUE(word_2, word_1, word) );" << std::endl #if defined(HAVE_SQLITE3_H) << "INSERT INTO \"_3_gram\" VALUES('foo', 'bar', 'foobar', 3);" << std::endl #elif defined(HAVE_SQLITE_H) << "INSERT INTO _3_gram VALUES('foo','bar','foobar',3);" << std::endl #endif << "COMMIT;" << std::endl; assertDatabaseDumpEqualsBenchmark(benchmark); } void SqliteDatabaseConnectorTest::testGetNgramLikeTable() { std::cout << "SqliteDatabaseConnectorTest::testGetNgramLikeTable()" << std::endl; // populate database sqliteDatabaseConnector->createNgramTable(1); sqliteDatabaseConnector->insertNgram(*unigram, MAGIC_NUMBER); sqliteDatabaseConnector->createNgramTable(2); sqliteDatabaseConnector->insertNgram(*bigram, MAGIC_NUMBER); sqliteDatabaseConnector->createNgramTable(3); sqliteDatabaseConnector->insertNgram(*trigram, MAGIC_NUMBER); NgramTable* expected_uni; NgramTable* expected_bi; NgramTable* expected_tri; NgramTable actual; Ngram* ngram; expected_uni = new NgramTable(); ngram = new Ngram(); ngram->push_back("foo"); ngram->push_back("1337"); expected_uni->push_back(*ngram); actual = sqliteDatabaseConnector->getNgramLikeTable(*unigram); assertEqualNgramTable(expected_uni, actual); delete ngram; expected_bi = new NgramTable(); ngram = new Ngram(); ngram->push_back("foo"); ngram->push_back("bar"); ngram->push_back("1337"); expected_bi->push_back(*ngram); actual = sqliteDatabaseConnector->getNgramLikeTable(*bigram); assertEqualNgramTable(expected_bi, actual); delete ngram; expected_tri = new NgramTable(); ngram = new Ngram(); ngram->push_back("foo"); ngram->push_back("bar"); ngram->push_back("foobar"); ngram->push_back("1337"); expected_tri->push_back(*ngram); actual = sqliteDatabaseConnector->getNgramLikeTable(*trigram); assertEqualNgramTable(expected_tri, actual); delete ngram; // add similar ngrams to database sqliteDatabaseConnector->insertNgram(*unigram1, MAGIC_NUMBER - 1); sqliteDatabaseConnector->insertNgram(*bigram1, MAGIC_NUMBER - 1); sqliteDatabaseConnector->insertNgram(*trigram1, MAGIC_NUMBER - 1); ngram = new Ngram(); ngram->push_back("foo1"); ngram->push_back("1336"); expected_uni->push_back(*ngram); actual = sqliteDatabaseConnector->getNgramLikeTable(*unigram); assertEqualNgramTable(expected_uni, actual); delete ngram; ngram = new Ngram(); ngram->push_back("foo"); ngram->push_back("bar1"); ngram->push_back("1336"); expected_bi->push_back(*ngram); actual = sqliteDatabaseConnector->getNgramLikeTable(*bigram); assertEqualNgramTable(expected_bi, actual); delete ngram; ngram = new Ngram(); ngram->push_back("foo"); ngram->push_back("bar"); ngram->push_back("foobar1"); ngram->push_back("1336"); expected_tri->push_back(*ngram); actual = sqliteDatabaseConnector->getNgramLikeTable(*trigram); assertEqualNgramTable(expected_tri, actual); delete ngram; delete expected_uni; delete expected_bi; delete expected_tri; } void SqliteDatabaseConnectorTest::assertEqualNgramTable(const NgramTable* const expected, const NgramTable& actual) { CPPUNIT_ASSERT_EQUAL(expected->size(), actual.size()); for (size_t i = 0; i < expected->size(); i++) { CPPUNIT_ASSERT_EQUAL((*expected)[i].size(), actual[i].size()); for (size_t j = 0; j < (*expected)[i].size(); j++) { std::cout << "[assertEqualNgramTable] (" << (*expected)[i][j] << ", " << actual[i][j] << ")" << std::endl; CPPUNIT_ASSERT((*expected)[i][j] == actual[i][j]); } } } void SqliteDatabaseConnectorTest::assertExistsAndRemoveFile(const char* filename) const { std::cerr << "SqliteDatabaseConnectorTest::assertExistsAndRemoveFile (" << filename << ")" << std::endl; #ifdef HAVE_DIRENT_H bool result = false; DIR* dp; struct dirent *ep; // check if file exists in current directory dp = opendir ("./"); if (dp != NULL) { while ((ep = readdir (dp)) && (result == 0)) { if (strcmp(ep->d_name, filename) == 0) { result = true; } } (void) closedir (dp); } else { perror ("[SqliteDatabaseConnectorTest] Couldn't open current directory!"); } CPPUNIT_ASSERT( result == true ); #else // if we cannot determine file existance, let us assume that file // exists bool result = true; #endif #ifdef HAVE_UNISTD_H // remove file if it exists if (result) { if (unlink(filename)) { perror ("Unable to remove file"); } } #else // fail test std::string message = "Unable to remove file: "; message += filename; CPPUNIT_FAIL( message.c_str() ); //exit(-1); #endif } void SqliteDatabaseConnectorTest::assertDatabaseDumpEqualsBenchmark(std::stringstream& benchmark) const { // dump database content using `sqlite' client std::string command = #if defined(HAVE_SQLITE3_H) static_cast<std::string>("sqlite3 ") #elif defined(HAVE_SQLITE_H) static_cast<std::string>("sqlite ") #endif + DEFAULT_DATABASE_FILENAME + " \".dump\" > " + DATABASE_DUMP; std::cout << "Executing `" << command << "'" << std::endl; int command_exit_value = system(command.c_str()); CPPUNIT_ASSERT(command_exit_value == 0); std::ifstream database_dump_stream(DATABASE_DUMP); // NOTE: this block of code has been commented out to account for // the fact that different versions of the sqlite/sqlite3 binary // return slightly different dumps of the same database. The // differences are limited to whitespace, single quotes, or double // quotes; but they do make a stream length comparison // inconclusive as to determine if two streams are a dump of the // same database. // // assert streams contain equal number of characters // //benchmark.seekg(0, std::ios::end); //database_dump_stream.seekg(0, std::ios::end); //CPPUNIT_ASSERT( benchmark.tellg() == database_dump_stream.tellg() ); //benchmark.seekg(0); //database_dump_stream.seekg(0); // remove PRAGMAs std::string buffer; std::stringstream stripped_database_dump_stream; while (getline(database_dump_stream, buffer)) { // if buffer does not contain substring "PRAGMA" if (buffer.find("PRAGMA") == std::string::npos) { stripped_database_dump_stream << buffer << std::endl; } } database_dump_stream.close(); // assert streams contain same characters std::string actual; std::string expected; bool equal = true;; while (getline(benchmark, expected) && getline(stripped_database_dump_stream, actual)) { // remove " and ' from strings, because different versions of // sqlite insert either double quotes or single quotes or no // quotes at all. strip_char('"', actual); strip_char('\'', actual); strip_char('"', expected); strip_char('\'', expected); // also remove space from strings // TODO: removing space is not bulletproof, i.e. a really // difference in the SQL might slip by unseen. strip_char(' ', actual); strip_char(' ', expected); equal = (expected == actual); //if (!equal) std::cout << "[expected] " << expected << std::endl << "[actual ] " << actual << std::endl; CPPUNIT_ASSERT(equal); } assertExistsAndRemoveFile(DATABASE_DUMP); //// // Using pipes instead of writing to a temp file. // Currently does not work. // // std::string command = static_cast<std::string>("sqlite ") + DEFAULT_DATABASE_FILENAME + " '.dump' > " + DATABASE_DUMP; // FILE* pipe = popen(command.c_str(), "r"); // while (!feof(pipe) && !ferror(pipe)) { // std::cout << static_cast<char>(fgetc(pipe)); // } // // CPPUNIT_ASSERT( pipe != NULL ); // if (pipe) { // int expected; // int actual; // while(benchmark.good() && !feof(pipe) && !ferror(pipe)) { // expected = benchmark.get(); // actual = fgetc(pipe); // // std::cout << "[expected] " << static_cast<char>(expected) // << " [actual] " << static_cast<char>(actual) << std::endl; // // // CPPUNIT_ASSERT_EQUAL( expected, actual ); // } // // pclose(pipe); // } else { // CPPUNIT_FAIL( "Unable to open pipe to execute `sqlite'" ); // } } void SqliteDatabaseConnectorTest::strip_char(char c, std::string& str) const { //std::cout << "string before: " << str << std::endl; std::string::size_type pos = 0; while ((pos = str.find(c, pos)) != std::string::npos) { str.erase(pos, 1); //std::cout << "pos: " << pos << "string: " << str << std::endl; } //std::cout << "string after : " << str << std::endl; } �������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dbconnector/Makefile.am�������������������������������������������0000644�0001750�0001750�00000003700�11763437013�020342� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if HAVE_CPPUNIT if USE_SQLITE TESTS = dbconnectorTestRunner check_PROGRAMS = $(TESTS) dbconnectorTestRunner_SOURCES = dbconnectorTestRunner.cpp \ databaseConnectorTest.cpp \ databaseConnectorTest.h \ sqliteDatabaseConnectorTest.cpp \ sqliteDatabaseConnectorTest.h \ $(top_srcdir)/src/lib/presageException.h \ $(top_srcdir)/src/lib/core/presageException.cpp \ $(top_srcdir)/src/lib/core/utility.h \ $(top_srcdir)/src/lib/core/utility.cpp # presageException files are included in sources since sqlite # database connector defines an exception that inherits from # presage base exception dbconnectorTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) dbconnectorTestRunner_LDFLAGS = $(CPPUNIT_LIBS) dbconnectorTestRunner_LDADD = $(top_builddir)/src/lib/predictors/dbconnector/libdbconnector.la dbconnectorTestRunner_CPPFLAGS = -I$(top_srcdir)/src/lib # Clean out files created during tests. # Required to make distcheck happy. DISTCLEANFILES = test.db endif endif ����������������������������������������������������������������presage-0.8.8/test/lib/predictors/dbconnector/sqliteDatabaseConnectorTest.h�������������������������0000644�0001750�0001750�00000005667�11763437013�024136� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_SQLITEDATABASECONNECTORTEST #define PRESAGE_SQLITEDATABASECONNECTORTEST #include <cppunit/extensions/HelperMacros.h> #include "predictors/dbconnector/sqliteDatabaseConnector.h" #include <iostream> #include <sstream> static const char DEFAULT_DATABASE_FILENAME[] = "database.db"; static const size_t DEFAULT_DATABASE_CARDINALITY = 3; static const bool DEFAULT_DATABASE_READ_WRITE_MODE = true; static const char DATABASE_DUMP[] = "database.dump"; class SqliteDatabaseConnectorTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testConstructor(); void testInsertNgram(); void testUpdateNgram(); void testRemoveNgram(); void testGetNgramCount(); void testIncrementNgramCount(); void testGetNgramLikeTable(); private: void assertExistsAndRemoveFile(const char* filename) const; void assertDatabaseDumpEqualsBenchmark(std::stringstream& benchmark) const; void assertEqualNgramTable(const NgramTable* const, const NgramTable&); void strip_char(char c, std::string& str) const; DatabaseConnector* sqliteDatabaseConnector; Ngram* unigram; Ngram* bigram; Ngram* trigram; Ngram* unigram1; Ngram* bigram1; Ngram* trigram1; static const int MAGIC_NUMBER; CPPUNIT_TEST_SUITE( SqliteDatabaseConnectorTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testInsertNgram ); CPPUNIT_TEST( testUpdateNgram ); CPPUNIT_TEST( testRemoveNgram ); CPPUNIT_TEST( testGetNgramCount ); CPPUNIT_TEST( testIncrementNgramCount ); CPPUNIT_TEST( testGetNgramLikeTable ); CPPUNIT_TEST_SUITE_END(); }; const int SqliteDatabaseConnectorTest::MAGIC_NUMBER = 1337; #endif // PRESAGE_SQLITEDATABASECONNECTORTEST �������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dbconnector/Makefile.in�������������������������������������������0000644�0001750�0001750�00000105432�11763440356�020364� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@TESTS = dbconnectorTestRunner$(EXEEXT) @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@check_PROGRAMS = $(am__EXEEXT_1) subdir = test/lib/predictors/dbconnector DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@am__EXEEXT_1 = dbconnectorTestRunner$(EXEEXT) am__dbconnectorTestRunner_SOURCES_DIST = dbconnectorTestRunner.cpp \ databaseConnectorTest.cpp databaseConnectorTest.h \ sqliteDatabaseConnectorTest.cpp sqliteDatabaseConnectorTest.h \ $(top_srcdir)/src/lib/presageException.h \ $(top_srcdir)/src/lib/core/presageException.cpp \ $(top_srcdir)/src/lib/core/utility.h \ $(top_srcdir)/src/lib/core/utility.cpp @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@am_dbconnectorTestRunner_OBJECTS = dbconnectorTestRunner-dbconnectorTestRunner.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ dbconnectorTestRunner-databaseConnectorTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ dbconnectorTestRunner-sqliteDatabaseConnectorTest.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ dbconnectorTestRunner-presageException.$(OBJEXT) \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ dbconnectorTestRunner-utility.$(OBJEXT) dbconnectorTestRunner_OBJECTS = $(am_dbconnectorTestRunner_OBJECTS) @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@dbconnectorTestRunner_DEPENDENCIES = $(top_builddir)/src/lib/predictors/dbconnector/libdbconnector.la dbconnectorTestRunner_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) \ $(dbconnectorTestRunner_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(dbconnectorTestRunner_SOURCES) DIST_SOURCES = $(am__dbconnectorTestRunner_SOURCES_DIST) ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@dbconnectorTestRunner_SOURCES = dbconnectorTestRunner.cpp \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ databaseConnectorTest.cpp \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ databaseConnectorTest.h \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ sqliteDatabaseConnectorTest.cpp \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ sqliteDatabaseConnectorTest.h \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ $(top_srcdir)/src/lib/presageException.h \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ $(top_srcdir)/src/lib/core/presageException.cpp \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ $(top_srcdir)/src/lib/core/utility.h \ @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@ $(top_srcdir)/src/lib/core/utility.cpp # presageException files are included in sources since sqlite # database connector defines an exception that inherits from # presage base exception @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@dbconnectorTestRunner_CXXFLAGS = $(CPPUNIT_CFLAGS) @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@dbconnectorTestRunner_LDFLAGS = $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@dbconnectorTestRunner_LDADD = $(top_builddir)/src/lib/predictors/dbconnector/libdbconnector.la @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@dbconnectorTestRunner_CPPFLAGS = -I$(top_srcdir)/src/lib # Clean out files created during tests. # Required to make distcheck happy. @HAVE_CPPUNIT_TRUE@@USE_SQLITE_TRUE@DISTCLEANFILES = test.db all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lib/predictors/dbconnector/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/lib/predictors/dbconnector/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list dbconnectorTestRunner$(EXEEXT): $(dbconnectorTestRunner_OBJECTS) $(dbconnectorTestRunner_DEPENDENCIES) @rm -f dbconnectorTestRunner$(EXEEXT) $(dbconnectorTestRunner_LINK) $(dbconnectorTestRunner_OBJECTS) $(dbconnectorTestRunner_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbconnectorTestRunner-databaseConnectorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbconnectorTestRunner-dbconnectorTestRunner.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbconnectorTestRunner-presageException.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbconnectorTestRunner-sqliteDatabaseConnectorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbconnectorTestRunner-utility.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< dbconnectorTestRunner-dbconnectorTestRunner.o: dbconnectorTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-dbconnectorTestRunner.o -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-dbconnectorTestRunner.Tpo -c -o dbconnectorTestRunner-dbconnectorTestRunner.o `test -f 'dbconnectorTestRunner.cpp' || echo '$(srcdir)/'`dbconnectorTestRunner.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-dbconnectorTestRunner.Tpo $(DEPDIR)/dbconnectorTestRunner-dbconnectorTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dbconnectorTestRunner.cpp' object='dbconnectorTestRunner-dbconnectorTestRunner.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-dbconnectorTestRunner.o `test -f 'dbconnectorTestRunner.cpp' || echo '$(srcdir)/'`dbconnectorTestRunner.cpp dbconnectorTestRunner-dbconnectorTestRunner.obj: dbconnectorTestRunner.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-dbconnectorTestRunner.obj -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-dbconnectorTestRunner.Tpo -c -o dbconnectorTestRunner-dbconnectorTestRunner.obj `if test -f 'dbconnectorTestRunner.cpp'; then $(CYGPATH_W) 'dbconnectorTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/dbconnectorTestRunner.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-dbconnectorTestRunner.Tpo $(DEPDIR)/dbconnectorTestRunner-dbconnectorTestRunner.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dbconnectorTestRunner.cpp' object='dbconnectorTestRunner-dbconnectorTestRunner.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-dbconnectorTestRunner.obj `if test -f 'dbconnectorTestRunner.cpp'; then $(CYGPATH_W) 'dbconnectorTestRunner.cpp'; else $(CYGPATH_W) '$(srcdir)/dbconnectorTestRunner.cpp'; fi` dbconnectorTestRunner-databaseConnectorTest.o: databaseConnectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-databaseConnectorTest.o -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-databaseConnectorTest.Tpo -c -o dbconnectorTestRunner-databaseConnectorTest.o `test -f 'databaseConnectorTest.cpp' || echo '$(srcdir)/'`databaseConnectorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-databaseConnectorTest.Tpo $(DEPDIR)/dbconnectorTestRunner-databaseConnectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='databaseConnectorTest.cpp' object='dbconnectorTestRunner-databaseConnectorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-databaseConnectorTest.o `test -f 'databaseConnectorTest.cpp' || echo '$(srcdir)/'`databaseConnectorTest.cpp dbconnectorTestRunner-databaseConnectorTest.obj: databaseConnectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-databaseConnectorTest.obj -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-databaseConnectorTest.Tpo -c -o dbconnectorTestRunner-databaseConnectorTest.obj `if test -f 'databaseConnectorTest.cpp'; then $(CYGPATH_W) 'databaseConnectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/databaseConnectorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-databaseConnectorTest.Tpo $(DEPDIR)/dbconnectorTestRunner-databaseConnectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='databaseConnectorTest.cpp' object='dbconnectorTestRunner-databaseConnectorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-databaseConnectorTest.obj `if test -f 'databaseConnectorTest.cpp'; then $(CYGPATH_W) 'databaseConnectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/databaseConnectorTest.cpp'; fi` dbconnectorTestRunner-sqliteDatabaseConnectorTest.o: sqliteDatabaseConnectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-sqliteDatabaseConnectorTest.o -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-sqliteDatabaseConnectorTest.Tpo -c -o dbconnectorTestRunner-sqliteDatabaseConnectorTest.o `test -f 'sqliteDatabaseConnectorTest.cpp' || echo '$(srcdir)/'`sqliteDatabaseConnectorTest.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-sqliteDatabaseConnectorTest.Tpo $(DEPDIR)/dbconnectorTestRunner-sqliteDatabaseConnectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sqliteDatabaseConnectorTest.cpp' object='dbconnectorTestRunner-sqliteDatabaseConnectorTest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-sqliteDatabaseConnectorTest.o `test -f 'sqliteDatabaseConnectorTest.cpp' || echo '$(srcdir)/'`sqliteDatabaseConnectorTest.cpp dbconnectorTestRunner-sqliteDatabaseConnectorTest.obj: sqliteDatabaseConnectorTest.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-sqliteDatabaseConnectorTest.obj -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-sqliteDatabaseConnectorTest.Tpo -c -o dbconnectorTestRunner-sqliteDatabaseConnectorTest.obj `if test -f 'sqliteDatabaseConnectorTest.cpp'; then $(CYGPATH_W) 'sqliteDatabaseConnectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/sqliteDatabaseConnectorTest.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-sqliteDatabaseConnectorTest.Tpo $(DEPDIR)/dbconnectorTestRunner-sqliteDatabaseConnectorTest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sqliteDatabaseConnectorTest.cpp' object='dbconnectorTestRunner-sqliteDatabaseConnectorTest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-sqliteDatabaseConnectorTest.obj `if test -f 'sqliteDatabaseConnectorTest.cpp'; then $(CYGPATH_W) 'sqliteDatabaseConnectorTest.cpp'; else $(CYGPATH_W) '$(srcdir)/sqliteDatabaseConnectorTest.cpp'; fi` dbconnectorTestRunner-presageException.o: $(top_srcdir)/src/lib/core/presageException.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-presageException.o -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-presageException.Tpo -c -o dbconnectorTestRunner-presageException.o `test -f '$(top_srcdir)/src/lib/core/presageException.cpp' || echo '$(srcdir)/'`$(top_srcdir)/src/lib/core/presageException.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-presageException.Tpo $(DEPDIR)/dbconnectorTestRunner-presageException.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(top_srcdir)/src/lib/core/presageException.cpp' object='dbconnectorTestRunner-presageException.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-presageException.o `test -f '$(top_srcdir)/src/lib/core/presageException.cpp' || echo '$(srcdir)/'`$(top_srcdir)/src/lib/core/presageException.cpp dbconnectorTestRunner-presageException.obj: $(top_srcdir)/src/lib/core/presageException.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-presageException.obj -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-presageException.Tpo -c -o dbconnectorTestRunner-presageException.obj `if test -f '$(top_srcdir)/src/lib/core/presageException.cpp'; then $(CYGPATH_W) '$(top_srcdir)/src/lib/core/presageException.cpp'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/lib/core/presageException.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-presageException.Tpo $(DEPDIR)/dbconnectorTestRunner-presageException.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(top_srcdir)/src/lib/core/presageException.cpp' object='dbconnectorTestRunner-presageException.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-presageException.obj `if test -f '$(top_srcdir)/src/lib/core/presageException.cpp'; then $(CYGPATH_W) '$(top_srcdir)/src/lib/core/presageException.cpp'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/lib/core/presageException.cpp'; fi` dbconnectorTestRunner-utility.o: $(top_srcdir)/src/lib/core/utility.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-utility.o -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-utility.Tpo -c -o dbconnectorTestRunner-utility.o `test -f '$(top_srcdir)/src/lib/core/utility.cpp' || echo '$(srcdir)/'`$(top_srcdir)/src/lib/core/utility.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-utility.Tpo $(DEPDIR)/dbconnectorTestRunner-utility.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(top_srcdir)/src/lib/core/utility.cpp' object='dbconnectorTestRunner-utility.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-utility.o `test -f '$(top_srcdir)/src/lib/core/utility.cpp' || echo '$(srcdir)/'`$(top_srcdir)/src/lib/core/utility.cpp dbconnectorTestRunner-utility.obj: $(top_srcdir)/src/lib/core/utility.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -MT dbconnectorTestRunner-utility.obj -MD -MP -MF $(DEPDIR)/dbconnectorTestRunner-utility.Tpo -c -o dbconnectorTestRunner-utility.obj `if test -f '$(top_srcdir)/src/lib/core/utility.cpp'; then $(CYGPATH_W) '$(top_srcdir)/src/lib/core/utility.cpp'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/lib/core/utility.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/dbconnectorTestRunner-utility.Tpo $(DEPDIR)/dbconnectorTestRunner-utility.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(top_srcdir)/src/lib/core/utility.cpp' object='dbconnectorTestRunner-utility.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbconnectorTestRunner_CPPFLAGS) $(CPPFLAGS) $(dbconnectorTestRunner_CXXFLAGS) $(CXXFLAGS) -c -o dbconnectorTestRunner-utility.obj `if test -f '$(top_srcdir)/src/lib/core/utility.cpp'; then $(CYGPATH_W) '$(top_srcdir)/src/lib/core/utility.cpp'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/lib/core/utility.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ echo "$$grn$$dashes"; \ else \ echo "$$red$$dashes"; \ fi; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes$$std"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool ctags \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am # 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: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dbconnector/dbconnectorTestRunner.cpp�����������������������������0000644�0001750�0001750�00000002661�11737142176�023355� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> int main() { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest( registry.makeTest() ); bool success = runner.run(); return success ? 0 : 1; } �������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dbconnector/databaseConnectorTest.cpp�����������������������������0000644�0001750�0001750�00000016766�11737142176�023315� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "databaseConnectorTest.h" CPPUNIT_TEST_SUITE_REGISTRATION( DatabaseConnectorTest ); void DatabaseConnectorTest::setUp() { lastQuery = new std::string; databaseConnector = new DatabaseConnectorImpl(lastQuery); unigram = new Ngram; unigram->push_back("foo"); bigram = new Ngram; bigram->push_back("foo"); bigram->push_back("bar"); trigram = new Ngram; trigram->push_back("foo"); trigram->push_back("bar"); trigram->push_back("foobar"); } void DatabaseConnectorTest::tearDown() { delete databaseConnector; delete lastQuery; delete unigram; delete bigram; delete trigram; } void DatabaseConnectorTest::testCreateNgramTable() { std::cout << "DatabaseConnectorTest::testCreateNgramTable()" << std::endl; for (int i = 1; i < 4; i++) { databaseConnector->createNgramTable(i); } } void DatabaseConnectorTest::testGetNgramCount() { std::cout << "DatabaseConnectorTest::testGetNgramCount()" << std::endl; CPPUNIT_ASSERT_EQUAL( GLOBAL_MAGIC_NUMBER, databaseConnector->getNgramCount(*unigram) ); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT count FROM _1_gram WHERE word = 'foo';"), *lastQuery ); CPPUNIT_ASSERT_EQUAL( GLOBAL_MAGIC_NUMBER, databaseConnector->getNgramCount(*bigram) ); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT count FROM _2_gram WHERE word_1 = 'foo' AND word = 'bar';"), *lastQuery ); CPPUNIT_ASSERT_EQUAL( GLOBAL_MAGIC_NUMBER, databaseConnector->getNgramCount(*trigram) ); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT count FROM _3_gram WHERE word_2 = 'foo' AND word_1 = 'bar' AND word = 'foobar';"), *lastQuery ); } void DatabaseConnectorTest::assertCorrectMockNgramTable(NgramTable ngramTable) { CPPUNIT_ASSERT_EQUAL(size_t(3), ngramTable.size()); CPPUNIT_ASSERT(ngramTable[0][0] == "foo"); CPPUNIT_ASSERT(ngramTable[0][1] == "bar"); CPPUNIT_ASSERT(ngramTable[0][2] == "foobar"); CPPUNIT_ASSERT(ngramTable[0][3] == "3"); CPPUNIT_ASSERT(ngramTable[1][0] == "bar"); CPPUNIT_ASSERT(ngramTable[1][1] == "foo"); CPPUNIT_ASSERT(ngramTable[1][2] == "foobar"); CPPUNIT_ASSERT(ngramTable[1][3] == "33"); CPPUNIT_ASSERT(ngramTable[2][0] == "foobar"); CPPUNIT_ASSERT(ngramTable[2][1] == "bar"); CPPUNIT_ASSERT(ngramTable[2][2] == "foo"); CPPUNIT_ASSERT(ngramTable[2][3] == "333"); } void DatabaseConnectorTest::testGetNgramLikeTable() { std::cout << "DatabaseConnectorTest::testGetNgramLikeTable()" << std::endl; std::string* lastLikeQuery = new std::string(); DatabaseConnectorLikeImpl* databaseConnectorLike = new DatabaseConnectorLikeImpl(lastLikeQuery); assertCorrectMockNgramTable(databaseConnectorLike->getNgramLikeTable(*unigram)); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT word, count FROM _1_gram WHERE word LIKE 'foo%' ORDER BY count DESC;"), *lastLikeQuery ); databaseConnectorLike->getNgramLikeTable(*bigram); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT word_1, word, count FROM _2_gram WHERE word_1 = 'foo' AND word LIKE 'bar%' ORDER BY count DESC;"), *lastLikeQuery ); databaseConnectorLike->getNgramLikeTable(*trigram); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT word_2, word_1, word, count FROM _3_gram WHERE word_2 = 'foo' AND word_1 = 'bar' AND word LIKE 'foobar%' ORDER BY count DESC;"), *lastLikeQuery ); delete lastLikeQuery; delete databaseConnectorLike; } void DatabaseConnectorTest::testGetNgramLikeTableLimit() { std::cout << "DatabaseConnectorTest::testGetNgramLikeTableLimit()" << std::endl; std::string* lastLikeQuery = new std::string(); DatabaseConnectorLikeImpl* databaseConnectorLike = new DatabaseConnectorLikeImpl(lastLikeQuery); assertCorrectMockNgramTable(databaseConnectorLike->getNgramLikeTable(*unigram, GLOBAL_MAGIC_NUMBER)); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT word, count FROM _1_gram WHERE word LIKE 'foo%' ORDER BY count DESC LIMIT 1337;"), *lastLikeQuery ); databaseConnectorLike->getNgramLikeTable(*bigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT word_1, word, count FROM _2_gram WHERE word_1 = 'foo' AND word LIKE 'bar%' ORDER BY count DESC LIMIT 1337;"), *lastLikeQuery ); databaseConnectorLike->getNgramLikeTable(*trigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("SELECT word_2, word_1, word, count FROM _3_gram WHERE word_2 = 'foo' AND word_1 = 'bar' AND word LIKE 'foobar%' ORDER BY count DESC LIMIT 1337;"), *lastLikeQuery ); delete lastLikeQuery; delete databaseConnectorLike; } void DatabaseConnectorTest::testInsertNgram() { std::cout << "DatabaseConnectorTest::testInsertNgram()" << std::endl; databaseConnector->insertNgram(*unigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("INSERT INTO _1_gram VALUES('foo', 1337);"), *lastQuery ); databaseConnector->insertNgram(*bigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("INSERT INTO _2_gram VALUES('foo', 'bar', 1337);"), *lastQuery ); databaseConnector->insertNgram(*trigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("INSERT INTO _3_gram VALUES('foo', 'bar', 'foobar', 1337);"), *lastQuery ); } void DatabaseConnectorTest::testUpdateNgram() { std::cout << "DatabaseConnectorTest::testUpdateNgram()" << std::endl; databaseConnector->updateNgram(*unigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("UPDATE _1_gram SET count = 1337 WHERE word = 'foo';"), *lastQuery ); databaseConnector->updateNgram(*bigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("UPDATE _2_gram SET count = 1337 WHERE word_1 = 'foo' AND word = 'bar';"), *lastQuery ); databaseConnector->updateNgram(*trigram, GLOBAL_MAGIC_NUMBER); CPPUNIT_ASSERT_EQUAL( static_cast<std::string>("UPDATE _3_gram SET count = 1337 WHERE word_2 = 'foo' AND word_1 = 'bar' AND word = 'foobar';"), *lastQuery ); } void DatabaseConnectorTest::testRemoveNgram() { std::cout << "DatabaseConnectorTest::testRemoveNgram()" << std::endl; databaseConnector->removeNgram(*unigram); databaseConnector->removeNgram(*bigram); databaseConnector->removeNgram(*trigram); } //void DatabaseConnectorTest::testSanitizeString() //{ // // TODO //} ����������presage-0.8.8/test/lib/predictors/dbconnector/databaseConnectorTest.h�������������������������������0000644�0001750�0001750�00000012454�11763437013�022744� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_DATABASECONNECTORTEST #define PRESAGE_DATABASECONNECTORTEST #include <cppunit/extensions/HelperMacros.h> #include "predictors/dbconnector/databaseConnector.h" #include <iostream> #include <sstream> const int GLOBAL_MAGIC_NUMBER = 1337; //DatabaseConnectorTest::DatabaseConnectorImpl::MAGIC_NUMBER = GLOBAL_MAGIC_NUMBER; class DatabaseConnectorTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); // void testSanitizeString(); void testCreateNgramTable(); void testGetNgramCount(); void testGetNgramLikeTable(); void testGetNgramLikeTableLimit(); void testInsertNgram(); void testUpdateNgram(); void testRemoveNgram(); /** Mock DatabaseConnector implementation object. * * The virtual executeSql() method stores the SQL query string * into a pointer to a string that is accessible to * DatabaseConnectorTest class. This string is compared against a * benchmarked SQL string. * * The same magic number is also always returned as a count. * */ class DatabaseConnectorImpl : public DatabaseConnector { public: DatabaseConnectorImpl(std::string* query) : DatabaseConnector("", 0, false), m_query(query), MAGIC_NUMBER(GLOBAL_MAGIC_NUMBER) {} virtual ~DatabaseConnectorImpl() {} virtual void openDatabase() {} virtual void closeDatabase() {} /** Stores SQL query in m_query data member. * * This fakes an SQL query execution. Useful to test that the * correct SQL query are generated. */ virtual NgramTable executeSql(const std::string query) const { std::cout << "[query] " << query << std::endl; *m_query = query; std::stringstream ss; ss << MAGIC_NUMBER; Ngram ngram; ngram.push_back(ss.str()); NgramTable ngramTable; ngramTable.push_back(ngram); return ngramTable; } private: std::string* const m_query; int MAGIC_NUMBER; }; /** Mock DatabaseConnector implementation object for getNgramCountLike(). * * The virtual executeSql() method stores the SQL query string * into a pointer to a string that is accessible to * DatabaseConnectorTest class. This string is compared against a * benchmarked SQL string. * * An mock ngram is returned. * */ class DatabaseConnectorLikeImpl : public DatabaseConnectorImpl { public: DatabaseConnectorLikeImpl(std::string* query) : DatabaseConnectorImpl(query) {} ~DatabaseConnectorLikeImpl() {} virtual void openDatabase() {} virtual void closeDatabase() {} /** Stores SQL query in m_query data member. * * This fakes an SQL query execution. Useful to test that the * correct SQL query are generated. */ virtual NgramTable executeSql(const std::string query) const { DatabaseConnectorImpl::executeSql(query); NgramTable ngramTable; Ngram* ngram = new Ngram(); ngram->push_back("foo"); ngram->push_back("bar"); ngram->push_back("foobar"); ngram->push_back("3"); ngramTable.push_back(*ngram); delete ngram; ngram = new Ngram(); ngram->push_back("bar"); ngram->push_back("foo"); ngram->push_back("foobar"); ngram->push_back("33"); ngramTable.push_back(*ngram); delete ngram; ngram = new Ngram(); ngram->push_back("foobar"); ngram->push_back("bar"); ngram->push_back("foo"); ngram->push_back("333"); ngramTable.push_back(*ngram); delete ngram; return ngramTable; } private: }; private: void assertCorrectMockNgramTable(NgramTable ngramcount); DatabaseConnector* databaseConnector; std::string* lastQuery; Ngram* unigram; Ngram* bigram; Ngram* trigram; CPPUNIT_TEST_SUITE( DatabaseConnectorTest ); // CPPUNIT_TEST( testSanitizeString ); CPPUNIT_TEST( testCreateNgramTable ); CPPUNIT_TEST( testGetNgramCount ); CPPUNIT_TEST( testGetNgramLikeTable ); CPPUNIT_TEST( testGetNgramLikeTableLimit ); CPPUNIT_TEST( testInsertNgram ); CPPUNIT_TEST( testUpdateNgram ); CPPUNIT_TEST( testRemoveNgram ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_DATABASECONNECTORTEST ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/predictors/dejavuPredictorTest.h���������������������������������������������0000644�0001750�0001750�00000003720�11743227551�020155� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_DEJAVUPREDICTORTEST #define PRESAGE_DEJAVUPREDICTORTEST #include <cppunit/extensions/HelperMacros.h> #include <predictors/dejavuPredictor.h> /** Test DejavuPredictor. * */ class DejavuPredictorTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testPredict(); private: Configuration* config; std::stringstream* stream; PresageCallback* callback; ContextTracker* ct; PredictorRegistry* predictorRegistry; static const int SIZE; static const char* NAME; static const char* PREDICTOR; static const char* LOGGER; static const char* TRIGGER; static const char* MEMORY; static const char* MEMORY_FILENAME; CPPUNIT_TEST_SUITE( DejavuPredictorTest ); CPPUNIT_TEST( testPredict ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_DEJAVUPREDICTORTEST ������������������������������������������������presage-0.8.8/test/lib/predictors/newSmoothedNgramPredictorTest.h�����������������������������������0000644�0001750�0001750�00000004436�11763437013�022163� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_NEWSMOOTHEDNGRAMPREDICTORTEST #define PRESAGE_NEWSMOOTHEDNGRAMPREDICTORTEST #include <cppunit/extensions/HelperMacros.h> #include <predictors/smoothedNgramPredictor.h> /** Test SmoothedNgramPredictor. * * this test doesn't follow the pattern of test * SmoothedNgramPredictorTest: i.e. it doesn't reuse the infrastructure * provided by the predictor test fixture, because that infrastructure * was not designed to accomodate predictors that are able to learn. * */ class NewSmoothedNgramPredictorTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); void testLearning(); void testFilter(); private: Configuration* config; std::stringstream* stream; PresageCallback* callback; ContextTracker* ct; PredictorRegistry* predictorRegistry; Predictor* predictor; static const char* DATABASE; static const size_t CARDINALITY; static const bool READ_WRITE_MODE; static const int SIZE; CPPUNIT_TEST_SUITE( NewSmoothedNgramPredictorTest ); CPPUNIT_TEST( testLearning ); CPPUNIT_TEST( testFilter ); CPPUNIT_TEST_SUITE_END(); }; #endif // PRESAGE_NEWSMOOTHEDNGRAMPREDICTORTEST ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/common/����������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�013215� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/common/testStringSuite.h�����������������������������������������������������0000644�0001750�0001750�00000005414�11737142176�016461� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef PRESAGE_TESTSTRINGSUITE #define PRESAGE_TESTSTRINGSUITE #include <string> #include <vector> /** Contains a set of <string, tokens> pairs used in tokenizer tests. * * Provides accessor methods and pseudo iterators to reduce the amount * of code needed to use all the <string, tokens> pairs in the * tozenizer unit tests. * * This a typical usage: * * while (stringSuite->hasMoreTestStrings()) { * std::stringstream ss; * assert(stringSuite->currentTestString() != 0); * ss << stringSuite->currentTestString()->getstr(); * ForwardTokenizer tok(ss, blankspaces, separators); * std::string str; * for (i = 0; tok.hasMoreTokens(); i++) { * str = stringSuite->currentTestString()->token(i); * CPPUNIT_ASSERT_EQUAL( str, tok.nextToken() ); * } * CPPUNIT_ASSERT_EQUAL( stringSuite->currentTestString()->tokencount(), * i ); * * stringSuite->nextTestString(); * } * */ class TestStringSuite { public: class TestString { public: TestString(std::string, std::vector<std::string>); ~TestString(); const std::string getstr () const; const int tokencount () const; const std::string token(const size_t index) const; private: std::string m_string; std::vector<std::string> m_tokens; }; TestStringSuite(); ~TestStringSuite(); bool hasMoreTestStrings() const; TestString* currentTestString(); TestString* nextTestString(); private: std::vector<TestString*> testStrings; std::vector<TestString*>::const_iterator iter; }; #endif // PRESAGE_TESTSTRINGSUITE ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/common/Makefile.am�����������������������������������������������������������0000644�0001750�0001750�00000002240�11763437013�015152� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in check_LTLIBRARIES = \ libcommon.la libcommon_la_SOURCES = \ testStringSuite.cpp \ testStringSuite.h \ stringstreamPresageCallback.cpp \ stringstreamPresageCallback.h AM_CPPFLAGS = -I$(top_srcdir)/src/lib ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/common/stringstreamPresageCallback.h�����������������������������������������0000644�0001750�0001750�00000003572�11737142176�020752� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #ifndef STRINGSTREAM_PRESAGE_CALLBACK #define STRINGSTREAM_PRESAGE_CALLBACK #include "presageCallback.h" /** Stringstream based callback implementation. * * This concrete callback object implementation accesses a * caller-provided std::stringstream object. It is provided here as an * example concrete implementation. * */ class StringstreamPresageCallback : public PresageCallback { public: StringstreamPresageCallback(std::stringstream& stream) : m_stream(stream) { } ~StringstreamPresageCallback() { } std::string get_past_stream() const { if (&m_stream) { return m_stream.str(); } else { return m_empty; } } std::string get_future_stream() const { return m_empty; } private: std::stringstream& m_stream; const std::string m_empty; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/common/Makefile.in�����������������������������������������������������������0000644�0001750�0001750�00000040623�11763440355�015175� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = test/lib/common DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = libcommon_la_LIBADD = am_libcommon_la_OBJECTS = testStringSuite.lo \ stringstreamPresageCallback.lo libcommon_la_OBJECTS = $(am_libcommon_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libcommon_la_SOURCES) DIST_SOURCES = $(libcommon_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ check_LTLIBRARIES = \ libcommon.la libcommon_la_SOURCES = \ testStringSuite.cpp \ testStringSuite.h \ stringstreamPresageCallback.cpp \ stringstreamPresageCallback.h AM_CPPFLAGS = -I$(top_srcdir)/src/lib all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/lib/common/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu test/lib/common/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkLTLIBRARIES: -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES) @list='$(check_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(CXXLINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringstreamPresageCallback.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testStringSuite.Plo@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkLTLIBRARIES clean-generic clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean \ clean-checkLTLIBRARIES clean-generic clean-libtool ctags \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am # 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: �������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/common/stringstreamPresageCallback.cpp���������������������������������������0000644�0001750�0001750�00000002247�11737142176�021303� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "stringstreamPresageCallback.h" // intentionally empty ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/test/lib/common/testStringSuite.cpp���������������������������������������������������0000644�0001750�0001750�00000011050�11737142176�017005� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "testStringSuite.h" #include <iostream> #include <assert.h> //// // TestString TestStringSuite::TestString::TestString( std::string str, std::vector<std::string> tokens ) : m_string (str), m_tokens (tokens) {} TestStringSuite::TestString::~TestString() {} const std::string TestStringSuite::TestString::getstr() const { // DEBUG //std::cerr << "TestString::str() called" << std::endl; //std::cerr << "Returning string: " << m_string << std::endl; return m_string; } const int TestStringSuite::TestString::tokencount() const { return m_tokens.size(); } const std::string TestStringSuite::TestString::token(const size_t index) const { assert(index < m_tokens.size()); return m_tokens[index]; } //// // TestStringSuite TestStringSuite::TestStringSuite() { std::string str; std::vector<std::string> tokens; str = "foo bar. Foo, bar! Foo bar... Foobar"; tokens.push_back("foo"); tokens.push_back("bar"); tokens.push_back("Foo"); tokens.push_back("bar"); tokens.push_back("Foo"); tokens.push_back("bar"); tokens.push_back("Foobar"); testStrings.push_back(new TestString(str, tokens)); tokens.clear(); str = "foo bar. Foo!!"; tokens.push_back("foo"); tokens.push_back("bar"); tokens.push_back("Foo"); tokens.push_back(""); testStrings.push_back(new TestString(str, tokens)); tokens.clear(); str = "FoO.\n \nBaR. fOoBaR\n."; tokens.push_back("FoO"); tokens.push_back("BaR"); tokens.push_back("fOoBaR"); tokens.push_back(""); testStrings.push_back(new TestString(str, tokens)); tokens.clear(); str = "foo bar foobar "; tokens.push_back("foo"); tokens.push_back("bar"); tokens.push_back("foobar"); tokens.push_back(""); testStrings.push_back(new TestString(str, tokens)); tokens.clear(); str = "frobnik "; tokens.push_back("frobnik"); tokens.push_back(""); testStrings.push_back(new TestString(str, tokens)); //// REVISIT: // These two following strings will cause tests to fail due to the // blankspace at the beginning whitespace. // Need to fix ReverseTokenizer! // // tokens.clear(); // str = " foo bar foobar"; // tokens.push_back("foo"); // tokens.push_back("bar"); // tokens.push_back("foobar"); // testStrings.push_back(new TestString(str, tokens)); // // tokens.clear(); // str = " foo bar foobar "; // tokens.push_back("foo"); // tokens.push_back("bar"); // tokens.push_back("foobar"); // tokens.push_back(""); // testStrings.push_back(new TestString(str, tokens)); //// // DEBUG //std::cerr << "TestStringSuite::TestStringSuite()" << std::endl; //for (std::vector<TestString*>::iterator it = testStrings.begin(); // it != testStrings.end(); // it++) { // std::cerr << (*it)->getstr() << std::endl; //} iter = testStrings.begin(); } TestStringSuite::~TestStringSuite() { for (iter = testStrings.begin(); iter != testStrings.end(); iter++) { delete *iter; } } bool TestStringSuite::hasMoreTestStrings() const { return ( iter == testStrings.end() ? false : true ); } TestStringSuite::TestString* TestStringSuite::nextTestString() { return *(iter++); } TestStringSuite::TestString* TestStringSuite::currentTestString() { // DEBUG //std::cerr << "Entered currentTestString()" << std::endl; //std::cerr << "Returning pointer: " << *iter << std::endl; return *iter; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/COPYING�������������������������������������������������������������������������������0000644�0001750�0001750�00000043110�11737142176�011141� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 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. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/����������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11764714756�012212� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/the_picture_of_dorian_gray.txt����������������������������������������������0000644�0001750�0001750�00001562623�11737142176�020256� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������*Project Gutenberg's The Picture of Dorian Gray by Oscar Wilde* *** Etexts From The Original Internet Information Providers *** Please take a look at the important information in this header. We encourage you to keep this file on your own disk, keeping an electronic path open for the next readers. Do not remove this. **Welcome To The World of Free Plain Vanilla Electronic Texts** **Etexts Readable By Both Humans and By Computers, Since 1971** *These Etexts Prepared By Hundreds of Volunteers and Donations* Information on contacting Project Gutenberg to get Etexts, and further information is included below. We need your donations. The Picture of Dorian Gray by Oscar Wilde October, 1994 Etext #174 [Date last updated: April 11, 2006] *Project Gutenberg's The Picture of Dorian Gray by Oscar Wilde* *****This file should be named dgray10.txt or dgray10.zip***** Corrected EDITIONS of our etexts get a new NUMBER, dgray11.txt. VERSIONS based on separate sources get new LETTER, dgray10a.txt. This etext was created by Judith Boss, Omaha, Nebraska. The equipment: an IBM-compatible 486/33, a Hewlett-Packard ScanJet IIc flatbed scanner, and Calera Recognition Systems' M/Series Professional OCR software and RISC Accelerator Board. Information about Project Gutenberg (one page) We produce about one million dollars for each hour we work. One hundred hours is a conservative estimate for how long it we take to get any etext selected, entered, proofread, edited, copyright searched and analyzed, the copyright letters written, etc. This projected audience is one hundred million readers. If our value per text is nominally estimated at one dollar, then we produce a million dollars per hour; next year we will have to do four text files per month, thus upping our productivity to two million/hr. The Goal of Project Gutenberg is to Give Away One Trillion Etext Files by the December 31, 2001. [10,000 x 100,000,000=Trillion] This is ten thousand titles each to one hundred million readers. We need your donations more than ever! All donations should be made to "Project Gutenberg/IBC", and are tax deductible to the extent allowable by law ("IBC" is Illinois Benedictine College). (Subscriptions to our paper newsletter go to IBC, too) For these and other matters, please mail to: David Turner, Project Gutenberg Illinois Benedictine College 5700 College Road Lisle, IL 60532-0900 Email requests to: Internet: chipmonk@eagle.ibc.edu (David Turner) Compuserve: chipmonk@eagle.ibc.edu (David Turner) Attmail: internet!chipmonk@eagle.ibc.edu (David Turner) MCImail: (David Turner) ADDRESS TYPE: MCI / EMS: INTERNET / MBX:chipmonk@eagle.ibc.edu We would prefer to send you this information by email (Internet, Bitnet, Compuserve, ATTMAIL or MCImail). ****** If you have an FTP program (or emulator), please: FTP directly to the Project Gutenberg archives: ftp mrcnext.cso.uiuc.edu login: anonymous password: your@login cd etext/etext91 or cd etext92 [for new books] [now also cd etext/etext92] or cd etext/articles [get suggest gut for more information] dir [to see files] get or mget [to get files. . .set bin for zip files] GET INDEX and AAINDEX for a list of books and GET NEW GUT for general information and MGET GUT* for newsletters. **Information prepared by the Project Gutenberg legal advisor** (Three Pages) ****START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START**** Why is this "Small Print!" statement here? You know: lawyers. They tell us you might sue us if there is something wrong with your copy of this etext, even if you got it for free from someone other than us, and even if what's wrong is not our fault. So, among other things, this "Small Print!" statement disclaims most of our liability to you. It also tells you how you can distribute copies of this etext if you want to. *BEFORE!* YOU USE OR READ THIS ETEXT By using or reading any part of this PROJECT GUTENBERG-tm etext, you indicate that you understand, agree to and accept this "Small Print!" statement. If you do not, you can receive a refund of the money (if any) you paid for this etext by sending a request within 30 days of receiving it to the person you got it from. If you received this etext on a physical medium (such as a disk), you must return it with your request. ABOUT PROJECT GUTENBERG-TM ETEXTS This PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG-tm etexts, is a "public domain" work distributed by Professor Michael S. Hart through the Project Gutenberg Association (the "Project"). Among other things, this means that no one owns a United States copyright on or for this work, so the Project (and you!) can copy and distribute it in the United States without permission and without paying copyright royalties. Special rules, set forth below, apply if you wish to copy and distribute this etext under the Project's "PROJECT GUTENBERG" trademark. To create these etexts, the Project expends considerable efforts to identify, transcribe and proofread public domain works. Despite these efforts, the Project's etexts and any medium they may be on may contain "Defects". Among other things, Defects may take the form of incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or damaged disk or other etext medium, a computer virus, or computer codes that damage or cannot be read by your equipment. DISCLAIMER But for the "Right of Replacement or Refund" described below, [1] the Project (and any other party you may receive this etext from as a PROJECT GUTENBERG-tm etext) disclaims all liability to you for damages, costs and expenses, including legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT, INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. If you discover a Defect in this etext within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending an explanatory note within that time to the person you received it from. If you received it on a physical medium, you must return it with your note, and such person may choose to alternatively give you a replacement copy. If you received it electronically, such person may choose to alternatively give you a second opportunity to receive it electronically. THIS ETEXT IS OTHERWISE PROVIDED TO YOU "AS-IS". NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS TO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimers of implied warranties or the exclusion or limitation of consequential damages, so the above disclaimers and exclusions may not apply to you, and you may have other legal rights. INDEMNITY You will indemnify and hold the Project, its directors, officers, members and agents harmless from all liability, cost and expense, including legal fees, that arise from any distribution of this etext for which you are responsible, and from [1] any alteration, modification or addition to the etext for which you are responsible, or [2] any Defect. DISTRIBUTION UNDER "PROJECT GUTENBERG-tm" You may distribute copies of this etext electronically, or by disk, book or any other medium if you either delete this "Small Print!" and all other references to Project Gutenberg, or: [1] Only give exact copies of it. Among other things, this re- quires that you do not remove, alter or modify the etext or this "small print!" statement. You may however, if you wish, distribute this etext in machine readable binary, compressed, mark-up, or proprietary form, including any form resulting from conversion by word processing or hyper- text software, but only so long as *EITHER*: [*] The etext, when displayed, is clearly readable. We consider an etext *not* clearly readable if it contains characters other than those intended by the author of the work, although tilde (~), asterisk (*) and underline (_) characters may be used to convey punctuation intended by the author, and additional characters may be used to indicate hypertext links. [*] The etext may be readily converted by the reader at no expense into plain ASCII, EBCDIC or equivalent form by the program that displays the etext (as is the case, for instance, with most word processors). [*] You provide, or agree to also provide on request at no additional cost, fee or expense, a copy of the etext in its original plain ASCII form (or in EBCDIC or other equivalent proprietary form). [2] Honor the etext refund and replacement provisions of this "Small Print!" statement. [3] Pay a trademark license fee of 20% (twenty percent) of the net profits you derive from distributing this etext under the trademark, determined in accordance with generally accepted accounting practices. The license fee: [*] Is required only if you derive such profits. In distributing under our trademark, you incur no obligation to charge money or earn profits for your distribution. [*] Shall be paid to "Project Gutenberg Association / Illinois Benedictine College" (or to such other person as the Project Gutenberg Association may direct) within the 60 days following each date you prepare (or were legally required to prepare) your year-end tax return with respect to your income for that year. WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO? The Project gratefully accepts contributions in money, time, scanning machines, OCR software, public domain etexts, royalty free copyright licenses, and every other sort of contribution you can think of. Money should be paid to "Project Gutenberg Association / Illinois Benedictine College". WRITE TO US! We can be reached at: Project Gutenberg Director of Communications (PGDIRCOM) Internet: pgdircom@vmd.cso.uiuc.edu Bitnet: pgdircom@uiucvmd CompuServe: >internet:pgdircom@.vmd.cso.uiuc.edu Attmail: internet!vmd.cso.uiuc.edu!pgdircom Drafted by CHARLES B. KRAMER, Attorney CompuServe: 72600,2026 Internet: 72600.2026@compuserve.com Tel: (212) 254-5093 *END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.07.02.92*END* The Picture of Dorian Gray by Oscar Wilde THE PREFACE The artist is the creator of beautiful things. To reveal art and conceal the artist is art's aim. The critic is he who can translate into another manner or a new material his impression of beautiful things. The highest as the lowest form of criticism is a mode of autobiography. Those who find ugly meanings in beautiful things are corrupt without being charming. This is a fault. Those who find beautiful meanings in beautiful things are the cultivated. For these there is hope. They are the elect to whom beautiful things mean only beauty. There is no such thing as a moral or an immoral book. Books are well written, or badly written. That is all. The nineteenth century dislike of realism is the rage of Caliban seeing his own face in a glass. The nineteenth century dislike of romanticism is the rage of Caliban not seeing his own face in a glass. The moral life of man forms part of the subject-matter of the artist, but the morality of art consists in the perfect use of an imperfect medium. No artist desires to prove anything. Even things that are true can be proved. No artist has ethical sympathies. An ethical sympathy in an artist is an unpardonable mannerism of style. No artist is ever morbid. The artist can express everything. Thought and language are to the artist instruments of an art. Vice and virtue are to the artist materials for an art. From the point of view of form, the type of all the arts is the art of the musician. From the point of view of feeling, the actor's craft is the type. All art is at once surface and symbol. Those who go beneath the surface do so at their peril. Those who read the symbol do so at their peril. It is the spectator, and not life, that art really mirrors. Diversity of opinion about a work of art shows that the work is new, complex, and vital. When critics disagree, the artist is in accord with himself. We can forgive a man for making a useful thing as long as he does not admire it. The only excuse for making a useless thing is that one admires it intensely. All art is quite useless. OSCAR WILDE CHAPTER 1 The studio was filled with the rich odour of roses, and when the light summer wind stirred amidst the trees of the garden, there came through the open door the heavy scent of the lilac, or the more delicate perfume of the pink-flowering thorn. From the corner of the divan of Persian saddle-bags on which he was lying, smoking, as was his custom, innumerable cigarettes, Lord Henry Wotton could just catch the gleam of the honey-sweet and honey-coloured blossoms of a laburnum, whose tremulous branches seemed hardly able to bear the burden of a beauty so flamelike as theirs; and now and then the fantastic shadows of birds in flight flitted across the long tussore-silk curtains that were stretched in front of the huge window, producing a kind of momentary Japanese effect, and making him think of those pallid, jade-faced painters of Tokyo who, through the medium of an art that is necessarily immobile, seek to convey the sense of swiftness and motion. The sullen murmur of the bees shouldering their way through the long unmown grass, or circling with monotonous insistence round the dusty gilt horns of the straggling woodbine, seemed to make the stillness more oppressive. The dim roar of London was like the bourdon note of a distant organ. In the centre of the room, clamped to an upright easel, stood the full-length portrait of a young man of extraordinary personal beauty, and in front of it, some little distance away, was sitting the artist himself, Basil Hallward, whose sudden disappearance some years ago caused, at the time, such public excitement and gave rise to so many strange conjectures. As the painter looked at the gracious and comely form he had so skilfully mirrored in his art, a smile of pleasure passed across his face, and seemed about to linger there. But he suddenly started up, and closing his eyes, placed his fingers upon the lids, as though he sought to imprison within his brain some curious dream from which he feared he might awake. "It is your best work, Basil, the best thing you have ever done," said Lord Henry languidly. "You must certainly send it next year to the Grosvenor. The Academy is too large and too vulgar. Whenever I have gone there, there have been either so many people that I have not been able to see the pictures, which was dreadful, or so many pictures that I have not been able to see the people, which was worse. The Grosvenor is really the only place." "I don't think I shall send it anywhere," he answered, tossing his head back in that odd way that used to make his friends laugh at him at Oxford. "No, I won't send it anywhere." Lord Henry elevated his eyebrows and looked at him in amazement through the thin blue wreaths of smoke that curled up in such fanciful whorls from his heavy, opium-tainted cigarette. "Not send it anywhere? My dear fellow, why? Have you any reason? What odd chaps you painters are! You do anything in the world to gain a reputation. As soon as you have one, you seem to want to throw it away. It is silly of you, for there is only one thing in the world worse than being talked about, and that is not being talked about. A portrait like this would set you far above all the young men in England, and make the old men quite jealous, if old men are ever capable of any emotion." "I know you will laugh at me," he replied, "but I really can't exhibit it. I have put too much of myself into it." Lord Henry stretched himself out on the divan and laughed. "Yes, I knew you would; but it is quite true, all the same." "Too much of yourself in it! Upon my word, Basil, I didn't know you were so vain; and I really can't see any resemblance between you, with your rugged strong face and your coal-black hair, and this young Adonis, who looks as if he was made out of ivory and rose-leaves. Why, my dear Basil, he is a Narcissus, and you-- well, of course you have an intellectual expression and all that. But beauty, real beauty, ends where an intellectual expression begins. Intellect is in itself a mode of exaggeration, and destroys the harmony of any face. The moment one sits down to think, one becomes all nose, or all forehead, or something horrid. Look at the successful men in any of the learned professions. How perfectly hideous they are! Except, of course, in the Church. But then in the Church they don't think. A bishop keeps on saying at the age of eighty what he was told to say when he was a boy of eighteen, and as a natural consequence he always looks absolutely delightful. Your mysterious young friend, whose name you have never told me, but whose picture really fascinates me, never thinks. I feel quite sure of that. He is some brainless beautiful creature who should be always here in winter when we have no flowers to look at, and always here in summer when we want something to chill our intelligence. Don't flatter yourself, Basil: you are not in the least like him." "You don't understand me, Harry," answered the artist. "Of course I am not like him. I know that perfectly well. Indeed, I should be sorry to look like him. You shrug your shoulders? I am telling you the truth. There is a fatality about all physical and intellectual distinction, the sort of fatality that seems to dog through history the faltering steps of kings. It is better not to be different from one's fellows. The ugly and the stupid have the best of it in this world. They can sit at their ease and gape at the play. If they know nothing of victory, they are at least spared the knowledge of defeat. They live as we all should live--undisturbed, indifferent, and without disquiet. They neither bring ruin upon others, nor ever receive it from alien hands. Your rank and wealth, Harry; my brains, such as they are--my art, whatever it may be worth; Dorian Gray's good looks--we shall all suffer for what the gods have given us, suffer terribly." "Dorian Gray? Is that his name?" asked Lord Henry, walking across the studio towards Basil Hallward. "Yes, that is his name. I didn't intend to tell it to you." "But why not?" "Oh, I can't explain. When I like people immensely, I never tell their names to any one. It is like surrendering a part of them. I have grown to love secrecy. It seems to be the one thing that can make modern life mysterious or marvellous to us. The commonest thing is delightful if one only hides it. When I leave town now I never tell my people where I am going. If I did, I would lose all my pleasure. It is a silly habit, I dare say, but somehow it seems to bring a great deal of romance into one's life. I suppose you think me awfully foolish about it?" "Not at all," answered Lord Henry, "not at all, my dear Basil. You seem to forget that I am married, and the one charm of marriage is that it makes a life of deception absolutely necessary for both parties. I never know where my wife is, and my wife never knows what I am doing. When we meet--we do meet occasionally, when we dine out together, or go down to the Duke's--we tell each other the most absurd stories with the most serious faces. My wife is very good at it--much better, in fact, than I am. She never gets confused over her dates, and I always do. But when she does find me out, she makes no row at all. I sometimes wish she would; but she merely laughs at me." "I hate the way you talk about your married life, Harry," said Basil Hallward, strolling towards the door that led into the garden. "I believe that you are really a very good husband, but that you are thoroughly ashamed of your own virtues. You are an extraordinary fellow. You never say a moral thing, and you never do a wrong thing. Your cynicism is simply a pose." "Being natural is simply a pose, and the most irritating pose I know," cried Lord Henry, laughing; and the two young men went out into the garden together and ensconced themselves on a long bamboo seat that stood in the shade of a tall laurel bush. The sunlight slipped over the polished leaves. In the grass, white daisies were tremulous. After a pause, Lord Henry pulled out his watch. "I am afraid I must be going, Basil," he murmured, "and before I go, I insist on your answering a question I put to you some time ago." "What is that?" said the painter, keeping his eyes fixed on the ground. "You know quite well." "I do not, Harry." "Well, I will tell you what it is. I want you to explain to me why you won't exhibit Dorian Gray's picture. I want the real reason." "I told you the real reason." "No, you did not. You said it was because there was too much of yourself in it. Now, that is childish." "Harry," said Basil Hallward, looking him straight in the face, "every portrait that is painted with feeling is a portrait of the artist, not of the sitter. The sitter is merely the accident, the occasion. It is not he who is revealed by the painter; it is rather the painter who, on the coloured canvas, reveals himself. The reason I will not exhibit this picture is that I am afraid that I have shown in it the secret of my own soul." Lord Henry laughed. "And what is that?" he asked. "I will tell you," said Hallward; but an expression of perplexity came over his face. "I am all expectation, Basil," continued his companion, glancing at him. "Oh, there is really very little to tell, Harry," answered the painter; "and I am afraid you will hardly understand it. Perhaps you will hardly believe it." Lord Henry smiled, and leaning down, plucked a pink-petalled daisy from the grass and examined it. "I am quite sure I shall understand it," he replied, gazing intently at the little golden, white-feathered disk, "and as for believing things, I can believe anything, provided that it is quite incredible." The wind shook some blossoms from the trees, and the heavy lilac-blooms, with their clustering stars, moved to and fro in the languid air. A grasshopper began to chirrup by the wall, and like a blue thread a long thin dragon-fly floated past on its brown gauze wings. Lord Henry felt as if he could hear Basil Hallward's heart beating, and wondered what was coming. "The story is simply this," said the painter after some time. "Two months ago I went to a crush at Lady Brandon's. You know we poor artists have to show ourselves in society from time to time, just to remind the public that we are not savages. With an evening coat and a white tie, as you told me once, anybody, even a stock-broker, can gain a reputation for being civilized. Well, after I had been in the room about ten minutes, talking to huge overdressed dowagers and tedious academicians, I suddenly became conscious that some one was looking at me. I turned half-way round and saw Dorian Gray for the first time. When our eyes met, I felt that I was growing pale. A curious sensation of terror came over me. I knew that I had come face to face with some one whose mere personality was so fascinating that, if I allowed it to do so, it would absorb my whole nature, my whole soul, my very art itself. I did not want any external influence in my life. You know yourself, Harry, how independent I am by nature. I have always been my own master; had at least always been so, till I met Dorian Gray. Then--but I don't know how to explain it to you. Something seemed to tell me that I was on the verge of a terrible crisis in my life. I had a strange feeling that fate had in store for me exquisite joys and exquisite sorrows. I grew afraid and turned to quit the room. It was not conscience that made me do so: it was a sort of cowardice. I take no credit to myself for trying to escape." "Conscience and cowardice are really the same things, Basil. Conscience is the trade-name of the firm. That is all." "I don't believe that, Harry, and I don't believe you do either. However, whatever was my motive--and it may have been pride, for I used to be very proud--I certainly struggled to the door. There, of course, I stumbled against Lady Brandon. 'You are not going to run away so soon, Mr. Hallward?' she screamed out. You know her curiously shrill voice?" "Yes; she is a peacock in everything but beauty," said Lord Henry, pulling the daisy to bits with his long nervous fingers. "I could not get rid of her. She brought me up to royalties, and people with stars and garters, and elderly ladies with gigantic tiaras and parrot noses. She spoke of me as her dearest friend. I had only met her once before, but she took it into her head to lionize me. I believe some picture of mine had made a great success at the time, at least had been chattered about in the penny newspapers, which is the nineteenth-century standard of immortality. Suddenly I found myself face to face with the young man whose personality had so strangely stirred me. We were quite close, almost touching. Our eyes met again. It was reckless of me, but I asked Lady Brandon to introduce me to him. Perhaps it was not so reckless, after all. It was simply inevitable. We would have spoken to each other without any introduction. I am sure of that. Dorian told me so afterwards. He, too, felt that we were destined to know each other." "And how did Lady Brandon describe this wonderful young man?" asked his companion. "I know she goes in for giving a rapid precis of all her guests. I remember her bringing me up to a truculent and red-faced old gentleman covered all over with orders and ribbons, and hissing into my ear, in a tragic whisper which must have been perfectly audible to everybody in the room, the most astounding details. I simply fled. I like to find out people for myself. But Lady Brandon treats her guests exactly as an auctioneer treats his goods. She either explains them entirely away, or tells one everything about them except what one wants to know." "Poor Lady Brandon! You are hard on her, Harry!" said Hallward listlessly. "My dear fellow, she tried to found a salon, and only succeeded in opening a restaurant. How could I admire her? But tell me, what did she say about Mr. Dorian Gray?" "Oh, something like, 'Charming boy--poor dear mother and I absolutely inseparable. Quite forget what he does--afraid he-- doesn't do anything--oh, yes, plays the piano--or is it the violin, dear Mr. Gray?' Neither of us could help laughing, and we became friends at once." "Laughter is not at all a bad beginning for a friendship, and it is far the best ending for one," said the young lord, plucking another daisy. Hallward shook his head. "You don't understand what friendship is, Harry," he murmured--"or what enmity is, for that matter. You like every one; that is to say, you are indifferent to every one." "How horribly unjust of you!" cried Lord Henry, tilting his hat back and looking up at the little clouds that, like ravelled skeins of glossy white silk, were drifting across the hollowed turquoise of the summer sky. "Yes; horribly unjust of you. I make a great difference between people. I choose my friends for their good looks, my acquaintances for their good characters, and my enemies for their good intellects. A man cannot be too careful in the choice of his enemies. I have not got one who is a fool. They are all men of some intellectual power, and consequently they all appreciate me. Is that very vain of me? I think it is rather vain." "I should think it was, Harry. But according to your category I must be merely an acquaintance." "My dear old Basil, you are much more than an acquaintance." "And much less than a friend. A sort of brother, I suppose?" "Oh, brothers! I don't care for brothers. My elder brother won't die, and my younger brothers seem never to do anything else." "Harry!" exclaimed Hallward, frowning. "My dear fellow, I am not quite serious. But I can't help detesting my relations. I suppose it comes from the fact that none of us can stand other people having the same faults as ourselves. I quite sympathize with the rage of the English democracy against what they call the vices of the upper orders. The masses feel that drunkenness, stupidity, and immorality should be their own special property, and that if any one of us makes an ass of himself, he is poaching on their preserves. When poor Southwark got into the divorce court, their indignation was quite magnificent. And yet I don't suppose that ten per cent of the proletariat live correctly." "I don't agree with a single word that you have said, and, what is more, Harry, I feel sure you don't either." Lord Henry stroked his pointed brown beard and tapped the toe of his patent-leather boot with a tasselled ebony cane. "How English you are Basil! That is the second time you have made that observation. If one puts forward an idea to a true Englishman--always a rash thing to do--he never dreams of considering whether the idea is right or wrong. The only thing he considers of any importance is whether one believes it oneself. Now, the value of an idea has nothing whatsoever to do with the sincerity of the man who expresses it. Indeed, the probabilities are that the more insincere the man is, the more purely intellectual will the idea be, as in that case it will not be coloured by either his wants, his desires, or his prejudices. However, I don't propose to discuss politics, sociology, or metaphysics with you. I like persons better than principles, and I like persons with no principles better than anything else in the world. Tell me more about Mr. Dorian Gray. How often do you see him?" "Every day. I couldn't be happy if I didn't see him every day. He is absolutely necessary to me." "How extraordinary! I thought you would never care for anything but your art." "He is all my art to me now," said the painter gravely. "I sometimes think, Harry, that there are only two eras of any importance in the world's history. The first is the appearance of a new medium for art, and the second is the appearance of a new personality for art also. What the invention of oil-painting was to the Venetians, the face of Antinous was to late Greek sculpture, and the face of Dorian Gray will some day be to me. It is not merely that I paint from him, draw from him, sketch from him. Of course, I have done all that. But he is much more to me than a model or a sitter. I won't tell you that I am dissatisfied with what I have done of him, or that his beauty is such that art cannot express it. There is nothing that art cannot express, and I know that the work I have done, since I met Dorian Gray, is good work, is the best work of my life. But in some curious way--I wonder will you understand me?--his personality has suggested to me an entirely new manner in art, an entirely new mode of style. I see things differently, I think of them differently. I can now recreate life in a way that was hidden from me before. 'A dream of form in days of thought'--who is it who says that? I forget; but it is what Dorian Gray has been to me. The merely visible presence of this lad--for he seems to me little more than a lad, though he is really over twenty-- his merely visible presence--ah! I wonder can you realize all that that means? Unconsciously he defines for me the lines of a fresh school, a school that is to have in it all the passion of the romantic spirit, all the perfection of the spirit that is Greek. The harmony of soul and body-- how much that is! We in our madness have separated the two, and have invented a realism that is vulgar, an ideality that is void. Harry! if you only knew what Dorian Gray is to me! You remember that landscape of mine, for which Agnew offered me such a huge price but which I would not part with? It is one of the best things I have ever done. And why is it so? Because, while I was painting it, Dorian Gray sat beside me. Some subtle influence passed from him to me, and for the first time in my life I saw in the plain woodland the wonder I had always looked for and always missed." "Basil, this is extraordinary! I must see Dorian Gray." Hallward got up from the seat and walked up and down the garden. After some time he came back. "Harry," he said, "Dorian Gray is to me simply a motive in art. You might see nothing in him. I see everything in him. He is never more present in my work than when no image of him is there. He is a suggestion, as I have said, of a new manner. I find him in the curves of certain lines, in the loveliness and subtleties of certain colours. That is all." "Then why won't you exhibit his portrait?" asked Lord Henry. "Because, without intending it, I have put into it some expression of all this curious artistic idolatry, of which, of course, I have never cared to speak to him. He knows nothing about it. He shall never know anything about it. But the world might guess it, and I will not bare my soul to their shallow prying eyes. My heart shall never be put under their microscope. There is too much of myself in the thing, Harry--too much of myself!" "Poets are not so scrupulous as you are. They know how useful passion is for publication. Nowadays a broken heart will run to many editions." "I hate them for it," cried Hallward. "An artist should create beautiful things, but should put nothing of his own life into them. We live in an age when men treat art as if it were meant to be a form of autobiography. We have lost the abstract sense of beauty. Some day I will show the world what it is; and for that reason the world shall never see my portrait of Dorian Gray." "I think you are wrong, Basil, but I won't argue with you. It is only the intellectually lost who ever argue. Tell me, is Dorian Gray very fond of you?" The painter considered for a few moments. "He likes me," he answered after a pause; "I know he likes me. Of course I flatter him dreadfully. I find a strange pleasure in saying things to him that I know I shall be sorry for having said. As a rule, he is charming to me, and we sit in the studio and talk of a thousand things. Now and then, however, he is horribly thoughtless, and seems to take a real delight in giving me pain. Then I feel, Harry, that I have given away my whole soul to some one who treats it as if it were a flower to put in his coat, a bit of decoration to charm his vanity, an ornament for a summer's day." "Days in summer, Basil, are apt to linger," murmured Lord Henry. "Perhaps you will tire sooner than he will. It is a sad thing to think of, but there is no doubt that genius lasts longer than beauty. That accounts for the fact that we all take such pains to over-educate ourselves. In the wild struggle for existence, we want to have something that endures, and so we fill our minds with rubbish and facts, in the silly hope of keeping our place. The thoroughly well-informed man--that is the modern ideal. And the mind of the thoroughly well-informed man is a dreadful thing. It is like a bric-a-brac shop, all monsters and dust, with everything priced above its proper value. I think you will tire first, all the same. Some day you will look at your friend, and he will seem to you to be a little out of drawing, or you won't like his tone of colour, or something. You will bitterly reproach him in your own heart, and seriously think that he has behaved very badly to you. The next time he calls, you will be perfectly cold and indifferent. It will be a great pity, for it will alter you. What you have told me is quite a romance, a romance of art one might call it, and the worst of having a romance of any kind is that it leaves one so unromantic." "Harry, don't talk like that. As long as I live, the personality of Dorian Gray will dominate me. You can't feel what I feel. You change too often." "Ah, my dear Basil, that is exactly why I can feel it. Those who are faithful know only the trivial side of love: it is the faithless who know love's tragedies." And Lord Henry struck a light on a dainty silver case and began to smoke a cigarette with a self-conscious and satisfied air, as if he had summed up the world in a phrase. There was a rustle of chirruping sparrows in the green lacquer leaves of the ivy, and the blue cloud-shadows chased themselves across the grass like swallows. How pleasant it was in the garden! And how delightful other people's emotions were!-- much more delightful than their ideas, it seemed to him. One's own soul, and the passions of one's friends--those were the fascinating things in life. He pictured to himself with silent amusement the tedious luncheon that he had missed by staying so long with Basil Hallward. Had he gone to his aunt's, he would have been sure to have met Lord Goodbody there, and the whole conversation would have been about the feeding of the poor and the necessity for model lodging-houses. Each class would have preached the importance of those virtues, for whose exercise there was no necessity in their own lives. The rich would have spoken on the value of thrift, and the idle grown eloquent over the dignity of labour. It was charming to have escaped all that! As he thought of his aunt, an idea seemed to strike him. He turned to Hallward and said, "My dear fellow, I have just remembered." "Remembered what, Harry?" "Where I heard the name of Dorian Gray." "Where was it?" asked Hallward, with a slight frown. "Don't look so angry, Basil. It was at my aunt, Lady Agatha's. She told me she had discovered a wonderful young man who was going to help her in the East End, and that his name was Dorian Gray. I am bound to state that she never told me he was good-looking. Women have no appreciation of good looks; at least, good women have not. She said that he was very earnest and had a beautiful nature. I at once pictured to myself a creature with spectacles and lank hair, horribly freckled, and tramping about on huge feet. I wish I had known it was your friend." "I am very glad you didn't, Harry." "Why?" "I don't want you to meet him." "You don't want me to meet him?" "No." "Mr. Dorian Gray is in the studio, sir," said the butler, coming into the garden. "You must introduce me now," cried Lord Henry, laughing. The painter turned to his servant, who stood blinking in the sunlight. "Ask Mr. Gray to wait, Parker: I shall be in in a few moments." The man bowed and went up the walk. Then he looked at Lord Henry. "Dorian Gray is my dearest friend," he said. "He has a simple and a beautiful nature. Your aunt was quite right in what she said of him. Don't spoil him. Don't try to influence him. Your influence would be bad. The world is wide, and has many marvellous people in it. Don't take away from me the one person who gives to my art whatever charm it possesses: my life as an artist depends on him. Mind, Harry, I trust you." He spoke very slowly, and the words seemed wrung out of him almost against his will. "What nonsense you talk!" said Lord Henry, smiling, and taking Hallward by the arm, he almost led him into the house. CHAPTER 2 As they entered they saw Dorian Gray. He was seated at the piano, with his back to them, turning over the pages of a volume of Schumann's "Forest Scenes." "You must lend me these, Basil," he cried. "I want to learn them. They are perfectly charming." "That entirely depends on how you sit to-day, Dorian." "Oh, I am tired of sitting, and I don't want a life-sized portrait of myself," answered the lad, swinging round on the music-stool in a wilful, petulant manner. When he caught sight of Lord Henry, a faint blush coloured his cheeks for a moment, and he started up. "I beg your pardon, Basil, but I didn't know you had any one with you." "This is Lord Henry Wotton, Dorian, an old Oxford friend of mine. I have just been telling him what a capital sitter you were, and now you have spoiled everything." "You have not spoiled my pleasure in meeting you, Mr. Gray," said Lord Henry, stepping forward and extending his hand. "My aunt has often spoken to me about you. You are one of her favourites, and, I am afraid, one of her victims also." "I am in Lady Agatha's black books at present," answered Dorian with a funny look of penitence. "I promised to go to a club in Whitechapel with her last Tuesday, and I really forgot all about it. We were to have played a duet together--three duets, I believe. I don't know what she will say to me. I am far too frightened to call." "Oh, I will make your peace with my aunt. She is quite devoted to you. And I don't think it really matters about your not being there. The audience probably thought it was a duet. When Aunt Agatha sits down to the piano, she makes quite enough noise for two people." "That is very horrid to her, and not very nice to me," answered Dorian, laughing. Lord Henry looked at him. Yes, he was certainly wonderfully handsome, with his finely curved scarlet lips, his frank blue eyes, his crisp gold hair. There was something in his face that made one trust him at once. All the candour of youth was there, as well as all youth's passionate purity. One felt that he had kept himself unspotted from the world. No wonder Basil Hallward worshipped him. "You are too charming to go in for philanthropy, Mr. Gray--far too charming." And Lord Henry flung himself down on the divan and opened his cigarette-case. The painter had been busy mixing his colours and getting his brushes ready. He was looking worried, and when he heard Lord Henry's last remark, he glanced at him, hesitated for a moment, and then said, "Harry, I want to finish this picture to-day. Would you think it awfully rude of me if I asked you to go away?" Lord Henry smiled and looked at Dorian Gray. "Am I to go, Mr. Gray?" he asked. "Oh, please don't, Lord Henry. I see that Basil is in one of his sulky moods, and I can't bear him when he sulks. Besides, I want you to tell me why I should not go in for philanthropy." "I don't know that I shall tell you that, Mr. Gray. It is so tedious a subject that one would have to talk seriously about it. But I certainly shall not run away, now that you have asked me to stop. You don't really mind, Basil, do you? You have often told me that you liked your sitters to have some one to chat to." Hallward bit his lip. "If Dorian wishes it, of course you must stay. Dorian's whims are laws to everybody, except himself." Lord Henry took up his hat and gloves. "You are very pressing, Basil, but I am afraid I must go. I have promised to meet a man at the Orleans. Good-bye, Mr. Gray. Come and see me some afternoon in Curzon Street. I am nearly always at home at five o'clock. Write to me when you are coming. I should be sorry to miss you." "Basil," cried Dorian Gray, "if Lord Henry Wotton goes, I shall go, too. You never open your lips while you are painting, and it is horribly dull standing on a platform and trying to look pleasant. Ask him to stay. I insist upon it." "Stay, Harry, to oblige Dorian, and to oblige me," said Hallward, gazing intently at his picture. "It is quite true, I never talk when I am working, and never listen either, and it must be dreadfully tedious for my unfortunate sitters. I beg you to stay." "But what about my man at the Orleans?" The painter laughed. "I don't think there will be any difficulty about that. Sit down again, Harry. And now, Dorian, get up on the platform, and don't move about too much, or pay any attention to what Lord Henry says. He has a very bad influence over all his friends, with the single exception of myself." Dorian Gray stepped up on the dais with the air of a young Greek martyr, and made a little moue of discontent to Lord Henry, to whom he had rather taken a fancy. He was so unlike Basil. They made a delightful contrast. And he had such a beautiful voice. After a few moments he said to him, "Have you really a very bad influence, Lord Henry? As bad as Basil says?" "There is no such thing as a good influence, Mr. Gray. All influence is immoral--immoral from the scientific point of view." "Why?" "Because to influence a person is to give him one's own soul. He does not think his natural thoughts, or burn with his natural passions. His virtues are not real to him. His sins, if there are such things as sins, are borrowed. He becomes an echo of some one else's music, an actor of a part that has not been written for him. The aim of life is self-development. To realize one's nature perfectly--that is what each of us is here for. People are afraid of themselves, nowadays. They have forgotten the highest of all duties, the duty that one owes to one's self. Of course, they are charitable. They feed the hungry and clothe the beggar. But their own souls starve, and are naked. Courage has gone out of our race. Perhaps we never really had it. The terror of society, which is the basis of morals, the terror of God, which is the secret of religion--these are the two things that govern us. And yet--" "Just turn your head a little more to the right, Dorian, like a good boy," said the painter, deep in his work and conscious only that a look had come into the lad's face that he had never seen there before. "And yet," continued Lord Henry, in his low, musical voice, and with that graceful wave of the hand that was always so characteristic of him, and that he had even in his Eton days, "I believe that if one man were to live out his life fully and completely, were to give form to every feeling, expression to every thought, reality to every dream--I believe that the world would gain such a fresh impulse of joy that we would forget all the maladies of mediaevalism, and return to the Hellenic ideal-- to something finer, richer than the Hellenic ideal, it may be. But the bravest man amongst us is afraid of himself. The mutilation of the savage has its tragic survival in the self-denial that mars our lives. We are punished for our refusals. Every impulse that we strive to strangle broods in the mind and poisons us. The body sins once, and has done with its sin, for action is a mode of purification. Nothing remains then but the recollection of a pleasure, or the luxury of a regret. The only way to get rid of a temptation is to yield to it. Resist it, and your soul grows sick with longing for the things it has forbidden to itself, with desire for what its monstrous laws have made monstrous and unlawful. It has been said that the great events of the world take place in the brain. It is in the brain, and the brain only, that the great sins of the world take place also. You, Mr. Gray, you yourself, with your rose-red youth and your rose-white boyhood, you have had passions that have made you afraid, thoughts that have filled you with terror, day-dreams and sleeping dreams whose mere memory might stain your cheek with shame--" "Stop!" faltered Dorian Gray, "stop! you bewilder me. I don't know what to say. There is some answer to you, but I cannot find it. Don't speak. Let me think. Or, rather, let me try not to think." For nearly ten minutes he stood there, motionless, with parted lips and eyes strangely bright. He was dimly conscious that entirely fresh influences were at work within him. Yet they seemed to him to have come really from himself. The few words that Basil's friend had said to him--words spoken by chance, no doubt, and with wilful paradox in them-- had touched some secret chord that had never been touched before, but that he felt was now vibrating and throbbing to curious pulses. Music had stirred him like that. Music had troubled him many times. But music was not articulate. It was not a new world, but rather another chaos, that it created in us. Words! Mere words! How terrible they were! How clear, and vivid, and cruel! One could not escape from them. And yet what a subtle magic there was in them! They seemed to be able to give a plastic form to formless things, and to have a music of their own as sweet as that of viol or of lute. Mere words! Was there anything so real as words? Yes; there had been things in his boyhood that he had not understood. He understood them now. Life suddenly became fiery-coloured to him. It seemed to him that he had been walking in fire. Why had he not known it? With his subtle smile, Lord Henry watched him. He knew the precise psychological moment when to say nothing. He felt intensely interested. He was amazed at the sudden impression that his words had produced, and, remembering a book that he had read when he was sixteen, a book which had revealed to him much that he had not known before, he wondered whether Dorian Gray was passing through a similar experience. He had merely shot an arrow into the air. Had it hit the mark? How fascinating the lad was! Hallward painted away with that marvellous bold touch of his, that had the true refinement and perfect delicacy that in art, at any rate comes only from strength. He was unconscious of the silence. "Basil, I am tired of standing," cried Dorian Gray suddenly. "I must go out and sit in the garden. The air is stifling here." "My dear fellow, I am so sorry. When I am painting, I can't think of anything else. But you never sat better. You were perfectly still. And I have caught the effect I wanted-- the half-parted lips and the bright look in the eyes. I don't know what Harry has been saying to you, but he has certainly made you have the most wonderful expression. I suppose he has been paying you compliments. You mustn't believe a word that he says." "He has certainly not been paying me compliments. Perhaps that is the reason that I don't believe anything he has told me." "You know you believe it all," said Lord Henry, looking at him with his dreamy languorous eyes. "I will go out to the garden with you. It is horribly hot in the studio. Basil, let us have something iced to drink, something with strawberries in it." "Certainly, Harry. Just touch the bell, and when Parker comes I will tell him what you want. I have got to work up this background, so I will join you later on. Don't keep Dorian too long. I have never been in better form for painting than I am to-day. This is going to be my masterpiece. It is my masterpiece as it stands." Lord Henry went out to the garden and found Dorian Gray burying his face in the great cool lilac-blossoms, feverishly drinking in their perfume as if it had been wine. He came close to him and put his hand upon his shoulder. "You are quite right to do that," he murmured. "Nothing can cure the soul but the senses, just as nothing can cure the senses but the soul." The lad started and drew back. He was bareheaded, and the leaves had tossed his rebellious curls and tangled all their gilded threads. There was a look of fear in his eyes, such as people have when they are suddenly awakened. His finely chiselled nostrils quivered, and some hidden nerve shook the scarlet of his lips and left them trembling. "Yes," continued Lord Henry, "that is one of the great secrets of life-- to cure the soul by means of the senses, and the senses by means of the soul. You are a wonderful creation. You know more than you think you know, just as you know less than you want to know." Dorian Gray frowned and turned his head away. He could not help liking the tall, graceful young man who was standing by him. His romantic, olive-coloured face and worn expression interested him. There was something in his low languid voice that was absolutely fascinating. His cool, white, flowerlike hands, even, had a curious charm. They moved, as he spoke, like music, and seemed to have a language of their own. But he felt afraid of him, and ashamed of being afraid. Why had it been left for a stranger to reveal him to himself? He had known Basil Hallward for months, but the friendship between them had never altered him. Suddenly there had come some one across his life who seemed to have disclosed to him life's mystery. And, yet, what was there to be afraid of? He was not a schoolboy or a girl. It was absurd to be frightened. "Let us go and sit in the shade," said Lord Henry. "Parker has brought out the drinks, and if you stay any longer in this glare, you will be quite spoiled, and Basil will never paint you again. You really must not allow yourself to become sunburnt. It would be unbecoming." "What can it matter?" cried Dorian Gray, laughing, as he sat down on the seat at the end of the garden. "It should matter everything to you, Mr. Gray." "Why?" "Because you have the most marvellous youth, and youth is the one thing worth having." "I don't feel that, Lord Henry." "No, you don't feel it now. Some day, when you are old and wrinkled and ugly, when thought has seared your forehead with its lines, and passion branded your lips with its hideous fires, you will feel it, you will feel it terribly. Now, wherever you go, you charm the world. Will it always be so? . . . You have a wonderfully beautiful face, Mr. Gray. Don't frown. You have. And beauty is a form of genius-- is higher, indeed, than genius, as it needs no explanation. It is of the great facts of the world, like sunlight, or spring-time, or the reflection in dark waters of that silver shell we call the moon. It cannot be questioned. It has its divine right of sovereignty. It makes princes of those who have it. You smile? Ah! when you have lost it you won't smile. . . . People say sometimes that beauty is only superficial. That may be so, but at least it is not so superficial as thought is. To me, beauty is the wonder of wonders. It is only shallow people who do not judge by appearances. The true mystery of the world is the visible, not the invisible. . . . Yes, Mr. Gray, the gods have been good to you. But what the gods give they quickly take away. You have only a few years in which to live really, perfectly, and fully. When your youth goes, your beauty will go with it, and then you will suddenly discover that there are no triumphs left for you, or have to content yourself with those mean triumphs that the memory of your past will make more bitter than defeats. Every month as it wanes brings you nearer to something dreadful. Time is jealous of you, and wars against your lilies and your roses. You will become sallow, and hollow-cheeked, and dull-eyed. You will suffer horribly.... Ah! realize your youth while you have it. Don't squander the gold of your days, listening to the tedious, trying to improve the hopeless failure, or giving away your life to the ignorant, the common, and the vulgar. These are the sickly aims, the false ideals, of our age. Live! Live the wonderful life that is in you! Let nothing be lost upon you. Be always searching for new sensations. Be afraid of nothing. . . . A new Hedonism-- that is what our century wants. You might be its visible symbol. With your personality there is nothing you could not do. The world belongs to you for a season. . . . The moment I met you I saw that you were quite unconscious of what you really are, of what you really might be. There was so much in you that charmed me that I felt I must tell you something about yourself. I thought how tragic it would be if you were wasted. For there is such a little time that your youth will last--such a little time. The common hill-flowers wither, but they blossom again. The laburnum will be as yellow next June as it is now. In a month there will be purple stars on the clematis, and year after year the green night of its leaves will hold its purple stars. But we never get back our youth. The pulse of joy that beats in us at twenty becomes sluggish. Our limbs fail, our senses rot. We degenerate into hideous puppets, haunted by the memory of the passions of which we were too much afraid, and the exquisite temptations that we had not the courage to yield to. Youth! Youth! There is absolutely nothing in the world but youth!" Dorian Gray listened, open-eyed and wondering. The spray of lilac fell from his hand upon the gravel. A furry bee came and buzzed round it for a moment. Then it began to scramble all over the oval stellated globe of the tiny blossoms. He watched it with that strange interest in trivial things that we try to develop when things of high import make us afraid, or when we are stirred by some new emotion for which we cannot find expression, or when some thought that terrifies us lays sudden siege to the brain and calls on us to yield. After a time the bee flew away. He saw it creeping into the stained trumpet of a Tyrian convolvulus. The flower seemed to quiver, and then swayed gently to and fro. Suddenly the painter appeared at the door of the studio and made staccato signs for them to come in. They turned to each other and smiled. "I am waiting," he cried. "Do come in. The light is quite perfect, and you can bring your drinks." They rose up and sauntered down the walk together. Two green-and-white butterflies fluttered past them, and in the pear-tree at the corner of the garden a thrush began to sing. "You are glad you have met me, Mr. Gray," said Lord Henry, looking at him. "Yes, I am glad now. I wonder shall I always be glad?" "Always! That is a dreadful word. It makes me shudder when I hear it. Women are so fond of using it. They spoil every romance by trying to make it last for ever. It is a meaningless word, too. The only difference between a caprice and a lifelong passion is that the caprice lasts a little longer." As they entered the studio, Dorian Gray put his hand upon Lord Henry's arm. "In that case, let our friendship be a caprice," he murmured, flushing at his own boldness, then stepped up on the platform and resumed his pose. Lord Henry flung himself into a large wicker arm-chair and watched him. The sweep and dash of the brush on the canvas made the only sound that broke the stillness, except when, now and then, Hallward stepped back to look at his work from a distance. In the slanting beams that streamed through the open doorway the dust danced and was golden. The heavy scent of the roses seemed to brood over everything. After about a quarter of an hour Hallward stopped painting, looked for a long time at Dorian Gray, and then for a long time at the picture, biting the end of one of his huge brushes and frowning. "It is quite finished," he cried at last, and stooping down he wrote his name in long vermilion letters on the left-hand corner of the canvas. Lord Henry came over and examined the picture. It was certainly a wonderful work of art, and a wonderful likeness as well. "My dear fellow, I congratulate you most warmly," he said. "It is the finest portrait of modern times. Mr. Gray, come over and look at yourself." The lad started, as if awakened from some dream. "Is it really finished?" he murmured, stepping down from the platform. "Quite finished," said the painter. "And you have sat splendidly to-day. I am awfully obliged to you." "That is entirely due to me," broke in Lord Henry. "Isn't it, Mr. Gray?" Dorian made no answer, but passed listlessly in front of his picture and turned towards it. When he saw it he drew back, and his cheeks flushed for a moment with pleasure. A look of joy came into his eyes, as if he had recognized himself for the first time. He stood there motionless and in wonder, dimly conscious that Hallward was speaking to him, but not catching the meaning of his words. The sense of his own beauty came on him like a revelation. He had never felt it before. Basil Hallward's compliments had seemed to him to be merely the charming exaggeration of friendship. He had listened to them, laughed at them, forgotten them. They had not influenced his nature. Then had come Lord Henry Wotton with his strange panegyric on youth, his terrible warning of its brevity. That had stirred him at the time, and now, as he stood gazing at the shadow of his own loveliness, the full reality of the description flashed across him. Yes, there would be a day when his face would be wrinkled and wizen, his eyes dim and colourless, the grace of his figure broken and deformed. The scarlet would pass away from his lips and the gold steal from his hair. The life that was to make his soul would mar his body. He would become dreadful, hideous, and uncouth. As he thought of it, a sharp pang of pain struck through him like a knife and made each delicate fibre of his nature quiver. His eyes deepened into amethyst, and across them came a mist of tears. He felt as if a hand of ice had been laid upon his heart. "Don't you like it?" cried Hallward at last, stung a little by the lad's silence, not understanding what it meant. "Of course he likes it," said Lord Henry. "Who wouldn't like it? It is one of the greatest things in modern art. I will give you anything you like to ask for it. I must have it." "It is not my property, Harry." "Whose property is it?" "Dorian's, of course," answered the painter. "He is a very lucky fellow." "How sad it is!" murmured Dorian Gray with his eyes still fixed upon his own portrait. "How sad it is! I shall grow old, and horrible, and dreadful. But this picture will remain always young. It will never be older than this particular day of June. . . . If it were only the other way! If it were I who was to be always young, and the picture that was to grow old! For that--for that--I would give everything! Yes, there is nothing in the whole world I would not give! I would give my soul for that!" "You would hardly care for such an arrangement, Basil," cried Lord Henry, laughing. "It would be rather hard lines on your work." "I should object very strongly, Harry," said Hallward. Dorian Gray turned and looked at him. "I believe you would, Basil. You like your art better than your friends. I am no more to you than a green bronze figure. Hardly as much, I dare say." The painter stared in amazement. It was so unlike Dorian to speak like that. What had happened? He seemed quite angry. His face was flushed and his cheeks burning. "Yes," he continued, "I am less to you than your ivory Hermes or your silver Faun. You will like them always. How long will you like me? Till I have my first wrinkle, I suppose. I know, now, that when one loses one's good looks, whatever they may be, one loses everything. Your picture has taught me that. Lord Henry Wotton is perfectly right. Youth is the only thing worth having. When I find that I am growing old, I shall kill myself." Hallward turned pale and caught his hand. "Dorian! Dorian!" he cried, "don't talk like that. I have never had such a friend as you, and I shall never have such another. You are not jealous of material things, are you?-- you who are finer than any of them!" "I am jealous of everything whose beauty does not die. I am jealous of the portrait you have painted of me. Why should it keep what I must lose? Every moment that passes takes something from me and gives something to it. Oh, if it were only the other way! If the picture could change, and I could be always what I am now! Why did you paint it? It will mock me some day--mock me horribly!" The hot tears welled into his eyes; he tore his hand away and, flinging himself on the divan, he buried his face in the cushions, as though he was praying. "This is your doing, Harry," said the painter bitterly. Lord Henry shrugged his shoulders. "It is the real Dorian Gray-- that is all." "It is not." "If it is not, what have I to do with it?" "You should have gone away when I asked you," he muttered. "I stayed when you asked me," was Lord Henry's answer. "Harry, I can't quarrel with my two best friends at once, but between you both you have made me hate the finest piece of work I have ever done, and I will destroy it. What is it but canvas and colour? I will not let it come across our three lives and mar them." Dorian Gray lifted his golden head from the pillow, and with pallid face and tear-stained eyes, looked at him as he walked over to the deal painting-table that was set beneath the high curtained window. What was he doing there? His fingers were straying about among the litter of tin tubes and dry brushes, seeking for something. Yes, it was for the long palette-knife, with its thin blade of lithe steel. He had found it at last. He was going to rip up the canvas. With a stifled sob the lad leaped from the couch, and, rushing over to Hallward, tore the knife out of his hand, and flung it to the end of the studio. "Don't, Basil, don't!" he cried. "It would be murder!" "I am glad you appreciate my work at last, Dorian," said the painter coldly when he had recovered from his surprise. "I never thought you would." "Appreciate it? I am in love with it, Basil. It is part of myself. I feel that." "Well, as soon as you are dry, you shall be varnished, and framed, and sent home. Then you can do what you like with yourself." And he walked across the room and rang the bell for tea. "You will have tea, of course, Dorian? And so will you, Harry? Or do you object to such simple pleasures?" "I adore simple pleasures," said Lord Henry. "They are the last refuge of the complex. But I don't like scenes, except on the stage. What absurd fellows you are, both of you! I wonder who it was defined man as a rational animal. It was the most premature definition ever given. Man is many things, but he is not rational. I am glad he is not, after all-- though I wish you chaps would not squabble over the picture. You had much better let me have it, Basil. This silly boy doesn't really want it, and I really do." "If you let any one have it but me, Basil, I shall never forgive you!" cried Dorian Gray; "and I don't allow people to call me a silly boy." "You know the picture is yours, Dorian. I gave it to you before it existed." "And you know you have been a little silly, Mr. Gray, and that you don't really object to being reminded that you are extremely young." "I should have objected very strongly this morning, Lord Henry." "Ah! this morning! You have lived since then." There came a knock at the door, and the butler entered with a laden tea-tray and set it down upon a small Japanese table. There was a rattle of cups and saucers and the hissing of a fluted Georgian urn. Two globe-shaped china dishes were brought in by a page. Dorian Gray went over and poured out the tea. The two men sauntered languidly to the table and examined what was under the covers. "Let us go to the theatre to-night," said Lord Henry. "There is sure to be something on, somewhere. I have promised to dine at White's, but it is only with an old friend, so I can send him a wire to say that I am ill, or that I am prevented from coming in consequence of a subsequent engagement. I think that would be a rather nice excuse: it would have all the surprise of candour." "It is such a bore putting on one's dress-clothes," muttered Hallward. "And, when one has them on, they are so horrid." "Yes," answered Lord Henry dreamily, "the costume of the nineteenth century is detestable. It is so sombre, so depressing. Sin is the only real colour-element left in modern life." "You really must not say things like that before Dorian, Harry." "Before which Dorian? The one who is pouring out tea for us, or the one in the picture?" "Before either." "I should like to come to the theatre with you, Lord Henry," said the lad. "Then you shall come; and you will come, too, Basil, won't you?" "I can't, really. I would sooner not. I have a lot of work to do." "Well, then, you and I will go alone, Mr. Gray." "I should like that awfully." The painter bit his lip and walked over, cup in hand, to the picture. "I shall stay with the real Dorian," he said, sadly. "Is it the real Dorian?" cried the original of the portrait, strolling across to him. "Am I really like that?" "Yes; you are just like that." "How wonderful, Basil!" "At least you are like it in appearance. But it will never alter," sighed Hallward. "That is something." "What a fuss people make about fidelity!" exclaimed Lord Henry. "Why, even in love it is purely a question for physiology. It has nothing to do with our own will. Young men want to be faithful, and are not; old men want to be faithless, and cannot: that is all one can say." "Don't go to the theatre to-night, Dorian," said Hallward. "Stop and dine with me." "I can't, Basil." "Why?" "Because I have promised Lord Henry Wotton to go with him." "He won't like you the better for keeping your promises. He always breaks his own. I beg you not to go." Dorian Gray laughed and shook his head. "I entreat you." The lad hesitated, and looked over at Lord Henry, who was watching them from the tea-table with an amused smile. "I must go, Basil," he answered. "Very well," said Hallward, and he went over and laid down his cup on the tray. "It is rather late, and, as you have to dress, you had better lose no time. Good-bye, Harry. Good-bye, Dorian. Come and see me soon. Come to-morrow." "Certainly." "You won't forget?" "No, of course not," cried Dorian. "And ... Harry!" "Yes, Basil?" "Remember what I asked you, when we were in the garden this morning." "I have forgotten it." "I trust you." "I wish I could trust myself," said Lord Henry, laughing. "Come, Mr. Gray, my hansom is outside, and I can drop you at your own place. Good-bye, Basil. It has been a most interesting afternoon." As the door closed behind them, the painter flung himself down on a sofa, and a look of pain came into his face. CHAPTER 3 At half-past twelve next day Lord Henry Wotton strolled from Curzon Street over to the Albany to call on his uncle, Lord Fermor, a genial if somewhat rough-mannered old bachelor, whom the outside world called selfish because it derived no particular benefit from him, but who was considered generous by Society as he fed the people who amused him. His father had been our ambassador at Madrid when Isabella was young and Prim unthought of, but had retired from the diplomatic service in a capricious moment of annoyance on not being offered the Embassy at Paris, a post to which he considered that he was fully entitled by reason of his birth, his indolence, the good English of his dispatches, and his inordinate passion for pleasure. The son, who had been his father's secretary, had resigned along with his chief, somewhat foolishly as was thought at the time, and on succeeding some months later to the title, had set himself to the serious study of the great aristocratic art of doing absolutely nothing. He had two large town houses, but preferred to live in chambers as it was less trouble, and took most of his meals at his club. He paid some attention to the management of his collieries in the Midland counties, excusing himself for this taint of industry on the ground that the one advantage of having coal was that it enabled a gentleman to afford the decency of burning wood on his own hearth. In politics he was a Tory, except when the Tories were in office, during which period he roundly abused them for being a pack of Radicals. He was a hero to his valet, who bullied him, and a terror to most of his relations, whom he bullied in turn. Only England could have produced him, and he always said that the country was going to the dogs. His principles were out of date, but there was a good deal to be said for his prejudices. When Lord Henry entered the room, he found his uncle sitting in a rough shooting-coat, smoking a cheroot and grumbling over The Times. "Well, Harry," said the old gentleman, "what brings you out so early? I thought you dandies never got up till two, and were not visible till five." "Pure family affection, I assure you, Uncle George. I want to get something out of you." "Money, I suppose," said Lord Fermor, making a wry face. "Well, sit down and tell me all about it. Young people, nowadays, imagine that money is everything." "Yes," murmured Lord Henry, settling his button-hole in his coat; "and when they grow older they know it. But I don't want money. It is only people who pay their bills who want that, Uncle George, and I never pay mine. Credit is the capital of a younger son, and one lives charmingly upon it. Besides, I always deal with Dartmoor's tradesmen, and consequently they never bother me. What I want is information: not useful information, of course; useless information." "Well, I can tell you anything that is in an English Blue Book, Harry, although those fellows nowadays write a lot of nonsense. When I was in the Diplomatic, things were much better. But I hear they let them in now by examination. What can you expect? Examinations, sir, are pure humbug from beginning to end. If a man is a gentleman, he knows quite enough, and if he is not a gentleman, whatever he knows is bad for him." "Mr. Dorian Gray does not belong to Blue Books, Uncle George," said Lord Henry languidly. "Mr. Dorian Gray? Who is he?" asked Lord Fermor, knitting his bushy white eyebrows. "That is what I have come to learn, Uncle George. Or rather, I know who he is. He is the last Lord Kelso's grandson. His mother was a Devereux, Lady Margaret Devereaux. I want you to tell me about his mother. What was she like? Whom did she marry? You have known nearly everybody in your time, so you might have known her. I am very much interested in Mr. Gray at present. I have only just met him." "Kelso's grandson!" echoed the old gentleman. "Kelso's grandson! ... Of course.... I knew his mother intimately. I believe I was at her christening. She was an extraordinarily beautiful girl, Margaret Devereux, and made all the men frantic by running away with a penniless young fellow-- a mere nobody, sir, a subaltern in a foot regiment, or something of that kind. Certainly. I remember the whole thing as if it happened yesterday. The poor chap was killed in a duel at Spa a few months after the marriage. There was an ugly story about it. They said Kelso got some rascally adventurer, some Belgian brute, to insult his son-in-law in public--paid him, sir, to do it, paid him-- and that the fellow spitted his man as if he had been a pigeon. The thing was hushed up, but, egad, Kelso ate his chop alone at the club for some time afterwards. He brought his daughter back with him, I was told, and she never spoke to him again. Oh, yes; it was a bad business. The girl died, too, died within a year. So she left a son, did she? I had forgotten that. What sort of boy is he? If he is like his mother, he must be a good-looking chap." "He is very good-looking," assented Lord Henry. "I hope he will fall into proper hands," continued the old man. "He should have a pot of money waiting for him if Kelso did the right thing by him. His mother had money, too. All the Selby property came to her, through her grandfather. Her grandfather hated Kelso, thought him a mean dog. He was, too. Came to Madrid once when I was there. Egad, I was ashamed of him. The Queen used to ask me about the English noble who was always quarrelling with the cabmen about their fares. They made quite a story of it. I didn't dare show my face at Court for a month. I hope he treated his grandson better than he did the jarvies." "I don't know," answered Lord Henry. "I fancy that the boy will be well off. He is not of age yet. He has Selby, I know. He told me so. And . . . his mother was very beautiful?" "Margaret Devereux was one of the loveliest creatures I ever saw, Harry. What on earth induced her to behave as she did, I never could understand. She could have married anybody she chose. Carlington was mad after her. She was romantic, though. All the women of that family were. The men were a poor lot, but, egad! the women were wonderful. Carlington went on his knees to her. Told me so himself. She laughed at him, and there wasn't a girl in London at the time who wasn't after him. And by the way, Harry, talking about silly marriages, what is this humbug your father tells me about Dartmoor wanting to marry an American? Ain't English girls good enough for him?" "It is rather fashionable to marry Americans just now, Uncle George." "I'll back English women against the world, Harry," said Lord Fermor, striking the table with his fist. "The betting is on the Americans." "They don't last, I am told," muttered his uncle. "A long engagement exhausts them, but they are capital at a steeplechase. They take things flying. I don't think Dartmoor has a chance." "Who are her people?" grumbled the old gentleman. "Has she got any?" Lord Henry shook his head. "American girls are as clever at concealing their parents, as English women are at concealing their past," he said, rising to go. "They are pork-packers, I suppose?" "I hope so, Uncle George, for Dartmoor's sake. I am told that pork-packing is the most lucrative profession in America, after politics." "Is she pretty?" "She behaves as if she was beautiful. Most American women do. It is the secret of their charm." "Why can't these American women stay in their own country? They are always telling us that it is the paradise for women." "It is. That is the reason why, like Eve, they are so excessively anxious to get out of it," said Lord Henry. "Good-bye, Uncle George. I shall be late for lunch, if I stop any longer. Thanks for giving me the information I wanted. I always like to know everything about my new friends, and nothing about my old ones." "Where are you lunching, Harry?" "At Aunt Agatha's. I have asked myself and Mr. Gray. He is her latest protege." "Humph! tell your Aunt Agatha, Harry, not to bother me any more with her charity appeals. I am sick of them. Why, the good woman thinks that I have nothing to do but to write cheques for her silly fads." "All right, Uncle George, I'll tell her, but it won't have any effect. Philanthropic people lose all sense of humanity. It is their distinguishing characteristic." The old gentleman growled approvingly and rang the bell for his servant. Lord Henry passed up the low arcade into Burlington Street and turned his steps in the direction of Berkeley Square. So that was the story of Dorian Gray's parentage. Crudely as it had been told to him, it had yet stirred him by its suggestion of a strange, almost modern romance. A beautiful woman risking everything for a mad passion. A few wild weeks of happiness cut short by a hideous, treacherous crime. Months of voiceless agony, and then a child born in pain. The mother snatched away by death, the boy left to solitude and the tyranny of an old and loveless man. Yes; it was an interesting background. It posed the lad, made him more perfect, as it were. Behind every exquisite thing that existed, there was something tragic. Worlds had to be in travail, that the meanest flower might blow. . . . And how charming he had been at dinner the night before, as with startled eyes and lips parted in frightened pleasure he had sat opposite to him at the club, the red candleshades staining to a richer rose the wakening wonder of his face. Talking to him was like playing upon an exquisite violin. He answered to every touch and thrill of the bow. . . . There was something terribly enthralling in the exercise of influence. No other activity was like it. To project one's soul into some gracious form, and let it tarry there for a moment; to hear one's own intellectual views echoed back to one with all the added music of passion and youth; to convey one's temperament into another as though it were a subtle fluid or a strange perfume: there was a real joy in that--perhaps the most satisfying joy left to us in an age so limited and vulgar as our own, an age grossly carnal in its pleasures, and grossly common in its aims.... He was a marvellous type, too, this lad, whom by so curious a chance he had met in Basil's studio, or could be fashioned into a marvellous type, at any rate. Grace was his, and the white purity of boyhood, and beauty such as old Greek marbles kept for us. There was nothing that one could not do with him. He could be made a Titan or a toy. What a pity it was that such beauty was destined to fade! . . . And Basil? From a psychological point of view, how interesting he was! The new manner in art, the fresh mode of looking at life, suggested so strangely by the merely visible presence of one who was unconscious of it all; the silent spirit that dwelt in dim woodland, and walked unseen in open field, suddenly showing herself, Dryadlike and not afraid, because in his soul who sought for her there had been wakened that wonderful vision to which alone are wonderful things revealed; the mere shapes and patterns of things becoming, as it were, refined, and gaining a kind of symbolical value, as though they were themselves patterns of some other and more perfect form whose shadow they made real: how strange it all was! He remembered something like it in history. Was it not Plato, that artist in thought, who had first analyzed it? Was it not Buonarotti who had carved it in the coloured marbles of a sonnet-sequence? But in our own century it was strange. . . . Yes; he would try to be to Dorian Gray what, without knowing it, the lad was to the painter who had fashioned the wonderful portrait. He would seek to dominate him--had already, indeed, half done so. He would make that wonderful spirit his own. There was something fascinating in this son of love and death. Suddenly he stopped and glanced up at the houses. He found that he had passed his aunt's some distance, and, smiling to himself, turned back. When he entered the somewhat sombre hall, the butler told him that they had gone in to lunch. He gave one of the footmen his hat and stick and passed into the dining-room. "Late as usual, Harry," cried his aunt, shaking her head at him. He invented a facile excuse, and having taken the vacant seat next to her, looked round to see who was there. Dorian bowed to him shyly from the end of the table, a flush of pleasure stealing into his cheek. Opposite was the Duchess of Harley, a lady of admirable good-nature and good temper, much liked by every one who knew her, and of those ample architectural proportions that in women who are not duchesses are described by contemporary historians as stoutness. Next to her sat, on her right, Sir Thomas Burdon, a Radical member of Parliament, who followed his leader in public life and in private life followed the best cooks, dining with the Tories and thinking with the Liberals, in accordance with a wise and well-known rule. The post on her left was occupied by Mr. Erskine of Treadley, an old gentleman of considerable charm and culture, who had fallen, however, into bad habits of silence, having, as he explained once to Lady Agatha, said everything that he had to say before he was thirty. His own neighbour was Mrs. Vandeleur, one of his aunt's oldest friends, a perfect saint amongst women, but so dreadfully dowdy that she reminded one of a badly bound hymn-book. Fortunately for him she had on the other side Lord Faudel, a most intelligent middle-aged mediocrity, as bald as a ministerial statement in the House of Commons, with whom she was conversing in that intensely earnest manner which is the one unpardonable error, as he remarked once himself, that all really good people fall into, and from which none of them ever quite escape. "We are talking about poor Dartmoor, Lord Henry," cried the duchess, nodding pleasantly to him across the table. "Do you think he will really marry this fascinating young person?" "I believe she has made up her mind to propose to him, Duchess." "How dreadful!" exclaimed Lady Agatha. "Really, some one should interfere." "I am told, on excellent authority, that her father keeps an American dry-goods store," said Sir Thomas Burdon, looking supercilious. "My uncle has already suggested pork-packing Sir Thomas." "Dry-goods! What are American dry-goods?" asked the duchess, raising her large hands in wonder and accentuating the verb. "American novels," answered Lord Henry, helping himself to some quail. The duchess looked puzzled. "Don't mind him, my dear," whispered Lady Agatha. "He never means anything that he says." "When America was discovered," said the Radical member-- and he began to give some wearisome facts. Like all people who try to exhaust a subject, he exhausted his listeners. The duchess sighed and exercised her privilege of interruption. "I wish to goodness it never had been discovered at all!" she exclaimed. "Really, our girls have no chance nowadays. It is most unfair." "Perhaps, after all, America never has been discovered," said Mr. Erskine; "I myself would say that it had merely been detected." "Oh! but I have seen specimens of the inhabitants," answered the duchess vaguely. "I must confess that most of them are extremely pretty. And they dress well, too. They get all their dresses in Paris. I wish I could afford to do the same." "They say that when good Americans die they go to Paris," chuckled Sir Thomas, who had a large wardrobe of Humour's cast-off clothes. "Really! And where do bad Americans go to when they die?" inquired the duchess. "They go to America," murmured Lord Henry. Sir Thomas frowned. "I am afraid that your nephew is prejudiced against that great country," he said to Lady Agatha. "I have travelled all over it in cars provided by the directors, who, in such matters, are extremely civil. I assure you that it is an education to visit it." "But must we really see Chicago in order to be educated?" asked Mr. Erskine plaintively. "I don't feel up to the journey." Sir Thomas waved his hand. "Mr. Erskine of Treadley has the world on his shelves. We practical men like to see things, not to read about them. The Americans are an extremely interesting people. They are absolutely reasonable. I think that is their distinguishing characteristic. Yes, Mr. Erskine, an absolutely reasonable people. I assure you there is no nonsense about the Americans." "How dreadful!" cried Lord Henry. "I can stand brute force, but brute reason is quite unbearable. There is something unfair about its use. It is hitting below the intellect." "I do not understand you," said Sir Thomas, growing rather red. "I do, Lord Henry," murmured Mr. Erskine, with a smile. "Paradoxes are all very well in their way... ." rejoined the baronet. "Was that a paradox?" asked Mr. Erskine. "I did not think so. Perhaps it was. Well, the way of paradoxes is the way of truth. To test reality we must see it on the tight rope. When the verities become acrobats, we can judge them." "Dear me!" said Lady Agatha, "how you men argue! I am sure I never can make out what you are talking about. Oh! Harry, I am quite vexed with you. Why do you try to persuade our nice Mr. Dorian Gray to give up the East End? I assure you he would be quite invaluable. They would love his playing." "I want him to play to me," cried Lord Henry, smiling, and he looked down the table and caught a bright answering glance. "But they are so unhappy in Whitechapel," continued Lady Agatha. "I can sympathize with everything except suffering," said Lord Henry, shrugging his shoulders. "I cannot sympathize with that. It is too ugly, too horrible, too distressing. There is something terribly morbid in the modern sympathy with pain. One should sympathize with the colour, the beauty, the joy of life. The less said about life's sores, the better." "Still, the East End is a very important problem," remarked Sir Thomas with a grave shake of the head. "Quite so," answered the young lord. "It is the problem of slavery, and we try to solve it by amusing the slaves." The politician looked at him keenly. "What change do you propose, then?" he asked. Lord Henry laughed. "I don't desire to change anything in England except the weather," he answered. "I am quite content with philosophic contemplation. But, as the nineteenth century has gone bankrupt through an over-expenditure of sympathy, I would suggest that we should appeal to science to put us straight. The advantage of the emotions is that they lead us astray, and the advantage of science is that it is not emotional." "But we have such grave responsibilities," ventured Mrs. Vandeleur timidly. "Terribly grave," echoed Lady Agatha. Lord Henry looked over at Mr. Erskine. "Humanity takes itself too seriously. It is the world's original sin. If the caveman had known how to laugh, history would have been different." "You are really very comforting," warbled the duchess. "I have always felt rather guilty when I came to see your dear aunt, for I take no interest at all in the East End. For the future I shall be able to look her in the face without a blush." "A blush is very becoming, Duchess," remarked Lord Henry. "Only when one is young," she answered. "When an old woman like myself blushes, it is a very bad sign. Ah! Lord Henry, I wish you would tell me how to become young again." He thought for a moment. "Can you remember any great error that you committed in your early days, Duchess?" he asked, looking at her across the table. "A great many, I fear," she cried. "Then commit them over again," he said gravely. "To get back one's youth, one has merely to repeat one's follies." "A delightful theory!" she exclaimed. "I must put it into practice." "A dangerous theory!" came from Sir Thomas's tight lips. Lady Agatha shook her head, but could not help being amused. Mr. Erskine listened. "Yes," he continued, "that is one of the great secrets of life. Nowadays most people die of a sort of creeping common sense, and discover when it is too late that the only things one never regrets are one's mistakes." A laugh ran round the table. He played with the idea and grew wilful; tossed it into the air and transformed it; let it escape and recaptured it; made it iridescent with fancy and winged it with paradox. The praise of folly, as he went on, soared into a philosophy, and philosophy herself became young, and catching the mad music of pleasure, wearing, one might fancy, her wine-stained robe and wreath of ivy, danced like a Bacchante over the hills of life, and mocked the slow Silenus for being sober. Facts fled before her like frightened forest things. Her white feet trod the huge press at which wise Omar sits, till the seething grape-juice rose round her bare limbs in waves of purple bubbles, or crawled in red foam over the vat's black, dripping, sloping sides. It was an extraordinary improvisation. He felt that the eyes of Dorian Gray were fixed on him, and the consciousness that amongst his audience there was one whose temperament he wished to fascinate seemed to give his wit keenness and to lend colour to his imagination. He was brilliant, fantastic, irresponsible. He charmed his listeners out of themselves, and they followed his pipe, laughing. Dorian Gray never took his gaze off him, but sat like one under a spell, smiles chasing each other over his lips and wonder growing grave in his darkening eyes. At last, liveried in the costume of the age, reality entered the room in the shape of a servant to tell the duchess that her carriage was waiting. She wrung her hands in mock despair. "How annoying!" she cried. "I must go. I have to call for my husband at the club, to take him to some absurd meeting at Willis's Rooms, where he is going to be in the chair. If I am late he is sure to be furious, and I couldn't have a scene in this bonnet. It is far too fragile. A harsh word would ruin it. No, I must go, dear Agatha. Good-bye, Lord Henry, you are quite delightful and dreadfully demoralizing. I am sure I don't know what to say about your views. You must come and dine with us some night. Tuesday? Are you disengaged Tuesday?" "For you I would throw over anybody, Duchess," said Lord Henry with a bow. "Ah! that is very nice, and very wrong of you," she cried; "so mind you come"; and she swept out of the room, followed by Lady Agatha and the other ladies. When Lord Henry had sat down again, Mr. Erskine moved round, and taking a chair close to him, placed his hand upon his arm. "You talk books away," he said; "why don't you write one?" "I am too fond of reading books to care to write them, Mr. Erskine. I should like to write a novel certainly, a novel that would be as lovely as a Persian carpet and as unreal. But there is no literary public in England for anything except newspapers, primers, and encyclopaedias. Of all people in the world the English have the least sense of the beauty of literature." "I fear you are right," answered Mr. Erskine. "I myself used to have literary ambitions, but I gave them up long ago. And now, my dear young friend, if you will allow me to call you so, may I ask if you really meant all that you said to us at lunch?" "I quite forget what I said," smiled Lord Henry. "Was it all very bad?" "Very bad indeed. In fact I consider you extremely dangerous, and if anything happens to our good duchess, we shall all look on you as being primarily responsible. But I should like to talk to you about life. The generation into which I was born was tedious. Some day, when you are tired of London, come down to Treadley and expound to me your philosophy of pleasure over some admirable Burgundy I am fortunate enough to possess." "I shall be charmed. A visit to Treadley would be a great privilege. It has a perfect host, and a perfect library." "You will complete it," answered the old gentleman with a courteous bow. "And now I must bid good-bye to your excellent aunt. I am due at the Athenaeum. It is the hour when we sleep there." "All of you, Mr. Erskine?" "Forty of us, in forty arm-chairs. We are practising for an English Academy of Letters." Lord Henry laughed and rose. "I am going to the park," he cried. As he was passing out of the door, Dorian Gray touched him on the arm. "Let me come with you," he murmured. "But I thought you had promised Basil Hallward to go and see him," answered Lord Henry. "I would sooner come with you; yes, I feel I must come with you. Do let me. And you will promise to talk to me all the time? No one talks so wonderfully as you do." "Ah! I have talked quite enough for to-day," said Lord Henry, smiling. "All I want now is to look at life. You may come and look at it with me, if you care to." CHAPTER 4 One afternoon, a month later, Dorian Gray was reclining in a luxurious arm-chair, in the little library of Lord Henry's house in Mayfair. It was, in its way, a very charming room, with its high panelled wainscoting of olive-stained oak, its cream-coloured frieze and ceiling of raised plasterwork, and its brickdust felt carpet strewn with silk, long-fringed Persian rugs. On a tiny satinwood table stood a statuette by Clodion, and beside it lay a copy of Les Cent Nouvelles, bound for Margaret of Valois by Clovis Eve and powdered with the gilt daisies that Queen had selected for her device. Some large blue china jars and parrot-tulips were ranged on the mantelshelf, and through the small leaded panes of the window streamed the apricot-coloured light of a summer day in London. Lord Henry had not yet come in. He was always late on principle, his principle being that punctuality is the thief of time. So the lad was looking rather sulky, as with listless fingers he turned over the pages of an elaborately illustrated edition of Manon Lescaut that he had found in one of the book-cases. The formal monotonous ticking of the Louis Quatorze clock annoyed him. Once or twice he thought of going away. At last he heard a step outside, and the door opened. "How late you are, Harry!" he murmured. "I am afraid it is not Harry, Mr. Gray," answered a shrill voice. He glanced quickly round and rose to his feet. "I beg your pardon. I thought--" "You thought it was my husband. It is only his wife. You must let me introduce myself. I know you quite well by your photographs. I think my husband has got seventeen of them." "Not seventeen, Lady Henry?" "Well, eighteen, then. And I saw you with him the other night at the opera." She laughed nervously as she spoke, and watched him with her vague forget-me-not eyes. She was a curious woman, whose dresses always looked as if they had been designed in a rage and put on in a tempest. She was usually in love with somebody, and, as her passion was never returned, she had kept all her illusions. She tried to look picturesque, but only succeeded in being untidy. Her name was Victoria, and she had a perfect mania for going to church. "That was at Lohengrin, Lady Henry, I think?" "Yes; it was at dear Lohengrin. I like Wagner's music better than anybody's. It is so loud that one can talk the whole time without other people hearing what one says. That is a great advantage, don't you think so, Mr. Gray?" The same nervous staccato laugh broke from her thin lips, and her fingers began to play with a long tortoise-shell paper-knife. Dorian smiled and shook his head: "I am afraid I don't think so, Lady Henry. I never talk during music--at least, during good music. If one hears bad music, it is one's duty to drown it in conversation." "Ah! that is one of Harry's views, isn't it, Mr. Gray? I always hear Harry's views from his friends. It is the only way I get to know of them. But you must not think I don't like good music. I adore it, but I am afraid of it. It makes me too romantic. I have simply worshipped pianists-- two at a time, sometimes, Harry tells me. I don't know what it is about them. Perhaps it is that they are foreigners. They all are, ain't they? Even those that are born in England become foreigners after a time, don't they? It is so clever of them, and such a compliment to art. Makes it quite cosmopolitan, doesn't it? You have never been to any of my parties, have you, Mr. Gray? You must come. I can't afford orchids, but I share no expense in foreigners. They make one's rooms look so picturesque. But here is Harry! Harry, I came in to look for you, to ask you something-- I forget what it was--and I found Mr. Gray here. We have had such a pleasant chat about music. We have quite the same ideas. No; I think our ideas are quite different. But he has been most pleasant. I am so glad I've seen him." "I am charmed, my love, quite charmed," said Lord Henry, elevating his dark, crescent-shaped eyebrows and looking at them both with an amused smile. "So sorry I am late, Dorian. I went to look after a piece of old brocade in Wardour Street and had to bargain for hours for it. Nowadays people know the price of everything and the value of nothing." "I am afraid I must be going," exclaimed Lady Henry, breaking an awkward silence with her silly sudden laugh. "I have promised to drive with the duchess. Good-bye, Mr. Gray. Good-bye, Harry. You are dining out, I suppose? So am I. Perhaps I shall see you at Lady Thornbury's." "I dare say, my dear," said Lord Henry, shutting the door behind her as, looking like a bird of paradise that had been out all night in the rain, she flitted out of the room, leaving a faint odour of frangipanni. Then he lit a cigarette and flung himself down on the sofa. "Never marry a woman with straw-coloured hair, Dorian," he said after a few puffs. "Why, Harry?" "Because they are so sentimental." "But I like sentimental people." "Never marry at all, Dorian. Men marry because they are tired; women, because they are curious: both are disappointed." "I don't think I am likely to marry, Harry. I am too much in love. That is one of your aphorisms. I am putting it into practice, as I do everything that you say." "Who are you in love with?" asked Lord Henry after a pause. "With an actress," said Dorian Gray, blushing. Lord Henry shrugged his shoulders. "That is a rather commonplace debut." "You would not say so if you saw her, Harry." "Who is she?" "Her name is Sibyl Vane." "Never heard of her." "No one has. People will some day, however. She is a genius." "My dear boy, no woman is a genius. Women are a decorative sex. They never have anything to say, but they say it charmingly. Women represent the triumph of matter over mind, just as men represent the triumph of mind over morals." "Harry, how can you?" "My dear Dorian, it is quite true. I am analysing women at present, so I ought to know. The subject is not so abstruse as I thought it was. I find that, ultimately, there are only two kinds of women, the plain and the coloured. The plain women are very useful. If you want to gain a reputation for respectability, you have merely to take them down to supper. The other women are very charming. They commit one mistake, however. They paint in order to try and look young. Our grandmothers painted in order to try and talk brilliantly. Rouge and esprit used to go together. That is all over now. As long as a woman can look ten years younger than her own daughter, she is perfectly satisfied. As for conversation, there are only five women in London worth talking to, and two of these can't be admitted into decent society. However, tell me about your genius. How long have you known her?" "Ah! Harry, your views terrify me." "Never mind that. How long have you known her?" "About three weeks." "And where did you come across her?" "I will tell you, Harry, but you mustn't be unsympathetic about it. After all, it never would have happened if I had not met you. You filled me with a wild desire to know everything about life. For days after I met you, something seemed to throb in my veins. As I lounged in the park, or strolled down Piccadilly, I used to look at every one who passed me and wonder, with a mad curiosity, what sort of lives they led. Some of them fascinated me. Others filled me with terror. There was an exquisite poison in the air. I had a passion for sensations. . . . Well, one evening about seven o'clock, I determined to go out in search of some adventure. I felt that this grey monstrous London of ours, with its myriads of people, its sordid sinners, and its splendid sins, as you once phrased it, must have something in store for me. I fancied a thousand things. The mere danger gave me a sense of delight. I remembered what you had said to me on that wonderful evening when we first dined together, about the search for beauty being the real secret of life. I don't know what I expected, but I went out and wandered eastward, soon losing my way in a labyrinth of grimy streets and black grassless squares. About half-past eight I passed by an absurd little theatre, with great flaring gas-jets and gaudy play-bills. A hideous Jew, in the most amazing waistcoat I ever beheld in my life, was standing at the entrance, smoking a vile cigar. He had greasy ringlets, and an enormous diamond blazed in the centre of a soiled shirt. 'Have a box, my Lord?' he said, when he saw me, and he took off his hat with an air of gorgeous servility. There was something about him, Harry, that amused me. He was such a monster. You will laugh at me, I know, but I really went in and paid a whole guinea for the stage-box. To the present day I can't make out why I did so; and yet if I hadn't-- my dear Harry, if I hadn't--I should have missed the greatest romance of my life. I see you are laughing. It is horrid of you!" "I am not laughing, Dorian; at least I am not laughing at you. But you should not say the greatest romance of your life. You should say the first romance of your life. You will always be loved, and you will always be in love with love. A grande passion is the privilege of people who have nothing to do. That is the one use of the idle classes of a country. Don't be afraid. There are exquisite things in store for you. This is merely the beginning." "Do you think my nature so shallow?" cried Dorian Gray angrily. "No; I think your nature so deep." "How do you mean?" "My dear boy, the people who love only once in their lives are really the shallow people. What they call their loyalty, and their fidelity, I call either the lethargy of custom or their lack of imagination. Faithfulness is to the emotional life what consistency is to the life of the intellect--simply a confession of failure. Faithfulness! I must analyse it some day. The passion for property is in it. There are many things that we would throw away if we were not afraid that others might pick them up. But I don't want to interrupt you. Go on with your story." "Well, I found myself seated in a horrid little private box, with a vulgar drop-scene staring me in the face. I looked out from behind the curtain and surveyed the house. It was a tawdry affair, all Cupids and cornucopias, like a third-rate wedding-cake. The gallery and pit were fairly full, but the two rows of dingy stalls were quite empty, and there was hardly a person in what I suppose they called the dress-circle. Women went about with oranges and ginger-beer, and there was a terrible consumption of nuts going on." "It must have been just like the palmy days of the British drama." "Just like, I should fancy, and very depressing. I began to wonder what on earth I should do when I caught sight of the play-bill. What do you think the play was, Harry?" "I should think 'The Idiot Boy', or 'Dumb but Innocent'. Our fathers used to like that sort of piece, I believe. The longer I live, Dorian, the more keenly I feel that whatever was good enough for our fathers is not good enough for us. In art, as in politics, les grandperes ont toujours tort." "This play was good enough for us, Harry. It was Romeo and Juliet. I must admit that I was rather annoyed at the idea of seeing Shakespeare done in such a wretched hole of a place. Still, I felt interested, in a sort of way. At any rate, I determined to wait for the first act. There was a dreadful orchestra, presided over by a young Hebrew who sat at a cracked piano, that nearly drove me away, but at last the drop-scene was drawn up and the play began. Romeo was a stout elderly gentleman, with corked eyebrows, a husky tragedy voice, and a figure like a beer-barrel. Mercutio was almost as bad. He was played by the low-comedian, who had introduced gags of his own and was on most friendly terms with the pit. They were both as grotesque as the scenery, and that looked as if it had come out of a country-booth. But Juliet! Harry, imagine a girl, hardly seventeen years of age, with a little, flowerlike face, a small Greek head with plaited coils of dark-brown hair, eyes that were violet wells of passion, lips that were like the petals of a rose. She was the loveliest thing I had ever seen in my life. You said to me once that pathos left you unmoved, but that beauty, mere beauty, could fill your eyes with tears. I tell you, Harry, I could hardly see this girl for the mist of tears that came across me. And her voice--I never heard such a voice. It was very low at first, with deep mellow notes that seemed to fall singly upon one's ear. Then it became a little louder, and sounded like a flute or a distant hautboy. In the garden-scene it had all the tremulous ecstasy that one hears just before dawn when nightingales are singing. There were moments, later on, when it had the wild passion of violins. You know how a voice can stir one. Your voice and the voice of Sibyl Vane are two things that I shall never forget. When I close my eyes, I hear them, and each of them says something different. I don't know which to follow. Why should I not love her? Harry, I do love her. She is everything to me in life. Night after night I go to see her play. One evening she is Rosalind, and the next evening she is Imogen. I have seen her die in the gloom of an Italian tomb, sucking the poison from her lover's lips. I have watched her wandering through the forest of Arden, disguised as a pretty boy in hose and doublet and dainty cap. She has been mad, and has come into the presence of a guilty king, and given him rue to wear and bitter herbs to taste of. She has been innocent, and the black hands of jealousy have crushed her reedlike throat. I have seen her in every age and in every costume. Ordinary women never appeal to one's imagination. They are limited to their century. No glamour ever transfigures them. One knows their minds as easily as one knows their bonnets. One can always find them. There is no mystery in any of them. They ride in the park in the morning and chatter at tea-parties in the afternoon. They have their stereotyped smile and their fashionable manner. They are quite obvious. But an actress! How different an actress is! Harry! why didn't you tell me that the only thing worth loving is an actress?" "Because I have loved so many of them, Dorian." "Oh, yes, horrid people with dyed hair and painted faces." "Don't run down dyed hair and painted faces. There is an extraordinary charm in them, sometimes," said Lord Henry. "I wish now I had not told you about Sibyl Vane." "You could not have helped telling me, Dorian. All through your life you will tell me everything you do." "Yes, Harry, I believe that is true. I cannot help telling you things. You have a curious influence over me. If I ever did a crime, I would come and confess it to you. You would understand me." "People like you--the wilful sunbeams of life--don't commit crimes, Dorian. But I am much obliged for the compliment, all the same. And now tell me-- reach me the matches, like a good boy--thanks--what are your actual relations with Sibyl Vane?" Dorian Gray leaped to his feet, with flushed cheeks and burning eyes. "Harry! Sibyl Vane is sacred!" "It is only the sacred things that are worth touching, Dorian," said Lord Henry, with a strange touch of pathos in his voice. "But why should you be annoyed? I suppose she will belong to you some day. When one is in love, one always begins by deceiving one's self, and one always ends by deceiving others. That is what the world calls a romance. You know her, at any rate, I suppose?" "Of course I know her. On the first night I was at the theatre, the horrid old Jew came round to the box after the performance was over and offered to take me behind the scenes and introduce me to her. I was furious with him, and told him that Juliet had been dead for hundreds of years and that her body was lying in a marble tomb in Verona. I think, from his blank look of amazement, that he was under the impression that I had taken too much champagne, or something." "I am not surprised." "Then he asked me if I wrote for any of the newspapers. I told him I never even read them. He seemed terribly disappointed at that, and confided to me that all the dramatic critics were in a conspiracy against him, and that they were every one of them to be bought." "I should not wonder if he was quite right there. But, on the other hand, judging from their appearance, most of them cannot be at all expensive." "Well, he seemed to think they were beyond his means," laughed Dorian. "By this time, however, the lights were being put out in the theatre, and I had to go. He wanted me to try some cigars that he strongly recommended. I declined. The next night, of course, I arrived at the place again. When he saw me, he made me a low bow and assured me that I was a munificent patron of art. He was a most offensive brute, though he had an extraordinary passion for Shakespeare. He told me once, with an air of pride, that his five bankruptcies were entirely due to 'The Bard,' as he insisted on calling him. He seemed to think it a distinction." "It was a distinction, my dear Dorian--a great distinction. Most people become bankrupt through having invested too heavily in the prose of life. To have ruined one's self over poetry is an honour. But when did you first speak to Miss Sibyl Vane?" "The third night. She had been playing Rosalind. I could not help going round. I had thrown her some flowers, and she had looked at me--at least I fancied that she had. The old Jew was persistent. He seemed determined to take me behind, so I consented. It was curious my not wanting to know her, wasn't it?" "No; I don't think so." "My dear Harry, why?" "I will tell you some other time. Now I want to know about the girl." "Sibyl? Oh, she was so shy and so gentle. There is something of a child about her. Her eyes opened wide in exquisite wonder when I told her what I thought of her performance, and she seemed quite unconscious of her power. I think we were both rather nervous. The old Jew stood grinning at the doorway of the dusty greenroom, making elaborate speeches about us both, while we stood looking at each other like children. He would insist on calling me 'My Lord,' so I had to assure Sibyl that I was not anything of the kind. She said quite simply to me, 'You look more like a prince. I must call you Prince Charming.'" "Upon my word, Dorian, Miss Sibyl knows how to pay compliments." "You don't understand her, Harry. She regarded me merely as a person in a play. She knows nothing of life. She lives with her mother, a faded tired woman who played Lady Capulet in a sort of magenta dressing-wrapper on the first night, and looks as if she had seen better days." "I know that look. It depresses me," murmured Lord Henry, examining his rings. "The Jew wanted to tell me her history, but I said it did not interest me." "You were quite right. There is always something infinitely mean about other people's tragedies." "Sibyl is the only thing I care about. What is it to me where she came from? From her little head to her little feet, she is absolutely and entirely divine. Every night of my life I go to see her act, and every night she is more marvellous." "That is the reason, I suppose, that you never dine with me now. I thought you must have some curious romance on hand. You have; but it is not quite what I expected." "My dear Harry, we either lunch or sup together every day, and I have been to the opera with you several times," said Dorian, opening his blue eyes in wonder. "You always come dreadfully late." "Well, I can't help going to see Sibyl play," he cried, "even if it is only for a single act. I get hungry for her presence; and when I think of the wonderful soul that is hidden away in that little ivory body, I am filled with awe." "You can dine with me to-night, Dorian, can't you?" He shook his head. "To-night she is Imogen," he answered, "and to-morrow night she will be Juliet." "When is she Sibyl Vane?" "Never." "I congratulate you." "How horrid you are! She is all the great heroines of the world in one. She is more than an individual. You laugh, but I tell you she has genius. I love her, and I must make her love me. You, who know all the secrets of life, tell me how to charm Sibyl Vane to love me! I want to make Romeo jealous. I want the dead lovers of the world to hear our laughter and grow sad. I want a breath of our passion to stir their dust into consciousness, to wake their ashes into pain. My God, Harry, how I worship her!" He was walking up and down the room as he spoke. Hectic spots of red burned on his cheeks. He was terribly excited. Lord Henry watched him with a subtle sense of pleasure. How different he was now from the shy frightened boy he had met in Basil Hallward's studio! His nature had developed like a flower, had borne blossoms of scarlet flame. Out of its secret hiding-place had crept his soul, and desire had come to meet it on the way. "And what do you propose to do?" said Lord Henry at last. "I want you and Basil to come with me some night and see her act. I have not the slightest fear of the result. You are certain to acknowledge her genius. Then we must get her out of the Jew's hands. She is bound to him for three years--at least for two years and eight months-- from the present time. I shall have to pay him something, of course. When all that is settled, I shall take a West End theatre and bring her out properly. She will make the world as mad as she has made me." "That would be impossible, my dear boy." "Yes, she will. She has not merely art, consummate art-instinct, in her, but she has personality also; and you have often told me that it is personalities, not principles, that move the age." "Well, what night shall we go?" "Let me see. To-day is Tuesday. Let us fix to-morrow. She plays Juliet to-morrow." "All right. The Bristol at eight o'clock; and I will get Basil." "Not eight, Harry, please. Half-past six. We must be there before the curtain rises. You must see her in the first act, where she meets Romeo." "Half-past six! What an hour! It will be like having a meat-tea, or reading an English novel. It must be seven. No gentleman dines before seven. Shall you see Basil between this and then? Or shall I write to him?" "Dear Basil! I have not laid eyes on him for a week. It is rather horrid of me, as he has sent me my portrait in the most wonderful frame, specially designed by himself, and, though I am a little jealous of the picture for being a whole month younger than I am, I must admit that I delight in it. Perhaps you had better write to him. I don't want to see him alone. He says things that annoy me. He gives me good advice." Lord Henry smiled. "People are very fond of giving away what they need most themselves. It is what I call the depth of generosity." "Oh, Basil is the best of fellows, but he seems to me to be just a bit of a Philistine. Since I have known you, Harry, I have discovered that." "Basil, my dear boy, puts everything that is charming in him into his work. The consequence is that he has nothing left for life but his prejudices, his principles, and his common sense. The only artists I have ever known who are personally delightful are bad artists. Good artists exist simply in what they make, and consequently are perfectly uninteresting in what they are. A great poet, a really great poet, is the most unpoetical of all creatures. But inferior poets are absolutely fascinating. The worse their rhymes are, the more picturesque they look. The mere fact of having published a book of second-rate sonnets makes a man quite irresistible. He lives the poetry that he cannot write. The others write the poetry that they dare not realize." "I wonder is that really so, Harry?" said Dorian Gray, putting some perfume on his handkerchief out of a large, gold-topped bottle that stood on the table. "It must be, if you say it. And now I am off. Imogen is waiting for me. Don't forget about to-morrow. Good-bye." As he left the room, Lord Henry's heavy eyelids drooped, and he began to think. Certainly few people had ever interested him so much as Dorian Gray, and yet the lad's mad adoration of some one else caused him not the slightest pang of annoyance or jealousy. He was pleased by it. It made him a more interesting study. He had been always enthralled by the methods of natural science, but the ordinary subject-matter of that science had seemed to him trivial and of no import. And so he had begun by vivisecting himself, as he had ended by vivisecting others. Human life--that appeared to him the one thing worth investigating. Compared to it there was nothing else of any value. It was true that as one watched life in its curious crucible of pain and pleasure, one could not wear over one's face a mask of glass, nor keep the sulphurous fumes from troubling the brain and making the imagination turbid with monstrous fancies and misshapen dreams. There were poisons so subtle that to know their properties one had to sicken of them. There were maladies so strange that one had to pass through them if one sought to understand their nature. And, yet, what a great reward one received! How wonderful the whole world became to one! To note the curious hard logic of passion, and the emotional coloured life of the intellect--to observe where they met, and where they separated, at what point they were in unison, and at what point they were at discord--there was a delight in that! What matter what the cost was? One could never pay too high a price for any sensation. He was conscious--and the thought brought a gleam of pleasure into his brown agate eyes--that it was through certain words of his, musical words said with musical utterance, that Dorian Gray's soul had turned to this white girl and bowed in worship before her. To a large extent the lad was his own creation. He had made him premature. That was something. Ordinary people waited till life disclosed to them its secrets, but to the few, to the elect, the mysteries of life were revealed before the veil was drawn away. Sometimes this was the effect of art, and chiefly of the art of literature, which dealt immediately with the passions and the intellect. But now and then a complex personality took the place and assumed the office of art, was indeed, in its way, a real work of art, life having its elaborate masterpieces, just as poetry has, or sculpture, or painting. Yes, the lad was premature. He was gathering his harvest while it was yet spring. The pulse and passion of youth were in him, but he was becoming self-conscious. It was delightful to watch him. With his beautiful face, and his beautiful soul, he was a thing to wonder at. It was no matter how it all ended, or was destined to end. He was like one of those gracious figures in a pageant or a play, whose joys seem to be remote from one, but whose sorrows stir one's sense of beauty, and whose wounds are like red roses. Soul and body, body and soul--how mysterious they were! There was animalism in the soul, and the body had its moments of spirituality. The senses could refine, and the intellect could degrade. Who could say where the fleshly impulse ceased, or the psychical impulse began? How shallow were the arbitrary definitions of ordinary psychologists! And yet how difficult to decide between the claims of the various schools! Was the soul a shadow seated in the house of sin? Or was the body really in the soul, as Giordano Bruno thought? The separation of spirit from matter was a mystery, and the union of spirit with matter was a mystery also. He began to wonder whether we could ever make psychology so absolute a science that each little spring of life would be revealed to us. As it was, we always misunderstood ourselves and rarely understood others. Experience was of no ethical value. It was merely the name men gave to their mistakes. Moralists had, as a rule, regarded it as a mode of warning, had claimed for it a certain ethical efficacy in the formation of character, had praised it as something that taught us what to follow and showed us what to avoid. But there was no motive power in experience. It was as little of an active cause as conscience itself. All that it really demonstrated was that our future would be the same as our past, and that the sin we had done once, and with loathing, we would do many times, and with joy. It was clear to him that the experimental method was the only method by which one could arrive at any scientific analysis of the passions; and certainly Dorian Gray was a subject made to his hand, and seemed to promise rich and fruitful results. His sudden mad love for Sibyl Vane was a psychological phenomenon of no small interest. There was no doubt that curiosity had much to do with it, curiosity and the desire for new experiences, yet it was not a simple, but rather a very complex passion. What there was in it of the purely sensuous instinct of boyhood had been transformed by the workings of the imagination, changed into something that seemed to the lad himself to be remote from sense, and was for that very reason all the more dangerous. It was the passions about whose origin we deceived ourselves that tyrannized most strongly over us. Our weakest motives were those of whose nature we were conscious. It often happened that when we thought we were experimenting on others we were really experimenting on ourselves. While Lord Henry sat dreaming on these things, a knock came to the door, and his valet entered and reminded him it was time to dress for dinner. He got up and looked out into the street. The sunset had smitten into scarlet gold the upper windows of the houses opposite. The panes glowed like plates of heated metal. The sky above was like a faded rose. He thought of his friend's young fiery-coloured life and wondered how it was all going to end. When he arrived home, about half-past twelve o'clock, he saw a telegram lying on the hall table. He opened it and found it was from Dorian Gray. It was to tell him that he was engaged to be married to Sibyl Vane. CHAPTER 5 "Mother, Mother, I am so happy!" whispered the girl, burying her face in the lap of the faded, tired-looking woman who, with back turned to the shrill intrusive light, was sitting in the one arm-chair that their dingy sitting-room contained. "I am so happy!" she repeated, "and you must be happy, too!" Mrs. Vane winced and put her thin, bismuth-whitened hands on her daughter's head. "Happy!" she echoed, "I am only happy, Sibyl, when I see you act. You must not think of anything but your acting. Mr. Isaacs has been very good to us, and we owe him money." The girl looked up and pouted. "Money, Mother?" she cried, "what does money matter? Love is more than money." "Mr. Isaacs has advanced us fifty pounds to pay off our debts and to get a proper outfit for James. You must not forget that, Sibyl. Fifty pounds is a very large sum. Mr. Isaacs has been most considerate." "He is not a gentleman, Mother, and I hate the way he talks to me," said the girl, rising to her feet and going over to the window. "I don't know how we could manage without him," answered the elder woman querulously. Sibyl Vane tossed her head and laughed. "We don't want him any more, Mother. Prince Charming rules life for us now." Then she paused. A rose shook in her blood and shadowed her cheeks. Quick breath parted the petals of her lips. They trembled. Some southern wind of passion swept over her and stirred the dainty folds of her dress. "I love him," she said simply. "Foolish child! foolish child!" was the parrot-phrase flung in answer. The waving of crooked, false-jewelled fingers gave grotesqueness to the words. The girl laughed again. The joy of a caged bird was in her voice. Her eyes caught the melody and echoed it in radiance, then closed for a moment, as though to hide their secret. When they opened, the mist of a dream had passed across them. Thin-lipped wisdom spoke at her from the worn chair, hinted at prudence, quoted from that book of cowardice whose author apes the name of common sense. She did not listen. She was free in her prison of passion. Her prince, Prince Charming, was with her. She had called on memory to remake him. She had sent her soul to search for him, and it had brought him back. His kiss burned again upon her mouth. Her eyelids were warm with his breath. Then wisdom altered its method and spoke of espial and discovery. This young man might be rich. If so, marriage should be thought of. Against the shell of her ear broke the waves of worldly cunning. The arrows of craft shot by her. She saw the thin lips moving, and smiled. Suddenly she felt the need to speak. The wordy silence troubled her. "Mother, Mother," she cried, "why does he love me so much? I know why I love him. I love him because he is like what love himself should be. But what does he see in me? I am not worthy of him. And yet--why, I cannot tell--though I feel so much beneath him, I don't feel humble. I feel proud, terribly proud. Mother, did you love my father as I love Prince Charming?" The elder woman grew pale beneath the coarse powder that daubed her cheeks, and her dry lips twitched with a spasm of pain. Sybil rushed to her, flung her arms round her neck, and kissed her. "Forgive me, Mother. I know it pains you to talk about our father. But it only pains you because you loved him so much. Don't look so sad. I am as happy to-day as you were twenty years ago. Ah! let me be happy for ever!" "My child, you are far too young to think of falling in love. Besides, what do you know of this young man? You don't even know his name. The whole thing is most inconvenient, and really, when James is going away to Australia, and I have so much to think of, I must say that you should have shown more consideration. However, as I said before, if he is rich . . ." "Ah! Mother, Mother, let me be happy!" Mrs. Vane glanced at her, and with one of those false theatrical gestures that so often become a mode of second nature to a stage-player, clasped her in her arms. At this moment, the door opened and a young lad with rough brown hair came into the room. He was thick-set of figure, and his hands and feet were large and somewhat clumsy in movement. He was not so finely bred as his sister. One would hardly have guessed the close relationship that existed between them. Mrs. Vane fixed her eyes on him and intensified her smile. She mentally elevated her son to the dignity of an audience. She felt sure that the tableau was interesting. "You might keep some of your kisses for me, Sibyl, I think," said the lad with a good-natured grumble. "Ah! but you don't like being kissed, Jim," she cried. "You are a dreadful old bear." And she ran across the room and hugged him. James Vane looked into his sister's face with tenderness. "I want you to come out with me for a walk, Sibyl. I don't suppose I shall ever see this horrid London again. I am sure I don't want to." "My son, don't say such dreadful things," murmured Mrs. Vane, taking up a tawdry theatrical dress, with a sigh, and beginning to patch it. She felt a little disappointed that he had not joined the group. It would have increased the theatrical picturesqueness of the situation. "Why not, Mother? I mean it." "You pain me, my son. I trust you will return from Australia in a position of affluence. I believe there is no society of any kind in the Colonies-- nothing that I would call society--so when you have made your fortune, you must come back and assert yourself in London." "Society!" muttered the lad. "I don't want to know anything about that. I should like to make some money to take you and Sibyl off the stage. I hate it." "Oh, Jim!" said Sibyl, laughing, "how unkind of you! But are you really going for a walk with me? That will be nice! I was afraid you were going to say good-bye to some of your friends-- to Tom Hardy, who gave you that hideous pipe, or Ned Langton, who makes fun of you for smoking it. It is very sweet of you to let me have your last afternoon. Where shall we go? Let us go to the park." "I am too shabby," he answered, frowning. "Only swell people go to the park." "Nonsense, Jim," she whispered, stroking the sleeve of his coat. He hesitated for a moment. "Very well," he said at last, "but don't be too long dressing." She danced out of the door. One could hear her singing as she ran upstairs. Her little feet pattered overhead. He walked up and down the room two or three times. Then he turned to the still figure in the chair. "Mother, are my things ready?" he asked. "Quite ready, James," she answered, keeping her eyes on her work. For some months past she had felt ill at ease when she was alone with this rough stern son of hers. Her shallow secret nature was troubled when their eyes met. She used to wonder if he suspected anything. The silence, for he made no other observation, became intolerable to her. She began to complain. Women defend themselves by attacking, just as they attack by sudden and strange surrenders. "I hope you will be contented, James, with your sea-faring life," she said. "You must remember that it is your own choice. You might have entered a solicitor's office. Solicitors are a very respectable class, and in the country often dine with the best families." "I hate offices, and I hate clerks," he replied. "But you are quite right. I have chosen my own life. All I say is, watch over Sibyl. Don't let her come to any harm. Mother, you must watch over her." "James, you really talk very strangely. Of course I watch over Sibyl." "I hear a gentleman comes every night to the theatre and goes behind to talk to her. Is that right? What about that?" "You are speaking about things you don't understand, James. In the profession we are accustomed to receive a great deal of most gratifying attention. I myself used to receive many bouquets at one time. That was when acting was really understood. As for Sibyl, I do not know at present whether her attachment is serious or not. But there is no doubt that the young man in question is a perfect gentleman. He is always most polite to me. Besides, he has the appearance of being rich, and the flowers he sends are lovely." "You don't know his name, though," said the lad harshly. "No," answered his mother with a placid expression in her face. "He has not yet revealed his real name. I think it is quite romantic of him. He is probably a member of the aristocracy." James Vane bit his lip. "Watch over Sibyl, Mother," he cried, "watch over her." "My son, you distress me very much. Sibyl is always under my special care. Of course, if this gentleman is wealthy, there is no reason why she should not contract an alliance with him. I trust he is one of the aristocracy. He has all the appearance of it, I must say. It might be a most brilliant marriage for Sibyl. They would make a charming couple. His good looks are really quite remarkable; everybody notices them." The lad muttered something to himself and drummed on the window-pane with his coarse fingers. He had just turned round to say something when the door opened and Sibyl ran in. "How serious you both are!" she cried. "What is the matter?" "Nothing," he answered. "I suppose one must be serious sometimes. Good-bye, Mother; I will have my dinner at five o'clock. Everything is packed, except my shirts, so you need not trouble." "Good-bye, my son," she answered with a bow of strained stateliness. She was extremely annoyed at the tone he had adopted with her, and there was something in his look that had made her feel afraid. "Kiss me, Mother," said the girl. Her flowerlike lips touched the withered cheek and warmed its frost. "My child! my child!" cried Mrs. Vane, looking up to the ceiling in search of an imaginary gallery. "Come, Sibyl," said her brother impatiently. He hated his mother's affectations. They went out into the flickering, wind-blown sunlight and strolled down the dreary Euston Road. The passersby glanced in wonder at the sullen heavy youth who, in coarse, ill-fitting clothes, was in the company of such a graceful, refined-looking girl. He was like a common gardener walking with a rose. Jim frowned from time to time when he caught the inquisitive glance of some stranger. He had that dislike of being stared at, which comes on geniuses late in life and never leaves the commonplace. Sibyl, however, was quite unconscious of the effect she was producing. Her love was trembling in laughter on her lips. She was thinking of Prince Charming, and, that she might think of him all the more, she did not talk of him, but prattled on about the ship in which Jim was going to sail, about the gold he was certain to find, about the wonderful heiress whose life he was to save from the wicked, red-shirted bushrangers. For he was not to remain a sailor, or a supercargo, or whatever he was going to be. Oh, no! A sailor's existence was dreadful. Fancy being cooped up in a horrid ship, with the hoarse, hump-backed waves trying to get in, and a black wind blowing the masts down and tearing the sails into long screaming ribands! He was to leave the vessel at Melbourne, bid a polite good-bye to the captain, and go off at once to the gold-fields. Before a week was over he was to come across a large nugget of pure gold, the largest nugget that had ever been discovered, and bring it down to the coast in a waggon guarded by six mounted policemen. The bushrangers were to attack them three times, and be defeated with immense slaughter. Or, no. He was not to go to the gold-fields at all. They were horrid places, where men got intoxicated, and shot each other in bar-rooms, and used bad language. He was to be a nice sheep-farmer, and one evening, as he was riding home, he was to see the beautiful heiress being carried off by a robber on a black horse, and give chase, and rescue her. Of course, she would fall in love with him, and he with her, and they would get married, and come home, and live in an immense house in London. Yes, there were delightful things in store for him. But he must be very good, and not lose his temper, or spend his money foolishly. She was only a year older than he was, but she knew so much more of life. He must be sure, also, to write to her by every mail, and to say his prayers each night before he went to sleep. God was very good, and would watch over him. She would pray for him, too, and in a few years he would come back quite rich and happy. The lad listened sulkily to her and made no answer. He was heart-sick at leaving home. Yet it was not this alone that made him gloomy and morose. Inexperienced though he was, he had still a strong sense of the danger of Sibyl's position. This young dandy who was making love to her could mean her no good. He was a gentleman, and he hated him for that, hated him through some curious race-instinct for which he could not account, and which for that reason was all the more dominant within him. He was conscious also of the shallowness and vanity of his mother's nature, and in that saw infinite peril for Sibyl and Sibyl's happiness. Children begin by loving their parents; as they grow older they judge them; sometimes they forgive them. His mother! He had something on his mind to ask of her, something that he had brooded on for many months of silence. A chance phrase that he had heard at the theatre, a whispered sneer that had reached his ears one night as he waited at the stage-door, had set loose a train of horrible thoughts. He remembered it as if it had been the lash of a hunting-crop across his face. His brows knit together into a wedgelike furrow, and with a twitch of pain he bit his underlip. "You are not listening to a word I am saying, Jim," cried Sibyl, "and I am making the most delightful plans for your future. Do say something." "What do you want me to say?" "Oh! that you will be a good boy and not forget us," she answered, smiling at him. He shrugged his shoulders. "You are more likely to forget me than I am to forget you, Sibyl." She flushed. "What do you mean, Jim?" she asked. "You have a new friend, I hear. Who is he? Why have you not told me about him? He means you no good." "Stop, Jim!" she exclaimed. "You must not say anything against him. I love him." "Why, you don't even know his name," answered the lad. "Who is he? I have a right to know." "He is called Prince Charming. Don't you like the name. Oh! you silly boy! you should never forget it. If you only saw him, you would think him the most wonderful person in the world. Some day you will meet him--when you come back from Australia. You will like him so much. Everybody likes him, and I ... love him. I wish you could come to the theatre to-night. He is going to be there, and I am to play Juliet. Oh! how I shall play it! Fancy, Jim, to be in love and play Juliet! To have him sitting there! To play for his delight! I am afraid I may frighten the company, frighten or enthrall them. To be in love is to surpass one's self. Poor dreadful Mr. Isaacs will be shouting 'genius' to his loafers at the bar. He has preached me as a dogma; to-night he will announce me as a revelation. I feel it. And it is all his, his only, Prince Charming, my wonderful lover, my god of graces. But I am poor beside him. Poor? What does that matter? When poverty creeps in at the door, love flies in through the window. Our proverbs want rewriting. They were made in winter, and it is summer now; spring-time for me, I think, a very dance of blossoms in blue skies." "He is a gentleman," said the lad sullenly. "A prince!" she cried musically. "What more do you want?" "He wants to enslave you." "I shudder at the thought of being free." "I want you to beware of him." "To see him is to worship him; to know him is to trust him." "Sibyl, you are mad about him." She laughed and took his arm. "You dear old Jim, you talk as if you were a hundred. Some day you will be in love yourself. Then you will know what it is. Don't look so sulky. Surely you should be glad to think that, though you are going away, you leave me happier than I have ever been before. Life has been hard for us both, terribly hard and difficult. But it will be different now. You are going to a new world, and I have found one. Here are two chairs; let us sit down and see the smart people go by." They took their seats amidst a crowd of watchers. The tulip-beds across the road flamed like throbbing rings of fire. A white dust-- tremulous cloud of orris-root it seemed--hung in the panting air. The brightly coloured parasols danced and dipped like monstrous butterflies. She made her brother talk of himself, his hopes, his prospects. He spoke slowly and with effort. They passed words to each other as players at a game pass counters. Sibyl felt oppressed. She could not communicate her joy. A faint smile curving that sullen mouth was all the echo she could win. After some time she became silent. Suddenly she caught a glimpse of golden hair and laughing lips, and in an open carriage with two ladies Dorian Gray drove past. She started to her feet. "There he is!" she cried. "Who?" said Jim Vane. "Prince Charming," she answered, looking after the victoria. He jumped up and seized her roughly by the arm. "Show him to me. Which is he? Point him out. I must see him!" he exclaimed; but at that moment the Duke of Berwick's four-in-hand came between, and when it had left the space clear, the carriage had swept out of the park. "He is gone," murmured Sibyl sadly. "I wish you had seen him." "I wish I had, for as sure as there is a God in heaven, if he ever does you any wrong, I shall kill him." She looked at him in horror. He repeated his words. They cut the air like a dagger. The people round began to gape. A lady standing close to her tittered. "Come away, Jim; come away," she whispered. He followed her doggedly as she passed through the crowd. He felt glad at what he had said. When they reached the Achilles Statue, she turned round. There was pity in her eyes that became laughter on her lips. She shook her head at him. "You are foolish, Jim, utterly foolish; a bad-tempered boy, that is all. How can you say such horrible things? You don't know what you are talking about. You are simply jealous and unkind. Ah! I wish you would fall in love. Love makes people good, and what you said was wicked." "I am sixteen," he answered, "and I know what I am about. Mother is no help to you. She doesn't understand how to look after you. I wish now that I was not going to Australia at all. I have a great mind to chuck the whole thing up. I would, if my articles hadn't been signed." "Oh, don't be so serious, Jim. You are like one of the heroes of those silly melodramas Mother used to be so fond of acting in. I am not going to quarrel with you. I have seen him, and oh! to see him is perfect happiness. We won't quarrel. I know you would never harm any one I love, would you?" "Not as long as you love him, I suppose," was the sullen answer. "I shall love him for ever!" she cried. "And he?" "For ever, too!" "He had better." She shrank from him. Then she laughed and put her hand on his arm. He was merely a boy. At the Marble Arch they hailed an omnibus, which left them close to their shabby home in the Euston Road. It was after five o'clock, and Sibyl had to lie down for a couple of hours before acting. Jim insisted that she should do so. He said that he would sooner part with her when their mother was not present. She would be sure to make a scene, and he detested scenes of every kind. In Sybil's own room they parted. There was jealousy in the lad's heart, and a fierce murderous hatred of the stranger who, as it seemed to him, had come between them. Yet, when her arms were flung round his neck, and her fingers strayed through his hair, he softened and kissed her with real affection. There were tears in his eyes as he went downstairs. His mother was waiting for him below. She grumbled at his unpunctuality, as he entered. He made no answer, but sat down to his meagre meal. The flies buzzed round the table and crawled over the stained cloth. Through the rumble of omnibuses, and the clatter of street-cabs, he could hear the droning voice devouring each minute that was left to him. After some time, he thrust away his plate and put his head in his hands. He felt that he had a right to know. It should have been told to him before, if it was as he suspected. Leaden with fear, his mother watched him. Words dropped mechanically from her lips. A tattered lace handkerchief twitched in her fingers. When the clock struck six, he got up and went to the door. Then he turned back and looked at her. Their eyes met. In hers he saw a wild appeal for mercy. It enraged him. "Mother, I have something to ask you," he said. Her eyes wandered vaguely about the room. She made no answer. "Tell me the truth. I have a right to know. Were you married to my father?" She heaved a deep sigh. It was a sigh of relief. The terrible moment, the moment that night and day, for weeks and months, she had dreaded, had come at last, and yet she felt no terror. Indeed, in some measure it was a disappointment to her. The vulgar directness of the question called for a direct answer. The situation had not been gradually led up to. It was crude. It reminded her of a bad rehearsal. "No," she answered, wondering at the harsh simplicity of life. "My father was a scoundrel then!" cried the lad, clenching his fists. She shook her head. "I knew he was not free. We loved each other very much. If he had lived, he would have made provision for us. Don't speak against him, my son. He was your father, and a gentleman. Indeed, he was highly connected." An oath broke from his lips. "I don't care for myself," he exclaimed, "but don't let Sibyl. . . . It is a gentleman, isn't it, who is in love with her, or says he is? Highly connected, too, I suppose." For a moment a hideous sense of humiliation came over the woman. Her head drooped. She wiped her eyes with shaking hands. "Sibyl has a mother," she murmured; "I had none." The lad was touched. He went towards her, and stooping down, he kissed her. "I am sorry if I have pained you by asking about my father," he said, "but I could not help it. I must go now. Good-bye. Don't forget that you will have only one child now to look after, and believe me that if this man wrongs my sister, I will find out who he is, track him down, and kill him like a dog. I swear it." The exaggerated folly of the threat, the passionate gesture that accompanied it, the mad melodramatic words, made life seem more vivid to her. She was familiar with the atmosphere. She breathed more freely, and for the first time for many months she really admired her son. She would have liked to have continued the scene on the same emotional scale, but he cut her short. Trunks had to be carried down and mufflers looked for. The lodging-house drudge bustled in and out. There was the bargaining with the cabman. The moment was lost in vulgar details. It was with a renewed feeling of disappointment that she waved the tattered lace handkerchief from the window, as her son drove away. She was conscious that a great opportunity had been wasted. She consoled herself by telling Sibyl how desolate she felt her life would be, now that she had only one child to look after. She remembered the phrase. It had pleased her. Of the threat she said nothing. It was vividly and dramatically expressed. She felt that they would all laugh at it some day. CHAPTER 6 "I suppose you have heard the news, Basil?" said Lord Henry that evening as Hallward was shown into a little private room at the Bristol where dinner had been laid for three. "No, Harry," answered the artist, giving his hat and coat to the bowing waiter. "What is it? Nothing about politics, I hope! They don't interest me. There is hardly a single person in the House of Commons worth painting, though many of them would be the better for a little whitewashing." "Dorian Gray is engaged to be married," said Lord Henry, watching him as he spoke. Hallward started and then frowned. "Dorian engaged to be married!" he cried. "Impossible!" "It is perfectly true." "To whom?" "To some little actress or other." "I can't believe it. Dorian is far too sensible." "Dorian is far too wise not to do foolish things now and then, my dear Basil." "Marriage is hardly a thing that one can do now and then, Harry." "Except in America," rejoined Lord Henry languidly. "But I didn't say he was married. I said he was engaged to be married. There is a great difference. I have a distinct remembrance of being married, but I have no recollection at all of being engaged. I am inclined to think that I never was engaged." "But think of Dorian's birth, and position, and wealth. It would be absurd for him to marry so much beneath him." "If you want to make him marry this girl, tell him that, Basil. He is sure to do it, then. Whenever a man does a thoroughly stupid thing, it is always from the noblest motives." "I hope the girl is good, Harry. I don't want to see Dorian tied to some vile creature, who might degrade his nature and ruin his intellect." "Oh, she is better than good--she is beautiful," murmured Lord Henry, sipping a glass of vermouth and orange-bitters. "Dorian says she is beautiful, and he is not often wrong about things of that kind. Your portrait of him has quickened his appreciation of the personal appearance of other people. It has had that excellent effect, amongst others. We are to see her to-night, if that boy doesn't forget his appointment." "Are you serious?" "Quite serious, Basil. I should be miserable if I thought I should ever be more serious than I am at the present moment." "But do you approve of it, Harry?" asked the painter, walking up and down the room and biting his lip. "You can't approve of it, possibly. It is some silly infatuation." "I never approve, or disapprove, of anything now. It is an absurd attitude to take towards life. We are not sent into the world to air our moral prejudices. I never take any notice of what common people say, and I never interfere with what charming people do. If a personality fascinates me, whatever mode of expression that personality selects is absolutely delightful to me. Dorian Gray falls in love with a beautiful girl who acts Juliet, and proposes to marry her. Why not? If he wedded Messalina, he would be none the less interesting. You know I am not a champion of marriage. The real drawback to marriage is that it makes one unselfish. And unselfish people are colourless. They lack individuality. Still, there are certain temperaments that marriage makes more complex. They retain their egotism, and add to it many other egos. They are forced to have more than one life. They become more highly organized, and to be highly organized is, I should fancy, the object of man's existence. Besides, every experience is of value, and whatever one may say against marriage, it is certainly an experience. I hope that Dorian Gray will make this girl his wife, passionately adore her for six months, and then suddenly become fascinated by some one else. He would be a wonderful study." "You don't mean a single word of all that, Harry; you know you don't. If Dorian Gray's life were spoiled, no one would be sorrier than yourself. You are much better than you pretend to be." Lord Henry laughed. "The reason we all like to think so well of others is that we are all afraid for ourselves. The basis of optimism is sheer terror. We think that we are generous because we credit our neighbour with the possession of those virtues that are likely to be a benefit to us. We praise the banker that we may overdraw our account, and find good qualities in the highwayman in the hope that he may spare our pockets. I mean everything that I have said. I have the greatest contempt for optimism. As for a spoiled life, no life is spoiled but one whose growth is arrested. If you want to mar a nature, you have merely to reform it. As for marriage, of course that would be silly, but there are other and more interesting bonds between men and women. I will certainly encourage them. They have the charm of being fashionable. But here is Dorian himself. He will tell you more than I can." "My dear Harry, my dear Basil, you must both congratulate me!" said the lad, throwing off his evening cape with its satin-lined wings and shaking each of his friends by the hand in turn. "I have never been so happy. Of course, it is sudden-- all really delightful things are. And yet it seems to me to be the one thing I have been looking for all my life." He was flushed with excitement and pleasure, and looked extraordinarily handsome. "I hope you will always be very happy, Dorian," said Hallward, "but I don't quite forgive you for not having let me know of your engagement. You let Harry know." "And I don't forgive you for being late for dinner," broke in Lord Henry, putting his hand on the lad's shoulder and smiling as he spoke. "Come, let us sit down and try what the new chef here is like, and then you will tell us how it all came about." "There is really not much to tell," cried Dorian as they took their seats at the small round table. "What happened was simply this. After I left you yesterday evening, Harry, I dressed, had some dinner at that little Italian restaurant in Rupert Street you introduced me to, and went down at eight o'clock to the theatre. Sibyl was playing Rosalind. Of course, the scenery was dreadful and the Orlando absurd. But Sibyl! You should have seen her! When she came on in her boy's clothes, she was perfectly wonderful. She wore a moss-coloured velvet jerkin with cinnamon sleeves, slim, brown, cross-gartered hose, a dainty little green cap with a hawk's feather caught in a jewel, and a hooded cloak lined with dull red. She had never seemed to me more exquisite. She had all the delicate grace of that Tanagra figurine that you have in your studio, Basil. Her hair clustered round her face like dark leaves round a pale rose. As for her acting--well, you shall see her to-night. She is simply a born artist. I sat in the dingy box absolutely enthralled. I forgot that I was in London and in the nineteenth century. I was away with my love in a forest that no man had ever seen. After the performance was over, I went behind and spoke to her. As we were sitting together, suddenly there came into her eyes a look that I had never seen there before. My lips moved towards hers. We kissed each other. I can't describe to you what I felt at that moment. It seemed to me that all my life had been narrowed to one perfect point of rose-coloured joy. She trembled all over and shook like a white narcissus. Then she flung herself on her knees and kissed my hands. I feel that I should not tell you all this, but I can't help it. Of course, our engagement is a dead secret. She has not even told her own mother. I don't know what my guardians will say. Lord Radley is sure to be furious. I don't care. I shall be of age in less than a year, and then I can do what I like. I have been right, Basil, haven't I, to take my love out of poetry and to find my wife in Shakespeare's plays? Lips that Shakespeare taught to speak have whispered their secret in my ear. I have had the arms of Rosalind around me, and kissed Juliet on the mouth." "Yes, Dorian, I suppose you were right," said Hallward slowly. "Have you seen her to-day?" asked Lord Henry. Dorian Gray shook his head. "I left her in the forest of Arden; I shall find her in an orchard in Verona." Lord Henry sipped his champagne in a meditative manner. "At what particular point did you mention the word marriage, Dorian? And what did she say in answer? Perhaps you forgot all about it." "My dear Harry, I did not treat it as a business transaction, and I did not make any formal proposal. I told her that I loved her, and she said she was not worthy to be my wife. Not worthy! Why, the whole world is nothing to me compared with her." "Women are wonderfully practical," murmured Lord Henry, "much more practical than we are. In situations of that kind we often forget to say anything about marriage, and they always remind us." Hallward laid his hand upon his arm. "Don't, Harry. You have annoyed Dorian. He is not like other men. He would never bring misery upon any one. His nature is too fine for that." Lord Henry looked across the table. "Dorian is never annoyed with me," he answered. "I asked the question for the best reason possible, for the only reason, indeed, that excuses one for asking any question-- simple curiosity. I have a theory that it is always the women who propose to us, and not we who propose to the women. Except, of course, in middle-class life. But then the middle classes are not modern." Dorian Gray laughed, and tossed his head. "You are quite incorrigible, Harry; but I don't mind. It is impossible to be angry with you. When you see Sibyl Vane, you will feel that the man who could wrong her would be a beast, a beast without a heart. I cannot understand how any one can wish to shame the thing he loves. I love Sibyl Vane. I want to place her on a pedestal of gold and to see the world worship the woman who is mine. What is marriage? An irrevocable vow. You mock at it for that. Ah! don't mock. It is an irrevocable vow that I want to take. Her trust makes me faithful, her belief makes me good. When I am with her, I regret all that you have taught me. I become different from what you have known me to be. I am changed, and the mere touch of Sibyl Vane's hand makes me forget you and all your wrong, fascinating, poisonous, delightful theories." "And those are ... ?" asked Lord Henry, helping himself to some salad. "Oh, your theories about life, your theories about love, your theories about pleasure. All your theories, in fact, Harry." "Pleasure is the only thing worth having a theory about," he answered in his slow melodious voice. "But I am afraid I cannot claim my theory as my own. It belongs to Nature, not to me. Pleasure is Nature's test, her sign of approval. When we are happy, we are always good, but when we are good, we are not always happy." "Ah! but what do you mean by good?" cried Basil Hallward. "Yes," echoed Dorian, leaning back in his chair and looking at Lord Henry over the heavy clusters of purple-lipped irises that stood in the centre of the table, "what do you mean by good, Harry?" "To be good is to be in harmony with one's self," he replied, touching the thin stem of his glass with his pale, fine-pointed fingers. "Discord is to be forced to be in harmony with others. One's own life--that is the important thing. As for the lives of one's neighbours, if one wishes to be a prig or a Puritan, one can flaunt one's moral views about them, but they are not one's concern. Besides, individualism has really the higher aim. Modern morality consists in accepting the standard of one's age. I consider that for any man of culture to accept the standard of his age is a form of the grossest immorality." "But, surely, if one lives merely for one's self, Harry, one pays a terrible price for doing so?" suggested the painter. "Yes, we are overcharged for everything nowadays. I should fancy that the real tragedy of the poor is that they can afford nothing but self-denial. Beautiful sins, like beautiful things, are the privilege of the rich." "One has to pay in other ways but money." "What sort of ways, Basil?" "Oh! I should fancy in remorse, in suffering, in . . . well, in the consciousness of degradation." Lord Henry shrugged his shoulders. "My dear fellow, mediaeval art is charming, but mediaeval emotions are out of date. One can use them in fiction, of course. But then the only things that one can use in fiction are the things that one has ceased to use in fact. Believe me, no civilized man ever regrets a pleasure, and no uncivilized man ever knows what a pleasure is." "I know what pleasure is," cried Dorian Gray. "It is to adore some one." "That is certainly better than being adored," he answered, toying with some fruits. "Being adored is a nuisance. Women treat us just as humanity treats its gods. They worship us, and are always bothering us to do something for them." "I should have said that whatever they ask for they had first given to us," murmured the lad gravely. "They create love in our natures. They have a right to demand it back." "That is quite true, Dorian," cried Hallward. "Nothing is ever quite true," said Lord Henry. "This is," interrupted Dorian. "You must admit, Harry, that women give to men the very gold of their lives." "Possibly," he sighed, "but they invariably want it back in such very small change. That is the worry. Women, as some witty Frenchman once put it, inspire us with the desire to do masterpieces and always prevent us from carrying them out." "Harry, you are dreadful! I don't know why I like you so much." "You will always like me, Dorian," he replied. "Will you have some coffee, you fellows? Waiter, bring coffee, and fine-champagne, and some cigarettes. No, don't mind the cigarettes--I have some. Basil, I can't allow you to smoke cigars. You must have a cigarette. A cigarette is the perfect type of a perfect pleasure. It is exquisite, and it leaves one unsatisfied. What more can one want? Yes, Dorian, you will always be fond of me. I represent to you all the sins you have never had the courage to commit." "What nonsense you talk, Harry!" cried the lad, taking a light from a fire-breathing silver dragon that the waiter had placed on the table. "Let us go down to the theatre. When Sibyl comes on the stage you will have a new ideal of life. She will represent something to you that you have never known." "I have known everything," said Lord Henry, with a tired look in his eyes, "but I am always ready for a new emotion. I am afraid, however, that, for me at any rate, there is no such thing. Still, your wonderful girl may thrill me. I love acting. It is so much more real than life. Let us go. Dorian, you will come with me. I am so sorry, Basil, but there is only room for two in the brougham. You must follow us in a hansom." They got up and put on their coats, sipping their coffee standing. The painter was silent and preoccupied. There was a gloom over him. He could not bear this marriage, and yet it seemed to him to be better than many other things that might have happened. After a few minutes, they all passed downstairs. He drove off by himself, as had been arranged, and watched the flashing lights of the little brougham in front of him. A strange sense of loss came over him. He felt that Dorian Gray would never again be to him all that he had been in the past. Life had come between them.... His eyes darkened, and the crowded flaring streets became blurred to his eyes. When the cab drew up at the theatre, it seemed to him that he had grown years older. CHAPTER 7 For some reason or other, the house was crowded that night, and the fat Jew manager who met them at the door was beaming from ear to ear with an oily tremulous smile. He escorted them to their box with a sort of pompous humility, waving his fat jewelled hands and talking at the top of his voice. Dorian Gray loathed him more than ever. He felt as if he had come to look for Miranda and had been met by Caliban. Lord Henry, upon the other hand, rather liked him. At least he declared he did, and insisted on shaking him by the hand and assuring him that he was proud to meet a man who had discovered a real genius and gone bankrupt over a poet. Hallward amused himself with watching the faces in the pit. The heat was terribly oppressive, and the huge sunlight flamed like a monstrous dahlia with petals of yellow fire. The youths in the gallery had taken off their coats and waistcoats and hung them over the side. They talked to each other across the theatre and shared their oranges with the tawdry girls who sat beside them. Some women were laughing in the pit. Their voices were horribly shrill and discordant. The sound of the popping of corks came from the bar. "What a place to find one's divinity in!" said Lord Henry. "Yes!" answered Dorian Gray. "It was here I found her, and she is divine beyond all living things. When she acts, you will forget everything. These common rough people, with their coarse faces and brutal gestures, become quite different when she is on the stage. They sit silently and watch her. They weep and laugh as she wills them to do. She makes them as responsive as a violin. She spiritualizes them, and one feels that they are of the same flesh and blood as one's self." "The same flesh and blood as one's self! Oh, I hope not!" exclaimed Lord Henry, who was scanning the occupants of the gallery through his opera-glass. "Don't pay any attention to him, Dorian," said the painter. "I understand what you mean, and I believe in this girl. Any one you love must be marvellous, and any girl who has the effect you describe must be fine and noble. To spiritualize one's age--that is something worth doing. If this girl can give a soul to those who have lived without one, if she can create the sense of beauty in people whose lives have been sordid and ugly, if she can strip them of their selfishness and lend them tears for sorrows that are not their own, she is worthy of all your adoration, worthy of the adoration of the world. This marriage is quite right. I did not think so at first, but I admit it now. The gods made Sibyl Vane for you. Without her you would have been incomplete." "Thanks, Basil," answered Dorian Gray, pressing his hand. "I knew that you would understand me. Harry is so cynical, he terrifies me. But here is the orchestra. It is quite dreadful, but it only lasts for about five minutes. Then the curtain rises, and you will see the girl to whom I am going to give all my life, to whom I have given everything that is good in me." A quarter of an hour afterwards, amidst an extraordinary turmoil of applause, Sibyl Vane stepped on to the stage. Yes, she was certainly lovely to look at-- one of the loveliest creatures, Lord Henry thought, that he had ever seen. There was something of the fawn in her shy grace and startled eyes. A faint blush, like the shadow of a rose in a mirror of silver, came to her cheeks as she glanced at the crowded enthusiastic house. She stepped back a few paces and her lips seemed to tremble. Basil Hallward leaped to his feet and began to applaud. Motionless, and as one in a dream, sat Dorian Gray, gazing at her. Lord Henry peered through his glasses, murmuring, "Charming! charming!" The scene was the hall of Capulet's house, and Romeo in his pilgrim's dress had entered with Mercutio and his other friends. The band, such as it was, struck up a few bars of music, and the dance began. Through the crowd of ungainly, shabbily dressed actors, Sibyl Vane moved like a creature from a finer world. Her body swayed, while she danced, as a plant sways in the water. The curves of her throat were the curves of a white lily. Her hands seemed to be made of cool ivory. Yet she was curiously listless. She showed no sign of joy when her eyes rested on Romeo. The few words she had to speak-- Good pilgrim, you do wrong your hand too much, Which mannerly devotion shows in this; For saints have hands that pilgrims' hands do touch, And palm to palm is holy palmers' kiss-- with the brief dialogue that follows, were spoken in a thoroughly artificial manner. The voice was exquisite, but from the point of view of tone it was absolutely false. It was wrong in colour. It took away all the life from the verse. It made the passion unreal. Dorian Gray grew pale as he watched her. He was puzzled and anxious. Neither of his friends dared to say anything to him. She seemed to them to be absolutely incompetent. They were horribly disappointed. Yet they felt that the true test of any Juliet is the balcony scene of the second act. They waited for that. If she failed there, there was nothing in her. She looked charming as she came out in the moonlight. That could not be denied. But the staginess of her acting was unbearable, and grew worse as she went on. Her gestures became absurdly artificial. She overemphasized everything that she had to say. The beautiful passage-- Thou knowest the mask of night is on my face, Else would a maiden blush bepaint my cheek For that which thou hast heard me speak to-night-- was declaimed with the painful precision of a schoolgirl who has been taught to recite by some second-rate professor of elocution. When she leaned over the balcony and came to those wonderful lines-- Although I joy in thee, I have no joy of this contract to-night: It is too rash, too unadvised, too sudden; Too like the lightning, which doth cease to be Ere one can say, "It lightens." Sweet, good-night! This bud of love by summer's ripening breath May prove a beauteous flower when next we meet-- she spoke the words as though they conveyed no meaning to her. It was not nervousness. Indeed, so far from being nervous, she was absolutely self-contained. It was simply bad art. She was a complete failure. Even the common uneducated audience of the pit and gallery lost their interest in the play. They got restless, and began to talk loudly and to whistle. The Jew manager, who was standing at the back of the dress-circle, stamped and swore with rage. The only person unmoved was the girl herself. When the second act was over, there came a storm of hisses, and Lord Henry got up from his chair and put on his coat. "She is quite beautiful, Dorian," he said, "but she can't act. Let us go." "I am going to see the play through," answered the lad, in a hard bitter voice. "I am awfully sorry that I have made you waste an evening, Harry. I apologize to you both." "My dear Dorian, I should think Miss Vane was ill," interrupted Hallward. "We will come some other night." "I wish she were ill," he rejoined. "But she seems to me to be simply callous and cold. She has entirely altered. Last night she was a great artist. This evening she is merely a commonplace mediocre actress." "Don't talk like that about any one you love, Dorian. Love is a more wonderful thing than art." "They are both simply forms of imitation," remarked Lord Henry. "But do let us go. Dorian, you must not stay here any longer. It is not good for one's morals to see bad acting. Besides, I don't suppose you will want your wife to act, so what does it matter if she plays Juliet like a wooden doll? She is very lovely, and if she knows as little about life as she does about acting, she will be a delightful experience. There are only two kinds of people who are really fascinating-- people who know absolutely everything, and people who know absolutely nothing. Good heavens, my dear boy, don't look so tragic! The secret of remaining young is never to have an emotion that is unbecoming. Come to the club with Basil and myself. We will smoke cigarettes and drink to the beauty of Sibyl Vane. She is beautiful. What more can you want?" "Go away, Harry," cried the lad. "I want to be alone. Basil, you must go. Ah! can't you see that my heart is breaking?" The hot tears came to his eyes. His lips trembled, and rushing to the back of the box, he leaned up against the wall, hiding his face in his hands. "Let us go, Basil," said Lord Henry with a strange tenderness in his voice, and the two young men passed out together. A few moments afterwards the footlights flared up and the curtain rose on the third act. Dorian Gray went back to his seat. He looked pale, and proud, and indifferent. The play dragged on, and seemed interminable. Half of the audience went out, tramping in heavy boots and laughing. The whole thing was a fiasco. The last act was played to almost empty benches. The curtain went down on a titter and some groans. As soon as it was over, Dorian Gray rushed behind the scenes into the greenroom. The girl was standing there alone, with a look of triumph on her face. Her eyes were lit with an exquisite fire. There was a radiance about her. Her parted lips were smiling over some secret of their own. When he entered, she looked at him, and an expression of infinite joy came over her. "How badly I acted to-night, Dorian!" she cried. "Horribly!" he answered, gazing at her in amazement. "Horribly! It was dreadful. Are you ill? You have no idea what it was. You have no idea what I suffered." The girl smiled. "Dorian," she answered, lingering over his name with long-drawn music in her voice, as though it were sweeter than honey to the red petals of her mouth. "Dorian, you should have understood. But you understand now, don't you?" "Understand what?" he asked, angrily. "Why I was so bad to-night. Why I shall always be bad. Why I shall never act well again." He shrugged his shoulders. "You are ill, I suppose. When you are ill you shouldn't act. You make yourself ridiculous. My friends were bored. I was bored." She seemed not to listen to him. She was transfigured with joy. An ecstasy of happiness dominated her. "Dorian, Dorian," she cried, "before I knew you, acting was the one reality of my life. It was only in the theatre that I lived. I thought that it was all true. I was Rosalind one night and Portia the other. The joy of Beatrice was my joy, and the sorrows of Cordelia were mine also. I believed in everything. The common people who acted with me seemed to me to be godlike. The painted scenes were my world. I knew nothing but shadows, and I thought them real. You came--oh, my beautiful love!-- and you freed my soul from prison. You taught me what reality really is. To-night, for the first time in my life, I saw through the hollowness, the sham, the silliness of the empty pageant in which I had always played. To-night, for the first time, I became conscious that the Romeo was hideous, and old, and painted, that the moonlight in the orchard was false, that the scenery was vulgar, and that the words I had to speak were unreal, were not my words, were not what I wanted to say. You had brought me something higher, something of which all art is but a reflection. You had made me understand what love really is. My love! My love! Prince Charming! Prince of life! I have grown sick of shadows. You are more to me than all art can ever be. What have I to do with the puppets of a play? When I came on to-night, I could not understand how it was that everything had gone from me. I thought that I was going to be wonderful. I found that I could do nothing. Suddenly it dawned on my soul what it all meant. The knowledge was exquisite to me. I heard them hissing, and I smiled. What could they know of love such as ours? Take me away, Dorian--take me away with you, where we can be quite alone. I hate the stage. I might mimic a passion that I do not feel, but I cannot mimic one that burns me like fire. Oh, Dorian, Dorian, you understand now what it signifies? Even if I could do it, it would be profanation for me to play at being in love. You have made me see that." He flung himself down on the sofa and turned away his face. "You have killed my love," he muttered. She looked at him in wonder and laughed. He made no answer. She came across to him, and with her little fingers stroked his hair. She knelt down and pressed his hands to her lips. He drew them away, and a shudder ran through him. Then he leaped up and went to the door. "Yes," he cried, "you have killed my love. You used to stir my imagination. Now you don't even stir my curiosity. You simply produce no effect. I loved you because you were marvellous, because you had genius and intellect, because you realized the dreams of great poets and gave shape and substance to the shadows of art. You have thrown it all away. You are shallow and stupid. My God! how mad I was to love you! What a fool I have been! You are nothing to me now. I will never see you again. I will never think of you. I will never mention your name. You don't know what you were to me, once. Why, once . . . Oh, I can't bear to think of it! I wish I had never laid eyes upon you! You have spoiled the romance of my life. How little you can know of love, if you say it mars your art! Without your art, you are nothing. I would have made you famous, splendid, magnificent. The world would have worshipped you, and you would have borne my name. What are you now? A third-rate actress with a pretty face." The girl grew white, and trembled. She clenched her hands together, and her voice seemed to catch in her throat. "You are not serious, Dorian?" she murmured. "You are acting." "Acting! I leave that to you. You do it so well," he answered bitterly. She rose from her knees and, with a piteous expression of pain in her face, came across the room to him. She put her hand upon his arm and looked into his eyes. He thrust her back. "Don't touch me!" he cried. A low moan broke from her, and she flung herself at his feet and lay there like a trampled flower. "Dorian, Dorian, don't leave me!" she whispered. "I am so sorry I didn't act well. I was thinking of you all the time. But I will try--indeed, I will try. It came so suddenly across me, my love for you. I think I should never have known it if you had not kissed me-- if we had not kissed each other. Kiss me again, my love. Don't go away from me. I couldn't bear it. Oh! don't go away from me. My brother . . . No; never mind. He didn't mean it. He was in jest. . . . But you, oh! can't you forgive me for to-night? I will work so hard and try to improve. Don't be cruel to me, because I love you better than anything in the world. After all, it is only once that I have not pleased you. But you are quite right, Dorian. I should have shown myself more of an artist. It was foolish of me, and yet I couldn't help it. Oh, don't leave me, don't leave me." A fit of passionate sobbing choked her. She crouched on the floor like a wounded thing, and Dorian Gray, with his beautiful eyes, looked down at her, and his chiselled lips curled in exquisite disdain. There is always something ridiculous about the emotions of people whom one has ceased to love. Sibyl Vane seemed to him to be absurdly melodramatic. Her tears and sobs annoyed him. "I am going," he said at last in his calm clear voice. "I don't wish to be unkind, but I can't see you again. You have disappointed me." She wept silently, and made no answer, but crept nearer. Her little hands stretched blindly out, and appeared to be seeking for him. He turned on his heel and left the room. In a few moments he was out of the theatre. Where he went to he hardly knew. He remembered wandering through dimly lit streets, past gaunt, black-shadowed archways and evil-looking houses. Women with hoarse voices and harsh laughter had called after him. Drunkards had reeled by, cursing and chattering to themselves like monstrous apes. He had seen grotesque children huddled upon door-steps, and heard shrieks and oaths from gloomy courts. As the dawn was just breaking, he found himself close to Covent Garden. The darkness lifted, and, flushed with faint fires, the sky hollowed itself into a perfect pearl. Huge carts filled with nodding lilies rumbled slowly down the polished empty street. The air was heavy with the perfume of the flowers, and their beauty seemed to bring him an anodyne for his pain. He followed into the market and watched the men unloading their waggons. A white-smocked carter offered him some cherries. He thanked him, wondered why he refused to accept any money for them, and began to eat them listlessly. They had been plucked at midnight, and the coldness of the moon had entered into them. A long line of boys carrying crates of striped tulips, and of yellow and red roses, defiled in front of him, threading their way through the huge, jade-green piles of vegetables. Under the portico, with its grey, sun-bleached pillars, loitered a troop of draggled bareheaded girls, waiting for the auction to be over. Others crowded round the swinging doors of the coffee-house in the piazza. The heavy cart-horses slipped and stamped upon the rough stones, shaking their bells and trappings. Some of the drivers were lying asleep on a pile of sacks. Iris-necked and pink-footed, the pigeons ran about picking up seeds. After a little while, he hailed a hansom and drove home. For a few moments he loitered upon the doorstep, looking round at the silent square, with its blank, close-shuttered windows and its staring blinds. The sky was pure opal now, and the roofs of the houses glistened like silver against it. From some chimney opposite a thin wreath of smoke was rising. It curled, a violet riband, through the nacre-coloured air. In the huge gilt Venetian lantern, spoil of some Doge's barge, that hung from the ceiling of the great, oak-panelled hall of entrance, lights were still burning from three flickering jets: thin blue petals of flame they seemed, rimmed with white fire. He turned them out and, having thrown his hat and cape on the table, passed through the library towards the door of his bedroom, a large octagonal chamber on the ground floor that, in his new-born feeling for luxury, he had just had decorated for himself and hung with some curious Renaissance tapestries that had been discovered stored in a disused attic at Selby Royal. As he was turning the handle of the door, his eye fell upon the portrait Basil Hallward had painted of him. He started back as if in surprise. Then he went on into his own room, looking somewhat puzzled. After he had taken the button-hole out of his coat, he seemed to hesitate. Finally, he came back, went over to the picture, and examined it. In the dim arrested light that struggled through the cream-coloured silk blinds, the face appeared to him to be a little changed. The expression looked different. One would have said that there was a touch of cruelty in the mouth. It was certainly strange. He turned round and, walking to the window, drew up the blind. The bright dawn flooded the room and swept the fantastic shadows into dusky corners, where they lay shuddering. But the strange expression that he had noticed in the face of the portrait seemed to linger there, to be more intensified even. The quivering ardent sunlight showed him the lines of cruelty round the mouth as clearly as if he had been looking into a mirror after he had done some dreadful thing. He winced and, taking up from the table an oval glass framed in ivory Cupids, one of Lord Henry's many presents to him, glanced hurriedly into its polished depths. No line like that warped his red lips. What did it mean? He rubbed his eyes, and came close to the picture, and examined it again. There were no signs of any change when he looked into the actual painting, and yet there was no doubt that the whole expression had altered. It was not a mere fancy of his own. The thing was horribly apparent. He threw himself into a chair and began to think. Suddenly there flashed across his mind what he had said in Basil Hallward's studio the day the picture had been finished. Yes, he remembered it perfectly. He had uttered a mad wish that he himself might remain young, and the portrait grow old; that his own beauty might be untarnished, and the face on the canvas bear the burden of his passions and his sins; that the painted image might be seared with the lines of suffering and thought, and that he might keep all the delicate bloom and loveliness of his then just conscious boyhood. Surely his wish had not been fulfilled? Such things were impossible. It seemed monstrous even to think of them. And, yet, there was the picture before him, with the touch of cruelty in the mouth. Cruelty! Had he been cruel? It was the girl's fault, not his. He had dreamed of her as a great artist, had given his love to her because he had thought her great. Then she had disappointed him. She had been shallow and unworthy. And, yet, a feeling of infinite regret came over him, as he thought of her lying at his feet sobbing like a little child. He remembered with what callousness he had watched her. Why had he been made like that? Why had such a soul been given to him? But he had suffered also. During the three terrible hours that the play had lasted, he had lived centuries of pain, aeon upon aeon of torture. His life was well worth hers. She had marred him for a moment, if he had wounded her for an age. Besides, women were better suited to bear sorrow than men. They lived on their emotions. They only thought of their emotions. When they took lovers, it was merely to have some one with whom they could have scenes. Lord Henry had told him that, and Lord Henry knew what women were. Why should he trouble about Sibyl Vane? She was nothing to him now. But the picture? What was he to say of that? It held the secret of his life, and told his story. It had taught him to love his own beauty. Would it teach him to loathe his own soul? Would he ever look at it again? No; it was merely an illusion wrought on the troubled senses. The horrible night that he had passed had left phantoms behind it. Suddenly there had fallen upon his brain that tiny scarlet speck that makes men mad. The picture had not changed. It was folly to think so. Yet it was watching him, with its beautiful marred face and its cruel smile. Its bright hair gleamed in the early sunlight. Its blue eyes met his own. A sense of infinite pity, not for himself, but for the painted image of himself, came over him. It had altered already, and would alter more. Its gold would wither into grey. Its red and white roses would die. For every sin that he committed, a stain would fleck and wreck its fairness. But he would not sin. The picture, changed or unchanged, would be to him the visible emblem of conscience. He would resist temptation. He would not see Lord Henry any more--would not, at any rate, listen to those subtle poisonous theories that in Basil Hallward's garden had first stirred within him the passion for impossible things. He would go back to Sibyl Vane, make her amends, marry her, try to love her again. Yes, it was his duty to do so. She must have suffered more than he had. Poor child! He had been selfish and cruel to her. The fascination that she had exercised over him would return. They would be happy together. His life with her would be beautiful and pure. He got up from his chair and drew a large screen right in front of the portrait, shuddering as he glanced at it. "How horrible!" he murmured to himself, and he walked across to the window and opened it. When he stepped out on to the grass, he drew a deep breath. The fresh morning air seemed to drive away all his sombre passions. He thought only of Sibyl. A faint echo of his love came back to him. He repeated her name over and over again. The birds that were singing in the dew-drenched garden seemed to be telling the flowers about her. CHAPTER 8 It was long past noon when he awoke. His valet had crept several times on tiptoe into the room to see if he was stirring, and had wondered what made his young master sleep so late. Finally his bell sounded, and Victor came in softly with a cup of tea, and a pile of letters, on a small tray of old Sevres china, and drew back the olive-satin curtains, with their shimmering blue lining, that hung in front of the three tall windows. "Monsieur has well slept this morning," he said, smiling. "What o'clock is it, Victor?" asked Dorian Gray drowsily. "One hour and a quarter, Monsieur." How late it was! He sat up, and having sipped some tea, turned over his letters. One of them was from Lord Henry, and had been brought by hand that morning. He hesitated for a moment, and then put it aside. The others he opened listlessly. They contained the usual collection of cards, invitations to dinner, tickets for private views, programmes of charity concerts, and the like that are showered on fashionable young men every morning during the season. There was a rather heavy bill for a chased silver Louis-Quinze toilet-set that he had not yet had the courage to send on to his guardians, who were extremely old-fashioned people and did not realize that we live in an age when unnecessary things are our only necessities; and there were several very courteously worded communications from Jermyn Street money-lenders offering to advance any sum of money at a moment's notice and at the most reasonable rates of interest. After about ten minutes he got up, and throwing on an elaborate dressing-gown of silk-embroidered cashmere wool, passed into the onyx-paved bathroom. The cool water refreshed him after his long sleep. He seemed to have forgotten all that he had gone through. A dim sense of having taken part in some strange tragedy came to him once or twice, but there was the unreality of a dream about it. As soon as he was dressed, he went into the library and sat down to a light French breakfast that had been laid out for him on a small round table close to the open window. It was an exquisite day. The warm air seemed laden with spices. A bee flew in and buzzed round the blue-dragon bowl that, filled with sulphur-yellow roses, stood before him. He felt perfectly happy. Suddenly his eye fell on the screen that he had placed in front of the portrait, and he started. "Too cold for Monsieur?" asked his valet, putting an omelette on the table. "I shut the window?" Dorian shook his head. "I am not cold," he murmured. Was it all true? Had the portrait really changed? Or had it been simply his own imagination that had made him see a look of evil where there had been a look of joy? Surely a painted canvas could not alter? The thing was absurd. It would serve as a tale to tell Basil some day. It would make him smile. And, yet, how vivid was his recollection of the whole thing! First in the dim twilight, and then in the bright dawn, he had seen the touch of cruelty round the warped lips. He almost dreaded his valet leaving the room. He knew that when he was alone he would have to examine the portrait. He was afraid of certainty. When the coffee and cigarettes had been brought and the man turned to go, he felt a wild desire to tell him to remain. As the door was closing behind him, he called him back. The man stood waiting for his orders. Dorian looked at him for a moment. "I am not at home to any one, Victor," he said with a sigh. The man bowed and retired. Then he rose from the table, lit a cigarette, and flung himself down on a luxuriously cushioned couch that stood facing the screen. The screen was an old one, of gilt Spanish leather, stamped and wrought with a rather florid Louis-Quatorze pattern. He scanned it curiously, wondering if ever before it had concealed the secret of a man's life. Should he move it aside, after all? Why not let it stay there? What was the use of knowing? If the thing was true, it was terrible. If it was not true, why trouble about it? But what if, by some fate or deadlier chance, eyes other than his spied behind and saw the horrible change? What should he do if Basil Hallward came and asked to look at his own picture? Basil would be sure to do that. No; the thing had to be examined, and at once. Anything would be better than this dreadful state of doubt. He got up and locked both doors. At least he would be alone when he looked upon the mask of his shame. Then he drew the screen aside and saw himself face to face. It was perfectly true. The portrait had altered. As he often remembered afterwards, and always with no small wonder, he found himself at first gazing at the portrait with a feeling of almost scientific interest. That such a change should have taken place was incredible to him. And yet it was a fact. Was there some subtle affinity between the chemical atoms that shaped themselves into form and colour on the canvas and the soul that was within him? Could it be that what that soul thought, they realized?--that what it dreamed, they made true? Or was there some other, more terrible reason? He shuddered, and felt afraid, and, going back to the couch, lay there, gazing at the picture in sickened horror. One thing, however, he felt that it had done for him. It had made him conscious how unjust, how cruel, he had been to Sibyl Vane. It was not too late to make reparation for that. She could still be his wife. His unreal and selfish love would yield to some higher influence, would be transformed into some nobler passion, and the portrait that Basil Hallward had painted of him would be a guide to him through life, would be to him what holiness is to some, and conscience to others, and the fear of God to us all. There were opiates for remorse, drugs that could lull the moral sense to sleep. But here was a visible symbol of the degradation of sin. Here was an ever-present sign of the ruin men brought upon their souls. Three o'clock struck, and four, and the half-hour rang its double chime, but Dorian Gray did not stir. He was trying to gather up the scarlet threads of life and to weave them into a pattern; to find his way through the sanguine labyrinth of passion through which he was wandering. He did not know what to do, or what to think. Finally, he went over to the table and wrote a passionate letter to the girl he had loved, imploring her forgiveness and accusing himself of madness. He covered page after page with wild words of sorrow and wilder words of pain. There is a luxury in self-reproach. When we blame ourselves, we feel that no one else has a right to blame us. It is the confession, not the priest, that gives us absolution. When Dorian had finished the letter, he felt that he had been forgiven. Suddenly there came a knock to the door, and he heard Lord Henry's voice outside. "My dear boy, I must see you. Let me in at once. I can't bear your shutting yourself up like this." He made no answer at first, but remained quite still. The knocking still continued and grew louder. Yes, it was better to let Lord Henry in, and to explain to him the new life he was going to lead, to quarrel with him if it became necessary to quarrel, to part if parting was inevitable. He jumped up, drew the screen hastily across the picture, and unlocked the door. "I am so sorry for it all, Dorian," said Lord Henry as he entered. "But you must not think too much about it." "Do you mean about Sibyl Vane?" asked the lad. "Yes, of course," answered Lord Henry, sinking into a chair and slowly pulling off his yellow gloves. "It is dreadful, from one point of view, but it was not your fault. Tell me, did you go behind and see her, after the play was over?" "Yes." "I felt sure you had. Did you make a scene with her?" "I was brutal, Harry--perfectly brutal. But it is all right now. I am not sorry for anything that has happened. It has taught me to know myself better." "Ah, Dorian, I am so glad you take it in that way! I was afraid I would find you plunged in remorse and tearing that nice curly hair of yours." "I have got through all that," said Dorian, shaking his head and smiling. "I am perfectly happy now. I know what conscience is, to begin with. It is not what you told me it was. It is the divinest thing in us. Don't sneer at it, Harry, any more--at least not before me. I want to be good. I can't bear the idea of my soul being hideous." "A very charming artistic basis for ethics, Dorian! I congratulate you on it. But how are you going to begin?" "By marrying Sibyl Vane." "Marrying Sibyl Vane!" cried Lord Henry, standing up and looking at him in perplexed amazement. "But, my dear Dorian--" "Yes, Harry, I know what you are going to say. Something dreadful about marriage. Don't say it. Don't ever say things of that kind to me again. Two days ago I asked Sibyl to marry me. I am not going to break my word to her. She is to be my wife." "Your wife! Dorian! . . . Didn't you get my letter? I wrote to you this morning, and sent the note down by my own man." "Your letter? Oh, yes, I remember. I have not read it yet, Harry. I was afraid there might be something in it that I wouldn't like. You cut life to pieces with your epigrams." "You know nothing then?" "What do you mean?" Lord Henry walked across the room, and sitting down by Dorian Gray, took both his hands in his own and held them tightly. "Dorian," he said, "my letter--don't be frightened--was to tell you that Sibyl Vane is dead." A cry of pain broke from the lad's lips, and he leaped to his feet, tearing his hands away from Lord Henry's grasp. "Dead! Sibyl dead! It is not true! It is a horrible lie! How dare you say it?" "It is quite true, Dorian," said Lord Henry, gravely. "It is in all the morning papers. I wrote down to you to ask you not to see any one till I came. There will have to be an inquest, of course, and you must not be mixed up in it. Things like that make a man fashionable in Paris. But in London people are so prejudiced. Here, one should never make one's debut with a scandal. One should reserve that to give an interest to one's old age. I suppose they don't know your name at the theatre? If they don't, it is all right. Did any one see you going round to her room? That is an important point." Dorian did not answer for a few moments. He was dazed with horror. Finally he stammered, in a stifled voice, "Harry, did you say an inquest? What did you mean by that? Did Sibyl--? Oh, Harry, I can't bear it! But be quick. Tell me everything at once." "I have no doubt it was not an accident, Dorian, though it must be put in that way to the public. It seems that as she was leaving the theatre with her mother, about half-past twelve or so, she said she had forgotten something upstairs. They waited some time for her, but she did not come down again. They ultimately found her lying dead on the floor of her dressing-room. She had swallowed something by mistake, some dreadful thing they use at theatres. I don't know what it was, but it had either prussic acid or white lead in it. I should fancy it was prussic acid, as she seems to have died instantaneously." "Harry, Harry, it is terrible!" cried the lad. "Yes; it is very tragic, of course, but you must not get yourself mixed up in it. I see by The Standard that she was seventeen. I should have thought she was almost younger than that. She looked such a child, and seemed to know so little about acting. Dorian, you mustn't let this thing get on your nerves. You must come and dine with me, and afterwards we will look in at the opera. It is a Patti night, and everybody will be there. You can come to my sister's box. She has got some smart women with her." "So I have murdered Sibyl Vane," said Dorian Gray, half to himself, "murdered her as surely as if I had cut her little throat with a knife. Yet the roses are not less lovely for all that. The birds sing just as happily in my garden. And to-night I am to dine with you, and then go on to the opera, and sup somewhere, I suppose, afterwards. How extraordinarily dramatic life is! If I had read all this in a book, Harry, I think I would have wept over it. Somehow, now that it has happened actually, and to me, it seems far too wonderful for tears. Here is the first passionate love-letter I have ever written in my life. Strange, that my first passionate love-letter should have been addressed to a dead girl. Can they feel, I wonder, those white silent people we call the dead? Sibyl! Can she feel, or know, or listen? Oh, Harry, how I loved her once! It seems years ago to me now. She was everything to me. Then came that dreadful night--was it really only last night?-- when she played so badly, and my heart almost broke. She explained it all to me. It was terribly pathetic. But I was not moved a bit. I thought her shallow. Suddenly something happened that made me afraid. I can't tell you what it was, but it was terrible. I said I would go back to her. I felt I had done wrong. And now she is dead. My God! My God! Harry, what shall I do? You don't know the danger I am in, and there is nothing to keep me straight. She would have done that for me. She had no right to kill herself. It was selfish of her." "My dear Dorian," answered Lord Henry, taking a cigarette from his case and producing a gold-latten matchbox, "the only way a woman can ever reform a man is by boring him so completely that he loses all possible interest in life. If you had married this girl, you would have been wretched. Of course, you would have treated her kindly. One can always be kind to people about whom one cares nothing. But she would have soon found out that you were absolutely indifferent to her. And when a woman finds that out about her husband, she either becomes dreadfully dowdy, or wears very smart bonnets that some other woman's husband has to pay for. I say nothing about the social mistake, which would have been abject--which, of course, I would not have allowed-- but I assure you that in any case the whole thing would have been an absolute failure." "I suppose it would," muttered the lad, walking up and down the room and looking horribly pale. "But I thought it was my duty. It is not my fault that this terrible tragedy has prevented my doing what was right. I remember your saying once that there is a fatality about good resolutions--that they are always made too late. Mine certainly were." "Good resolutions are useless attempts to interfere with scientific laws. Their origin is pure vanity. Their result is absolutely nil. They give us, now and then, some of those luxurious sterile emotions that have a certain charm for the weak. That is all that can be said for them. They are simply cheques that men draw on a bank where they have no account." "Harry," cried Dorian Gray, coming over and sitting down beside him, "why is it that I cannot feel this tragedy as much as I want to? I don't think I am heartless. Do you?" "You have done too many foolish things during the last fortnight to be entitled to give yourself that name, Dorian," answered Lord Henry with his sweet melancholy smile. The lad frowned. "I don't like that explanation, Harry," he rejoined, "but I am glad you don't think I am heartless. I am nothing of the kind. I know I am not. And yet I must admit that this thing that has happened does not affect me as it should. It seems to me to be simply like a wonderful ending to a wonderful play. It has all the terrible beauty of a Greek tragedy, a tragedy in which I took a great part, but by which I have not been wounded." "It is an interesting question," said Lord Henry, who found an exquisite pleasure in playing on the lad's unconscious egotism, "an extremely interesting question. I fancy that the true explanation is this: It often happens that the real tragedies of life occur in such an inartistic manner that they hurt us by their crude violence, their absolute incoherence, their absurd want of meaning, their entire lack of style. They affect us just as vulgarity affects us. They give us an impression of sheer brute force, and we revolt against that. Sometimes, however, a tragedy that possesses artistic elements of beauty crosses our lives. If these elements of beauty are real, the whole thing simply appeals to our sense of dramatic effect. Suddenly we find that we are no longer the actors, but the spectators of the play. Or rather we are both. We watch ourselves, and the mere wonder of the spectacle enthralls us. In the present case, what is it that has really happened? Some one has killed herself for love of you. I wish that I had ever had such an experience. It would have made me in love with love for the rest of my life. The people who have adored me--there have not been very many, but there have been some--have always insisted on living on, long after I had ceased to care for them, or they to care for me. They have become stout and tedious, and when I meet them, they go in at once for reminiscences. That awful memory of woman! What a fearful thing it is! And what an utter intellectual stagnation it reveals! One should absorb the colour of life, but one should never remember its details. Details are always vulgar." "I must sow poppies in my garden," sighed Dorian. "There is no necessity," rejoined his companion. "Life has always poppies in her hands. Of course, now and then things linger. I once wore nothing but violets all through one season, as a form of artistic mourning for a romance that would not die. Ultimately, however, it did die. I forget what killed it. I think it was her proposing to sacrifice the whole world for me. That is always a dreadful moment. It fills one with the terror of eternity. Well--would you believe it?--a week ago, at Lady Hampshire's, I found myself seated at dinner next the lady in question, and she insisted on going over the whole thing again, and digging up the past, and raking up the future. I had buried my romance in a bed of asphodel. She dragged it out again and assured me that I had spoiled her life. I am bound to state that she ate an enormous dinner, so I did not feel any anxiety. But what a lack of taste she showed! The one charm of the past is that it is the past. But women never know when the curtain has fallen. They always want a sixth act, and as soon as the interest of the play is entirely over, they propose to continue it. If they were allowed their own way, every comedy would have a tragic ending, and every tragedy would culminate in a farce. They are charmingly artificial, but they have no sense of art. You are more fortunate than I am. I assure you, Dorian, that not one of the women I have known would have done for me what Sibyl Vane did for you. Ordinary women always console themselves. Some of them do it by going in for sentimental colours. Never trust a woman who wears mauve, whatever her age may be, or a woman over thirty-five who is fond of pink ribbons. It always means that they have a history. Others find a great consolation in suddenly discovering the good qualities of their husbands. They flaunt their conjugal felicity in one's face, as if it were the most fascinating of sins. Religion consoles some. Its mysteries have all the charm of a flirtation, a woman once told me, and I can quite understand it. Besides, nothing makes one so vain as being told that one is a sinner. Conscience makes egotists of us all. Yes; there is really no end to the consolations that women find in modern life. Indeed, I have not mentioned the most important one." "What is that, Harry?" said the lad listlessly. "Oh, the obvious consolation. Taking some one else's admirer when one loses one's own. In good society that always whitewashes a woman. But really, Dorian, how different Sibyl Vane must have been from all the women one meets! There is something to me quite beautiful about her death. I am glad I am living in a century when such wonders happen. They make one believe in the reality of the things we all play with, such as romance, passion, and love." "I was terribly cruel to her. You forget that." "I am afraid that women appreciate cruelty, downright cruelty, more than anything else. They have wonderfully primitive instincts. We have emancipated them, but they remain slaves looking for their masters, all the same. They love being dominated. I am sure you were splendid. I have never seen you really and absolutely angry, but I can fancy how delightful you looked. And, after all, you said something to me the day before yesterday that seemed to me at the time to be merely fanciful, but that I see now was absolutely true, and it holds the key to everything." "What was that, Harry?" "You said to me that Sibyl Vane represented to you all the heroines of romance--that she was Desdemona one night, and Ophelia the other; that if she died as Juliet, she came to life as Imogen." "She will never come to life again now," muttered the lad, burying his face in his hands. "No, she will never come to life. She has played her last part. But you must think of that lonely death in the tawdry dressing-room simply as a strange lurid fragment from some Jacobean tragedy, as a wonderful scene from Webster, or Ford, or Cyril Tourneur. The girl never really lived, and so she has never really died. To you at least she was always a dream, a phantom that flitted through Shakespeare's plays and left them lovelier for its presence, a reed through which Shakespeare's music sounded richer and more full of joy. The moment she touched actual life, she marred it, and it marred her, and so she passed away. Mourn for Ophelia, if you like. Put ashes on your head because Cordelia was strangled. Cry out against Heaven because the daughter of Brabantio died. But don't waste your tears over Sibyl Vane. She was less real than they are." There was a silence. The evening darkened in the room. Noiselessly, and with silver feet, the shadows crept in from the garden. The colours faded wearily out of things. After some time Dorian Gray looked up. "You have explained me to myself, Harry," he murmured with something of a sigh of relief. "I felt all that you have said, but somehow I was afraid of it, and I could not express it to myself. How well you know me! But we will not talk again of what has happened. It has been a marvellous experience. That is all. I wonder if life has still in store for me anything as marvellous." "Life has everything in store for you, Dorian. There is nothing that you, with your extraordinary good looks, will not be able to do." "But suppose, Harry, I became haggard, and old, and wrinkled? What then?" "Ah, then," said Lord Henry, rising to go, "then, my dear Dorian, you would have to fight for your victories. As it is, they are brought to you. No, you must keep your good looks. We live in an age that reads too much to be wise, and that thinks too much to be beautiful. We cannot spare you. And now you had better dress and drive down to the club. We are rather late, as it is." "I think I shall join you at the opera, Harry. I feel too tired to eat anything. What is the number of your sister's box?" "Twenty-seven, I believe. It is on the grand tier. You will see her name on the door. But I am sorry you won't come and dine." "I don't feel up to it," said Dorian listlessly. "But I am awfully obliged to you for all that you have said to me. You are certainly my best friend. No one has ever understood me as you have." "We are only at the beginning of our friendship, Dorian," answered Lord Henry, shaking him by the hand. "Good-bye. I shall see you before nine-thirty, I hope. Remember, Patti is singing." As he closed the door behind him, Dorian Gray touched the bell, and in a few minutes Victor appeared with the lamps and drew the blinds down. He waited impatiently for him to go. The man seemed to take an interminable time over everything. As soon as he had left, he rushed to the screen and drew it back. No; there was no further change in the picture. It had received the news of Sibyl Vane's death before he had known of it himself. It was conscious of the events of life as they occurred. The vicious cruelty that marred the fine lines of the mouth had, no doubt, appeared at the very moment that the girl had drunk the poison, whatever it was. Or was it indifferent to results? Did it merely take cognizance of what passed within the soul? He wondered, and hoped that some day he would see the change taking place before his very eyes, shuddering as he hoped it. Poor Sibyl! What a romance it had all been! She had often mimicked death on the stage. Then Death himself had touched her and taken her with him. How had she played that dreadful last scene? Had she cursed him, as she died? No; she had died for love of him, and love would always be a sacrament to him now. She had atoned for everything by the sacrifice she had made of her life. He would not think any more of what she had made him go through, on that horrible night at the theatre. When he thought of her, it would be as a wonderful tragic figure sent on to the world's stage to show the supreme reality of love. A wonderful tragic figure? Tears came to his eyes as he remembered her childlike look, and winsome fanciful ways, and shy tremulous grace. He brushed them away hastily and looked again at the picture. He felt that the time had really come for making his choice. Or had his choice already been made? Yes, life had decided that for him--life, and his own infinite curiosity about life. Eternal youth, infinite passion, pleasures subtle and secret, wild joys and wilder sins--he was to have all these things. The portrait was to bear the burden of his shame: that was all. A feeling of pain crept over him as he thought of the desecration that was in store for the fair face on the canvas. Once, in boyish mockery of Narcissus, he had kissed, or feigned to kiss, those painted lips that now smiled so cruelly at him. Morning after morning he had sat before the portrait wondering at its beauty, almost enamoured of it, as it seemed to him at times. Was it to alter now with every mood to which he yielded? Was it to become a monstrous and loathsome thing, to be hidden away in a locked room, to be shut out from the sunlight that had so often touched to brighter gold the waving wonder of its hair? The pity of it! the pity of it! For a moment, he thought of praying that the horrible sympathy that existed between him and the picture might cease. It had changed in answer to a prayer; perhaps in answer to a prayer it might remain unchanged. And yet, who, that knew anything about life, would surrender the chance of remaining always young, however fantastic that chance might be, or with what fateful consequences it might be fraught? Besides, was it really under his control? Had it indeed been prayer that had produced the substitution? Might there not be some curious scientific reason for it all? If thought could exercise its influence upon a living organism, might not thought exercise an influence upon dead and inorganic things? Nay, without thought or conscious desire, might not things external to ourselves vibrate in unison with our moods and passions, atom calling to atom in secret love or strange affinity? But the reason was of no importance. He would never again tempt by a prayer any terrible power. If the picture was to alter, it was to alter. That was all. Why inquire too closely into it? For there would be a real pleasure in watching it. He would be able to follow his mind into its secret places. This portrait would be to him the most magical of mirrors. As it had revealed to him his own body, so it would reveal to him his own soul. And when winter came upon it, he would still be standing where spring trembles on the verge of summer. When the blood crept from its face, and left behind a pallid mask of chalk with leaden eyes, he would keep the glamour of boyhood. Not one blossom of his loveliness would ever fade. Not one pulse of his life would ever weaken. Like the gods of the Greeks, he would be strong, and fleet, and joyous. What did it matter what happened to the coloured image on the canvas? He would be safe. That was everything. He drew the screen back into its former place in front of the picture, smiling as he did so, and passed into his bedroom, where his valet was already waiting for him. An hour later he was at the opera, and Lord Henry was leaning over his chair. CHAPTER 9 As he was sitting at breakfast next morning, Basil Hallward was shown into the room. "I am so glad I have found you, Dorian," he said gravely. "I called last night, and they told me you were at the opera. Of course, I knew that was impossible. But I wish you had left word where you had really gone to. I passed a dreadful evening, half afraid that one tragedy might be followed by another. I think you might have telegraphed for me when you heard of it first. I read of it quite by chance in a late edition of The Globe that I picked up at the club. I came here at once and was miserable at not finding you. I can't tell you how heart-broken I am about the whole thing. I know what you must suffer. But where were you? Did you go down and see the girl's mother? For a moment I thought of following you there. They gave the address in the paper. Somewhere in the Euston Road, isn't it? But I was afraid of intruding upon a sorrow that I could not lighten. Poor woman! What a state she must be in! And her only child, too! What did she say about it all?" "My dear Basil, how do I know?" murmured Dorian Gray, sipping some pale-yellow wine from a delicate, gold-beaded bubble of Venetian glass and looking dreadfully bored. "I was at the opera. You should have come on there. I met Lady Gwendolen, Harry's sister, for the first time. We were in her box. She is perfectly charming; and Patti sang divinely. Don't talk about horrid subjects. If one doesn't talk about a thing, it has never happened. It is simply expression, as Harry says, that gives reality to things. I may mention that she was not the woman's only child. There is a son, a charming fellow, I believe. But he is not on the stage. He is a sailor, or something. And now, tell me about yourself and what you are painting." "You went to the opera?" said Hallward, speaking very slowly and with a strained touch of pain in his voice. "You went to the opera while Sibyl Vane was lying dead in some sordid lodging? You can talk to me of other women being charming, and of Patti singing divinely, before the girl you loved has even the quiet of a grave to sleep in? Why, man, there are horrors in store for that little white body of hers!" "Stop, Basil! I won't hear it!" cried Dorian, leaping to his feet. "You must not tell me about things. What is done is done. What is past is past." "You call yesterday the past?" "What has the actual lapse of time got to do with it? It is only shallow people who require years to get rid of an emotion. A man who is master of himself can end a sorrow as easily as he can invent a pleasure. I don't want to be at the mercy of my emotions. I want to use them, to enjoy them, and to dominate them." "Dorian, this is horrible! Something has changed you completely. You look exactly the same wonderful boy who, day after day, used to come down to my studio to sit for his picture. But you were simple, natural, and affectionate then. You were the most unspoiled creature in the whole world. Now, I don't know what has come over you. You talk as if you had no heart, no pity in you. It is all Harry's influence. I see that." The lad flushed up and, going to the window, looked out for a few moments on the green, flickering, sun-lashed garden. "I owe a great deal to Harry, Basil," he said at last, "more than I owe to you. You only taught me to be vain." "Well, I am punished for that, Dorian--or shall be some day." "I don't know what you mean, Basil," he exclaimed, turning round. "I don't know what you want. What do you want?" "I want the Dorian Gray I used to paint," said the artist sadly. "Basil," said the lad, going over to him and putting his hand on his shoulder, "you have come too late. Yesterday, when I heard that Sibyl Vane had killed herself--" "Killed herself! Good heavens! is there no doubt about that?" cried Hallward, looking up at him with an expression of horror. "My dear Basil! Surely you don't think it was a vulgar accident? Of course she killed herself." The elder man buried his face in his hands. "How fearful," he muttered, and a shudder ran through him. "No," said Dorian Gray, "there is nothing fearful about it. It is one of the great romantic tragedies of the age. As a rule, people who act lead the most commonplace lives. They are good husbands, or faithful wives, or something tedious. You know what I mean--middle-class virtue and all that kind of thing. How different Sibyl was! She lived her finest tragedy. She was always a heroine. The last night she played-- the night you saw her--she acted badly because she had known the reality of love. When she knew its unreality, she died, as Juliet might have died. She passed again into the sphere of art. There is something of the martyr about her. Her death has all the pathetic uselessness of martyrdom, all its wasted beauty. But, as I was saying, you must not think I have not suffered. If you had come in yesterday at a particular moment-- about half-past five, perhaps, or a quarter to six-- you would have found me in tears. Even Harry, who was here, who brought me the news, in fact, had no idea what I was going through. I suffered immensely. Then it passed away. I cannot repeat an emotion. No one can, except sentimentalists. And you are awfully unjust, Basil. You come down here to console me. That is charming of you. You find me consoled, and you are furious. How like a sympathetic person! You remind me of a story Harry told me about a certain philanthropist who spent twenty years of his life in trying to get some grievance redressed, or some unjust law altered--I forget exactly what it was. Finally he succeeded, and nothing could exceed his disappointment. He had absolutely nothing to do, almost died of ennui, and became a confirmed misanthrope. And besides, my dear old Basil, if you really want to console me, teach me rather to forget what has happened, or to see it from a proper artistic point of view. Was it not Gautier who used to write about la consolation des arts? I remember picking up a little vellum-covered book in your studio one day and chancing on that delightful phrase. Well, I am not like that young man you told me of when we were down at Marlow together, the young man who used to say that yellow satin could console one for all the miseries of life. I love beautiful things that one can touch and handle. Old brocades, green bronzes, lacquer-work, carved ivories, exquisite surroundings, luxury, pomp--there is much to be got from all these. But the artistic temperament that they create, or at any rate reveal, is still more to me. To become the spectator of one's own life, as Harry says, is to escape the suffering of life. I know you are surprised at my talking to you like this. You have not realized how I have developed. I was a schoolboy when you knew me. I am a man now. I have new passions, new thoughts, new ideas. I am different, but you must not like me less. I am changed, but you must always be my friend. Of course, I am very fond of Harry. But I know that you are better than he is. You are not stronger-- you are too much afraid of life--but you are better. And how happy we used to be together! Don't leave me, Basil, and don't quarrel with me. I am what I am. There is nothing more to be said." The painter felt strangely moved. The lad was infinitely dear to him, and his personality had been the great turning point in his art. He could not bear the idea of reproaching him any more. After all, his indifference was probably merely a mood that would pass away. There was so much in him that was good, so much in him that was noble. "Well, Dorian," he said at length, with a sad smile, "I won't speak to you again about this horrible thing, after to-day. I only trust your name won't be mentioned in connection with it. The inquest is to take place this afternoon. Have they summoned you?" Dorian shook his head, and a look of annoyance passed over his face at the mention of the word "inquest." There was something so crude and vulgar about everything of the kind. "They don't know my name," he answered. "But surely she did?" "Only my Christian name, and that I am quite sure she never mentioned to any one. She told me once that they were all rather curious to learn who I was, and that she invariably told them my name was Prince Charming. It was pretty of her. You must do me a drawing of Sibyl, Basil. I should like to have something more of her than the memory of a few kisses and some broken pathetic words." "I will try and do something, Dorian, if it would please you. But you must come and sit to me yourself again. I can't get on without you." "I can never sit to you again, Basil. It is impossible!" he exclaimed, starting back. The painter stared at him. "My dear boy, what nonsense!" he cried. "Do you mean to say you don't like what I did of you? Where is it? Why have you pulled the screen in front of it? Let me look at it. It is the best thing I have ever done. Do take the screen away, Dorian. It is simply disgraceful of your servant hiding my work like that. I felt the room looked different as I came in." "My servant has nothing to do with it, Basil. You don't imagine I let him arrange my room for me? He settles my flowers for me sometimes-- that is all. No; I did it myself. The light was too strong on the portrait." "Too strong! Surely not, my dear fellow? It is an admirable place for it. Let me see it." And Hallward walked towards the corner of the room. A cry of terror broke from Dorian Gray's lips, and he rushed between the painter and the screen. "Basil," he said, looking very pale, "you must not look at it. I don't wish you to." "Not look at my own work! You are not serious. Why shouldn't I look at it?" exclaimed Hallward, laughing. "If you try to look at it, Basil, on my word of honour I will never speak to you again as long as I live. I am quite serious. I don't offer any explanation, and you are not to ask for any. But, remember, if you touch this screen, everything is over between us." Hallward was thunderstruck. He looked at Dorian Gray in absolute amazement. He had never seen him like this before. The lad was actually pallid with rage. His hands were clenched, and the pupils of his eyes were like disks of blue fire. He was trembling all over. "Dorian!" "Don't speak!" "But what is the matter? Of course I won't look at it if you don't want me to," he said, rather coldly, turning on his heel and going over towards the window. "But, really, it seems rather absurd that I shouldn't see my own work, especially as I am going to exhibit it in Paris in the autumn. I shall probably have to give it another coat of varnish before that, so I must see it some day, and why not to-day?" "To exhibit it! You want to exhibit it?" exclaimed Dorian Gray, a strange sense of terror creeping over him. Was the world going to be shown his secret? Were people to gape at the mystery of his life? That was impossible. Something--he did not know what--had to be done at once. "Yes; I don't suppose you will object to that. Georges Petit is going to collect all my best pictures for a special exhibition in the Rue de Seze, which will open the first week in October. The portrait will only be away a month. I should think you could easily spare it for that time. In fact, you are sure to be out of town. And if you keep it always behind a screen, you can't care much about it." Dorian Gray passed his hand over his forehead. There were beads of perspiration there. He felt that he was on the brink of a horrible danger. "You told me a month ago that you would never exhibit it," he cried. "Why have you changed your mind? You people who go in for being consistent have just as many moods as others have. The only difference is that your moods are rather meaningless. You can't have forgotten that you assured me most solemnly that nothing in the world would induce you to send it to any exhibition. You told Harry exactly the same thing." He stopped suddenly, and a gleam of light came into his eyes. He remembered that Lord Henry had said to him once, half seriously and half in jest, "If you want to have a strange quarter of an hour, get Basil to tell you why he won't exhibit your picture. He told me why he wouldn't, and it was a revelation to me." Yes, perhaps Basil, too, had his secret. He would ask him and try. "Basil," he said, coming over quite close and looking him straight in the face, "we have each of us a secret. Let me know yours, and I shall tell you mine. What was your reason for refusing to exhibit my picture?" The painter shuddered in spite of himself. "Dorian, if I told you, you might like me less than you do, and you would certainly laugh at me. I could not bear your doing either of those two things. If you wish me never to look at your picture again, I am content. I have always you to look at. If you wish the best work I have ever done to be hidden from the world, I am satisfied. Your friendship is dearer to me than any fame or reputation." "No, Basil, you must tell me," insisted Dorian Gray. "I think I have a right to know." His feeling of terror had passed away, and curiosity had taken its place. He was determined to find out Basil Hallward's mystery. "Let us sit down, Dorian," said the painter, looking troubled. "Let us sit down. And just answer me one question. Have you noticed in the picture something curious?--something that probably at first did not strike you, but that revealed itself to you suddenly?" "Basil!" cried the lad, clutching the arms of his chair with trembling hands and gazing at him with wild startled eyes. "I see you did. Don't speak. Wait till you hear what I have to say. Dorian, from the moment I met you, your personality had the most extraordinary influence over me. I was dominated, soul, brain, and power, by you. You became to me the visible incarnation of that unseen ideal whose memory haunts us artists like an exquisite dream. I worshipped you. I grew jealous of every one to whom you spoke. I wanted to have you all to myself. I was only happy when I was with you. When you were away from me, you were still present in my art.... Of course, I never let you know anything about this. It would have been impossible. You would not have understood it. I hardly understood it myself. I only knew that I had seen perfection face to face, and that the world had become wonderful to my eyes-- too wonderful, perhaps, for in such mad worships there is peril, the peril of losing them, no less than the peril of keeping them.... Weeks and weeks went on, and I grew more and more absorbed in you. Then came a new development. I had drawn you as Paris in dainty armour, and as Adonis with huntsman's cloak and polished boar-spear. Crowned with heavy lotus-blossoms you had sat on the prow of Adrian's barge, gazing across the green turbid Nile. You had leaned over the still pool of some Greek woodland and seen in the water's silent silver the marvel of your own face. And it had all been what art should be--unconscious, ideal, and remote. One day, a fatal day I sometimes think, I determined to paint a wonderful portrait of you as you actually are, not in the costume of dead ages, but in your own dress and in your own time. Whether it was the realism of the method, or the mere wonder of your own personality, thus directly presented to me without mist or veil, I cannot tell. But I know that as I worked at it, every flake and film of colour seemed to me to reveal my secret. I grew afraid that others would know of my idolatry. I felt, Dorian, that I had told too much, that I had put too much of myself into it. Then it was that I resolved never to allow the picture to be exhibited. You were a little annoyed; but then you did not realize all that it meant to me. Harry, to whom I talked about it, laughed at me. But I did not mind that. When the picture was finished, and I sat alone with it, I felt that I was right.... Well, after a few days the thing left my studio, and as soon as I had got rid of the intolerable fascination of its presence, it seemed to me that I had been foolish in imagining that I had seen anything in it, more than that you were extremely good-looking and that I could paint. Even now I cannot help feeling that it is a mistake to think that the passion one feels in creation is ever really shown in the work one creates. Art is always more abstract than we fancy. Form and colour tell us of form and colour--that is all. It often seems to me that art conceals the artist far more completely than it ever reveals him. And so when I got this offer from Paris, I determined to make your portrait the principal thing in my exhibition. It never occurred to me that you would refuse. I see now that you were right. The picture cannot be shown. You must not be angry with me, Dorian, for what I have told you. As I said to Harry, once, you are made to be worshipped." Dorian Gray drew a long breath. The colour came back to his cheeks, and a smile played about his lips. The peril was over. He was safe for the time. Yet he could not help feeling infinite pity for the painter who had just made this strange confession to him, and wondered if he himself would ever be so dominated by the personality of a friend. Lord Henry had the charm of being very dangerous. But that was all. He was too clever and too cynical to be really fond of. Would there ever be some one who would fill him with a strange idolatry? Was that one of the things that life had in store? "It is extraordinary to me, Dorian," said Hallward, "that you should have seen this in the portrait. Did you really see it?" "I saw something in it," he answered, "something that seemed to me very curious." "Well, you don't mind my looking at the thing now?" Dorian shook his head. "You must not ask me that, Basil. I could not possibly let you stand in front of that picture." "You will some day, surely?" "Never." "Well, perhaps you are right. And now good-bye, Dorian. You have been the one person in my life who has really influenced my art. Whatever I have done that is good, I owe to you. Ah! you don't know what it cost me to tell you all that I have told you." "My dear Basil," said Dorian, "what have you told me? Simply that you felt that you admired me too much. That is not even a compliment." "It was not intended as a compliment. It was a confession. Now that I have made it, something seems to have gone out of me. Perhaps one should never put one's worship into words." "It was a very disappointing confession." "Why, what did you expect, Dorian? You didn't see anything else in the picture, did you? There was nothing else to see?" "No; there was nothing else to see. Why do you ask? But you mustn't talk about worship. It is foolish. You and I are friends, Basil, and we must always remain so." "You have got Harry," said the painter sadly. "Oh, Harry!" cried the lad, with a ripple of laughter. "Harry spends his days in saying what is incredible and his evenings in doing what is improbable. Just the sort of life I would like to lead. But still I don't think I would go to Harry if I were in trouble. I would sooner go to you, Basil." "You will sit to me again?" "Impossible!" "You spoil my life as an artist by refusing, Dorian. No man comes across two ideal things. Few come across one." "I can't explain it to you, Basil, but I must never sit to you again. There is something fatal about a portrait. It has a life of its own. I will come and have tea with you. That will be just as pleasant." "Pleasanter for you, I am afraid," murmured Hallward regretfully. "And now good-bye. I am sorry you won't let me look at the picture once again. But that can't be helped. I quite understand what you feel about it." As he left the room, Dorian Gray smiled to himself. Poor Basil! How little he knew of the true reason! And how strange it was that, instead of having been forced to reveal his own secret, he had succeeded, almost by chance, in wresting a secret from his friend! How much that strange confession explained to him! The painter's absurd fits of jealousy, his wild devotion, his extravagant panegyrics, his curious reticences-- he understood them all now, and he felt sorry. There seemed to him to be something tragic in a friendship so coloured by romance. He sighed and touched the bell. The portrait must be hidden away at all costs. He could not run such a risk of discovery again. It had been mad of him to have allowed the thing to remain, even for an hour, in a room to which any of his friends had access. CHAPTER 10 When his servant entered, he looked at him steadfastly and wondered if he had thought of peering behind the screen. The man was quite impassive and waited for his orders. Dorian lit a cigarette and walked over to the glass and glanced into it. He could see the reflection of Victor's face perfectly. It was like a placid mask of servility. There was nothing to be afraid of, there. Yet he thought it best to be on his guard. Speaking very slowly, he told him to tell the house-keeper that he wanted to see her, and then to go to the frame-maker and ask him to send two of his men round at once. It seemed to him that as the man left the room his eyes wandered in the direction of the screen. Or was that merely his own fancy? After a few moments, in her black silk dress, with old-fashioned thread mittens on her wrinkled hands, Mrs. Leaf bustled into the library. He asked her for the key of the schoolroom. "The old schoolroom, Mr. Dorian?" she exclaimed. "Why, it is full of dust. I must get it arranged and put straight before you go into it. It is not fit for you to see, sir. It is not, indeed." "I don't want it put straight, Leaf. I only want the key." "Well, sir, you'll be covered with cobwebs if you go into it. Why, it hasn't been opened for nearly five years--not since his lordship died." He winced at the mention of his grandfather. He had hateful memories of him. "That does not matter," he answered. "I simply want to see the place-- that is all. Give me the key." "And here is the key, sir," said the old lady, going over the contents of her bunch with tremulously uncertain hands. "Here is the key. I'll have it off the bunch in a moment. But you don't think of living up there, sir, and you so comfortable here?" "No, no," he cried petulantly. "Thank you, Leaf. That will do." She lingered for a few moments, and was garrulous over some detail of the household. He sighed and told her to manage things as she thought best. She left the room, wreathed in smiles. As the door closed, Dorian put the key in his pocket and looked round the room. His eye fell on a large, purple satin coverlet heavily embroidered with gold, a splendid piece of late seventeenth-century Venetian work that his grandfather had found in a convent near Bologna. Yes, that would serve to wrap the dreadful thing in. It had perhaps served often as a pall for the dead. Now it was to hide something that had a corruption of its own, worse than the corruption of death itself-- something that would breed horrors and yet would never die. What the worm was to the corpse, his sins would be to the painted image on the canvas. They would mar its beauty and eat away its grace. They would defile it and make it shameful. And yet the thing would still live on. It would be always alive. He shuddered, and for a moment he regretted that he had not told Basil the true reason why he had wished to hide the picture away. Basil would have helped him to resist Lord Henry's influence, and the still more poisonous influences that came from his own temperament. The love that he bore him--for it was really love-- had nothing in it that was not noble and intellectual. It was not that mere physical admiration of beauty that is born of the senses and that dies when the senses tire. It was such love as Michelangelo had known, and Montaigne, and Winckelmann, and Shakespeare himself. Yes, Basil could have saved him. But it was too late now. The past could always be annihilated. Regret, denial, or forgetfulness could do that. But the future was inevitable. There were passions in him that would find their terrible outlet, dreams that would make the shadow of their evil real. He took up from the couch the great purple-and-gold texture that covered it, and, holding it in his hands, passed behind the screen. Was the face on the canvas viler than before? It seemed to him that it was unchanged, and yet his loathing of it was intensified. Gold hair, blue eyes, and rose-red lips--they all were there. It was simply the expression that had altered. That was horrible in its cruelty. Compared to what he saw in it of censure or rebuke, how shallow Basil's reproaches about Sibyl Vane had been!-- how shallow, and of what little account! His own soul was looking out at him from the canvas and calling him to judgement. A look of pain came across him, and he flung the rich pall over the picture. As he did so, a knock came to the door. He passed out as his servant entered. "The persons are here, Monsieur." He felt that the man must be got rid of at once. He must not be allowed to know where the picture was being taken to. There was something sly about him, and he had thoughtful, treacherous eyes. Sitting down at the writing-table he scribbled a note to Lord Henry, asking him to send him round something to read and reminding him that they were to meet at eight-fifteen that evening. "Wait for an answer," he said, handing it to him, "and show the men in here." In two or three minutes there was another knock, and Mr. Hubbard himself, the celebrated frame-maker of South Audley Street, came in with a somewhat rough-looking young assistant. Mr. Hubbard was a florid, red-whiskered little man, whose admiration for art was considerably tempered by the inveterate impecuniosity of most of the artists who dealt with him. As a rule, he never left his shop. He waited for people to come to him. But he always made an exception in favour of Dorian Gray. There was something about Dorian that charmed everybody. It was a pleasure even to see him. "What can I do for you, Mr. Gray?" he said, rubbing his fat freckled hands. "I thought I would do myself the honour of coming round in person. I have just got a beauty of a frame, sir. Picked it up at a sale. Old Florentine. Came from Fonthill, I believe. Admirably suited for a religious subject, Mr. Gray." "I am so sorry you have given yourself the trouble of coming round, Mr. Hubbard. I shall certainly drop in and look at the frame-- though I don't go in much at present for religious art--but to-day I only want a picture carried to the top of the house for me. It is rather heavy, so I thought I would ask you to lend me a couple of your men." "No trouble at all, Mr. Gray. I am delighted to be of any service to you. Which is the work of art, sir?" "This," replied Dorian, moving the screen back. "Can you move it, covering and all, just as it is? I don't want it to get scratched going upstairs." "There will be no difficulty, sir," said the genial frame-maker, beginning, with the aid of his assistant, to unhook the picture from the long brass chains by which it was suspended. "And, now, where shall we carry it to, Mr. Gray?" "I will show you the way, Mr. Hubbard, if you will kindly follow me. Or perhaps you had better go in front. I am afraid it is right at the top of the house. We will go up by the front staircase, as it is wider." He held the door open for them, and they passed out into the hall and began the ascent. The elaborate character of the frame had made the picture extremely bulky, and now and then, in spite of the obsequious protests of Mr. Hubbard, who had the true tradesman's spirited dislike of seeing a gentleman doing anything useful, Dorian put his hand to it so as to help them. "Something of a load to carry, sir," gasped the little man when they reached the top landing. And he wiped his shiny forehead. "I am afraid it is rather heavy," murmured Dorian as he unlocked the door that opened into the room that was to keep for him the curious secret of his life and hide his soul from the eyes of men. He had not entered the place for more than four years--not, indeed, since he had used it first as a play-room when he was a child, and then as a study when he grew somewhat older. It was a large, well-proportioned room, which had been specially built by the last Lord Kelso for the use of the little grandson whom, for his strange likeness to his mother, and also for other reasons, he had always hated and desired to keep at a distance. It appeared to Dorian to have but little changed. There was the huge Italian cassone, with its fantastically painted panels and its tarnished gilt mouldings, in which he had so often hidden himself as a boy. There the satinwood book-case filled with his dog-eared schoolbooks. On the wall behind it was hanging the same ragged Flemish tapestry where a faded king and queen were playing chess in a garden, while a company of hawkers rode by, carrying hooded birds on their gauntleted wrists. How well he remembered it all! Every moment of his lonely childhood came back to him as he looked round. He recalled the stainless purity of his boyish life, and it seemed horrible to him that it was here the fatal portrait was to be hidden away. How little he had thought, in those dead days, of all that was in store for him! But there was no other place in the house so secure from prying eyes as this. He had the key, and no one else could enter it. Beneath its purple pall, the face painted on the canvas could grow bestial, sodden, and unclean. What did it matter? No one could see it. He himself would not see it. Why should he watch the hideous corruption of his soul? He kept his youth-- that was enough. And, besides, might not his nature grow finer, after all? There was no reason that the future should be so full of shame. Some love might come across his life, and purify him, and shield him from those sins that seemed to be already stirring in spirit and in flesh-- those curious unpictured sins whose very mystery lent them their subtlety and their charm. Perhaps, some day, the cruel look would have passed away from the scarlet sensitive mouth, and he might show to the world Basil Hallward's masterpiece. No; that was impossible. Hour by hour, and week by week, the thing upon the canvas was growing old. It might escape the hideousness of sin, but the hideousness of age was in store for it. The cheeks would become hollow or flaccid. Yellow crow's feet would creep round the fading eyes and make them horrible. The hair would lose its brightness, the mouth would gape or droop, would be foolish or gross, as the mouths of old men are. There would be the wrinkled throat, the cold, blue-veined hands, the twisted body, that he remembered in the grandfather who had been so stern to him in his boyhood. The picture had to be concealed. There was no help for it. "Bring it in, Mr. Hubbard, please," he said, wearily, turning round. "I am sorry I kept you so long. I was thinking of something else." "Always glad to have a rest, Mr. Gray," answered the frame-maker, who was still gasping for breath. "Where shall we put it, sir?" "Oh, anywhere. Here: this will do. I don't want to have it hung up. Just lean it against the wall. Thanks." "Might one look at the work of art, sir?" Dorian started. "It would not interest you, Mr. Hubbard," he said, keeping his eye on the man. He felt ready to leap upon him and fling him to the ground if he dared to lift the gorgeous hanging that concealed the secret of his life. "I shan't trouble you any more now. I am much obliged for your kindness in coming round." "Not at all, not at all, Mr. Gray. Ever ready to do anything for you, sir." And Mr. Hubbard tramped downstairs, followed by the assistant, who glanced back at Dorian with a look of shy wonder in his rough uncomely face. He had never seen any one so marvellous. When the sound of their footsteps had died away, Dorian locked the door and put the key in his pocket. He felt safe now. No one would ever look upon the horrible thing. No eye but his would ever see his shame. On reaching the library, he found that it was just after five o'clock and that the tea had been already brought up. On a little table of dark perfumed wood thickly incrusted with nacre, a present from Lady Radley, his guardian's wife, a pretty professional invalid who had spent the preceding winter in Cairo, was lying a note from Lord Henry, and beside it was a book bound in yellow paper, the cover slightly torn and the edges soiled. A copy of the third edition of The St. James's Gazette had been placed on the tea-tray. It was evident that Victor had returned. He wondered if he had met the men in the hall as they were leaving the house and had wormed out of them what they had been doing. He would be sure to miss the picture--had no doubt missed it already, while he had been laying the tea-things. The screen had not been set back, and a blank space was visible on the wall. Perhaps some night he might find him creeping upstairs and trying to force the door of the room. It was a horrible thing to have a spy in one's house. He had heard of rich men who had been blackmailed all their lives by some servant who had read a letter, or overheard a conversation, or picked up a card with an address, or found beneath a pillow a withered flower or a shred of crumpled lace. He sighed, and having poured himself out some tea, opened Lord Henry's note. It was simply to say that he sent him round the evening paper, and a book that might interest him, and that he would be at the club at eight-fifteen. He opened The St. James's languidly, and looked through it. A red pencil-mark on the fifth page caught his eye. It drew attention to the following paragraph: INQUEST ON AN ACTRESS.--An inquest was held this morning at the Bell Tavern, Hoxton Road, by Mr. Danby, the District Coroner, on the body of Sibyl Vane, a young actress recently engaged at the Royal Theatre, Holborn. A verdict of death by misadventure was returned. Considerable sympathy was expressed for the mother of the deceased, who was greatly affected during the giving of her own evidence, and that of Dr. Birrell, who had made the post-mortem examination of the deceased. He frowned, and tearing the paper in two, went across the room and flung the pieces away. How ugly it all was! And how horribly real ugliness made things! He felt a little annoyed with Lord Henry for having sent him the report. And it was certainly stupid of him to have marked it with red pencil. Victor might have read it. The man knew more than enough English for that. Perhaps he had read it and had begun to suspect something. And, yet, what did it matter? What had Dorian Gray to do with Sibyl Vane's death? There was nothing to fear. Dorian Gray had not killed her. His eye fell on the yellow book that Lord Henry had sent him. What was it, he wondered. He went towards the little, pearl-coloured octagonal stand that had always looked to him like the work of some strange Egyptian bees that wrought in silver, and taking up the volume, flung himself into an arm-chair and began to turn over the leaves. After a few minutes he became absorbed. It was the strangest book that he had ever read. It seemed to him that in exquisite raiment, and to the delicate sound of flutes, the sins of the world were passing in dumb show before him. Things that he had dimly dreamed of were suddenly made real to him. Things of which he had never dreamed were gradually revealed. It was a novel without a plot and with only one character, being, indeed, simply a psychological study of a certain young Parisian who spent his life trying to realize in the nineteenth century all the passions and modes of thought that belonged to every century except his own, and to sum up, as it were, in himself the various moods through which the world-spirit had ever passed, loving for their mere artificiality those renunciations that men have unwisely called virtue, as much as those natural rebellions that wise men still call sin. The style in which it was written was that curious jewelled style, vivid and obscure at once, full of argot and of archaisms, of technical expressions and of elaborate paraphrases, that characterizes the work of some of the finest artists of the French school of Symbolistes. There were in it metaphors as monstrous as orchids and as subtle in colour. The life of the senses was described in the terms of mystical philosophy. One hardly knew at times whether one was reading the spiritual ecstasies of some mediaeval saint or the morbid confessions of a modern sinner. It was a poisonous book. The heavy odour of incense seemed to cling about its pages and to trouble the brain. The mere cadence of the sentences, the subtle monotony of their music, so full as it was of complex refrains and movements elaborately repeated, produced in the mind of the lad, as he passed from chapter to chapter, a form of reverie, a malady of dreaming, that made him unconscious of the falling day and creeping shadows. Cloudless, and pierced by one solitary star, a copper-green sky gleamed through the windows. He read on by its wan light till he could read no more. Then, after his valet had reminded him several times of the lateness of the hour, he got up, and going into the next room, placed the book on the little Florentine table that always stood at his bedside and began to dress for dinner. It was almost nine o'clock before he reached the club, where he found Lord Henry sitting alone, in the morning-room, looking very much bored. "I am so sorry, Harry," he cried, "but really it is entirely your fault. That book you sent me so fascinated me that I forgot how the time was going." "Yes, I thought you would like it," replied his host, rising from his chair. "I didn't say I liked it, Harry. I said it fascinated me. There is a great difference." "Ah, you have discovered that?" murmured Lord Henry. And they passed into the dining-room. CHAPTER 11 For years, Dorian Gray could not free himself from the influence of this book. Or perhaps it would be more accurate to say that he never sought to free himself from it. He procured from Paris no less than nine large-paper copies of the first edition, and had them bound in different colours, so that they might suit his various moods and the changing fancies of a nature over which he seemed, at times, to have almost entirely lost control. The hero, the wonderful young Parisian in whom the romantic and the scientific temperaments were so strangely blended, became to him a kind of prefiguring type of himself. And, indeed, the whole book seemed to him to contain the story of his own life, written before he had lived it. In one point he was more fortunate than the novel's fantastic hero. He never knew--never, indeed, had any cause to know--that somewhat grotesque dread of mirrors, and polished metal surfaces, and still water which came upon the young Parisian so early in his life, and was occasioned by the sudden decay of a beau that had once, apparently, been so remarkable. It was with an almost cruel joy-- and perhaps in nearly every joy, as certainly in every pleasure, cruelty has its place--that he used to read the latter part of the book, with its really tragic, if somewhat overemphasized, account of the sorrow and despair of one who had himself lost what in others, and the world, he had most dearly valued. For the wonderful beauty that had so fascinated Basil Hallward, and many others besides him, seemed never to leave him. Even those who had heard the most evil things against him-- and from time to time strange rumours about his mode of life crept through London and became the chatter of the clubs-- could not believe anything to his dishonour when they saw him. He had always the look of one who had kept himself unspotted from the world. Men who talked grossly became silent when Dorian Gray entered the room. There was something in the purity of his face that rebuked them. His mere presence seemed to recall to them the memory of the innocence that they had tarnished. They wondered how one so charming and graceful as he was could have escaped the stain of an age that was at once sordid and sensual. Often, on returning home from one of those mysterious and prolonged absences that gave rise to such strange conjecture among those who were his friends, or thought that they were so, he himself would creep upstairs to the locked room, open the door with the key that never left him now, and stand, with a mirror, in front of the portrait that Basil Hallward had painted of him, looking now at the evil and aging face on the canvas, and now at the fair young face that laughed back at him from the polished glass. The very sharpness of the contrast used to quicken his sense of pleasure. He grew more and more enamoured of his own beauty, more and more interested in the corruption of his own soul. He would examine with minute care, and sometimes with a monstrous and terrible delight, the hideous lines that seared the wrinkling forehead or crawled around the heavy sensual mouth, wondering sometimes which were the more horrible, the signs of sin or the signs of age. He would place his white hands beside the coarse bloated hands of the picture, and smile. He mocked the misshapen body and the failing limbs. There were moments, indeed, at night, when, lying sleepless in his own delicately scented chamber, or in the sordid room of the little ill-famed tavern near the docks which, under an assumed name and in disguise, it was his habit to frequent, he would think of the ruin he had brought upon his soul with a pity that was all the more poignant because it was purely selfish. But moments such as these were rare. That curiosity about life which Lord Henry had first stirred in him, as they sat together in the garden of their friend, seemed to increase with gratification. The more he knew, the more he desired to know. He had mad hungers that grew more ravenous as he fed them. Yet he was not really reckless, at any rate in his relations to society. Once or twice every month during the winter, and on each Wednesday evening while the season lasted, he would throw open to the world his beautiful house and have the most celebrated musicians of the day to charm his guests with the wonders of their art. His little dinners, in the settling of which Lord Henry always assisted him, were noted as much for the careful selection and placing of those invited, as for the exquisite taste shown in the decoration of the table, with its subtle symphonic arrangements of exotic flowers, and embroidered cloths, and antique plate of gold and silver. Indeed, there were many, especially among the very young men, who saw, or fancied that they saw, in Dorian Gray the true realization of a type of which they had often dreamed in Eton or Oxford days, a type that was to combine something of the real culture of the scholar with all the grace and distinction and perfect manner of a citizen of the world. To them he seemed to be of the company of those whom Dante describes as having sought to "make themselves perfect by the worship of beauty." Like Gautier, he was one for whom "the visible world existed." And, certainly, to him life itself was the first, the greatest, of the arts, and for it all the other arts seemed to be but a preparation. Fashion, by which what is really fantastic becomes for a moment universal, and dandyism, which, in its own way, is an attempt to assert the absolute modernity of beauty, had, of course, their fascination for him. His mode of dressing, and the particular styles that from time to time he affected, had their marked influence on the young exquisites of the Mayfair balls and Pall Mall club windows, who copied him in everything that he did, and tried to reproduce the accidental charm of his graceful, though to him only half-serious, fopperies. For, while he was but too ready to accept the position that was almost immediately offered to him on his coming of age, and found, indeed, a subtle pleasure in the thought that he might really become to the London of his own day what to imperial Neronian Rome the author of the Satyricon once had been, yet in his inmost heart he desired to be something more than a mere arbiter elegantiarum, to be consulted on the wearing of a jewel, or the knotting of a necktie, or the conduct of a cane. He sought to elaborate some new scheme of life that would have its reasoned philosophy and its ordered principles, and find in the spiritualizing of the senses its highest realization. The worship of the senses has often, and with much justice, been decried, men feeling a natural instinct of terror about passions and sensations that seem stronger than themselves, and that they are conscious of sharing with the less highly organized forms of existence. But it appeared to Dorian Gray that the true nature of the senses had never been understood, and that they had remained savage and animal merely because the world had sought to starve them into submission or to kill them by pain, instead of aiming at making them elements of a new spirituality, of which a fine instinct for beauty was to be the dominant characteristic. As he looked back upon man moving through history, he was haunted by a feeling of loss. So much had been surrendered! and to such little purpose! There had been mad wilful rejections, monstrous forms of self-torture and self-denial, whose origin was fear and whose result was a degradation infinitely more terrible than that fancied degradation from which, in their ignorance, they had sought to escape; Nature, in her wonderful irony, driving out the anchorite to feed with the wild animals of the desert and giving to the hermit the beasts of the field as his companions. Yes: there was to be, as Lord Henry had prophesied, a new Hedonism that was to recreate life and to save it from that harsh uncomely puritanism that is having, in our own day, its curious revival. It was to have its service of the intellect, certainly, yet it was never to accept any theory or system that would involve the sacrifice of any mode of passionate experience. Its aim, indeed, was to be experience itself, and not the fruits of experience, sweet or bitter as they might be. Of the asceticism that deadens the senses, as of the vulgar profligacy that dulls them, it was to know nothing. But it was to teach man to concentrate himself upon the moments of a life that is itself but a moment. There are few of us who have not sometimes wakened before dawn, either after one of those dreamless nights that make us almost enamoured of death, or one of those nights of horror and misshapen joy, when through the chambers of the brain sweep phantoms more terrible than reality itself, and instinct with that vivid life that lurks in all grotesques, and that lends to Gothic art its enduring vitality, this art being, one might fancy, especially the art of those whose minds have been troubled with the malady of reverie. Gradually white fingers creep through the curtains, and they appear to tremble. In black fantastic shapes, dumb shadows crawl into the corners of the room and crouch there. Outside, there is the stirring of birds among the leaves, or the sound of men going forth to their work, or the sigh and sob of the wind coming down from the hills and wandering round the silent house, as though it feared to wake the sleepers and yet must needs call forth sleep from her purple cave. Veil after veil of thin dusky gauze is lifted, and by degrees the forms and colours of things are restored to them, and we watch the dawn remaking the world in its antique pattern. The wan mirrors get back their mimic life. The flameless tapers stand where we had left them, and beside them lies the half-cut book that we had been studying, or the wired flower that we had worn at the ball, or the letter that we had been afraid to read, or that we had read too often. Nothing seems to us changed. Out of the unreal shadows of the night comes back the real life that we had known. We have to resume it where we had left off, and there steals over us a terrible sense of the necessity for the continuance of energy in the same wearisome round of stereotyped habits, or a wild longing, it may be, that our eyelids might open some morning upon a world that had been refashioned anew in the darkness for our pleasure, a world in which things would have fresh shapes and colours, and be changed, or have other secrets, a world in which the past would have little or no place, or survive, at any rate, in no conscious form of obligation or regret, the remembrance even of joy having its bitterness and the memories of pleasure their pain. It was the creation of such worlds as these that seemed to Dorian Gray to be the true object, or amongst the true objects, of life; and in his search for sensations that would be at once new and delightful, and possess that element of strangeness that is so essential to romance, he would often adopt certain modes of thought that he knew to be really alien to his nature, abandon himself to their subtle influences, and then, having, as it were, caught their colour and satisfied his intellectual curiosity, leave them with that curious indifference that is not incompatible with a real ardour of temperament, and that, indeed, according to certain modern psychologists, is often a condition of it. It was rumoured of him once that he was about to join the Roman Catholic communion, and certainly the Roman ritual had always a great attraction for him. The daily sacrifice, more awful really than all the sacrifices of the antique world, stirred him as much by its superb rejection of the evidence of the senses as by the primitive simplicity of its elements and the eternal pathos of the human tragedy that it sought to symbolize. He loved to kneel down on the cold marble pavement and watch the priest, in his stiff flowered dalmatic, slowly and with white hands moving aside the veil of the tabernacle, or raising aloft the jewelled, lantern-shaped monstrance with that pallid wafer that at times, one would fain think, is indeed the "panis caelestis," the bread of angels, or, robed in the garments of the Passion of Christ, breaking the Host into the chalice and smiting his breast for his sins. The fuming censers that the grave boys, in their lace and scarlet, tossed into the air like great gilt flowers had their subtle fascination for him. As he passed out, he used to look with wonder at the black confessionals and long to sit in the dim shadow of one of them and listen to men and women whispering through the worn grating the true story of their lives. But he never fell into the error of arresting his intellectual development by any formal acceptance of creed or system, or of mistaking, for a house in which to live, an inn that is but suitable for the sojourn of a night, or for a few hours of a night in which there are no stars and the moon is in travail. Mysticism, with its marvellous power of making common things strange to us, and the subtle antinomianism that always seems to accompany it, moved him for a season; and for a season he inclined to the materialistic doctrines of the Darwinismus movement in Germany, and found a curious pleasure in tracing the thoughts and passions of men to some pearly cell in the brain, or some white nerve in the body, delighting in the conception of the absolute dependence of the spirit on certain physical conditions, morbid or healthy, normal or diseased. Yet, as has been said of him before, no theory of life seemed to him to be of any importance compared with life itself. He felt keenly conscious of how barren all intellectual speculation is when separated from action and experiment. He knew that the senses, no less than the soul, have their spiritual mysteries to reveal. And so he would now study perfumes and the secrets of their manufacture, distilling heavily scented oils and burning odorous gums from the East. He saw that there was no mood of the mind that had not its counterpart in the sensuous life, and set himself to discover their true relations, wondering what there was in frankincense that made one mystical, and in ambergris that stirred one's passions, and in violets that woke the memory of dead romances, and in musk that troubled the brain, and in champak that stained the imagination; and seeking often to elaborate a real psychology of perfumes, and to estimate the several influences of sweet-smelling roots and scented, pollen-laden flowers; of aromatic balms and of dark and fragrant woods; of spikenard, that sickens; of hovenia, that makes men mad; and of aloes, that are said to be able to expel melancholy from the soul. At another time he devoted himself entirely to music, and in a long latticed room, with a vermilion-and-gold ceiling and walls of olive-green lacquer, he used to give curious concerts in which mad gipsies tore wild music from little zithers, or grave, yellow-shawled Tunisians plucked at the strained strings of monstrous lutes, while grinning Negroes beat monotonously upon copper drums and, crouching upon scarlet mats, slim turbaned Indians blew through long pipes of reed or brass and charmed-- or feigned to charm--great hooded snakes and horrible horned adders. The harsh intervals and shrill discords of barbaric music stirred him at times when Schubert's grace, and Chopin's beautiful sorrows, and the mighty harmonies of Beethoven himself, fell unheeded on his ear. He collected together from all parts of the world the strangest instruments that could be found, either in the tombs of dead nations or among the few savage tribes that have survived contact with Western civilizations, and loved to touch and try them. He had the mysterious juruparis of the Rio Negro Indians, that women are not allowed to look at and that even youths may not see till they have been subjected to fasting and scourging, and the earthen jars of the Peruvians that have the shrill cries of birds, and flutes of human bones such as Alfonso de Ovalle heard in Chile, and the sonorous green jaspers that are found near Cuzco and give forth a note of singular sweetness. He had painted gourds filled with pebbles that rattled when they were shaken; the long clarin of the Mexicans, into which the performer does not blow, but through which he inhales the air; the harsh ture of the Amazon tribes, that is sounded by the sentinels who sit all day long in high trees, and can be heard, it is said, at a distance of three leagues; the teponaztli, that has two vibrating tongues of wood and is beaten with sticks that are smeared with an elastic gum obtained from the milky juice of plants; the yotl-bells of the Aztecs, that are hung in clusters like grapes; and a huge cylindrical drum, covered with the skins of great serpents, like the one that Bernal Diaz saw when he went with Cortes into the Mexican temple, and of whose doleful sound he has left us so vivid a description. The fantastic character of these instruments fascinated him, and he felt a curious delight in the thought that art, like Nature, has her monsters, things of bestial shape and with hideous voices. Yet, after some time, he wearied of them, and would sit in his box at the opera, either alone or with Lord Henry, listening in rapt pleasure to "Tannhauser" and seeing in the prelude to that great work of art a presentation of the tragedy of his own soul. On one occasion he took up the study of jewels, and appeared at a costume ball as Anne de Joyeuse, Admiral of France, in a dress covered with five hundred and sixty pearls. This taste enthralled him for years, and, indeed, may be said never to have left him. He would often spend a whole day settling and resettling in their cases the various stones that he had collected, such as the olive-green chrysoberyl that turns red by lamplight, the cymophane with its wirelike line of silver, the pistachio-coloured peridot, rose-pink and wine-yellow topazes, carbuncles of fiery scarlet with tremulous, four-rayed stars, flame-red cinnamon-stones, orange and violet spinels, and amethysts with their alternate layers of ruby and sapphire. He loved the red gold of the sunstone, and the moonstone's pearly whiteness, and the broken rainbow of the milky opal. He procured from Amsterdam three emeralds of extraordinary size and richness of colour, and had a turquoise de la vieille roche that was the envy of all the connoisseurs. He discovered wonderful stories, also, about jewels. In Alphonso's Clericalis Disciplina a serpent was mentioned with eyes of real jacinth, and in the romantic history of Alexander, the Conqueror of Emathia was said to have found in the vale of Jordan snakes "with collars of real emeralds growing on their backs." There was a gem in the brain of the dragon, Philostratus told us, and "by the exhibition of golden letters and a scarlet robe" the monster could be thrown into a magical sleep and slain. According to the great alchemist, Pierre de Boniface, the diamond rendered a man invisible, and the agate of India made him eloquent. The cornelian appeased anger, and the hyacinth provoked sleep, and the amethyst drove away the fumes of wine. The garnet cast out demons, and the hydropicus deprived the moon of her colour. The selenite waxed and waned with the moon, and the meloceus, that discovers thieves, could be affected only by the blood of kids. Leonardus Camillus had seen a white stone taken from the brain of a newly killed toad, that was a certain antidote against poison. The bezoar, that was found in the heart of the Arabian deer, was a charm that could cure the plague. In the nests of Arabian birds was the aspilates, that, according to Democritus, kept the wearer from any danger by fire. The King of Ceilan rode through his city with a large ruby in his hand, as the ceremony of his coronation. The gates of the palace of John the Priest were "made of sardius, with the horn of the horned snake inwrought, so that no man might bring poison within." Over the gable were "two golden apples, in which were two carbuncles," so that the gold might shine by day and the carbuncles by night. In Lodge's strange romance 'A Margarite of America', it was stated that in the chamber of the queen one could behold "all the chaste ladies of the world, inchased out of silver, looking through fair mirrours of chrysolites, carbuncles, sapphires, and greene emeraults." Marco Polo had seen the inhabitants of Zipangu place rose-coloured pearls in the mouths of the dead. A sea-monster had been enamoured of the pearl that the diver brought to King Perozes, and had slain the thief, and mourned for seven moons over its loss. When the Huns lured the king into the great pit, he flung it away-- Procopius tells the story--nor was it ever found again, though the Emperor Anastasius offered five hundred-weight of gold pieces for it. The King of Malabar had shown to a certain Venetian a rosary of three hundred and four pearls, one for every god that he worshipped. When the Duke de Valentinois, son of Alexander VI, visited Louis XII of France, his horse was loaded with gold leaves, according to Brantome, and his cap had double rows of rubies that threw out a great light. Charles of England had ridden in stirrups hung with four hundred and twenty-one diamonds. Richard II had a coat, valued at thirty thousand marks, which was covered with balas rubies. Hall described Henry VIII, on his way to the Tower previous to his coronation, as wearing "a jacket of raised gold, the placard embroidered with diamonds and other rich stones, and a great bauderike about his neck of large balasses." The favourites of James I wore ear-rings of emeralds set in gold filigrane. Edward II gave to Piers Gaveston a suit of red-gold armour studded with jacinths, a collar of gold roses set with turquoise-stones, and a skull-cap parseme with pearls. Henry II wore jewelled gloves reaching to the elbow, and had a hawk-glove sewn with twelve rubies and fifty-two great orients. The ducal hat of Charles the Rash, the last Duke of Burgundy of his race, was hung with pear-shaped pearls and studded with sapphires. How exquisite life had once been! How gorgeous in its pomp and decoration! Even to read of the luxury of the dead was wonderful. Then he turned his attention to embroideries and to the tapestries that performed the office of frescoes in the chill rooms of the northern nations of Europe. As he investigated the subject-- and he always had an extraordinary faculty of becoming absolutely absorbed for the moment in whatever he took up--he was almost saddened by the reflection of the ruin that time brought on beautiful and wonderful things. He, at any rate, had escaped that. Summer followed summer, and the yellow jonquils bloomed and died many times, and nights of horror repeated the story of their shame, but he was unchanged. No winter marred his face or stained his flowerlike bloom. How different it was with material things! Where had they passed to? Where was the great crocus-coloured robe, on which the gods fought against the giants, that had been worked by brown girls for the pleasure of Athena? Where the huge velarium that Nero had stretched across the Colosseum at Rome, that Titan sail of purple on which was represented the starry sky, and Apollo driving a chariot drawn by white, gilt-reined steeds? He longed to see the curious table-napkins wrought for the Priest of the Sun, on which were displayed all the dainties and viands that could be wanted for a feast; the mortuary cloth of King Chilperic, with its three hundred golden bees; the fantastic robes that excited the indignation of the Bishop of Pontus and were figured with "lions, panthers, bears, dogs, forests, rocks, hunters--all, in fact, that a painter can copy from nature"; and the coat that Charles of Orleans once wore, on the sleeves of which were embroidered the verses of a song beginning "Madame, je suis tout joyeux," the musical accompaniment of the words being wrought in gold thread, and each note, of square shape in those days, formed with four pearls. He read of the room that was prepared at the palace at Rheims for the use of Queen Joan of Burgundy and was decorated with "thirteen hundred and twenty-one parrots, made in broidery, and blazoned with the king's arms, and five hundred and sixty-one butterflies, whose wings were similarly ornamented with the arms of the queen, the whole worked in gold." Catherine de Medicis had a mourning-bed made for her of black velvet powdered with crescents and suns. Its curtains were of damask, with leafy wreaths and garlands, figured upon a gold and silver ground, and fringed along the edges with broideries of pearls, and it stood in a room hung with rows of the queen's devices in cut black velvet upon cloth of silver. Louis XIV had gold embroidered caryatides fifteen feet high in his apartment. The state bed of Sobieski, King of Poland, was made of Smyrna gold brocade embroidered in turquoises with verses from the Koran. Its supports were of silver gilt, beautifully chased, and profusely set with enamelled and jewelled medallions. It had been taken from the Turkish camp before Vienna, and the standard of Mohammed had stood beneath the tremulous gilt of its canopy. And so, for a whole year, he sought to accumulate the most exquisite specimens that he could find of textile and embroidered work, getting the dainty Delhi muslins, finely wrought with gold-thread palmates and stitched over with iridescent beetles' wings; the Dacca gauzes, that from their transparency are known in the East as "woven air," and "running water," and "evening dew"; strange figured cloths from Java; elaborate yellow Chinese hangings; books bound in tawny satins or fair blue silks and wrought with fleurs-de-lis, birds and images; veils of lacis worked in Hungary point; Sicilian brocades and stiff Spanish velvets; Georgian work, with its gilt coins, and Japanese Foukousas, with their green-toned golds and their marvellously plumaged birds. He had a special passion, also, for ecclesiastical vestments, as indeed he had for everything connected with the service of the Church. In the long cedar chests that lined the west gallery of his house, he had stored away many rare and beautiful specimens of what is really the raiment of the Bride of Christ, who must wear purple and jewels and fine linen that she may hide the pallid macerated body that is worn by the suffering that she seeks for and wounded by self-inflicted pain. He possessed a gorgeous cope of crimson silk and gold-thread damask, figured with a repeating pattern of golden pomegranates set in six-petalled formal blossoms, beyond which on either side was the pine-apple device wrought in seed-pearls. The orphreys were divided into panels representing scenes from the life of the Virgin, and the coronation of the Virgin was figured in coloured silks upon the hood. This was Italian work of the fifteenth century. Another cope was of green velvet, embroidered with heart-shaped groups of acanthus-leaves, from which spread long-stemmed white blossoms, the details of which were picked out with silver thread and coloured crystals. The morse bore a seraph's head in gold-thread raised work. The orphreys were woven in a diaper of red and gold silk, and were starred with medallions of many saints and martyrs, among whom was St. Sebastian. He had chasubles, also, of amber-coloured silk, and blue silk and gold brocade, and yellow silk damask and cloth of gold, figured with representations of the Passion and Crucifixion of Christ, and embroidered with lions and peacocks and other emblems; dalmatics of white satin and pink silk damask, decorated with tulips and dolphins and fleurs-de-lis; altar frontals of crimson velvet and blue linen; and many corporals, chalice-veils, and sudaria. In the mystic offices to which such things were put, there was something that quickened his imagination. For these treasures, and everything that he collected in his lovely house, were to be to him means of forgetfulness, modes by which he could escape, for a season, from the fear that seemed to him at times to be almost too great to be borne. Upon the walls of the lonely locked room where he had spent so much of his boyhood, he had hung with his own hands the terrible portrait whose changing features showed him the real degradation of his life, and in front of it had draped the purple-and-gold pall as a curtain. For weeks he would not go there, would forget the hideous painted thing, and get back his light heart, his wonderful joyousness, his passionate absorption in mere existence. Then, suddenly, some night he would creep out of the house, go down to dreadful places near Blue Gate Fields, and stay there, day after day, until he was driven away. On his return he would sit in front of the her times, with that pride of individualism that is half the fascination of sin, and smiling with secret pleasure at the misshapen shadow that had to bear the burden that should have been his own. After a few years he could not endure to be long out of England, and gave up the villa that he had shared at Trouville with Lord Henry, as well as the little white walled-in house at Algiers where they had more than once spent the winter. He hated to be separated from the picture that was such a part of his life, and was also afraid that during his absence some one might gain access to the room, in spite of the elaborate bars that he had caused to be placed upon the door. He was quite conscious that this would tell them nothing. It was true that the portrait still preserved, under all the foulness and ugliness of the face, its marked likeness to himself; but what could they learn from that? He would laugh at any one who tried to taunt him. He had not painted it. What was it to him how vile and full of shame it looked? Even if he told them, would they believe it? Yet he was afraid. Sometimes when he was down at his great house in Nottinghamshire, entertaining the fashionable young men of his own rank who were his chief companions, and astounding the county by the wanton luxury and gorgeous splendour of his mode of life, he would suddenly leave his guests and rush back to town to see that the door had not been tampered with and that the picture was still there. What if it should be stolen? The mere thought made him cold with horror. Surely the world would know his secret then. Perhaps the world already suspected it. For, while he fascinated many, there were not a few who distrusted him. He was very nearly blackballed at a West End club of which his birth and social position fully entitled him to become a member, and it was said that on one occasion, when he was brought by a friend into the smoking-room of the Churchill, the Duke of Berwick and another gentleman got up in a marked manner and went out. Curious stories became current about him after he had passed his twenty-fifth year. It was rumoured that he had been seen brawling with foreign sailors in a low den in the distant parts of Whitechapel, and that he consorted with thieves and coiners and knew the mysteries of their trade. His extraordinary absences became notorious, and, when he used to reappear again in society, men would whisper to each other in corners, or pass him with a sneer, or look at him with cold searching eyes, as though they were determined to discover his secret. Of such insolences and attempted slights he, of course, took no notice, and in the opinion of most people his frank debonair manner, his charming boyish smile, and the infinite grace of that wonderful youth that seemed never to leave him, were in themselves a sufficient answer to the calumnies, for so they termed them, that were circulated about him. It was remarked, however, that some of those who had been most intimate with him appeared, after a time, to shun him. Women who had wildly adored him, and for his sake had braved all social censure and set convention at defiance, were seen to grow pallid with shame or horror if Dorian Gray entered the room. Yet these whispered scandals only increased in the eyes of many his strange and dangerous charm. His great wealth was a certain element of security. Society--civilized society, at least-- is never very ready to believe anything to the detriment of those who are both rich and fascinating. It feels instinctively that manners are of more importance than morals, and, in its opinion, the highest respectability is of much less value than the possession of a good chef. And, after all, it is a very poor consolation to be told that the man who has given one a bad dinner, or poor wine, is irreproachable in his private life. Even the cardinal virtues cannot atone for half-cold entrees, as Lord Henry remarked once, in a discussion on the subject, and there is possibly a good deal to be said for his view. For the canons of good society are, or should be, the same as the canons of art. Form is absolutely essential to it. It should have the dignity of a ceremony, as well as its unreality, and should combine the insincere character of a romantic play with the wit and beauty that make such plays delightful to us. Is insincerity such a terrible thing? I think not. It is merely a method by which we can multiply our personalities. Such, at any rate, was Dorian Gray's opinion. He used to wonder at the shallow psychology of those who conceive the ego in man as a thing simple, permanent, reliable, and of one essence. To him, man was a being with myriad lives and myriad sensations, a complex multiform creature that bore within itself strange legacies of thought and passion, and whose very flesh was tainted with the monstrous maladies of the dead. He loved to stroll through the gaunt cold picture-gallery of his country house and look at the various portraits of those whose blood flowed in his veins. Here was Philip Herbert, described by Francis Osborne, in his Memoires on the Reigns of Queen Elizabeth and King James, as one who was "caressed by the Court for his handsome face, which kept him not long company." Was it young Herbert's life that he sometimes led? Had some strange poisonous germ crept from body to body till it had reached his own? Was it some dim sense of that ruined grace that had made him so suddenly, and almost without cause, give utterance, in Basil Hallward's studio, to the mad prayer that had so changed his life? Here, in gold-embroidered red doublet, jewelled surcoat, and gilt-edged ruff and wristbands, stood Sir Anthony Sherard, with his silver-and-black armour piled at his feet. What had this man's legacy been? Had the lover of Giovanna of Naples bequeathed him some inheritance of sin and shame? Were his own actions merely the dreams that the dead man had not dared to realize? Here, from the fading canvas, smiled Lady Elizabeth Devereux, in her gauze hood, pearl stomacher, and pink slashed sleeves. A flower was in her right hand, and her left clasped an enamelled collar of white and damask roses. On a table by her side lay a mandolin and an apple. There were large green rosettes upon her little pointed shoes. He knew her life, and the strange stories that were told about her lovers. Had he something of her temperament in him? These oval, heavy-lidded eyes seemed to look curiously at him. What of George Willoughby, with his powdered hair and fantastic patches? How evil he looked! The face was saturnine and swarthy, and the sensual lips seemed to be twisted with disdain. Delicate lace ruffles fell over the lean yellow hands that were so overladen with rings. He had been a macaroni of the eighteenth century, and the friend, in his youth, of Lord Ferrars. What of the second Lord Beckenham, the companion of the Prince Regent in his wildest days, and one of the witnesses at the secret marriage with Mrs. Fitzherbert? How proud and handsome he was, with his chestnut curls and insolent pose! What passions had he bequeathed? The world had looked upon him as infamous. He had led the orgies at Carlton House. The star of the Garter glittered upon his breast. Beside him hung the portrait of his wife, a pallid, thin-lipped woman in black. Her blood, also, stirred within him. How curious it all seemed! And his mother with her Lady Hamilton face and her moist, wine-dashed lips--he knew what he had got from her. He had got from her his beauty, and his passion for the beauty of others. She laughed at him in her loose Bacchante dress. There were vine leaves in her hair. The purple spilled from the cup she was holding. The carnations of the painting had withered, but the eyes were still wonderful in their depth and brilliancy of colour. They seemed to follow him wherever he went. Yet one had ancestors in literature as well as in one's own race, nearer perhaps in type and temperament, many of them, and certainly with an influence of which one was more absolutely conscious. There were times when it appeared to Dorian Gray that the whole of history was merely the record of his own life, not as he had lived it in act and circumstance, but as his imagination had created it for him, as it had been in his brain and in his passions. He felt that he had known them all, those strange terrible figures that had passed across the stage of the world and made sin so marvellous and evil so full of subtlety. It seemed to him that in some mysterious way their lives had been his own. The hero of the wonderful novel that had so influenced his life had himself known this curious fancy. In the seventh chapter he tells how, crowned with laurel, lest lightning might strike him, he had sat, as Tiberius, in a garden at Capri, reading the shameful books of Elephantis, while dwarfs and peacocks strutted round him and the flute-player mocked the swinger of the censer; and, as Caligula, had caroused with the green-shirted jockeys in their stables and supped in an ivory manger with a jewel-frontleted horse; and, as Domitian, had wandered through a corridor lined with marble mirrors, looking round with haggard eyes for the reflection of the dagger that was to end his days, and sick with that ennui, that terrible taedium vitae, that comes on those to whom life denies nothing; and had peered through a clear emerald at the red shambles of the circus and then, in a litter of pearl and purple drawn by silver-shod mules, been carried through the Street of Pomegranates to a House of Gold and heard men cry on Nero Caesar as he passed by; and, as Elagabalus, had painted his face with colours, and plied the distaff among the women, and brought the Moon from Carthage and given her in mystic marriage to the Sun. Over and over again Dorian used to read this fantastic chapter, and the two chapters immediately following, in which, as in some curious tapestries or cunningly wrought enamels, were pictured the awful and beautiful forms of those whom vice and blood and weariness had made monstrous or mad: Filippo, Duke of Milan, who slew his wife and painted her lips with a scarlet poison that her lover might suck death from the dead thing he fondled; Pietro Barbi, the Venetian, known as Paul the Second, who sought in his vanity to assume the title of Formosus, and whose tiara, valued at two hundred thousand florins, was bought at the price of a terrible sin; Gian Maria Visconti, who used hounds to chase living men and whose murdered body was covered with roses by a harlot who had loved him; the Borgia on his white horse, with Fratricide riding beside him and his mantle stained with the blood of Perotto; Pietro Riario, the young Cardinal Archbishop of Florence, child and minion of Sixtus IV, whose beauty was equalled only by his debauchery, and who received Leonora of Aragon in a pavilion of white and crimson silk, filled with nymphs and centaurs, and gilded a boy that he might serve at the feast as Ganymede or Hylas; Ezzelin, whose melancholy could be cured only by the spectacle of death, and who had a passion for red blood, as other men have for red wine--the son of the Fiend, as was reported, and one who had cheated his father at dice when gambling with him for his own soul; Giambattista Cibo, who in mockery took the name of Innocent and into whose torpid veins the blood of three lads was infused by a Jewish doctor; Sigismondo Malatesta, the lover of Isotta and the lord of Rimini, whose effigy was burned at Rome as the enemy of God and man, who strangled Polyssena with a napkin, and gave poison to Ginevra d'Este in a cup of emerald, and in honour of a shameful passion built a pagan church for Christian worship; Charles VI, who had so wildly adored his brother's wife that a leper had warned him of the insanity that was coming on him, and who, when his brain had sickened and grown strange, could only be soothed by Saracen cards painted with the images of love and death and madness; and, in his trimmed jerkin and jewelled cap and acanthuslike curls, Grifonetto Baglioni, who slew Astorre with his bride, and Simonetto with his page, and whose comeliness was such that, as he lay dying in the yellow piazza of Perugia, those who had hated him could not choose but weep, and Atalanta, who had cursed him, blessed him. There was a horrible fascination in them all. He saw them at night, and they troubled his imagination in the day. The Renaissance knew of strange manners of poisoning-- poisoning by a helmet and a lighted torch, by an embroidered glove and a jewelled fan, by a gilded pomander and by an amber chain. Dorian Gray had been poisoned by a book. There were moments when he looked on evil simply as a mode through which he could realize his conception of the beautiful. CHAPTER 12 It was on the ninth of November, the eve of his own thirty-eighth birthday, as he often remembered afterwards. He was walking home about eleven o'clock from Lord Henry's, where he had been dining, and was wrapped in heavy furs, as the night was cold and foggy. At the corner of Grosvenor Square and South Audley Street, a man passed him in the mist, walking very fast and with the collar of his grey ulster turned up. He had a bag in his hand. Dorian recognized him. It was Basil Hallward. A strange sense of fear, for which he could not account, came over him. He made no sign of recognition and went on quickly in the direction of his own house. But Hallward had seen him. Dorian heard him first stopping on the pavement and then hurrying after him. In a few moments, his hand was on his arm. "Dorian! What an extraordinary piece of luck! I have been waiting for you in your library ever since nine o'clock. Finally I took pity on your tired servant and told him to go to bed, as he let me out. I am off to Paris by the midnight train, and I particularly wanted to see you before I left. I thought it was you, or rather your fur coat, as you passed me. But I wasn't quite sure. Didn't you recognize me?" "In this fog, my dear Basil? Why, I can't even recognize Grosvenor Square. I believe my house is somewhere about here, but I don't feel at all certain about it. I am sorry you are going away, as I have not seen you for ages. But I suppose you will be back soon?" "No: I am going to be out of England for six months. I intend to take a studio in Paris and shut myself up till I have finished a great picture I have in my head. However, it wasn't about myself I wanted to talk. Here we are at your door. Let me come in for a moment. I have something to say to you." "I shall be charmed. But won't you miss your train?" said Dorian Gray languidly as he passed up the steps and opened the door with his latch-key. The lamplight struggled out through the fog, and Hallward looked at his watch. "I have heaps of time," he answered. "The train doesn't go till twelve-fifteen, and it is only just eleven. In fact, I was on my way to the club to look for you, when I met you. You see, I shan't have any delay about luggage, as I have sent on my heavy things. All I have with me is in this bag, and I can easily get to Victoria in twenty minutes." Dorian looked at him and smiled. "What a way for a fashionable painter to travel! A Gladstone bag and an ulster! Come in, or the fog will get into the house. And mind you don't talk about anything serious. Nothing is serious nowadays. At least nothing should be." Hallward shook his head, as he entered, and followed Dorian into the library. There was a bright wood fire blazing in the large open hearth. The lamps were lit, and an open Dutch silver spirit-case stood, with some siphons of soda-water and large cut-glass tumblers, on a little marqueterie table. "You see your servant made me quite at home, Dorian. He gave me everything I wanted, including your best gold-tipped cigarettes. He is a most hospitable creature. I like him much better than the Frenchman you used to have. What has become of the Frenchman, by the bye?" Dorian shrugged his shoulders. "I believe he married Lady Radley's maid, and has established her in Paris as an English dressmaker. Anglomania is very fashionable over there now, I hear. It seems silly of the French, doesn't it? But--do you know?--he was not at all a bad servant. I never liked him, but I had nothing to complain about. One often imagines things that are quite absurd. He was really very devoted to me and seemed quite sorry when he went away. Have another brandy-and-soda? Or would you like hock-and-seltzer? I always take hock-and-seltzer myself. There is sure to be some in the next room." "Thanks, I won't have anything more," said the painter, taking his cap and coat off and throwing them on the bag that he had placed in the corner. "And now, my dear fellow, I want to speak to you seriously. Don't frown like that. You make it so much more difficult for me." "What is it all about?" cried Dorian in his petulant way, flinging himself down on the sofa. "I hope it is not about myself. I am tired of myself to-night. I should like to be somebody else." "It is about yourself," answered Hallward in his grave deep voice, "and I must say it to you. I shall only keep you half an hour." Dorian sighed and lit a cigarette. "Half an hour!" he murmured. "It is not much to ask of you, Dorian, and it is entirely for your own sake that I am speaking. I think it right that you should know that the most dreadful things are being said against you in London." "I don't wish to know anything about them. I love scandals about other people, but scandals about myself don't interest me. They have not got the charm of novelty." "They must interest you, Dorian. Every gentleman is interested in his good name. You don't want people to talk of you as something vile and degraded. Of course, you have your position, and your wealth, and all that kind of thing. But position and wealth are not everything. Mind you, I don't believe these rumours at all. At least, I can't believe them when I see you. Sin is a thing that writes itself across a man's face. It cannot be concealed. People talk sometimes of secret vices. There are no such things. If a wretched man has a vice, it shows itself in the lines of his mouth, the droop of his eyelids, the moulding of his hands even. Somebody--I won't mention his name, but you know him--came to me last year to have his portrait done. I had never seen him before, and had never heard anything about him at the time, though I have heard a good deal since. He offered an extravagant price. I refused him. There was something in the shape of his fingers that I hated. I know now that I was quite right in what I fancied about him. His life is dreadful. But you, Dorian, with your pure, bright, innocent face, and your marvellous untroubled youth-- I can't believe anything against you. And yet I see you very seldom, and you never come down to the studio now, and when I am away from you, and I hear all these hideous things that people are whispering about you, I don't know what to say. Why is it, Dorian, that a man like the Duke of Berwick leaves the room of a club when you enter it? Why is it that so many gentlemen in London will neither go to your house or invite you to theirs? You used to be a friend of Lord Staveley. I met him at dinner last week. Your name happened to come up in conversation, in connection with the miniatures you have lent to the exhibition at the Dudley. Staveley curled his lip and said that you might have the most artistic tastes, but that you were a man whom no pure-minded girl should be allowed to know, and whom no chaste woman should sit in the same room with. I reminded him that I was a friend of yours, and asked him what he meant. He told me. He told me right out before everybody. It was horrible! Why is your friendship so fatal to young men? There was that wretched boy in the Guards who committed suicide. You were his great friend. There was Sir Henry Ashton, who had to leave England with a tarnished name. You and he were inseparable. What about Adrian Singleton and his dreadful end? What about Lord Kent's only son and his career? I met his father yesterday in St. James's Street. He seemed broken with shame and sorrow. What about the young Duke of Perth? What sort of life has he got now? What gentleman would associate with him?" "Stop, Basil. You are talking about things of which you know nothing," said Dorian Gray, biting his lip, and with a note of infinite contempt in his voice. "You ask me why Berwick leaves a room when I enter it. It is because I know everything about his life, not because he knows anything about mine. With such blood as he has in his veins, how could his record be clean? You ask me about Henry Ashton and young Perth. Did I teach the one his vices, and the other his debauchery? If Kent's silly son takes his wife from the streets, what is that to me? If Adrian Singleton writes his friend's name across a bill, am I his keeper? I know how people chatter in England. The middle classes air their moral prejudices over their gross dinner-tables, and whisper about what they call the profligacies of their betters in order to try and pretend that they are in smart society and on intimate terms with the people they slander. In this country, it is enough for a man to have distinction and brains for every common tongue to wag against him. And what sort of lives do these people, who pose as being moral, lead themselves? My dear fellow, you forget that we are in the native land of the hypocrite." "Dorian," cried Hallward, "that is not the question. England is bad enough I know, and English society is all wrong. That is the reason why I want you to be fine. You have not been fine. One has a right to judge of a man by the effect he has over his friends. Yours seem to lose all sense of honour, of goodness, of purity. You have filled them with a madness for pleasure. They have gone down into the depths. You led them there. Yes: you led them there, and yet you can smile, as you are smiling now. And there is worse behind. I know you and Harry are inseparable. Surely for that reason, if for none other, you should not have made his sister's name a by-word." "Take care, Basil. You go too far." "I must speak, and you must listen. You shall listen. When you met Lady Gwendolen, not a breath of scandal had ever touched her. Is there a single decent woman in London now who would drive with her in the park? Why, even her children are not allowed to live with her. Then there are other stories-- stories that you have been seen creeping at dawn out of dreadful houses and slinking in disguise into the foulest dens in London. Are they true? Can they be true? When I first heard them, I laughed. I hear them now, and they make me shudder. What about your country-house and the life that is led there? Dorian, you don't know what is said about you. I won't tell you that I don't want to preach to you. I remember Harry saying once that every man who turned himself into an amateur curate for the moment always began by saying that, and then proceeded to break his word. I do want to preach to you. I want you to lead such a life as will make the world respect you. I want you to have a clean name and a fair record. I want you to get rid of the dreadful people you associate with. Don't shrug your shoulders like that. Don't be so indifferent. You have a wonderful influence. Let it be for good, not for evil. They say that you corrupt every one with whom you become intimate, and that it is quite sufficient for you to enter a house for shame of some kind to follow after. I don't know whether it is so or not. How should I know? But it is said of you. I am told things that it seems impossible to doubt. Lord Gloucester was one of my greatest friends at Oxford. He showed me a letter that his wife had written to him when she was dying alone in her villa at Mentone. Your name was implicated in the most terrible confession I ever read. I told him that it was absurd--that I knew you thoroughly and that you were incapable of anything of the kind. Know you? I wonder do I know you? Before I could answer that, I should have to see your soul." "To see my soul!" muttered Dorian Gray, starting up from the sofa and turning almost white from fear. "Yes," answered Hallward gravely, and with deep-toned sorrow in his voice, "to see your soul. But only God can do that." A bitter laugh of mockery broke from the lips of the younger man. "You shall see it yourself, to-night!" he cried, seizing a lamp from the table. "Come: it is your own handiwork. Why shouldn't you look at it? You can tell the world all about it afterwards, if you choose. Nobody would believe you. If they did believe you, they would like me all the better for it. I know the age better than you do, though you will prate about it so tediously. Come, I tell you. You have chattered enough about corruption. Now you shall look on it face to face." There was the madness of pride in every word he uttered. He stamped his foot upon the ground in his boyish insolent manner. He felt a terrible joy at the thought that some one else was to share his secret, and that the man who had painted the portrait that was the origin of all his shame was to be burdened for the rest of his life with the hideous memory of what he had done. "Yes," he continued, coming closer to him and looking steadfastly into his stern eyes, "I shall show you my soul. You shall see the thing that you fancy only God can see." Hallward started back. "This is blasphemy, Dorian!" he cried. "You must not say things like that. They are horrible, and they don't mean anything." "You think so?" He laughed again. "I know so. As for what I said to you to-night, I said it for your good. You know I have been always a stanch friend to you." "Don't touch me. Finish what you have to say." A twisted flash of pain shot across the painter's face. He paused for a moment, and a wild feeling of pity came over him. After all, what right had he to pry into the life of Dorian Gray? If he had done a tithe of what was rumoured about him, how much he must have suffered! Then he straightened himself up, and walked over to the fire-place, and stood there, looking at the burning logs with their frostlike ashes and their throbbing cores of flame. "I am waiting, Basil," said the young man in a hard clear voice. He turned round. "What I have to say is this," he cried. "You must give me some answer to these horrible charges that are made against you. If you tell me that they are absolutely untrue from beginning to end, I shall believe you. Deny them, Dorian, deny them! Can't you see what I am going through? My God! don't tell me that you are bad, and corrupt, and shameful." Dorian Gray smiled. There was a curl of contempt in his lips. "Come upstairs, Basil," he said quietly. "I keep a diary of my life from day to day, and it never leaves the room in which it is written. I shall show it to you if you come with me." "I shall come with you, Dorian, if you wish it. I see I have missed my train. That makes no matter. I can go to-morrow. But don't ask me to read anything to-night. All I want is a plain answer to my question." "That shall be given to you upstairs. I could not give it here. You will not have to read long." CHAPTER 13 He passed out of the room and began the ascent, Basil Hallward following close behind. They walked softly, as men do instinctively at night. The lamp cast fantastic shadows on the wall and staircase. A rising wind made some of the windows rattle. When they reached the top landing, Dorian set the lamp down on the floor, and taking out the key, turned it in the lock. "You insist on knowing, Basil?" he asked in a low voice. "Yes." "I am delighted," he answered, smiling. Then he added, somewhat harshly, "You are the one man in the world who is entitled to know everything about me. You have had more to do with my life than you think"; and, taking up the lamp, he opened the door and went in. A cold current of air passed them, and the light shot up for a moment in a flame of murky orange. He shuddered. "Shut the door behind you," he whispered, as he placed the lamp on the table. Hallward glanced round him with a puzzled expression. The room looked as if it had not been lived in for years. A faded Flemish tapestry, a curtained picture, an old Italian cassone, and an almost empty book-case--that was all that it seemed to contain, besides a chair and a table. As Dorian Gray was lighting a half-burned candle that was standing on the mantelshelf, he saw that the whole place was covered with dust and that the carpet was in holes. A mouse ran scuffling behind the wainscoting. There was a damp odour of mildew. "So you think that it is only God who sees the soul, Basil? Draw that curtain back, and you will see mine." The voice that spoke was cold and cruel. "You are mad, Dorian, or playing a part," muttered Hallward, frowning. "You won't? Then I must do it myself," said the young man, and he tore the curtain from its rod and flung it on the ground. An exclamation of horror broke from the painter's lips as he saw in the dim light the hideous face on the canvas grinning at him. There was something in its expression that filled him with disgust and loathing. Good heavens! it was Dorian Gray's own face that he was looking at! The horror, whatever it was, had not yet entirely spoiled that marvellous beauty. There was still some gold in the thinning hair and some scarlet on the sensual mouth. The sodden eyes had kept something of the loveliness of their blue, the noble curves had not yet completely passed away from chiselled nostrils and from plastic throat. Yes, it was Dorian himself. But who had done it? He seemed to recognize his own brushwork, and the frame was his own design. The idea was monstrous, yet he felt afraid. He seized the lighted candle, and held it to the picture. In the left-hand corner was his own name, traced in long letters of bright vermilion. It was some foul parody, some infamous ignoble satire. He had never done that. Still, it was his own picture. He knew it, and he felt as if his blood had changed in a moment from fire to sluggish ice. His own picture! What did it mean? Why had it altered? He turned and looked at Dorian Gray with the eyes of a sick man. His mouth twitched, and his parched tongue seemed unable to articulate. He passed his hand across his forehead. It was dank with clammy sweat. The young man was leaning against the mantelshelf, watching him with that strange expression that one sees on the faces of those who are absorbed in a play when some great artist is acting. There was neither real sorrow in it nor real joy. There was simply the passion of the spectator, with perhaps a flicker of triumph in his eyes. He had taken the flower out of his coat, and was smelling it, or pretending to do so. "What does this mean?" cried Hallward, at last. His own voice sounded shrill and curious in his ears. "Years ago, when I was a boy," said Dorian Gray, crushing the flower in his hand, "you met me, flattered me, and taught me to be vain of my good looks. One day you introduced me to a friend of yours, who explained to me the wonder of youth, and you finished a portrait of me that revealed to me the wonder of beauty. In a mad moment that, even now, I don't know whether I regret or not, I made a wish, perhaps you would call it a prayer. . . ." "I remember it! Oh, how well I remember it! No! the thing is impossible. The room is damp. Mildew has got into the canvas. The paints I used had some wretched mineral poison in them. I tell you the thing is impossible." "Ah, what is impossible?" murmured the young man, going over to the window and leaning his forehead against the cold, mist-stained glass. "You told me you had destroyed it." "I was wrong. It has destroyed me." "I don't believe it is my picture." "Can't you see your ideal in it?" said Dorian bitterly. "My ideal, as you call it. . ." "As you called it." "There was nothing evil in it, nothing shameful. You were to me such an ideal as I shall never meet again. This is the face of a satyr." "It is the face of my soul." "Christ! what a thing I must have worshipped! It has the eyes of a devil." "Each of us has heaven and hell in him, Basil," cried Dorian with a wild gesture of despair. Hallward turned again to the portrait and gazed at it. "My God! If it is true," he exclaimed, "and this is what you have done with your life, why, you must be worse even than those who talk against you fancy you to be!" He held the light up again to the canvas and examined it. The surface seemed to be quite undisturbed and as he had left it. It was from within, apparently, that the foulness and horror had come. Through some strange quickening of inner life the leprosies of sin were slowly eating the thing away. The rotting of a corpse in a watery grave was not so fearful. His hand shook, and the candle fell from its socket on the floor and lay there sputtering. He placed his foot on it and put it out. Then he flung himself into the rickety chair that was standing by the table and buried his face in his hands. "Good God, Dorian, what a lesson! What an awful lesson!" There was no answer, but he could hear the young man sobbing at the window. "Pray, Dorian, pray," he murmured. "What is it that one was taught to say in one's boyhood? 'Lead us not into temptation. Forgive us our sins. Wash away our iniquities.' Let us say that together. The prayer of your pride has been answered. The prayer of your repentance will be answered also. I worshipped you too much. I am punished for it. You worshipped yourself too much. We are both punished." Dorian Gray turned slowly around and looked at him with tear-dimmed eyes. "It is too late, Basil," he faltered. "It is never too late, Dorian. Let us kneel down and try if we cannot remember a prayer. Isn't there a verse somewhere, 'Though your sins be as scarlet, yet I will make them as white as snow'?" "Those words mean nothing to me now." "Hush! Don't say that. You have done enough evil in your life. My God! Don't you see that accursed thing leering at us?" Dorian Gray glanced at the picture, and suddenly an uncontrollable feeling of hatred for Basil Hallward came over him, as though it had been suggested to him by the image on the canvas, whispered into his ear by those grinning lips. The mad passions of a hunted animal stirred within him, and he loathed the man who was seated at the table, more than in his whole life he had ever loathed anything. He glanced wildly around. Something glimmered on the top of the painted chest that faced him. His eye fell on it. He knew what it was. It was a knife that he had brought up, some days before, to cut a piece of cord, and had forgotten to take away with him. He moved slowly towards it, passing Hallward as he did so. As soon as he got behind him, he seized it and turned round. Hallward stirred in his chair as if he was going to rise. He rushed at him and dug the knife into the great vein that is behind the ear, crushing the man's head down on the table and stabbing again and again. There was a stifled groan and the horrible sound of some one choking with blood. Three times the outstretched arms shot up convulsively, waving grotesque, stiff-fingered hands in the air. He stabbed him twice more, but the man did not move. Something began to trickle on the floor. He waited for a moment, still pressing the head down. Then he threw the knife on the table, and listened. He could hear nothing, but the drip, drip on the threadbare carpet. He opened the door and went out on the landing. The house was absolutely quiet. No one was about. For a few seconds he stood bending over the balustrade and peering down into the black seething well of darkness. Then he took out the key and returned to the room, locking himself in as he did so. The thing was still seated in the chair, straining over the table with bowed head, and humped back, and long fantastic arms. Had it not been for the red jagged tear in the neck and the clotted black pool that was slowly widening on the table, one would have said that the man was simply asleep. How quickly it had all been done! He felt strangely calm, and walking over to the window, opened it and stepped out on the balcony. The wind had blown the fog away, and the sky was like a monstrous peacock's tail, starred with myriads of golden eyes. He looked down and saw the policeman going his rounds and flashing the long beam of his lantern on the doors of the silent houses. The crimson spot of a prowling hansom gleamed at the corner and then vanished. A woman in a fluttering shawl was creeping slowly by the railings, staggering as she went. Now and then she stopped and peered back. Once, she began to sing in a hoarse voice. The policeman strolled over and said something to her. She stumbled away, laughing. A bitter blast swept across the square. The gas-lamps flickered and became blue, and the leafless trees shook their black iron branches to and fro. He shivered and went back, closing the window behind him. Having reached the door, he turned the key and opened it. He did not even glance at the murdered man. He felt that the secret of the whole thing was not to realize the situation. The friend who had painted the fatal portrait to which all his misery had been due had gone out of his life. That was enough. Then he remembered the lamp. It was a rather curious one of Moorish workmanship, made of dull silver inlaid with arabesques of burnished steel, and studded with coarse turquoises. Perhaps it might be missed by his servant, and questions would be asked. He hesitated for a moment, then he turned back and took it from the table. He could not help seeing the dead thing. How still it was! How horribly white the long hands looked! It was like a dreadful wax image. Having locked the door behind him, he crept quietly downstairs. The woodwork creaked and seemed to cry out as if in pain. He stopped several times and waited. No: everything was still. It was merely the sound of his own footsteps. When he reached the library, he saw the bag and coat in the corner. They must be hidden away somewhere. He unlocked a secret press that was in the wainscoting, a press in which he kept his own curious disguises, and put them into it. He could easily burn them afterwards. Then he pulled out his watch. It was twenty minutes to two. He sat down and began to think. Every year--every month, almost-- men were strangled in England for what he had done. There had been a madness of murder in the air. Some red star had come too close to the earth. . . . And yet, what evidence was there against him? Basil Hallward had left the house at eleven. No one had seen him come in again. Most of the servants were at Selby Royal. His valet had gone to bed.... Paris! Yes. It was to Paris that Basil had gone, and by the midnight train, as he had intended. With his curious reserved habits, it would be months before any suspicions would be roused. Months! Everything could be destroyed long before then. A sudden thought struck him. He put on his fur coat and hat and went out into the hall. There he paused, hearing the slow heavy tread of the policeman on the pavement outside and seeing the flash of the bull's-eye reflected in the window. He waited and held his breath. After a few moments he drew back the latch and slipped out, shutting the door very gently behind him. Then he began ringing the bell. In about five minutes his valet appeared, half-dressed and looking very drowsy. "I am sorry to have had to wake you up, Francis," he said, stepping in; "but I had forgotten my latch-key. What time is it?" "Ten minutes past two, sir," answered the man, looking at the clock and blinking. "Ten minutes past two? How horribly late! You must wake me at nine to-morrow. I have some work to do." "All right, sir." "Did any one call this evening?" "Mr. Hallward, sir. He stayed here till eleven, and then he went away to catch his train." "Oh! I am sorry I didn't see him. Did he leave any message?" "No, sir, except that he would write to you from Paris, if he did not find you at the club." "That will do, Francis. Don't forget to call me at nine to-morrow." "No, sir." The man shambled down the passage in his slippers. Dorian Gray threw his hat and coat upon the table and passed into the library. For a quarter of an hour he walked up and down the room, biting his lip and thinking. Then he took down the Blue Book from one of the shelves and began to turn over the leaves. "Alan Campbell, 152, Hertford Street, Mayfair." Yes; that was the man he wanted. CHAPTER 14 At nine o'clock the next morning his servant came in with a cup of chocolate on a tray and opened the shutters. Dorian was sleeping quite peacefully, lying on his right side, with one hand underneath his cheek. He looked like a boy who had been tired out with play, or study. The man had to touch him twice on the shoulder before he woke, and as he opened his eyes a faint smile passed across his lips, as though he had been lost in some delightful dream. Yet he had not dreamed at all. His night had been untroubled by any images of pleasure or of pain. But youth smiles without any reason. It is one of its chiefest charms. He turned round, and leaning upon his elbow, began to sip his chocolate. The mellow November sun came streaming into the room. The sky was bright, and there was a genial warmth in the air. It was almost like a morning in May. Gradually the events of the preceding night crept with silent, blood-stained feet into his brain and reconstructed themselves there with terrible distinctness. He winced at the memory of all that he had suffered, and for a moment the same curious feeling of loathing for Basil Hallward that had made him kill him as he sat in the chair came back to him, and he grew cold with passion. The dead man was still sitting there, too, and in the sunlight now. How horrible that was! Such hideous things were for the darkness, not for the day. He felt that if he brooded on what he had gone through he would sicken or grow mad. There were sins whose fascination was more in the memory than in the doing of them, strange triumphs that gratified the pride more than the passions, and gave to the intellect a quickened sense of joy, greater than any joy they brought, or could ever bring, to the senses. But this was not one of them. It was a thing to be driven out of the mind, to be drugged with poppies, to be strangled lest it might strangle one itself. When the half-hour struck, he passed his hand across his forehead, and then got up hastily and dressed himself with even more than his usual care, giving a good deal of attention to the choice of his necktie and scarf-pin and changing his rings more than once. He spent a long time also over breakfast, tasting the various dishes, talking to his valet about some new liveries that he was thinking of getting made for the servants at Selby, and going through his correspondence. At some of the letters, he smiled. Three of them bored him. One he read several times over and then tore up with a slight look of annoyance in his face. "That awful thing, a woman's memory!" as Lord Henry had once said. After he had drunk his cup of black coffee, he wiped his lips slowly with a napkin, motioned to his servant to wait, and going over to the table, sat down and wrote two letters. One he put in his pocket, the other he handed to the valet. "Take this round to 152, Hertford Street, Francis, and if Mr. Campbell is out of town, get his address." As soon as he was alone, he lit a cigarette and began sketching upon a piece of paper, drawing first flowers and bits of architecture, and then human faces. Suddenly he remarked that every face that he drew seemed to have a fantastic likeness to Basil Hallward. He frowned, and getting up, went over to the book-case and took out a volume at hazard. He was determined that he would not think about what had happened until it became absolutely necessary that he should do so. When he had stretched himself on the sofa, he looked at the title-page of the book. It was Gautier's Emaux et Camees, Charpentier's Japanese-paper edition, with the Jacquemart etching. The binding was of citron-green leather, with a design of gilt trellis-work and dotted pomegranates. It had been given to him by Adrian Singleton. As he turned over the pages, his eye fell on the poem about the hand of Lacenaire, the cold yellow hand "du supplice encore mal lavee," with its downy red hairs and its "doigts de faune." He glanced at his own white taper fingers, shuddering slightly in spite of himself, and passed on, till he came to those lovely stanzas upon Venice: Sur une gamme chromatique, Le sein de peries ruisselant, La Venus de l'Adriatique Sort de l'eau son corps rose et blanc. Les domes, sur l'azur des ondes Suivant la phrase au pur contour, S'enflent comme des gorges rondes Que souleve un soupir d'amour. L'esquif aborde et me depose, Jetant son amarre au pilier, Devant une facade rose, Sur le marbre d'un escalier. How exquisite they were! As one read them, one seemed to be floating down the green water-ways of the pink and pearl city, seated in a black gondola with silver prow and trailing curtains. The mere lines looked to him like those straight lines of turquoise-blue that follow one as one pushes out to the Lido. The sudden flashes of colour reminded him of the gleam of the opal-and-iris-throated birds that flutter round the tall honeycombed Campanile, or stalk, with such stately grace, through the dim, dust-stained arcades. Leaning back with half-closed eyes, he kept saying over and over to himself: "Devant une facade rose, Sur le marbre d'un escalier." The whole of Venice was in those two lines. He remembered the autumn that he had passed there, and a wonderful love that had stirred him to mad delightful follies. There was romance in every place. But Venice, like Oxford, had kept the background for romance, and, to the true romantic, background was everything, or almost everything. Basil had been with him part of the time, and had gone wild over Tintoret. Poor Basil! What a horrible way for a man to die! He sighed, and took up the volume again, and tried to forget. He read of the swallows that fly in and out of the little cafe at Smyrna where the Hadjis sit counting their amber beads and the turbaned merchants smoke their long tasselled pipes and talk gravely to each other; he read of the Obelisk in the Place de la Concorde that weeps tears of granite in its lonely sunless exile and longs to be back by the hot, lotus-covered Nile, where there are Sphinxes, and rose-red ibises, and white vultures with gilded claws, and crocodiles with small beryl eyes that crawl over the green steaming mud; he began to brood over those verses which, drawing music from kiss-stained marble, tell of that curious statue that Gautier compares to a contralto voice, the "monstre charmant" that couches in the porphyry-room of the Louvre. But after a time the book fell from his hand. He grew nervous, and a horrible fit of terror came over him. What if Alan Campbell should be out of England? Days would elapse before he could come back. Perhaps he might refuse to come. What could he do then? Every moment was of vital importance. They had been great friends once, five years before-- almost inseparable, indeed. Then the intimacy had come suddenly to an end. When they met in society now, it was only Dorian Gray who smiled: Alan Campbell never did. He was an extremely clever young man, though he had no real appreciation of the visible arts, and whatever little sense of the beauty of poetry he possessed he had gained entirely from Dorian. His dominant intellectual passion was for science. At Cambridge he had spent a great deal of his time working in the laboratory, and had taken a good class in the Natural Science Tripos of his year. Indeed, he was still devoted to the study of chemistry, and had a laboratory of his own in which he used to shut himself up all day long, greatly to the annoyance of his mother, who had set her heart on his standing for Parliament and had a vague idea that a chemist was a person who made up prescriptions. He was an excellent musician, however, as well, and played both the violin and the piano better than most amateurs. In fact, it was music that had first brought him and Dorian Gray together--music and that indefinable attraction that Dorian seemed to be able to exercise whenever he wished-- and, indeed, exercised often without being conscious of it. They had met at Lady Berkshire's the night that Rubinstein played there, and after that used to be always seen together at the opera and wherever good music was going on. For eighteen months their intimacy lasted. Campbell was always either at Selby Royal or in Grosvenor Square. To him, as to many others, Dorian Gray was the type of everything that is wonderful and fascinating in life. Whether or not a quarrel had taken place between them no one ever knew. But suddenly people remarked that they scarcely spoke when they met and that Campbell seemed always to go away early from any party at which Dorian Gray was present. He had changed, too--was strangely melancholy at times, appeared almost to dislike hearing music, and would never himself play, giving as his excuse, when he was called upon, that he was so absorbed in science that he had no time left in which to practise. And this was certainly true. Every day he seemed to become more interested in biology, and his name appeared once or twice in some of the scientific reviews in connection with certain curious experiments. This was the man Dorian Gray was waiting for. Every second he kept glancing at the clock. As the minutes went by he became horribly agitated. At last he got up and began to pace up and down the room, looking like a beautiful caged thing. He took long stealthy strides. His hands were curiously cold. The suspense became unbearable. Time seemed to him to be crawling with feet of lead, while he by monstrous winds was being swept towards the jagged edge of some black cleft of precipice. He knew what was waiting for him there; saw it, indeed, and, shuddering, crushed with dank hands his burning lids as though he would have robbed the very brain of sight and driven the eyeballs back into their cave. It was useless. The brain had its own food on which it battened, and the imagination, made grotesque by terror, twisted and distorted as a living thing by pain, danced like some foul puppet on a stand and grinned through moving masks. Then, suddenly, time stopped for him. Yes: that blind, slow-breathing thing crawled no more, and horrible thoughts, time being dead, raced nimbly on in front, and dragged a hideous future from its grave, and showed it to him. He stared at it. Its very horror made him stone. At last the door opened and his servant entered. He turned glazed eyes upon him. "Mr. Campbell, sir," said the man. A sigh of relief broke from his parched lips, and the colour came back to his cheeks. "Ask him to come in at once, Francis." He felt that he was himself again. His mood of cowardice had passed away. The man bowed and retired. In a few moments, Alan Campbell walked in, looking very stern and rather pale, his pallor being intensified by his coal-black hair and dark eyebrows. "Alan! This is kind of you. I thank you for coming." "I had intended never to enter your house again, Gray. But you said it was a matter of life and death." His voice was hard and cold. He spoke with slow deliberation. There was a look of contempt in the steady searching gaze that he turned on Dorian. He kept his hands in the pockets of his Astrakhan coat, and seemed not to have noticed the gesture with which he had been greeted. "Yes: it is a matter of life and death, Alan, and to more than one person. Sit down." Campbell took a chair by the table, and Dorian sat opposite to him. The two men's eyes met. In Dorian's there was infinite pity. He knew that what he was going to do was dreadful. After a strained moment of silence, he leaned across and said, very quietly, but watching the effect of each word upon the face of him he had sent for, "Alan, in a locked room at the top of this house, a room to which nobody but myself has access, a dead man is seated at a table. He has been dead ten hours now. Don't stir, and don't look at me like that. Who the man is, why he died, how he died, are matters that do not concern you. What you have to do is this--" "Stop, Gray. I don't want to know anything further. Whether what you have told me is true or not true doesn't concern me. I entirely decline to be mixed up in your life. Keep your horrible secrets to yourself. They don't interest me any more." "Alan, they will have to interest you. This one will have to interest you. I am awfully sorry for you, Alan. But I can't help myself. You are the one man who is able to save me. I am forced to bring you into the matter. I have no option. Alan, you are scientific. You know about chemistry and things of that kind. You have made experiments. What you have got to do is to destroy the thing that is upstairs-- to destroy it so that not a vestige of it will be left. Nobody saw this person come into the house. Indeed, at the present moment he is supposed to be in Paris. He will not be missed for months. When he is missed, there must be no trace of him found here. You, Alan, you must change him, and everything that belongs to him, into a handful of ashes that I may scatter in the air." "You are mad, Dorian." "Ah! I was waiting for you to call me Dorian." "You are mad, I tell you--mad to imagine that I would raise a finger to help you, mad to make this monstrous confession. I will have nothing to do with this matter, whatever it is. Do you think I am going to peril my reputation for you? What is it to me what devil's work you are up to?" "It was suicide, Alan." "I am glad of that. But who drove him to it? You, I should fancy." "Do you still refuse to do this for me?" "Of course I refuse. I will have absolutely nothing to do with it. I don't care what shame comes on you. You deserve it all. I should not be sorry to see you disgraced, publicly disgraced. How dare you ask me, of all men in the world, to mix myself up in this horror? I should have thought you knew more about people's characters. Your friend Lord Henry Wotton can't have taught you much about psychology, whatever else he has taught you. Nothing will induce me to stir a step to help you. You have come to the wrong man. Go to some of your friends. Don't come to me." "Alan, it was murder. I killed him. You don't know what he had made me suffer. Whatever my life is, he had more to do with the making or the marring of it than poor Harry has had. He may not have intended it, the result was the same." "Murder! Good God, Dorian, is that what you have come to? I shall not inform upon you. It is not my business. Besides, without my stirring in the matter, you are certain to be arrested. Nobody ever commits a crime without doing something stupid. But I will have nothing to do with it." "You must have something to do with it. Wait, wait a moment; listen to me. Only listen, Alan. All I ask of you is to perform a certain scientific experiment. You go to hospitals and dead-houses, and the horrors that you do there don't affect you. If in some hideous dissecting-room or fetid laboratory you found this man lying on a leaden table with red gutters scooped out in it for the blood to flow through, you would simply look upon him as an admirable subject. You would not turn a hair. You would not believe that you were doing anything wrong. On the contrary, you would probably feel that you were benefiting the human race, or increasing the sum of knowledge in the world, or gratifying intellectual curiosity, or something of that kind. What I want you to do is merely what you have often done before. Indeed, to destroy a body must be far less horrible than what you are accustomed to work at. And, remember, it is the only piece of evidence against me. If it is discovered, I am lost; and it is sure to be discovered unless you help me." "I have no desire to help you. You forget that. I am simply indifferent to the whole thing. It has nothing to do with me." "Alan, I entreat you. Think of the position I am in. Just before you came I almost fainted with terror. You may know terror yourself some day. No! don't think of that. Look at the matter purely from the scientific point of view. You don't inquire where the dead things on which you experiment come from. Don't inquire now. I have told you too much as it is. But I beg of you to do this. We were friends once, Alan." "Don't speak about those days, Dorian--they are dead." "The dead linger sometimes. The man upstairs will not go away. He is sitting at the table with bowed head and outstretched arms. Alan! Alan! If you don't come to my assistance, I am ruined. Why, they will hang me, Alan! Don't you understand? They will hang me for what I have done." "There is no good in prolonging this scene. I absolutely refuse to do anything in the matter. It is insane of you to ask me." "You refuse?" "Yes." "I entreat you, Alan." "It is useless." The same look of pity came into Dorian Gray's eyes. Then he stretched out his hand, took a piece of paper, and wrote something on it. He read it over twice, folded it carefully, and pushed it across the table. Having done this, he got up and went over to the window. Campbell looked at him in surprise, and then took up the paper, and opened it. As he read it, his face became ghastly pale and he fell back in his chair. A horrible sense of sickness came over him. He felt as if his heart was beating itself to death in some empty hollow. After two or three minutes of terrible silence, Dorian turned round and came and stood behind him, putting his hand upon his shoulder. "I am so sorry for you, Alan," he murmured, "but you leave me no alternative. I have a letter written already. Here it is. You see the address. If you don't help me, I must send it. If you don't help me, I will send it. You know what the result will be. But you are going to help me. It is impossible for you to refuse now. I tried to spare you. You will do me the justice to admit that. You were stern, harsh, offensive. You treated me as no man has ever dared to treat me--no living man, at any rate. I bore it all. Now it is for me to dictate terms." Campbell buried his face in his hands, and a shudder passed through him. "Yes, it is my turn to dictate terms, Alan. You know what they are. The thing is quite simple. Come, don't work yourself into this fever. The thing has to be done. Face it, and do it." A groan broke from Campbell's lips and he shivered all over. The ticking of the clock on the mantelpiece seemed to him to be dividing time into separate atoms of agony, each of which was too terrible to be borne. He felt as if an iron ring was being slowly tightened round his forehead, as if the disgrace with which he was threatened had already come upon him. The hand upon his shoulder weighed like a hand of lead. It was intolerable. It seemed to crush him. "Come, Alan, you must decide at once." "I cannot do it," he said, mechanically, as though words could alter things. "You must. You have no choice. Don't delay." He hesitated a moment. "Is there a fire in the room upstairs?" "Yes, there is a gas-fire with asbestos." "I shall have to go home and get some things from the laboratory." "No, Alan, you must not leave the house. Write out on a sheet of notepaper what you want and my servant will take a cab and bring the things back to you." Campbell scrawled a few lines, blotted them, and addressed an envelope to his assistant. Dorian took the note up and read it carefully. Then he rang the bell and gave it to his valet, with orders to return as soon as possible and to bring the things with him. As the hall door shut, Campbell started nervously, and having got up from the chair, went over to the chimney-piece. He was shivering with a kind of ague. For nearly twenty minutes, neither of the men spoke. A fly buzzed noisily about the room, and the ticking of the clock was like the beat of a hammer. As the chime struck one, Campbell turned round, and looking at Dorian Gray, saw that his eyes were filled with tears. There was something in the purity and refinement of that sad face that seemed to enrage him. "You are infamous, absolutely infamous!" he muttered. "Hush, Alan. You have saved my life," said Dorian. "Your life? Good heavens! what a life that is! You have gone from corruption to corruption, and now you have culminated in crime. In doing what I am going to do--what you force me to do-- it is not of your life that I am thinking." "Ah, Alan," murmured Dorian with a sigh, "I wish you had a thousandth part of the pity for me that I have for you." He turned away as he spoke and stood looking out at the garden. Campbell made no answer. After about ten minutes a knock came to the door, and the servant entered, carrying a large mahogany chest of chemicals, with a long coil of steel and platinum wire and two rather curiously shaped iron clamps. "Shall I leave the things here, sir?" he asked Campbell. "Yes," said Dorian. "And I am afraid, Francis, that I have another errand for you. What is the name of the man at Richmond who supplies Selby with orchids?" "Harden, sir." "Yes--Harden. You must go down to Richmond at once, see Harden personally, and tell him to send twice as many orchids as I ordered, and to have as few white ones as possible. In fact, I don't want any white ones. It is a lovely day, Francis, and Richmond is a very pretty place-- otherwise I wouldn't bother you about it." "No trouble, sir. At what time shall I be back?" Dorian looked at Campbell. "How long will your experiment take, Alan?" he said in a calm indifferent voice. The presence of a third person in the room seemed to give him extraordinary courage. Campbell frowned and bit his lip. "It will take about five hours," he answered. "It will be time enough, then, if you are back at half-past seven, Francis. Or stay: just leave my things out for dressing. You can have the evening to yourself. I am not dining at home, so I shall not want you." "Thank you, sir," said the man, leaving the room. "Now, Alan, there is not a moment to be lost. How heavy this chest is! I'll take it for you. You bring the other things." He spoke rapidly and in an authoritative manner. Campbell felt dominated by him. They left the room together. When they reached the top landing, Dorian took out the key and turned it in the lock. Then he stopped, and a troubled look came into his eyes. He shuddered. "I don't think I can go in, Alan," he murmured. "It is nothing to me. I don't require you," said Campbell coldly. Dorian half opened the door. As he did so, he saw the face of his portrait leering in the sunlight. On the floor in front of it the torn curtain was lying. He remembered that the night before he had forgotten, for the first time in his life, to hide the fatal canvas, and was about to rush forward, when he drew back with a shudder. What was that loathsome red dew that gleamed, wet and glistening, on one of the hands, as though the canvas had sweated blood? How horrible it was!--more horrible, it seemed to him for the moment, than the silent thing that he knew was stretched across the table, the thing whose grotesque misshapen shadow on the spotted carpet showed him that it had not stirred, but was still there, as he had left it. He heaved a deep breath, opened the door a little wider, and with half-closed eyes and averted head, walked quickly in, determined that he would not look even once upon the dead man. Then, stooping down and taking up the gold-and-purple hanging, he flung it right over the picture. There he stopped, feeling afraid to turn round, and his eyes fixed themselves on the intricacies of the pattern before him. He heard Campbell bringing in the heavy chest, and the irons, and the other things that he had required for his dreadful work. He began to wonder if he and Basil Hallward had ever met, and, if so, what they had thought of each other. "Leave me now," said a stern voice behind him. He turned and hurried out, just conscious that the dead man had been thrust back into the chair and that Campbell was gazing into a glistening yellow face. As he was going downstairs, he heard the key being turned in the lock. It was long after seven when Campbell came back into the library. He was pale, but absolutely calm. "I have done what you asked me to do," he muttered "And now, good-bye. Let us never see each other again." "You have saved me from ruin, Alan. I cannot forget that," said Dorian simply. As soon as Campbell had left, he went upstairs. There was a horrible smell of nitric acid in the room. But the thing that had been sitting at the table was gone. CHAPTER 15 That evening, at eight-thirty, exquisitely dressed and wearing a large button-hole of Parma violets, Dorian Gray was ushered into Lady Narborough's drawing-room by bowing servants. His forehead was throbbing with maddened nerves, and he felt wildly excited, but his manner as he bent over his hostess's hand was as easy and graceful as ever. Perhaps one never seems so much at one's ease as when one has to play a part. Certainly no one looking at Dorian Gray that night could have believed that he had passed through a tragedy as horrible as any tragedy of our age. Those finely shaped fingers could never have clutched a knife for sin, nor those smiling lips have cried out on God and goodness. He himself could not help wondering at the calm of his demeanour, and for a moment felt keenly the terrible pleasure of a double life. It was a small party, got up rather in a hurry by Lady Narborough, who was a very clever woman with what Lord Henry used to describe as the remains of really remarkable ugliness. She had proved an excellent wife to one of our most tedious ambassadors, and having buried her husband properly in a marble mausoleum, which she had herself designed, and married off her daughters to some rich, rather elderly men, she devoted herself now to the pleasures of French fiction, French cookery, and French esprit when she could get it. Dorian was one of her especial favourites, and she always told him that she was extremely glad she had not met him in early life. "I know, my dear, I should have fallen madly in love with you," she used to say, "and thrown my bonnet right over the mills for your sake. It is most fortunate that you were not thought of at the time. As it was, our bonnets were so unbecoming, and the mills were so occupied in trying to raise the wind, that I never had even a flirtation with anybody. However, that was all Narborough's fault. He was dreadfully short-sighted, and there is no pleasure in taking in a husband who never sees anything." Her guests this evening were rather tedious. The fact was, as she explained to Dorian, behind a very shabby fan, one of her married daughters had come up quite suddenly to stay with her, and, to make matters worse, had actually brought her husband with her. "I think it is most unkind of her, my dear," she whispered. "Of course I go and stay with them every summer after I come from Homburg, but then an old woman like me must have fresh air sometimes, and besides, I really wake them up. You don't know what an existence they lead down there. It is pure unadulterated country life. They get up early, because they have so much to do, and go to bed early, because they have so little to think about. There has not been a scandal in the neighbourhood since the time of Queen Elizabeth, and consequently they all fall asleep after dinner. You shan't sit next either of them. You shall sit by me and amuse me." Dorian murmured a graceful compliment and looked round the room. Yes: it was certainly a tedious party. Two of the people he had never seen before, and the others consisted of Ernest Harrowden, one of those middle-aged mediocrities so common in London clubs who have no enemies, but are thoroughly disliked by their friends; Lady Ruxton, an overdressed woman of forty-seven, with a hooked nose, who was always trying to get herself compromised, but was so peculiarly plain that to her great disappointment no one would ever believe anything against her; Mrs. Erlynne, a pushing nobody, with a delightful lisp and Venetian-red hair; Lady Alice Chapman, his hostess's daughter, a dowdy dull girl, with one of those characteristic British faces that, once seen, are never remembered; and her husband, a red-cheeked, white-whiskered creature who, like so many of his class, was under the impression that inordinate joviality can atone for an entire lack of ideas. He was rather sorry he had come, till Lady Narborough, looking at the great ormolu gilt clock that sprawled in gaudy curves on the mauve-draped mantelshelf, exclaimed: "How horrid of Henry Wotton to be so late! I sent round to him this morning on chance and he promised faithfully not to disappoint me." It was some consolation that Harry was to be there, and when the door opened and he heard his slow musical voice lending charm to some insincere apology, he ceased to feel bored. But at dinner he could not eat anything. Plate after plate went away untasted. Lady Narborough kept scolding him for what she called "an insult to poor Adolphe, who invented the menu specially for you," and now and then Lord Henry looked across at him, wondering at his silence and abstracted manner. From time to time the butler filled his glass with champagne. He drank eagerly, and his thirst seemed to increase. "Dorian," said Lord Henry at last, as the chaud-froid was being handed round, "what is the matter with you to-night? You are quite out of sorts." "I believe he is in love," cried Lady Narborough, "and that he is afraid to tell me for fear I should be jealous. He is quite right. I certainly should." "Dear Lady Narborough," murmured Dorian, smiling, "I have not been in love for a whole week--not, in fact, since Madame de Ferrol left town." "How you men can fall in love with that woman!" exclaimed the old lady. "I really cannot understand it." "It is simply because she remembers you when you were a little girl, Lady Narborough," said Lord Henry. "She is the one link between us and your short frocks." "She does not remember my short frocks at all, Lord Henry. But I remember her very well at Vienna thirty years ago, and how decolletee she was then." "She is still decolletee," he answered, taking an olive in his long fingers; "and when she is in a very smart gown she looks like an edition de luxe of a bad French novel. She is really wonderful, and full of surprises. Her capacity for family affection is extraordinary. When her third husband died, her hair turned quite gold from grief." "How can you, Harry!" cried Dorian. "It is a most romantic explanation," laughed the hostess. "But her third husband, Lord Henry! You don't mean to say Ferrol is the fourth?" "Certainly, Lady Narborough." "I don't believe a word of it." "Well, ask Mr. Gray. He is one of her most intimate friends." "Is it true, Mr. Gray?" "She assures me so, Lady Narborough," said Dorian. "I asked her whether, like Marguerite de Navarre, she had their hearts embalmed and hung at her girdle. She told me she didn't, because none of them had had any hearts at all." "Four husbands! Upon my word that is trop de zele." "Trop d'audace, I tell her," said Dorian. "Oh! she is audacious enough for anything, my dear. And what is Ferrol like? I don't know him." "The husbands of very beautiful women belong to the criminal classes," said Lord Henry, sipping his wine. Lady Narborough hit him with her fan. "Lord Henry, I am not at all surprised that the world says that you are extremely wicked." "But what world says that?" asked Lord Henry, elevating his eyebrows. "It can only be the next world. This world and I are on excellent terms." "Everybody I know says you are very wicked," cried the old lady, shaking her head. Lord Henry looked serious for some moments. "It is perfectly monstrous," he said, at last, "the way people go about nowadays saying things against one behind one's back that are absolutely and entirely true." "Isn't he incorrigible?" cried Dorian, leaning forward in his chair. "I hope so," said his hostess, laughing. "But really, if you all worship Madame de Ferrol in this ridiculous way, I shall have to marry again so as to be in the fashion." "You will never marry again, Lady Narborough," broke in Lord Henry. "You were far too happy. When a woman marries again, it is because she detested her first husband. When a man marries again, it is because he adored his first wife. Women try their luck; men risk theirs." "Narborough wasn't perfect," cried the old lady. "If he had been, you would not have loved him, my dear lady," was the rejoinder. "Women love us for our defects. If we have enough of them, they will forgive us everything, even our intellects. You will never ask me to dinner again after saying this, I am afraid, Lady Narborough, but it is quite true." "Of course it is true, Lord Henry. If we women did not love you for your defects, where would you all be? Not one of you would ever be married. You would be a set of unfortunate bachelors. Not, however, that that would alter you much. Nowadays all the married men live like bachelors, and all the bachelors like married men." "Fin de siecle," murmured Lord Henry. "Fin du globe," answered his hostess. "I wish it were fin du globe," said Dorian with a sigh. "Life is a great disappointment." "Ah, my dear," cried Lady Narborough, putting on her gloves, "don't tell me that you have exhausted life. When a man says that one knows that life has exhausted him. Lord Henry is very wicked, and I sometimes wish that I had been; but you are made to be good-- you look so good. I must find you a nice wife. Lord Henry, don't you think that Mr. Gray should get married?" "I am always telling him so, Lady Narborough," said Lord Henry with a bow. "Well, we must look out for a suitable match for him. I shall go through Debrett carefully to-night and draw out a list of all the eligible young ladies." "With their ages, Lady Narborough?" asked Dorian. "Of course, with their ages, slightly edited. But nothing must be done in a hurry. I want it to be what The Morning Post calls a suitable alliance, and I want you both to be happy." "What nonsense people talk about happy marriages!" exclaimed Lord Henry. "A man can be happy with any woman, as long as he does not love her." "Ah! what a cynic you are!" cried the old lady, pushing back her chair and nodding to Lady Ruxton. "You must come and dine with me soon again. You are really an admirable tonic, much better than what Sir Andrew prescribes for me. You must tell me what people you would like to meet, though. I want it to be a delightful gathering." "I like men who have a future and women who have a past," he answered. "Or do you think that would make it a petticoat party?" "I fear so," she said, laughing, as she stood up. "A thousand pardons, my dear Lady Ruxton," she added, "I didn't see you hadn't finished your cigarette." "Never mind, Lady Narborough. I smoke a great deal too much. I am going to limit myself, for the future." "Pray don't, Lady Ruxton," said Lord Henry. "Moderation is a fatal thing. Enough is as bad as a meal. More than enough is as good as a feast." Lady Ruxton glanced at him curiously. "You must come and explain that to me some afternoon, Lord Henry. It sounds a fascinating theory," she murmured, as she swept out of the room. "Now, mind you don't stay too long over your politics and scandal," cried Lady Narborough from the door. "If you do, we are sure to squabble upstairs." The men laughed, and Mr. Chapman got up solemnly from the foot of the table and came up to the top. Dorian Gray changed his seat and went and sat by Lord Henry. Mr. Chapman began to talk in a loud voice about the situation in the House of Commons. He guffawed at his adversaries. The word doctrinaire--word full of terror to the British mind-- reappeared from time to time between his explosions. An alliterative prefix served as an ornament of oratory. He hoisted the Union Jack on the pinnacles of thought. The inherited stupidity of the race--sound English common sense he jovially termed it--was shown to be the proper bulwark for society. A smile curved Lord Henry's lips, and he turned round and looked at Dorian. "Are you better, my dear fellow?" he asked. "You seemed rather out of sorts at dinner." "I am quite well, Harry. I am tired. That is all." "You were charming last night. The little duchess is quite devoted to you. She tells me she is going down to Selby." "She has promised to come on the twentieth." "Is Monmouth to be there, too?" "Oh, yes, Harry." "He bores me dreadfully, almost as much as he bores her. She is very clever, too clever for a woman. She lacks the indefinable charm of weakness. It is the feet of clay that make the gold of the image precious. Her feet are very pretty, but they are not feet of clay. White porcelain feet, if you like. They have been through the fire, and what fire does not destroy, it hardens. She has had experiences." "How long has she been married?" asked Dorian. "An eternity, she tells me. I believe, according to the peerage, it is ten years, but ten years with Monmouth must have been like eternity, with time thrown in. Who else is coming?" "Oh, the Willoughbys, Lord Rugby and his wife, our hostess, Geoffrey Clouston, the usual set. I have asked Lord Grotrian." "I like him," said Lord Henry. "A great many people don't, but I find him charming. He atones for being occasionally somewhat overdressed by being always absolutely over-educated. He is a very modern type." "I don't know if he will be able to come, Harry. He may have to go to Monte Carlo with his father." "Ah! what a nuisance people's people are! Try and make him come. By the way, Dorian, you ran off very early last night. You left before eleven. What did you do afterwards? Did you go straight home?" Dorian glanced at him hurriedly and frowned. "No, Harry," he said at last, "I did not get home till nearly three." "Did you go to the club?" "Yes," he answered. Then he bit his lip. "No, I don't mean that. I didn't go to the club. I walked about. I forget what I did. . . . How inquisitive you are, Harry! You always want to know what one has been doing. I always want to forget what I have been doing. I came in at half-past two, if you wish to know the exact time. I had left my latch-key at home, and my servant had to let me in. If you want any corroborative evidence on the subject, you can ask him." Lord Henry shrugged his shoulders. "My dear fellow, as if I cared! Let us go up to the drawing-room. No sherry, thank you, Mr. Chapman. Something has happened to you, Dorian. Tell me what it is. You are not yourself to-night." "Don't mind me, Harry. I am irritable, and out of temper. I shall come round and see you to-morrow, or next day. Make my excuses to Lady Narborough. I shan't go upstairs. I shall go home. I must go home." "All right, Dorian. I dare say I shall see you to-morrow at tea-time. The duchess is coming." "I will try to be there, Harry," he said, leaving the room. As he drove back to his own house, he was conscious that the sense of terror he thought he had strangled had come back to him. Lord Henry's casual questioning had made him lose his nerves for the moment, and he wanted his nerve still. Things that were dangerous had to be destroyed. He winced. He hated the idea of even touching them. Yet it had to be done. He realized that, and when he had locked the door of his library, he opened the secret press into which he had thrust Basil Hallward's coat and bag. A huge fire was blazing. He piled another log on it. The smell of the singeing clothes and burning leather was horrible. It took him three-quarters of an hour to consume everything. At the end he felt faint and sick, and having lit some Algerian pastilles in a pierced copper brazier, he bathed his hands and forehead with a cool musk-scented vinegar. Suddenly he started. His eyes grew strangely bright, and he gnawed nervously at his underlip. Between two of the windows stood a large Florentine cabinet, made out of ebony and inlaid with ivory and blue lapis. He watched it as though it were a thing that could fascinate and make afraid, as though it held something that he longed for and yet almost loathed. His breath quickened. A mad craving came over him. He lit a cigarette and then threw it away. His eyelids drooped till the long fringed lashes almost touched his cheek. But he still watched the cabinet. At last he got up from the sofa on which he had been lying, went over to it, and having unlocked it, touched some hidden spring. A triangular drawer passed slowly out. His fingers moved instinctively towards it, dipped in, and closed on something. It was a small Chinese box of black and gold-dust lacquer, elaborately wrought, the sides patterned with curved waves, and the silken cords hung with round crystals and tasselled in plaited metal threads. He opened it. Inside was a green paste, waxy in lustre, the odour curiously heavy and persistent. He hesitated for some moments, with a strangely immobile smile upon his face. Then shivering, though the atmosphere of the room was terribly hot, he drew himself up and glanced at the clock. It was twenty minutes to twelve. He put the box back, shutting the cabinet doors as he did so, and went into his bedroom. As midnight was striking bronze blows upon the dusky air, Dorian Gray, dressed commonly, and with a muffler wrapped round his throat, crept quietly out of his house. In Bond Street he found a hansom with a good horse. He hailed it and in a low voice gave the driver an address. The man shook his head. "It is too far for me," he muttered. "Here is a sovereign for you," said Dorian. "You shall have another if you drive fast." "All right, sir," answered the man, "you will be there in an hour," and after his fare had got in he turned his horse round and drove rapidly towards the river. CHAPTER 16 A cold rain began to fall, and the blurred street-lamps looked ghastly in the dripping mist. The public-houses were just closing, and dim men and women were clustering in broken groups round their doors. From some of the bars came the sound of horrible laughter. In others, drunkards brawled and screamed. Lying back in the hansom, with his hat pulled over his forehead, Dorian Gray watched with listless eyes the sordid shame of the great city, and now and then he repeated to himself the words that Lord Henry had said to him on the first day they had met, "To cure the soul by means of the senses, and the senses by means of the soul." Yes, that was the secret. He had often tried it, and would try it again now. There were opium dens where one could buy oblivion, dens of horror where the memory of old sins could be destroyed by the madness of sins that were new. The moon hung low in the sky like a yellow skull. From time to time a huge misshapen cloud stretched a long arm across and hid it. The gas-lamps grew fewer, and the streets more narrow and gloomy. Once the man lost his way and had to drive back half a mile. A steam rose from the horse as it splashed up the puddles. The sidewindows of the hansom were clogged with a grey-flannel mist. "To cure the soul by means of the senses, and the senses by means of the soul!" How the words rang in his ears! His soul, certainly, was sick to death. Was it true that the senses could cure it? Innocent blood had been spilled. What could atone for that? Ah! for that there was no atonement; but though forgiveness was impossible, forgetfulness was possible still, and he was determined to forget, to stamp the thing out, to crush it as one would crush the adder that had stung one. Indeed, what right had Basil to have spoken to him as he had done? Who had made him a judge over others? He had said things that were dreadful, horrible, not to be endured. On and on plodded the hansom, going slower, it seemed to him, at each step. He thrust up the trap and called to the man to drive faster. The hideous hunger for opium began to gnaw at him. His throat burned and his delicate hands twitched nervously together. He struck at the horse madly with his stick. The driver laughed and whipped up. He laughed in answer, and the man was silent. The way seemed interminable, and the streets like the black web of some sprawling spider. The monotony became unbearable, and as the mist thickened, he felt afraid. Then they passed by lonely brickfields. The fog was lighter here, and he could see the strange, bottle-shaped kilns with their orange, fanlike tongues of fire. A dog barked as they went by, and far away in the darkness some wandering sea-gull screamed. The horse stumbled in a rut, then swerved aside and broke into a gallop. After some time they left the clay road and rattled again over rough-paven streets. Most of the windows were dark, but now and then fantastic shadows were silhouetted against some lamplit blind. He watched them curiously. They moved like monstrous marionettes and made gestures like live things. He hated them. A dull rage was in his heart. As they turned a corner, a woman yelled something at them from an open door, and two men ran after the hansom for about a hundred yards. The driver beat at them with his whip. It is said that passion makes one think in a circle. Certainly with hideous iteration the bitten lips of Dorian Gray shaped and reshaped those subtle words that dealt with soul and sense, till he had found in them the full expression, as it were, of his mood, and justified, by intellectual approval, passions that without such justification would still have dominated his temper. From cell to cell of his brain crept the one thought; and the wild desire to live, most terrible of all man's appetites, quickened into force each trembling nerve and fibre. Ugliness that had once been hateful to him because it made things real, became dear to him now for that very reason. Ugliness was the one reality. The coarse brawl, the loathsome den, the crude violence of disordered life, the very vileness of thief and outcast, were more vivid, in their intense actuality of impression, than all the gracious shapes of art, the dreamy shadows of song. They were what he needed for forgetfulness. In three days he would be free. Suddenly the man drew up with a jerk at the top of a dark lane. Over the low roofs and jagged chimney-stacks of the houses rose the black masts of ships. Wreaths of white mist clung like ghostly sails to the yards. "Somewhere about here, sir, ain't it?" he asked huskily through the trap. Dorian started and peered round. "This will do," he answered, and having got out hastily and given the driver the extra fare he had promised him, he walked quickly in the direction of the quay. Here and there a lantern gleamed at the stern of some huge merchantman. The light shook and splintered in the puddles. A red glare came from an outward-bound steamer that was coaling. The slimy pavement looked like a wet mackintosh. He hurried on towards the left, glancing back now and then to see if he was being followed. In about seven or eight minutes he reached a small shabby house that was wedged in between two gaunt factories. In one of the top-windows stood a lamp. He stopped and gave a peculiar knock. After a little time he heard steps in the passage and the chain being unhooked. The door opened quietly, and he went in without saying a word to the squat misshapen figure that flattened itself into the shadow as he passed. At the end of the hall hung a tattered green curtain that swayed and shook in the gusty wind which had followed him in from the street. He dragged it aside and entered a long low room which looked as if it had once been a third-rate dancing-saloon. Shrill flaring gas-jets, dulled and distorted in the fly-blown mirrors that faced them, were ranged round the walls. Greasy reflectors of ribbed tin backed them, making quivering disks of light. The floor was covered with ochre-coloured sawdust, trampled here and there into mud, and stained with dark rings of spilled liquor. Some Malays were crouching by a little charcoal stove, playing with bone counters and showing their white teeth as they chattered. In one corner, with his head buried in his arms, a sailor sprawled over a table, and by the tawdrily painted bar that ran across one complete side stood two haggard women, mocking an old man who was brushing the sleeves of his coat with an expression of disgust. "He thinks he's got red ants on him," laughed one of them, as Dorian passed by. The man looked at her in terror and began to whimper. At the end of the room there was a little staircase, leading to a darkened chamber. As Dorian hurried up its three rickety steps, the heavy odour of opium met him. He heaved a deep breath, and his nostrils quivered with pleasure. When he entered, a young man with smooth yellow hair, who was bending over a lamp lighting a long thin pipe, looked up at him and nodded in a hesitating manner. "You here, Adrian?" muttered Dorian. "Where else should I be?" he answered, listlessly. "None of the chaps will speak to me now." "I thought you had left England." "Darlington is not going to do anything. My brother paid the bill at last. George doesn't speak to me either. . . . I don't care," he added with a sigh. "As long as one has this stuff, one doesn't want friends. I think I have had too many friends." Dorian winced and looked round at the grotesque things that lay in such fantastic postures on the ragged mattresses. The twisted limbs, the gaping mouths, the staring lustreless eyes, fascinated him. He knew in what strange heavens they were suffering, and what dull hells were teaching them the secret of some new joy. They were better off than he was. He was prisoned in thought. Memory, like a horrible malady, was eating his soul away. From time to time he seemed to see the eyes of Basil Hallward looking at him. Yet he felt he could not stay. The presence of Adrian Singleton troubled him. He wanted to be where no one would know who he was. He wanted to escape from himself. "I am going on to the other place," he said after a pause. "On the wharf?" "Yes." "That mad-cat is sure to be there. They won't have her in this place now." Dorian shrugged his shoulders. "I am sick of women who love one. Women who hate one are much more interesting. Besides, the stuff is better." "Much the same." "I like it better. Come and have something to drink. I must have something." "I don't want anything," murmured the young man. "Never mind." Adrian Singleton rose up wearily and followed Dorian to the bar. A half-caste, in a ragged turban and a shabby ulster, grinned a hideous greeting as he thrust a bottle of brandy and two tumblers in front of them. The women sidled up and began to chatter. Dorian turned his back on them and said something in a low voice to Adrian Singleton. A crooked smile, like a Malay crease, writhed across the face of one of the women. "We are very proud to-night," she sneered. "For God's sake don't talk to me," cried Dorian, stamping his foot on the ground. "What do you want? Money? Here it is. Don't ever talk to me again." Two red sparks flashed for a moment in the woman's sodden eyes, then flickered out and left them dull and glazed. She tossed her head and raked the coins off the counter with greedy fingers. Her companion watched her enviously. "It's no use," sighed Adrian Singleton. "I don't care to go back. What does it matter? I am quite happy here." "You will write to me if you want anything, won't you?" said Dorian, after a pause. "Perhaps." "Good night, then." "Good night," answered the young man, passing up the steps and wiping his parched mouth with a handkerchief. Dorian walked to the door with a look of pain in his face. As he drew the curtain aside, a hideous laugh broke from the painted lips of the woman who had taken his money. "There goes the devil's bargain!" she hiccoughed, in a hoarse voice. "Curse you!" he answered, "don't call me that." She snapped her fingers. "Prince Charming is what you like to be called, ain't it?" she yelled after him. The drowsy sailor leaped to his feet as she spoke, and looked wildly round. The sound of the shutting of the hall door fell on his ear. He rushed out as if in pursuit. Dorian Gray hurried along the quay through the drizzling rain. His meeting with Adrian Singleton had strangely moved him, and he wondered if the ruin of that young life was really to be laid at his door, as Basil Hallward had said to him with such infamy of insult. He bit his lip, and for a few seconds his eyes grew sad. Yet, after all, what did it matter to him? One's days were too brief to take the burden of another's errors on one's shoulders. Each man lived his own life and paid his own price for living it. The only pity was one had to pay so often for a single fault. One had to pay over and over again, indeed. In her dealings with man, destiny never closed her accounts. There are moments, psychologists tell us, when the passion for sin, or for what the world calls sin, so dominates a nature that every fibre of the body, as every cell of the brain, seems to be instinct with fearful impulses. Men and women at such moments lose the freedom of their will. They move to their terrible end as automatons move. Choice is taken from them, and conscience is either killed, or, if it lives at all, lives but to give rebellion its fascination and disobedience its charm. For all sins, as theologians weary not of reminding us, are sins of disobedience. When that high spirit, that morning star of evil, fell from heaven, it was as a rebel that he fell. Callous, concentrated on evil, with stained mind, and soul hungry for rebellion, Dorian Gray hastened on, quickening his step as he went, but as he darted aside into a dim archway, that had served him often as a short cut to the ill-famed place where he was going, he felt himself suddenly seized from behind, and before he had time to defend himself, he was thrust back against the wall, with a brutal hand round his throat. He struggled madly for life, and by a terrible effort wrenched the tightening fingers away. In a second he heard the click of a revolver, and saw the gleam of a polished barrel, pointing straight at his head, and the dusky form of a short, thick-set man facing him. "What do you want?" he gasped. "Keep quiet," said the man. "If you stir, I shoot you." "You are mad. What have I done to you?" "You wrecked the life of Sibyl Vane," was the answer, "and Sibyl Vane was my sister. She killed herself. I know it. Her death is at your door. I swore I would kill you in return. For years I have sought you. I had no clue, no trace. The two people who could have described you were dead. I knew nothing of you but the pet name she used to call you. I heard it to-night by chance. Make your peace with God, for to-night you are going to die." Dorian Gray grew sick with fear. "I never knew her," he stammered. "I never heard of her. You are mad." "You had better confess your sin, for as sure as I am James Vane, you are going to die." There was a horrible moment. Dorian did not know what to say or do. "Down on your knees!" growled the man. "I give you one minute to make your peace--no more. I go on board to-night for India, and I must do my job first. One minute. That's all." Dorian's arms fell to his side. Paralysed with terror, he did not know what to do. Suddenly a wild hope flashed across his brain. "Stop," he cried. "How long ago is it since your sister died? Quick, tell me!" "Eighteen years," said the man. "Why do you ask me? What do years matter?" "Eighteen years," laughed Dorian Gray, with a touch of triumph in his voice. "Eighteen years! Set me under the lamp and look at my face!" James Vane hesitated for a moment, not understanding what was meant. Then he seized Dorian Gray and dragged him from the archway. Dim and wavering as was the wind-blown light, yet it served to show him the hideous error, as it seemed, into which he had fallen, for the face of the man he had sought to kill had all the bloom of boyhood, all the unstained purity of youth. He seemed little more than a lad of twenty summers, hardly older, if older indeed at all, than his sister had been when they had parted so many years ago. It was obvious that this was not the man who had destroyed her life. He loosened his hold and reeled back. "My God! my God!" he cried, "and I would have murdered you!" Dorian Gray drew a long breath. "You have been on the brink of committing a terrible crime, my man," he said, looking at him sternly. "Let this be a warning to you not to take vengeance into your own hands." "Forgive me, sir," muttered James Vane. "I was deceived. A chance word I heard in that damned den set me on the wrong track." "You had better go home and put that pistol away, or you may get into trouble," said Dorian, turning on his heel and going slowly down the street. James Vane stood on the pavement in horror. He was trembling from head to foot. After a little while, a black shadow that had been creeping along the dripping wall moved out into the light and came close to him with stealthy footsteps. He felt a hand laid on his arm and looked round with a start. It was one of the women who had been drinking at the bar. "Why didn't you kill him?" she hissed out, putting haggard face quite close to his. "I knew you were following him when you rushed out from Daly's. You fool! You should have killed him. He has lots of money, and he's as bad as bad." "He is not the man I am looking for," he answered, "and I want no man's money. I want a man's life. The man whose life I want must be nearly forty now. This one is little more than a boy. Thank God, I have not got his blood upon my hands." The woman gave a bitter laugh. "Little more than a boy!" she sneered. "Why, man, it's nigh on eighteen years since Prince Charming made me what I am." "You lie!" cried James Vane. She raised her hand up to heaven. "Before God I am telling the truth," she cried. "Before God?" "Strike me dumb if it ain't so. He is the worst one that comes here. They say he has sold himself to the devil for a pretty face. It's nigh on eighteen years since I met him. He hasn't changed much since then. I have, though," she added, with a sickly leer. "You swear this?" "I swear it," came in hoarse echo from her flat mouth. "But don't give me away to him," she whined; "I am afraid of him. Let me have some money for my night's lodging." He broke from her with an oath and rushed to the corner of the street, but Dorian Gray had disappeared. When he looked back, the woman had vanished also. CHAPTER 17 A week later Dorian Gray was sitting in the conservatory at Selby Royal, talking to the pretty Duchess of Monmouth, who with her husband, a jaded-looking man of sixty, was amongst his guests. It was tea-time, and the mellow light of the huge, lace-covered lamp that stood on the table lit up the delicate china and hammered silver of the service at which the duchess was presiding. Her white hands were moving daintily among the cups, and her full red lips were smiling at something that Dorian had whispered to her. Lord Henry was lying back in a silk-draped wicker chair, looking at them. On a peach-coloured divan sat Lady Narborough, pretending to listen to the duke's description of the last Brazilian beetle that he had added to his collection. Three young men in elaborate smoking-suits were handing tea-cakes to some of the women. The house-party consisted of twelve people, and there were more expected to arrive on the next day. "What are you two talking about?" said Lord Henry, strolling over to the table and putting his cup down. "I hope Dorian has told you about my plan for rechristening everything, Gladys. It is a delightful idea." "But I don't want to be rechristened, Harry," rejoined the duchess, looking up at him with her wonderful eyes. "I am quite satisfied with my own name, and I am sure Mr. Gray should be satisfied with his." "My dear Gladys, I would not alter either name for the world. They are both perfect. I was thinking chiefly of flowers. Yesterday I cut an orchid, for my button-hole. It was a marvellous spotted thing, as effective as the seven deadly sins. In a thoughtless moment I asked one of the gardeners what it was called. He told me it was a fine specimen of Robinsoniana, or something dreadful of that kind. It is a sad truth, but we have lost the faculty of giving lovely names to things. Names are everything. I never quarrel with actions. My one quarrel is with words. That is the reason I hate vulgar realism in literature. The man who could call a spade a spade should be compelled to use one. It is the only thing he is fit for." "Then what should we call you, Harry?" she asked. "His name is Prince Paradox," said Dorian. "I recognize him in a flash," exclaimed the duchess. "I won't hear of it," laughed Lord Henry, sinking into a chair. "From a label there is no escape! I refuse the title." "Royalties may not abdicate," fell as a warning from pretty lips. "You wish me to defend my throne, then?" "Yes." "I give the truths of to-morrow." "I prefer the mistakes of to-day," she answered. "You disarm me, Gladys," he cried, catching the wilfulness of her mood. "Of your shield, Harry, not of your spear." "I never tilt against beauty," he said, with a wave of his hand. "That is your error, Harry, believe me. You value beauty far too much." "How can you say that? I admit that I think that it is better to be beautiful than to be good. But on the other hand, no one is more ready than I am to acknowledge that it is better to be good than to be ugly." "Ugliness is one of the seven deadly sins, then?" cried the duchess. "What becomes of your simile about the orchid?" "Ugliness is one of the seven deadly virtues, Gladys. You, as a good Tory, must not underrate them. Beer, the Bible, and the seven deadly virtues have made our England what she is." "You don't like your country, then?" she asked. "I live in it." "That you may censure it the better." "Would you have me take the verdict of Europe on it?" he inquired. "What do they say of us?" "That Tartuffe has emigrated to England and opened a shop." "Is that yours, Harry?" "I give it to you." "I could not use it. It is too true." "You need not be afraid. Our countrymen never recognize a description." "They are practical." "They are more cunning than practical. When they make up their ledger, they balance stupidity by wealth, and vice by hypocrisy." "Still, we have done great things." "Great things have been thrust on us, Gladys." "We have carried their burden." "Only as far as the Stock Exchange." She shook her head. "I believe in the race," she cried. "It represents the survival of the pushing." "It has development." "Decay fascinates me more." "What of art?" she asked. "It is a malady." "Love?" "An illusion." "Religion?" "The fashionable substitute for belief." "You are a sceptic." "Never! Scepticism is the beginning of faith." "What are you?" "To define is to limit." "Give me a clue." "Threads snap. You would lose your way in the labyrinth." "You bewilder me. Let us talk of some one else." "Our host is a delightful topic. Years ago he was christened Prince Charming." "Ah! don't remind me of that," cried Dorian Gray. "Our host is rather horrid this evening," answered the duchess, colouring. "I believe he thinks that Monmouth married me on purely scientific principles as the best specimen he could find of a modern butterfly." "Well, I hope he won't stick pins into you, Duchess," laughed Dorian. "Oh! my maid does that already, Mr. Gray, when she is annoyed with me." "And what does she get annoyed with you about, Duchess?" "For the most trivial things, Mr. Gray, I assure you. Usually because I come in at ten minutes to nine and tell her that I must be dressed by half-past eight." "How unreasonable of her! You should give her warning." "I daren't, Mr. Gray. Why, she invents hats for me. You remember the one I wore at Lady Hilstone's garden-party? You don't, but it is nice of you to pretend that you do. Well, she made if out of nothing. All good hats are made out of nothing." "Like all good reputations, Gladys," interrupted Lord Henry. "Every effect that one produces gives one an enemy. To be popular one must be a mediocrity." "Not with women," said the duchess, shaking her head; "and women rule the world. I assure you we can't bear mediocrities. We women, as some one says, love with our ears, just as you men love with your eyes, if you ever love at all." "It seems to me that we never do anything else," murmured Dorian. "Ah! then, you never really love, Mr. Gray," answered the duchess with mock sadness. "My dear Gladys!" cried Lord Henry. "How can you say that? Romance lives by repetition, and repetition converts an appetite into an art. Besides, each time that one loves is the only time one has ever loved. Difference of object does not alter singleness of passion. It merely intensifies it. We can have in life but one great experience at best, and the secret of life is to reproduce that experience as often as possible." "Even when one has been wounded by it, Harry?" asked the duchess after a pause. "Especially when one has been wounded by it," answered Lord Henry. The duchess turned and looked at Dorian Gray with a curious expression in her eyes. "What do you say to that, Mr. Gray?" she inquired. Dorian hesitated for a moment. Then he threw his head back and laughed. "I always agree with Harry, Duchess." "Even when he is wrong?" "Harry is never wrong, Duchess." "And does his philosophy make you happy?" "I have never searched for happiness. Who wants happiness? I have searched for pleasure." "And found it, Mr. Gray?" "Often. Too often." The duchess sighed. "I am searching for peace," she said, "and if I don't go and dress, I shall have none this evening." "Let me get you some orchids, Duchess," cried Dorian, starting to his feet and walking down the conservatory. "You are flirting disgracefully with him," said Lord Henry to his cousin. "You had better take care. He is very fascinating." "If he were not, there would be no battle." "Greek meets Greek, then?" "I am on the side of the Trojans. They fought for a woman." "They were defeated." "There are worse things than capture," she answered. "You gallop with a loose rein." "Pace gives life," was the riposte. "I shall write it in my diary to-night." "What?" "That a burnt child loves the fire." "I am not even singed. My wings are untouched." "You use them for everything, except flight." "Courage has passed from men to women. It is a new experience for us." "You have a rival." "Who?" He laughed. "Lady Narborough," he whispered. "She perfectly adores him." "You fill me with apprehension. The appeal to antiquity is fatal to us who are romanticists." "Romanticists! You have all the methods of science." "Men have educated us." "But not explained you." "Describe us as a sex," was her challenge. "Sphinxes without secrets." She looked at him, smiling. "How long Mr. Gray is!" she said. "Let us go and help him. I have not yet told him the colour of my frock." "Ah! you must suit your frock to his flowers, Gladys." "That would be a premature surrender." "Romantic art begins with its climax." "I must keep an opportunity for retreat." "In the Parthian manner?" "They found safety in the desert. I could not do that." "Women are not always allowed a choice," he answered, but hardly had he finished the sentence before from the far end of the conservatory came a stifled groan, followed by the dull sound of a heavy fall. Everybody started up. The duchess stood motionless in horror. And with fear in his eyes, Lord Henry rushed through the flapping palms to find Dorian Gray lying face downwards on the tiled floor in a deathlike swoon. He was carried at once into the blue drawing-room and laid upon one of the sofas. After a short time, he came to himself and looked round with a dazed expression. "What has happened?" he asked. "Oh! I remember. Am I safe here, Harry?" He began to tremble. "My dear Dorian," answered Lord Henry, "you merely fainted. That was all. You must have overtired yourself. You had better not come down to dinner. I will take your place." "No, I will come down," he said, struggling to his feet. "I would rather come down. I must not be alone." He went to his room and dressed. There was a wild recklessness of gaiety in his manner as he sat at table, but now and then a thrill of terror ran through him when he remembered that, pressed against the window of the conservatory, like a white handkerchief, he had seen the face of James Vane watching him. CHAPTER 18 The next day he did not leave the house, and, indeed, spent most of the time in his own room, sick with a wild terror of dying, and yet indifferent to life itself. The consciousness of being hunted, snared, tracked down, had begun to dominate him. If the tapestry did but tremble in the wind, he shook. The dead leaves that were blown against the leaded panes seemed to him like his own wasted resolutions and wild regrets. When he closed his eyes, he saw again the sailor's face peering through the mist-stained glass, and horror seemed once more to lay its hand upon his heart. But perhaps it had been only his fancy that had called vengeance out of the night and set the hideous shapes of punishment before him. Actual life was chaos, but there was something terribly logical in the imagination. It was the imagination that set remorse to dog the feet of sin. It was the imagination that made each crime bear its misshapen brood. In the common world of fact the wicked were not punished, nor the good rewarded. Success was given to the strong, failure thrust upon the weak. That was all. Besides, had any stranger been prowling round the house, he would have been seen by the servants or the keepers. Had any foot-marks been found on the flower-beds, the gardeners would have reported it. Yes, it had been merely fancy. Sibyl Vane's brother had not come back to kill him. He had sailed away in his ship to founder in some winter sea. From him, at any rate, he was safe. Why, the man did not know who he was, could not know who he was. The mask of youth had saved him. And yet if it had been merely an illusion, how terrible it was to think that conscience could raise such fearful phantoms, and give them visible form, and make them move before one! What sort of life would his be if, day and night, shadows of his crime were to peer at him from silent corners, to mock him from secret places, to whisper in his ear as he sat at the feast, to wake him with icy fingers as he lay asleep! As the thought crept through his brain, he grew pale with terror, and the air seemed to him to have become suddenly colder. Oh! in what a wild hour of madness he had killed his friend! How ghastly the mere memory of the scene! He saw it all again. Each hideous detail came back to him with added horror. Out of the black cave of time, terrible and swathed in scarlet, rose the image of his sin. When Lord Henry came in at six o'clock, he found him crying as one whose heart will break. It was not till the third day that he ventured to go out. There was something in the clear, pine-scented air of that winter morning that seemed to bring him back his joyousness and his ardour for life. But it was not merely the physical conditions of environment that had caused the change. His own nature had revolted against the excess of anguish that had sought to maim and mar the perfection of its calm. With subtle and finely wrought temperaments it is always so. Their strong passions must either bruise or bend. They either slay the man, or themselves die. Shallow sorrows and shallow loves live on. The loves and sorrows that are great are destroyed by their own plenitude. Besides, he had convinced himself that he had been the victim of a terror-stricken imagination, and looked back now on his fears with something of pity and not a little of contempt. After breakfast, he walked with the duchess for an hour in the garden and then drove across the park to join the shooting-party. The crisp frost lay like salt upon the grass. The sky was an inverted cup of blue metal. A thin film of ice bordered the flat, reed-grown lake. At the corner of the pine-wood he caught sight of Sir Geoffrey Clouston, the duchess's brother, jerking two spent cartridges out of his gun. He jumped from the cart, and having told the groom to take the mare home, made his way towards his guest through the withered bracken and rough undergrowth. "Have you had good sport, Geoffrey?" he asked. "Not very good, Dorian. I think most of the birds have gone to the open. I dare say it will be better after lunch, when we get to new ground." Dorian strolled along by his side. The keen aromatic air, the brown and red lights that glimmered in the wood, the hoarse cries of the beaters ringing out from time to time, and the sharp snaps of the guns that followed, fascinated him and filled him with a sense of delightful freedom. He was dominated by the carelessness of happiness, by the high indifference of joy. Suddenly from a lumpy tussock of old grass some twenty yards in front of them, with black-tipped ears erect and long hinder limbs throwing it forward, started a hare. It bolted for a thicket of alders. Sir Geoffrey put his gun to his shoulder, but there was something in the animal's grace of movement that strangely charmed Dorian Gray, and he cried out at once, "Don't shoot it, Geoffrey. Let it live." "What nonsense, Dorian!" laughed his companion, and as the hare bounded into the thicket, he fired. There were two cries heard, the cry of a hare in pain, which is dreadful, the cry of a man in agony, which is worse. "Good heavens! I have hit a beater!" exclaimed Sir Geoffrey. "What an ass the man was to get in front of the guns! Stop shooting there!" he called out at the top of his voice. "A man is hurt." The head-keeper came running up with a stick in his hand. "Where, sir? Where is he?" he shouted. At the same time, the firing ceased along the line. "Here," answered Sir Geoffrey angrily, hurrying towards the thicket. "Why on earth don't you keep your men back? Spoiled my shooting for the day." Dorian watched them as they plunged into the alder-clump, brushing the lithe swinging branches aside. In a few moments they emerged, dragging a body after them into the sunlight. He turned away in horror. It seemed to him that misfortune followed wherever he went. He heard Sir Geoffrey ask if the man was really dead, and the affirmative answer of the keeper. The wood seemed to him to have become suddenly alive with faces. There was the trampling of myriad feet and the low buzz of voices. A great copper-breasted pheasant came beating through the boughs overhead. After a few moments--that were to him, in his perturbed state, like endless hours of pain--he felt a hand laid on his shoulder. He started and looked round. "Dorian," said Lord Henry, "I had better tell them that the shooting is stopped for to-day. It would not look well to go on." "I wish it were stopped for ever, Harry," he answered bitterly. "The whole thing is hideous and cruel. Is the man ... ?" He could not finish the sentence. "I am afraid so," rejoined Lord Henry. "He got the whole charge of shot in his chest. He must have died almost instantaneously. Come; let us go home." They walked side by side in the direction of the avenue for nearly fifty yards without speaking. Then Dorian looked at Lord Henry and said, with a heavy sigh, "It is a bad omen, Harry, a very bad omen." "What is?" asked Lord Henry. "Oh! this accident, I suppose. My dear fellow, it can't be helped. It was the man's own fault. Why did he get in front of the guns? Besides, it is nothing to us. It is rather awkward for Geoffrey, of course. It does not do to pepper beaters. It makes people think that one is a wild shot. And Geoffrey is not; he shoots very straight. But there is no use talking about the matter." Dorian shook his head. "It is a bad omen, Harry. I feel as if something horrible were going to happen to some of us. To myself, perhaps," he added, passing his hand over his eyes, with a gesture of pain. The elder man laughed. "The only horrible thing in the world is ennui, Dorian. That is the one sin for which there is no forgiveness. But we are not likely to suffer from it unless these fellows keep chattering about this thing at dinner. I must tell them that the subject is to be tabooed. As for omens, there is no such thing as an omen. Destiny does not send us heralds. She is too wise or too cruel for that. Besides, what on earth could happen to you, Dorian? You have everything in the world that a man can want. There is no one who would not be delighted to change places with you." "There is no one with whom I would not change places, Harry. Don't laugh like that. I am telling you the truth. The wretched peasant who has just died is better off than I am. I have no terror of death. It is the coming of death that terrifies me. Its monstrous wings seem to wheel in the leaden air around me. Good heavens! don't you see a man moving behind the trees there, watching me, waiting for me?" Lord Henry looked in the direction in which the trembling gloved hand was pointing. "Yes," he said, smiling, "I see the gardener waiting for you. I suppose he wants to ask you what flowers you wish to have on the table to-night. How absurdly nervous you are, my dear fellow! You must come and see my doctor, when we get back to town." Dorian heaved a sigh of relief as he saw the gardener approaching. The man touched his hat, glanced for a moment at Lord Henry in a hesitating manner, and then produced a letter, which he handed to his master. "Her Grace told me to wait for an answer," he murmured. Dorian put the letter into his pocket. "Tell her Grace that I am coming in," he said, coldly. The man turned round and went rapidly in the direction of the house. "How fond women are of doing dangerous things!" laughed Lord Henry. "It is one of the qualities in them that I admire most. A woman will flirt with anybody in the world as long as other people are looking on." "How fond you are of saying dangerous things, Harry! In the present instance, you are quite astray. I like the duchess very much, but I don't love her." "And the duchess loves you very much, but she likes you less, so you are excellently matched." "You are talking scandal, Harry, and there is never any basis for scandal." "The basis of every scandal is an immoral certainty," said Lord Henry, lighting a cigarette. "You would sacrifice anybody, Harry, for the sake of an epigram." "The world goes to the altar of its own accord," was the answer. "I wish I could love," cried Dorian Gray with a deep note of pathos in his voice. "But I seem to have lost the passion and forgotten the desire. I am too much concentrated on myself. My own personality has become a burden to me. I want to escape, to go away, to forget. It was silly of me to come down here at all. I think I shall send a wire to Harvey to have the yacht got ready. On a yacht one is safe." "Safe from what, Dorian? You are in some trouble. Why not tell me what it is? You know I would help you." "I can't tell you, Harry," he answered sadly. "And I dare say it is only a fancy of mine. This unfortunate accident has upset me. I have a horrible presentiment that something of the kind may happen to me." "What nonsense!" "I hope it is, but I can't help feeling it. Ah! here is the duchess, looking like Artemis in a tailor-made gown. You see we have come back, Duchess." "I have heard all about it, Mr. Gray," she answered. "Poor Geoffrey is terribly upset. And it seems that you asked him not to shoot the hare. How curious!" "Yes, it was very curious. I don't know what made me say it. Some whim, I suppose. It looked the loveliest of little live things. But I am sorry they told you about the man. It is a hideous subject." "It is an annoying subject," broke in Lord Henry. "It has no psychological value at all. Now if Geoffrey had done the thing on purpose, how interesting he would be! I should like to know some one who had committed a real murder." "How horrid of you, Harry!" cried the duchess. "Isn't it, Mr. Gray? Harry, Mr. Gray is ill again. He is going to faint." Dorian drew himself up with an effort and smiled. "It is nothing, Duchess," he murmured; "my nerves are dreadfully out of order. That is all. I am afraid I walked too far this morning. I didn't hear what Harry said. Was it very bad? You must tell me some other time. I think I must go and lie down. You will excuse me, won't you?" They had reached the great flight of steps that led from the conservatory on to the terrace. As the glass door closed behind Dorian, Lord Henry turned and looked at the duchess with his slumberous eyes. "Are you very much in love with him?" he asked. She did not answer for some time, but stood gazing at the landscape. "I wish I knew," she said at last. He shook his head. "Knowledge would be fatal. It is the uncertainty that charms one. A mist makes things wonderful." "One may lose one's way." "All ways end at the same point, my dear Gladys." "What is that?" "Disillusion." "It was my debut in life," she sighed. "It came to you crowned." "I am tired of strawberry leaves." "They become you." "Only in public." "You would miss them," said Lord Henry. "I will not part with a petal." "Monmouth has ears." "Old age is dull of hearing." "Has he never been jealous?" "I wish he had been." He glanced about as if in search of something. "What are you looking for?" she inquired. "The button from your foil," he answered. "You have dropped it." She laughed. "I have still the mask." "It makes your eyes lovelier," was his reply. She laughed again. Her teeth showed like white seeds in a scarlet fruit. Upstairs, in his own room, Dorian Gray was lying on a sofa, with terror in every tingling fibre of his body. Life had suddenly become too hideous a burden for him to bear. The dreadful death of the unlucky beater, shot in the thicket like a wild animal, had seemed to him to pre-figure death for himself also. He had nearly swooned at what Lord Henry had said in a chance mood of cynical jesting. At five o'clock he rang his bell for his servant and gave him orders to pack his things for the night-express to town, and to have the brougham at the door by eight-thirty. He was determined not to sleep another night at Selby Royal. It was an ill-omened place. Death walked there in the sunlight. The grass of the forest had been spotted with blood. Then he wrote a note to Lord Henry, telling him that he was going up to town to consult his doctor and asking him to entertain his guests in his absence. As he was putting it into the envelope, a knock came to the door, and his valet informed him that the head-keeper wished to see him. He frowned and bit his lip. "Send him in," he muttered, after some moments' hesitation. As soon as the man entered, Dorian pulled his chequebook out of a drawer and spread it out before him. "I suppose you have come about the unfortunate accident of this morning, Thornton?" he said, taking up a pen. "Yes, sir," answered the gamekeeper. "Was the poor fellow married? Had he any people dependent on him?" asked Dorian, looking bored. "If so, I should not like them to be left in want, and will send them any sum of money you may think necessary." "We don't know who he is, sir. That is what I took the liberty of coming to you about." "Don't know who he is?" said Dorian, listlessly. "What do you mean? Wasn't he one of your men?" "No, sir. Never saw him before. Seems like a sailor, sir." The pen dropped from Dorian Gray's hand, and he felt as if his heart had suddenly stopped beating. "A sailor?" he cried out. "Did you say a sailor?" "Yes, sir. He looks as if he had been a sort of sailor; tattooed on both arms, and that kind of thing." "Was there anything found on him?" said Dorian, leaning forward and looking at the man with startled eyes. "Anything that would tell his name?" "Some money, sir--not much, and a six-shooter. There was no name of any kind. A decent-looking man, sir, but rough-like. A sort of sailor we think." Dorian started to his feet. A terrible hope fluttered past him. He clutched at it madly. "Where is the body?" he exclaimed. "Quick! I must see it at once." "It is in an empty stable in the Home Farm, sir. The folk don't like to have that sort of thing in their houses. They say a corpse brings bad luck." "The Home Farm! Go there at once and meet me. Tell one of the grooms to bring my horse round. No. Never mind. I'll go to the stables myself. It will save time." In less than a quarter of an hour, Dorian Gray was galloping down the long avenue as hard as he could go. The trees seemed to sweep past him in spectral procession, and wild shadows to fling themselves across his path. Once the mare swerved at a white gate-post and nearly threw him. He lashed her across the neck with his crop. She cleft the dusky air like an arrow. The stones flew from her hoofs. At last he reached the Home Farm. Two men were loitering in the yard. He leaped from the saddle and threw the reins to one of them. In the farthest stable a light was glimmering. Something seemed to tell him that the body was there, and he hurried to the door and put his hand upon the latch. There he paused for a moment, feeling that he was on the brink of a discovery that would either make or mar his life. Then he thrust the door open and entered. On a heap of sacking in the far corner was lying the dead body of a man dressed in a coarse shirt and a pair of blue trousers. A spotted handkerchief had been placed over the face. A coarse candle, stuck in a bottle, sputtered beside it. Dorian Gray shuddered. He felt that his could not be the hand to take the handkerchief away, and called out to one of the farm-servants to come to him. "Take that thing off the face. I wish to see it," he said, clutching at the door-post for support. When the farm-servant had done so, he stepped forward. A cry of joy broke from his lips. The man who had been shot in the thicket was James Vane. He stood there for some minutes looking at the dead body. As he rode home, his eyes were full of tears, for he knew he was safe. CHAPTER 19 "There is no use your telling me that you are going to be good," cried Lord Henry, dipping his white fingers into a red copper bowl filled with rose-water. "You are quite perfect. Pray, don't change." Dorian Gray shook his head. "No, Harry, I have done too many dreadful things in my life. I am not going to do any more. I began my good actions yesterday." "Where were you yesterday?" "In the country, Harry. I was staying at a little inn by myself." "My dear boy," said Lord Henry, smiling, "anybody can be good in the country. There are no temptations there. That is the reason why people who live out of town are so absolutely uncivilized. Civilization is not by any means an easy thing to attain to. There are only two ways by which man can reach it. One is by being cultured, the other by being corrupt. Country people have no opportunity of being either, so they stagnate." "Culture and corruption," echoed Dorian. "I have known something of both. It seems terrible to me now that they should ever be found together. For I have a new ideal, Harry. I am going to alter. I think I have altered." "You have not yet told me what your good action was. Or did you say you had done more than one?" asked his companion as he spilled into his plate a little crimson pyramid of seeded strawberries and, through a perforated, shell-shaped spoon, snowed white sugar upon them. "I can tell you, Harry. It is not a story I could tell to any one else. I spared somebody. It sounds vain, but you understand what I mean. She was quite beautiful and wonderfully like Sibyl Vane. I think it was that which first attracted me to her. You remember Sibyl, don't you? How long ago that seems! Well, Hetty was not one of our own class, of course. She was simply a girl in a village. But I really loved her. I am quite sure that I loved her. All during this wonderful May that we have been having, I used to run down and see her two or three times a week. Yesterday she met me in a little orchard. The apple-blossoms kept tumbling down on her hair, and she was laughing. We were to have gone away together this morning at dawn. Suddenly I determined to leave her as flowerlike as I had found her." "I should think the novelty of the emotion must have given you a thrill of real pleasure, Dorian," interrupted Lord Henry. "But I can finish your idyll for you. You gave her good advice and broke her heart. That was the beginning of your reformation." "Harry, you are horrible! You mustn't say these dreadful things. Hetty's heart is not broken. Of course, she cried and all that. But there is no disgrace upon her. She can live, like Perdita, in her garden of mint and marigold." "And weep over a faithless Florizel," said Lord Henry, laughing, as he leaned back in his chair. "My dear Dorian, you have the most curiously boyish moods. Do you think this girl will ever be really content now with any one of her own rank? I suppose she will be married some day to a rough carter or a grinning ploughman. Well, the fact of having met you, and loved you, will teach her to despise her husband, and she will be wretched. From a moral point of view, I cannot say that I think much of your great renunciation. Even as a beginning, it is poor. Besides, how do you know that Hetty isn't floating at the present moment in some starlit mill-pond, with lovely water-lilies round her, like Ophelia?" "I can't bear this, Harry! You mock at everything, and then suggest the most serious tragedies. I am sorry I told you now. I don't care what you say to me. I know I was right in acting as I did. Poor Hetty! As I rode past the farm this morning, I saw her white face at the window, like a spray of jasmine. Don't let us talk about it any more, and don't try to persuade me that the first good action I have done for years, the first little bit of self-sacrifice I have ever known, is really a sort of sin. I want to be better. I am going to be better. Tell me something about yourself. What is going on in town? I have not been to the club for days." "The people are still discussing poor Basil's disappearance." "I should have thought they had got tired of that by this time," said Dorian, pouring himself out some wine and frowning slightly. "My dear boy, they have only been talking about it for six weeks, and the British public are really not equal to the mental strain of having more than one topic every three months. They have been very fortunate lately, however. They have had my own divorce-case and Alan Campbell's suicide. Now they have got the mysterious disappearance of an artist. Scotland Yard still insists that the man in the grey ulster who left for Paris by the midnight train on the ninth of November was poor Basil, and the French police declare that Basil never arrived in Paris at all. I suppose in about a fortnight we shall be told that he has been seen in San Francisco. It is an odd thing, but every one who disappears is said to be seen at San Francisco. It must be a delightful city, and possess all the attractions of the next world." "What do you think has happened to Basil?" asked Dorian, holding up his Burgundy against the light and wondering how it was that he could discuss the matter so calmly. "I have not the slightest idea. If Basil chooses to hide himself, it is no business of mine. If he is dead, I don't want to think about him. Death is the only thing that ever terrifies me. I hate it." "Why?" said the younger man wearily. "Because," said Lord Henry, passing beneath his nostrils the gilt trellis of an open vinaigrette box, "one can survive everything nowadays except that. Death and vulgarity are the only two facts in the nineteenth century that one cannot explain away. Let us have our coffee in the music-room, Dorian. You must play Chopin to me. The man with whom my wife ran away played Chopin exquisitely. Poor Victoria! I was very fond of her. The house is rather lonely without her. Of course, married life is merely a habit, a bad habit. But then one regrets the loss even of one's worst habits. Perhaps one regrets them the most. They are such an essential part of one's personality." Dorian said nothing, but rose from the table, and passing into the next room, sat down to the piano and let his fingers stray across the white and black ivory of the keys. After the coffee had been brought in, he stopped, and looking over at Lord Henry, said, "Harry, did it ever occur to you that Basil was murdered?" Lord Henry yawned. "Basil was very popular, and always wore a Waterbury watch. Why should he have been murdered? He was not clever enough to have enemies. Of course, he had a wonderful genius for painting. But a man can paint like Velasquez and yet be as dull as possible. Basil was really rather dull. He only interested me once, and that was when he told me, years ago, that he had a wild adoration for you and that you were the dominant motive of his art." "I was very fond of Basil," said Dorian with a note of sadness in his voice. "But don't people say that he was murdered?" "Oh, some of the papers do. It does not seem to me to be at all probable. I know there are dreadful places in Paris, but Basil was not the sort of man to have gone to them. He had no curiosity. It was his chief defect." "What would you say, Harry, if I told you that I had murdered Basil?" said the younger man. He watched him intently after he had spoken. "I would say, my dear fellow, that you were posing for a character that doesn't suit you. All crime is vulgar, just as all vulgarity is crime. It is not in you, Dorian, to commit a murder. I am sorry if I hurt your vanity by saying so, but I assure you it is true. Crime belongs exclusively to the lower orders. I don't blame them in the smallest degree. I should fancy that crime was to them what art is to us, simply a method of procuring extraordinary sensations." "A method of procuring sensations? Do you think, then, that a man who has once committed a murder could possibly do the same crime again? Don't tell me that." "Oh! anything becomes a pleasure if one does it too often," cried Lord Henry, laughing. "That is one of the most important secrets of life. I should fancy, however, that murder is always a mistake. One should never do anything that one cannot talk about after dinner. But let us pass from poor Basil. I wish I could believe that he had come to such a really romantic end as you suggest, but I can't. I dare say he fell into the Seine off an omnibus and that the conductor hushed up the scandal. Yes: I should fancy that was his end. I see him lying now on his back under those dull-green waters, with the heavy barges floating over him and long weeds catching in his hair. Do you know, I don't think he would have done much more good work. During the last ten years his painting had gone off very much." Dorian heaved a sigh, and Lord Henry strolled across the room and began to stroke the head of a curious Java parrot, a large, grey-plumaged bird with pink crest and tail, that was balancing itself upon a bamboo perch. As his pointed fingers touched it, it dropped the white scurf of crinkled lids over black, glasslike eyes and began to sway backwards and forwards. "Yes," he continued, turning round and taking his handkerchief out of his pocket; "his painting had quite gone off. It seemed to me to have lost something. It had lost an ideal. When you and he ceased to be great friends, he ceased to be a great artist. What was it separated you? I suppose he bored you. If so, he never forgave you. It's a habit bores have. By the way, what has become of that wonderful portrait he did of you? I don't think I have ever seen it since he finished it. Oh! I remember your telling me years ago that you had sent it down to Selby, and that it had got mislaid or stolen on the way. You never got it back? What a pity! it was really a masterpiece. I remember I wanted to buy it. I wish I had now. It belonged to Basil's best period. Since then, his work was that curious mixture of bad painting and good intentions that always entitles a man to be called a representative British artist. Did you advertise for it? You should." "I forget," said Dorian. "I suppose I did. But I never really liked it. I am sorry I sat for it. The memory of the thing is hateful to me. Why do you talk of it? It used to remind me of those curious lines in some play--Hamlet, I think--how do they run?-- "Like the painting of a sorrow, A face without a heart." Yes: that is what it was like." Lord Henry laughed. "If a man treats life artistically, his brain is his heart," he answered, sinking into an arm-chair. Dorian Gray shook his head and struck some soft chords on the piano. "'Like the painting of a sorrow,'" he repeated, "'a face without a heart.'" The elder man lay back and looked at him with half-closed eyes. "By the way, Dorian," he said after a pause, "'what does it profit a man if he gain the whole world and lose--how does the quotation run?-- his own soul'?" The music jarred, and Dorian Gray started and stared at his friend. "Why do you ask me that, Harry?" "My dear fellow," said Lord Henry, elevating his eyebrows in surprise, "I asked you because I thought you might be able to give me an answer. That is all. I was going through the park last Sunday, and close by the Marble Arch there stood a little crowd of shabby-looking people listening to some vulgar street-preacher. As I passed by, I heard the man yelling out that question to his audience. It struck me as being rather dramatic. London is very rich in curious effects of that kind. A wet Sunday, an uncouth Christian in a mackintosh, a ring of sickly white faces under a broken roof of dripping umbrellas, and a wonderful phrase flung into the air by shrill hysterical lips--it was really very good in its way, quite a suggestion. I thought of telling the prophet that art had a soul, but that man had not. I am afraid, however, he would not have understood me." "Don't, Harry. The soul is a terrible reality. It can be bought, and sold, and bartered away. It can be poisoned, or made perfect. There is a soul in each one of us. I know it." "Do you feel quite sure of that, Dorian?" "Quite sure." "Ah! then it must be an illusion. The things one feels absolutely certain about are never true. That is the fatality of faith, and the lesson of romance. How grave you are! Don't be so serious. What have you or I to do with the superstitions of our age? No: we have given up our belief in the soul. Play me something. Play me a nocturne, Dorian, and, as you play, tell me, in a low voice, how you have kept your youth. You must have some secret. I am only ten years older than you are, and I am wrinkled, and worn, and yellow. You are really wonderful, Dorian. You have never looked more charming than you do to-night. You remind me of the day I saw you first. You were rather cheeky, very shy, and absolutely extraordinary. You have changed, of course, but not in appearance. I wish you would tell me your secret. To get back my youth I would do anything in the world, except take exercise, get up early, or be respectable. Youth! There is nothing like it. It's absurd to talk of the ignorance of youth. The only people to whose opinions I listen now with any respect are people much younger than myself. They seem in front of me. Life has revealed to them her latest wonder. As for the aged, I always contradict the aged. I do it on principle. If you ask them their opinion on something that happened yesterday, they solemnly give you the opinions current in 1820, when people wore high stocks, believed in everything, and knew absolutely nothing. How lovely that thing you are playing is! I wonder, did Chopin write it at Majorca, with the sea weeping round the villa and the salt spray dashing against the panes? It is marvellously romantic. What a blessing it is that there is one art left to us that is not imitative! Don't stop. I want music to-night. It seems to me that you are the young Apollo and that I am Marsyas listening to you. I have sorrows, Dorian, of my own, that even you know nothing of. The tragedy of old age is not that one is old, but that one is young. I am amazed sometimes at my own sincerity. Ah, Dorian, how happy you are! What an exquisite life you have had! You have drunk deeply of everything. You have crushed the grapes against your palate. Nothing has been hidden from you. And it has all been to you no more than the sound of music. It has not marred you. You are still the same." "I am not the same, Harry." "Yes, you are the same. I wonder what the rest of your life will be. Don't spoil it by renunciations. At present you are a perfect type. Don't make yourself incomplete. You are quite flawless now. You need not shake your head: you know you are. Besides, Dorian, don't deceive yourself. Life is not governed by will or intention. Life is a question of nerves, and fibres, and slowly built-up cells in which thought hides itself and passion has its dreams. You may fancy yourself safe and think yourself strong. But a chance tone of colour in a room or a morning sky, a particular perfume that you had once loved and that brings subtle memories with it, a line from a forgotten poem that you had come across again, a cadence from a piece of music that you had ceased to play-- I tell you, Dorian, that it is on things like these that our lives depend. Browning writes about that somewhere; but our own senses will imagine them for us. There are moments when the odour of lilas blanc passes suddenly across me, and I have to live the strangest month of my life over again. I wish I could change places with you, Dorian. The world has cried out against us both, but it has always worshipped you. It always will worship you. You are the type of what the age is searching for, and what it is afraid it has found. I am so glad that you have never done anything, never carved a statue, or painted a picture, or produced anything outside of yourself! Life has been your art. You have set yourself to music. Your days are your sonnets." Dorian rose up from the piano and passed his hand through his hair. "Yes, life has been exquisite," he murmured, "but I am not going to have the same life, Harry. And you must not say these extravagant things to me. You don't know everything about me. I think that if you did, even you would turn from me. You laugh. Don't laugh." "Why have you stopped playing, Dorian? Go back and give me the nocturne over again. Look at that great, honey-coloured moon that hangs in the dusky air. She is waiting for you to charm her, and if you play she will come closer to the earth. You won't? Let us go to the club, then. It has been a charming evening, and we must end it charmingly. There is some one at White's who wants immensely to know you--young Lord Poole, Bournemouth's eldest son. He has already copied your neckties, and has begged me to introduce him to you. He is quite delightful and rather reminds me of you." "I hope not," said Dorian with a sad look in his eyes. "But I am tired to-night, Harry. I shan't go to the club. It is nearly eleven, and I want to go to bed early." "Do stay. You have never played so well as to-night. There was something in your touch that was wonderful. It had more expression than I had ever heard from it before." "It is because I am going to be good," he answered, smiling. "I am a little changed already." "You cannot change to me, Dorian," said Lord Henry. "You and I will always be friends." "Yet you poisoned me with a book once. I should not forgive that. Harry, promise me that you will never lend that book to any one. It does harm." "My dear boy, you are really beginning to moralize. You will soon be going about like the converted, and the revivalist, warning people against all the sins of which you have grown tired. You are much too delightful to do that. Besides, it is no use. You and I are what we are, and will be what we will be. As for being poisoned by a book, there is no such thing as that. Art has no influence upon action. It annihilates the desire to act. It is superbly sterile. The books that the world calls immoral are books that show the world its own shame. That is all. But we won't discuss literature. Come round to-morrow. I am going to ride at eleven. We might go together, and I will take you to lunch afterwards with Lady Branksome. She is a charming woman, and wants to consult you about some tapestries she is thinking of buying. Mind you come. Or shall we lunch with our little duchess? She says she never sees you now. Perhaps you are tired of Gladys? I thought you would be. Her clever tongue gets on one's nerves. Well, in any case, be here at eleven." "Must I really come, Harry?" "Certainly. The park is quite lovely now. I don't think there have been such lilacs since the year I met you." "Very well. I shall be here at eleven," said Dorian. "Good night, Harry." As he reached the door, he hesitated for a moment, as if he had something more to say. Then he sighed and went out. CHAPTER 20 It was a lovely night, so warm that he threw his coat over his arm and did not even put his silk scarf round his throat. As he strolled home, smoking his cigarette, two young men in evening dress passed him. He heard one of them whisper to the other, "That is Dorian Gray." He remembered how pleased he used to be when he was pointed out, or stared at, or talked about. He was tired of hearing his own name now. Half the charm of the little village where he had been so often lately was that no one knew who he was. He had often told the girl whom he had lured to love him that he was poor, and she had believed him. He had told her once that he was wicked, and she had laughed at him and answered that wicked people were always very old and very ugly. What a laugh she had!--just like a thrush singing. And how pretty she had been in her cotton dresses and her large hats! She knew nothing, but she had everything that he had lost. When he reached home, he found his servant waiting up for him. He sent him to bed, and threw himself down on the sofa in the library, and began to think over some of the things that Lord Henry had said to him. Was it really true that one could never change? He felt a wild longing for the unstained purity of his boyhood-- his rose-white boyhood, as Lord Henry had once called it. He knew that he had tarnished himself, filled his mind with corruption and given horror to his fancy; that he had been an evil influence to others, and had experienced a terrible joy in being so; and that of the lives that had crossed his own, it had been the fairest and the most full of promise that he had brought to shame. But was it all irretrievable? Was there no hope for him? Ah! in what a monstrous moment of pride and passion he had prayed that the portrait should bear the burden of his days, and he keep the unsullied splendour of eternal youth! All his failure had been due to that. Better for him that each sin of his life had brought its sure swift penalty along with it. There was purification in punishment. Not "Forgive us our sins" but "Smite us for our iniquities" should be the prayer of man to a most just God. The curiously carved mirror that Lord Henry had given to him, so many years ago now, was standing on the table, and the white-limbed Cupids laughed round it as of old. He took it up, as he had done on that night of horror when he had first noted the change in the fatal picture, and with wild, tear-dimmed eyes looked into its polished shield. Once, some one who had terribly loved him had written to him a mad letter, ending with these idolatrous words: "The world is changed because you are made of ivory and gold. The curves of your lips rewrite history." The phrases came back to his memory, and he repeated them over and over to himself. Then he loathed his own beauty, and flinging the mirror on the floor, crushed it into silver splinters beneath his heel. It was his beauty that had ruined him, his beauty and the youth that he had prayed for. But for those two things, his life might have been free from stain. His beauty had been to him but a mask, his youth but a mockery. What was youth at best? A green, an unripe time, a time of shallow moods, and sickly thoughts. Why had he worn its livery? Youth had spoiled him. It was better not to think of the past. Nothing could alter that. It was of himself, and of his own future, that he had to think. James Vane was hidden in a nameless grave in Selby churchyard. Alan Campbell had shot himself one night in his laboratory, but had not revealed the secret that he had been forced to know. The excitement, such as it was, over Basil Hallward's disappearance would soon pass away. It was already waning. He was perfectly safe there. Nor, indeed, was it the death of Basil Hallward that weighed most upon his mind. It was the living death of his own soul that troubled him. Basil had painted the portrait that had marred his life. He could not forgive him that. It was the portrait that had done everything. Basil had said things to him that were unbearable, and that he had yet borne with patience. The murder had been simply the madness of a moment. As for Alan Campbell, his suicide had been his own act. He had chosen to do it. It was nothing to him. A new life! That was what he wanted. That was what he was waiting for. Surely he had begun it already. He had spared one innocent thing, at any rate. He would never again tempt innocence. He would be good. As he thought of Hetty Merton, he began to wonder if the portrait in the locked room had changed. Surely it was not still so horrible as it had been? Perhaps if his life became pure, he would be able to expel every sign of evil passion from the face. Perhaps the signs of evil had already gone away. He would go and look. He took the lamp from the table and crept upstairs. As he unbarred the door, a smile of joy flitted across his strangely young-looking face and lingered for a moment about his lips. Yes, he would be good, and the hideous thing that he had hidden away would no longer be a terror to him. He felt as if the load had been lifted from him already. He went in quietly, locking the door behind him, as was his custom, and dragged the purple hanging from the portrait. A cry of pain and indignation broke from him. He could see no change, save that in the eyes there was a look of cunning and in the mouth the curved wrinkle of the hypocrite. The thing was still loathsome--more loathsome, if possible, than before--and the scarlet dew that spotted the hand seemed brighter, and more like blood newly spilled. Then he trembled. Had it been merely vanity that had made him do his one good deed? Or the desire for a new sensation, as Lord Henry had hinted, with his mocking laugh? Or that passion to act a part that sometimes makes us do things finer than we are ourselves? Or, perhaps, all these? And why was the red stain larger than it had been? It seemed to have crept like a horrible disease over the wrinkled fingers. There was blood on the painted feet, as though the thing had dripped--blood even on the hand that had not held the knife. Confess? Did it mean that he was to confess? To give himself up and be put to death? He laughed. He felt that the idea was monstrous. Besides, even if he did confess, who would believe him? There was no trace of the murdered man anywhere. Everything belonging to him had been destroyed. He himself had burned what had been below-stairs. The world would simply say that he was mad. They would shut him up if he persisted in his story. . . . Yet it was his duty to confess, to suffer public shame, and to make public atonement. There was a God who called upon men to tell their sins to earth as well as to heaven. Nothing that he could do would cleanse him till he had told his own sin. His sin? He shrugged his shoulders. The death of Basil Hallward seemed very little to him. He was thinking of Hetty Merton. For it was an unjust mirror, this mirror of his soul that he was looking at. Vanity? Curiosity? Hypocrisy? Had there been nothing more in his renunciation than that? There had been something more. At least he thought so. But who could tell? . . . No. There had been nothing more. Through vanity he had spared her. In hypocrisy he had worn the mask of goodness. For curiosity's sake he had tried the denial of self. He recognized that now. But this murder--was it to dog him all his life? Was he always to be burdened by his past? Was he really to confess? Never. There was only one bit of evidence left against him. The picture itself-- that was evidence. He would destroy it. Why had he kept it so long? Once it had given him pleasure to watch it changing and growing old. Of late he had felt no such pleasure. It had kept him awake at night. When he had been away, he had been filled with terror lest other eyes should look upon it. It had brought melancholy across his passions. Its mere memory had marred many moments of joy. It had been like conscience to him. Yes, it had been conscience. He would destroy it. He looked round and saw the knife that had stabbed Basil Hallward. He had cleaned it many times, till there was no stain left upon it. It was bright, and glistened. As it had killed the painter, so it would kill the painter's work, and all that that meant. It would kill the past, and when that was dead, he would be free. It would kill this monstrous soul-life, and without its hideous warnings, he would be at peace. He seized the thing, and stabbed the picture with it. There was a cry heard, and a crash. The cry was so horrible in its agony that the frightened servants woke and crept out of their rooms. Two gentlemen, who were passing in the square below, stopped and looked up at the great house. They walked on till they met a policeman and brought him back. The man rang the bell several times, but there was no answer. Except for a light in one of the top windows, the house was all dark. After a time, he went away and stood in an adjoining portico and watched. "Whose house is that, Constable?" asked the elder of the two gentlemen. "Mr. Dorian Gray's, sir," answered the policeman. They looked at each other, as they walked away, and sneered. One of them was Sir Henry Ashton's uncle. Inside, in the servants' part of the house, the half-clad domestics were talking in low whispers to each other. Old Mrs. Leaf was crying and wringing her hands. Francis was as pale as death. After about a quarter of an hour, he got the coachman and one of the footmen and crept upstairs. They knocked, but there was no reply. They called out. Everything was still. Finally, after vainly trying to force the door, they got on the roof and dropped down on to the balcony. The windows yielded easily--their bolts were old. When they entered, they found hanging upon the wall a splendid portrait of their master as they had last seen him, in all the wonder of his exquisite youth and beauty. Lying on the floor was a dead man, in evening dress, with a knife in his heart. He was withered, wrinkled, and loathsome of visage. It was not till they had examined the rings that they recognized who it was. End of the Project Gutenberg Etext of Dorian Gray �������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/presage.png�����������������������������������������������������������������0000644�0001750�0001750�00000002415�11737142176�014257� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���]���7���nFÿ���sBIT|dˆ��� pHYs��‚��‚ƒýz���tEXtSoftware�www.inkscape.org›î<��ŠIDATxœíœmh[UÆwM›eiÓõÅÖtØ­N­Re*U;&FdNq2k@½Á*D :Dî‡1Á~0 :½LP±Å®›¸1_ -Š¢ŽvU««tí°µo«mÓŽ¢¡k“%é=÷Ül½?ɇ›çùçÉÉɹçÜ{4!—¡pÄ<�Ô•@ÅÏ•@10 ,yt§LCŸs¢ædhÙz()¶kW 3´Í@›ièãò*\Yz(¹ 8�M¢ôð!ðŠièg%êf„&„xð9UÀb·ttµ}uúàI䆽”Yà-à5ÓЇmôIˆ&„8”«6NÄ«M­ó]½ƒ…–ÀëÀ¦¡/¨2]£Ê(¨  @¬; GŠT™Æ?äÝòAK§*ß8›¯»šÝ»¶*÷]Âý@g(Ùaú»Íâ¡ÏDçRÿÇ^Z\ Ü3 Õ@G(i0 ý˜FYÕ½d…Àg¡p$h§‰úrr€#¡pd³]nè‰Y´„‘õvˆ»¡'çzb->G¶°ú¥ /ÊuCOÍ^ÙÝŒzjŠ=2ãÓ�ÿLG”©k½¹”—�hlj¥»wPy i0 T›†~N†XüäÈïóâ÷yeh^‰ø€ýÀnbšâb?!éÌDç|¿÷ß™îñ‡›Ûé±£L¥¦¡O[ò�Y¯'1Ïì{÷e íгœuÄF3ŸZ²{Vï›õÓ&×c}¸³FÛ Xž—Ñ„O[®&C#þýA2XŒèü颳óÒk)-Êçоéº+żc‡ðUÅ<×poFïéê$:«~¥Õ‹ŽócO?}çþVî{ãÆ ª7”‹B?Ùq†£_þ¬¼˜º[«x<¸E™ßw§Ïr¢ÝöuŠe4<tÇòÐ'§¢Ž,bŒOZ]v¸Ó�à†î�nèà†î�nèà†î�«îä¨fS¥”y˜L©º¦4þ:úÖ-›¸ic…òbùj¯]­«­¢®¶J©çRâ¡ú)*ô;Y˪ABœ²Cxn~!÷·¾¿îÎäê÷7ß?Éøùg¨š¦È_ÉýËtÆö?¿ý–²’€¥©PpŸåjëÉ¡±©õà;ô3A!ëËl.+ ô[±{ôÒl³¾j,¯A¬¥KJÄÛOåw÷žOûøÈG_319cW9V™ŽËò`ã’šßçåö›7¤}ü{Íív•"SÆ¢4\4µ;ãH+óûò(,X§Ü7C¦‰]‚!…E‹=9ú­,Ý´Ùv× <»³^¹o†’u¡¸Ó�é0Bìf0i¸¡§æ€ièc2ÝÐ/Íqà lQ7ôäü4Øq©zbÆ€²»•ÿqC_αÞc—úÅŒÛMC—r晌ø8ݛ硰@ý¾ >ožrÏ$üJ¬KQwÇt°¾†`}Ý~ÙÊÀ.ÓÐGU˜eU÷¢ÅöcQɰxPUàké/©2Kŵ•Å'†F'÷° ö{Qí™’Õ°³‘SÞ)q÷ðr˜+i·º˜ÖU¾ sG����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/abbreviations_en.txt��������������������������������������������������������0000644�0001750�0001750�00000000206�11737142176�016172� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������2 to 4 for 2moro tomorrow u you w8 wait b4 before c see r are afaik as far as I know asap as soon as possible ianal I am not a lawyer ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/presage.xpm�����������������������������������������������������������������0000644�0001750�0001750�00000007747�11737142176�014314� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static char * presage_xpm[] = { "32 32 115 2", " c None", ". c #58729A", "+ c #58729B", "@ c #59729B", "# c #59739A", "$ c #577199", "% c #59739B", "& c #58739A", "* c #E3E8EE", "= c #CAD3DF", "- c #D8DEE8", "; c #B8C4D5", "> c #5B759C", ", c #ADB9CD", "' c #61799F", ") c #60799F", "! c #90A1BC", "~ c #B3BFD1", "{ c #A9B6CB", "] c #8A9CB8", "^ c #58739B", "/ c #C4CDDB", "( c #8E9FBA", "_ c #8D9FBA", ": c #B0BDCF", "< c #B4C0D2", "[ c #577299", "} c #FAFAFB", "| c #F5F6F9", "1 c #EBEFF3", "2 c #D2D9E3", "3 c #D1D9E3", "4 c #D3DAE4", "5 c #A3B2C7", "6 c #8E9FB9", "7 c #778CAD", "8 c #6B82A5", "9 c #7288AA", "0 c #7E92B1", "a c #7E93B1", "b c #A2B0C6", "c c #F7F9FA", "d c #F3F4F7", "e c #DDE3EA", "f c #D3D9E4", "g c #D4DBE5", "h c #A0AFC5", "i c #5A749B", "j c #5C759C", "k c #BAC4D5", "l c #DEE3EA", "m c #D8DEE7", "n c #DCE2EA", "o c #E1E6EC", "p c #F0F3F6", "q c #BDC7D7", "r c #899BB7", "s c #889AB7", "t c #B1BDD0", "u c #B0BCCF", "v c #B8C3D4", "w c #96A6BF", "x c #6F85A8", "y c #7187A9", "z c #B9C4D5", "A c #A3B1C7", "B c #AFBBCE", "C c #8397B4", "D c #5A749C", "E c #AFBBCF", "F c #A2B1C7", "G c #A8B5CA", "H c #627AA0", "I c #617AA0", "J c #97A7C0", "K c #B9C4D4", "L c #9AAAC2", "M c #768BAC", "N c #778DAD", "O c #BCC6D7", "P c #E3E7ED", "Q c #CED5E1", "R c #CBD2DF", "S c #C9D1DE", "T c #D7DDE7", "U c #B5C0D2", "V c #DAE0E9", "W c #D7DDE6", "X c #E5EAF0", "Y c #F3F4F8", "Z c #C0CAD8", "` c #7D92B0", " . c #6B82A6", ".. c #7389AA", "+. c #889AB5", "@. c #FFFFFF", "#. c #FDFFFF", "$. c #D6DDE6", "%. c #AEBBCE", "&. c #889BB7", "*. c #D9DEE7", "=. c #BBC5D5", "-. c #BAC5D5", ";. c #CED6E1", ">. c #A4B2C8", ",. c #92A3BD", "'. c #59729A", "). c #C8D1DE", "!. c #9DACC3", "~. c #BEC8D7", "{. c #FDFDFD", "]. c #FBFBFD", "^. c #FBFDFD", "/. c #A6B5C9", "(. c #58719A", " ", " ", " ", " ", " ", " . + @ # $ ", " . . % % % % % & & ", " * = = = = = = = = = - ; > % % % % % % % % . ", " , ' ) ) ) ) ) ) ) ) ! ~ > % % % % % % % % % @ ", " { % % % % % % % % % ] ~ > % % % % % % % % % % ^ ", " { % % % % % % % % % ] ~ > % % % % % % % % % % @ ", " / ( _ _ _ _ _ _ _ _ : < > % % % % % % % % % % % [ ", " } | | | | | | 1 2 3 4 5 > % % % % % % % % % % % . ", " 6 7 7 7 8 % % % % % % % 9 0 0 0 0 a b ", " c d d d d d d e f f g h i % % % % % j k l m m m m n o o o o p ", " q r s s s s s s s s t u i % % % % % j v w x x x x x x x x y z ", " A % % % % % % % % % ! B i % % % % % j v C % % % % % % % % D E ", " F % % % % % % % % % ! B i % % % % % j v C % % % % % % % % D E ", " G H I I I I I I I I J B i % % % % % j K L M M M M M M M M N O ", " P Q Q Q Q Q Q R S S T u i % % % % % j U V W W W W l X X X X Y ", " Z L L L ` % % % % % % % ...........+. ", " @.#.#.#.#.#.#.$.u %.%.&.% % % % % % % % % % % % % ", " *.=.=.=.=.=.=.-.v v ;.t i % % % % % % % % % % % . ", " >.j > > > > > > > > ,.B i % % % % % % % % % % '. ", " F % % % % % % % % % ! B i % % % % % % % % % % . ", " A % % % % % % % % % ! B i % % % % % % % % % . ", " ).!.!.!.!.!.!.!.!.!.~.: i % % % % % % % % . ", " {.].].].].].].].].].^./.@ . % % % % % '.& ", " . ^ . . + . (. ", " ", " ", " "}; �������������������������presage-0.8.8/resources/Makefile.am�����������������������������������������������������������������0000644�0001750�0001750�00000004405�11737142176�014160� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = arpa profiles EXTRA_DIST = \ the_picture_of_dorian_gray.txt \ l_innocente.txt \ el_quijote.txt \ abbreviations_en.txt \ abbreviations_it.txt \ presage.svg dist_pkgdata_DATA = \ presage.png \ presage.xpm \ presage.svg \ abbreviations_en.txt \ abbreviations_it.txt if USE_SQLITE BUILT_SOURCES = database_en.db \ database_it.db \ database_es.db database_it.db: l_innocente.txt @rm -f $@ @$(top_builddir)/src/tools/text2ngram -n 1 -l -f sqlite -o $@ $^ @$(top_builddir)/src/tools/text2ngram -n 2 -l -f sqlite -o $@ $^ @$(top_builddir)/src/tools/text2ngram -n 3 -l -f sqlite -o $@ $^ database_en.db: the_picture_of_dorian_gray.txt @rm -f $@ @$(top_builddir)/src/tools/text2ngram -n 1 -l -f sqlite -o $@ $^ @$(top_builddir)/src/tools/text2ngram -n 2 -l -f sqlite -o $@ $^ @$(top_builddir)/src/tools/text2ngram -n 3 -l -f sqlite -o $@ $^ database_es.db: el_quijote.txt @rm -f $@ @$(top_builddir)/src/tools/text2ngram -n 1 -l -f sqlite -o $@ $^ @$(top_builddir)/src/tools/text2ngram -n 2 -l -f sqlite -o $@ $^ @$(top_builddir)/src/tools/text2ngram -n 3 -l -f sqlite -o $@ $^ # Clean out files created during tests. # Required to make distcheck happy. DISTCLEANFILES = database_en.db \ database_it.db \ database_es.db pkgdata_DATA = database_en.db \ database_it.db \ database_es.db endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/abbreviations_it.txt��������������������������������������������������������0000644�0001750�0001750�00000000104�11737142176�016201� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������6 sei c ci t ti nn non tvb ti voglio bene tvtb ti voglio tanto bene ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/l_innocente.txt�������������������������������������������������������������0000644�0001750�0001750�00001771272�11737142176�015200� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������The Project Gutenberg EBook of L'Innocente, by Gabriele d'Annunzio This eBook is for the use of anyone anywhere at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.org Title: L'Innocente Author: Gabriele d'Annunzio Release Date: September 16, 2007 [EBook #22642] Language: Italian Character set encoding: ISO-8859-1 *** START OF THIS PROJECT GUTENBERG EBOOK L'INNOCENTE *** Produced by Mark C. Orton and the Online Distributed Proofreading Team at http://www.pgdp.net [Copertina] Gabriele d'Annunzio I ROMANZI DELLA ROSA L'INNOCENTE _Nono migliaio._ MILANO--FRATELLI TREVES, EDITORI--MILANO Via Palermo, 2, e Galleria Vittorio Emanuele, 64 e 66. ROMA: Corso, 383.--NAPOLI; Via Roma (già Toledo), 34. BOLOGNA: presso la Libreria Treves, di L. Beltrami, angolo Via Farini. TRIESTE: presso Giuseppe Schubart. LIPSIA, VIENNA e BERLINO: presso A. F. Brockhaus. PARIGI: presso J. Boyveau et Chevillet, 22, rue de la Banque. [Occhiello] L'INNOCENTE. [Retro] _OPERE di GABRIELE D'ANNUNZIO_ I ROMANZI DELLA ROSA: =Il Piacere= L. 5-- =L'Innocente= 4 -- =Trionfo della Morte= 5 -- I ROMANZI DEL GIGLIO: I. =Le Vergini delle Rocce= 5 -- II. =La Grazia= *. III. =L'Annunziazione= *. I ROMANZI DEL MELAGRANO: =Il Fuoco= _(di prossima pubblicazione)_. =Il Dittatore= *. =Trionfo della Vita= *. POESIE: =Canto novo; Intermezzo= 4 -- =L'Isottéo=; =la Chimera= 4 -- Poema paradisiaco; Odi navali 4 -- * Laudi del Cielo, del Mare, della Terra e degli Eroi. MISTERI: =Persefone= *. =Adone= *. =Orfeo= *. DRAMI: =La Città morta= 4 -- I Sogni delle Stagioni Sogno d'un mattino di primavera 2 -- * Sogno d'un meriggio d'estate. Sogno d'un tramonto d'autunno 2 -- * Sogno d'una notte d'inverno. La Gioconda } } di prossima pubblicazione. La Tragedia della Folla } =Frate Sole= *. [Frontespizio] Gabriele d'Annunzio _I ROMANZI DELLA ROSA_ L'INNOCENTE _Nono migliaio_ MILANO FRATELLI TREVES, EDITORI 1899. [Verso] PROPRIETÀ LETTERARIA _Riservati tutti i diritti._ Tip. Fratelli Treves. ALLA CONTESSA MARIA ANGUISSOLA GRAVINA CRUYLLAS DI RAMACCA QUESTO LIBRO È DEDICATO. _Napoli, 11 marzo 1892._ L'INNOCENTE _Beati immaculati...._ Andare d'avanti al giudice, dirgli: "Ho commesso un delitto. Quella povera creatura non sarebbe morta se io non l'avessi uccisa. Io Tullio Hermil, io stesso l'ho uccisa. Ho premeditato l'assassinio, nella mia casa. L'ho compiuto con una perfetta lucidità di conscienza, esattamente, nella massima sicurezza. Poi ho seguitato a vivere col mio segreto nella mia casa, un anno intero, fino ad oggi. Oggi è l'anniversario. Eccomi nelle vostre mani. Ascoltatemi. Giudicatemi." Posso andare d'avanti al giudice, posso parlargli così? Non posso né voglio. La giustizia degli uomini non mi tocca. Nessun tribunale della terra saprebbe giudicarmi. E pure bisogna che io mi accusi, che io mi confessi. Bisogna che io riveli il mio segreto a qualcuno. A CHI? I. Il primo ricordo è questo. Era di aprile. Eravamo in provincia, da alcuni giorni, io e Giuliana e le nostre due bambine Maria e Natalia, per le feste di Pasqua, in casa di mia madre, in una grande e vecchia casa di campagna, detta La Badiola. Correva il settimo anno dal matrimonio. Ed erano già corsi tre anni da un'altra Pasqua che veramente m'era parsa una festa di perdono, di pace e d'amore, in quella villa bianca e solinga come un monasterio, profumata di violacciocche; quando Natalia, la seconda delle mie figliuole tentava i primi passi, uscita allora allora dalle fasce come un fiore dall'invoglio, e Giuliana si mostrava per me piena d'indulgenza, se bene con un sorriso un po' malinconico. Io era tornato a lei, pentito e sommesso, dopo la prima grave infedeltà. Mia madre, inconsapevole, con le sue care mani aveva posto un ramoscello d'olivo a capo del nostro letto e aveva riempita la piccola acquasantiera d'argento che pendeva dalla parete. Ma ora, in tre anni, quante cose mutate! Tra me e Giuliana era avvenuto un distacco definitivo, irreparabile. I miei torti verso di lei s'erano andati accumulando. Io l'aveva offesa nei modi più crudeli, senza riguardo, senza ritegno, trascinato dalla mia avidità di piacere, dalla rapidità delle mie passioni, dalla curiosità del mio spirito corrotto. Ero stato l'amante di due tra le sue amiche intime. Avevo passato alcune settimane a Firenze con Teresa Raffo, imprudentemente. Avevo avuto col falso conte Raffo un duello in cui il mio disgraziato avversario s'era coperto di ridicolo, per talune circostanze bizzarre. E nessuna di queste cose era rimasta ignota a Giuliana. Ed ella aveva sofferto, ma con molta fierezza, quasi in silenzio. C'erano stati pochissimi dialoghi tra noi, e brevi, in proposito; nei quali io non avevo mai mentito, credendo con la mia sincerità diminuire la mia colpa agli occhi di quella dolce e nobile donna che io sapevo intellettuale. Anche sapevo che ella riconosceva la superiorità della mia intelligenza e che scusava in parte i disordini della mia vita con le teorie speciose da me esposte più d'una volta in presenza di lei a danno delle dottrine morali professate apparentemente dalla maggioranza degli uomini. La certezza di non essere giudicato da lei come un uomo comune alleggeriva nella mia conscienza il peso dei miei errori. "Anch'ella dunque--io pensavo--comprende che, essendo io diverso dagli altri ed avendo un diverso concetto della vita, posso giustamente sottrarmi ai doveri che gli altri vorrebbero impormi, posso giustamente disprezzare l'opinione altrui e vivere nella assoluta sincerità della mia natura eletta." Io era convinto di essere non pure uno spirito eletto ma uno spirito _raro_; e credevo che la _rarità_ delle mie sensazioni e dei miei sentimenti nobilitasse, _distinguesse_ qualunque mio atto. Orgoglioso e curioso di questa mia rarità, io non sapevo concepire un sacrificio, un'abnegazione di me stesso, come non sapevo rinunciare a un'espressione, a una manifestazione del mio desiderio. Ma in fondo a tutte queste mie sottigliezze non c'era se non un terribile egoismo; poiché, trascurando gli obblighi, io accettavo i benefizi del mio stato. A poco a poco, in fatti, di abuso in abuso, io era giunto a riconquistare la mia primitiva libertà col consenso di Giuliana, senza ipocrisie, senza sotterfugi, senza menzogne degradanti. Io mettevo il mio studio nell'esser leale, a qualunque costo, come altri nel fingere. Cercavo di confermare in tutte le occasioni, tra me e Giuliana, il nuovo patto di fraternità, di amicizia pura. Ella doveva essere la mia sorella, la mia migliore amica. Una mia sorella, l'unica, Costanza, era morta a nove anni lasciandomi in cuore un rimpianto senza fine. Io pensavo spesso, con una profonda malinconia, a quella piccola anima che non aveva potuto offrirmi il tesoro della sua tenerezza, un tesoro da me sognato inesauribile. Fra tutti gli affetti umani, fra tutti gli amori della terra, quello _sororale_ m'era sempre parso il più alto e il più consolante. Io pensavo spesso alla grande consolazione perduta, con un dolore che la irrevocabilità della morte rendeva quasi mistico. Dove trovare, su la terra, un'altra sorella? Spontaneamente, questa aspirazione sentimentale si volse verso Giuliana. Sdegnosa di mescolanze, ella aveva già rinunziato ad ogni carezza, a qualunque abbandono. Io già da tempo non provavo più né pur l'ombra d'un turbamento sensuale, standole accanto; sentendo il suo alito, aspirando il suo profumo, guardando il piccolo segno bruno ch'ella aveva sul collo, io rimanevo nella più pura frigidità. Non mi pareva possibile che quella fosse la donna medesima che un giorno io aveva veduto impallidire e mancare sotto la violenza del mio ardore. Io le offersi dunque la mia fraternità; ed ella accettò, semplicemente. Se ella era triste, io era più triste ancora, pensando che noi avevamo sepolto il nostro amore per sempre, senza speranza di resurrezione; pensando che le nostre labbra non si sarebbero forse unite mai più, mai più. E, nella cecità del mio egoismo, mi parve che ella dovesse in cuor suo essermi grata di quella mia tristezza che io già sentivo immedicabile, e mi parve che ella dovesse anche esserne paga e consolarsene come d'un riflesso del lontano amore. Ambedue un tempo avevamo sognato non pur l'amore ma la passione fino alla morte, _usque ad mortem_. Ambedue avevamo creduto al nostro sogno e avevamo proferito più d'una volta, nell'ebrezza, le due grandi parole illusorie: _Sempre! Mai!_ Avevamo perfino creduto all'affinità della nostra carne, a quell'affinità rarissima e misteriosa che lega due creature umane col tremendo legame del desiderio insaziabile; ci avevamo creduto perchè l'acutezza delle nostre sensazioni non era diminuita nè pure dopo che, avendo noi procreato un nuovo essere, l'oscuro Genio della specie aveva raggiunto per mezzo di noi il suo unico intento. L'illusione era caduta; ogni fiamma era spenta. La mia anima (lo giuro) aveva pianto sinceramente su la ruina. Ma come opporsi a un fenomeno necessario? Come evitare l'inevitabile? Era dunque gran ventura che, morto l'amore per le necessità fatali dei fenomeni e quindi senza colpa di alcuno, noi potessimo ancora vivere nella stessa casa tenuti da un sentimento nuovo, forse non meno profondo dell'antico, certo più elevato e più singolare. Era gran ventura che una nuova illusione potesse succedere all'antica e stabilire tra le nostre anime uno scambio di affetti puri, di commozioni delicate, di squisite tristezze. Ma, in realtà, questa specie di retorica platonica a qual fine tendeva? Ad ottenere che una vittima si lasciasse sacrificare sorridendo. In realtà, la nuova vita, non più conjugale ma fraterna, si basava tutta su un presupposto: su l'assoluta abnegazione della _sorella_. Io riconquistavo la mia libertà, potevo andare in cerca delle sensazioni acute di cui avevano bisogno i miei nervi, potevo appassionarmi per un'altra donna, vivere fuori della mia casa e trovare _la sorella_ ad aspettarmi, trovare nelle mie stanze la traccia visibile delle sue cure, trovare sul mio tavolo in una coppa le rose disposte dalle sue mani, trovare da per tutto l'ordine e l'eleganza e il nitore come in un luogo abitato da una Grazia. Questa mia condizione non era invidiabile? E non era straordinariamente preziosa la donna che consentiva a sacrificarmi la sua giovinezza, paga soltanto di essere baciata con gratitudine e quasi con religione su la fronte altera e dolce? La mia gratitudine talvolta diveniva così calda che si espandeva in una infinità di delicatezze, di premure affettuose. Io sapevo essere il migliore dei fratelli. Quando ero assente, scrivevo a Giuliana lunghe lettere malinconiche e tenere che spesso partivano insieme con quelle dirette alla mia amante; e la mia amante non avrebbe potuto esserne gelosa, allo stesso modo che non poteva esser gelosa della mia adorazione per la memoria di Costanza. Ma, se bene assorto nell'intensità della mia vita particolare, io non sfuggivo alle interrogazioni che di tratto in tratto mi sorgevano dentro. Perchè Giuliana persistesse in quella meravigliosa forza di sacrificio, bisognava ch'ella mi amasse d'un sovrano amore; e, amandomi e non potendo essere se non la mia _sorella_, doveva portar chiusa in sè una disperazione mortale.--Non era dunque un forsennato l'uomo che immolava, senza rimorso, ad altri amori torbidi e vani quella creatura così dolorosamente sorridente, così semplice, così coraggiosa?--Mi ricordo (e la perversione mia di quel tempo mi stupisce), mi ricordo che tra le ragioni che io dissi a me stesso per acquietarmi, questa fu la più forte: "La grandezza morale risultando dalla violenza dei dolori superati, perchè ella avesse occasione d'essere eroica era necessario ch'ella soffrisse quel ch'io le ho fatto soffrire." Ma un giorno io m'avvidi ch'ella soffriva anche nella sua salute; m'avvidi che il suo pallore diveniva più cupo e talvolta si empiva come di ombre livide. Più d'una volta sorpresi nella sua faccia le contrazioni d'uno spasimo represso; più d'una volta ella fu assalita, in mia presenza, da un tremito infrenabile che la scoteva tutta e le faceva battere i denti come nel ribrezzo di una febbre subitanea. Una sera, da una stanza lontana mi giunse un grido di lei, lacerante; e io corsi, e la trovai in piedi, addossata a un armario, convulsa, che si torceva come se avesse inghiottito un veleno. Mi afferrò una mano e me la tenne stretta come in una morsa. --Tullio, Tullio, che cosa orribile! Ah, che cosa orribile! Ella mi guardava, da presso; teneva fissi nei miei occhi i suoi occhi dilatati, che mi parvero nella penombra straordinariamente larghi. E io vedevo in quei larghi occhi passare, come a onde, la sofferenza sconosciuta; e quello sguardo continuo, intollerabile, mi suscitò d'un tratto un terrore folle. Era di sera, era il crepuscolo, e la finestra era spalancata, e le tende si gonfiavano sbattendo, e una candela ardeva su un tavolo, contro uno specchio; e, non so perchè, lo sbattito delle tende, l'agitazione disperata di quella fiammella, che lo specchio pallido rifletteva, presero nel mio spirito un significato sinistro, aumentarono il mio terrore. Il pensiero del veleno mi balenò; e in quell'attimo ella non potè frenare un altro grido; e, fuori di sè per lo spasimo, si gittò sul mio petto perdutamente. --Oh Tullio, Tullio, aiutami! aiutami! Agghiacciato dal terrore io rimasi un minuto senza poter proferire una parola, senza poter muovere le braccia. --Che hai fatto? Che hai fatto? Giuliana! Parla, parla.... Che hai fatto? Sorpresa dalla profonda alterazione della mia voce, ella si ritrasse un poco e mi guardò. Io dovevo avere la faccia più bianca e più sconvolta della sua, perchè ella mi disse rapidamente, smarritamente: --Nulla, nulla. Tullio, non ti spaventare. Non è nulla, vedi.... Sono i miei soliti dolori.... Sai, è è una delle solite crisi.... che passano. Càlmati. Ma io, invasato dal terribile sospetto, dubitai delle sue parole. Mi pareva che tutte le cose intorno a me rivelassero l'avvenimento tragico e che una voce interna mi accertasse: "_Per te, per te ha voluto morire. Tu, tu l'hai spinta a morire._" E io le presi le mani e sentii che erano fredde, e vidi scendere dalla sua fronte una goccia di sudore.... --No, no, tu m'inganni--proruppi--tu m'inganni. Per pietà, Giuliana, anima mia, parla, parla! Dimmi: che hai.... Dimmi, per pietà: che hai.... _bevuto_? E i miei occhi esterrefatti cercarono in torno, su i mobili, sul tappeto, dovunque, un indizio. Allora ella comprese. Si lasciò cadere di nuovo sul mio petto e disse, rabbrividendo e facendomi rabbrividire, disse con la bocca contro la mia spalla (mai, mai dimenticherò l'accento indefinibile), disse: --No, no, no, Tullio; no. Ah, che cosa nell'universo può uguagliare l'accelerazione vertiginosa della nostra vita interiore? Noi rimanemmo in quell'atto, nel mezzo della stanza, muti; e un mondo inconcepibilmente vasto di sentimenti e di pensieri si agitò dentro di me, in un sol punto, con una lucidità spaventevole. "_E se fosse stato vero?_" chiedeva la voce. "_Se fosse stato vero?_" Un sussulto incessante scoteva Giuliana, contro il mio petto; ed ella ancora teneva celata la faccia; ed io sapeva che ella, pur soffrendo ancora nella sua povera carne, non ad altro pensava che alla _possibilità_ del fatto da me sospettato, non ad altro pensava che al mio folle terrore. Una domanda mi salì alle labbra: "Hai tu mai avuta _la tentazione?_" E poi un'altra: "Potrebbe essere che tu cedessi _alla tentazione?_" Nè l'una nè l'altra proferii; e pure mi parve ch'ella intendesse. Ambedue oramai eravamo dominati da quel pensiero di morte, da quell'imagine di morte; ambedue eravamo entrati in una specie di esaltazione tragica, dimenticando l'equivoco che l'aveva generata, smarrendo la conscienza della realtà. Ed ella a un tratto si mise a singhiozzare; e il suo pianto chiamò il mio pianto; e mescolammo le nostre lacrime, ahi me!, che erano così calde e che non potevano mutare il nostro destino. Seppi, dopo, che già da alcuni mesi la travagliavano malattie complicate della matrice e dell'ovaia, quelle terribili malattie nascoste che turbano in una donna tutte le funzioni della vita. Il dottore, col quale volli avere un colloquio, mi fece intendere che per un lungo periodo io doveva rinunziare a qualunque contatto con la malata, anche alla più lieve delle carezze; e mi dichiarò che un nuovo parto avrebbe potuto esserle fatale. Queste cose, pure affliggendomi, mi alleggerirono di due inquietudini: mi persuasero che io non avevo colpa nello sfiorire di Giuliana e mi diedero un modo semplice di poter giustificare d'avanti a mia madre la separazione di letto e gli altri mutamenti avvenuti nella mia vita domestica. Mia madre a punto era per arrivare a Roma dalla provincia, dove ella, dopo la morte di mio padre, passava la maggior parte dell'anno con mio fratello Federico. Mia madre amava molto la giovine nuora. Giuliana era veramente per lei la sposa ideale, la compagna _sognata_ pel suo figliuolo. Ella non riconosceva al mondo una donna più bella, più dolce, più nobile di Giuliana. Ella non concepiva che io potessi desiderare altre donne, abbandonarmi in altre braccia, dormire su altri cuori. Essendo stata amata per venti anni da un uomo, sempre con la stessa devozione, con la stessa fede, _sino alla morte_, ella ignorava la stanchezza, il disgusto, il tradimento, tutte le miserie e tutte le ignominie che si covano nel talamo. Ella ignorava lo strazio che io avevo fatto e facevo di quella cara anima immeritevole. Ingannata dalla dissimulazione generosa di Giuliana, credeva ancora nella nostra felicità. Guai s'ella avesse saputo! Io era ancora in quell'epoca sotto il dominio di Teresa Raffo, della violenta avvelenatrice che mi dava imagine dell'amasia di Menippo. Ricordate? Ricordate le parole di Apollonio a Menippo nel poema inebriante? "_O beau jeune homme, tu caresses un serpent; un serpent te caresse!_" Il caso mi favorì. Per la morte d'una zia, Teresa fu costretta ad allontanarsi da Roma e a rimanere assente qualche tempo. Io potei con una insolita assiduità presso mia moglie riempire il gran vuoto che la "Biondissima" partendo lasciava nelle mie giornate. E non era ancora svanito in me il turbamento di quella sera; e qualche cosa di nuovo, indefinibile, da qualche sera ondeggiava tra me e Giuliana. Poiché le sofferenze fisiche di lei aumentavano, io e mia madre potemmo con molta fatica ottenere che ella si sottoponesse all'operazione chirurgica richiesta dal suo stato. L'operazione portava per séguito trenta o quaranta giorni di assoluto riposo nel letto e una convalescenza prudente. Già la povera malata aveva i nervi estremamente indeboliti ed irritabili. I preparativi lunghi e fastidiosi la estenuarono e la esasperarono al punto che ella più d'una volta tentò di gittarsi giù dal letto, di ribellarsi, di sottrarsi a quel supplizio brutale che la violava, che l'umiliava, che l'avviliva.... --Di'--mi chiese un giorno, con la bocca amara--se tu ci pensi, non hai ribrezzo di me? Ah, che brutta cosa! E fece un atto di disgusto su sé medesima; e s'accigliò, e si ammutolì. Un altro giorno, mentre io entravo nella sua stanza, ella si accorse che un odore mi aveva ferito. Gridò, fuori di sé, pallida come la sua camicia: --Vattene, vattene, Tullio. Ti prego! Parti. Ritornerai quando sarò guarita. Se tu rimarrai qui, mi prenderai in odio. Sono odiosa così; sono odiosa.... Non mi guardare. E i singhiozzi la soffocarono. Poi, in quello stesso giorno, dopo qualche ora, mentre io tacevo credendo ch'ella fosse per assopirsi, uscì in queste parole oscure, con l'accento strano di chi parla in sogno: --_Ah, se davvero l'avessi fatto! Era un buon suggerimento_.... --Che dici, Giuliana? Ella non rispose. --A che pensi, Giuliana? Non rispose se non con un atto della bocca, che voleva essere un sorriso e non poté. Mi parve di comprendere. E un'onda tumultuosa di rammarico, di tenerezza e di pietà mi assalse. E tutto avrei dato perché ella avesse potuto leggermi l'anima, in quel momento, perché ella avesse potuto raccogliere intera la mia commozione irrivelabile, inesprimibile e quindi vana. "Perdonami, perdonami. Dimmi quello che io debbo fare perché tu mi perdoni, perché tu dimentichi tutte le cattive cose.... Io tornerò a te, non sarò d'altri che di te, per sempre. Te sola veramente io ho amata, nella vita; amo te sola. Sempre la mia anima si volge a te, e ti cerca, e ti rimpiange. Te lo giuro: lontano da te, non ho provato mai nessuna gioia sincera, non ho avuto mai un attimo di pieno oblio; mai, mai: te lo giuro. Tu sola, al mondo, hai la bontà e la dolcezza. Tu sei la più buona e la più dolce creatura che io abbia mai sognata: sei l'Unica. E ho potuto offenderti, ho potuto farti soffrire, ho potuto farti pensare alla morte come a una cosa desiderabile! Ah, tu mi perdonerai, ma io non potrò mai perdonarmi; tu dimenticherai, ma io non dimenticherò. Sempre mi parrà d'essere indegno; né pure con la devozione di tutta la mia vita mi parrà di averti compensata. Da ora innanzi, come un tempo, tu sarai la mia amante, la mia amica, la mia sorella; come un tempo, tu sarai la mia custode, la mia consigliera. Io ti dirò tutto, ti svelerò tutto. Sarai la mia anima. E guarirai. Io, io ti guarirò. Tu vedrai di quali tenerezze io sarò capace per medicarti.... Ah, tu le conosci. Ricòrdati! Ricòrdati! Anche allora tu fosti malata e me solo volesti per medicarti; e io non mi mossi mai dal tuo capezzale, né di giorno, né di notte. E tu dicevi:--Sempre Giuliana _se ne ricorderà_, sempre.--E tu avevi le lacrime negli occhi, e io te le bevevo tremando.--Santa! Santa!--Ricordati. E quando ti leverai, quando sarai convalescente, andremo laggiù, torneremo a Villalilla. Tu sarai ancora un poco debole, ma ti sentirai tanto bene. E io ritroverò la mia gaiezza d'una volta, e ti farò sorridere, ti farò ridere. Tu ritroverai quelle tue belle risa che mi rinfrescavano il cuore; tu ritroverai quelle tue arie di fanciulla deliziose, e porterai ancora la treccia giù per le spalle come mi piaceva. Siamo giovani. Riconquisteremo la felicità, se tu vorrai. Vivremo, vivremo...." Così, dentro di me, le parlavo; e le parole non uscivano dalle mie labbra. Pur essendo commosso e avendo gli occhi umidi, io sapevo che la commozione era passeggera e che quelle promesse erano fallaci. E anche sapevo che Giuliana non si sarebbe illusa e che mi avrebbe risposto con quel suo tenue sorriso sfiduciato, già altre volte comparsole su le labbra. Quel sorriso significava: "Sì, io so che tu sei buono e che vorresti non farmi soffrire; ma tu non sei padrone di te, non puoi resistere alle fatalità che ti trascinano. Perché vuoi tu che io m'illuda?" Tacqui, in quel giorno; e nei giorni che seguirono, pur ricadendo più volte nella stessa confusa agitazione di ravvedimenti e di propositi e di sogni vaghi, non osai parlare: "Per tornare a lei, tu devi abbandonare le cose in cui ti compiaci, la donna che ti corrompe. Ne avrai la forza?" Io rispondevo a me stesso: "Chi sa!" E aspettavo di giorno in giorno questa forza che non veniva; aspettavo di giorno in giorno un evento (non sapevo quale) che provocasse la mia risoluzione, che me la rendesse inevitabile. E m'indugiavo a imaginare, a sognare la nostra vita nuova, la lenta rifioritura del nostro amore legittimo, il sapore strano di certe sensazioni rinnovate. "Noi andremmo dunque laggiù, a Villalilla, nella casa che conserva le nostre più belle memorie; e saremmo noi due soltanto, perchè lasceremmo Maria e Natalia con mia madre alla Badiola. E la stagione sarebbe mite; e la convalescente si appoggerebbe sempre al mio braccio, pei sentieri conosciuti, dove ogni nostro passo risveglierebbe una memoria. Ed io vedrei di tratto in tratto sul suo pallore diffondersi qualche lieve fiamma subitanea; ed ambedue saremmo, l'uno verso l'altra, un poco timidi; sembreremmo qualche volta pensierosi; eviteremmo qualche volta di guardarci negli occhi. Perchè? E un giorno, sentendo più forte la suggestione dei luoghi, io ardirei parlarle delle nostre più folli ebrezze di quei primi tempi.--Ti ricordi? Ti ricordi? Ti ricordi?--E a poco a poco ambedue sentiremmo in noi il turbamento crescere, divenire insostenibile; e ambedue, nel tempo medesimo, perdutamente, ci stringeremmo, ci baceremmo in bocca, crederemmo venir meno. Ella, ella sì verrebbe meno; e io la sosterrei nelle mie braccia chiamandola con nomi suggeriti da una tenerezza suprema. Ella riaprirebbe gli occhi, leverebbe tutto il velo del suo sguardo, fisserebbe un istante su me la sua stessa anima; mi parrebbe trasfigurata. E così saremmo ripresi dall'antico ardore, rientreremmo nella grande illusione. Ambedue saremmo tenuti da un pensiero unico, assiduo; saremmo agitati da un'ansietà inconfessabile. Io le chiederei tremando:--_Sei guarita?_--Ed ella dal suono della mia voce comprenderebbe la domanda celata in quella domanda. E risponderebbe, senza potermi nascondere il brivido:--_Non ancora!-_-E la sera, dividendoci, rientrando nelle nostre stanze separate, ci sentiremmo morire d'angoscia. Ma una mattina, con uno sguardo impreveduto, i suoi occhi mi direbbero:--_Oggi, oggi...._--Ed ella, paventando quel divino e terribile momento, con qualche pretesto puerile mi sfuggirebbe, protrarrebbe la nostra tortura. Direbbe ella:--Usciamo; usciamo....--Usciremmo: in un pomeriggio velato, tutto bianco, un poco snervante, un poco soffocante. Cammineremmo a fatica. Comincerebbero a cadere, su le nostre mani, sul nostro viso, gocce di pioggia tiepide come lacrime. Io direi, con la voce alterata:--Rientriamo.--E, presso la soglia, all'improvviso, la prenderei su le mie braccia, la sentirei abbandonarsi come esanime, la porterei su per le scale senza avvertire alcun peso.--Dopo tanto! Dopo tanto!--La violenza del desiderio sarebbe in me attenuata dalla paura di farle male, di strapparle un grido di dolore.--Dopo tanto!--E i nostri esseri, all'urto di una sensazione divina e terribile, non provata né imaginata mai, si struggerebbero. Ed ella, dopo, mi parrebbe quasi morente, con la faccia tutta molle di pianto, pallida come il suo guanciale." Ah, così mi parve, morente mi parve, quella mattina, quando i dottori l'addormentavano col cloroformio ed ella, sentendosi sprofondare nell'insensibilità della morte, due o tre volte tentò di alzare le braccia verso di me, tentò di chiamarmi. Io uscii dalla stanza, sconvolto; e intravidi i ferri chirurgici, una specie di cucchiaio tagliente, e la garza e il cotone e il ghiaccio e le altre cose preparate su un tavolo. Due lunghe ore, interminabili ore, aspettai, esacerbando la mia sofferenza con l'eccesso delle imaginazioni. E una disperata pietà strinse le mie viscere d'uomo, per quella creatura che i ferri del chirurgo violavano non soltanto nella carne miserabile ma nell'intimo dell'anima, nel sentimento più delicato che una donna possa custodire:--una pietà per quella e per le altre, agitate da aspirazioni indefinite verso le idealità dell'amore, illuse dal sogno capzioso di cui il desiderio maschile le avvolge, smanianti d'inalzarsi, e così deboli, così malsane, così imperfette, uguagliate alle femmine brute dalle leggi inabolibili della Natura; che impone a loro il diritto della specie, sforza le loro matrici, le travaglia di morbi orrendi, le lascia esposte a tutte le degenerazioni. E in quella e nelle altre, rabbrividendo per ogni fibra, io vidi allora, con una lucidità spaventevole, vidi la piaga originale, la turpe ferita sempre aperta "che sanguina e che pute".... Quando rientrai nella stanza di Giuliana, ella era ancora sotto l'azione dell'anestetico, senza conoscenza, senza parola: ancora simile a una morente. Mia madre era ancora pallidissima e convulsa. Ma pareva che l'operazione fosse riuscita bene; i dottori parevano soddisfatti. L'odore del jodoformio impregnava l'aria. In un canto, la monaca inglese empiva di ghiaccio una vescica; l'assistente ravvolgeva una fascia. Le cose tornavano nell'ordine e nella calma, a poco a poco. L'inferma rimase a lungo in quel sopore; la febbre comparve leggerissima. Nella notte però ella fu presa da spasimi allo stomaco e da un vomito infrenabile. Il laudano non la calmava. E io, fuori di me, allo spettacolo di quello strazio inumano, credendo ch'ella dovesse morire, non so più che dissi, non so più che feci. Agonizzai con lei. Nel giorno seguente, lo stato dell'inferma migliorò; e poi, di giorno in giorno, andò ancora migliorando. Le forze lentissimamente tornavano. Io fui assiduo al capezzale. Mettevo una certa ostentazione nel ricordare a lei, con i miei atti, l'infermiere d'una volta; ma il sentimento era diverso, era sempre _fraterno_. Spesso io avevo lo spirito preoccupato da qualche frase d'una lettera della amante lontana, mentre leggevo a lei qualche pagina d'un libro preferito. L'Assente era indimenticabile. Talora però, quando nel rispondere a una lettera mi sentivo un po' svogliato e quasi tediato, in certe strane pause che nella lontananza ha anche una passione forte, io credevo questo un indizio di disamore; e ripetevo a me stesso: "Chi sa!" Un giorno, mia madre disse a Giuliana, in mia presenza: --Quando ti leverai, quando ti potrai muovere, andremo tutti insieme alla Badiola. Non è vero, Tullio? Giuliana mi guardò. --Sì, mamma--risposi, senza esitare, senza riflettere.--Anzi, io e Giuliana andremo a Villalilla. Ed ella di nuovo mi guardò; e sorrise, d'un sorriso impreveduto, indescrivibile, che aveva una espressione di credulità quasi infantile, che somigliava un poco a quello d'un bambino malato a cui sia fatta una grande insperata promessa. Ed abbassò le palpebre; e continuò a sorridere, con gli occhi socchiusi che vedevano qualche cosa lontana, molto lontana. E il sorriso s'attenuava, s'attenuava, senza estinguersi. Quanto mi piacque! Come l'adorai, in quel momento! Come sentii che nulla al mondo vale la semplice commozione della bontà! Una bontà infinita emanava da quella creatura e mi penetrava tutto l'essere, mi colmava il cuore. Ella stava nel letto supina, rialzata da due o tre guanciali; e la sua faccia dall'abbondanza dei capelli castagni un poco rilasciati acquistava una finezza estrema, una specie d'immaterialità apparente. Aveva una camicia chiusa intorno al collo, chiusa intorno ai polsi; e le sue mani posavano sul lenzuolo, prone, così pallide che soltanto le vene azzurre le distinguevano dal lino. Presi una di quelle mani (mia madre era già uscita dalla stanza); e dissi sotto voce: --Torneremo dunque.... a Villalilla. La convalescente disse: --Sì. E tacemmo, per prolungare la nostra commozione, per conservare la nostra illusione. Sapevamo ambedue il significato profondo che nascondevano quelle poche parole scambiate sotto voce. Un acuto istinto ci avvertiva di non insistere, di non definire, di non andare oltre. Se avessimo parlato ancora, ci saremmo trovati d'avanti alle realtà inconciliabili con l'illusione in cui le nostre anime respiravano e a poco a poco s'intorpidivano deliziosamente. Quel torpore favoriva i sogni, favoriva gli oblii. Passammo un intero pomeriggio quasi sempre soli, leggendo a intervalli, chinandoci insieme su la stessa pagina, seguendo con gli occhi la stessa riga. Avevamo là qualche libro di poesia; e noi davamo ai versi una intensità di significato, che non avevano. Muti, ci parlavamo per la bocca di quel poeta affabile. Io segnavo con l'unghia le strofe che parevano rispondere al mio sentimento non rivelato. Je veux, guidé par vous, beaux yeux aux flammes douces, Par toi conduit, o main où tremblera ma main, Marcher droit, que ce soit par des sentiers de mousses Ou que rocs et cailloux encombrent le chemin, Oui, je veux marcher droit et calme dans la Vie.... Ed ella, dopo aver letto, si riabbandonava per un poco su i guanciali, chiudendo gli occhi, con un sorriso quasi impercettibile. Toi la bonté, toi le sourire, N'es tu pas le conseil aussi, Le bon conseil loyal et brave.... Ma io vedevo sul suo petto la camicia secondare il ritmo del respiro con una mollezza che incominciava a turbarmi come il fievole profumo di ireos esalato dai lenzuoli e dai guanciali. Desiderai ed aspettai che ella, sorpresa da un subitaneo languore, mi cingesse il collo con un braccio e congiungesse la sua guancia alla mia così ch'io sentissi sfiorarmi dall'angolo della sua bocca. Ella pose l'indice affilato su la pagina e segnò con l'unghia il margine, guidando la mia lettura commossa. La voix vous fut connue (et chère?) Mais à présent elle est voilée Comme une veuve désolée.... Elle dit, la voix reconnue, que la bonté c'est notre vie.... Elle parle aussi de la gloire D'être simple sans plus attendre, Et de noces d'or et du tendre Bonheur d'une paix sans victoire. Accueillez la voix qui persiste Dans son naïf épithalame. Allez, rien n'est meilleur à l'âme Que de faire une âme moins triste! Io le presi il polso; e chinando il capo lentamente, fino a porre le labbra nel cavo della sua mano, mormorai: --Tu.... potresti dimenticare? Ella mi chiuse la bocca e pronunziò la sua gran parola: --Silenzio. Entrò mia madre annunziando la visita della signora Tàlice, in quel punto. Io lessi nel volto di Giuliana il fastidio, e anch'io fui preso da un'irritazione sorda contro l'importuna. Giuliana sospirò: --Oh mio Dio! --Dille che Giuliana riposa--io suggerii a mia madre con un accento quasi supplichevole. Ella mi accennò che la visitatrice aspettava nella stanza contigua. Bisognò riceverla. Questa signora Tàlice era d'una loquacità maligna e stucchevole. Mi guardava di tratto in tratto con un'aria curiosa. Come mia madre per caso, nel corso della conversazione, disse ch'io tenevo compagnia alla convalescente dalla mattina alla sera quasi di continuo, la signora Tàlice esclamò con un tono d'ironia manifesta, guardandomi: --Che marito perfetto! La mia irritazione crebbe così che mi risolsi, con un pretesto qualunque, ad andarmene. Uscii di casa. Incontrai per le scale Maria e Natalia che tornavano accompagnate dalla governante. Mi assalirono secondo il solito, con un'infinità di moine; e Maria, la maggiore, mi diede alcune lettere che aveva prese dal portiere. Tra queste riconobbi subito la lettera dell'Assente. E allora mi sottrassi alle moine, quasi con impazienza. Giunto su la strada, mi soffermai per leggere. Era una lettera breve ma appassionata, con due o tre frasi d'una eccessiva acutezza, quali sapeva trovare Teresa per agitarmi. Ella mi faceva sapere che sarebbe stata a Firenze tra il 20 e il 25 del mese e che avrebbe voluto incontrarmi là "come l'altra volta." Mi prometteva notizie più esatte pel convegno. Tutti i fantasmi delle illusioni e delle commozioni recenti abbandonarono a un tratto il mio spirito, come i fiori d'un albero scosso da una folata gagliarda. E come i fiori caduti sono per l'albero irrecuperabili, così furono per me quelle cose dell'anima: mi divennero estranee. Feci uno sforzo, tentai di raccogliermi; non riuscii a nulla. Mi misi a girare per le strade, senza scopo; entrai da un pasticciere, entrai da un libraio; comprai dolci e libri macchinalmente. Scendeva il crepuscolo; s'accendevano i fanali; i marciapiedi erano affollati; due o tre signore dalle loro carrozze risposero al mio saluto; passò un amico a fianco della sua amante che portava tra le mani un mazzo di rose, camminando presto e parlando e ridendo. Il soffio malefico della vita cittadina m'investì; risuscitò le mie curiosità, le mie cupidige, le mie invidie. Arricchito in quelle settimane di continenza, il mio sangue ebbe come un'accensione subitanea. Alcune imagini mi balenarono lucidissime dentro. L'Assente mi riafferrò con le parole della sua lettera. E tutto il mio desiderio andò verso di lei, senza freno. Ma quando il primo tumulto si fu placato, mentre risalivo le scale della mia casa, compresi tutta la gravità di quel che era accaduto, di quel che avevo fatto; compresi che veramente, poche ore prima, avevo riallacciato un legame, avevo obbligata la mia fede, avevo data una promessa, una promessa tacita ma solenne a una creatura ancora debole e inferma; compresi che non avrei potuto senza infamia ritrarmi. E allora io mi rammaricai di non aver diffidato di quella commozione ingannevole, mi rammaricai di essermi troppo indugiato in quel languore sentimentale! Esaminai minutamente i miei atti e i miei detti di quel giorno, con la fredda sottigliezza d'un mercante subdolo il quale cerchi un appiglio per sottrarsi alla stipulazione di un contratto già concordato. Ah, le mie ultime parole erano state troppo gravi. Quel "Tu potresti dimenticare?" pronunziato con quell'accento, dopo la lettura di quei versi, aveva avuto il valore di una conferma definitiva. E quel "Silenzio" di Giuliana era stato come un suggello. "Ma" io pensai "questa volta ha ella proprio creduto al mio ravvedimento? Non è ella stata sempre un poco scettica a riguardo dei miei buoni moti?" E rividi quel suo tenue sorriso sfiduciato, già altre volte comparsole sulle labbra. "Se ella dentro di sé non avesse creduto, se anche la sua illusione fosse caduta subitamente, allora forse la mia ritirata non avrebbe molta gravità, non la ferirebbe né la sdegnerebbe troppo; e l'episodio rimarrebbe senza conseguenza, e io rimarrei libero come prima. Villalilla rimarrebbe nel suo sogno." E rividi l'altro sorriso, il sorriso nuovo, impreveduto, credulo, che le era comparso su le labbra al nome di Villalilla. "Che fare? Che risolvere? Come contenermi?" La lettera di Teresa Raffo mi bruciava forte. Quando rientrai nella stanza di Giuliana, m'accorsi al primo sguardo che ella _mi aspettava_. Mi parve lieta, con gli occhi lucidi, con un pallore più animato, più fresco. --Tullio, dove sei stato?--mi domandò ridendo. Io risposi: --Mi ha messo in fuga la signora Tàlice. Ella seguitò a ridere, d'un limpido riso giovenile che la trasfigurava. Io le porsi i libri e la scatola delle confetture. --Per me?--esclamò, tutta contenta, come una bambina golosa; e si affrettò ad aprire la scatola, con piccoli gesti di grazia, che risollevavano nel mio spirito lembi di ricordi lontani. --Per me? Prese un _bonbon_, fece l'atto di portarlo alla bocca, esitò un poco, lo lasciò ricadere, allontanò la scatola; e disse: --Poi, poi.... --Sai, Tullio--m'avvertì mia madre--non ha ancora mangiato nulla. Ha voluto aspettarti. --Ah, non t'ho ancora detto....--proruppe Giuliana, divenuta rosea--non t'ho ancora detto che c'è stato il dottore, mentre eri fuori. Mi ha trovata molto meglio. Potrò alzarmi giovedì. Capisci, Tullio? Potrò alzarmi giovedì.... Soggiunse: --Fra dieci, fra quindici giorni al più, potrò anche mettermi in treno. Soggiunse, dopo una pausa pensosa, con un tono minore: --Villalilla! Ella non aveva dunque pensato ad altro, non aveva sognato altro. Ella _aveva creduto_; _credeva_. Io duravo fatica a dissimulare la mia angoscia. Mi occupavo, con soverchia premura, forse, dei preparativi pel suo piccolo pranzo. Io medesimo le misi su le ginocchia la tavoletta. Ella seguiva tutti i miei movimenti con uno sguardo carezzevole che mi faceva male. "Ah, se ella potesse indovinare!" D'un tratto, mia madre esclamò, candidamente: --Come sei bella stasera, Giuliana! In fatti, un'animazione straordinaria le avvivava le linee del volto, le accendeva gli occhi, la ringiovaniva tutta quanta. All'esclamazione di mia madre, ella arrossì; e un'ombra di quel rossore le rimase per tutta la sera su le gote. --Giovedì mi alzerò--ripeteva.--Giovedì, fra tre giorni! Non saprò più camminare.... Insisteva col discorso su la sua guarigione, su la nostra partenza prossima. Chiese a mia madre alcune notizie su lo stato attuale della villa, sul giardino. --Io piantai un ramo di salice vicino alla peschiera, l'ultima volta che ci fummo. Ti ricordi, Tullio? Chi sa se ce lo ritroverò.... --Sì sì--interruppe mia madre, raggiante--ce lo ritroverai; è cresciuto; è un albero. Domandalo a Federico. --Davvero? Davvero? Dimmi dunque, mamma... Pareva che quella piccola particolarità in quel momento avesse per lei un'importanza incalcolabile. Ella divenne loquace. Io mi meravigliavo ch'ella fosse così a dentro nell'illusione, mi meravigliavo ch'ella fosse così trasfigurata dal suo sogno. "Perché, perché questa volta ella _ha creduto_? Come mai si lascia così trasportare? Chi le dà questa insolita fede?" E il pensiero della mia infamia prossima, forse inevitabile, mi agghiacciava. "Perché inevitabile? Non saprò dunque mai liberarmi? Io _debbo_, io _debbo_ mantenere la mia promessa. Mia madre è testimone della mia promessa. A qualunque costo, la manterrò." E con uno sforzo interiore, quasi direi con una scossa della conscienza, io uscii dal tumulto delle incertezze; e mi rivolsi a Giuliana, per un moto dell'anima quasi violento. Ella mi piacque ancora, eccitata com'era, vivace, giovine. Mi rammentava la Giuliana d'un tempo, che tante volte in mezzo alla tranquillità della vita famigliare io aveva sollevata d'improvviso su le mie braccia, come preso da una follia repentina, e portata di corsa nell'alcova. --No, no, mamma; non mi far più bere--ella pregò, trattenendo mia madre che le versava il vino.--Già ho bevuto troppo, senza accorgermene. Ah questo Chablis! Ti ricordi, Tullio? E rise, guardandomi dentro le pupille, nell'evocare il ricordo d'amore su cui ondeggiava il fumo di quel delicato vino amaretto e biondo ch'ella prediligeva. --Mi ricordo--io risposi. Ella socchiuse le palpebre, con un leggero tremolio dei cigli. Disse poi: --Fa caldo qui. È vero? Ho gli orecchi che mi scottano. E si strinse la testa fra le palme, per sentire il bruciore. Il lume, che ardeva a lato del letto, rischiarava intensamente la lunga linea del viso; faceva rilucere tra il folto de' capelli castagni alcuni fili d'oro chiaro, ove l'orecchio piccolo e fine, acceso alla sommità, traspariva. A un punto, mentre io aiutavo a sparecchiare (mia madre era uscita, e la cameriera anche, per un momento, e stavano nella stanza attigua), ella chiamò sotto voce: --Tullio! E, con un gesto furtivo attirandomi, mi baciò su una gota. Ora, non doveva ella con quel bacio riprendermi interamente, anima e corpo, per sempre? Quell'atto, in lei così sdegnosa e così fiera, non significava che ella voleva tutto obliare, che aveva già tutto obliato per rivivere con me una vita nuova? Avrebbe potuto ella riabbandonarsi al mio amore con più grazia, con maggior confidenza? La sorella ridiventava l'amante a un tratto. La sorella impeccabile aveva conservato nel sangue, nelle più segrete vene, la memoria delle mie carezze, quella memoria organica delle sensazioni, così viva nella donna e così tenace. Ripensando, quando mi ritrovai solo, ebbi interrottamente alcune visioni di giorni lontani, di sere lontane. "Un crepuscolo di giugno, caldo, tutto roseo, navigato da misteriosi profumi, terribile ai solitarii, a coloro che rimpiangono o che desiderano. Io entro nella stanza. Ella è seduta presso alla finestra, con un libro sulle ginocchia, tutta languida, pallidissima, nell'attitudine di chi sia per venir meno.--Giuliana!--Ella si scuote, si risolleva.--Che fai?--Risponde:--Nulla. E un'alterazione indefinibile, come una violenza di cose soffocate, passa nei suoi occhi troppo neri." Quante volte, dal giorno della triste rinunzia, ella aveva patito nella sua povera carne quelle torture? Il mio pensiero s'indugiò intorno alle imagini suscitate dal piccolo fatto recente. La singolare eccitazione mostrata da Giuliana mi rammentò certi esempi della sua sensibilità fisica straordinariamente acuta. La malattia, forse, aveva aumentata, esasperata quella sensibilità. Ed io pensai, curioso e perverso, che avrei veduto la debole vita della convalescente ardere e struggersi sotto la mia carezza; e pensai che la voluttà avrebbe avuto quasi un sapore di incesto. "Se ella ne morisse?" pensai. Certe parole del chirurgo mi tornavano alla memoria, sinistre. E, per quella crudeltà che è in fondo a tutti gli uomini sensuali, il pericolo non mi spaventò ma mi attrasse. Io m'indugiai ad esaminare il mio sentimento con quella specie di amara compiacenza, mista di disgusto, che portavo nell'analisi di tutte le manifestazioni interiori le quali mi paressero fornire una prova della malvagità fondamentale umana. "Perchè l'uomo ha nella sua natura questa orribile facoltà di godere con maggiore acutezza quando è consapevole di nuocere alla creatura da cui prende il godimento? Perchè un germe della tanto esecrata perversione sàdica è in ciascun uomo che ama e che desidera?" Questi pensieri, più che il primitivo spontaneo sentimento di bontà e di pietà, questi pensieri obliqui mi condussero in quella notte a raffermare il mio proposito in favore della illusa. L'Assente mi avvelenava anche di lontano. Per vincere la resistenza del mio egoismo, ebbi bisogno di contrapporre all'imagine della deliziosa depravazione di quella donna l'imagine di una nuova rarissima depravazione che io mi promettevo di coltivar con lentezza nella onesta securità della mia casa. Allora, con quell'arte quasi direi alchimistica che io aveva nel combinare i varii _prodotti_ del mio spirito, analizzai la serie degli "stati d'animo" speciali in me determinati da Giuliana nelle diverse epoche della nostra vita comune, e ne trassi alcuni elementi i quali mi servirono a construrre un nuovo stato, fittizio, singolarmente adatto ad accrescere l'intensità di quelle sensazioni che io voleva esperimentare. Così, per esempio, allo scopo di rendere più acre quel "sapore d'incesto" che m'attraeva eccitando la mia fantasia scellerata, io cercai di rappresentarmi i momenti in cui più profondo era stato in me il "sentimento fraterno" e più schietta mi era parsa l'attitudine di sorella in Giuliana. E chi s'indugiava in queste miserabili sottigliezze di maniaco era l'uomo medesimo che poche ore innanzi aveva sentito il suo cuore tremare nella semplice commozione della bontà, al lume di un sorriso impreveduto! Di tali crisi contradittorie si componeva la sua vita: illogica, frammentaria, incoerente. Erano in lui tendenze d'ogni specie, tutti i possibili contrarii, e tra questi contrarii tutte le gradazioni intermedie e tra quelle tendenze, tutte le combinazioni. Secondo il tempo e il luogo, secondo il vario urto delle circostanze, d'un piccolo fatto, d'una parola, secondo influenze interne assai più oscure, il fondo stabile del suo essere si rivestiva di aspetti mutevolissimi, fuggevolissimi, strani. Un suo speciale stato organico rinforzava una sua speciale tendenza; e questa tendenza diveniva un centro di attrazione verso il quale convergevano gli stati e le tendenze direttamente associati; e a poco a poco le associazioni si propagavano. Il suo centro di gravità allora si trovava spostato e la sua personalità diventava un'altra. Silenziose onde di sangue e d'idee facevano fiorire sul fondo stabile del suo essere, a gradi o un tratto, anime nuove. Egli era _multanime_. Insisto su l'episodio perchè veramente segna il punto decisivo. La mattina dopo, al risveglio, non conservavo se non una nozione confusa di quanto era accaduto. La viltà e l'angoscia mi ripresero appena ebbi sotto gli occhi un'altra lettera di Teresa Raffo, con cui ella mi confermava il convegno a Firenze pel 21, dandomi istruzioni precise. Il 21 era sabato, e giovedì 19 Giuliana si levava per la prima volta. Io discussi a lungo, con me stesso, tutte le possibilità. Discutendo, incominciai a transigere. "Sì, non c'è dubbio: è necessaria una rottura, è inevitabile. Ma in che modo io romperò? con quale pretesto? Posso io annunziare il mio proposito a Teresa con una semplice lettera? La mia ultima risposta era ancora calda di passione, smaniosa di desiderio. Come giustificare questo mutamento subitaneo? Merita la povera amica un colpo tanto inaspettato e brutale? Ella mi ha molto amato, mi ama; ha sfidato per me, un tempo, qualche pericolo. Io l'ho amata.... l'amo. La nostra grande e strana passione è conosciuta; invidiata anche; insidiata anche.... Quanti uomini ambiscono a succedermi! Innumerevoli." Numerai rapidamente i rivali più temibili, i successori più probabili, considerandone le figure imaginate. "C'è forse a Roma una donna più bionda, più affascinante, più desiderabile di lei?" La stessa accensione repentina, avvenuta la sera innanzi nel mio sangue, mi percorse tutte le vene. E il pensiero della rinunzia volontaria mi parve assurdo, inammissibile. "No, no, non avrò mai la forza; non vorrò, non potrò mai." Sedata la turbolenza, proseguii il vano dibattito, pur avendo in fondo a me la certezza che, giunta l'ora, non avrei potuto non partire. Ebbi però il coraggio, uscendo dalla stanza della convalescente, essendo ancora tutto vibrante di commozione, ebbi il supremo coraggio di scrivere a quella che mi chiamava: "Non verrò." Inventai un pretesto; e, mi ricordo bene, quasi per istinto lo scelsi tale che a lei non sembrasse troppo grave.--Speri dunque che ella non curi il pretesto e t'imponga di partire?--chiese qualcuno dentro di me. Non sfuggii a quel sarcasmo; e un'irritazione e un'ansietà atroci s'impadronirono di me, non mi diedero tregua. Facevo sforzi inauditi per dissimulare, al conspetto di Giuliana e di mia madre. Evitavo studiosamente di trovarmi solo con la povera illusa; e ad ogni tratto mi pareva di leggere nei suoi miti umidi occhi il principio di un dubbio, mi pareva di veder passare qualche ombra su la sua fronte pura. Il giorno di mercoledì ebbi un telegramma imperioso e minaccioso (non era quasi aspettato?): "O tu verrai o non mi vedrai più. Rispondi." E io risposi: "Verrò." Subito dopo quell'atto, commesso con quella specie di sovreccitazione inconsciente che accompagna tutti gli atti decisivi della vita, io provai un particolare sollievo, vedendo gli avvenimenti determinarsi. Il senso della mia irresponsabilità, il senso della necessità di ciò che accadeva ed era per accadere divennero in me profondissimi. "Se, pur conoscendo il male che io faccio e pur condannandomi in me medesimo, io non posso fare altrimenti, segno è che obbedisco a una forza superiore ignota. Io sono la vittima di un Destino crudele, ironico ed invincibile." Nondimeno, a pena misi il piede su la soglia della stanza di Giuliana, sentii piombarmi sul cuore un peso enorme; e mi soffermai, vacillante, fra le portiere che mi nascondevano. "Basterà ch'ella mi guardi per indovinar tutto", pensai smarrito. E fui sul punto di tornare in dietro. Ma ella disse, con una voce che non m'era mai parsa tanto dolce: --Tullio, sei tu? Allora feci un passo. Ella gridò, vedendomi: --Tullio, che hai? Ti senti male? --Una vertigine.... M'è passata già--risposi; e mi rassicurai pensando: "Ella non ha indovinato." Ella, in fatti, era inconsapevole; e a me pareva strano che così fosse. Dovevo io prepararla al colpo brutale? Dovevo parlare sinceramente o architettare qualche menzogna pietosa? O pure dovevo partire all'improvviso, senza avvertirla, lasciandole in una lettera la mia confessione? Qual era il modo preferibile per rendere meno grave a me lo sforzo e meno cruda in lei la sorpresa? Ahimè, nel dibattito difficile, per un tristo istinto io mi preoccupavo d'alleggerir me più che lei. E certo avrei scelto il modo della partenza improvvisa e della lettera, se non mi avesse trattenuto il riguardo per mia madre. Era necessario risparmiare mia madre, sempre, ad ogni patto. Anche questa volta non sfuggii al sarcasmo interiore. "Ah, ad _ogni_ patto? Che cuore generoso! Ma pure, via, è così comodo per te il vecchio patto, ed anche sicuro.... Anche questa volta, se tu vorrai, la vittima si sforzerà di sorridere sentendosi morire. Confida in lei, dunque, e non ti curare d'altro, cuore generoso." L'uomo trova nel sincero e supremo disprezzo di sé medesimo qualche volta, veramente, una particolare gioia. --A che pensi, Tullio?--mi domandò Giuliana, con un gesto ingenuo appuntandomi l'indice tra l'uno e l'altro sopracciglio come per fermare il pensiero. Io le presi quella mano, senza rispondere. E il silenzio stesso, che parve grave, bastò a modificare di nuovo l'attitudine del mio spirito; la dolcezza che era nella voce e nel gesto della inconsapevole mi ammollì, mi suscitò quel sentimento snervante da cui hanno origine le lacrime; che si chiama _pietà di sé_. Provai un acuto bisogno d'essere compassionato. Nel tempo medesimo qualcuno mi suggeriva dentro: "Approfitta di questa disposizione d'animo, senza fare per ora alcuna rivelazione. Esagerandola, tu puoi facilmente giungere fino al pianto. Tu sai bene che straordinario effetto abbia su una donna il pianto dell'uomo amato. Giuliana ne sarà sconvolta; e tu sembrerai essere travagliato da un dolore terribile. Domani poi, quando tu le dirai la verità, il ricordo delle lacrime ti rialzerà nell'animo di lei. Ella potrà pensare:--Ah dunque per questo ieri piangeva così dirottamente. Povero amico!--E tu non sarai giudicato un egoista odioso; ma sembrerai aver combattuto con tutte le tue forze in vano contro chi sa qual potere funesto; sembrerai essere tenuto chi sa da quale morbo immedicabile e portare nel tuo petto un cuore lacerato. Approfitta, dunque, approfitta." --Hai qualche cosa _sul cuore_?--mi domandò Giuliana, con una voce sommessa, carezzevole, piena di confidenza. Io tenevo il capo chino; ed ero, certo, commosso. Ma la preparazione di quel pianto _utile_ distrasse il mio sentimento, ne arrestò la spontaneità e ritardò quindi il fenomeno fisiologico delle lacrime. "Se io non potessi piangere? Se non _mi venissero_ le lacrime?" pensai con uno sgomento ridicolo e puerile, come se tutto dipendesse da quel piccolo fatto materiale che la mia volontà non bastava a produrre. E intanto qualcuno, sempre il medesimo, soffiava: "Che peccato! Che peccato! L'ora non potrebbe essere più favorevole. Nella stanza ci si vede appena. Che effetto, un singhiozzo nell'ombra!" --Tullio, non mi rispondi?--soggiunse Giuliana, dopo un intervallo, passandomi la mano su la fronte e su i capelli perché io alzassi la faccia.--A me tu puoi dire tutto. Lo sai. Ah, veramente, dopo d'allora io non ho mai più udita una voce umana di quella dolcezza. Né pure mia madre ha mai saputo parlarmi così. Gli occhi mi si inumidirono, e io sentii tra i cigli il tepore del pianto. "Questo, questo è il momento di prorompere." Ma non fu se non una lacrima; e io (umiliante cosa ma pur vera; e in simili meschinità mimiche si rimpicciolisce la maggior parte delle commozioni umane nel manifestarsi) io alzai il viso perché Giuliana la scorgesse e provai per qualche attimo un'ansietà smaniosa temendo che nell'ombra ella non la scorgesse luccicare. Quasi per avvertirla, ritirai il fiato in dentro, forte, come si fa quando si vuol contenere un singhiozzo. Ed ella avvicinando il suo volto al mio per guardarmi da presso, poiché rimanevo muto, ripetè: --Non rispondi? E intravide; e, per accertarsi, mi afferrò la testa e me l'arrovesciò, con un gesto quasi brusco. --Piangi? La sua voce era mutata. E io mi liberai all'improvviso, mi levai per fuggire, come uno che non possa più reggere la piena dell'affanno. --Addio, addio. Lasciami andare, Giuliana. Addio. E uscii dalla stanza, a precipizio. Quando fui solo, ebbi disgusto di me. Era la vigilia d'una solennità per la convalescente. Qualche ora dopo, come mi ripresentai a lei per assistere al piccolo pranzo consueto, la ritrovai in compagnia di mia madre. A pena mi vide, mia madre esclamò: --Dunque domani, Tullio, giorno di festa. Io e Giuliana ci guardammo, ambedue ansiosi. Poi parlammo del domani, dell'ora in cui ella avrebbe potuto alzarsi, di tante minute particolarità, con un certo sforzo, un poco distratti. E io m'auguravo, dentro di me, che mia madre non si assentasse. Ebbi fortuna, perché una sola volta mia madre uscì e rientrò quasi subito. Nel frattempo, Giuliana rapidamente mi chiese: --Che avevi, dianzi? Non me lo vuoi dire? --Nulla, nulla. --Vedi, così tu mi guasti la festa. --No, no. Ti dirò.... ti dirò.... poi. Non ci pensare, ora; ti prego. --Sii buono! Mia madre rientrava con Maria e Natalia. Ma l'accento con cui Giuliana aveva proferito quelle poche parole bastò per convincermi che ella non sospettava la verità. Pensava ella forse che quella tristezza mi venisse da un'ombra del mio passato incancellabile e inespiabile? Pensava che io fossi torturato dal rammarico di averle fatto tanto male e dal timore di non meritare tutto il suo perdono? Fu ancora una commozione viva, la mattina dopo (per compiacere il desiderio di lei aspettavo nella stanza prossima), quando mi sentii chiamare dalla sua voce squillante. --Tullio, vieni. Ed entrai; e la vidi in piedi, che sembrava più alta, più snella, quasi fragile. Vestita d'una specie di tunica ampia e fluida, a lunghe pieghe diritte, ella sorrideva, esitando, reggendosi a pena, tenendo le braccia discoste dai fianchi come per cercare l'equilibrio, volgendosi ora a me ora a mia madre. Mia madre la guardava con una indescrivibile espressione di tenerezza, pronta a sorreggerla. Io stesso tendevo le mani, pronto a sorreggerla. --No, no--ella pregò--lasciatemi, lasciatemi. Non cado. Voglio andare da me fino alla poltrona. Ella avanzò il piede, fece un passo, pianamente. Aveva nel viso il candore d'una gioia infantile. --Bada, Giuliana! Fece ancora due o tre passi; poi, assalita da uno sbigottimento repentino, dal timor pànico di cadere, esitò un attimo tra me e mia madre, e si gittò nelle mie braccia, sul mio petto, abbandonandosi con tutto il suo peso, sussultando come se singhiozzasse. Ella rideva, in vece, un poco soffocata dall'ansia; e, come ella non portava busto, le mie mani la sentirono tutta esile e pieghevole a traverso la stoffa, il mio petto la sentì tutta palpitante e morbida, le mie nari aspirarono il profumo dei suoi capelli, i miei occhi rividero sul suo collo il piccolo segno bruno. --Ho avuto paura--ella diceva interrottamente, ridendo e ansando--ho avuto paura di cadere. E, come ella arrovesciava la testa verso mia madre per guardarla, senza staccarsi da me, io scorsi un poco della sua gengiva esangue e il bianco degli occhi e qualche cosa di convulso in tutto il viso. E conobbi che tenevo fra le braccia una povera creatura inferma, profondamente alterata dall'infermità, con i nervi indeboliti, con le vene impoverite, forse insanabile. Ma ripensai la sua trasfigurazione in quella sera del bacio inaspettato; e l'opera di carità e d'amore e d'ammenda, a cui rinunziavo, ancora una volta m'apparve bellissima. --Conducimi tu alla poltrona, Tullio--ella diceva. Sostenendola col mio braccio alle reni, io la condussi piano piano; l'aiutai ad adagiarsi; disposi su la spalliera i cuscini di piume, e mi ricordo che scelsi quello di tono più squisito perché ella vi appoggiasse la testa. Anche, per metterle un cuscino sotto i piedi, m'inginocchiai; e vidi la sua calza di colore gridellino, la sua pianella esigua che nascondeva poco più del pollice. Come in _quella sera_, ella seguiva tutti i miei movimenti con uno sguardo carezzevole. E io m'indugiavo. Accostai un piccolo tavolo da tè, sopra ci posai un vaso di fiori freschi, qualche libro, una stecca d'avorio. Senza volere, mettevo in quelle mie premure un po' di ostentazione. L'ironia ricominciò. "Molto abile! Molto abile! È utilissimo quel che fai, sotto gli occhi di tua madre. Come potrà ella sospettare, dopo avere assistito a queste tue tenerezze? Quel po' di ostentazione, anche, non guasta. Ella non ha la vista troppo acuta. Séguita, séguita. Tutto va a meraviglia. Coraggio!" --Oh come si sta bene qui!--esclamò Giuliana con un sospiro di sollievo, socchiudendo i cigli.--Grazie, Tullio. Qualche minuto dopo, quando mia madre uscì, quando rimanemmo soli, ella ripetè, con un sentimento più profondo: --Grazie. E alzò una mano verso di me, perché io la prendessi nelle mie. Essendo ampia la manica, nel gesto il braccio si scoperse fin quasi al gomito. E quella mano bianca e fedele, che portava l'amore, l'indulgenza, la pace, il sogno, l'oblio, tutte le cose belle e tutte le cose buone, tremò un istante nell'aria verso di me come per l'offerta suprema. Credo che nell'ora della morte, nell'attimo stesso in cui cesserò di soffrire, io rivedrò quel gesto solo; fra tutte le imagini della vita passata innumerabili, rivedrò unicamente quel gesto. Quando ripenso, non riesco a ricostruire con esattezza la condizione nella quale mi trovai. Posso affermare che anche allora io comprendevo l'estrema gravità del momento e lo straordinario valore degli atti che si compivano ed erano per compiersi. La mia perspicacia era, o mi pareva, perfetta. Due processi di conscienza si svolgevano dentro di me, senza confondersi, bene distinti, paralleli. In uno predominava, insieme con la pietà verso la creatura che io stava per colpire, un sentimento di acuto rammarico verso l'offerta ch'io stava per respingere. Nell'altro predominava insieme con la cupa bramosia verso l'amante lontana, un sentimento egoistico esercitato nel freddo esame delle circostanze che potevano favorire la mia impunità. Questo parallelismo portava la mia vita interna ad una intensità e ad una accelerazione incredibili. Il momento decisivo era venuto. Dovendo partire al dimani, non potevo temporeggiare più oltre. Perché la cosa non sembrasse oscura e troppo subitanea, era necessario in quella mattina stessa, a colazione, annunziare la partenza a mia madre e addurre il pretesto plausibile. Era necessario anche, prima che a mia madre, dare l'annunzio a Giuliana perché non accadessero contrattempi pericolosi. "E se Giuliana prorompesse, al fine? Se, nell'impeto del dolore e dello sdegno, ella rivelasse a mia madre la verità? Come ottenere da lei una promessa di silenzio, un nuovo atto di abnegazione?" Fino all'ultimo io discussi, dentro di me. "Comprenderà subito, alla prima parola? E se non comprendesse? Se ingenuamente mi chiedesse la ragione del mio viaggio? Come risponderei? Ma ella comprenderà. È impossibile che ella non abbia già saputo da qualcuna delle sue amiche, da quella signora Tàlice, per esempio, che Teresa Raffo non è a Roma." Le mie forze cominciavano già a cedere. Non avrei potuto più a lungo sostenere l'orgasmo che cresceva di minuto in minuto. Mi risolsi, con una tensione di tutti i miei nervi; e, poiché ella parlava, desiderai che ella medesima mi offrisse l'opportunità di scoccare la freccia. Ella parlava di molte cose specialmente future, con una volubilità insolita. Quel non so che di convulso in lei, già da me notato prima, mi pareva più palese. Io stavo ancora in piedi, dietro la poltrona. Fino a quel momento avevo evitato il suo sguardo movendomi ad arte per la stanza, sempre dietro la poltrona, ora occupato a fermare le tende della finestra, ora a riordinare i libri nella piccola scansia, ora a raccogliere di sul tappeto le foglie cadute da un mazzo di rose disfatto. Stando in piedi, guardavo la riga dei suoi capelli, i suoi cigli lunghi e ricurvi, la lieve palpitazione del suo petto, e le sue mani, le sue belle mani che posavano su i bracciuoli, prone come in quel giorno, pallide come in quel giorno quando "soltanto le vene azzurre le distinguevano dal lino". Quel giorno! Non era trascorsa né pure una settimana. Perché pareva dunque tanto remoto? Stando in piedi dietro di lei, in quella tensione estrema, come in agguato, io pensai che forse ella sentiva per istinto sul suo capo la minaccia; e credetti indovinare in lei una specie di vago malessere. Ancora una volta mi si strinse il cuore, intollerabilmente. A un punto, in fine, ella disse: --_Domani_, se starò meglio, tu mi porterai su la terrazza, all'aria.... Io interruppi: --_Domani_ non sarò qui. Ella si scosse al suono strano della mia voce. Io soggiunsi, senza attendere: --Partirò.... Soggiunsi ancora, con uno sforzo per snodare la lingua, raccapricciato come uno che debba iterare il colpo per finire la vittima: --Partirò per Firenze. --Ah! Ella aveva compreso a un tratto. Si volse con un moto rapido, si torse tutta su i cuscini per guardarmi; e io rividi, per quella torsione violenta, il bianco de' suoi occhi, la sua gengiva esangue. --Giuliana!--balbettai, senza sapere che altro dirle, chinandomi verso di lei, temendo ch'ella venisse meno. Ma ella abbassò le palpebre, si ricompose, si ritrasse, si restrinse in sé stessa, come presa da un gran freddo. Rimase così qualche minuto, con gli occhi chiusi, con la bocca serrata, immobile. Soltanto la pulsazione visibile della carotide nel collo e qualche contrazione convulsiva nelle mani davano indizio della vita. Non fu un delitto? Fu il _primo_ dei miei delitti; e non il minore, forse. Partii, in condizioni terribili. La mia assenza durò più di una settimana. Quando tornai e nei giorni che seguirono il mio ritorno, io stesso mi meravigliavo della mia sfrontatezza quasi cinica. Ero posseduto da una specie di malefizio che aboliva in me ogni senso morale e mi rendeva capace delle peggiori ingiustizie, delle peggiori crudeltà. Giuliana anche questa volta mostrava una forza prodigiosa; anche questa volta aveva saputo tacere. E m'appariva chiusa nel suo silenzio come in un'armatura adamantina, impenetrabile. Andò con le figlie e con mia madre alla Badiola. Le accompagnava mio fratello. Io rimasi a Roma. Da quel tempo incominciò per me un periodo tristissimo, oscurissimo, il cui ricordo ancora mi riempie di nausea e d'umiliazione. Tenuto da quel sentimento che meglio di ogni altro rimescola il fango essenziale nell'uomo, io patii tutto lo strazio che una donna può fare di un'anima fiacca, appassionata e sempre vigile. Accesa da un sospetto, una terribile gelosia sensuale divampò in me disseccando tutte le buone fonti interiori, alimentandosi di tutto il fecciume che posava nell'infimo della mia sostanza bruta. Teresa Raffo non m'era parsa mai desiderabile come ora che non potevo disgiungerla da una imagine fallica, da una sozzura. Ed ella si valeva del mio stesso disprezzo per inacerbire la mia brama. Agonie atroci, gioie abiette, sottomissioni disonoranti, patti vili proposti ed accettati senza rossore, lacrime più acri di qualunque tossico, frenesie improvvise che mi spingevano sul confine della demenza, cadute nell'abisso della lussuria così violente che mi lasciavano per lunghi giorni istupidito, tutte le miserie e tutte le ignominie della passione carnale esasperata dalla gelosia, tutte io le conobbi. La mia casa mi divenne estranea; la presenza di Giuliana mi divenne incresciosa. Intere settimane passavano, talvolta, senza che io le rivolgessi una parola. Assorto nel mio supplizio interiore, io non la vedevo, non la udivo. In certi momenti, levando gli occhi su lei, mi meravigliavo del suo pallore, della sua espressione, di certe particolarità del suo volto, come di cose nuove, inaspettate, strane; e non giungevo a riconquistare intera la nozione della realtà. Tutti gli atti della sua esistenza m'erano ignoti. Io non provavo alcun bisogno d'interrogarla, di sapere; non provavo per lei alcuna inquietudine, alcuna sollecitudine, alcun timore. Una durezza inesplicabile mi fasciava l'anima contro di lei. Anche, talvolta, io avevo contro di lei una specie di vago rancore, inesplicabile. Un giorno la sentii ridere; e il suo riso m'irritò, mi fece quasi ira. Un altro giorno palpitai forte, udendola cantare da una stanza lontana. Cantava l'aria di Orfeo: Che farò senza Euridice? Era la prima volta, dopo lungo tempo, che ella cantava così, movendosi per la casa; era la prima volta che io la riudiva, dopo lunghissimo tempo.--Perché cantava? Era dunque lieta? A quale affetto del suo animo rispondeva quell'effusione insolita?--Un turbamento inesplicabile mi vinse. Andai verso di lei senza riflettere, chiamandola per nome. Vedendomi entrare nella sua stanza, ella si stupì; rimase per un poco attonita, in una sospensione manifesta. --Canti?--io dissi, per dire qualche cosa, impacciato, meravigliato io stesso del mio atto straordinario. Ella sorrise d'un sorriso incerto, non sapendo che rispondere, non sapendo quale contegno assumere davanti a me. E mi parve di leggere nei suoi occhi una curiosità penosa, già altre volte da me notata fuggevolmente: quella curiosità compassionevole con cui si guarda una persona sospettata di follia, un ossesso. In fatti, nello specchio di contro io scorsi la mia imagine; rividi il mio volto scarno, le mie occhiaie profonde, la mia bocca tumida, quell'aspetto di febricitante che avevo già da qualche mese. --Ti vestivi per uscire?--le domandai, ancora impacciato, quasi peritoso, non sapendo che altro dimandare, volendo evitare il silenzio. --Sì. Era di mattina; era di novembre. Ella stava in piedi, presso a un tavolo ornato di merletti su cui rilucevano sparse le innumerevoli minuterie moderne destinate alla cura della bellezza muliebre. Portava un abito di vigogna oscuro; e teneva ancora in mano un pettine di tartaruga bionda con la costola d'argento. L'abito, di foggia semplicissima, secondava la svelta eleganza della persona. Un gran mazzo di crisantemi bianchi le saliva di sul tavolo all'altezza della spalla. Il sole dell'estate di San Martino scendeva per la finestra; e nella luce vagava un profumo di cipria o d'essenza che io non seppi riconoscere. --Qual'è, ora, il tuo profumo?--le domandai. Ella rispose: --_Crab-apple_. Io soggiunsi: --Mi piace. Ella prese di sul tavolo una fiala e me la porse. E io la fiutai a lungo per fare qualche cosa, per avere il tempo di preparare un'altra qualunque frase. Non riuscivo a dissipare la mia confusione, a riconquistare la mia franchezza. Sentivo che ogni intimità fra noi due era caduta. Ella mi pareva _un'altra donna_. E intanto l'aria di Orfeo mi ondeggiava ancora su l'anima, m'inquietava ancora. Che farò senza Euridice? In quella luce dorata e tepida, in quel profumo così molle, in mezzo a tutti quegli oggetti improntati di grazia femminile, il fantasma della melodia antica pareva svegliare il palpito d'una vita segreta, spandere l'ombra d'un non so che mistero. --Com'è bella l'aria che tu cantavi dianzi!--io dissi, obbedendo all'impulso che mi veniva dalla inquietudine. --Tanto bella!--ella esclamò. E una domanda mi saliva alle labbra: "Ma perchè cantavi?" La trattenni; e ricercai dentro di me la ragione di quella curiosità che mi pungeva. Successe un intervallo di silenzio. Ella scorreva con l'unghia del pollice su i denti del pettine, producendo un leggero stridore. (Quello stridore è una particolarità chiarissima nel mio ricordo). --Tu ti vestivi per uscire. Séguita dunque--io dissi. --Non ho da mettermi che la giacca e il cappello. Che ora è? --Manca un quarto alle undici. --Ah, già così tardi? Ella prese il cappello e il velo; e si mise a sedere davanti allo specchio. Io la guardavo. Un'altra domanda mi salì alle labbra; "Dove vai?" Ma trattenni anche questa, benché potesse sembrare naturale. E seguitai a guardarla attento. Ella mi riapparve quale era in realtà: una giovine signora elegantissima, una dolce e nobile figura, piena di finezze fisiche, e illuminata da intense espressioni spirituali; una signora adorabile, insomma, che avrebbe potuto essere un'amante deliziosa per la carne e per lo spirito. "S'ella fosse veramente l'amante di qualcuno?" allora pensai. "Certo è impossibile ch'ella non sia stata molte volte insidiata e da molti. Troppo è noto l'abbandono in cui la lascio; troppo son noti i miei torti. S'ella avesse ceduto a qualcuno? O se anche stesse per cedere? S'ella giudicasse alfine inutile e ingiusto il sacrificio della sua giovinezza? S'ella fosse alfine stanca della lunga abnegazione? S'ella conoscesse un uomo a me superiore, un seduttore delicato e profondo che le insegnasse la curiosità del nuovo e le facesse dimenticare l'infedele? Se io avessi già perduto interamente il suo cuore, troppe volte calpestato senza pietà e senza rimorso?" Uno sgomento subitaneo m'invase; e la stretta dell'angoscia fu così forte che io pensai: "Ecco, ora le confesso il mio dubbio. La guarderò in fondo alle pupille dicendole:--Sei ancora _pura_?--E saprò la verità. Ella non è capace di mentire." "Non è capace di mentire? Ah, ah, ah! Una donna!... Che ne sai tu? Una donna è capace di tutto. Ricordatene. Qualche volta un gran manto eroico è servito a nascondere una mezza dozzina di amanti. Sacrificio! Abnegazione! Apparenze, parole. Chi potrà mai conoscere il vero? Giura, se puoi, su la fedeltà di tua moglie: non dico su quella d'oggi ma soltanto su quella anteriore all'episodio della malattia. Giura in perfetta fede, se puoi." E la voce maligna (ah, Teresa Raffo, come operava il vostro veleno!), la voce perfida mi agghiacciò. --Abbi pazienza, Tullio--mi disse, quasi timidamente, Giuliana.--Mettimi questo spillo qui, nel velo. Ella teneva le braccia alzate e arcuate verso la sommità della testa, per fermare il velo; e le sue dita bianche cercavano invano d'appuntarlo. La sua attitudine era piena di grazia. Le sue dita bianche mi fecero pensare: "Quanto tempo è che noi non ci stringiamo la mano! Oh le forti e calde strette di mano che ella mi dava un tempo, come per assicurarmi che non mi serbava rancore di nessuna offesa! Ora forse la sua mano è impura?" E, mentre le appuntavo il velo, provai una repulsione istantanea al pensiero della possibile impurità. Ella si levò, e io l'aiutai anche a indossare la giacca. Due o tre volte i nostri occhi s'incontrarono fugacemente; ma ancora una volta io lessi nei suoi una specie di curiosità inquieta. Ella forse domandava a sé stessa: "Perchè è entrato qui? Perchè si trattiene? Che significa quella sua aria smarrita? Che vuole da me? Che gli accade?" --Permetti.... un momento--disse, e uscì dalla stanza. L'udii che chiamava miss Edith, la governante. Come fui solo, involontariamente i miei occhi andarono alla piccola scrivania ingombra di lettere, di biglietti, di libri. M'avvicinai; e i miei occhi vagarono per un poco su le carte, come tentati di scoprire.... "che cosa? forse _la prova?_" Ma scossi da me la tentazione bassa e sciocca. Guardai un libro che aveva una coperta di stoffa antica e tra le pagine una daghetta. Era il libro in lettura, sfogliato a metà. Era il romanzo recentissimo di Filippo Arborio, _il Segreto_. Lessi sul frontespizio una dedica, di pugno dell'autore:--_A voi, Giuliana Hermil, _TVRRIS EBVRNEA_, indegnamente offro. F. Arborio. Ognissanti '85_. Giuliana dunque conosceva il romanziere? Quale attitudine aveva lo spirito di Giuliana verso colui? Ed evocai la figura fine e seducente dello scrittore, quale io l'aveva veduta in luoghi publici qualche volta. Certo, egli poteva piacere a Giuliana. Secondo alcune voci che erano corse, egli piaceva alle donne. I suoi romanzi, pieni d'una psicologia complicata, talora acutissima, spesso falsa, turbavano le anime sentimentali, accendevano le fantasie inquiete, insegnavano con suprema eleganza il disdegno della vita comune. _Un'agonia, la Cattolicissima, Angelica Doni, Giorgio Aliora, Il Segreto_ davano della vita una visione intensa come d'una vasta combustione dalle figure di bragia innumerevoli. Ciascuno dei suoi personaggi combatteva per la sua Chimera, in un duello disperato con la realtà. Non aveva questo straordinario artista, che i suoi libri mostravano quasi direi sublimato in essenza spirituale pura, non aveva egli esercitato il suo fascino anche su me? Non avevo io chiamato quel suo _Giorgio Aliora_ un libro "fraterno?" Non avevo io ritrovato in qualcuna delle sue creature letterarie certe strane rassomiglianze col mio essere intimo? E se a punto questa nostra affinità strana gli agevolasse l'opera di seduzione forse intrapresa? "Se Giuliana gli si abbandonasse, avendogli a punto riconosciuta qualcuna di quelle attrazioni medesime per cui io mi feci un tempo da lei adorare?" pensai, con un nuovo sgomento. Ella rientrò nella stanza. Vedendo quel libro tra le mie mani, disse con un sorriso confuso, con un po' di rossore: --Che guardi? --Conosci Filippo Arborio?--io le domandai subito, ma senza alcuna alterazione di voce, con il tono più calmo e più ingenuo ch'io seppi. --Sì,--ella rispose, franca.--Mi fu presentato in casa Monterisi. È venuto anche qualche volta qui, ma non ha avuto occasione d'incontrarti. Una domanda mi salì alle labbra. "E perché tu non me ne hai parlato?" Ma la trattenni. Come avrebbe ella potuto parlarmene, se da molto tempo io col mio contegno aveva interrotto tra noi ogni scambio di notizie e di confidenze amichevoli? --È assai più semplice dei suoi libri--ella soggiunse, disinvolta, mettendosi i guanti con lentezza.--Hai letto _Il Segreto_? --Sì, l'ho già letto. --T'è piaciuto? Senza riflettere, per un bisogno istintivo di rilevare davanti a Giuliana la mia superiorità, io risposi: --No. È mediocre. Ed ella disse al fine: --Io vado. E si mosse per uscire. Io la seguii fino all'anticamera, camminando nel solco del profumo ch'ella lasciava dietro di sé fievolissimo, a pena a pena sensibile. D'avanti al domestico, ella disse soltanto: --A rivederci. E con un passo leggero varcò la soglia. Io tornai alle mie stanze. Apersi la finestra, mi affacciai per veder lei nella strada. Ella andava, col suo passo leggero, sul marciapiede dalla parte del sole: diritta, senza mai volgere il capo da nessuna banda. L'estate di San Martino diffondeva una doratura tenuissima sul cristallo del cielo; e un tepore quieto addolciva l'aria, evocava il profumo assente delle violette. Una tristezza enorme mi piombò sopra, mi tenne abbattuto contro il davanzale; a poco a poco divenne intollerabile. Rare volte nella vita avevo sofferto come per quel dubbio che faceva crollare d'un tratto la mia fede in Giuliana, una fede durata per tanti anni; rare volte la mia anima aveva gridato così forte dietro un'illusione fuggente. Ma dunque era proprio, senza riparo, fuggita? Io non potevo, non volevo persuadermene. Tutta la mia vita d'errore era stata accompagnata dalla grande illusione, che rispondeva non pure alle esigenze del mio egoismo, ma a un mio sogno estetico di grandezza morale. "La grandezza morale risultando dalla violenza dei dolori superati, perché ella avesse occasione d'essere eroica era necessario ch'ella soffrisse quel ch'io le ho fatto soffrire." Questo assioma con cui molte volte ero riuscito a placare i miei rimorsi, s'era profondamente radicato nel mio spirito, generandovi un fantasma ideale dalla parte migliore di me assunto in una specie di culto platonico. Io dissoluto obliquo e fiacco mi compiacevo di riconoscere nel cerchio della mia esistenza un'anima severa diritta e forte, un'anima incorruttibile; e mi compiacevo d'esserne l'oggetto amato, per sempre amato. Tutto il mio vizio, tutta la mia miseria e tutta la mia debolezza si appoggiavano a questa illusione. Io credevo che per me potesse tradursi in realtà il sogno di tutti gli uomini intellettuali:--essere costantemente infedele ad una donna costantemente fedele. "Che cerchi? Tutte le ebrezze della vita? Esci, va, inèbriati. Nella tua casa, come un'imagine velata in un santuario, la creatura taciturna e memore aspetta. La lampada, dove tu non versi mai una stilla d'olio, rimane sempre accesa." Non è questo il sogno di tutti gli uomini intellettuali? Anche: "In qualunque ora, dopo qualunque fortuna, ritornando, tu la ritroverai. Ella era sicura del tuo ritorno ma non ti racconterà la sua attesa. Tu poserai il capo su le sue ginocchia; ed ella ti passerà lungo le tempie l'estremità delle sue dita, per magnetizzare il tuo dolore." Ben un tal ritorno era nel mio presentimento: il ritorno finale, dopo una di quelle catastrofi interne che trasformano un uomo. E tutte le mie disperazioni venivano temperate da un'intima confidenza nell'indefettibile rifugio; e in fondo a tutte le mie abiezioni scendeva un qualche lume dalla donna che per amore di me e _per opera mia_ aveva raggiunto il sommo dell'altezza corrispondendo perfettamente a una forma delle mie idealità. Bastava un dubbio a distruggere ogni cosa in un attimo? Io riandai tutta la scena passata tra me e Giuliana, dal momento del mio ingresso nella stanza al momento della sua uscita. Pur attribuendo gran parte dei miei moti intimi a uno speciale stato nervoso transitorio, non potei dissipare la strana impressione esattamente espressa dalle parole: "Ella mi pareva _un'altra donna_." Certo, una qualche novità era in lei. Ma quale? La dedica di Filippo Arborio non aveva più tosto un significato rassicurante? Non riaffermava a punto l'impenetrabilità della TVRRIS EBVRNEA? L'appellativo glorioso era stato suggerito a colui o semplicemente dalla fama di purezza che avvolgeva il nome di Giuliana Hermil o anche da un tentativo d'assalto fallito e forse da una rinunzia all'assedio intrapreso. La Torre d'avorio doveva essere dunque ancora intatta. Ragionando così per medicare il morso del sospetto, io provavo in fondo a me una vaga ansietà, quasi temessi l'insorgere improvviso d'una qualche obbiezione ironica. "Tu sai: la pelle di Giuliana è straordinariamente bianca. Ella è proprio _pallida come la sua camicia_. L'appellativo sacro potrebbe anche nascondere un significato profano...." Ma quell'_indegnamente_? "Eh, eh, quanti cavilli!" Un impeto iroso d'insofferenza interruppe quel dibattito umiliante e vano. Mi ritrassi dalla finestra, scossi le spalle, feci due o tre giri per la stanza, apersi un libro macchinalmente, lo respinsi. Ma l'ambascia non diminuiva. "In somma" pensai fermandomi come per affrontare un avversario invisibile "tutto questo a che conduce? O ella è già caduta, e la perdita è irreparabile; o ella è in pericolo, e io nel mio stato presente non posso intervenire per salvarla; o ella è pura con la forza di serbarsi pura, e allora nulla è mutato. In ogni caso, io non ho alcuna _azione_ da compiere. Ciò che è, è necessario; ciò che sarà, sarà necessario. Questa crisi di sofferenza passerà. Bisogna aspettare. I crisantemi bianchi sul tavolo di Giuliana, dianzi, com'erano belli! Uscirò per comprarne di simili in gran quantità. Il convegno con Teresa è oggi alle due. Mancano quasi tre ore.... Non mi disse ella, l'ultima volta, che voleva trovare il caminetto acceso? Sarà il _primo fuoco_ d'inverno, in una giornata così tiepida. Ella è in una settimana di bontà, mi pare. Se durasse! Ma io alla prima occasione provocherò Eugenio Egano." Il mio pensiero seguì il nuovo corso, con qualche arresto repentino, con deviamenti improvvisi. Tra le stesse imagini della voluttà prossima mi balenò un'altra imagine impura, quella temuta, quella a cui volevo sfuggire. Alcune pagine ardite e ardenti della _Cattolicissima_ mi tornarono alla memoria. E dall'uno spasimo sorgeva l'altro. E io confondevo, se bene con una diversa sofferenza, nella medesima contaminazione le due donne e nel medesimo odio Filippo Arborio ed Eugenio Egano. La crisi passò, lasciandomi nell'animo una specie di vaga disistima mista di rancore verso la _sorella_. Io mi allontanai sempre più, mi feci sempre più duro, più incurante, più chiuso. La mia trista passione per Teresa Raffo divenne sempre più esclusiva, occupò tutte le mie facoltà, non mi diede un'ora di tregua. Io era veramente un ossesso, un uomo invaso da una diabolica follia, corroso da un morbo ignoto e spaventevole. I ricordi di quell'inverno sono confusi nel mio spirito, incoerenti, interrotti da strane oscurità, rari. In quell'inverno non incontrai mai a casa mia Filippo Arborio; poche volte lo vidi in luoghi publici. Ma una sera lo trovai in una sala d'armi; e là ci conoscemmo, fummo presentati l'uno all'altro dal maestro, scambiammo qualche parola. La luce del gas, il rimbombo del tavolato, il tintinno e il luccichio delle lame, le varie pose incomposte o eleganti degli schermitori, lo scatto rapido di tutte quelle gambe inarcate, l'esalazione calda e acre di tutti quei corpi, i gridi gutturali, le interiezioni veementi, gli scoppi di risa ricompongono con una singolare evidenza nel mio ricordo la scena che si svolgeva intorno a noi mentre eravamo l'uno al conspetto dell'altro e il maestro pronunziava i nostri nomi. Rivedo il gesto con cui Filippo Arborio si levò la maschera mostrando il viso acceso, tutto rigato di sudore. Tenendo da una mano la maschera e dall'altra il fioretto, s'inchinò. Ansava troppo, affaticato e un po' convulso, come chi non ha la consuetudine dell'esercizio muscolare. Istintivamente, pensai ch'egli non era un uomo temibile sul terreno. Affettai anche una certa alterigia; a studio non gli rivolsi né pure una parola che si riferisse alla sua celebrità, alla mia ammirazione; mi contenni come mi sarei contenuto verso un qualunque ignoto. --Dunque--mi chiese il maestro sorridendo--per domani? --Sì, alle dieci. --Vi battete?--fece l'Arborio con una curiosità manifesta. --Sì. Egli esitò un poco; quindi soggiunse: --Con chi?, se non sono indiscreto. --Con Eugenio Egano. M'accorsi ch'egli desiderava di sapere qualche cosa di più, ma che lo tratteneva il mio contegno freddo e in apparenza disattento. --Maestro, un assalto di cinque minuti--io dissi, e mi volsi per andare nello spogliatoio. Giunto su la soglia, mi soffermai a guardare in dietro e scorsi l'Arborio che aveva ripreso a schermire. Un'occhiata mi bastò per conoscere ch'egli era mediocrissimo in quel giuoco. Quando incominciai l'assalto col maestro, sotto gli occhi di tutti i presenti, s'impadronì di me una particolare eccitazione nervosa che raddoppiò la mia energia. E sentivo su la mia persona lo sguardo fisso di Filippo Arborio. Dopo, nello spogliatoio, ci ritrovammo. La stanza troppo bassa era già piena di fumo e d'un odore umano acutissimo, nauseante. Tutti là dentro, nudi, nelle larghe cappe bianche, si strofinavano il petto, le braccia, le spalle, con lentezza, fumando, motteggiando ad alta voce, dando sfogo nel turpiloquio alla loro bestialità. Gli scrosci della doccia si alternavano con le grasse risa. E due o tre volte, con un indefinibile senso di repulsione, con un sussulto simile a quello che mi avrebbe dato un violento urto fisico, io intravidi il corpo smilzo dell'Arborio, a cui i miei occhi andavano involontariamente. E di nuovo l'imagine odiosa si formò. Non ebbi, dopo d'allora, altra occasione d'avvicinare colui e né pure d'incontrarlo. Né me ne curai. Né in séguito fui colpito da alcuna apparenza sospetta nella condotta di Giuliana. Di là dal cerchio sempre più angusto in cui mi agitavo, nulla era per me chiaramente sensibile, intelligibile. Tutte le impressioni estranee passavano sul mio spirito come gocciole d'acqua su una lastra arroventata, o rimbalzando o dissolvendosi. Gli eventi precipitarono. Su lo scorcio di febbraio dopo un'ultima e vergognosa prova, avvenne tra me e Teresa Raffo la rottura definitiva. Io partii per Venezia, solo. Rimasi là circa un mese, in uno stato di malessere incomprensibile; in una specie di stupefazione che le caligini e i silenzii della laguna addensavano. Non altro conservavo in me che il sentimento della mia esistenza isolata, tra i fantasimi inerti di tutte le cose. Per lunghe ore non altro sentivo che la fissità grave, schiacciante, della vita e il piccolo battito di un'arteria nella mia testa. Per lunghe ore mi teneva quel fascino strano che esercita su l'anima come su i sensi il passaggio continuo e monotono di qualche cosa indistinta. Piovigginava. Le nebbie su l'acqua prendevano talvolta forme lugubri, camminando come spettri con un passo lento e solenne. Spesso nella gondola, come in una bara, io trovavo una specie di morte imaginaria. Quando il rematore mi chiedeva in che luogo dovesse condurmi, io facevo quasi sempre un gesto vago; e comprendevo dentro di me la disperata sincerità delle parole: "_Dovunque, fuori del mondo!_" Tornai a Roma negli ultimi giorni di marzo. Avevo della realtà un senso nuovo, come dopo una lunga eclisse della conscienza. Una timidezza, uno smarrimento, una paura senza ragione mi prendevano talvolta all'improvviso; e mi sentivo debole come un fanciullo. Guardavo intorno a me di continuo, con un'attenzione insolita, per riafferrare il significato vero delle cose, per coglierne i giusti rapporti, per rendermi conto di ciò che era mutato, di ciò che era scomparso. E, come a poco a poco rientravo nell'esistenza comune, si ristabiliva nel mio spirito l'equilibrio, si ridestava qualche speranza, risorgeva la cura dell'avvenire. Trovai Giuliana molto abbattuta di forze, alterata nella salute, triste come non mai. Poco parlammo e senza guardarci dentro alle pupille, senza aprire i nostri cuori. Ambedue cercavamo la compagnia delle due bambine; e Maria e Natalia in una felice inconsapevolezza riempivano i silenzii con le loro fresche voci. Un giorno Maria domandò: --Mamma, andremo quest'anno, per Pasqua, alla Badiola? Io risposi, invece della madre, senza esitare: --Sì, andremo. Allora Maria si mise a saltare per la stanza, in segno di gioia, trascinando la sorella. Io guardai Giuliana. --Vuoi che andiamo?--le chiesi, timido, quasi con umiltà. Ella consentì col capo. --Vedo che tu non stai bene--soggiunsi. Anche io non sto bene.... Forse la campagna.... la primavera.... Ella era distesa in una poltrona, tenendo le mani bianche posate lungo i bracciuoli; e la sua attitudine mi ricordò un'altra attitudine: quella della convalescente nel mattino della levata ma dopo l'annunzio. Fu decisa la partenza. Ci preparammo. Una speranza luceva nel profondo della mia anima, e io non osavo mirarla. I. Il primo ricordo è questo. Intendevo, quando ho incominciato il racconto, intendevo: questo è il primo ricordo che si riferisce alla cosa tremenda. Era di aprile, dunque. Eravamo da alcuni giorni alla Badiola. --Ah, figliuoli miei,--aveva detto mia madre, con la sua grande ingenuità--come siete sciupati! Ah quella Roma, quella Roma! Bisogna che restiate qui con me, in campagna, molto tempo, per rimettervi.... molto tempo.... --Sì--aveva detto Giuliana, sorridendo--sì, mamma, resteremo quanto vorrai. Quel sorriso ridivenne frequente su le labbra di Giuliana, in presenza di mia madre; e, se bene la malinconia degli occhi rimanesse inalterabile, era così dolce quel sorriso, era così profondamente buono che io stesso mi lasciai illudere. Ed osai mirare la mia speranza. Nei primi giorni, mia madre non si distaccava mai dalle care ospiti; pareva che volesse saziarle di tenerezza. Due o tre volte io la vidi, palpitando d'una commozione indefinibile, io la vidi accarezzare con la sua mano benedetta i capelli di Giuliana. Una volta la udii che chiedeva: --Ti vuol sempre lo stesso bene? --Povero Tullio! Sì--rispose l'altra voce. --Dunque, non è vero.... --Che? --Quello che mi hanno riferito. --Che ti hanno riferito? --Nulla, nulla.... Credevo che Tullio ti avesse dato qualche dispiacere. Parlavano nel vano di una finestra, dietro le cortine ondeggianti, mentre di fuori stormivano gli olmi. Io mi feci innanzi, prima che s'accorgessero di me; sollevai una cortina, mostrandomi. --Ah, Tullio!--esclamò mia madre. E si scambiarono uno sguardo, un po' confuse. --Parlavamo di te--soggiunse mia madre. --Di me! Male?--chiesi con un'aria gaia. --No, bene--disse Giuliana, subito; e io colsi nella sua voce l'intenzione, ch'ella certo ebbe, di _rassicurarmi_. Il sole d'aprile batteva sul davanzale, riluceva nei capelli grigi di mia madre, svegliava qualche tenue bagliore su le tempie di Giuliana. Le cortine candidissime ondeggiavano, si riflettevano nei vetri luminose. I grandi olmi dello spiazzo, coperti di piccole foglie nuove, producevano un susurro, ora leggero ora forte, alla cui misura le ombre or meno or più si agitavano. Dal muro stesso della casa, ammantato di violacciocche innumerevoli, saliva un profumo pasquale, quasi un vapore invisibile di mirra. --Com'è acuto quest'odore!--mormorò Giuliana, passandosi le dita su i sopraccigli e socchiudendo le palpebre.--Stordisce. Io stavo tra lei e mia madre, un poco in dietro Una voglia mi venne, di chinarmi sul davanzale cingendo l'una e l'altra con le mie braccia. Avrei voluto mettere in quella semplice familiarità tutta la tenerezza che mi gonfiava il cuore e far intendere a Giuliana una moltitudine di cose inesprimibili e riconquistarla intera con quell'unico atto. Ma ancora mi tratteneva un senso di temenza quasi puerile. --Guarda, Giuliana,--disse mia madre, indicando un punto del colle--la tua Villalilla. La scorgi? --Sì, sì. Ella, schermendosi dal sole con la mano aperta, aguzzava la vista; e io, che la osservavo, notai un piccolo tremito nel suo labbro inferiore. --Distingui il cipresso?--le chiesi, volendo aumentare con la domanda suggestiva il suo turbamento. E io rivedevo nella mia imaginazione il vecchio cipresso venerabile che aveva al suo piede un cespo di rose e un coro di passeri alla sua cima. --Sì, sì, lo distinguo.... appena. Villalilla biancheggiava a mezzo dell'altura, molto lontana, in un pianoro. La catena dei colli si svolgeva d'innanzi a noi con un lineamento nobile e pacato, per ove gli oliveti avevano un'apparenza di straordinaria leggerezza somigliando a un vapore verdegrigio cumulato in forme costanti. Gli alberi in fiore, bianchi e rosei trionfi, interrompevano l'uguaglianza. Il cielo pareva di continuo impallidire, come se nella sua liquidità un latte di continuo si diffondesse e si dileguasse. --Andremo a Villalilla dopo Pasqua. Sarà tutta fiorita--io dissi, tentando di rimettere in quell'anima il sogno che le avevo strappato brutalmente. E osai accostarmi, cingere con le mie braccia Giuliana e mia madre, chinarmi sul davanzale tenendo la mia testa tra l'una e l'altra testa; in modo che i capelli dell'una e dell'altra mi sfioravano. La primavera, quella bontà dell'aria, quella nobiltà dei luoghi, quella placida trasfigurazione di tutte le creature per una virtù materna, e quel cielo divino pel suo pallore, più divino come più si faceva pallido, mi davano un senso di vita così nuovo che io pensai tremando dentro di me: "Ma è possibile? Ma è possibile? Ma dunque, dopo tutto quel che è accaduto, dopo tutto quel che ho sofferto, dopo tante colpe, dopo tante vergogne, io posso ancora trovare nella vita questo sapore! Io posso ancora _sperare_, posso ancora avere il presentimento di una felicità! Chi dunque mi ha benedetto?" Pareva che tutto il mio essere si alleggerisse, espandendosi, dilatandosi oltre i suoi confini, con una vibrazione sottile, rapida e incessante. Nulla può dare un'idea di ciò che diveniva in me la sensazione minima prodotta da un capello che mi sfiorava la guancia. Rimanemmo alcuni minuti in quell'attitudine, senza parlare. Gli olmi stormivano. Il tremolio innumerevole dei fiori gialli e violacei, che ammantavano il muro sotto la finestra, incantava le mie pupille. Un profumo denso e caldo saliva nel sole, col ritmo di un alito. A un tratto, Giuliana si sollevò, si ritirò, smorta, con qualche cosa di torbido negli occhi, con la bocca sforzata come da una nausea, dicendo: --Quest'odore è terribile. Da il capogiro. Mamma, non fa male anche a te? E si volse per andarsene; diede qualche passo incerto, vacillante; poi si affrettò, uscì dalla stanza, seguita da mia madre. Io le guardai allontanarsi per la fuga delle porte, ancora tenuto da un resto della sensazione primitiva, trasognato. II. La mia confidenza nell'avvenire aumentava di giorno in giorno. Non mi ricordavo quasi più di nulla. La mia anima troppo affaticata si dimenticava di soffrire. In certe ore di completo abbandono tutto si dileguava, si distendeva, si fondeva, si immergeva nella fluidità originale, diveniva irriconoscibile. Poi, dopo questi strani dissolvimenti ulteriori, mi pareva che un altro principio di vita entrasse in me, che un'altra forza mi possedesse. Una moltitudine di sensazioni involontarie, spontanee, inconscienti, istintive componeva la mia esistenza reale. Tra l'esterno e l'interno si stabiliva un giuoco di minime azioni e di minime reazioni istantanee che fremevano in infinite ripercussioni; e ciascuna di queste ripercussioni incalcolabili si convertiva in un fenomeno psichico stupendo. Tutto il mio essere veniva alterato da ciò che passava nell'aria, da un soffio, da un'ombra, da un bagliore. Le grandi malattie dell'anima come quelle del corpo rinnovellano l'uomo; e le convalescenze spirituali non sono meno soavi e meno miracolose di quelle fisiche. D'avanti a un arbusto fiorito, d'avanti a un ramo coperto di minute gemme, d'avanti a un rampollo nato su un vecchio tronco quasi estinto, d'avanti alla più umile fra le grazie della terra, alla più modesta tra le trasfigurazioni della primavera, io mi soffermavo, semplice, candido, attonito! Uscivo spesso con mio fratello, al mattino. In quell'ora tutto era fresco, facile, libero. La compagnia di Federico mi purificava e mi fortificava come la buona brezza selvaggia. Aveva allora ventisette anni Federico; aveva vissuto quasi sempre nella campagna, d'una vita sobria e laboriosa; pareva portare in sè raccolta la mite sincerità terrestre. Egli possedeva la Regola. Leone Tolstoi, baciandolo su la bella fronte serena, lo avrebbe chiamato suo figliuolo. Andavamo per i campi senza meta, di rado ragionando. Egli lodava la fertilità dei nostri dominii, mi spiegava le innovazioni introdotte nelle culture, mi mostrava i miglioramenti. Le case dei nostri contadini erano larghe, ariose, linde. Le nostre stalle erano piene di un bestiame sano e ben pasciuto. Le nostre cascine erano in un ordine perfetto. Spesso, nel cammino, egli s'arrestava per osservare una pianta. Le sue mani virili erano di una delicatezza estrema quando toccavano le piccole foglie verdi in cima ai rametti novelli. Talvolta passavamo attraverso un frutteto. I peschi, i peri, i meli, i ciliegi, i prugni, gli albicocchi portavano su le loro braccia milioni di fiori; giù per la trasparenza dei petali rosei ed argentei, la luce si cangiava quasi direi in una umidità divina, in una cosa indescrivibilmente vaga e benigna; tra i minimi intervalli delle ghirlande leggere, il cielo aveva la vivente dolcezza di uno sguardo. Egli diceva, imaginando il pensile tesoro futuro, mentre io lodavo i fiori: --Vedrai, vedrai i frutti. "Io li vedrò" ripetevo dentro di me. "Vedrò cadere i fiori, nascere le foglie, crescere i frutti, colorirsi, maturarsi, distaccarsi." Questa assicurazione, già passata per la bocca di mio fratello, aveva per me un'importanza grave, come se si riferisse a non so quale felicità promessa e attesa, la quale a punto dovesse svolgersi in quel periodo del parto arboreo, nel tempo che corre tra il fiore e il frutto. "Prima che io abbia manifestato il mio proposito, a mio fratello par già naturale che io rimanga omai qui, nella campagna, con lui, con nostra madre; poiché egli dice che io vedrò i frutti dei suoi alberi. Egli è _sicuro_ che io li vedrò! Dunque è proprio vero che è ricominciata una vita nuova per me, e che questo sentimento ch'io ho dentro di me non m'inganna. In fatti, tutto ora si compie con una facilità strana, insolita, con un'abbondanza d'amore. Come amo Federico! Non l'ho mai amato così." Tali erano i miei soliloquii interiori, un po' slegati, incoerenti, qualche volta puerili per una singolare disposizione d'animo che mi portava a vedere in qualunque fatto insignificante un segno favorevole, un pronostico benigno. Il gaudio mio più intenso era nel sapermi lontano dalle cose passate, lontano da certi luoghi, da certe persone, inaccessibile. Assaporavo talvolta la pace della campagna primaverile raffigurandomi lo spazio che mi divideva dal mondo oscuro dove io avevo tanto sofferto e di dolori tanto cattivi. Una paura indefinita mi stringeva ancora, talvolta, e mi faceva cercare con sollecitudine intorno a me le prove della sicurtà presente, mi spingeva a mettere il braccio sotto il braccio di mio fratello, a leggere negli occhi di lui l'affetto indubitabile e tutelare. Io confidavo in Federico, ciecamente. Avrei voluto essere da lui non soltanto amato ma dominato; avrei voluto cedere la primogenitura a lui più degno e star sommesso al suo consiglio, riguardarlo come la mia guida, obedirgli. Al suo fianco non avrei più corso il pericolo di smarrirmi, poiché egli conosceva la via diritta e camminava per quella con un passo infallibile; ed egli anche aveva il braccio possente e mi avrebbe difeso. Era l'uomo esemplare: buono, forte, sagace. Nulla per me uguagliava in nobiltà lo spettacolo di quella giovinezza devota alla religione del "conscientemente bene operare", dedicata all'amore della Terra. Parevano i suoi occhi aver assunto un limpido color vegetale dalla contemplazione assidua delle cose verdi. --Gesù della Gleba--io lo chiamai un giorno, sorridendo. Era un mattino pieno d'innocenza, uno di quei mattini che danno imagine delle albe primordiali nell'infanzia della Terra. Sul limite di un campo, mio fratello parlava a un gruppo di agricoltori. Parlava in piedi, avanzando di tutto il corpo gli astanti; e il suo gesto calmo dimostrava la semplicità delle sue parole. Uomini vecchi incanutiti nella saggezza, uomini maturi già prossimi al limitare della vecchiaia ascoltavano quel giovine. Tutti portavano su i loro corpi nodosi la traccia della grande comune opera. Poiché nessun albero era da presso, poiché il frumento era umile nei solchi, le loro attitudini apparivano integre nella santità della luce. Come mi vide muovere verso di lui, mio fratello licenziò i suoi uomini per venirmi incontro. Allora spontanea mi uscì dalle labbra la salutazione: --Gesù della Gleba, osanna! Egli aveva per tutti gli esseri vegetali una diligenza infinita. Nulla sfuggiva alle sue pupille acute, quasi onniveggenti. Nelle nostre corse mattutine, si soffermava ad ogni tratto per liberare da una chiocciola, da un bruco, da una formica una piccola foglia. Un giorno, senza badarci, camminando, battevo le erbe con la punta del bastone; e le teneri cime verdi recise ad ogni colpo s'involavano. Egli ne soffriva perchè mi tolse di mano il bastone ma con un gentile atto; ed arrossì, pensando forse che quella sua misericordia mi sarebbe parsa una esagerata morbidezza sentimentale. Oh quel rossore su quel volto così maschio! Un altro giorno, mentre spezzavo a un melo qualche ramo fiorito, sorpresi nelli occhi di Federico un'ombra di rammarico. Subito tralasciai, ritrassi le mani, dicendo: --Se ti dispiace..... Egli si mise a ridere forte. --Ma no, ma no.... Spoglia pure tutto l'albero. Intanto il ramo già rotto, ritenuto da alcune delle sue vive fibre, penzolava lungo il fusto; e, proprio, quella frattura umida di linfa aveva un aspetto di cosa dolente; e quei fiori esili, un po' carnicini, un po' bianchi, simili a ciocche di rose scempie, che portavano un germe omai condannato, avevano all'aria un tremolio incessante. Io dissi allora, come ad attenuare la crudezza di quella manomessione: --È per Giuliana. E, strappando le ultime fibrille vive, distaccai il ramo già rotto. III. Non quel ramo solo portai a Giuliana, ma molti altri. Tornavo alla Badiola sempre carico di doni floreali. Una mattina, avendo su le braccia un fascio di spine albe, incontrai nel vestibolo, mia madre. Ero un poco ansante, accaldato, agitato da una leggera ebrezza. Domandai: --Dov'è Giuliana? --Su, nelle sue stanze,--ella rispose, ridendo. Io feci di corsa le scale, attraversai il corridoio, entrai franco nell'appartamento, chiamai: --Giuliana, Giuliana! Dove sei? Maria e Natalia mi uscirono in contro con grandi feste, rallegrate alla vista dei fiori, irrequiete, folli. --Vieni, vieni,--mi gridarono--la mamma è qui, nella camera da letto. Vieni. E io varcai quella soglia palpitando più forte; mi trovai alla presenza di Giuliana sorridente e confusa: le gittai il fascio ai piedi. --Guarda! --Oh, che cosa bella!--esclamò, chinandosi sul fresco tesoro odorante. Portava una delle sue ampie tuniche preferite, d'un verde eguale al verde d'una foglia d'aloe. Non ancora pettinati, i suoi capelli erano mal trattenuti dalle forcine; le coprivano la nuca, le nascondevano gli orecchi, in dense matasse. L'effluvio della spina, un color misto di timo e di mandorla amara, la investiva tutta, si diffondeva per la camera. --Bada di non pungerti--io le dissi.--Guarda le mie mani. E le mostrai le scalfitture ancora sanguinanti, come per rendere più meritoria l'offerta. "Oh se ella ora mi prendesse le mani" pensai. E mi passò su lo spirito, vago, il ricordo di un giorno lontanissimo in cui ella mi aveva baciate le mani scalfite dalle spine e aveva voluto suggere le stille di sangue che spuntavano l'una dopo l'altra. "Se ella ora mi prendesse le mani e in questo solo atto mettesse tutto il suo perdono e tutto il suo abbandono!" Io avevo di continuo, in quei giorni, l'aspettazione d'un momento simile. Non sapevo veramente da che mi venisse una tal fiducia; ma ero sicuro che Giuliana si sarebbe ridonata a me, così, o prima o poi, con un solo semplice atto silenzioso in cui ella avrebbe saputo mettere "tutto il suo perdono e tutto il suo abbandono". Ella sorrise. Un'ombra di sofferenza apparve sul suo volto troppo bianco, ne' suoi occhi troppo incavati. --Non ti senti un poco meglio, da che sei qui?--le domandai accostandomi. --Sì, sì, meglio--ella rispose. Dopo una pausa: --E tu? --Oh, io sono già guarito. Non vedi? --Sì, è vero. Quando mi parlava, in quei giorni, mi parlava con una esitazione singolare che per me era piena di grazia ma che ora m'è impossibile definire. Pareva quasi ch'ella fosse di continuo occupata a trattenere la parola che le saliva alle labbra, per pronunziarne una diversa. Inoltre, la sua voce era, se si può dir così, più feminile; aveva perduta la primitiva fermezza e una parte di sonorità; s'era velata come quella d'uno strumento con la sordina. Ma, essendo ella dunque verso di me in tutte le sue espressioni tanto mite, che cosa ancora c'impediva di stringerci? Che cosa manteneva ancora tra lei e me quell'intervallo? In quel periodo che rimarrà nella storia della mia anima sempre misterioso, la mia nativa perspicacia sembrava interamente abolita. Tutte le mie terribili facoltà analitiche, quelle stesse che mi avevano dato tanti spasimi, sembravano esauste. La potenza delle facoltà inquiete pareva distrutta. Innumerevoli sensazioni, innumerevoli sentimenti di quel tempo mi riescono ora incomprensibili, inesplicabili, perché non ho alcuna guida per rintracciarne l'origine, per determinarne la natura. Una discontinuità, un difetto di fusione, è tra quel periodo della mia vita psichica e gli altri. Udii una volta raccontare, nel corso di una favola, che un giovine principe, dopo un lungo pellegrinaggio avventuroso, giunse infine al cospetto della donna che egli aveva con tanto ardore cercata. Tremava di speranza il giovine, mentre la donna gli sorrideva da vicino. Ma un velo rendeva intangibile la donna sorridente. Era un velo d'ignota materia, così tenue che si confondeva con l'aria; eppure il giovine non potè stringere l'amata a traverso un tal velo. Questa imaginazione mi aiuta un poco a rappresentarmi il singolare stato in cui mi trovavo allora, a riguardo di Giuliana. Io sentivo che qualche cosa, inconoscibile, manteneva ancora tra lei e me l'intervallo. Ma, nel tempo medesimo, confidavo nel "semplice atto silenzioso" che, o prima o poi, doveva distruggere l'ostacolo e rendermi felice. Come mi piaceva intanto la camera di Giuliana! Era tappezzata d'un tessuto chiaro, un po' invecchiato, a fiorami assai sbiaditi, e aveva un'alcova profonda. Come la profumavano le spine albe! Ella disse, troppo bianca: --È acuto questo odore. Dà alla testa. Non lo senti? E andò verso una finestra per aprirla. Poi soggiunse: --Maria, chiama miss Edith. La governante comparve. --Edith, vi prego, portate questi fiori nella stanza del pianoforte. Metteteli nei vasi. Badate di non pungervi. Maria e Natalia vollero portare una parte del fascio. Rimanemmo soli. Ella andò ancora verso la finestra; si appoggiò al davanzale, volgendo le spalle alla luce. Io dissi: --Hai qualche cosa da fare? Vuoi che me ne vada? --No, no. Resta pure. Siediti. Raccontami la tua passeggiata di stamani. Fin dove sei giunto? Ella pronunziò queste frasi con un po' di precipitazione. Come il parapetto era all'altezza delle reni, ella teneva sul davanzale i gomiti; e il suo busto s'inclinava indietro, entrando nel rettangolo della finestra. La faccia, rivolta verso di me in pieno, si empiva d'ombra, specialmente nel cavo degli occhi; ma i capelli, ricevendo in sommo la luce, formavano una esigua aureola; gli omeri anche in sommo si rischiaravano. Un piede, su cui più premeva il peso del corpo, avanzava l'estremità della veste, mostrando un po' della calza cinerina e la babbuccia brillante. Tutta la figura, in quell'attitudine, in quella luce, aveva una straordinaria forza di seduzione. Un lembo di paesaggio turchiniccio e voluttuoso, tra l'uno e l'altro stipite, sfondava pel vano, dietro quella testa. Allora fu che, d'improvviso, come per una rivelazione fulminea, io rividi in lei la donna desiderabile e nel mio sangue si riaccesero il ricordo e il desiderio delle carezze. Io le parlavo guardandola fissamente. Come più la guardavo, più mi sentivo turbare; ed ella certo doveva leggere nel mio sguardo, perché l'inquietudine in lei si fece palese. Io pensai con un'acuta ansietà ulteriore: "Se ardissi? Se m'avanzassi fino a lei e la prendessi fra le mie braccia?" Anche la franchezza apparente che io cercavo di mettere nei miei discorsi leggeri, m'abbandonò. Mi confusi. Quel disagio divenne insostenibile. Giungevano dalle stanze contigue le voci di Maria, di Natalia e di Edith, indistinte. Io mi levai, m'accostai alla finestra, mi misi a fianco di Giuliana, fui sul punto di chinarmi verso di lei per proferire al fine le parole già tante volte ripetute dentro di me in colloqui imaginarii. Ma il timore di una interruzione probabile mi trattenne. Pensai che quel momento era forse inopportuno, che non avrei avuto forse il tempo di dirle tutto, di aprirle tutto il mio cuore, di raccontarle la mia vita interna delle ultime settimane, la misteriosa convalescenza della mia anima, il risveglio delle mie fibre più tenere, la rifioritura de' miei sogni più gentili, la profondità del mio sentimento nuovo, la tenacità della mia speranza. Pensai che non avrei avuto il tempo di raccontarle i minuti episodii recenti, quelle piccole confessioni ingenue, deliziose all'orecchio della donna che ama, fresche di verità, più persuasive di qualunque eloquenza. Io dovevo infatti riuscire a persuaderla d'una grande e forse per lei incredibile cosa, dopo tante delusioni: riuscire a persuaderla che questo mio ritorno non era ingannevole, ma sincero, definitivo, necessitato da un bisogno vitale di tutto il mio essere. Ella, certo, diffidava ancora; certo, in questo suo diffidare stava la ragione del suo ritegno. Ancora fra noi s'intrapponeva l'ombra d'un atroce ricordo. Io dovevo scacciare quell'ombra, ricongiungere la mia anima a quella di lei così strettamente che nulla più potesse intrapporsi. E questo doveva accadere in un'ora favorevole, in un luogo segreto, silenzioso, abitato soltanto dalle memorie: a Villalilla. Noi tacevamo, intanto, ambedue nel vano della finestra, l'uno a fianco dell'altra. Giungevano dalle stanze contigue le voci di Maria, di Natalia e di Edith, indistinte. Il profumo delle spine albe era vanito. Le tende che pendevano dall'arco dell'alcova lasciavano intravedere il letto nel fondo, ove i miei occhi andavano spesso, curiosi della penombra, quasi cupidi. Giuliana aveva chinato il capo, perché sentiva anch'ella forse il peso dolce e angoscioso del silenzio. Il vento leggero le agitava su la tempia una ciocca libera. L'irrequietudine di quella ciocca scura, un po' lionata, ove anzi qualche filo alla luce diveniva oro su quella terapia pallida come un'ostia, mi faceva languire. E, guardando, io rividi sul collo il piccolo segno fosco da cui tante volte in altri tempi era partita la favilla della tentazione. Allora, non potendo più reggere, con un misto di temenza e di ardire, levai la mano per ravviare quella ciocca; e le mie dita tremanti di su i capelli sfiorarono l'orecchio, il collo, ma a pena a pena, con la più tenue delle carezze. --Che fai?--disse Giuliana, scossa da un sussulto, volgendomi uno sguardo smarrito, tremando più di me forse. E si scostò dalla finestra; sentendosi seguire, diede qualche passo come di fuga, perdutamente. --Ah perché, perché questo, Giuliana?--esclamai, fermandomi. Ma subito dopo: --É vero: non sono ancora degno. Perdonami! In quel punto le due campane della cappella incominciarono a squillare. E Maria e Natalia si precipitarono nella camera, verso la madre, gridando di gioia; e, l'una dopo l'altra, le s'appesero al collo e le coprirono il viso di baci; e dalla madre passarono a me, e io le sollevai, l'una dopo l'altra, nelle mie braccia. Le due campane squillavano a furia; tutta la Badiola pareva invasa dal fremito del bronzo. Era il Sabato Santo, l'ora della Risurrezione. IV. Nel pomeriggio di quel medesimo sabato, ebbi un accesso di tristezza singolare. Era giunta la posta alla Badiola; e io e mio fratello, nella sala del bigliardo, davamo una scorsa ai giornali. Per caso mi venne sotto gli occhi il nome di Filippo Arborio, citato in una cronaca. Un turbamento subitaneo s'impadronì di me. Così un lieve urto solleva il fondiglio in un vaso chiarito. Mi ricordo: era un pomeriggio nebuloso, illuminato come da uno stanco riverbero biancastro. Fuori, innanzi alla vetrata che dava su lo spiazzo, passarono Giuliana e mia madre, l'una a braccio dell'altra, conversando. Giuliana portava un libro; e camminava con un'aria stracca. Con la inconseguenza delle imagini che si svolgono nel sogno, si risollevarono nel mio spirito alcuni frammenti della vita passata: Giuliana avanti allo specchio, nel giorno di novembre; il mazzo dei crisantemi bianchi; la mia ansietà nell'udire l'aria di Orfeo; le parole scritte sul frontespizio del _Segreto_; il colore dell'abito di Giuliana; il mio dibattito alla finestra; il volto di Filippo Arborio, grondante di sudore; la scena dello spogliatoio, nella sala d'armi. Io pensai con un fremito di paura, come uno che si trovi d'improvviso inclinato su l'orlo di una voragine: "Potrei dunque non salvarmi?" Sopraffatto dall'ambascia, avendo bisogno d'esser solo per guardare dentro di me, per guardare in faccia la mia paura, io salutai mio fratello, uscii dalla sala, andai nelle mie stanze. Il mio turbamento era misto d'impazienza irosa. Io ero come uno che, in mezzo al benessere d'una guarigione illusoria, nella ricuperata sicurtà della vita, senta a un tratto il morso del male antico, si accorga di portare ancora nella sua carne il male inestirpabile e sia costretto ad osservarsi, a sorvegliarsi, per convincersi dell'orrenda verità. "Potrei dunque non salvarmi? E perché?" Nello strano oblio che tutte le cose passate aveva sommerso, in quella specie di oscuramento che pareva aver invaso un intero strato della mia conscienza, anche il dubbio contro Giuliana, l'odioso dubbio s'era perduto, s'era disciolto. Troppo grande bisogno aveva la mia anima di cullarsi nell'illusione, di credere e di sperare. La mano santa di mia madre, accarezzando i capelli di Giuliana, aveva per me riaccesa intorno a quel capo l'aureola. Per uno di quelli abbagli sentimentali frequenti nei periodi di debolezza, vedendo le due donne respirare nel medesimo cerchio con una concordia così dolce, io le avevo confuse in una medesima irradiazione di purità. Ora, un piccolo fatto casuale, un semplice nome letto per caso in un diario, il risveglio d'un ricordo torbido erano bastati a sconvolgermi, a sbigottirmi, a spalancarmi d'innanzi un abisso; nel quale io non osavo gittare uno sguardo risoluto e profondo, perché il mio sogno di felicità mi tratteneva, mi tirava in dietro, attaccato a me tenacemente. Ondeggiai prima in un'angoscia fosca, indefinibile, su cui passavano a quando a quando i bagliori temuti. "É possibile ch'ella non sia pura. E allora?--Filippo Arborio o un altro.... Chi sa!--Conoscendo la colpa potrei perdonare?--Che colpa? Che perdono? Tu non hai il diritto di giudicarla, tu non hai il diritto di alzare la voce. Troppe volte ella ha taciuto; questa volta dovresti tu tacere.--E la felicità?--Sogni tu la felicità tua o quella di entrambi? Quella di entrambi, certo, perché un semplice riflesso della _sua_ tristezza oscurerebbe qualunque tua gioia. Tu supponi che, essendo tu contento, ella sarebbe anche contenta: tu col tuo passato di licenza continua, ella col suo passato di continuo martirio. La felicità che tu sogni riposa tutta su l'abolizione del passato. Perché dunque, se ella veramente non fosse pura, non potresti tu mettere il velo o la pietra su la sua colpa come su la tua? Perché dunque, volendo far dimenticare, non dimenticheresti? Perché dunque, volendo essere un uomo nuovo, disgiunto completamente dal passato, non potresti considerar lei come una donna nuova, nelle condizioni medesime? Una tale ineguaglianza sarebbe forse la peggiore delle tue ingiustizie.--Ma l'Ideale? Ma l'Ideale? La mia felicità sarebbe allora possibile quando io potessi riconoscere in Giuliana assolutamente una creatura superiore, impeccabile, degna di tutta l'adorazione; e nel sentimento intimo di questa superiorità, nella conscienza della sua propria grandezza morale ella a punto troverebbe la massima parte della felicità sua. Io non potrei astrarre dal mio passato né dal suo, perché questa particolare felicità non potrebbe essere senza la nequizia della mia vita anteriore e senza quell'eroismo invitto e quasi sovrumano d'avanti al cui fantasma la mia anima è rimasta sempre china.--Ma sai tu quanto ci sia d'egoismo in questo tuo sogno e quanto d'elevazione ideale? Meriti tu forse la felicità, questo alto premio? Per quale privilegio? Così dunque il tuo lungo errore ti avrebbe condotto non alla espiazione ma alla ricompensa...." Io mi scossi, per interrompere il dibattito. "In fine, non si tratta se non di un antico dubbio, assai vago, ora risorto per caso. Questo turbamento irragionevole si dileguerà. Io do consistenza a un'ombra. Fra due, fra tre giorni, dopo Pasqua, andremo a Villalilla; e là io saprò, io sentirò indubitabilmente il vero.--Ma quella profonda, inalterabile malinconia ch'ella porta negli occhi non è _sospetta_? Quella sua aria smarrita, quella nube d'un pensiero continuo che le pesa tra ciglio e ciglio, quella stanchezza immensa che rivelano certe sue attitudini, quell'ansietà ch'ella non riesce a dissimulare quando tu ti avvicini, non sono _sospette_?" Tali ambigue apparenze potevano anche spiegarsi in un senso favorevole. Però, sopraffatto da un'onda di dolore più violenta, io mi levai e andai verso la finestra col desiderio istintivo d'immergermi nello spettacolo esterno per trovarvi una rispondenza allo stato del mio spirito o una rivelazione o una pacificazione. Il cielo era tutto bianco, simile a una compagine di veli sovrapposti in mezzo a cui l'aria circolasse producendo larghe e mobili pieghe. Qualcuno di quei veli pareva a quando a quando distaccarsi, avvicinarsi alla terra, quasi radere la cima degli alberi, lacerarsi, ridursi in lembi cadenti, tremolare a fior del suolo, vanire. Le linee dalle alture si volgevano indeterminate verso il fondo, si scomponevano, si ricomponevano, in lontananze illusorie, come un paese in un sogno, senza realità. Un'ombra plumbea occupava la valle, e l'Assòro dalle rive invisibili l'animava de' suoi luccicori. Quel fiume tortuoso, luccicante in quel golfo d'ombra, sotto quel continuo dissolvimento lento del cielo, attirava lo sguardo, aveva per lo spirito il fascino delle cose simboliche, parendo portare in sé la significazione occulta di quello spettacolo indefinito. Il mio dolore perse a poco a poco l'acredine, divenne pacato, eguale. "Perché aspirare con tanta bramosia alla felicità, non essendone degno? Perché poggiare tutto l'edifizio de la vita futura su un'illusione? Perché credere con una fede così cieca in un privilegio inesistente? Forse tutti gli uomini, vivendo, incontrano un punto decisivo in cui ai più sagaci è dato di comprendere _quale dovrebbe essere la loro vita_. Tu già ti trovasti in quel punto. Ricòrdati dell'istante in cui la mano bianca e fedele, che portava l'amore, l'indulgenza, la pace, il sogno, l'oblio, tutte le cose belle e tutte le cose buone, tremò nell'aria verso di te _come per l'offerta suprema_...." Il rammarico mi gonfiò di lacrime il cuore. Appoggiai i gomiti sul davanzale, mi presi la testa fra le palme; guardando fiso il meandro del fiume in fondo alla valle plumbea, mentre la compagine del cielo si dissolveva senza posa, restai qualche minuto sotto la minaccia d'un castigo imminente, sentii sovra di me pendere una sventura ignota. Come mi giunse dalla stanza sottoposta il suono del pianoforte, inaspettato, la greve oppressione disparve a un tratto; e mi agitò un'ansia confusa in cui tutti i sogni, tutti i desiderii, tutte le speranze, tutti i rimpianti, tutti i rimorsi, tutti i terrori si rimescolarono con una rapidità inconcepibile, soffocantemente. Riconobbi la musica. Era una _Romanza senza parole_ che Giuliana prediligeva e che miss Edith sonava spesso; era una di quelle melodie velate ma profonde in cui pare che l'Anima rivolga alla Vita con accenti sempre diversi una medesima domanda: "Perché hai delusa la mia aspettazione?" Cedendo a un impulso quasi istintivo, uscii sollecito, attraversai il corridoio, scesi le scale, mi fermai d'innanzi alla porta d'onde veniva il suono. La porta era socchiusa; m'insinuai senza far rumore; guardai per l'apertura delle tende. Giuliana era là?--I miei occhi non videro nulla, da prima impregnati di luce, finchè non s'adattarono alla penombra ma mi ferì il profumo acuto delle spine albe, quell'odor misto di timo e di mandorla amara, fresco come un latte selvaggio. Guardai. La stanza era a pena illuminata dal chiarore verdognolo che scendeva di tra le stecche delle gelosie. Miss Edith era sola, d'avanti alla tastiera; e seguitava la sua musica, senza accorgersi di me. La cassa dell'istrumento riluceva nella penombra; i rami delle spine biancheggiavano. In quella quiete raccolta, in quel profumo effuso da rami che mi ricordavano la buona ebrezza matutina e il sorriso di Giuliana e il mio tremito, la romanza mi parve sconsolata come non mai. Dov'era Giuliana? Era risalita? Era ancora fuori?--Mi ritrassi; discesi le altre scale; attraversai il vestibolo senza incontrare nessuno. Avevo un bisogno indomabile di cercarla, di vederla; pensavo che forse il suo solo aspetto mi avrebbe ridata la calma, mi avrebbe ridata la confidenza. Come uscii su lo spiazzo, scorsi Giuliana sotto gli olmi in compagnia di Federico. Ambedue mi sorrisero. Disse mio fratello, sorridendo, quando fui da presso: --Parlavamo di te. Giuliana crede che tu ti stancherai presto della Badiola.... E i nostri progetti, allora? --No, Giuliana _non sa_--io risposi, sforzandomi di riprendere la mia disinvoltura consueta.--Ma tu vedrai. Sono, invece, così stanco di Roma.... e di tutto il resto! Guardavo Giuliana. E una mirabile mutazione avvenne nel mio interno, poichè le tristi cose, che fino a quel minuto mi avevano oppresso, ora precipitavano al fondo, si oscuravano, si dileguavano, cedevano il luogo al sentimento salutare che il solo aspetto di lei e di mio fratello bastava a suscitarmi. Ella era seduta, un po' abbandonata su sé stessa, tenendo su le ginocchia un libro che io riconobbi, il libro che io le avevo dato pochi giorni innanzi: _La Guerra e la Pace_. Tutto in lei, veramente, nell'attitudine e nello sguardo era dolce ed era buono. E nacque in me qualche cosa di simile al sentimento che avrei forse provato se io avessi veduto in quel medesimo luogo, sotto gli olmi famigliari che perdevano i loro fiori morti, Costanza adulta, la povera sorella, al fianco di Federico. Gli olmi piovevano i loro fiori innumerevoli, ad ogni fiato. Era, nella luce bianca, una discesa continua, lentissima di pellicole diafane, quasi impalpabili, che s'indugiavano nell'aria, esitavano, tremolavano come alette di libellule, tra verdognole e biondicce, dando alla vista per quella continuità e per quella labilità una sensazione quasi allucinante. Giuliana le riceveva su le ginocchia, su le spalle; di tratto in tratto faceva un debole gesto per toglierne qualcuna che rimaneva presa nei capelli delle tempie. --Ah, se Tullio rimarrà alla Badiola--diceva Federico rivolto a lei--faremo grandi cose. Promulgheremo le nuove leggi agrarie; gitteremo le basi della nuova constituzione agraria.... Sorridi? Avrai anche tu una parte nella nostra opera. Ti affideremo l'esercizio di due o tre precetti del nostro Decalogo. Anche tu lavorerai. A proposito, Tullio, quando cominceremo questo noviziato? Tu hai le mani troppo bianche. Eh, le punture di certe spine non bastano.... Parlava gaiamente, con quella sua voce limpida e forte che trasfondeva subito in chi l'udiva un senso di sicurtà e di fidanza. Parlava dei suoi disegni vecchi e nuovi, intorno alla interpretazione della legge cristiana primitiva sul lavoro alimentario, con una gravità di pensiero e di sentimento, temperata da quella gaiezza gioviale, che era come un velo di modestia spiegato da lui medesimo contro la meraviglia e l'elogio di chi l'udiva. Tutto in lui appariva semplice, facile, spontaneo. Questo giovine, per la sola forza del suo spirito illuminato dalla sua bontà nativa, già da alcuni anni aveva intuita la teoria sociale inspirata a Leone Tolstoi dal _moujik_ Timoteo Bondareff. In quel tempo egli non conosceva neppure _La Guerra e la Pace_, il gran libro, apparso allora allora nell'Occidente. --Ecco un libro per te--io gli dissi, prendendo il volume di su le ginocchia di Giuliana. --Sì; tu me lo darai. Lo leggerò. --A te piace?--chiese a Giuliana. --Sì, molto. È triste e consolante, insieme. Amo già Maria Bolkonsky, e anche Pietro Besoukhow.... Io mi posi accanto a lei, sul sedile. Mi pareva di non pensare a nulla, di non avere pensieri ben definiti; ma la mia anima vigilava e meditava. Un contrasto palese era tra il sentimento dell'ora, delle cose circostanti, e il sentimento rappresentato dai discorsi di Federico, da quel libro, dai nomi dei personaggi che Giuliana amava. L'ora fluiva lenta e molle, quasi accidiosa, in quel confuso vapore biancastro dove gli olmi a poco a poco si disfioravano. Giungeva fioco il suono del pianoforte, e inintelligibile, aumentando la malinconia della luce, quasi cullando la sonnolenza dell'aria. Senza più ascoltare, assorto, io apersi quel libro, lo sfogliai qua e là, scorsi il principio di qualche pagina. M'avvidi che qualche pagina era piegata all'angolo, come per ricordo; qualche altra era solcata da un colpo d'unghia sul margine, secondo la nota consuetudine della lettrice. Volli leggere, allora, curioso, quasi ansioso. Nella scena tra Pietro Besoukhow e il vecchio incognito, alla posta di Torjok, molte frasi erano segnate. ".... La tua vista spirituale si ripieghi sul tuo essere interiore. Domanda a te stesso se tu sei contento di te stesso. A qual esito sei giunto avendo per unica guida il tuo intelletto! Voi siete giovine, voi siete ricco, voi siete intelligente. Che avete fatto di tutti questi doni? Siete contento di voi e della vostra esistenza? --No, l'aborro. --Se tu l'aborri, mutala, purificati; e, secondo che ti trasformerai, imparerai a conoscere la saggezza. Come l'avete voi trascorsa questa esistenza? In orgie, in bagordi, in depravazioni: ricevendo tutto dalla società e nulla dando. Come avete usati i beni di fortuna ricevuti? Che avete fatto pel vostro prossimo? Avete pensato alle vostre migliaia di servi? Li avete aiutati moralmente e materialmente? No; è vero? Avete profittato della loro fatica per vivere una vita corrotta. Avete cercato di adoperarvi a vantaggio del vostro prossimo? No. Avete vissuto nell'ozio. Poi, vi siete ammogliato: avete accettata la responsabilità di servire da guida a una donna giovine. E allora? Invece di aiutarla a trovare la via della verità, l'avete gittata nell'abisso della menzogna e della sciagura...." Di nuovo, l'insostenibile peso mi piombò sopra, mi schiacciò; e fu uno strazio più atroce di quello già sofferto, perché la vicinanza di Giuliana aumentava l'orgasmo. Il passo trascritto era indicato nella pagina con un solo segno. Certo, Giuliana lo aveva segnato pensando a me, ai miei errori. Ma anche l'ultima riga si riferiva a me, a noi? L'avevo io gittata, era ella caduta "nell'abisso della menzogna e della sciagura?" Io temevo che ella e Federico udissero i battiti del mio cuore. Un'altra pagina era piegata, portava un solco visibilissimo: quella su la morte della principessa Lisa a Lissy-Gory. "....Gli occhi della morta erano chiusi; ma il suo volto esile non era mutato. Ed ella pareva dire pur sempre:--Che avete voi fatto di me?--Il principe Andrea non piangeva; ma si senti lacerare il cuore, pensando ch'egli era colpevole di torti ormai irreparabili e indimenticabili. Il principe vecchio anche venne, e baciò una delle fragili mani di cera, che stavano incrociate l'una su l'altra. E parve che quel povero esile volto ripetesse anche a lui:--Che avete fatto di me?...." La dolce e terribile domanda mi ferì come un aculeo. "Che avete fatto di me?" Tenevo gli occhi fissi su la pagina, non osando di volgermi a guardare Giuliana e pur essendo ansioso di guardarla. E avevo paura che ella e Federico udissero i battiti del mio cuore e si volgessero essi a guardar me e scoprissero il mio turbamento. Così forte era il mio turbamento, ch'io credevo di avere il viso scomposto e di non potermi levare e di non poter proferire una sillaba. Un solo sguardo, rapido, obliquo, gittai a Giuliana; e il suo profilo mi s'impresse così che mi parve di continuare a vederlo su la pagina, accanto al "povero esile volto" della principessa morta. Era un profilo pensoso, reso più grave dall'attenzione, ombrato dai lunghi cigli; e le labbra serrate, un po' cadenti all'angolo, parevano involontariamente confessare una stanchezza e una tristezza estreme. Ella ascoltava mio fratello. E la voce di mio fratello mi sonava all'orecchio confusa, mi pareva remota se bene fosse tanto vicina; e tutti quei fiori degli olmi, che piovevano piovevano senza posa, tutti quei fiori morti, quasi irreali, quasi inesistenti, mi davano una sensazione inesprimibile, come se quella visione fisica mi si convertisse in uno strano fenomeno interno e io assistessi al passaggio continuo di quelle innumerevoli ombre impalpabili in un cielo intimo, nell'intimo dell'anima mia. "Che avete fatto di me?" ripetevano la morta e la vivente, ambedue senza muovere le labbra. "Che avete fatto di me?" --Ma che leggi, ora, Tullio?--disse Giuliana volgendosi, togliendomi il libro di tra le mani, chiudendolo, posandolo di nuovo su le sue ginocchia, con una specie d'impazienza nervosa. E subito dopo, senza alcuna pausa, come per rendere insignificante quel suo atto: --Perché non andiamo su, da miss Edith, a fare un po' di musica? Sentite? Sta sonando, mi pare, la _Marcia funebre per la morte di un Eroe_, quella che piace a te, Federico.... Ed ella tese l'orecchio, in ascolto. Tutt'e tre ascoltammo. Qualche gruppo di note giungeva fino a noi, nel silenzio. Ella non s'era ingannata. Soggiunse, levandosi: --Andiamo, dunque. Venite? Io fui l'ultimo ad alzarmi, per vederla d'innanzi a me. Ella non si curò di scuotere dalla sua veste i fiori dell'olmo; che sul terreno intorno avevano composto un tappeto soffice, seguitando a piovere, a piovere senza tregua. In piedi, rimase là qualche istante, a capo chino, a guardare lo strato dei fiori ch'ella scavava e ammonticchiava con la punta sottile della sua scarpetta, mentre anche su lei altri fiori altri fiori seguitavano a piovere a piovere senza tregua. Io non le vedevo la faccia. Era ella intenta a quell'atto ozioso o assorta in una perplessità? V. La mattina dopo, tra gli altri portatori di doni pasquali, venne alla Badiola Calisto, il vecchio Calisto, il guardiano di Villalilla, con un fascio enorme di fiori di lilla ancora freschissimi, fragranti. E volle egli stesso, con le sue proprie mani offrirlo a Giuliana, rammentandole i bei tempi del nostro soggiorno, pregandola di una visita, di una visita anche breve.--La signora pareva così allegra, così contenta laggiù! Perché non ci tornava? La casa era rimasta intatta, non era mutata in nulla. Il giardino era diventato più folto. Gli alberi di lilla, un bosco!, erano in piena fioritura. Non giungeva fino alla Badiola il profumo, verso sera? La casa, il giardino, proprio, aspettavano la visita. Tutti i vecchi nidi sotto le gronde erano pieni di rondinelle. Secondo il desiderio della signora, quei nidi erano stati rispettati sempre come cose sante. Ma, proprio, erano omai troppi. Bisognava ogni settimana adoperare la pala sui balconi, su i davanzali delle finestre. E che stridìo dall'alba al tramonto! Quando sarebbe dunque venuta, la signora? Presto? Io dissi a Giuliana: --Vuoi che andiamo martedì? Con un po' di esitazione, mentre reggeva a fatica il fascio smisurato che quasi le nascondeva il volto, ella rispose: --Andiamo pure, se vuoi, martedì. --Verremo martedì, dunque, Calisto--io dissi al vecchio, con un accento di allegrezza così vivace che io stesso ne fui sorpreso, tanto era stato spontaneo e subitaneo il moto dell'animo.--Aspettaci per martedì mattina. Porteremo con noi la colazione. Tu non preparare nulla; hai capito? Lascia la casa chiusa. Voglio aprire io stesso la porta; voglio aprire io stesso le finestre a una a una. Intendi? Una strana allegrezza, tutta irriflessiva, mi agitava, mi suggeriva atti e parole puerili, quasi folli, che stentavo a rattenere. Avrei voluto abbracciare Calisto, accarezzargli la bella barba bianca, prenderlo a braccio e parlare con lui di Villalilla, delle cose passate, dei "nostri tempi" abbondantemente, sotto quel gran sole di Pasqua, "Ecco ancora d'avanti a me un uomo semplice, sincero, tutto d'un pezzo: un cuore fedele!" io pensavo, guardandolo. E ancora una volta mi sentivo rassicurato, come se l'affetto di quel vecchio fosse per me un altro buon talismano contro la sorte. Ancora una volta, dopo la caduta del giorno innanzi, la mia anima si risollevava incitata dalla grande letizia ch'era nell'aria, che splendeva in tutti gli occhi, che emanava da tutte le cose. La Badiola in quella mattina pareva la meta di un pellegrinaggio. Nessuno del contado aveva mancato di portare il dono e l'augurio. Mia madre riceveva su le sue mani benedette baci innumerevoli, d'uomini, di donne, di fanciulli. Alla messa celebrata nella Cappella assisteva una turba densa che traboccava fuor della soglia dilatandosi per lo spiazzo, religiosa sotto il dòmo ceruleo. Le campane argentine squillavano con un accordo felice, quasi musicale, nell'aria senza mutamento. Su la torre l'inscrizione del quadrante solare diceva: _Hora est benefaciendi_. E in quella mattina di gloria, in cui pareva salire verso la dolce casa materna tutta la gratitudine dovuta al lungo benefizio, le tre parole cantavano. Come potevo io dunque conservare dentro di me la perfidia dei dubbi, dei sospetti, delle imagini impure, dei ricordi torbidi? Che potevo io temere, dopo aver veduto mia madre premere più volte le sue labbra su la fronte di Giuliana sorridente?, dopo aver veduto mio fratello stringere nella sua mano fiera e leale la gracile mano pallida di quella che era per lui come la seconda incarnazione di Costanza? VI. Il pensiero della gita a Villalilla mi occupò per tutto quel giorno e pel giorno seguente, di continuo. Non mai, credo, l'attesa dell'ora stabilita pel primo convegno con un'amante mi aveva data un'ansietà così fiera. "Cattivi sogni, cattivi sogni, soliti effetti dell'esser allucinato!" io giudicavo le angosce del sabato tristo: con una straordinaria leggerezza d'animo, con una volubilità obliosa, posseduto interamente dalla pervicace illusione che scacciata ritornava e distrutta rinasceva sempre. Lo stesso turbamento sensuale del desiderio concorreva ad oscurare la conscienza, a renderla ottusa. Io pensavo di riconquistare non l'anima sola di Giuliana ma anche il corpo; e nella mia ansietà entrava una parte di orgasmo fisico. Il nome di Villalilla suscitava in me ricordi voluttuosi: ricordi non di mite idilio ma di passione ardente, non di sospiri ma di gridi. Senza accorgermene, io avevo forse acuito e corrotto il mio desiderio con le imagini inevitabili generate dal dubbio; e portavo in me latente quel germe venefico. In fatti, sino allora in me era parsa predominante la commozione spirituale, ed io, aspettando il gran giorno, m'ero compiaciuto in puri colloquii fantastici con la donna da cui volevo ottenere il perdono. Ora in vece non tanto _vedevo_ la scena patetica fra me e lei quanto la scena di voluttà, che doveva esserne conseguenza immediata. Il perdono si mutava in abbandono, il bacio trepido su la fronte in bacio cupido su la bocca--nel mio sogno. Il senso sopraffaceva lo spirito. E a poco a poco, per una eliminazione rapida e inarrestabile, una imagine escluse tutte le altre e m'occupò e mi signoreggiò, fissa, lucidissima, esatta nelle minime particolarità. "È dopo la colazione. Un piccolo bicchiere di Chablis è bastato a turbare Giuliana che è quasi un'astemia. Il pomeriggio si fa sempre più caldo; l'odore delle rose, dei giaggiòli, dei fiori di lilla si fa violento; le rondini passano e ripassano con un gran garrire assordante. E siamo soli, ambedue invasi da un tremito interiore insostenibile. E io le dico, a un tratto:--Vuoi che andiamo a rivedere la nostra stanza?--È l'antica stanza nuziale che ad arte io ho tralasciato di aprire nel nostro giro per la villa. Entriamo. C'è, là dentro, come un cupo rombo, lo stesso rombo che pare sia in fondo a certe conchiglie sinuose; e non altro è che il rumore delle mie vene. Ed ella anche forse ode quel rombo; e non altro è che il rumore delle sue vene. Tutto il resto è silenzio: pare che le rondini non garriscano più. Io voglio parlare; e, alla prima parola rauca, ella mi cade fra le braccia, quasi svenuta...." Questa rappresentazione fantastica si arricchiva di continuo, si faceva più complessa, simulava la realità, raggiungeva una evidenza incredibile. Io non riescivo a contenderle il dominio assoluto del mio spirito, pareva che risorgesse in me l'antico libertino, così profondo era il compiacimento che io provavo a contemplare e ad accarezzare l'imagine voluttuosa. La castità mantenuta per alcune settimane, in quella primavera così fervida, produceva ora i suoi effetti nel mio organismo ristorato. Un semplice fenomeno fisiologico mutava completamente il mio stato di conscienza, dava una piega completamente diversa ai miei pensieri, mi trasformava in un altro uomo. Maria e Natalia avevano mostrata la voglia di accompagnarci nella gita. Giuliana avrebbe voluto consentire. Io mi opposi; adoperai tutta la mia abilità e la mia grazia per raggiungere lo scopo. Federico aveva proposto:--Martedì io debbo andare a Casal Caldore. Vi accompagno in carrozza sino a Villalilla: voi vi fermate e io proseguo. Poi, la sera, ripassando, vi riprendo in carrozza; e torniamo insieme alla Badiola.--Giuliana, me presente, aveva accettato. Io pensavo che la compagnia di Federico, almeno nell'andata, non sarebbe stata inopportuna; mi avrebbe anzi tolto da una certa perplessità. In fatti: di che avremmo discorso, se fossimo stati soli, io e Giuliana, in quelle due o tre ore di viaggio? Quale attitudine avrei presa verso di lei? Avrei potuto anche guastare le cose, compromettere il buon esito, o almeno togliere la freschezza alla nostra commozione. Non avevo sognato io di ritrovarmi d'un tratto con lei a Villalilla, come per una magia, e di rivolgerle quivi la mia prima parola tenera e sommessa? La presenza di Federico mi avrebbe dato il modo di evitare i preliminari incerti, i lunghi silenzii tormentosi, le frasi proferite a bassa voce per riguardo agli orecchi del cocchiere, tutte insomma le piccole irritazioni e le piccole torture. Noi saremmo discesi a Villalilla, e là, soltanto là, ci saremmo ritrovati finalmente l'uno a fianco dell'altra, d'innanzi alla porta del paradiso perduto. VII. Così fu. M'è impossibile rappresentar con parole la sensazione ch'io provai nell'udire il tintinno delle sonagliere, lo strepito della carrozza che s'allontanava portando Federico verso Casal Caldore. Io dissi a Calisto, prendendo dalle sue mani le chiavi, con un'impazienza manifesta: --Ora, tu puoi andare. Ti chiamerò più tardi. E rinchiusi io stesso il cancello, dietro il vecchio che m'era parso un po' attonito e scontento di quel congedo quasi brusco. --Ci siamo, alla fine!--esclamai, quando io e Giuliana fummo soli. Tutta l'onda di felicità che m'aveva invaso passò nella mia voce. Io ero felice, felice, indicibilmente felice; ero posseduto come da una grande allucinazione di felicità inaspettata, insperata, che trasfigurava tutto il mio essere, suscitava e moltiplicava quanto di buono e di giovine era ancora rimasto in me, m'isolava dal mondo, concentrava a un tratto la mia vita nel cerchio delle mura che chiudevano quel giardino. Le parole mi s'affollavano alle labbra, senza nesso, improfferibili; la ragione mi si smarriva tra un balenio fulmineo di pensieri. Come poteva Giuliana non indovinare quel che avveniva in me? Come poteva non intendermi? Come poteva non esser colpita nel mezzo del cuore dal raggio violento della mia gioia? Ci guardammo. Vedo ancora l'espressione ansiosa di quel volto su cui errava un sorriso mal sicuro. Ella disse, con la sua voce velata, debole, sempre esitante di quella singolare esitazione già da me notata altre volte, che la faceva sembrare quasi di continuo attenta a trattenere la parola che le saliva alle labbra, per pronunziarne una diversa, disse: --Giriamo un poco pel giardino, prima di aprire la casa. Quanto tempo è che non lo rivedo così fiorito! L'ultima volta che ci venimmo fu tre anni fa, ti ricordi?, anche d'aprile, nei giorni di Pasqua.... Ella voleva forse dominare il suo turbamento, ma non poteva; voleva forse frenare l'effusione della tenerezza, ma non sapeva. Ella stessa, con le prime parole pronunziate in quel luogo, aveva incominciato ad evocare i ricordi. Si soffermò, dopo alcuni passi; e ci guardammo. Un'alterazione indefinibile, come una violenza di cose soffocate, passò ne' suoi occhi neri. --Giuliana!--io proruppi, non reggendo più, sentendomi sgorgare dall'intimo del cuore un flutto di parole appassionate e dolci, provando un bisogno folle d'inginocchiarmi d'avanti a lei su la ghiaia, e di abbracciarla alle ginocchia e di baciarle la veste, le mani, i polsi, furiosamente, senza fine. Ella m'accennò che tacessi, con un gesto supplichevole. E seguitò a internarsi pel viale, con un passo più celere. Portava un abito di panno grigio chiaro ornato di trine più oscure, un cappello di feltro grigio, un ombrellino di seta grigia a piccoli trifogli bianchi. Vedo ancora la sua persona elegante in quel colore fine e sobrio avanzarsi tra le folte masse degli alberi di lilla che s'inchinavano verso di lei carichi dei loro innumerevoli grappoli fra turchinicci e violetti. Mancava quasi un'ora al mezzogiorno. Era una mattina calda, d'un caldo precoce, azzurra ma navigata da qualche nuvola molle. I frutici deliziosi, che davano il nome alla villa, fiorivano per ogni dove, signoreggiavano tutto il giardino, facevano un bosco a pena interrotto qua e là da cespugli di rose gialle e da mucchi di giaggiòli. Qua e là le rose si arrampicavano su per i fusti, s'insinuavano tra i rami, ricadevano miste in catene, in ghirlande, in festoni, in corimbi; a piè dei fusti le iridi fiorentine elevavano di tra le foglie simili a lunghe spade glauche le forme ampie e nobili dei loro fiori; i tre profumi si mescevano in un accordo profondo che io _riconoscevo_ perché dal tempo lontano era rimasto nella mia memoria distinto come un accordo musicale di tre note. Nel silenzio, non si udiva se non il garrire delle rondini. La casa a pena s'intravedeva tra i coni dei cipressi, e le rondini vi accorrevano innumerevoli come le api all'alveare. Dopo un poco, Giuliana rallentò il passo. Io le camminavo al fianco, così vicino che di tratto in tratto i nostri gomiti si toccavano. Ella guardava intorno a sé con occhi mobili e attenti, come temendo che le sfuggisse qualche cosa. Due o tre volte io sorpresi su le sue labbra l'atto di parlare: il principio di una parola vi si disegnava, senza suono. Io le chiesi a voce bassa, timido, come un amante: --Che pensi? --Penso che non avremmo mai dovuto partire di qui.... --È vero, Giuliana. Le rondini talvolta, quasi ci rasentavano, con un grido, rapide e rilucenti come strali pennuti. --Quanto ho desiderato questo giorno, Giuliana! Ah, tu non saprai mai quanto l'ho desiderato!--io proruppi allora, in preda a una commozione così forte che la mia voce doveva essere irriconoscibile.--Nessuna ansietà, vedi, nessuna ansietà, mai nella vita ho provata eguale a questa che mi divora da jer l'altro, dal momento che tu consentisti a venire. Ti ricordi tu della prima volta che ci vedemmo in segreto, su la terrazza di Villa Oggèri, e che ci baciammo? Ero folle di te: tu te ne ricordi. E bene, l'attesa di quella notte mi par nulla al confronto.... Tu non mi credi; tu hai ragione di non credermi, di diffidare, ma io voglio dirti tutto, voglio raccontarti quel che ho sofferto, quel che ho temuto, quel che ho sperato. Oh, lo so: quel che ho sofferto è forse poco al confronto di quel che t'ho fatto soffrire. Lo so, lo so: tutti i miei dolori non valgono forse il tuo dolore, non valgono le tue lacrime. Io non ho espiato il mio fallo, e non sono degno d'essere perdonato. Ma dimmi tu, ma dimmi tu quello che io debbo fare perché tu mi perdoni! Tu non mi credi; ma io voglio dirti tutto. Te sola veramente io ho amata nella vita; amo te sola. Lo so, lo so: queste sono le cose che gli uomini dicono, per farsi perdonare; e tu hai ragione di non credermi. Ma pure, vedi, se tu pensi al nostro amore d'una volta, se tu pensi a quei primi tre anni di tenerezza mai interrotta, se tu ti ricordi, se tu ti ricordi, vedi, non è possibile che tu non mi creda. Anche nelle mie peggiori cadute, tu dovevi essere per me indimenticabile; e la mia anima si doveva volgere a te, e ti doveva cercare, e ti doveva rimpiangere, sempre, intendi?, sempre. Tu stessa non te n'accorgevi? Quando tu eri per me una sorella, certe volte non t'accorgevi che io morivo di tristezza? Te lo giuro: lontano da te, non ho provato mai una gioia sincera, non ho avuto mai un'ora di pieno oblio; mai, mai: te lo giuro. Tu eri la mia adorazione costante, profonda, segreta. La parte migliore di me è stata sempre tua; e una speranza v'è rimasta sempre accesa; la speranza di liberarmi dai miei mali e di ritrovare il mio primo unico amore intatto.... Ah, dimmi che non ho sperato inutilmente, Giuliana! Ella camminava con estrema lentezza, senza più guardare d'innanzi a sé, a capo chino, troppo bianca. Una piccola contrattura dolorosa le appariva di quando in quando all'angolo della bocca. E poiché, ella taceva, incominciò a muoversi in fondo a me un'inquietudine vaga. Un senso vago di oppressione incominciò a venirmi da quel sole, da quei fiori, dai gridi di quelle rondini, da tutto quel riso, troppo aperto, della primavera trionfante. --Non mi rispondi?--seguitai, prendendole la mano ch'ella teneva abbandonata lungo il fianco.--Tu non mi credi; tu hai perduto qualunque fede in me; tu temi ancora che io ti deluda; tu non osi di ridonarti perché pensi sempre a _quella volta_.... Sì, è vero: fu la più cruda delle mie infamie. Io n'ho rimorso come d'un delitto; e, anche se tu mi perdonerai, io non potrò mai perdonarmi. Ma non t'accorgesti tu che io ero malato, che io ero demente? Una maledizione mi perseguitava. E da quel giorno io non ebbi più un minuto di tregua, non ebbi più un intervallo di lucidezza. Non ti ricordi? Non ti ricordi? Tu, certo, sapevi che ero fuori di me, in uno stato di demenza; perché tu mi guardavi come si guarda un pazzo. Più d'una volta io sorpresi nel tuo sguardo una compassione penosa, non so che curiosità e che timore. Non ti ricordi com'ero ridotto? Irriconoscibile.... E bene, io sono guarito, io mi sono salvato, per te. Ho potuto vedere la luce. Finalmente la luce si è fatta. Te sola ho amata nella vita; amo te sola. Intendi? Pronunziai le ultime parole con una voce più ferma e più lenta, come per imprimerle a una a una su l'anima della donna; e strinsi forte la mano che già tenevo nella mia. Ella sì fermò, nell'atto di chi sta per lasciarsi cadere, anelando. Più tardi, soltanto più tardi, nelle ore che seguirono, compresi tutta la mortale angoscia esalata in quell'anelito. Ma allora non altro compresi che questo: "il ricordo dell'orribile tradimento, evocato da me, le rinnova la sofferenza. Ho toccato piaghe che sono ancora aperte. Ah, se potessi persuaderla a credermi! Se potessi vincere la sfiducia che la tiene! Non sente ella dunque la verità nella mia voce?" Eravamo presso ad un bivio. C'era là un sedile. Ella mormorò: --Sediamo, un poco. Sedemmo. Non so s'ella riconobbe subito il luogo. Io non lo riconobbi subito, smarrito come uno che abbia portata per qualche tempo la benda. Ambedue guardammo intorno; poi ci guardammo, avendo negli occhi lo stesso pensiero. Molte memorie di tenerezza erano legate a quel vecchio sedile di pietra. Il cuore non mi si gonfiò di rammarico ma d'una avidità affannosa, quasi d'un furore di vita, che mi diede in un lampo una visione dell'avvenire fantastica e allucinante. "Ah ella non sa di quali nuove tenerezze io sia capace! Io ho il paradiso per lei nella mia anima!" E l'idealità dell'amore fiammeggiò dentro di me così forte ch'io mi esaltai. --Tu ti addolori. Ma quale creatura al mondo è stata amata come tu sei amata? Quale donna ha potuto avere una prova di amore che valga questa ch'io ti do? Non avremmo mai dovuto partire di qui--tu dicevi, dianzi.--E forse saremmo stati felici. Tu non avresti sofferto il martirio, non avresti versato tante lacrime, non avresti perduto tanta vita; ma non avresti conosciuto il mio amore, tutto il mio amore.... Ella teneva il capo reclinato sul petto e le palpebre socchiuse; e ascoltava, immobile. I cigli le spandevano a sommo delle gote un'ombra che mi turbava più d'uno sguardo. --Io, io stesso non avrei conosciuto il mio amore. Quando mi allontanai da te la prima volta, non credevo già che tutto fosse finito? Cercavo un'altra passione, un'altra febbre, un'altra ebrezza. Volevo abbracciare la vita con una sola stretta. Tu non mi bastavi. E per anni mi sono estenuato in una fatica atroce, oh tanto atroce che n'ho orrore come un forzato ha orrore della galera dove ha vissuto _morendo tutti i giorni un poco_. E ho dovuto passare d'oscurità in oscurità, per anni, prima che si facesse questa luce nella mia anima, prima che questa grande verità m'apparisse. Non ho amato che una donna: te sola. Tu sola al mondo hai la bontà e la dolcezza. Tu sei la più buona e la più dolce creatura che io abbia mai sognata; sei l'Unica. E tu eri nella mia casa mentre io ti cercavo lontano.... Intendi ora? Intendi? _Tu eri nella mia casa mentre io ti cercavo lontano._ Ah, dimmi tu: questa rivelazione non vale tutte le tue lacrime? Non vorresti averne versate anche più, anche più per una tale prova? --Sì, anche più--ella disse, così piano che a pena l'udii. Fu un soffio su quelle labbra esangui. E le lacrime le sgorgarono di tra i cigli, le solcarono le gote, le bagnarono la bocca convulsa, le caddero sul petto ansioso. --Giuliana, mio amore, mio amore!--gridai, con un brivido di felicità suprema, gittandomi in ginocchio d'innanzi a lei. E la cinsi con le mie braccia, misi la testa nel suo grembo, provai per tutto il corpo quella tensione smaniosa in cui si risolve lo sforzo vano d'esprimere con un atto, con un gesto, con una carezza l'ineffabile passione interiore. Le sue lacrime caddero su la mia guancia. Se l'effetto materiale di quelle calde gocce viventi avesse corrisposto alla sensazione ch'io n'ebbi, porterei su la mia pelle una traccia indelebile! --Oh, lasciami bere,--io pregai. E, rilevandomi, accostai le mie labbra ai suoi cigli, le bagnai nel suo pianto, mentre le mie dita smarritamente la toccavano. Una pieghevolezza strana era venuta alle mie membra, una specie di fluidità illusoria per cui non avvertivo più l'impaccio delle vesti. Credevo che mi sarebbe stato possibile circondare, avviluppare tutta quanta la persona amata. --Sognavi--io le dicevo, avendo in bocca il sapore salso che mi si diffondeva nei precordii (più tardi, nelle ore che seguirono, mi stupii di non aver trovato in quelle lagrime una intollerabile amarezza) sognavi d'essere tanto amata? Sognavi questa felicità? Sono io, guardami, sono io che ti parlo così; guardami bene, sono io.... Se tu sapessi come mi pare strano tutto questo! Se ti potessi dire!... So che ti ho conosciuta prima d'ora, so che ti ho amata prima d'ora; so che ti ho _ritrovata_. E pure mi pare di averti _trovata_ soltanto ora, un momento fa, quando tu hai detto: "Sì, anche più...." Hai detto così; è vero? Tre parole sole.... un soffio.... E io rivivo, e tu rivivi; ed ecco che siamo felici, siamo felici per sempre. Io le dicevo queste cose con quella voce che ci viene come di lontano, interrotta, indefinibile; che pare giunga all'orlo delle labbra modulata non nella materialità dei nostri organi ma nell'estremo fondo dell'anima nostra. Ed ella, che fino a quel momento aveva versato un pianto silenzioso, ruppe in singhiozzi. Forte, troppo forte singhiozzava, non come chi sia sopraffatto da una gioia senza limiti ma come chi esali una disperazione inconsolabile. Singhiozzava così forte ch'io rimasi per qualche istante in quello stupore che suscitano le manifestazioni eccessive, i grandi parosismi della commozione umana. Inconscientemente, mi scostai un poco; ma subito dopo, notai quell'intervallo che s'era aperto tra lei e me; subito dopo, notai che non soltanto il contatto materiale era cessalo ma che anche il sentimento di comunione s'era disperso in un attimo. Eravamo pur sempre due esseri ben distinti, separati, estranei. La stessa diversità delle nostre attitudini aumentava il distacco. Ripiegata su sé medesima, premendosi con le sue mani il fazzoletto su la bocca, ella singhiozzava; e ogni singhiozzo le scoteva tutta la persona, pareva rivelarne la fragilità. Io stavo ancora in ginocchio d'innanzi a lei, senza toccarla; e la guardavo: stupito e pur nondimeno stranamente lucido; attento a sorvegliare tutto ciò ch'era per accadere dentro di me, e pur nondimeno avendo tutti i sensi aperti alla percezione delle cose che mi circondavano. Udivo il singhiozzo di lei e il garrito delle rondini; e avevo la nozione del tempo e del luogo esatta. E quei fiori e quelli odori e quella grande luminosità immobile dell'aria e tutto quel riso della primavera aperto mi diedero uno sgomento che crebbe, che crebbe e diventò una specie di timor pánico, una paura istintiva e cieca a cui la ragione non poté opporsi. E, come scoppia un fulmine in un cumulo di nubi, un pensiero guizzò in mezzo a quello scompiglio pauroso, m'illuminò e mi percosse. "Ella è impura." Ah, perché non caddi allora fulminato? Perchè non mi si spezzò un viscere vitale e non restai là su la ghiaia, ai piedi della donna che nella fuga di pochi attimi m'aveva sollevato all'apice della felicità e m'aveva precipitato in un abisso di miseria? --Rispondi--(Le afferrai i polsi, le scopersi la faccia, le parlai da presso; e la mia voce era così sorda che io medesimo a pena la udivo tra il romorio del mio cervello.)--rispondi: che è questo pianto? Ella cessò di singhiozzare, e mi guardò; e gli occhi benché bruciati dalle lacrime, le si dilatarono esprimendo un'ansietà estrema, come se mi avessero veduto morire. Io dovevo aver perduto, in fatti, ogni colore di vita. --_È tardi, forse? È troppo tardi?_--soggiunsi, rivelando il mio pensiero terribile in quella domanda oscura. --No, no, no.... Tullio, non è.... nulla. Tu hai potuto pensare!... No, no.... Sono tanto debole, vedi; non sono più come una volta.... Non reggo.... Sono malata tu sai; sono tanto malata. Non ho potuto resistere.... a quello che mi dicevi. Tu intendi.... M'è venuto questo accesso all'improvviso.... È una cosa dei nervi.... come una convulsione.... Si spasima; non si capisce più se si pianga di gioia o di dolore.... Ah, mio Dio!.... Vedi, mi passa.... Alzati Tullio; vieni qui accanto a me. Mi parlava con una voce affiochita ancora dal pianto, interrotta ancora da qualche singulto; mi guardava con una espressione che io riconoscevo, con una espressione ch'ella aveva avuta già altre volte alla vista della mia sofferenza. Un tempo, ella non poteva vedermi soffrire. La sua sensibilità per questo riguardo era esagerata così che io potevo ottener tutto da lei mostrandomi dolente. Tutto ella avrebbe fatto per allontanare da me una pena, la minima pena. Spesso allora io mi fingevo afflitto, per gioco, per agitarla, per essere consolato come un fanciullo, per avere certe carezze che mi piacevano, per muovere in lei certe grazie che adiravo. Ed ora non appariva ne' suoi occhi la medesima espressione tenera e inquieta? --Vieni qui accanto a me, siediti. O vuoi che seguitiamo a girare pel giardino? Non abbiamo ancora veduto nulla.... Andiamo verso la peschiera. Voglio bagnarmi gli occhi.... Perché mi guardi così? Che pensi? Non siamo felici? Ecco, vedi, incomincio a sentirmi bene, tanto bene. Ma avrei bisogno di bagnarmi gli occhi, il viso.... Che ora sarà? Sarà mezzogiorno? Federico ripasserà verso le sei. Abbiamo tempo.... Vuoi che andiamo? Parlava interrottamente, ancora un po' convulsa, con uno sforzo palese, volendo ricomporsi, riacquistare il dominio su i suoi nervi, dissipare in me qualunque ombra, apparirmi fidente e felice. La trepidazione del suo sorriso negli occhi ancora umidi e rosei aveva una dolcezza penosa che m'inteneriva. Nella sua voce, nella sua attitudine, in tutta la sua persona era questa dolcezza che m'inteneriva e m'illanguidiva d'un languore un po' sensuale. Mi è impossibile definire la delicata seduzione che emanava da quella creatura su i miei sensi e sul mio spirito, in quello stato di conscienza irresoluto e confuso. Ella pareva dirmi, mutamente: "Io non potrei essere più dolce. Prendimi dunque, già che mi ami; prendimi nelle tue braccia, ma piano, senza farmi male, senza stringermi troppo forte. Oh, io mi struggo d'essere accarezzata da te! Ma credo che tu potresti farmi morire!" Questa imaginazione mi aiuta un poco a rendere l'effetto ch'ella produceva su me col suo sorriso. Io le guardavo la bocca, quando ella mi disse:--Perché mi guardi così?--Quando ella mi disse:--Non siamo felici?--, io provai il cieco bisogno d'una sensazione voluttuosa nella quale attutire il malessere lasciatomi dalla violenza recente. Quando ella si levò, con un atto rapidissimo io me la presi fra le braccia e attaccai la mia bocca alla sua. Fu un bacio di amante quello che io le diedi, un bacio lungo e profondo che agitò tutta la essenza delle nostre due vite. Ella si lasciò ricadere sul sedile, spossata. --Ah no, no, Tullio: ti prego! Non più, non più! Lasciami prima riprendere un po' di forza--supplicò, stendendo le mani come per tenermi discosto.--Altrimenti non mi potrò più levare di qui.... Vedi, sono morta. Ma in me era avvenuto uno straordinario fenomeno. Tale sul mio spirito quella sensazione quale su una riva un flutto gagliardo che spazzi qualunque traccia lasciando la sabbia rasa. Fu come un annullamento istantaneo; e subito uno stato nuovo si formò sotto l'influenza immediata delle circostanze, sotto l'urgenza del sangue riacceso. Non altro più conobbi che questo:--la donna che io desideravo era là, d'innanzi a me, tremante, prostrata dal mio bacio, tutta mia alfine; in torno a noi fioriva un giardino solitario, memore, pieno di segreti; una segreta casa ci aspettava, di là dagli alberi floridi, custodita dalle rondini familiari. --Credi tu che io non sarei capace di portarti?--dissi, prendendole le mani, intrecciando le mie dita alle sue.--Una volta eri leggera come una piuma. Ora devi essere anche più leggera.... Proviamo? Qualche cosa d'oscuro passò ne' suoi occhi. Ella per un istante parve alienarsi in un suo pensiero, come chi considera e risolve rapidamente. Poi scosse il capo; e arrovesciandosi in dietro e appendendosi a me con le braccia stese e ridendo (un poco della sua genciva esangue apparve nel riso), fece: --Su, tirami su! E alzata s'abbatté sul mio petto; e questa volta fu ella che mi baciò prima, con una specie di furia convulsa, come presa da una frenesia repentina, quasi volesse in un solo tratto estinguere una sete atrocemente patita. --Ah, sono morta!--ripeté, quando ebbe distaccata la sua bocca dalla mia. E quella bocca umida, un po' gonfia, semiaperta, divenuta più rosea, atteggiata di languore, in quel viso così pallido e così tenue, mi diede veramente l'impressione indefinibile d'una cosa che sola fosse rimasta viva nella sembianza d'una morta. Bisbigliò, levando gli occhi chiusi (i lunghi cigli le tremolavano come se un sorriso esiguo di sotto alle palpebre vi stillasse), trasognata: --Sei felice? Io la strinsi al mio cuore. --Andiamo, dunque. Portami dove vuoi. Reggimi tu un poco. Tullio, perché le ginocchia mi si piegano.... --Alla nostra casa, Giuliana? --Dove vuoi.... La reggevo forte alle reni con un braccio e la sospingevo. Ella era come una sonnambula. Per un tratto, rimanemmo in silenzio. Ci volgevamo a quando a quando l'uno verso l'altra, nel tempo medesimo, per rimirarci. Ella veramente mi pareva _nuova_. Una piccolezza fermava la mia attenzione, mi occupava: un piccolo segno appena visibile nella sua pelle, un piccolo incavo nel labbro inferiore, la curva dei cigli, una vena della tempia, l'ombra che cerchiava gli occhi, il lobo dell'orecchio infinitamente delicato. Il granello fosco sul collo era nascosto a pena dall'orlo del merletto; ma, per qualche moto che Giuliana faceva col capo, appariva talvolta e poi spariva; e la piccola vicenda incitava la mia impazienza. Ero ebro e pur tuttavia stranamente lucido. Udivo i gridi delle rondini più numerosi e il chioccolio dei getti d'acqua nella peschiera prossima. Sentivo la vita scorrere, il tempo fuggire. E quel sole e quei fiori e quelli odori e quei romori e tutto quel riso della primavera troppo aperto mi diedero per la terza volta un senso di ansietà inesplicabile. --Il mio salice!--esclamò Giuliana in vicinanza della peschiera, cessando di appoggiarsi a me, sollecitando il passo.--Guarda, guarda com'è grande! Ti ricordi? Era un ramo.... E soggiunse, dopo una pausa pensosa, con un accento diverso, a voce bassa: --Io l'avevo già riveduto.... Tu forse non sai: io ci venni a Villalilla, _quella volta_. Non trattenne un sospiro. Ma subito, come per dissipare l'ombra ch'ella aveva messa tra noi con quelle parole, come per togliersi dalla bocca quell'amarezza, si chinò a una delle cannelle, bevve qualche sorso e risollevandosi fece l'atto di chiedermi un bacio. Aveva il mento bagnato e le labbra fresche. Ambedue, taciti, in quella stretta risolvemmo d'affrettare l'evento omai necessario, la ricongiunzione suprema che tutte le nostre fibre chiedevano. Quando ci distaccammo, ambedue ci ripetemmo con gli occhi la stessa cosa inebriante. Fu straordinario il sentimento che il volto di Giuliana espresse, ma incomprensibile allora per me. Solo più tardi, nelle ore che seguirono, potei comprenderlo; quando seppi che un'imagine di morte e una imagine di voluttà insieme avevano inebriata la povera creatura e che ella aveva fatto un voto funebre nell'abbandonarsi al languore del suo sangue. Vedo come se l'avessi d'innanzi, vedrò sempre quel volto misterioso nell'ombra prodotta dalla grande capellatura arborea che ci pioveva sopra. I baleni dell'acqua al sole, guizzando tra i lunghi rami dalle foglie diafane, davano all'ombra una vibrazione allucinante. Gli echi fondevano in una monotonia cupa e continua le voci dei getti sonori. Tutte le apparenze esaltavano il mio essere fuori della realità. Movendo verso la casa non parlammo. Così intensa era divenuta la mia brama, la visione dell'evento prossimo rapiva la mia anima in un turbine così alto di gioia, così forte era il battito delle mie arterie che io pensai: "È il delirio? Non provai questo la prima notte nuziale, quando misi il piede su la soglia...." Due o tre volte m'assalì un impeto selvaggio, come un accesso istantaneo di follia, che contenni per prodigio: tale era il mio bisogno fisico di ripossedere quella donna. Anche in lei l'orgasmo doveva essere divenuto insostenibile, perché ella si fermò sospirando: --Oh mio Dio, mio Dio! È troppo. Soffocata, oppressa, m'afferrò una mano e se la portò al cuore. --Senti! Più che i battiti del suo cuore io seguii la mollezza del suo seno a traverso la stoffa; e le mie dita istintivamente si piegarono a stringere la piccola forma che conoscevano. Vidi negli occhi di Giuliana l'iride perdersi nel bianco sotto le palpebre che si abbassavano. Temendo ch'ella venisse meno, la mantenni, poi la sospinsi, quasi la portai di peso fino ai cipressi, fino a un sedile dove sedemmo ambedue estenuati. Stava d'innanzi a noi la casa, come in un sogno. Ella disse reclinando la testa su la mia spalla: --Ah, Tullio, che cosa terribile! Non credi anche tu che potremmo morire? Ella soggiunse, grave, con una voce venutale chi sa da quale profondità dell'essere: --Vuoi che moriamo? Il singolare brivido ch'io ebbi mi rivelò che un sentimento straordinario era in quelle parole, forse il sentimento medesimo che aveva trasfigurato il viso di Giuliana sotto il salice, dopo la stretta, dopo la muta risoluzione. Ma anche questa volta non potei comprendere. Soltanto compresi che ambedue eravamo posseduti omai da una specie di delirio e respiravamo in un'atmosfera di sogno. Come in un sogno stava d'innanzi a noi la casa. Su la facciata rustica, per tutte le cornici, per tutte le sporgenze, lungo il gocciolatoio, sopra gli architravi, sotto i davanzali delle finestre, sotto le lastre dei balconi, tra le mensole, tra le bugne, dovunque le rondini avevano nidificato. I nidi di creta innumerevoli, vecchi e nuovi, agglomerati come le cellette di un alveare, lasciavano pochi intervalli liberi. Su quelli intervalli e su le stecche delle persiane e sui ferri delle ringhiere gli escrementi biancheggiavano come spruzzi di calcina. Benché chiusa e disabitata, la casa viveva. Viveva d'una vita irrequieta, allegra e tenera. Le rondini fedeli l'avvolgevano dei loro voli, dei loro gridi, dei loro luccichii, di tutte le loro grazie e di tutte le loro tenerezze, senza posa. Mentre gli stormi s'inseguivano per l'aria in caccia con la velocità delle saette, alternando i clamori, allontanandosi e riavvicinandosi in un attimo, radendo gli alberi, levandosi nel sole, gittando a tratti dalle macchie bianche un baleno, instancabili, ferveva dentro ai nidi e in torno ai nidi un'altra opera. Delle rondini covaticce alcune rimanevano per qualche istante sospese agli orifizi; altre si reggevano su le ali brillando; altre s'introducevano a mezzo, lasciando di fuori la piccola coda forcuta che tremolava vivamente, nera e bianca su la mota giallastra; altre di dentro escivano a mezzo, mostrando un po' del petto lustro, la gola fulva; altre, fino allora invisibili, si spiccavano a volo con un grido acutissimo, scoccavano. E tutta quella mobilità alacre ed ilare intorno alla casa chiusa, tutta quella vivacità di nidi intorno al nostro antico nido erano uno spettacolo così dolce, un così fino miracolo di gentilezza che noi per qualche minuto, come in una pausa della nostra febbre, ci obliammo a contemplarlo. Io ruppi l'incanto, alzandomi. Dissi: --Ecco la chiave. Che aspettiamo? --Sì, Tullio, aspettiamo ancora un poco!--ella supplicò, paventando. --Io vado ad aprire. E mi mossi verso la porta; salii i tre gradini che parevano quelli di un altare. Mentre stavo per girare la chiave col tremito del devoto che apre il reliquiario, sentii dietro di me Giuliana che m'aveva seguito furtiva, leggera come un'ombra. Ebbi un sussulto. --Sei tu? --Sì, sono io--bisbigliò ella, carezzevole, spirandomi nell'orecchio il suo alito. E, standomi alle spalle, mi cinse il collo con le braccia in modo che i suoi polsi delicati s'incrociarono sotto il mio mento. L'atto furtivo, quel tremolio di riso ch'era nel suo bisbiglio e che tradiva la sua gioia infantile d'avermi sorpreso, quella maniera d'allacciarmi, tutte quelle grazie agili mi ricordarono la Giuliana d'un tempo, la giovine e tenera compagna degli anni felici, la creatura deliziosa dalla lunga treccia, dalle fresche risa, dalle arie di fanciulla. Un soffio della stessa felicità m'investì, sul limitare della casa memore. --Apro?--domandai, tenendo ancora la mano su la chiave per girarla. --Apri,--ella rispose, senza lasciarmi, spirandomi ancora il suo alito nel collo. Allo stridere che fece la chiave nella serratura, ella mi legò più forte con le braccia, mi si serrò addosso, comunicandomi il suo brivido. Le rondini garrivano sul nostro capo; e pure quel lieve stridore ci parve distinto come in un silenzio profondo. --Entra--ella mi bisbigliò, senza lasciarmi. Entra, entra. Quella voce, proferita da labbra tanto vicine ma invisibili, reale e pure misteriosa, spiratami calda nell'orecchio e pure intima come se mi parlasse nel mezzo dell'anima, e femmina e dolce come nessun'altra voce fu mai, io la odo ancora, la udrò sempre. --Entra, entra. Spinsi la porta. Varcammo la soglia, come fusi in una sola persona, pianamente. L'andito era rischiarato da un'alta finestra rotonda. Una rondine ci svolazzò sul capo garrendo. Levammo gli occhi, sorpresi. Un nido pendeva fra le grottesche della volta. Alla finestra, mancava un vetro. La rondine fuggì via pel varco, garrendo. --Ora sono tua, tua, tua!--bisbigliò Giuliana, senza distaccarsi dal mio collo ma girando flessuosamente per venirmi sul petto, per incontrare la mia bocca. A lungo ci baciammo. Io dissi, ebro: --Vieni. Andiamo su. Vuoi che ti porti? Se bene ebro, io mi sentivo nei muscoli la forza di portarla su per le scale in un tratto. Ella rispose: --No. Posso salire da me. Ma non pareva ch'ella potesse, a udirla, a vederla. Io la cinsi, come prima nel viale: e la sospinsi di gradino in gradino, così sorreggendola. Veramente pareva nella casa fosse quel rombo cupo e remoto che conservano in loro certe conchiglie profonde. Veramente pareva che nessun altro romore dall'esterno vi giungesse. Quando fummo sul pianerottolo, io non aprii l'uscio di contro; ma volsi a destra pel corridoio oscuro, traendo lei per la mano, senza parlare. Tanto forte ella ansava che mi faceva pena, mi comunicava l'ambascia. --Dove andiamo?--mi domandò. Io risposi: --Alla stanza _nostra_. Quasi non ci si vedeva. Io ero come guidato da un istinto. Ritrovai la maniglia; aprii. Entrammo. L'oscurità era rotta dall'albore che trapelava dagli spiragli; e vi si udiva più cupo il rombo. Io volevo correre verso quegli indizi per fare subito la luce, ma non potevo lasciare Giuliana; mi pareva di non potermi distaccare da lei, di non poter interrompere né pure per un attimo il contatto delle nostre mani, quasi che a traverso la cute le estremità vive dei nostri nervi aderissero magneticamente. Ci avanzammo insieme, ciechi. Un ostacolo ci arrestò, nell'ombra. Era il letto, il gran letto delle nostre nozze e dei nostri amori.... Fin dovo s'udì il grido terribile? VIII. Erano le due del pomeriggio. Tre ore circa erano passate dal momento del nostro arrivo a Villalilla. Avevo lasciata sola Giuliana per alcuni minuti; ero andato a chiamare Calisto. Il vecchio aveva portato il canestro della colazione; e, non più con sorpresa ma con una certa malizia bonaria, aveva ricevuto un secondo congedo bizzarro. Stavamo ora, io e Giuliana, seduti a tavola come due amanti, l'uno di fronte all'altra, sorridendoci. Avevamo là vivande fredde, conserve di frutti, biscotti, aranci, una bottiglia di Chablis. La sala, con la sua volta a ornati barocchi, con le sue pareti chiare, con le sue pitture pastorali nei soprapporti, aveva una certa gaiezza antiquata, un'aria del secolo scorso. Pel balcone aperto entrava una luce assai mite, poiché pel cielo s'erano diffuse lunghe vene lattee. Nel rettangolo pallido campeggiava "il vecchio cipresso venerabile che aveva al suo piede un cespo di rose e un coro di passeri alla sua cima." Più giù, a traverso i ferri curvi della ringhiera appariva la delicata selva di color gridellino, la gloria primaverile di Villalilla. Il triplice profumo, l'anima primaverile di Villalilla, esalava nella calma a onde lente eguali. Giuliana diceva: --Ti ricordi? Ripeteva, ripeteva: --Ti ricordi? Le più lontane ricordanze del nostro amore venivano a una a una su la sua bocca, evocate a pena con qualche accenno discreto e pur riviventi con una straordinaria intensità nel luogo natale, tra le cose favorevoli. Ma quella sollecitudine affannosa, quel furore di vita, che m'avevano invaso nel giardino alla prima sosta, ora anche mi rendevano quasi insofferente, mi suggerivano visioni dell'avvenire iperboliche da contrapporre ai fantasmi del passato troppo incalzanti. --Bisogna che noi torniamo qui, domani, fra due, fra tre giorni al più, per rimanere; ma soli. Tu vedi: qui non manca nulla; non è stato portato via nulla. Se tu volessi, potremmo anche rimanere stanotte qui.... Ma tu non vuoi! È vero che non vuoi? Con la voce, col gesto, con lo sguardo io cercavo di tentarla. Le mie ginocchia toccavano le sue ginocchia. Ed ella mi guardava fissamente, senza rispondere. --Imagini tu _la prima sera_, qui, a Villalilla? Andar fuori, restar fuori sin dopo l'Ave Maria, vedere le finestre illuminate! Ah, tu intendi bene.... I lumi che si accendono in una casa per la prima volta, _la prima sera_! Imagini? Fino ad ora tu non hai fatto che ricordare, ricordare. E pure, vedi: tutti i tuoi ricordi non valgono per me un momento di oggi, non varranno un momento di domani. Dubiti tu, forse, della felicità che abbiamo d'avanti? Io non t'ho mai amata come t'amo ora, Giuliana; mai mai. Intendi? Io non sono mai stato tuo come ora, Giuliana.... Ti racconterò, ti racconterò le mie giornate, perchè tu conosca i tuoi miracoli. Dopo tante cattive cose, chi poteva sperare una cosa simile? Ti racconterò.... Mi pareva, in certe ore, d'essere tornato al tempo dell'adolescenza, al tempo della prima giovinezza. Mi sentivo _candido_ come allora; buono, tenero, semplice. Non mi ricordavo più di nulla. Tutti tutti i miei pensieri erano tuoi; tutte le mie commozioni si riferivano a te. Certe volte, la vista d'un fiore, d'una piccola foglia, bastava a far traboccare la mia anima, tanto era piena. E tu non sapevi nulla; non t'accorgevi di nulla, forse. Ti racconterò.... L'altro giorno, sabato, quando entrai nella tua stanza con quelle spine! Ero timido come un innamorato novello e mi sentivo morire, dentro, dal desiderio di prenderti fra le mie braccia.... Non te n'accorgesti? Ti racconterò tutto; ti farò ridere. Quel giorno le cortine dell'alcova lasciavano intravedere il tuo letto. Non potevo distaccare gli occhi di là, e tremavo. Come tremavo! Tu non sai.... Già due o tre altre volte io ero entrato nella tua stanza, solo, di nascosto, con una grande palpitazione; ed avevo sollevato le cortine per guardare il tuo letto, per toccare il tuo lenzuolo, per affondare la faccia nel tuo guanciale, come un amante fanatico. E certe notti, quando tutti già dormivano alla Badiola, io mi avventuravo, piano piano, fin quasi alla tua porta; credevo di ascoltare il tuo respiro.... Dimmi, dimmi: stanotte potrò venire da te? Mi vorrai? Di': mi aspetterai? Potremmo dormire lontani, stanotte? Impossibile! La tua guancia ritroverà il suo posto sul mio petto, qui,--ti ricordi? Come dormivi leggera! --Tullio, Tullio, taci!--m'interruppe ella, supplichevole, quasi che le mie parole le facessero male. Soggiunse, sorridendo: --Bisogna che tu non mi ubriachi così.... Te lo dicevo, dianzi. Sono tanto debole; sono una povera malata.... Tu mi dai le vertigini. Io non reggo. Vedi come mi hai già ridotta? Mi hai lasciata con mezz'anima.... Ella sorrideva, con un sorriso tenue, stancamente. Aveva le palpebre un poco arrossite; ma sotto quella stanchezza delle palpebre gli occhi le ardevano d'un ardore febrile e mi guardavano di continuo, con una fissità quasi intollerabile se bene temperata dall'ombra dei cigli. In tutta la sua attitudine era qualche cosa d'innaturale che la mia vista non riusciva a cogliere né il mio spirito a definire. Quando mai la sua fisonomia aveva avuto quel carattere di mistero inquietante? Pareva che di tratto in tratto la sua espressione si complicasse, si oscurasse fino a divenire enigmatica. Ed io pensavo: "Ella è travagliata dal vortice interiore. Non vede ancora chiaramente in sé medesima quel che è accaduto. Tutto, forse, dentro di lei è sconvolto. La sua esistenza non è mutata in un attimo?" E quella espressione profonda mi attirava e mi appassionava sempre più. L'ardore del suo sguardo mi penetrava nelle midolle come un fuoco vorace. Benché io la vedessi così affranta, ero impaziente di prenderla ancora, di stringerla ancora, di udire un altro suo grido, di beverle tutta l'anima. --Non mangi nulla--io le dissi, facendo uno sforzo per dissipare il vapore che mi saliva al capo rapidamente. --Anche tu. --Almeno bevi un sorso. Non riconosci questo vino? --Oh, lo riconosco. --Ti ricordi? E ci guardammo dentro le pupille, alterati, nell'evocare il ricordo d'amore su cui ondeggiava il fumo di quel delicato vino amaretto e biondo ch'ella prediligeva. --Beviamo dunque insieme, alla nostra felicità! Urtammo i bicchieri ed io bevvi con foga; ma ella non bagnò né pure le labbra, come presa da una ripugnanza invincibile. --E bene? --Non posso, Tullio. --Perché? --Non posso. Non mi forzare. Credo che anche una goccia mi farebbe male. Ella s'era coperta d'un pallore cadaverico. --Ma tu ti senti male, Giuliana. --Un poco, alziamoci. Andiamo sul balcone. Cingendola sentii la viva mollezza del suo fianco, poiché nella mia assenza ella s'era liberata del busto. Le dissi: --Vuoi stenderti sul letto? Tu ti riposerai e io ti starò accanto.... --No, Tullio. Sto già bene, vedi. E ci fermammo sul limitare del balcone, al conspetto del cipresso. Ella s'appoggiò allo stipite, e posò una mano su la mia spalla. Dalla sporgenza dell'architrave, di sotto alla cimasa, pendeva un gruppo di nidi. Le rondini vi accorrevano e se ne partivano con un'attività incessante. Ma così piena era la calma del giardino sottoposto, così ferma era la cima del cipresso innanzi a noi, che quei frulli, quei voli, quei gridi mi diedero un senso di fastidio, mi dispiacquero. Poiché tutto s'attenuava, si velava, in quella luce quieta, desiderai una pausa, un lungo intervallo di silenzio, un raccoglimento, per assaporare tutta quanta la soavità dell'ora e della solitudine. --Ci saranno ancora gli usignuoli?--dissi, ricordando le violente melodìe vespertine. --Chi sa! Forse. --Cantano verso sera. Non ti piacerebbe di riudirli? --Ma a che ora ripasserà Federico? --Tardi, speriamo, --Oh sì, tardi, tardi!--ella esclamò, con una sincerità d'augurio così calda ch'io n'ebbi un fremito di gioia. --Sei felice?--le domandai, cercandole negli occhi la risposta. --Sì, sono felice--ella rispose, abbassando i cigli. --Sai che amo te sola, che sono tutto tuo per sempre? --Lo so. --E tu ora.... come mi ami? --Come non potrai mai sapere, povero Tullio! E, dicendo queste parole, ella si staccò dallo stipite e si appoggiò tutta su me con una di quelle sue movenze indescrivibili in cui era quanto di abbandonata dolcezza la più femmina delle creature può emanare verso un uomo. --Bella! bella! Veramente bella appariva, illanguidita, arrendevole, molle, quasi direi fluida così che mi faceva pensare alla possibilità di assorbirla a poco a poco, d'imbevermene. Sul pallore del viso la massa dei capelli rilasciata sembrava che stesse per diffondersi in fiotto. I cigli le spandevano a sommo delle gote un'ombra che mi turbava più d'uno sguardo. --Anche tu non potrai mai sapere.... Se ti dicessi i pensieri folli che mi nascono dentro! È una felicità così grande che mi dà l'angoscia, mi dà quasi il desiderio di morire. --Morire!--ella ripetè sommessamente, con un sorriso tenue. --Chi sa, Tullio, che io non ti muoia.... presto! --Oh, Giuliana! Ella si sollevò diritta per guardarmi; e soggiunse: --Dimmi, che faresti tu se io ti morissi, all'improvviso? --Bambina! --Se, per esempio, domani io fossi morta? --Ma taci! E io la presi alle tempie e incominciai a baciarla su la bocca, su le gote, su gli occhi, su la fronte, su i capelli, con baci rapidi e leggeri. Ella si lasciava baciare. Anzi, quando io mi arrestai, mormorò: --Ancora! --Ritorniamo nella nostra stanza--io pregai, traendola. Ella si lasciava trarre. Anche nella nostra stanza il balcone era aperto. Entrava con la luce l'odore muschiato delle rose gialle che fiorivano là presso. Sul fondo chiaro delle tappezzerie i minuti fiori azzurri erano tanto sbiaditi che a pena si vedevano. Un lembo del giardino si rifletteva nello specchio di un armadio, sfondando in una lontananza chimerica. I guanti, il cappello, un braccialetto di Giuliana, posati su un tavolo, parevano aver già ridestata là dentro l'amorosa vita di un tempo, aver già diffusa un'aria nuova d'intimità. --Domani, domani bisogna tornare qui; non più tardi--io dicevo, ardendo d'impazienza, sentendo venire a me da tutte quelle cose non so quale incitazione e quale lusinga.--Bisogna che domani noi dormiamo qui. Tu vuoi; non è vero? --Domani! --Ricominciare l'amore, in questa casa, in questo giardino, con questa primavera.... Ricominciare l'amore, come se nulla ci fosse noto; ricercare a una a una le nostre carezze e trovare in ognuna un sapore nuovo, come se non le avessimo provate mai; e avere d'innanzi a noi molti giorni, molti giorni.... --No, no, Tullio; non si parla dell'avvenire.... Non sai che è un cattivo augurio? Oggi, oggi... Pensa a oggi, all'ora che passa.... Ed ella si strinse a me, perdutamente, con un ardore incredibile, serrandomi a furia di baci la bocca. IX. --M'è parso di udire i sonagli dei cavalli--fece Giuliana, sollevandosi.--Arriva Federico. Ascoltammo. Ella doveva essersi ingannata. --Non è l'ora?--mi domandò. --Sì, sono quasi le sei. --Oh, mio Dio! Ascoltammo di nuovo. Non si udiva alcuno strepito che annunziasse la carrozza. --Ma è meglio che tu vada a vedere, Tullio. Uscii dalla stanza: scesi le scale. Vacillavo un poco; avevo una nebbia su gli occhi; mi sembrava che un vapore mi s'involasse dal cervello. Per la piccola porta laterale del muro di cinta, chiamai Calisto che aveva la sua abitazione là presso. Lo interrogai.--La carrozza non si vedeva ancora. Il vecchio avrebbe voluto trattenermi a discorrere. --Sai, Calisto, che torneremo qui probabilmente domani, per rimanerci?--gli dissi. Alzò le braccia verso il cielo, in segno d'allegrezza. --Davvero? --Davvero. Avremo tempo di discorrere! Quando vedi la carrozza, vieni ad avvertirmi. Addio, Calisto. E lo lasciai per rientrare. Cadendo il giorno, le rondini aumentavano i clamori. L'aria s'era accesa, e gli stormi veementi la fendevano luccicando. --E bene?--mi chiese Giuliana, volgendosi dallo specchio d'innanzi a cui stava già per mettersi il cappello. --Nulla. --Guardami. Sono ancora troppo scapigliata? --No. --Ma che viso! Guardami. Pareva veramente ch'ella si fosse levata dalla bara tanto era disfatta. I suoi occhi avevano un gran cerchio violaceo. --E pure sono viva--ella soggiunse; e volle sorridere. --Tu soffri? --No, Tullio. Ma già, non so. Mi pare di essere tutta vuota, di avere la testa vuota, le vene vuote, il cuore vuoto.... Tu potrai dire che t'ho dato tutto. Non ho lasciato per me, vedi, che a pena a pena un'apparenza di vita.... Ella sorrideva, pronunziando tali parole, stranamente; sorrideva d'un sorriso tenue e sibillino che mi turbava a dentro movendo indefinite inquietudini. Troppo ero intorpidito dalla voluttà, troppo ero offuscato dall'ebrezza; e i moti del mio spirito erano per ciò pigri, la mia conscienza era ottusa. Non mi penetrava ancora nessun sospetto sinistro. Pure, io la guardavo con attenzione, la esaminavo angustiato senza sapere perché. Ella si rivolse allo specchio, si mise il cappello; poi andò verso il tavolo, prese il braccialetto, i guanti. --Sono pronta--disse. Parve cercare qualche altro oggetto, con lo sguardo. Soggiunse: --Avevo un ombrello; è vero? --Sì, credo. --Ah, ecco: devo averlo lasciato laggiù, sul sedile, al bivio. --Andiamo a cercarlo? --Sono troppo stanca. --Vado io solo, allora. --No. Manda Calisto. --Vado io. Ti coglierò qualche ramo di lilla, un mazzo di rose muscate. Vuoi? --No. Lascia stare i fiori.... --Vieni qui. Siediti, intanto. Forse Federico tarderà. Accostai al balcone una poltrona, per lei; ed ella vi si abbandonò. --Già che scendi--mi disse--guarda se il mio mantello è da Calisto. Non sarà rimasto nella carrozza; è vero! Ho un poco di freddo. Rabbrividiva in fatti. --Vuoi che ti chiuda il balcone? --No, no. Lasciami guardare il giardino. A quest'ora, com'è bello! Vedi? Com'è bello! Il giardino si dorava qua e là, vagamente. Le cime fiorite degli alberi di lilla pendevano in un color paonazzo vivo; e, come il resto dei rami fioriti in una massa tra bigia e turchiniccia ondeggiava all'aria, parevano i riflessi d'una seta cangiante. Su la peschiera i salici di Babilonia inchinavano le loro capellature soavi; e l'acqua vi traspariva col fulgore della madreperla. Quel fulgore immobile e quel gran pianto arboreo e quella selva di fiori così delicata in quell'oro morente componevano una visione maliosa, incantevole, senza realtà. Ambedue per qualche minuto rimanemmo taciturni, in potere di quei prestigi. Una malinconia confusa m'invadeva l'anima; l'oscura disperazione che è latente in fondo ad ogni amore umano si moveva dentro di me. D'avanti a quello spettacolo ideale, la mia stanchezza fisica, il torpore de' miei sensi, parevano appesantirsi. Mi occupavano il malessere, lo scontento, l'indefinito rimorso che seguono la cessazione delle voluttà troppo acute e troppo lunghe. Io soffrivo. Giuliana disse, come in un sogno: --Ecco, ora vorrei chiudere gli occhi e non riaprirli più. Soggiunse, rabbrividendo: --Tullio, ho freddo. Va. Distesa nella poltrona, ella si restrinse in sé stessa come per resistere ai brividi che l'assalivano. Il suo volto, specie intorno alle narici aveva la trasparenza di certi alabastri lividicci. Ella soffriva. --Tu ti senti male, povera anima!--io le dissi, accorato, con un po' di sbigottimento, guardandola fiso. --Ho freddo. Va. Portami il mantello, subito.... Ti prego. Corsi giù da Calisto, mi feci dare il mantello; risalii subito. Ella aveva fretta d'indossarlo. L'aiutai. Quando si riadagiò nella poltrona, nascondendo le mani dentro le maniche, disse: --Sto bene, così. --Vado allora a prendere l'ombrello, laggiù, dove l'hai lasciato? --No. Che importa? Io aveva una strana smania di tornare laggiù, a quel vecchio sedile di pietra dove avevamo fatta la prima sosta, dove ella aveva pianto, dove ella aveva pronunziate le tre parole divine: "Sì, anche più...." Era una tendenza sentimentale? Era la curiosità d'una sensazione nuova? Era il fascino che esercitava su me l'aspetto misterioso del giardino in quell'ora ultima? --Vado e torno in un minuto--dissi. Uscii. Come fui sotto il balcone, chiamai: --Giuliana! Ella si mostrò. Ho ancora avanti gli occhi dell'anima, evidentissima, la muta apparizione crepuscolare: quella figura alta, resa più alta dalla lunghezza del mantello amaranto, e sul cupo colore quella bianca bianca faccia. (Le parole di Jacopo ad Amanda si sono legate, nel mio spirito, con l'imagine inalterabile. "_Come_ _bianca, questa sera, Amanda! Vi siete voi svenata per colorare la vostra veste?_") Ella si ritrasse; anzi meglio è dire, per esprimere la sensazione ch'io n'ebbi; disparve. Ed io m'avanzai pel viale rapidamente, non avendo la piena consapevolezza di ciò che mi spingeva. Udivo risonare i miei passi nel mio cervello. Tanto ero smarrito che dovetti fermarmi per riconoscere i sentieri. Da che mi veniva quell'agitazione cieca? Da una semplice causa fisica, forse; da uno stato particolare de' miei nervi, Così pensai. Incapace d'uno sforzo riflessivo, d'un esame ordinato, d'un raccoglimento, io ero in balìa de' miei nervi; su i quali le apparenze si riflettevano provocando fenomeni d'una straordinaria intensità, come nelle allucinazioni. Ma alcuni pensieri balenavano chiari sopra gli altri, si distinguevano; accrescevano in me quel senso di perplessità che già alcuni incidenti impreveduti avevano mosso.--Giuliana in quel giorno non m'era apparsa tale quale avrebbe ella dovuto apparire essendo la creatura ch'io conoscevo, "la Giuliana d'una volta." Ella non aveva assunto verso di me, in certe date circostanze, le attitudini che io m'aspettavo. Un elemento estraneo, qualche cosa d'oscuro, di convulso, di eccessivo, aveva modificata, difformata la sua personalità. Dovevano queste alterazioni attribuirsi a uno stato morboso del suo organismo? "Sono malata, sono molto malata", ella aveva spesso ripetuto, come per giustificarsi. Certo, la malattia produceva alterazioni profonde, poteva rendere irriconoscibile un essere umano. Ma qual'era la sua malattia? L'antica, non distrutta dal ferro del chirurgo, complicata forse? Insanabile? "Chi sa che io non ti muoia _presto_!" ella aveva detto, con un accento singolare che avrebbe potuto essere profetico. Più d'una volta ella aveva parlato di morte. Sapeva ella dunque di portare in sé un germe letale? Era ella dunque dominata da un pensiero lugubre? Un tal pensiero avea forse accesi in lei quelli ardori cupi, quasi disperati, quasi folli, tra le mie braccia. La gran luce subitanea della felicità aveva forse reso a lei più visibile e più terribile il fantasma che la perseguitava.... "Ella potrebbe dunque morire! La morte potrebbe dunque colpirla anche tra le mie braccia, in mezzo alla felicità!" pensai, con una paura che mi agghiacciò tutto e per qualche attimo m'impedì di proseguire, quasi che il pericolo apparisse imminente, quasi che Giuliana avesse presagito il vero quando aveva detto: "Se, per esempio, _domani_ io fossi morta?" Il crepuscolo cadeva, umidiccio. Qualche soffio di vento passava tra i cespugli imitando il fruscìo che vi avrebbero messo animali veloci nel trascorrere. Ancora qualche rondine dispersa gettava un grido, rombando per l'aria come il sasso d'una fionda. Su l'orizzonte occidentale la luce persisteva come il riverbero d'una vasta fucina sinistra. Giunsi fino al sedile, trovai l'ombrello; non mi indugiai se bene i ricordi recenti, ancor vivi, ancora caldi, mi toccassero l'anima. Là ella s'era lasciata cadere, affievolita, vinta; là io le avevo detto le parole supreme, le avevo fatto la rivelazione inebriante; "_Tu eri nella mia_ _casa, mentre io ti cercava lontano_"; là io avevo raccolto dalle sue labbra quel soffio per cui la mia anima era balzata all'apice della gioia; là io avevo bevuto le sue prime lacrime, e avevo udito i suoi singhiozzi, e avevo proferito la domanda oscura: "_È tardi, forse? È troppo tardi?_" Poche ore erano trascorse e tutte quelle cose erano già così lontane! Poche ore erano trascorse e la felicità pareva già dileguata! Con un altro senso, non meno terribile, si ripeteva dentro di me la domanda: "_È tardi, forse? È troppo tardi?_" E la mia angoscia cresceva; e quella luce dubbia, e quella discesa tacita dell'ombra, e quei rumori sospetti nei cespugli già intenebrati, e tutte quelle parvenze ingannevoli del crepuscolo presero nel mio spirito un significato funesto. "Se veramente fosse troppo tardi? Se veramente ella si sapesse condannata, sapesse di portare già dentro di sé la morte? Stanca di vivere, stanca di patire, non sperando più nulla da me, non osando di uccidersi a un tratto con un'arma o con un veleno, ella forse ha coltivato, ha aiutato il suo male, l'ha tenuto nascosto perché si diffondesse, perché s'approfondisse, perché divenisse immedicabile. Ella ha voluto essere condotta a poco a poco, segretamente, verso la liberazione, verso la fine. Sorvegliandosi, ella ha acquistato la scienza del suo male; ed ora _sa_, _è sicura_ di dover soccombere; sa anche forse che l'amore, la voluttà, i miei baci precipiteranno l'opera. Io torno a lei per sempre; una felicità insperata le si apre d'innanzi; ella mi ama e sa di essere immensamente amata; in un giorno, un sogno è divenuto per noi una realtà. Ed ecco, una parola viene alla sua bocca:--Morire!--" In confuso mi passarono d'innanzi le imagini truci che m'avevano travagliato nelle due ore d'attesa in quella mattina dell'operazione chirurgica, quando m'era parso di avere sotto gli occhi, precise come le figure di un atlante anatomico, tutte le spaventevoli devastazioni prodotte dai morbi nel grembo femminile. E un altro ricordo, anche più lontano, mi tornò portando imagini precise:--la stanza nell'ombra, la finestra spalancata, le tende palpitanti, la fiammella inquieta della candela contro lo specchio pallido, aspetti malaugurosi, e lei, Giuliana, in piedi, addossata a un armario, convulsa, che si torceva come se avesse inghiottito un veleno... E la voce accusatrice, la medesima voce, anche ripeteva: "_Per te, per te ha voluto morire. Tu, tu l'hai spinta a morire._" Preso da uno sgomento cieco, da una specie di pànico, quasi che quelle imagini fossero tutte realtà indubitabili, io mi misi a correre verso la casa. Alzando gli occhi vidi la casa inanimata, le aperture delle finestre e dei balconi piene d'ombra. --Giuliana!--gridai, con un'ambascia estrema, slanciandomi su per i gradini, quasi che temessi di non giungere in tempo a rivederla. Ma che avevo? Che demenza era quella? Anelavo, su per le scale quasi buie. Entrai nella stanza a precipizio. --Che è accaduto?--mi domandò Giuliana, sollevandosi. --Nulla, nulla... Credevo che tu avessi chiamato. Ho corso, un poco. Tu come stai ora? --Ho tanto freddo, Tullio; tanto freddo. Sentimi le mani. Ella mi tese le mani. Erano di gelo. --Sono tutta gelata così.... --Mio Dio! Come ti sarà venuto questo freddo? Che potrei fare per riscaldarti? --Non ti prender pena, Tullio. Non è la prima volta.... Mi dura ore ed ore. Non c'è nulla che giovi. Bisogna aspettare che passi.... Ma perchè tarda tanto Federico? È quasi notte. Ella si riabbandonò alla spalliera, come se avesse consumata tutta la sua forza in quelle parole. --Ora chiudo--io dissi, volgendomi al balcone. --No, no; lascia aperto.... Non è l'aria che mi dà questo freddo. Ho bisogno, anzi, di respirare.... Vieni qui, piuttosto, accanto a me. Prenditi quello sgabello. Io m'inginocchiai. Ella mi passò la sua mano gelida sul capo, con un gesto fievole, mormorando: --Povero Tullio mio! --Ma dimmi, Giuliana, amore, anima--proruppi, non potendo più reggere--dimmi la verità! Tu mi nascondi qualche cosa. Qualche cosa tu hai, certo, che non vuoi confessare: un pensiero fisso, qui, nel mezzo della fronte, un'ombra che non t'ha lasciata mai, da che siamo qui, da che siamo.... felici. Ma siamo veramente felici? Sei tu, puoi tu essere felice? Dimmi la verità. Giuliana! Perché vorresti ingannarmi? Sì, è vero; tu hai avuto male, tu stai male; è vero. Ma non è questo, no. _È un'altra cosa_, che non comprendo, che non conosco.... Dimmi la verità, anche se la verità dovesse fulminarmi. Stamani, quando tu singhiozzavi, io ti ho chiesto: "_È troppo tardi?_" E tu mi hai risposto: "No, no...." E io ti ho creduta. Ma non potrebbe essere _troppo tardi_ per un'altra ragione? _Qualche cosa_ potrebbe impedirti di godere questa grande felicità che oggi s'è aperta? Intendo: qualche cosa che tu sappia, che sia già nel tuo pensiero.... Dimmi la verità! E la fissai; e, come ella rimaneva muta, a poco a poco non vidi se non gli occhi suoi larghi, straordinariamente larghi, e cupi ed immobili. Tutto disparve, in torno. E io dovetti chiudere le palpebre per dissipare la sensazione di terrore che quelli occhi avevano messa in me. Quanto durò la pausa? Un'ora? Un secondo? --Sono malata--ella disse alfine, con una lentezza angosciosa. --Ma come malata?--io balbettai, fuori di me, credendo sentire nel suono di quelle due parole una confessione che corrispondeva al mio sospetto.--Come malata? _Da morirne_? Non so in che modo, non so con quale voce, non so con quale atto proferii la domanda estrema; non so veramente neppure se mi uscì intera dalle labbra, se ella la udì intera. --Tullio, no; non volevo dire questo, no, no.... Volevo dire che non è colpa mia se sono così, un poco strana.... Non è colpa mia.... Bisogna che tu abbia pazienza con me, bisogna che tu mi prenda ora così come sono.... Non c'è null'altro, credi; non ti nascondo nulla.... Potrò guarire, poi; guarirò.... Tu avrai pazienza; è vero? Tu sarai buono.... Vieni qui, Tullio, anima. Anche tu sei un poco strano, mi sembra; sospettoso.... Ti spaventi subito; ti fai bianco; chi sa che imagini.... Vieni qui, vieni qui; dammi un bacio.... Ancora uno.... ancora uno.... Così. Baciami; riscaldami.... Ora arriva Federico. Parlava interrottamente, un po' roca, con quella intraducibile espressione, carezzevole, tenera, inquieta, ch'ella aveva già avuto verso di me alcune ore prima, sul sedile, per calmarmi, per consolarmi. Io la baciavo. Poiché la poltrona era ampia e bassa, ella che era sottile mi fece posto al suo fianco e mi si strinse addosso rabbrividendo e con una mano prese un lembo del suo mantello e mi coprì. Stavamo come in un giaciglio, avvinti, a petto a petto, mescolando gli aliti. E io pensavo: "Se il mio alito, se il mio contatto potessero trasfonderle tutto il mio calore!" E facevo uno sforzo di volontà illusorio perché la trasfusione avvenisse. --Stasera--bisbigliai--stasera, nel tuo letto, ti terrò meglio. Tu non tremerai più.... --Sì, sì. --Vedrai come saprò tenerti. Ti addormenterò. Mi dormirai tutta la notte sul cuore.... --Sì. --Io ti veglierò, mi beverò il tuo fiato, ti leggerò sul viso i sogni che sognerai. Forse mi nominerai, in sogno.... --Sì, sì. --Qualche notte, _allora_, parlavi in sogno. Come mi piacevi! Ah che voce! Tu non puoi sapere.... Una voce che tu non hai potuto mai intendere e che io solo ti conosco, io solo.... E la riudrò. Chi sa che dirà! Forse mi nominerai. Quanto è caro l'atto della tua bocca mentre pronunzia l'_u_ del mio nome! Pare l'accenno di un bacio.... Lo sai? E ti suggerirò qualche parola all'orecchio, per entrare nel tuo sogno. Ti ricordi, _allora_, quando certe mattine indovinavo qualche cosa di quello che tu avevi sognato? Oh, vedrai, anima: sarò più dolce di allora. Vedrai di che tenerezze sarò capace, per guarirti. Tu hai bisogno di tante tenerezze, povera anima.... --Sì, sì--ella ripeteva ad ogni tratto, abbandonatamente, favorendo la mia illusione ultima, aumentando quella specie di ebrietà torpida che mi veniva dalla mia stessa voce e dal credere che ella ne fosse cullata come da una cantilena voluttuosa. --Hai udito?--le chiesi, sollevandomi un poco per ascoltar meglio. --Che? Arriva Federico? --No. Ascolta. Ambedue ascoltammo, guardando verso il giardino. Il giardino s'era confuso in una massa violacea, rotta ancora dal luccichio cupo della vasca. Una zona di luce persisteva ai confini del cielo, una larga zona tricolore: sanguigna in basso, poi arancia, poi verde del verde d'un vegetale morente. Nel silenzio crepuscolare una voce liquida e forte risonò, simile al preludio d'un flauto. Cantava l'usignuolo. --È sul salice--mi susurrò Giuliana. Ambedue ascoltammo, guardando verso l'estrema zona che impallidiva sotto la cenere impalpabile della sera. La mia anima era sospesa, quasi che da quel linguaggio aspettasse una qualche alta rivelazione d'amore. Che provò in quei minuti d'ascolto, al mio fianco, la povera creatura? A quale sommità di dolore giunse la povera anima? L'usignuolo cantava. Da prima fu come uno scoppio di giubilo melodioso, un getto di trilli facili che caddero nell'aria con un suono di perle rimbalzanti su per i vetri di un'armonica. Successe una pausa. Un gorgheggio si levò, agilissimo, prolungato straordinariamente come per una prova di forza, per un impeto di baldanza, per una sfida a un rivale sconosciuto. Una seconda pausa. Un tema di tre note, con un sentimento interrogativo, passò per una catena di variazioni leggère, ripetendo la piccola domanda cinque o sei volte, modulato come su un tenue flauto di canne, su una fistula pastorale. Una terza pausa. Il canto divenne elegiaco, si svolse in un tono minore, si addolcì come un sospiro, si affievolì come un gemito, espresse la tristezza di un amante solitario, un desio accorato, un'attesa vana; gittò un richiamo finale, improvviso, acuto come un grido di angoscia; si spense. Un'altra pausa, più grave. Si udì allora un accento nuovo, che non pareva escire dalla stessa gola, tanto era umile, timido, flebile, tanto somigliava al pigolio delli uccelli appena nati, al cinguettio d'una passeretta; poi, con una volubilità mirabile, quell'accento ingenuo si mutò in una progressione di note sempre più rapide che brillarono in volate di trilli, vibrarono in gorgheggi nitidi, si piegarono in passaggi arditissimi, sminuirono, crebbero, attinsero le altezze soprane. Il cantore s'inebriava del suo canto. Con pause così brevi che le note quasi non finivano di spegnersi, effondeva la sua ebrietà in una melodia sempre varia, appassionata e dolce, sommessa e squillante, leggera e grave, e interrotta ora da gemiti fiochi, da implorazioni lamentevoli, ora da improvvisi impeti lirici, da invocazioni supreme. Pareva che anche il giardino ascoltasse, che il cielo s'inchinasse su l'albero melancolico dalla cui cima un poeta, invisibile, versava tali flutti di poesia. La selva dei fiori aveva un respiro profondo ma tacito. Qualche bagliore giallo s'indugiava nella zona occidentale; e quell'ultimo sguardo del giorno era triste, quasi lugubre. Ma una stella, spuntò, tutta viva e trepida come una goccia di rugiada luminosa. --Domani!--io mormorai quasi inconscio, rispondendo a una sollecitazione interiore quella parola che conteneva per me tante promesse. Poichè per ascoltare ci eravamo sollevati alquanto ed eravamo rimasti qualche minuto in quell'attitudine assorti; io sentii all'improvviso abbattermisi contro la spalla il capo di Giuliana pesantemente come una cosa inanimata. --Giuliana!--gridai sbigottito.--Giuliana! E, pel moto che io feci, quel capo si arrovesciò in dietro pesantemente come una cosa inanimata. --Giuliana! Ella non udiva. Scorgendo il pallore cadaverico di quel volto che rischiaravano gli ultimi barlumi gialligni avversi al balcone, io fui percosso dall'idea terribile. Fuori di me, lasciando ricadere su la spalliera Giuliana inerte, non cessando di chiamarla per nome, mi misi ad aprirle l'abito sul petto con le dita convulse, ansioso di sentirle il cuore.... E la voce gaia di mio fratello chiamò: --Colombi, dove siete? X. Ella aveva ricuperata in breve la conoscenza. A pena in grado di reggersi, aveva voluto subito montare in carrozza per tornare alla Badiola. Ora, coperta dei nostri _plaids_, stava rannicchiata nel suo posto, silenziosa. Io e mio fratello di tratto in tratto ci guardavamo inquieti. Il cocchiere sferzava i cavalli. E il trotto serrato risonava forte su la strada che le siepi qua e là fiorite limitavano: in una sera d'aprile mitissima, sotto un cielo puro. Di tratto in tratto io e Federico domandavamo: --Come ti senti, Giuliana? Ella rispondeva: --Eh, così.... un po' meglio. --Hai freddo? --Sì.... un poco. Rispondeva con uno sforzo manifesto. Pareva quasi che le nostre domande la irritassero; tanto che, insistendo Federico a muovere qualche discorso, ella disse alfine: --Scusa, Federico.... Mi dà fastidio parlare Essendo spiegato il mantice, ella stava nell'ombra, nascosta, immobile sotto le coperte. Più d'una volta io mi chinai verso di lei per scorgerle il viso, o credendo ch'ella si fosse assopita o temendo ch'ella fosse ricaduta nel deliquio. Tutte le volte ebbi la stessa sensazione inaspettata di sgomento, accorgendomi ch'ella teneva nell'ombra gli occhi sbarrati e fissi. Seguì un lungo intervallo di silenzio. Anche io e Federico ammutolimmo. Il trotto dei cavalli non mi pareva a bastanza rapido. Avrei voluto ordinare al cocchiere di spingerli al galoppo. --Sferza, Giovanni! Erano quasi le dieci quando giungemmo alla Badiola. Mia madre ci aspettava, in pena per l'indugio. Quando vide Giuliana in quello stato, disse: --Me l'imaginavo io, che lo strapazzo ti avrebbe fatto male.... Giuliana volle rassicurarla. --Non è nulla, mamma.... Vedrai che domattina starò bene. Un po' di stanchezza.... Ma, guardandola alla luce, mia madre esclamò spaventata: --Dio mio! Dio mio! Tu hai un viso che fa paura.... Tu non ti reggi in piedi.... Edith, Cristina, presto, correte su a scaldare il letto. Vieni, Tullio, che la portiamo su.... --Ma no, ma no--insisteva Giuliana, opponendosi--non ti spaventare, mamma, che non è nulla.... --Io vado a Tussi con la carrozza a prendere il medico--propose Federico.--Tra mezz'ora son qui. --No, Federico, no!--gridò Giuliana; quasi con violenza, come esasperata.--Non voglio. Il medico non può farmi nulla. So io quel che debbo prendere. Ho tutto, su. Andiamo, mamma. Dio mio! Come v'allarmate subito! Andiamo, andiamo.... Ed ella parve aver riacquistata la forza a un tratto. Diede alcuni passi, franca. Su per le scale, io e mia madre la sorreggemmo. Nella stanza, ella fu assalita da un vomito convulso che le durò alcuni minuti. Le donne incominciavano a spogliarla. --Va, Tullio, va--ella mi pregò.--Tornerai dopo a vedermi. Resta qui la mamma, intanto. Non ti prender pena.... Uscii. Rimasi in una delle stanze attigue, seduto su un divano, ad aspettare. Ascoltavo il passo delle donne di casa affaccendate; mi rodevo d'impazienza. "Quando potrò rientrare? Quando potrò rimanere solo con lei? La veglierò; starò tutta la notte al suo capezzale. Forse fra qualche ora ella si calmerà, si sentirà bene. Accarezzandole i capelli, forse riescirò ad addormentarla. Chi sa! Dopo un poco, tra la veglia ed il sonno, mi dirà:--Vieni." Avevo una strana fede nella virtù delle mie carezze. Speravo ancora che quella notte potesse avere una dolce fine. E come sempre, tra le angosce che mi dava il pensiero delle sofferenze di Giuliana, l'imagine sensuale si determinava diventando una visione lucida e durevole. "_Pallida come la sua camicia_, al chiaror della lampada che arde dietro le cortine dell'alcova, ella si sveglia dopo il primo sonno breve, mi guarda con gli occhi semiaperti, languida, mormorando:--Vieni a dormire anche tu...." Entrò Federico. --E bene?--disse affettuosamente.--Pare che non sia nulla. Ho parlato con miss Edith or ora, per le scale. Non vuoi scendere a mangiar qualche cosa? Giù, hanno preparato.... --No, non ho appetito, ora. Forse più tardi.... Aspetto che mi chiamino dentro. --Intanto io vado, se non c'è bisogno di me. --Va pure, Federico. Scenderò poi. Grazie. Lo seguii con lo sguardo, mentre s'allontanava. E ancora una volta mi venne dal buon fratello un sentimento di confidenza; ancora una volta mi s'allargò il cuore. Passarono tre minuti circa. L'orologio a pendolo, ch'era su la parete di contro a me, li misurò col suo ticchettio. Le sfere segnavano le dieci e tre quarti. Mentre io mi levavo impaziente per andare verso la stanza di Giuliana, entrò mia madre commossa dicendo sotto voce: --S'è calmata. Ora ha bisogno di riposo. Povera figliuola! --Posso andare?--le domandai. --Sì, va; ma lasciala riposare. Come io mi mossi, ella mi richiamò. --Tullio! --Che vuoi, mamma? Ella pareva esitante. --Dimmi.... Dal tempo dell'operazione, hai più parlato col dottore? --Ah, sì, qualche volta.... Perché? --T'ha rassicurato sul pericolo.... Ella esitava. --.... sul pericolo che potrebbe correre Giuliana, in un altro parto? Io non avevo parlato col dottore; non sapevo che rispondere. Confuso, ripetei: --Perché? Ella esitava ancora. --Non ti sei accorto che Giuliana è incinta? Percosso come da un colpo di maglio nel mezzo del petto, da prima non afferrai la verità. --Incinta!--balbettai. Mia madre mi prese le mani. --E bene, Tullio? --Non sapevo.... --Ma tu mi fai paura. Il dottore dunque.... --Già, il dottore.... --Vieni, Tullio, siediti. E mi fece sedere sul divano. Mi guardava sbigottita, aspettando che io parlassi. Per qualche attimo, benché io l'avessi lì d'avanti agli occhi, non la vidi più. Una luce violentissima si fece nel mio spirito, a un tratto; e mi si presentò il dramma. Chi mi diede la forza di resistere? Chi mi conservò la ragione? Forse nell'eccesso medesimo del dolore e dell'orrore io trovai il sentimento eroico che mi salvò. A pena riacquistai la sensibilità fisica, la percezione delle cose esteriori, e vidi mia madre che mi guardava da presso con ansia, compresi che prima di tutto bisognava assicurare mia madre. Le dissi: --Non sapevo.... Giuliana non m'ha detto nulla. Non mi sono accorto di nulla.... È una sorpresa.... Il dottore, sì, mi parlò di qualche pericolo.... Per ciò la notizia mi fa quest'impressione.... Sai, Giuliana ora è così debole.... Ma veramente il dottore non accennò a nulla di troppo grave; perché, essendo riescita l'operazione.... Vedremo. Lo chiameremo qui; lo consulteremo.... --Sì, sì; è necessario. --Ma tu, mamma, sei sicura della cosa? Te l'ha confessata Giuliana, forse? O pure.... --Io me ne sono accorta, sai, dai soliti segni, impossibile ingannarsi. Fino a due o tre giorni fa, Giuliana negava o almeno diceva di non esserne certa.... Sapendoti così apprensivo, m'ha pregata di non parlartene per ora. Ma io ho voluto avvisarti.... Giuliana, tu la conosci, è così trascurata per la sua salute! Vedi: qui, in vece di migliorare, mi sembra che vada ogni giorno peggiorando; mentre prima bastava una settimana di campagna per farla rifiorire. Ti ricordi? --Sì, è vero. --Le precauzioni, in questi casi, non sono mai troppe. Bisogna che tu ne scriva subito al dottor Vebesti. --Sì, subito. E, poiché sentivo che non avrei potuto dominarmi più oltre, mi alzai soggiungendo: --Vado da Giuliana. --Va; ma stasera lasciala riposare, lasciala tranquilla. Io scendo e poi torno su. --Grazie, mamma. E le sfiorai la fronte con le labbra. --Figlio benedetto!--ella mormorò, allontanandosi. Su la soglia della porta opposta mi fermai e mi volsi; e vidi sparire quella dolce figura ancora diritta, così nobile nella veste nera. Ebbi una sensazione indescrivibile, simile forse a quella che avrei avuta dal crollo fulmineo di tutta la casa. Tutto crollò, ruinò, dentro di me, intorno a me, irresistibilmente. XI. Chi non ha udito qualche volta proferire da uomini sventurati una frase di questo genere? "In un'ora ho vissuto dieci anni." Una tal cosa è inconcepibile. Bene, io la comprendo. Nei pochi minuti di quel dialogo quasi pacato tra me e mia madre, io non vissi più di dieci anni? L'accelerazione della vita umana interiore è il più meraviglioso e il più spaventoso fenomeno dell'universo. Ora, che doveva io fare? Impeti folli mi venivano, di fuggire lontano nella notte, o di correre alle mie stanze per chiudermi, per rimaner solo a considerare la mia ruina, a conoscerla tutta quanta. Ma seppi resistere. La superiorità della mia natura si mostrò in quella notte. Seppi svincolare dall'atroce torsione qualcuna delle mie facoltà più virili. E pensai: "È necessario che nessuno dei miei atti apparisca singolare, inesplicabile, a mia madre, a mio fratello, a qualunque persona di questa casa." Innanzi all'uscio della stanza di Giuliana m'arrestai, impotente a frenare il tremore fisico che mi scoteva. Udendo giungere pel corridoio suono di passi, entrai risoluto. Miss Edith usciva dall'alcova su la punta dei piedi. Mi accennò di non far rumore. Mi disse sotto voce: --Sta per addormentarsi. Se ne andò, socchiudendo l'uscio dietro di sè, pianamente. La lampada ardeva sospesa nel mezzo della volta, con un chiarore placido eguale. Su una sedia era posato il mantello amaranto; su un'altra sedia, il busto di raso nero, il busto che Giuliana s'era tolto a Villalilla nella mia breve assenza; su un'altra sedia, l'abito grigio, quel medesimo ch'ella aveva portato con tanta finezza tra i fiori di lilla eleganti. La vista di quelle cose mi diede un tale spasimo che di nuovo ebbi l'impeto di fuggire. Mi volsi all'alcova, discostai le cortine; vidi il letto, vidi sul guanciale la macchia cupa dei capelli, non la faccia: vidi il rilievo del corpo rattratto sotto le coperte. Mi si presentò allo spirito la verità brutale in tutta la sua più ignobile brutalità. "Ella è stata posseduta da un altro, ha ricevuta l'escrezione di un altro, porta nel ventre il seme di un altro." E una serie d'imagini fisiche odiose mi si svolse d'avanti agli occhi dell'anima, che io non potevo serrare. E non furono soltanto le imagini di ciò che era accaduto, ma anche quelle di ciò che doveva necessariamente accadere. Bisognò anche ch'io vedessi, con una precisione inesorabile, Giuliana nel futuro (il mio Sogno, la mia Idealità!) difformata da un ventre enorme, gravida d'un feto adulterino.... Chi avrebbe potuto imaginare un castigo più feroce? E tutto era vero, tutto era _certo_! Quando il dolore eccede le forze, istintivamente l'uomo cerca nel dubbio un'attenuazione momentanea della sofferenza insofferibile; pensa: "Forse io m'inganno; forse la mia sciagura non è quale mi appare; forse tutto questo dolore è irragionevole." E, per protrarre la tregua, intende lo spirito perplesso ad acquistare una nozione più esatta della realtà. Ma a me il dubbio non si presentò né pure per un attimo; io non ebbi né pure un attimo d'incertezza. M'è impossibile esplicare il fenomeno che si svolse nella mia coscienza divenuta straordinariamente lucida. Pareva che per un segreto spontaneo processo, compiutosi in una sfera ulteriore oscura, tutti gli inavvertiti indizii relativi alla cosa tremenda si fossero coordinati tra loro formando una nozione logica, completa, coerente, definitiva, irrefragabile; la quale ora mi si manifestasse d'un tratto assorgendo nella mia conscienza con la rapidità di un oggetto che, non più trattenuto al fondo da legami ignoti, venga su la linea dell'acqua a galleggiare e vi rimanga insommergibile. Tutti gli indizii, tutte le prove erano là, in ordine. Io non dovevo compiere alcuno sforzo per ricercarli, per scegliergli, per riunirli. Fatti insignificanti, lontani, s'illuminavano nella nuova luce; lembi di vita recente si ricolorivano. E l'avversione insolita di Giuliana per i fiori, per gli odori, i suoi turbamenti singolari, le sue nausee mal dissimulate, i suoi pallori subitanei, quella specie di nube continua tra ciglio e ciglio, quella stanchezza immensa di certe sue attitudini e le pagine segnate con l'unghia nel libro russo, il rimprovero del vecchio al conte Besoukhow, la domanda estrema della piccola principessa Lisa, e quel gesto con cui ella mi aveva tolto di mano il libro; e poi le scene di Villalilla, le lacrime, i singhiozzi, le frasi ambigue, i sorrisi sibillini, i quasi lugubri ardori, le volubilità quasi folli, le evocazioni della morte, tutti gli indizii si aggruppavano intorno alle parole di mia madre incise nel centro della mia anima. Mia madre aveva detto: "_È impossibile ingannarsi._ Fino a due o tre giorni fa Giuliana negava o almeno _diceva di non esserne certa_.... Sapendoti così apprensivo, _m'ha pregata di non parlartene_...." La verità non poteva essere più chiara. Tutto, dunque, omai era certo! Entrai nell'alcova; m'appressai al letto. Dietro di me le cortine ricaddero; la luce divenne più fievole. L'ansietà mi tolse il respiro, tutto il sangue mi si fermò nelle arterie, quando io giunsi al capezzale e mi chinai per guardare più da vicino la testa di Giuliana quasi celata dal lenzuolo. Io non so che sarebbe avvenuto s'ella avesse alzato la faccia ed avesse parlato, in quel momento. Dormiva ella? Soltanto la fronte, fino ai sopraccigli, era scoperta. Rimasi là qualche minuto, in piedi, aspettando. Ma dormiva ella? Non si moveva, giacendo sul fianco. La bocca nascosta dal lenzuolo non dava segno di respirazione al mio udito. Soltanto la fronte, fino ai sopraccigli, era scoperta. Come mi sarei contenuto s'ella si fosse accorta della mia presenza? Non era quella l'ora delle interrogazioni, l'ora del colloquio. S'ella avesse sospettato che tutto m'era noto, a quali estremità si sarebbe spinta in quella notte? Avrei io dunque dovuto simulare un'ingenua tenerezza, avrei dovuto mostrarmi perfettamente ignaro, persistere nella espressione del sentimento che m'aveva dettato le dolci parole, quattro ore innanzi, a Villalilla. "Stasera, stasera, nel tuo letto.... Vedrai come saprò tenerti. Ti addormenterò. Mi dormirai tutta la notte sul cuore...." Girando lo sguardo in torno smarrito, scorsi sul tappeto gli scarpini lucidi e sottili, su la spalliera d'una sedia le lunghe calze di seta cinerina, le giarrettiere d'amoerro, un altro oggetto di segreta eleganza, tutte cose di cui i miei occhi d'amante s'erano già dilettati nelle intimità recenti. E la gelosia dei sensi mi morse con tanta furia che fu un prodigio se io mi trattenni dal gittarmi su Giuliana per risvegliarla e per gridarle le parole folli e crude che mi suggeriva la collera subitanea. Mi ritrassi vacillando, uscii dall'alcova. Pensai con un cieco sgomento: "Come finiremo?" Mi disponevo ad andarmene. "Scenderò. Dirò a mia madre che Giuliana dorme, che ha un sonno molto calmo; le dirò che anch'io ho bisogno di riposo. Mi ritirerò nella mia stanza. Domattina poi...." Ma rimanevo là perplesso, incapace di varcare la soglia, assalito da mille paure. Mi volsi ancora verso l'alcova, con un moto repentino, come se avessi sentito uno sguardo sopra di me. Mi parve che le cortine ondeggiassero; ma fu un abbaglio. E pure qualche cosa come un'onda magnetica a traverso le cortine veniva a penetrarmi; qualche cosa a cui non resistevo. Entrai nell'alcova una seconda volta, rabbrividendo. Giuliana giaceva nella medesima attitudine. Dormiva? Soltanto la fronte, fino ai sopraccigli, era scoperta. Mi sedetti, presso al capezzale; ed aspettai. Guardavo quella fronte pallida come il lenzuolo, tenue e pura come una particela, sororale, che tante volte le mie labbra avevano baciata religiosamente, che tante volte avevano baciata le labbra di mia madre. Non v'appariva segno di contaminazione; alla vista era sempre la stessa. E nulla al mondo poteva omai cancellare la macchia che vedevano su quel pallore gli occhi della mia anima! Alcune parole, proferite da me nell'ultima ebrezza, mi tornarono alla memoria. "Io ti veglierò, ti leggerò sul viso i sogni che sognerai." Ripensai: "Ella ripeteva ad ogni tratto:--Sì, sì." Domandai a me medesimo: "Di che vita ella vive, entro di sé? Quali sono i suoi propositi? Che ha ella risoluto?" E guardavo la sua fronte. E non più considerai il mio dolore; ma mi piegai tutto a raffigurare il suo dolore, a comprendere il suo dolore. Certo, doveva essere una disperazione inumana, la sua; senza tregua, senza limite. Il mio castigo era anche il suo castigo, ed era per lei forse un castigo anche più terribile. Laggiù, a Villalilla, pel viale, sul sedile, nella casa, ella aveva certo sentita la verità nelle mie parole, aveva certo letta la verità nella mia faccia. Ella aveva creduto al mio amore immenso. "_.... Tu eri nella mia casa mentre io ti cercavo lontano._ Ah, dimmi tu: questa rivelazione non vale tutte le tue lacrime? Non vorresti averne versate anche più, anche più, per una tale prova? --_Sì, anche più!..._" Così aveva ella risposto, così tutta la sua anima aveva risposto, con un soffio che veramente m'era parso divino. "_Sì, anche più!..._" Ella avrebbe voluto aver versato altre lacrime, avrebbe voluto aver sofferto un altro martirio per quella rivelazione! E, vedendo ai suoi piedi appassionato come non mai l'uomo da anni perduto e pianto, vedendo aprirsi d'innanzi a sé un gran paradiso ignoto, ella s'era sentita impura, aveva avuta la sensazione materiale della sua impurità, aveva dovuto sopportare la mia testa sul grembo fecondato dal seme di un altro uomo. Ah come mai, veramente le sue lacrime non mi avevano piagata la faccia? Come mai avevo potuto io beverle senza avvelenarmi? Rivissi in un attimo tutta la nostra giornata d'amore. Rividi tutte le espressioni, anche le più fuggevoli, apparse sul volto di Giuliana dal momento del nostro ingresso a Villalilla; e tutte le compresi. Una gran luce s'era fatta in me. "Ah quando io le parlavo del domani, le parlavo dell'avvenire!... Che spaventosa parola doveva essere per lei quel _Domani_ su le mie labbra!" E mi tornò alla memoria il breve dialogo avvenuto sul limitare del balcone al conspetto del cipresso. Ella aveva ripetuto sommessamente, con un sorriso tenue: "Morire!" Aveva parlato di fine prossima. Aveva domandato: "Che faresti tu se io ti morissi all'improvviso? Se, per esempio, _domani_ io fossi morta?" Più tardi, nella nostra stanza, ella aveva gridato stringendosi a me: "No, no, Tullio; non si parla dell'avvenire.... Pensa a oggi, all'ora che passa!" Non tradivano tali atti, tali parole un proposito di morte, una risoluzione tragica? Era manifesto ch'ella aveva risoluto di uccidersi, ch'ella si sarebbe uccisa, forse in quella notte medesima, prima del _domani_ indifferibile, non essendoci per lei altro scampo. Quando cessò il raccapriccio che mi venne dal pensiero del pericolo imminente, io considerai in me stesso: "Sarebbero più gravi le conseguenze della morte di Giuliana o quelle della sua incolumità? Poiché la ruina è senza riparo e l'abisso è senza fondo, una catastrofe immediata è forse preferibile alla prolungazione indefinita del dramma spaventevole." E la mia imaginazione mi faceva assistere alle fasi della nuova maternità di Giuliana, mi faceva vedere il nuovo essere procreato, l'intruso che avrebbe portato il mio nome, che sarebbe stato il mio erede, che avrebbe usurpato le carezze di mia madre, delle mie figliuole, di mio fratello. "Certo, soltanto la morte può interrompere il corso fatale di questi eventi. Ma il suicidio resterebbe segreto? Con qual mezzo Giuliana si ucciderebbe? Accertata la morte volontaria, che penserebbero mia madre, mio fratello? Qual colpo ne riceverebbe mia madre? E Maria? E Natalia? E che farei allora io della mia vita?" Non riuscivo, veramente, a concepire la mia vita senza Giuliana. Io amavo quella povera creatura anche nella sua impurità. Tranne quell'impeto subitaneo di collera suscitatomi dalla gelosia carnale, io non avevo ancor provato contro di lei un senso d'odio o di rancore o di disdegno. Non m'era balenato alcun pensiero di vendetta. In vece, io avevo di lei una misericordia profonda. Io accettavo, fin da principio, tutta la responsabilità della sua caduta. Un sentimento fiero e generoso mi sollevò, mi esaltò. "Ella ha saputo chinare il capo sotto i miei colpi, ha saputo soffrire, ha saputo tacere; mi ha dato l'esempio del coraggio virile, dell'abnegazione eroica. Ora è venuta la mia volta. Io le debbo il contraccambio. Debbo salvarla ad ogni costo." E questa sollevazione dell'anima, questa cosa buona, mi veniva da lei. La guardai da presso. Rimaneva come immobile, nella medesima attitudine, con la fronte scoperta. Pensai: "Ma dorme? Se invece fingesse di dormire per allontanare ogni sospetto, per farsi credere calma, per esser lasciata sola? Certo, se il suo proposito è di non arrivare a domani, ella cerca di favorirne l'esecuzione con ogni mezzo. Ella simula il sonno. Se il sonno fosse reale, non sarebbe così tranquillo, così fermo, in lei che ha i nervi sovreccitati. Ora la scuoto...." ma esitai: "Se realmente dormisse? Talvolta, dopo una grande dispersione di forza nervosa, anche in mezzo alle più fiere inquietudini morali il sonno piomba grave come una sincope. Oh le durasse questo sonno fino a domani e potesse ella domani levarsi rinfrancata, a bastanza forte per sostenere il colloquio tra noi inevitabile!" Guardavo fissamente quella fronte pallida come il lenzuolo; e, chinandomi un poco più, m'accorsi che diveniva madida. Una stilla di sudore spuntava sul sopracciglio. E quella stilla mi suscitò l'idea del sudor freddo che annuncia l'azione dei veleni narcotici. Subito mi balenò un sospetto. "La morfina!" E per istinto il mio sguardo corso al tavolo da notte, di là dal capezzale, come a cercarvi la fiala di vetro contrassegnata dal piccolo teschio nero, dal noto simbolo mortuario. Erano su quel tavolo una boccia d'acqua, un bicchiere, un candeliere, un fazzoletto, alcune forcine che rilucevano; non v'era altro. Feci un esame rapido di tutta l'alcova. Un'ansietà angosciosa mi stringeva. "Giuliana ha la morfina. Ne ha sempre avuta una certa quantità, liquida, per le iniezioni. Son sicuro che ha pensato di avvelenarsi con quella. Dove tiene nascosta la bottiglietta?" Io avevo fissa dentro le pupille l'imagine della piccola fiala di vetro veduta una volta tra le mani di Giuliana, distinta da quel segno sinistro che usano i farmacisti per distinguere un tossico. La fantasia eccitata mi suggerì: "E se ella avesse già bevuto?... Quel sudore...." Tremavo, su la sedia; e un dibattito rapido si agitava dentro di me. "Ma quando? Ma come? Ella non è rimasta mai sola.--Basta un attimo per vuotare una fiala.--Ma in lei non sarebbe forse mancato il vomito....--E quell'accesso di vomito convulso, dianzi, a pena ella è giunta qui? Avendo premeditato il suicidio, forse ella portava seco la morfina. Non può essere ch'ella l'abbia bevuta prima di giungere alla Badiola, in carrozza, nell'ombra? In fatti, ella ha impedito che Federico andasse a chiamare il medico...." Io non conoscevo bene i sintomi dell'avvelenamento per morfina. Nel dubbio, la fronte bianca e madida, la immobilità perfetta di Giuliana mi atterrivano. Stavo per scuoterla. "Ma se m'inganno? Ella si sveglia ed io che cosa le dico?" Mi pareva che la prima parola di lei, il primo sguardo scambiato tra lei e me, la prima comunicazione diretta tra lei e me, dovessero cagionarmi un effetto straordinario, d'una violenza imprevedibile, inimaginabile. Mi pareva che non avrei potuto dominarmi, dissimulare, e che ella subito, guardandomi, avrebbe indovinata la mia consapevolezza. E allora? Tesi l'orecchio, sperando e temendo che sopraggiungesse mia madre. Poi (non avrei tremato così nel sollevare il lembo d'un lenzuolo funebre per rivedere la sembianza di una persona estinta) scopersi a poco poco il volto di Giuliana. Ella aprì gli occhi. --Ah, Tullio, sei tu? Ella aveva la sua voce naturale. Cosa inaspettata: io potevo parlare. --Dormivi?--le dissi, evitando di guardarla nelle pupille. --Sì, m'ero assopita. --Io dunque t'ho svegliata.... Perdonami.... Volevo scoprirti la bocca. Temevo che tu non respirassi bene.... che le coperte ti affogassero.... --Sì, è vero. Ora ho caldo, troppo caldo.... Levami qualcuna di queste coperte; ti prego. E io mi alzai per alleggerirla di qualche coperta. M'è ora impossibile definire il mio stato di conscienza relativo a quelli atti che io facevo, a quelle parole che io dicevo e udivo, a quelle cose che accadevano naturalmente come se nulla fosse mutato, come se io e Giuliana fossimo ignari e immuni, come se là dentro non fossero l'adulterio, il disinganno, il rimorso, la gelosia, la paura, la morte, tutte le atrocità umane, in quell'alcova tranquilla. Ella mi domandò: --È molto tardi? --No, non è ancora mezzanotte. --La mamma è andata a letto? --Non ancora. Dopo una pausa: --E tu.... non vai? Devi essere stanco.... Non seppi rispondere. Dovevo rispondere che rimanevo? pregarla di lasciarmi rimanere? ripeterle le parole tènere proferite su la poltrona, nella _nostra_ stanza, a Villalilla? Ma, rimanendo, in che modo avrei passata la notte? Là, sulla sedia, a vegliare, o nel letto accanto a lei? in che modo mi sarei condotto? Avrei potuto simulare sino in fondo? Ella soggiunse: --È meglio che tu vada, Tullio.... per questa sera.... Io non ho bisogno più di nulla; non ho bisogno d'altro che di riposo. Se tu rimanessi.... sarebbe male.... È meglio che tu vada, per questa sera, Tullio. --Ma tu potresti aver bisogno.... --No. E poi, in ogni caso, c'è Cristina che dorme qui accanto. --Io mi stendo là, sul canapè, con una coperta.... --Perché vuoi soffrire? Tu sei molto stanco: si vede dalla faccia.... E poi, se io ti sapessi là, non dormirei. Sii buono, Tullio! Domattina, presto, tu verrai a vedermi. Ora abbiamo bisogno di riposo, tutt'e due: d'un riposo completo.... Ella aveva la voce fioca e carezzevole, senza alcun accento insolito. Tranne l'insistenza nel persuadermi ad andarmene, null'altro accusava in lei il proposito funesto. Ella pareva prostrata di forze ma calma. Di tratto in tratto chiudeva gli occhi, come se il sonno le aggravasse le palpebre.--Che fare? Lasciarla? Ma la sua calma a punto mi spaventava. Una tale calma non poteva venirle che dalla fermezza del proposito. Che fare? Tutto considerato, anche la mia presenza durante la notte sarebbe stata vana. Ella avrebbe potuto benissimo mandare ad effetto il suo pensiero, essendosi preparata, avendo pronto il mezzo. Questo mezzo era veramente la morfina? E dove teneva ella nascosta la fiala? sotto il guanciale? Nel cassetto del tavolo da notte? In che modo farne ricerca? Bisognava palesare tutto, dire all'improvviso: "Io so che tu ti vuoi uccidere." Ma quale scena sarebbe seguita? Non sarebbe stato possibile nascondere il resto. E che notte, allora, sarebbe stata quella?--Tante perplessità esaurivano ogni mia energia, mi dissolvevano. I miei nervi si rilasciavano. La stanchezza fisica diveniva sempre più grave. Tutto il mio organismo entrava in quello stato di sfinimento estremo in cui ogni funzione volontaria sta per essere sospesa, in cui azioni e reazioni non si corrispondono più o non si compiono. Io mi sentivo incapace di resistere più oltre, di lottare, di operare in una qualunque maniera utile. Il sentimento della mia debolezza, il sentimento della necessità di ciò che accadeva ed era per accadere mi paralizzavano. Il mio essere pareva colpito come da una paralisia repentina. Io provavo un bisogno cieco di sfuggire anche a quell'ultima oscura conscienza dell'essere. E finalmente tutte le mie ansietà si risolsero in un pensiero disperato. "Avvenga che può, c'è anche per me la morte." --Sì, Giuliana,--dissi--ti lascio in pace. Dormi. Ci vedremo domani. --Non ti reggi! --Già, è vero; non mi reggo.... Addio. Buona notte! --Non mi dai un bacio, Tullio? Un brivido di ripugnanza istintiva mi attraversò. Esitai. In quel punto entrava mia madre. --Come? Sei sveglia?--esclamò mia madre. --Sì, ma ora mi riaddormento. --Sono stata a vedere le bambine. Natalia era desta. M'ha domandato subito: "È tornata la mamma?" Voleva venire.... --Perché non dici a Edith che me la porti? S'è messa a letto Edith? --No. --Addio, Giuliana--interruppi. E m'appressai, e mi chinai a baciarle la guancia ch'ella mi porgeva sollevandosi un poco su i gomiti. --Addio, mamma. Vado a coricarmi perché ho un sonno che m'acceca. --E non prendi nulla? Federico è rimasto giù ad aspettarti.... --No, mamma; non ho voglia. Buona notte! E baciai su la guancia anche lei. Ed uscii senza indugio, senza volgere uno sguardo a Giuliana; raccolsi le poche forze che mi restavano e, a pena fuori della soglia, mi misi a correre verso le mie stanze, per tema di cadere prima di aver raggiunta la mia porta. Mi gettai bocconi sul letto. M'agitava quell'orgasmo che precede i grandi scoppi di pianto, quando il nodo dell'angoscia sta per disciogliersi, quando la tensione sta per allentarsi. Ma l'orgasmo durava, e il pianto non veniva. La sofferenza era orribile. Un peso enorme mi gravava in tutto il corpo, un peso che io sentivo non sopra ma dentro di me come se le mie ossa e i miei muscoli fossero divenuti di piombo compatto. E il mio cervello pensava ancora! E la mia conscienza era ancora vigile! "No, non dovevo lasciarla, non dovevo consentire ad andarmene così. Certo, quando mia madre si sarà ritirata, ella si ucciderà, il suono della sua voce quando ha espresso il desiderio di rivedere Natalia!..." Un'allucinazione s'impadronì di me, subitamente.--Mia madre usciva dalla stanza. Giuliana si levava a sedere sul letto, si metteva in ascolto. Poi, sicura d'essere alfine sola, prendeva dal cassetto del tavolo da notte la bottiglia della morfina; non esitava un attimo; con un gesto risoluto, la vuotava d'un fiato; si ritraeva sotto le coperte; si metteva supina, ad aspettare....--La visione imaginaria del cadavere giunse a una tale intensità che io, come un ossesso, m'alzai; girai tre o quattro volte intorno alla stanza urtando contro i mobili, inciampando nei tappeti, gesticolando paurosamente. Aprii una finestra. La notte era tranquilla, piena d'un gracidare di rane monotono e continuo. Le stelle palpitavano. L'Orsa brillava in contro, distinta. Il tempo fluiva. Rimasi alcuni minuti al davanzale, in attesa, fissando la grande costellazione che pareva alla mia vista perturbata avvicinarsi. Non sapevo, veramente, che attendessi. Mi smarrivo. Avevo un sentimento particolare della vacuità di quel cielo immenso. All'improvviso, in quella specie di pausa dubitosa, come se un qualche influsso oscuro avesse operato sul mio essere nella profondità dell'inconscienza, risorse spontanea la domanda non ancora bene compresa: "_Che avete fatto di me?_" E la visione del cadavere, per poco interrotta, si riaffacciò. L'orrore fu tale che io, pur non sapendo quale azione volessi compiere, mi volsi, uscii senza esitare, mi diressi verso la stanza di Giuliana. Incontrai miss Edith nell'andito. --Di dove venite, Edith?--le chiesi. M'accorsi ch'ella si stupì del mio aspetto. --Ho portato Natalia dalla signora che la voleva vedere; ma ho dovuto lasciarla là. Non è stato possibile persuaderla a tornarsene nel suo letto. Ha pianto tanto che la signora ha consentito a tenerla con sé. Speriamo che Maria non si svegli ora.... --Ah dunque.... Il cuore mi batteva con tal veemenza, che non potevo parlare di seguito. --Ah, dunque, Natalia è rimasta nel letto della madre.... --Sì, signore. --E Maria.... Andiamo a vedere Maria. La commozione mi soffocava. Giuliana per quella notte era salva! Non era possibile ch'ella pensasse a morire in quella notte, avendo la bambina al suo fianco. Per miracolo, il tenero capriccio di Natalia aveva salvato la madre. "Benedetta! Benedetta!" Prima di guardare Maria addormentata, io guardai il piccolo letto vuoto dov'era rimasto un piccolo solco. Strane voglie mi venivano, di baciare il guanciale, di sentire se il solco fosse ancora tiepido. La presenza di Edith mi teneva in disagio. Mi volsi a Maria, mi chinai trattenendo il respiro, la contemplai a lungo, ricercai a una a una le note somiglianze ch'ella aveva con me, quasi numerai le vene tenui che le trasparivano nella tempia, nella guancia, nella gola. Dormiva sul fianco, tenendo la testa abbandonata in dietro così che tutta la gola rimaneva scoperta sotto il mento alzato. I denti, minuti come grani di riso mondi, lucevano nella bocca socchiusa. I cigli, lunghi come quelli della madre, spandevano dal cavo degli occhi un'ombra che toccava il sommo delle gote. Una gracilità di fiore prezioso, una finezza estrema distinguevano quella forma infantile in cui io _sentivo_ fluire il mio sangue assottigliato. Quando mai, da che le due creature vivevano, quando mai avevo provato per loro un sentimento così profondo, così dolce e così triste? Mi tolsi di là a fatica. Avrei voluto sedermi tra i due piccoli letti e riposare il capo su la sponda di quello vuoto, aspettando il _domani_. --Buona notte, Edith,--dissi uscendo; e la mia voce tremava d'un tremito diverso. Come giunsi alla mia stanza, di nuovo mi gittai bocconi sul letto. E ruppi alfine in singhiozzi, perdutamente. XII. Quando mi svegliai dal sonno greve e quasi direi brutale che a una certa ora della notte m'era piombato sopra di schianto, durai fatica a ricuperare la nozione esatta della realtà. Dopo un poco, al mio spirito scevro dalle eccitazioni notturne, la realtà si presentò fredda, nuda, incommutabile. Che erano le angosce recenti al paragone dello sgomento che allora m'invase?--Bisognava vivere! Ed era come se qualcuno mi presentasse una coppa profonda, dicendomi: "Se tu vuoi bere, oggi, se tu vuoi vivere, bisogna che tu sprema qui dentro, fino all'ultima goccia, il sangue del tuo cuore." Una ripugnanza, un disgusto, un ribrezzo indefinibili mi salirono dall'intimo dell'essere. E, intanto, bisognava vivere, bisognava accettare anche in quel mattino la vita! E bisognava, sopra tutto, _agire!_ Il confronto ch'io feci dentro di me, tra quel risveglio reale e il risveglio sognato e sperato a Villalilla il giorno innanzi, aumentò la mia insofferenza. Pensai: "È impossibile che io accetti un tale stato; è impossibile che io mi levi, che io mi vesta, che io esca di qui, che io riveda Giuliana, che io le parli, che io seguiti a dissimulare innanzi a mia madre, che io aspetti l'ora opportuna per un colloquio definitivo, che in quel colloquio io stabilisca le condizioni della nostra esistenza avvenire. È impossibile. E allora? La distruzione assoluta istantanea di tutto ciò che in me soffre.... Liberarmi, sfuggire.... _Non c'è altro._" E, considerando la facilità della cosa, imaginando l'azione rapida, lo scatto dell'arma, l'effetto immediato del piombo, l'oscurità consecutiva, io provai in tutto il corpo una tensione particolare, angosciosa e pur mista d'un senso di sollievo, quasi di dolcezza. "_Non c'è altro._" E, benché l'ansia di sapere mi agitasse, pensai con sollievo che non avrei saputo più nulla di nulla, che quella stessa ansia sarebbe d'un tratto cessata, che tutto in somma avrebbe avuto fine. Udii battere alla porta. E la voce di mio fratello gridò: --Tullio, non ti sei ancora levato? Sono le nove. Posso entrare? --Entra, Federico. Egli entrò. --Sai che è tardi? Sono passate le nove.... --Mi sono addormentato tardi, ed ero stanchissimo. --Come stai? --Così.... --La mamma è levata. M'ha detto che Giuliana sta a bastanza bene. Vuoi che t'apra la finestra? È una mattinata stupenda. Spalancò la finestra. Un flutto d'aria fresca, inondò la stanza; le tende si gonfiarono come due vele; apparve nel vano l'azzurro. --Vedi? La luce viva scoprì forse nel mio volto i segni dello strazio perché egli soggiunse: --Ma anche tu stanotte ti sei sentito male? --Credo d'aver avuto qualche po' di febbre. Federico mi guardava con i suoi limpidi occhi glauchi; e in quel momento mi parve di avere su l'anima tutto il peso delle menzogne e delle dissimulazioni future. Oh, s'egli avesse saputo! Ma, come sempre, la sua presenza fugò da me la viltà che già mi teneva. Una energia fittizia, come dopo un sorso di cordiale, mi rialzò. Pensai: "In che modo si condurrebbe egli nel mio caso?" Il mio passato, la mia educazione, l'essenza stessa della mia natura contrastavano qualunque riscontro probabile; però questo al meno era certo:--in caso di sciagura, simile o dissimile, egli si sarebbe condotto da uomo forte e caritatevole, avrebbe affrontato il dolore eroicamente, avrebbe preferito al sacrificio degli altri il sacrificio di sé. --Fammi sentire....--disse, accostandosi. E mi toccò la fronte con la palma della mano, mi prese il polso. --Ora sei libero, mi sembra. Ma che polso ineguale! --Lasciami levare, Federico, che è tardi. --Oggi, dopo mezzogiorno, vado al bosco d'Assòro. Se tu vuoi venire, faccio sellare per te Orlando. Ti ricordi tu del bosco? Peccato che Giuliana non stia bene! Altrimenti, condurremmo anche lei.... Vedrebbe le carbonare accese. Quando nominava Giuliana, pareva che la sua voce divenisse più affettuosa, più dolce, quasi direi più fraterna. Oh, s'egli avesse saputo! --Addio, Tullio. Vado a lavorare. Quando comincerai ad aiutarmi? --Oggi stesso, domani, quando vorrai. Egli si mise a ridere. --Che ardore! Basta: ti vedrò alla prova. Addio, Tullio. Ed uscì con quel suo passo alacre e franco, poiché lo sollecitava di continuo l'esortazione inscritta nel quadrante solare:--_Hora est benefaciendi_. XIII. Erano le dieci quando io uscii. La gran luce di quel mattino d'aprile, che inondava la Badiola per le finestre e per i balconi spalancati, m'intimidiva. Come portare la maschera sotto quella luce? Cercai di mia madre, prima d'entrare nelle stanze di Giuliana. --Ti sei levato tardi--ella disse, vedendomi. --Come stai! --Bene. --Sei pallido. --Credo d'aver avuto un po' di febbre, stanotte, ma ora sto bene. --Hai veduta Giuliana? --Non ancora. --Ha voluto levarsi, quella benedetta figliuola! Dice che non si sente più nulla; ma ha un viso.... --Vado da lei. --E bisogna che tu non trascuri di scrivere al dottore. Non dar retta a Giuliana. Scrivi oggi stesso. --Tu le hai detto.... che io _so_? --Sì, le ho detto che tu _sai_. --Vado, mamma. La lasciai d'avanti ai suoi grandi armarii di noce, profumati d'ireos, dove due donne accumulavano la bella biancheria di bucato, l'opulenza di Casa Hermil. Maria, nella sala del pianoforte, prendeva la lezione da miss Edith; e le scale cromatiche si succedevano rapide ed eguali. Passava Pietro, il più fedele dei servitori, canuto, un po' curvo, portando un vassoio pieno di cristalli che tintinnivano poiché le braccia tremavano di vecchiaia. Tutta la Badiola, inondata d'aria e di luce, aveva un aspetto di letizia tranquilla. V'era non so qual sentimento di bontà diffuso per ogni dove: qualche cosa come il sorriso tenue e inestinguibile dei Lari. Mai quel sentimento, quel sorriso m'avevano penetrata l'anima così a dentro. Tanta pace, tanta bontà circondavano l'ignobile segreto che io e Giuliana dovevamo custodire in noi senza morirne. "Ed ora?" pensai, al colmo dell'angoscia, girando per l'andito come un estraneo smarrito, non potendo dirigere il mio passo verso il luogo temuto, quasi che il mio corpo si rifiutasse d'obedire all'impulso della volontà, "Ed ora? Ella sa che io conosco il vero. Tra noi due ogni dissimulazione è omai inutile. Ed è necessario che noi ci guardiamo in faccia, che noi parliamo della cosa tremenda. Ma non è possibile che questo duello avvenga stamani. Le conseguenze sono imprevedibili. Ed è necessario, ora più che mai, è necessario che nessuno dei nostri atti apparisca singolare, inesplicabile a mia madre, a mio fratello, a qualunque persona di questa casa. Il mio turbamento di iersera, le mie inquietudini, le mie tristezze si possono spiegare con la preoccupazione del pericolo a cui Giuliana va incontro essendo incinta; ma logicamente, agli occhi altrui, questa preoccupazione deve rendermi verso di lei più tenero, più sollecito, più premuroso che mai. La mia prudenza oggi dev'essere estrema. Bisogna che io eviti ad ogni costo una scena tra me e Giuliana, oggi. Bisogna che io sfugga l'occasione di rimaner solo con lei, oggi. Ma bisogna anche ch'io trovi subito il modo di farle comprendere il sentimento che determina queste mie attitudini verso di lei, il proposito che regola la mia condotta. E se ella persistesse nella volontà di uccidersi? Se ella avesse soltanto differita di qualche ora l'esecuzione? Se ella stesse già aspettando l'opportunità?" Questo timore troncò gli indugi e mi spinse ad agire. Somigliavo quei soldati orientali che erano spinti alla battaglia a colpi di frusta. Mi diressi verso la sala del pianoforte. Vedendomi, Maria interruppe i suoi esercizi e corse a me tutta leggera e allegra, come a un liberatore. Ella aveva la grazia, l'agilità, la leggerezza delle creature alate. La sollevai tra le mie braccia per baciarla. --Mi porti con te?--mi chiese ella.--Sono stanca. È un'ora che miss Edith mi tiene qui.... Non ne posso più. Portami con te, fuori! _Let us take a walk before breakfast._ --Dove? --_Where you please, it is the same to me._ --Ma andiamo prima dalla mamma.... --Eh, ieri voi ve n'andaste a Villalilla e noi rimanemmo alla Badiola. Fosti tu, proprio tu, che non volesti condurci; perché la mamma voleva. Cattivo! _We should like to go there. Tell me how you amused yourselves...._ Ella cantava come un uccello, in quella lingua non sua, deliziosamente. Quel cinguettio non intermesso accompagnava la mia ansietà, mentre andavamo verso le stanze di Giuliana. Poiché io esitavo, Maria battè alla porta chiamando: --Mamma! Giuliana aprì, ella medesima, non sospettando la mia presenza. Mi vide. Sussultò forte come se avesse veduto un fantasma, uno spettro, qualche cosa di terrifico. --Sei tu?--balbettò, tanto piano che a pena l'udii, mentre le labbra nel muoversi le si scoloravano: divenuta a un tratto, dopo il sussulto, più rigida di un'erma. E ci guardammo, là, su la soglia; ci fissammo; fissammo per un istante l'uno su l'altra la nostra stessa anima. Tutto disparve in torno; tutto fra noi due fu detto, fu compreso, fu risoluto, in un istante. Dopo, che avvenne? Non so bene, non ricordo bene. Ricordo che per qualche tempo ebbi di ciò che avveniva una conscienza quasi direi intermittente, come per una successione di brevi eclissi. Era, credo, un fenomeno simile in parte a quello prodotto dall'indebolimento dell'attenzione volontaria in certi infermi. Smarrivo la facoltà dell'attenzione: non vedevo, non udivo, non afferravo più il senso delle parole, non comprendevo più. Poi, dopo un poco, ricuperavo quella facoltà, esaminavo d'intorno a me le cose e le persone, ridiventavo attento e consciente. Giuliana era seduta; aveva Natalia su le ginocchia. Anch'io ero seduto. E Maria andava da lei a me e da me a lei, con una mobilità continua, parlando senza posa, incitando la sorella, rivolgendoci una quantità di domande a cui non rispondevamo se non con qualche cenno del capo. Quel favellìo vivace riempiva il nostro silenzio. In uno dei frammenti che io udii, Maria diceva alla sorella: --Ah, tu hai dormito con la mamma, stanotte. È vero? E Natalia: --Sì, perché io sono piccola. --Ah, ma la notte che viene, sai, tocca a me. È vero, mamma? Prendi me nel tuo letto, la notte che viene.... Giuliana taceva, non sorrideva, assorta. Poiché Natalia le stava su le ginocchia volgendole le spalle, ella la teneva cinta con le braccia alla vita; e le sue mani posavano nel grembo della figliuola congiunte, più bianche della vestetta bianca su cui posavano, e affilate, e dolenti, così dolenti che rivelavano esse sole una immensità, di tristezza. Giungendole la testa di Natalia a fiore del mento, ella reclinata pareva premere la bocca su quei riccioli; così che quando io le gettavo uno sguardo, non vedevo la parte inferiore del volto, non le vedevo l'espressione della bocca. Né incontravo mai gli occhi. Ma ogni volta vedevo le palpebre abbassate, un poco rosse, che ogni volta mi turbavano a dentro come se lasciassero trasparire la fissità della pupilla che coprivano. Aspettava ella che io dicessi qualche parola? Salivano intanto alla sua bocca nascosta parole improfferibili? Quando alfine con uno sforzo mi riuscì di sottrarmi a quello stato d'inazione in cui s'erano avvicendate lucidità e oscurità straordinarie, io dissi, (ed ebbi, credo, l'accento che avrei avuto nel continuare un dialogo già iniziato, nell'aggiungere nuove parole alle dette) io dissi piano: --La mamma vuole che io avvisi il dottore Vebesti. Le ho promesso di scrivere. Scriverò. Ella non sollevò le palpebre; rimase muta. Maria, nella sua profonda inconsapevolezza, la guardò attonita; poi guardò me. Io m'alzai, per uscire, --Oggi, dopo mezzogiorno, andrò al bosco d'Assòro, con Federico. Ci vedremo stasera, al ritorno? Poiché ella non accennava a rispondere, ripetei con una voce che significava tutte le cose non espresse: --Ci vedremo, stasera, al ritorno? Le sue labbra tra i riccioli di Natalia spirarono: --Sì. XIV. Nella violenza delle mie agitazioni diverse e contrarie, nel primo tumulto del dolore, sotto la minaccia dei pericoli imminenti, io non m'era ancora fermato a considerare l'Altro. Ma anche, fin dal principio, non avevo avuto né pur l'ombra di un dubbio su la giustezza del mio antico sospetto. Subito, nel mio spirito, l'Altro aveva preso l'imagine di Filippo Arborio; e, al primo impeto di gelosia carnale che m'aveva assalito dentro l'alcova, l'imagine abominevole s'era accoppiata con quella di Giuliana in una serie di visioni orrende. Ora, mentre io e Federico andavamo cavalcando verso la foresta, lungo quel fiume tortuoso che io avevo contemplato nel torbido pomeriggio del sabato santo, l'Altro veniva con noi. Tra me e mio fratello s'intrapponeva la figura di Filippo Arborio, vivificata dal mio odio, resa dal mio odio così intensamente viva che io provavo, guardandola, _in sensazione reale_, un orgasmo fisico, qualche cosa di simile al fremito selvaggio da cui ero stato preso talvolta trovandomi sul terreno, di fronte all'avversario spogliato di camicia, al segnale dell'attacco. La vicinanza di mio fratello aumentava straordinariamente il mio male. Al paragone di Federico, la figura di quell'uomo, così fine, così nervosa, così feminea, si rimpiccioliva, s'immiseriva, diveniva spregevole per me ed ignobile. Sotto l'influsso del nuovo ideale di forza e di semplicità virile, ispiratomi dall'esempio fraterno, io non soltanto odiavo ma disprezzavo quell'essere complicato ed ambiguo che pure apparteneva alla mia stessa razza e aveva comuni con me alcune particolarità di constituzione cerebrale, come appariva dalla sua opera d'arte. Io me lo imaginavo, a simiglianza d'uno dei suoi personaggi letterarii, affetto dalle più tristi malattie dello spirito, obliquo, doppio, crudelmente curioso, isterilito dall'abitudine dell'analisi e dell'ironia riflessa, di continuo occupato a convertire i più caldi e spontanei moti dell'animo in nozioni chiare e glaciali, avvezzo a considerare qualunque creatura umana come un soggetto di pura speculazione psicologica, incapace d'amore, incapace d'un atto generoso, d'una rinuncia, d'un sacrificio, indurito nella menzogna, ottuso dal disgusto, lascivo, cinico, vile. Da un tale uomo Giuliana era stata sedotta, era stata posseduta: certo, non amata. La _maniera_ non appariva anche in quella dedica scritta sul frontespizio del _Segreto_, in quella dedica enfatica che era l'unico documento a me noto risguardante la relazione passata tra il romanziere e mia moglie? Certo, ella era stata nelle mani di colui una cosa di voluttà, non altro. Espugnare la Torre d'avorio, corrompere una donna pubblicamente vantata incorruttibile, esperimentare un metodo di seduzione sopra un soggetto tanto raro:--impresa ardua ma piena di attrattive, degna in tutto di un artista raffinato, del difficile psicologo che aveva scritto _La Cattolicissima_ e _Angelica Doni_. Come più riflettevo, i fatti mi apparivano nella loro crudità bruta. Certo, Filippo Arborio aveva incontrata Giuliana in uno di quei periodi in cui la donna così detta "spirituale", che ha sofferta una lunga astinenza, è commossa da aspirazioni poetiche, da desiderii indefiniti, da languori vaghi; i quali non sono se non le larve di cui si mascherano i bassi stimoli dell'appetito sessuale. Filippo Arborio, esperto, avendo indovinato la special condizione fisica della donna ch'egli voleva possedere, s'era servito del metodo più conveniente e più sicuro, che è questo:--parlare d'idealità, di zone superiori, di alleanze mistiche, ed occupare nel tempo medesimo le mani alla scoperta d'altri misteri; unire in somma un brano di pura eloquenza a una delicata manomessione.--E Giuliana, _la Turris eburnea_, la grande taciturna, la creatura composta d'oro duttile e d'acciaio, l'Unica, s'era prestata a quel vecchio giuoco, s'era lasciata prendere a quel vecchio inganno, aveva anch'ella obedito alla vecchia legge della fragilità muliebre. E il duetto sentimentale era finito con una copula disgraziatamente feconda.... Un orribile sarcasmo mi torceva l'anima. Mi pareva d'avere non nella bocca ma dentro di me la convulsione provocata da quell'erba che ci fa morire a modo di chi ride. Spronai il cavallo; e lo misi al galoppo, lungo l'argine del fiume. L'argine era periglioso, strettissimo nelle lunate, minacciato di frana in taluni punti, in altri ingombrato dai rami di qualche grosso albero torto, in altri attraversato da radici a fior di terra enormi. Io avevo perfetta conscienza del pericolo a cui mi esponevo; e, in vece di trattenere, spingevo sempre più il cavallo, non con l'intenzione d'incontrare la morte ma volendo trovare in quell'ansietà una tregua allo spasimo intollerabile. Conoscevo già l'efficacia di una tale follia. Dieci anni fa, quando'ero assai giovine, addetto all'ambasciata in Costantinopoli, per sfuggire a certi accessi di tristezza prodotti da ricordi recenti di passione, nelle notti di luna entravo a cavallo in uno di quei cimiteri musulmani densi di tombe, su le pietre lisce in pendio, correndo mille volte il rischio di uccidermi in una caduta. Stando con me in groppa, la morte cacciava ogni altra cura. --Tullio! Tullio! Férmati!--mi gridava Federico a distanza.--Férmati! Io non gli davo ascolto. Più d'una volta, per prodigio, evitai di battere la fronte contro qualche ramo orizzontale. Più d'una volta per prodigio impedii al cavallo di urtare contro un tronco. Più d'una volta, nei passi angusti, vidi certa la caduta nel fiume che mi luccicava sotto. Ma quando udii dietro di me un altro galoppo e m'accorsi che Federico m'inseguiva alla gran carriera, temendo per lui, con una strappata violenta arrestai il povero animale che s'impennò, rimase un istante inalberato come per precipitarsi nell'acqua, poi ricadde. Io ero incolume. --Ma sei impazzito?--mi gridò Federico, sopraggiungendo, pallidissimo. --T'ho fatto paura? Perdonami. Credevo che non ci fosse pericolo. Volevo provare il cavallo.... Poi non lo potevo più fermare.... È un po' duro, di bocca.... --Duro di bocca Orlando! --Non ti pare? Egli mi guardò fiso, con un'espressione inquieta. Io tentai di sorridere. Il suo pallore insolito mi faceva pena e tenerezza. --Non so come tu non ti sia spezzato il capo contro uno di questi alberi; non so come tu non sia precipitato.... --E tu? Per inseguirmi egli aveva corso lo stesso pericolo, forse anche maggiore perché il suo cavallo era più pesante ed egli aveva dovuto metterlo a tutta carriera volendo raggiungermi in tempo. Ambedue considerammo la via dietro di noi. --È un miracolo--egli disse.--Già, salvarsi dall'Assòro è quasi impossibile. Non vedi? Ambedue considerammo sotto di noi il fiume mortifero. Cupo, luccicante, rapido, pieno di mulinelli e di gorghi, l'Assòro correva tra gli argini cretacei con un silenzio che lo rendeva più torvo. Il paesaggio rispondeva a quell'aspetto di perfidia e di minaccia. Il cielo pomeridiano s'era impregnato di vapori e biancheggiava stancamente con un riverbero diffuso, sopra una distesa di macchioni rossastri che la primavera non aveva ancor vinti. Le foglie morte si mescevano quivi con le viventi nuove, gli stecchi aridi con i virgulti, i cadaveri coi neonati vegetali, in un denso intrico allegorico. Su la turbolenza del fiume, sul contrasto della boscaglia biancheggiava il cielo stancamente, dissolvendosi. "Un tonfo improvviso; e non avrei più pensato, non avrei più sofferto, non avrei più portato il peso della mia carne miserabile. Ma forse avrei trascinato con me nel precipizio mio fratello: una forma nobile di vita, un Uomo. Io sono salvo per miracolo com'egli è salvo per miracolo. La mia follia lo ha esposto al rischio estremo. Un mondo di cose belle e di cose buone sarebbe scomparso con lui. Quale fatalità vuole che io sia così nocivo alle persone che mi amano?" Guardai Federico. Egli era divenuto pensoso e grave. Non osai interrogarlo; ma provai un acuto rammarico d'averlo contristato.--Che pensava egli? Qual pensiero alimentava il suo turbamento? Aveva forse indovinato che io dissimulavo una sofferenza inconfessabile e che soltanto l'aculeo d'una idea fissa m'aveva spinto alla corsa mortale? Seguitammo lungo l'argine, l'uno dietro l'altro, al passo. Poi volgemmo per un sentiero che s'inoltrava nella macchia; e, come il sentiero era abbastanza largo, di nuovo cavalcammo l'uno a fianco dell'altro mentre i cavalli sbuffavano avvicinando le froge come per parlarsi in segreto e mescolavano la schiuma dei loro freni. Pensavo, gittando di tratto in tratto un'occhiata a Federico e vedendolo ancora severo: "Certo, se io gli rivelassi la verità, egli non mi crederebbe. Egli non potrebbe credere al fallo di Giuliana, alla contaminazione della sorella. Io non so decidere veramente, tra l'affetto di lui e l'affetto di mia madre per Giuliana, quale sia più profondo. Non ha egli sempre tenuto sul suo tavolo il ritratto della nostra povera Costanza e il ritratto di Giuliana riuniti come in un dittico per la stessa adorazione? Anche stamani! come s'addolciva la sua voce nominandola!" Subitamente, per contrasto, la bruttura mi si ripresentò anche più turpe. Era il corpo intraveduto nello spogliatoio della sala d'armi quello che si atteggiava nelle mie visioni. E il mio odio pur troppo operava su quell'imagine come l'acido nitrico su i tratti segnati nella lastra di rame. L'incisione diveniva sempre più netta. Allora, mentre mi durava nel sangue l'eccitamento della corsa, per quell'esuberanza di coraggio fisico, per quell'istinto di combattività ereditario che tanto spesso si risvegliava in me al rude contatto degli altri uomini, io sentii che non avrei potuto rinunziare ad affrontare Filippo Arborio. "Andrò a Roma, cercherò di lui, lo provocherò in qualche modo, lo costringerò a battersi, farò di tutto per ucciderlo o per renderlo invalido." Io me lo imaginavo pusillanime. Mi tornò alla memoria una mossa un po' ridicola che gli era sfuggita, nella sala d'armi, al ricevere in pieno petto una botta dal maestro. Mi tornò alla memoria la sua curiosità nel chiedermi notizia del mio duello: quella curiosità puerile che fa spalancare gli occhi a chi non s'è trovato mai nel cimento. Mi ricordai che, durante il mio assalto, egli aveva tenuto lo sguardo sempre fisso su me. La conscienza della mia superiorità, la certezza di poterlo sopraffare mi sollevarono. Nella mia visione, un rivo rosso rigò quella sua pallida carne ributtante. Alcuni frammenti di sensazioni reali, provate in altri tempi a fronte di altri uomini, concorsero a particolarizzare quello spettacolo imaginario nel quale m'indugiavo. E vidi colui sanguinoso e inerte su un pagliericcio, in un casale lontano, mentre i due medici accigliati gli si curvavano sopra. Quante volte io, ideologo e analista e sofista in epoca di decadenza, m'ero compiaciuto d'essere il discendente di quel Raimondo Hermil de Penedo che alla Goletta operò prodigi di valore e di ferocia sotto gli occhi di Carlo Quinto! Lo sviluppo eccessivo della mia intelligenza e la mia _multanimità_ non avevano potuto modificare il fondo della mia sostanza, il substrato nascosto in cui erano inscritti tutti i caratteri ereditarii della mia razza. In mio fratello, organismo equilibrato, il pensiero s'accompagnava sempre all'opera; in me il pensiero predominava ma senza distruggere le mie facoltà di azione che anzi non di rado si esplicavano con una straordinaria potenza. Io ero insomma un violento e un appassionato consciente, nel quale l'ipertrofia di alcuni centri cerebrali rendeva impossibile la coordinazione necessaria alla vita normale dello spirito. Lucidissimo sorvegliatore di me stesso, avevo tutti gli impeti delle nature primitive indisciplinabili. Più d'una volta io ero stato tentato da improvvise suggestioni delittuose. Più d'una volta ero rimasto sorpreso dall'insurrezione spontanea d'un istinto crudele. --Ecco le Carbonare--disse mio fratello, mettendo il cavallo al trotto. Si udivano i colpi delle scuri nella foresta e si vedevano le spire del turno salire tra gli alberi. La colonia dei carbonai ci salutò. Federico interrogava i lavoratori intorno all'andamento delle opere, li consigliava, li ammoniva, osservando con occhio esperto i fornelli. Tutti stavano davanti a lui in attitudini di reverenza e lo ascolvano attenti. Il lavoro d'in torno pareva esser divenuto più fervido, più facile, più giocondo, come il crepitio del fuoco efficace. Gli uomini correvano qua e là a gittar terra dove il fumo usciva con troppa copia, a chiudere con zolle i varchi aperti dalle esplosioni; correvano e vociavano. Gridi gutturali d'abbattitori si mescevano a quelle voci rudi. Rimbombava nell'interno lo schianto di qualche albero caduto. Fischiavano, in qualche pausa, i merli. E la grande foresta immobile contemplava i roghi alimentati dalle sue vite. Mentre mio fratello compiva l'esame delle opere, io mi allontanai lasciando al cavallo la scelta dei sentieri che si diramavano pel folto. I rumori si affiochivano dietro di me, gli echi morivano. Un silenzio grave scendeva dalle cime. Io pensavo: "Come farò per risollevarmi? Quale sarà la mia vita da domani in poi? Potrò seguitare a vivere nella casa di mia madre col mio segreto? Potrò accomunare la mia esistenza con quella di Federico? Chi mai, che cosa mai al mondo potrà risuscitare nella mia anima una scintilla di fede?" Lo strepito delle opere si spegneva dietro di me; la solitudine diventava perfetta. "Lavorare, praticare il bene, vivere per gli altri.... Potrei _ora_ ritrovare in queste cose il vero senso della vita? E veramente il senso della vita non si ritrova pieno nella felicità personale ma in queste cose soltanto? L'altro giorno, mentre mio fratello parlava, io credevo di comprendere la sua parola; credevo che la _dottrina della verità_ mi si rivelasse per la sua bocca. La dottrina della verità, secondo mio fratello, non sta nelle leggi, non sta nei precetti, ma semplicemente e unicamente nel senso che l'uomo dà alla vita. Mi pareva d'aver compreso. Ora, d'un tratto, sono ritornato nel buio; sono ridiventato cieco. Non comprendo più nulla. Chi mai, che cosa mai al mondo mi potrà consolare del bene che ho perduto?" E l'avvenire mi apparve spaventoso, senza speranza. L'imagine indeterminata del nascituro crebbe, si dilatò, come quelle orribili cose informi che noi vediamo talvolta negli incubi, ed occupò tutto il campo. Non si trattava d'un rimpianto, d'un rimorso, d'un ricordo indistruttibile, d'una qualunque più amara cosa interiore, ma di un essere vivente. Il mio avvenire era legato a un essere vivente d'una vita tenace e malefica; era legato a un estraneo, a un intruso, a una creatura abominevole contro di cui non soltanto la mia anima ma la mia carne, tutto il mio sangue e tutte le mie fibre votavano un'avversione bruta, feroce, implacabile fino alla morte, oltre la morte. Pensavo: "Chi avrebbe potuto imaginare un supplizio peggiore per torturarmi insieme l'anima e la carne? Il più ingegnosamente efferato dei tiranni non saprebbe concepire certe crudeltà ironiche, le quali sono soltanto del Destino. Era presumibile che la malattia avesse resa sterile Giuliana. Or bene, ella si dà a un uomo, commette il suo primo fallo, e rimane incinta, ignobilmente, con la facilità di quelle femmine calde che i villani sforzano dietro le siepi, su l'erba in tempo di foia. E, a punto mentre ella è piena delle sue nausee, io mi pasco di sogni, m'abbevero d'ideale, ritrovo le ingenuità della mia adolescenza, non m'occupo di altro che di cogliere fiori.... (Oh quei fiori, quegli stomachevoli fiori, offerti con tanta timidezza!) E, dopo una grande ubbriacatura tra sentimentale e sensuale, ricevo la dolce notizia--da chi?--da mia madre! E, dopo la notizia, ho un'esaltazione generosa, faccio in buona fede una parte nobile, mi sacrifico in silenzio, come un eroe di Octave Feuillet! Che eroe! Che eroe!" Il sarcasmo mi torceva l'anima, mi contraeva tutte le fibre. E di nuovo, allora, mi prese la follia della fuga. Guardai davanti a me. In vicinanza, tra i fusti, irreale come un inganno di occhi allucinati, brillava l'Assoro. "Strano!" pensai, provando un brivido particolare. Non m'ero accorto, prima di quel momento, che il cavallo senza guida s'era inoltrato per un sentiero che conduceva al fiume. Pareva quasi che l'Assoro mi avesse attirato. Stetti in forse, per un istante, tra il proseguire sino alla riva e il ritornare indietro. Scossi da me il fascino dell'acqua, e il cattivo pensiero. Voltai il cavallo. Un grave accasciamento succedeva alla convulsione interna. Mi sembrò che a un tratto la mia anima fosse divenuta una povera cosa gualcita, avvizzita, rimpicciolita, una cosa miserabile. Mi ammollii; ebbi pietà di me, ebbi pietà di Giuliana, ebbi pietà di tutte le creature su cui il dolore imprime le sue stimate, di tutte le creature che tremano abbrancate dalla vita come trema un vinto sotto il pugno del vincitore inesecrabile. "Che siamo noi? Che sappiamo noi? Che vogliamo? Nessuno mai ha ottenuto quel che avrebbe amato; nessuno otterrà quel che amerebbe. Cerchiamo la bontà, la virtù, l'entusiasmo, la passione che riempirà la nostra anima, la fede che calmerà le nostre inquietudini, l'idea che difenderemo con tutto il nostro coraggio, l'opera a cui ci voteremo, la causa per cui moriremo con gioia. E la fine di tutti gli sforzi è una stanchezza vacua, il sentimento della forza che si disperde e del tempo che si dilegua...." E la vita m'apparve in quell'ora come una visione lontana, confusa e vagamente mostruosa. La demenza, l'imbecillità, la povertà, la cecità, tutti i morbi, tutte le disgrazie; l'agitazione oscura continua di forze inconscienti, ataviche e bestiali nell'intimo della nostra sostanza; le più alte manifestazioni dello spirito instabili, fugaci, sempre subordinate a uno stato fisico, legate alla funzione d'un organo; le transfigurazioni istantanee prodotte da una causa impercettibile, da un nulla; la parte immancabile di egoismo nei più nobili atti; la inutilità di tante energie morali dirette verso uno scopo incerto, la futilità degli amori creduti eterni, la fragilità delle virtù credute incrollabili, la debolezza delle più sane volontà, tutte le vergogne, tutte le miserie m'apparvero in quell'ora. "Come si può vivere? Come si può amare?" Risonavano le scuri nella foresta: un grido breve e selvaggio accompagnava ogni colpo. Qua e là negli spiazzi i grandi mucchi, in forma di coni tronchi o di piramidi quadrangolari, fumigavano. Le colonne del fumo si levavano dense e diritte come i fusti arborei, nell'aria senza vento. Per me tutto era simbolo, in quell'ora. Diressi il cavallo verso una carbonaia vicina, avendo riconosciuto Federico. Egli era smontato; e parlava con un vecchio di alta statura, dalla faccia rasa. --Oh, finalmente!--mi gridò, vedendomi.--Temevo che tu ti fossi smarrito. --No, non sono andato molto lontano.... --Vedi qui Giovanni di Scòrdio, un Uomo--disse, mettendo una mano su la spalla del vecchio. Guardai il nominato. Un sorriso singolarmente dolce apparve su la bocca appassita di colui. Non avevo mai veduto sotto una fronte umana occhi tanto tristi. --Addio, Giovanni. Coraggio!--soggiunse mio fratello, con quella voce che pareva avere talvolta, come certi liquori, la potenza d'elevare il tono vitale.--Noi, Tullio, possiamo riprendere la via della Badiola. È già tardi. Ci aspettano. Rimontò a cavallo. Salutò di nuovo il vecchio. Passando presso ai fornelli, dava qualche avvertimento ai lavoratori per le operazioni della notte prossima in cui doveva apparire il _gran fuoco_. Ci allontanammo, cavalcando l'uno a fianco dell'altro. Il cielo si apriva sul nostro capo, lentamente. I veli dei vapori fluttuavano, si disperdevano, si ricomponevano, così che l'azzurro pareva di continuo impallidire come se nella sua liquidità un latte di continuo si diffondesse e si dileguasse. Era vicina quell'ora medesima in cui, il giorno innanzi, a Villalilla, io e Giuliana avevamo guardato il giardino ondeggiante in una luce ideale. La boscaglia in torno cominciava a dorarsi. Gli uccelli cantavano, invisibili. --Hai osservato bene Giovanni di Scòrdio, quel vecchio?--mi chiese Federico. --Sì--risposi.--Credo che non dimenticherò il suo sorriso e i suoi occhi. --Quel vecchio è un santo--soggiunse Federico.--Nessun uomo ha lavorato e sofferto quanto quel vecchio. Ha quattordici figliuoli e tutti a uno a uno si sono distaccati da lui come i frutti maturi si distaccano dall'albero. La moglie, una specie di carnefice, è morta. Egli è rimasto solo. I figli l'hanno spogliato e rinnegato. Tutta l'ingratitudine umana s'è accanita contro di lui. Egli non ha esperimentata la perversità degli estranei ma quella delle sue creature. Intendi? Il suo stesso sangue s'è inviperito in altri esseri ch'egli ha sempre amato ed aiutato, che ama ancora, che non sa maledire, che certamente benedirà nell'ora della morte, anche se lo lasceranno morir solo. Non è straordinaria, quasi incredibile, questa pertinacia d'un uomo nella bontà? Dopo tutto quel che ha sofferto, egli ha potuto conservare il sorriso che tu gli hai veduto! _Farai bene, Tullio, a non dimenticare quel sorriso...._ XV L'ora della prova, l'ora temuta e desiderata a un tempo, si approssimava. Giuliana era pronta. Ella aveva resistito fermamente al capriccio di Maria; aveva voluto rimanere sola nella sua stanza ad aspettarmi. "Che le dirò? Che mi dirà ella? Quale sarà la mia attitudine verso di lei?" Tutte le prevenzioni, tutti i propositi si disperdevano. Non mi restava se non un'ansietà intollerabile. Chi avrebbe potuto prevedere l'esito del colloquio? Io non mi sentivo padrone di me, non delle mie parole, non dei miei atti. Soltanto sentivo in me un viluppo di cose oscure e contrarie che al minimo urto dovevano insorgere. Mai come in quell'ora avevo avuto chiara e disperata la conscienza delle discordie intestine che mi straziavano, la percezione degli elementi irreconciliabili che si agitavano nel mio essere e si soverchiavano e si distruggevano a vicenda in un perpetuo conflitto, ribelli a qualunque dominio. Alla commozione del mio spirito si aggiungeva un particolare turbamento del senso, promosso dalle imagini che in quel giorno mi avevano torturato senza tregua. Io conoscevo bene, troppo bene, quel turbamento che meglio d'ogni altro rimescola il fango infimo nell'uomo; conoscevo troppo bene quella bassa specie di concupiscenza da cui nulla ci può difendere, quella tremenda febbre sessuale che per alcuni mesi m'aveva tenuto avvinto a una donna odiata e disprezzata, a Teresa Raffo. Ed ora i sentimenti di bontà, di pietà e di forza, che m'erano necessari per sostenere il confronto con Giuliana e per insistere nel proposito primitivo, si movevano in me come vapori vaghi su un fondo limaccioso, pieno di gorgogli sordi, infido. Mancava poco a mezzanotte, quando io uscii dalla mia stanza per andare verso quella di Giuliana. Tutti i rumori erano cessati. La Badiola riposava in un silenzio profondo. Stetti in ascolto; e mi parve quasi di sentir salire nel silenzio la respirazione calma di mia madre, di mio fratello, delle mie figliuole, degli esseri inconsapevoli e puri. Mi riapparve il volto di Maria addormentata, quale io l'avevo veduto la notte innanzi; Mi apparvero anche gli altri volti; e in ciascuno era un'espressione di riposo, di pace, di bontà. Un intenerimento subitaneo m'invase. La felicità, nel giorno innanzi per un momento intraveduta e scomparsa, ribalenò al mio spirito immensa. Se nulla fosse accaduto, se io fossi rimasto nella piena illusione, che notte sarebbe stata quella! Sarei andato verso Giuliana come verso una persona divina. E quale cosa avrei potuto desiderare più dolce di quel silenzio intorno all'ansietà del mio amore? Passai per la stanza dove la sera innanzi avevo ricevuto dalla bocca di mia madre la rivelazione improvvisa. Riudii l'orologio a pendolo che aveva segnata l'ora; e, non so perché, quel tic tac sempre eguale aumentò la mia ambascia. Non so perché, mi parve di sentir rispondere alla mia l'ambascia di Giuliana, a traverso lo spazio che ancora ci divideva, con un'accelerazione di palpiti concorde. Camminai diretto, senza più soffermarmi, senza evitare lo strepito dei passi. Non picchiai all'uscio ma d'un tratto l'apersi; entrai. Giuliana era là, d'avanti a me, in piedi; con una mano poggiata all'angolo di un tavolo immobile, più rigida di un'erma. Vedo ancora tutto. Nulla mi sfuggì allora; nulla mi sfugge. Il mondo reale era completamente svanito. Non restava più se non un mondo fittizio in cui respiravo ansioso, col cuore compresso, incapace di profferire una sillaba, ma pur tuttavia singolarmente lucido, come d'avanti a una scena di teatro. Una candela ardeva sul tavolo, aggiungendo evidenza a quell'aspetto di finzione scenica poiché la fiammella mobile pareva agitare intorno a sé quel vago orrore che lasciano nell'aria con un gran gesto disperato o minaccioso gli attori d'un dramma. La strana sensazione si dissipò quando al fine, non potendo più sopportare quel silenzio e l'immobilità marmorea di Giuliana, proferii le prime parole. Il suono della mia voce fu diverso da quel che credevo al momento d'aprire le labbra. Involontariamente, la mia voce fu dolce, tremula, quasi timida. --M'aspettavi? Ella teneva le palpebre abbassate. Senza sollevarle, rispose: --Sì. Io guardavo il suo braccio, quel braccio immobile come un puntello, che pareva sempre più irrigidirsi su la mano poggiata all'angolo del tavolo. Temevo che quel sostegno fragile, a cui era affidata tutta la persona, da un momento all'altro cedesse ed ella stramazzasse di schianto. --Tu sai perché io sono venuto--soggiunsi, con estrema lentezza, svellendomi dal cuore le parole a una a una. Ella tacque. --È vero--seguitai--è vero.... quel che ho saputo da mia madre? Ancora tacque. Parve raccogliere tutte le sue forze. Strana cosa: in quell'intervallo io non credetti assolutamente impossibile che ella rispondesse no. Rispose (più tosto che udire le parole io le vidi disegnarsi su le labbra esangui): --È vero. Ricevei in mezzo al petto un urto che forse fu più fiero di quel che m'avevan dato le parole di mia madre. Già tutto io sapevo; avevo già vissuto ventiquattro ore nella certezza; e pure quella conferma così chiara e precisa mi atterrò, come se per la prima volta mi si rivelasse la verità incommutabile. --È vero!--ripetei, istintivamente, parlando a me stesso, avendo una sensazione simile forse a quella che avrei avuta se mi fossi ritrovato vivo e conscio in fondo a una voragine. Allora Giuliana sollevò le palpebre; fissò le sue pupille nelle mie con una specie di spasmodica violenza. --Tullio--disse--ascoltami. Ma la soffocazione le spense la voce nella gola. --Ascoltami. Io so quel che debbo fare. Ero risoluta a tutto per risparmiarti quest'ora: ma il destino ha voluto che fino a quest'ora io vivessi per soffrire la cosa più orribile, la cosa di cui avevo uno spavento folle (ah, tu m'intendi) mille volte più che della morte: Tullio, Tullio, il tuo sguardo.... Un'altra soffocazione l'arrestò, nel punto in cui la sua voce diveniva così straziante che mi dava l'impressione fisica d'un dilaceramento delle fibre più segrete. Io mi lasciai cadere su una sedia, accanto al tavolo; e mi presi la testa fra le palme, aspettando ch'ella seguitasse. --Dovevo morire, prima di giungere a quest'ora. Da tanto tempo dovevo morire! Sarebbe stato meglio, certo, che io non fossi venuta qui. Sarebbe stato meglio che, tornando da Venezia, tu non m'avessi più trovata. Io sarei morta, e tu non avresti conosciuta questa vergogna; mi avresti rimpianta, forse mi avresti sempre adorata. Io sarei rimasta forse per sempre il tuo grande amore, il tuo _unico_ amore, come dicevi ieri.... Non avevo paura della morte, sai; non ho paura. Ma il pensiero delle nostre bambine, di nostra madre, m'ha fatto differire di giorno in giorno l'esecuzione. Ed è stata un'agonia, Tullio, una agonia inumana, dove ho consumato non una ma mille vite. E sono ancora viva! Soggiunse, dopo una pausa: --Com'è possibile che, con una salute così miserabile, io abbia tanta resistenza a soffrire? Sono disgraziata anche in questo. Vedi: io pensavo, consentendo a venire qui con te, io pensavo: "Certamente mi ammalerò; quando sarò giunta là, mi dovrò mettere a letto; e non mi leverò più. Sembrerà che io muoia di morte naturale. Tullio non saprà mai nulla, non sospetterà mai di nulla. Tutto sarà finito." In vece, mi veggo ancora in piedi; e tu sai ogni cosa; e tutto è perduto, senza riparo. Era sommessa la sua voce, debolissima, e pure lacerante come un grido acuto e iterato. Io mi stringevo le tempie e sentivo il battito così forte che n'avevo quasi ribrezzo come se le arterie fossero scoppiate fuori della cute e aderissero nude alle mie palme con la loro tunica molle e calda. --La mia unica preoccupazione era di nasconderti la verità, non per me, ma per te, per la tua salvezza. Tu non saprai mai quali terrori mi abbiano agghiacciata, quali angosce mi abbiano soffocata. Tu, dal giorno che siamo giunti qui fino a ieri, hai sperato, hai sognato, sei stato quasi felice. Ma imagina la mia vita qui, col mio segreto, accanto a tua madre, in questa casa benedetta! Mi dicesti ieri a Villalilla, mentre eravamo a tavola, raccontandomi quelle cose tanto dolci che mi straziavano, mi dicesti: "Tu non sapevi nulla, non t'accorgevi di nulla." Ah, non è vero! Tutto sapevo, tutto indovinavo. E, quando sorprendevo nei tuoi occhi la tenerezza, mi sentivo cadere l'anima. Ascoltami, Tullio. Ho nella bocca la verità, la pura verità. Io sono qui, d'avanti a te, come una moribonda. Non potrei mentire. Credi a quel che ti dico. Non penso a discolparmi, non penso a difendermi. Oramai tutto è finito. Ma voglio dirti una cosa che è la verità. Tu sai come ti ho amato dal primo giorno che ci vedemmo. Per anni, per anni, ti sono stata devota, ciecamente, e non negli anni della felicità soltanto ma in quelli della sventura, quando in te s'era stancato l'amore. Tu lo sai, Tullio. Hai potuto sempre fare di me quel che hai voluto. Hai trovato sempre in me l'amica, la sorella, la moglie, l'amante, pronta a qualunque sacrificio per il tuo piacere. Non credere, Tullio, non credere che io ti ricordi la mia lunga devozione per accusarti; no, no. Né pure una stilla di amarezza ho nell'anima per te; intendi? né pure una stilla. Ma lascia, in quest'ora, che io ti ricordi la devozione e la tenerezza durate per tanti anni e che io ti parli d'amore, del mio amore _non interrotto, non cessato mai,_ intendi?, _non cessato mai_. Credo che la mia passione per te non sia stata mai così intensa come in queste ultime settimane. Tu mi raccontavi ieri tutte quelle cose.... Ah se io potessi raccontarti la mia vita di questi ultimi giorni! Tutto sapevo di te, tutto indovinavo; ed ero costretta a fuggirti. Più di una volta sono stata per caderti nelle braccia, per chiudere gli occhi e lasciarmi prendere da te, nei momenti di debolezza e di stanchezza estrema. L'altra mattina, la mattina di sabato, quando tu entrasti qui con quei fiori, io ti guardai e mi sembrasti _quello d'una volta_, così acceso, com'eri, sorridente, gentile, con gli occhi lucidi. E mi mostrasti le scalfitture che avevi nelle mani! Un impeto mi venne, di prenderti le mani e di baciartele.... Chi mi diede la forza di contenermi? _Non mi sentivo degna._ E vidi in un lampo tutta la felicità che tu mi offrivi con quei fiori, tutta la felicità a cui dovevo rinunziare per sempre. Ah, Tullio, il mio cuore è a tutta prova se ha potuto resistere a certe strette. Ho la vita tenace. Ella pronunziò quest'ultima frase con una voce più sorda, con un accento indefinibile, quasi d'ironia e d'ira. Io non osavo alzare il viso e guardarla. Le sue parole mi davano un'atroce sofferenza; e pure io tremavo quando ella faceva una pausa. Temevo che ad un tratto le mancassero le forze e che ella non potesse più continuare. E io aspettavo dalla sua bocca altre confessioni, altri lembi d'anima. --Grande errore--ella continuò--grande errore non esser morta prima del tuo ritorno da Venezia. Ma la povera Maria, ma la povera Natalia, come le avrei lasciate? Ella esitò un poco. --Te anche, forse avrei lasciato male.... Ti avrei lasciato qualche rimorso. La gente ti avrebbe accusato. Non avremmo potuto nascondere a nostra madre.... Ella ti avrebbe domandato: "perché ha voluto morire?" Sarebbe giunta a conoscere la verità che le abbiamo nascosta fino ad ora.... Povera santa! Le si chiudeva la gola, forse; perché la sua voce si affiochiva, prendeva un tremolìo di pianto contenuto. Lo stesso nodo serrava la mia gola. --Ci pensai. Anche pensai, quando tu volesti condurmi qui, che ero divenuta indegna di lei, indegna d'essere baciata su la fronte, d'essere chiamata figliuola. Ma tu sai come noi siamo deboli, come facilmente ci abbandoniamo alla forza delle cose. Io non speravo più nulla; sapevo bene che, fuori della morte, non c'era altro scampo per me; sapevo bene che ogni giorno più il cerchio si stringeva. E pure, lasciavo passare i giorni a uno a uno, senza risolvermi. E avevo un mezzo sicuro per morire! Ella s'arrestò. Obedendo a un impulso repentino, io levai il viso e la guardai fissamente. Un gran fremito la scosse. E tanto fu manifesto il male che io le facevo guardandola, che di nuovo abbassai la fronte. Ripresi la mia attitudine. Ella stava ancora in piedi. Sedette. Seguì un intervallo di silenzio. --Credi tu--ella mi domandò, con una timidezza penosa--credi tu che la colpa sia grave, quando l'anima non consente? Bastò quell'accenno alla _colpa_ per rimescolare in me d'un tratto il torbido fondo che s'era quietato; e una specie di rigurgito amaro mi salì alla bocca. Involontariamente mi uscì dalle labbra il sarcasmo. Dissi, facendo segno di sorridere: --Povera anima! Apparve sul volto di Giuliana un'espressione di dolore così intensa che io subito provai una fitta di pentimento acutissima. M'accorsi che non avrei potuto farle una ferita più cruda e che l'ironia in quell'ora, contro quella creatura sommessa, era la peggiore delle viltà. --Perdonami--ella disse con l'aspetto di una donna colpita a morte (e mi parve proprio ch'ella avesse l'occhio dolce, triste, quasi infantile che avevo veduto qualche volta ai feriti adagiati nelle barelle)--perdonami. Anche tu ieri parlasti di anima.... Tu pensi ora: "_Queste sono le cose che le donne dicono, per farsi perdonare._" Ma io non cerco di farmi perdonare. So che il perdono è impossibile, che l'oblio è impossibile. So che non c'è scampo. Intendi? Volevo soltanto farmi perdonare da te i baci che ho presi da tua madre.... Ancora era sommessa la sua voce, debolissima, e pure lacerante come un grido acuto e iterato. --Mi sentivo su la fronte un peso di dolore così grande che non per me, Tullio, ma per quel dolore, soltanto, per quel dolore accettavo su la fronte i baci di tua madre. E se io ero indegna, quel dolore era degno. Tu puoi perdonarmi. Ebbi un moto di bontà, di pietà ma non cedetti. Io non la guardavo negli occhi. Il mio sguardo andava involontariamente al grembo, come per scoprire i segni della cosa tremenda; e facevo sforzi enormi per non contorcermi negli accessi di spasimo, per non darmi ad atti insensati. --Certi giorni differivo d'ora in ora l'esecuzione del mio proposito; e il pensiero di questa casa, di ciò che sarebbe accaduto dopo in questa casa, mi toglieva il coraggio. E così svanì anche la speranza di poterti nascondere la verità, di poterti salvare; perché fin dai primi giorni la mamma indovinò il mio stato. Ti ricordi tu di quel giorno che là alla finestra, per l'odore delle violacciocche, ebbi un disturbo? Fin da allora, la mamma se ne accorse. Imagina i miei terrori! Io pensavo: "Se mi uccido, Tullio avrà la rivelazione dalla madre. Chi sa fin dove giungeranno le conseguenze del male che ho fatto!" E mi divoravo l'anima, giorno e notte, per trovare il modo di salvarti. Quando tu domenica mi domandasti: "Vuoi che andiamo martedì a Villalilla?", io acconsentii senza riflettere, mi abbandonai al destino, mi affidai alla forza del caso, alla ventura. Ero certa che quello sarebbe stato il mio ultimo giorno. Questa certezza mi esaltava, mi dava una specie di demenza. Ah, Tullio, ripensa alle tue parole di ieri e dimmi se comprendi ora il mio martirio.... Lo comprendi? Ella si chinò, si protese verso di me, come per spingermi dentro l'anima la sua domanda angosciosa; e, tenendo le dita intrecciate, si torceva le mani. --Non m'avevi mai parlato così; non avevi mai avuta quella voce. Quando là, al sedile, tu mi domandasti: "_È troppo tardi, forse?_", io ti guardai e il tuo viso mi fece paura. Potevo risponderti: "Sì, è troppo tardi?" Potevo spezzarti il cuore a un tratto? Che sarebbe accaduto di noi? E allora volli concedermi l'ultima ebrezza, diventai folle, non vidi più che la morte e la mia passione. Ella era divenuta stranamente rauca. Io la guardavo; e mi pareva di non riconoscerla, tanto era trasfigurata. Una convulsione contraeva tutte le linee del suo viso; il labbro inferiore le tremava forte; gli occhi le ardevano d'un ardore febrile. --Mi condanni?--domandò rauca ed acre.--Mi disprezzi per quel che feci ieri? Si coprì il viso con le mani. Poi, dopo una pausa, con un accento indefinibile di strazio, di voluttà e di orrore, con un accento venutole chi sa da quale abisso dell'essere, ella soggiunse: --Iersera, _per non distruggere quel che di te m'era rimasto nel sangue_, indugiavo a prendere il veleno. Le mani le ricaddero. Ella scosse da sé la debolezza, con un atto risoluto. La sua voce divenne più ferma. --Il destino ha voluto che io vivessi fino a quest'ora. Il destino ha voluto che tu sapessi da tua madre la verità: da tua madre! Iersera, quando tu rientrasti qui, sapevi tutto. E tacesti, e d'avanti a tua madre mi baciasti la guancia che io ti offrivo. Lascerai che prima di morire io ti baci le mani. Non ti chiedo altro. T'ho aspettato per obbedirti. Sono pronta a tutto. Parla. Io dissi: --È necessario che tu viva. --Impossibile, Tullio; impossibile--ella esclamò.--Hai tu pensato _a quel che accadrebbe se io vivessi_? --Ho pensato. È necessario che tu viva. --Orrore! Ed ella ebbe un sussulto violento, un moto istintivo di raccapriccio, forse perché sentì nelle sue viscere _quell'altra vita_, il nascituro. --Ascoltami, Tullio. Oramai tu sai tutto; oramai non debbo uccidermi per nasconderti una vergogna, per evitare di ritrovarmi innanzi a te. Tu sai tutto; e siamo qui, e possiamo ancora guardarci, possiamo ancora parlare! Si tratta di ben altro. Io non penso di eludere la tua vigilanza per darmi la morte. Io voglio anzi che tu mi aiuti a scomparire nel modo più naturale che sia possibile per non destare sospetti qui nella casa. Ho due veleni: la morfina e il sublimato corrosivo. Forse non servono. Forse è difficile tener celato un avvelenamento. E bisogna che la mia morte sembri involontaria, cagionata da un caso qualunque, da una disgrazia. Intendi? In questo modo noi raggiungeremo lo scopo. Il segreto rimarrà fra noi due.... Ella ora parlava rapidamente, con una espressione di serietà ferma, come se ragionasse per persuadermi ad accettare un accordo utile non un patto di morte, non una parte di complice nell'attuazione d'un proposito insensato. Io lasciavo ch'ella continuasse. Una specie di fascino strano mi faceva rimaner là a guardare, ad ascoltare quella creatura così fragile, così pallida, così malata, in cui entravano onde di energia morale così veementi. --Ascoltami, Tullio. Ho un'idea. Federico m'ha raccontato la tua follia di oggi, il pericolo che hai corso oggi su l'argine dell'Assoro, m'ha raccontato tutto. Io pensavo, tremando: "Chi sa per quale impeto di dolore s'è gittato a quel rischio!" E, ancora pensando, m'è parso di comprendere. Ho avuta una divinazione. E tutte le altre tue sofferenze future, mi si sono affacciate all'anima: sofferenze da cui nulla ti potrebbe difendere, sofferenze che aumenterebbero di giorno in giorno, inconsolabili, intollerabili. Ah, Tullio, certo tu le hai già presentite e pensi che non potresti sostenerle. Un solo mezzo c'è per salvare te, me, le nostre anime, il nostro amore; sì, lasciami dire: _il nostro amore_. Lasciami ancora credere alle tue parole di ieri e lasciami ripetere che io ti amo ora come non t'ho amato mai. A punto per questo, a punto perché noi ci amiamo, bisogna che io sparisca dal mondo, bisogna che tu non mi veda più. Fu straordinaria l'elevazione morale che rialzò la voce, tutta la persona di lei, in quell'istante. Un gran fremito mi agitò; un'illusione fugace s'impadronì del mio spirito. Credetti che veramente in quell'istante il mio amore e l'amore di quella donna si trovassero di fronte alti d'una smisurata altezza ideale e scevri di miseria umana, non macchiati di colpa, intatti. Riebbi per pochi attimi la stessa sensazione provata in principio quando il mondo reale m'era parso completamente vanito. Poi, come sempre, il fenomeno inevitabile si compì. Quello stato di conscienza non mi appartenne più, si fece obbiettivo, mi diventò _estraneo_. --Ascoltami--seguitò ella, abbassando la voce, come per tema che qualcuno udisse.--Ho mostrato a Federico un gran desiderio di rivedere il bosco, le carbonaie, tutti quei luoghi. Domattina Federico non potrà accompagnarci perché dovrà tornare a Casal Caldore. Andremo noi due soli. Federico m'ha detto che potrò montare Favilla. Quando saremo su l'argine.... farò quel che tu hai fatto stamani. Accadrà una disgrazia. Federico m'ha detto che è impossibile salvarsi dall'Assoro.... Vuoi? Se bene ella proferisse parole coerenti, sembrava in preda a una specie di delirio. Un rossore insolito le accendeva la sommità delle gote, e gli occhi le splendevano straordinariamente. Una visione del fiume sinistro mi passò nello spirito, rapida. Ella ripetè, tendendosi verso di me: --Vuoi? Io m'alzai, le presi le mani. Volevo calmare la sua febbre. Una pena e una pietà immense mi premevano. E la mia voce fu dolce, fu buona; tremò di tenerezza. --Povera Giuliana! Non t'agitare così. Tu soffri troppo; il dolore ti fa insensata, povera anima! Bisogna che tu abbia molto coraggio; bisogna che tu non pensi più alle cose che hai dette.... Pensa a Maria, a Natalia.... Io ho accettato questo castigo. Per tutto il male che ho fatto, forse meritavo questo castigo. L'ho accettato; lo sopporterò. Ma è necessario che tu viva. Mi prometti, Giuliana, per Maria, per Natalia, per quanto hai cara la mamma, per le cose che io ti dissi ieri, mi prometti che in nessun modo cercherai di morire? Ella teneva il capo chino. E d'un tratto, liberando le sue mani, afferrò le mie e si mise a baciarmele furiosamente; e io sentii su la mia pelle il caldo della sua bocca, il caldo delle sue lacrime. E, come io tentavo di sottrarmi, ella dalla sedia cadde in ginocchio, senza lasciarmi le mani, singhiozzando, mostrandomi la sua faccia sconvolta, dove il pianto colava a rivi, dove la contrazione della bocca rivelava l'indicibile spasimo da cui tutto l'essere era convulso. E, senza poterla rialzare, senza poter più parlare, soffocato da un accesso violento d'ambascia, soggiogato dalla forza dello spasimo che contraeva quella povera bocca smorta, abbandonato da qualunque rancore, da qualunque orgoglio, non provando se non la cieca paura della vita, non sentendo nella donna prostrata e in me se non la sofferenza umana, l'eterna miseria umana, il danno delle trasgressioni inevitabili, il peso della nostra carne bruta, l'orrore delle fatalità inscritte nelle radici stesse del nostro essere e inabolibili, tutta la corporale tristezza del nostro amore, anch'io caddi in ginocchio d'innanzi a lei per un bisogno instintivo di prostrarmi, di uguagliarmi anche nell'attitudine alla creatura che soffriva e che mi faceva soffrire. E anch'io ruppi in singhiozzi. E ancora una volta, dopo tanto, rimescolammo le nostre lacrime, ahi me!, che erano così cocenti e che non potevano mutare il nostro destino. XVI. Chi saprà mai rendere con le parole quel senso di aridità desolata e di stupore, che resta nell'uomo dopo uno spargimento inutile di pianto, dopo un parosismo d'inutile disperazione? Il pianto è un fenomeno passeggero, ogni crisi deve risolversi, ogni eccesso è breve; e l'uomo si ritrova esausto, quasi direi disseccato, più che mai convinto della propria impotenza, corporalmente stupido e triste, d'innanzi alla realtà impassibile. Io primo terminai di piangere; io primo riebbi negli occhi la luce; io primo feci attenzione alla positura della mia persona, a quella di Giuliana, alle cose circostanti. Eravamo ancora in ginocchio l'uno di fronte all'altra, sul tappeto; e ancora qualche singulto scoteva Giuliana. La candela ardeva sul tavolo, e la fiammella si moveva a quando a quando come inchinata da un soffio. Nel silenzio il mio orecchio percepì il piccolo rumore d'un orologio che doveva essere nella stanza, posato in qualche luogo. La vita scorreva, il tempo fuggiva. La mia anima era vuota e sola. Passata la veemenza del sentimento, passata quell'ebrietà di dolore, le nostre attitudini non avevano più significato, non avevano più ragion d'essere. Bisognava che io mi alzassi, che io sollevassi Giuliana, che io dicessi qualche cosa, che quella scena avesse una chiusura definitiva; ma io provavo per tutto ciò una strana ripugnanza. Mi pareva di non essere più capace del minimo sforzo materiale e morale. M'incresceva di trovarmi là, in quelle necessità, in quelle difficoltà, costretto a quella continuazione. E una specie di rancore sordo incominciò a muoversi vagamente in fondo a me, contro Giuliana. M'alzai. L'aiutai ad alzarsi. Ciascun singulto, che ancora a quando a quando la scoteva, aumentava in me quel rancore inesplicabile. È proprio vero dunque che qualche parte d'odio si cela in fondo ad ogni sentimento che accomuna due creature umane, cioè che ravvicina due egoismi. È proprio vero dunque che questa parte d'odio immancabile disonora sempre i nostri più teneri abbandoni, i nostri migliori impeti. Tutte le belle cose dell'anima portano in loro un germe di corruzione latente, e devono corrompersi. Io dissi (e temevo che la voce mio malgrado non fosse a bastanza dolce): --Càlmati, Giuliana. Ora bisogna che tu sii forte. Vieni, siedi qui. Càlmati. Vuoi un poco d'acqua da bere? Vuoi qualche cosa da odorare? Dimmi tu. --Sì, un poco d'acqua. Cerca là, nell'alcova, sul tavolo da notte. Ella aveva ancora una voce di pianto; e si asciugava la faccia con un fazzoletto, seduta su un divano basso, di contro al grande specchio d'un armario. Il singulto le durava ancora. Entrai nell'alcova per prendere il bicchiere. Nella penombra scorsi il letto. Era già preparato: un lembo delle coperte era rialzato e discostato, una lunga camicia bianca era posata presso il guanciale. Subito il mio senso acuto e vigile percepì il fievole odore della batista, un odore svanito d'ireos e di mammola che conoscevo. La vista del letto, l'odore noto mi diedero un turbamento profondo. In fretta versai l'acqua ed uscii per portare il bicchiere a Giuliana che aspettava. Ella bevve qualche sorso, a riprese, mentre io, in piedi d'avanti a lei, la guardavo notando l'atto della sua bocca. Disse: --Grazie, Tullio. E mi rese il bicchiere non vuotato se non a metà. Come avevo sete, io bevvi il resto dell'acqua. Bastò quel piccolo fatto irriflessivo per aumentare in me il turbamento. Sedetti anch'io sul divano. E tacemmo, ambedue assorti nel nostro pensiero, separati da un breve spazio. Il divano con le nostre figure si rifletteva nello specchio dell'armario. Senza guardarci noi potevamo vedere i nostri volti ma non bene distinti perché la luce era scarsa e mobile. Io consideravo fissamente nel fondo vago dello specchio la figura di Giuliana che prendeva a poco a poco nella sua immobilità un aspetto misterioso, l'inquietante fascino di certi ritratti feminili oscurati dal tempo, l'intensa vita fittizia degli esseri creati da una allucinazione. Ed accadde che a poco a poco quell'imagine discosta mi sembrò più viva della persona reale. Accadde che a poco a poco in quell'imagine io vidi la donna delle carezze, la donna di voluttà, l'amante, l'infedele. Chiusi gli occhi. L'Altro comparve. Una delle note visioni si formò. Io pensavo: "Ella non ha finora mai alluso direttamente alla sua caduta, al modo della sua caduta. Una sola frase significante ella ha proferito:--Credi tu che la colpa sia grave _quando l'anima non consente_?--Una frase! E che ha voluto ella significare? Si tratta d'una delle solite distinzioni sottili che servono a scusare e ad attenuare tutti i tradimenti e tutte le infamie. Ma, in somma, quale specie di relazione è corsa tra lei e Filippo Arborio, oltre quella carnale innegabile? E in quali circostanze ella s'è abbandonata?" Un'atroce curiosità mi pungeva. Le suggestioni mi venivano dalla mia stessa esperienza. Mi tornavano alla memoria, precise, certe particolari maniere di cedere usate da alcune delle mie antiche amanti. Le imagini si formavano, si mutavano, si succedevano lucide e rapide. Rivedevo Giuliana, quale l'avevo veduta in giorni lontani, sola nel vano d'una finestra, con un libro su le ginocchia, tutta languida, pallidissima, nell'attitudine di chi sia per venir meno, mentre un'alterazione indefinibile, come una violenza di cose soffocate, passava ne' suoi occhi troppo neri.--Era stata sorpresa da colui in uno di quei languori, nella mia casa stessa, ed aveva patita la violazione in una specie d'inconsapevolezza, e risvegliandosi aveva provato orrore e disgusto dell'atto irreparabile, e aveva scacciato colui e non l'aveva più riveduto? O pure aveva consentito a recarsi in qualche luogo segreto, in un piccolo appartamento remoto, forse in una delle camere mobiliate per ove passano le sozzure di cento adulterii, e aveva ricevuto e prodigato sul medesimo guanciale tutte le carezze, non una sola volta, ma più volte, ma molti giorni di seguito, ad ore stabilite, nella sicurtà procuratale dalla mia incuranza? E rividi Giuliana d'avanti allo specchio nel giorno di novembre, la sua attitudine nell'appuntare il velo al cappello, il colore del suo abito, e poi il suo passo leggero "sul marciapiede dalla parte del sole."--Quella mattina era andata a un ritrovo forse? Io soffrivo una tortura senza nome. La smania di sapere mi torceva l'anima; le imagini fisiche mi esasperavano. Il rancore contro Giuliana diveniva più acre; e il ricordo delle voluttà recenti, il ricordo del letto nuziale di Villalilla, quel che di lei m'era rimasto nel sangue, alimentavano una cupa fiamma. Dalla sensazione che mi dava la vicinanza del corpo di Giuliana, da uno speciale tremito io m'accorsi che ero già caduto in preda alla ben nota febbre della gelosia sessuale e che per non cedere a un impeto odioso bisognava fuggire. Ma la mia volontà pareva colpita da paralisi; io non ero padrone di me. Rimanevo là, tenuto da due forze contrarie, da una repulsione e da una attrazione interamente fisiche, da una concupiscenza mista di disgusto, da un oscuro contrasto che io non potevo sedare perché si svolgeva nell'infimo della mia sostanza bruta. L'Altro, dall'istante in cui era comparso, era rimasto di continuo innanzi a me. Era Filippo Arborio? Avevo proprio indovinato? Non m'ingannavo? Mi voltai verso Giuliana all'improvviso. Ella mi guardò. La domanda repentina mi rimase strozzata nella gola. Abbassai gli occhi, piegai il capo: e, con la stessa tensione spasmodica che avrei provato nello strapparmi da una parte del corpo un lembo di carne viva, osai chiedere: --Il nome di _quell'uomo_? La mia voce era tremante e roca, e faceva male a me medesimo. Alla domanda inaspettata, Giuliana trasalì; ma tacque. --Non rispondi?--incalzai, sforzandomi di comprimere la collera che stava per invasarmi, quella collera cieca che già la notte innanzi nell'alcova era passata sul mio spirito come una raffica. --Oh mio Dio!--ella gemette angosciosamente, abbattendosi sul fianco, nascondendo la faccia in un cuscino.--Mio Dio, mio Dio! Ma io volevo sapere; io volevo strapparle la confessione ad ogni costo. --Ti ricordi--seguitai--ti ricordi tu di quella mattina che entrai nella tua stanza all'improvviso, su i primi di novembre? Ti ricordi? Entrai non so perché: perché tu cantavi. Cantavi l'aria di Orfeo. Eri quasi pronta per uscire. Ti ricordi? Io vidi un libro su la tua scrivania, l'apersi, lessi sul frontespizio una dedica.... Era un romanzo:--_Il Segreto_.... Ti ricordi? Ella rimaneva abbattuta sul cuscino, senza rispondere. Mi chinai verso di lei. Tremavo d'un ribrezzo simile a quello che precede il freddo della febbre. Soggiunsi: --È forse colui? Ella non rispose, ma si sollevò con un impeto disperato. Pareva demente. Fece l'atto di gettarsi su me, poi si trattenne. --Abbi pietà! Abbi pietà!--proruppe.--Lasciami morire! Questo che tu mi fai soffrire è peggiore di qualunque morte. Tutto ho sopportato, tutto potrei sopportare; ma questo non posso, non posso.... Se io vivrò, sarà per noi un martirio di tutte l'ore, ed ogni giorno più sarà terribile. E tu mi odierai: tutto il tuo odio mi verrà sopra. Lo so, lo so. Ho già sentito l'odio nella tua voce. Abbi pietà! Lasciami prima morire! Pareva demente. Aveva il bisogno smanioso di aggrapparsi a me; e, non osando, si torceva le mani per trattenersi, con un orgasmo di tutta la persona. Ma io la presi per le braccia, l'attirai a me. --Non saprò dunque nulla?--le dissi quasi su la bocca, divenuto anch'io demente, incitato da un istinto crudele che rendeva rudi le mie mani. --T'amo, t'ho amato sempre, sono stata sempre tua, sconto con quest'inferno un minuto di debolezza, intendi?, _un minuto di debolezza_.... È la verità. Non senti che è la verità? Ancora un attimo lucido; e poi l'effetto d'un impulso cieco, selvaggio, inarrestabile. Ella cadde sul cuscino rovescia. Le mie labbra soffocarono il suo grido. XVII. Molte cose quella stretta violenta aveva soffocate. "Selvaggio! Selvaggio!" Io rivedevo le lacrime mute che avevano riempito a Giuliana il cavo degli occhi; riudivo il rantolo ch'ella aveva emesso nel sussulto supremo, un rantolo d'agonizzante. E mi ripassava per l'anima un'onda di quella tristezza, non somigliante a nessun'altra, che dopo l'atto m'era piombata sopra. "Ah, veramente selvaggio!" La prima suggestione del delitto non era entrata in me proprio allora? Non s'era affacciata alla mia conscienza, durante la furia, un'intenzione micidiale? E ripensavo alle amare parole di Giuliana: "Ho la vita tenace". Non la tenacità della sua vita mi pareva straordinaria ma quella dell'_altra vita_ ch'ella portava dentro; e contro quella a punto io m'esasperavo, contro quella incominciavo a macchinare. Non erano ancora manifesti nella persona di Giuliana i segni esterni: l'allargamento dei fianchi, l'aumento del volume nel ventre. Ella si trovava dunque ancora ai primi mesi: forse al terzo, forse al principio del quarto. Le aderenze che univano il feto alla matrice dovevano esser deboli. L'aborto doveva essere facilissimo. Come mai le violente commozioni della giornata di Villalilla e di quella notte, gli sforzi, gli spasimi, le contratture, non l'avevano provocato? Tutto m'era avverso, tutti i casi congiuravano contro di me. E la mia ostilità diveniva più acre. Impedire che il figlio nascesse era il mio segreto proposito. Tutto l'orrore della nostra condizione veniva dalla antiveggenza di quella natività, dalla minaccia dell'intruso. Come mai Giuliana, al primo sospetto, non aveva tentato ogni mezzo per distruggere il concepimento infame? Era stata ella trattenuta da un pregiudizio, da una paura, da una ripugnanza instintiva di madre? Aveva ella un senso materno anche per il feto adulterino? E io consideravo la vita avvenire, divinata con una specie di chiaroveggenza.--Giuliana dava alla luce un maschio, unico erede del nostro antico nome. Il figliuolo non mio cresceva, incolume; usurpava l'amore di mia madre, di mio fratello; era careggiato, adorato a preferenza di Maria e di Natalia, delle mie creature. La forza dell'abitudine quietava i rimorsi in Giuliana, ed ella si abbandonava al suo sentimento materno, senza ritegno. E il figliuolo non mio cresceva protetto da lei, per le cure assidue di lei; si faceva robusto e bello; diveniva capriccioso come un piccolo despota; s'impadroniva della mia casa.--Queste visioni a poco a poco si particolarizzavano. Certe rappresentazioni fantastiche assumevano il rilievo e il movimento di una scena reale; e qualche tratto d'una tal vita fittizia s'imprimeva così forte nella mia conscienza da restarvi notato per un certo tempo con tutti i caratteri di una realtà. La figura del fanciullo era infinitamente variabile; i suoi atti, i suoi gesti erano diversissimi. Ora io me lo figuravo esile, pallido, taciturno, con una grossa testa pesante inchinata sul petto; ora tutto roseo, rotondo, gaio, loquace, pieno di vezzi e di blandizie, singolarmente amorevole verso di me, buono; ora in vece tutto nervi, bilioso, un po' felino, pieno d'intelligenza e d'istinti malvagi, duro con le sorelle, crudele verso gli animali, incapace di tenerezze, indisciplinabile. A poco a poco questa ultima figurazione si sovrappose alle altre, le eliminò permanendo, si raffermò in un tipo preciso, si animò di una intensa vita fittiva, prese perfino un nome: il nome già da tempo stabilito per l'erede mascolino, il nome di mio padre: Raimondo. Il piccolo fantasma perverso era una emanazion diretta del mio odio; aveva contro di me la stessa inimicizia che io avevo contro di lui; era un nemico, un avversario col quale stavo per impegnare la lotta. Egli era la mia vittima ed io ero la sua. Ed io non potevo sfuggirgli, egli non poteva sfuggirmi. Eravamo ambedue chiusi in un cerchio d'acciaio. I suoi occhi erano grigi come quelli di Filippo Arborio. Tra le varie espressioni del suo sguardo una mi colpiva più spesso, in una scena imaginaria che ogni tanto si ripeteva. La scena era questa:--Io entrava senza sospetto in una stanza immersa nell'ombra, piena d'un silenzio singolare. Credevo d'esser solo, là dentro. A un tratto, volgendomi, m'accorgevo della presenza di Raimondo che mi guardava fiso con i suoi occhi grigi e malvagi. M'assaliva subitamente la tentazione del delitto, così forte che, per non gittarmi sul piccolo essere malefico, fuggivo. XVIII. Il patto dunque tra me e Giuliana pareva concluso. Ella viveva. Ambedue seguitavamo a vivere simulando, dissimulando. Avevamo, come i dipsomani, due vite alterne: una tranquilla, tutta composta di dolci apparenze, di tenerezze filiali, di affetti puri, di atti benigni; l'altra agitata, febrile, torbida, incerta, senza speranza, dominata dall'idea fissa, incalzata sempre da una minaccia, precipitante verso una catastrofe ignota. Io avevo qualche raro momento in cui l'anima, sfuggendo all'assedio di tante cattive cose, liberandosi dal male che la avvolgeva come di mille tentacoli, si slanciava con un grande anelito verso l'alto ideale di bontà più volte intraveduto. Mi tornavano alla memoria le singolari parole da mio fratello dette sul limite del bosco d'Assoro, riguardanti Giovanni di Scòrdio: "_Farai bene, Tullio, a non dimenticare quel sorriso._" E quel sorriso su la bocca appassita del vecchio prendeva un significato profondo, diventava straordinariamente luminoso, m'esaltava come la rivelazione d'una suprema verità. Quasi sempre, in quei rari momenti, un altro sorriso mi riappariva; quello di Giuliana ancora inferma sui guanciali, il sorriso impreveduto che "s'attenuava, s'attenuava senza estinguersi." E il ricordo del lontano pomeriggio quieto in cui avevo inebriato d'un'ebrezza ingannevole la povera convalescente dalle mani così bianche; il ricordo della mattina in cui ella s'era levata per la prima volta e a mezzo della stanza m'era caduta fra le braccia ridendo e ansando; il ricordo del gesto veramente divino con cui ella m'aveva offerto l'amore, l'indulgenza, la pace, il bisogno, l'oblio, tutte le cose belle e tutte le cose buone, mi davano rimpianti e rimorsi senza fine disperati. La dolce e terribile domanda che Andrea Bolkonsky aveva letto sul viso estinto della principessa Lisa, io la leggevo di continuo sul viso ancor vivente di Giuliana: "Che avete fatto di me?" Nessun rimprovero era uscito dalla sua bocca; per diminuire la gravità della sua colpa ella non aveva saputo rinfacciarmi nessuna delle mie infamie, ella era stata umile d'innanzi al suo carnefice, non una stilla di amaro aveva inasprito le sue parole; e pure i suoi occhi mi ripetevano: "Che hai tu fatto di me?" Uno strano ardore di sacrificio m'infiammava subitamente, mi spingeva ad abbracciare la mia croce. La grandezza dell'espiazione mi pareva degna del mio coraggio. Mi sentivo una sovrabbondanza di forze, l'anima eroica, l'intelletto illuminato. Andando verso la _sorella_ dolorosa, io pensavo: "Troverò la buona parola per consolarla, troverò l'accento fraterno per mitigare il suo dolore, per rialzare la sua fronte." Ma, giunto alla presenza di lei, non parlavo più. Le mie labbra parevano premute da un suggello infrangibile; tutto il mio essere pareva colpito da un malefizio. La luce interiore si spengeva a un tratto, come per un soffio gelido, d'ignota origine. E nella oscurità incominciava a muoversi vagamente, quel sordo rancore che io già troppo conoscevo e non potevo reprimere. Era l'indizio d'un accesso. Balbettavo qualche parola, smarrito, evitando di guardare Giuliana negli occhi; e andavo via, fuggivo. Più d'una volta rimasi. Perdutamente, quando l'orgasmo diventava insostenibile, io cercavo la bocca di Giuliana; ed erano baci prolungati fino alla soffocazione, erano strette quasi rabbiose, che ci lasciavano più affranti, più tristi, divisi da un abisso più cupo, avviliti da una macchia di più. "Selvaggio! Selvaggio!" Un'intenzione micidiale era in fondo a quelli impeti, un'intenzione che non osavo confessare a me stesso.--Se una volta alfine le contratture dello spasmo, in una di quelle strette, avessero distaccato dalla matrice il germe tenace!--Io non consideravo il mortale pericolo a cui esponevo Giuliana. Era evidente che, se un caso simile fosse avvenuto, la vita della madre avrebbe corso un grave rischio. E bene io da prima, nella mia demenza, non pensai se non alla probabilità di distruggere il figlio. Soltanto più tardi considerai che l'una vita era schiava dell'altra e che con i miei folli tentativi insidiavo l'una e l'altra insieme. Giuliana in fatti, che forse sospettava di quali elementi ignobili si formasse il mio desiderio, non mi resisteva. Le mute lacrime dell'anima calpestata non più le riempivano il cavo degli occhi. Ella rispondeva al mio ardore con un ardore quasi lugubre. Veramente ella aveva talvolta "sudori d'agonizzante e aspetti di cadavere", che mi atterrivano. E una volta mi gridò, fuori di sé, con la voce soffocata: --Sì, sì, uccidimi! Compresi. Ella sperava la morte, l'aspettava da me. XIX Era incredibile la sua forza nel dissimulare, alla presenza degli inconsapevoli. Ella riusciva ancora a sorridere! I noti timori per la salute di lei mi davano modo di giustificare certe tristezze che non sapevo nascondere. Tali timori a punto, comuni a mia madre e a mio fratello, facevano sì che nella casa la nuova concezione non fosse festeggiata come le altre e fossero evitati i soliti pronostici ed ogni discorso allusivo. Ed era fortuna. Ma giunse finalmente alla Badiola il dottor Vebesti. La sua visita fu rassicurante. Egli trovò Giuliana molto indebolita, osservò in lei qualche disordine nervoso, l'impoverimento del sangue, un disturbo nutritivo generale dell'organismo; ma affermò che il processo della gravidanza non presentava anomalie notevoli e che, migliorate le condizioni generali, anche il processo del parto avrebbe potuto compiersi regolarmente. Inoltre egli mostrò di confidar molto nella tempra eccezionale di Giuliana, dalla quale anche pel passato aveva avuto prove straordinarie di resistenza. Ordinò una cura igienica e dietetica atta a ricostituirla, approvò il soggiorno alla Badiola, raccomandò il metodo, l'esercizio moderato, la tranquillità di spirito. --Conto specialmente su voi--mi disse, con serietà. Io rimasi deluso. Avevo riposta in lui una speranza di salvezza ed ecco, la perdevo. Prima del suo arrivo, avevo sperato: "Se dichiarasse necessario, per guarentire la madre, sacrificare il figlio ancora informe e non vitale! Se dichiarasse necessario provocare ad arte l'aborto per evitare la catastrofe sicura all'epoca della maturità!... Giuliana sarebbe salva, guarirebbe; ed io anche sarei salvo, mi sentirei rinascere. Credo che potrei quasi dimenticare, o, almeno, rassegnarmi. Il tempo chiude tante piaghe e il lavoro consola di tante tristezze. Credo che potrei conquistare la pace, a poco a poco, ed emendarmi, seguire l'esempio di mio fratello, diventar migliore, diventare un Uomo, vivere per gli altri, abbracciare la religione nuova. Credo che potrei ritrovare in questo stesso dolore la mia dignità.--L'uomo a cui è dato soffrire più degli altri, è _degno_ di soffrire più degli altri.--Non è un versetto del vangelo di mio fratello? C'è dunque una elezione di dolore. Giovanni di Scòrdio, per esempio, è un eletto. Chi possiede quel sorriso possiede un dono divino. Credo che potrei meritare quel dono...." Avevo sperato. Contraddicendo al mio fervore espiatorio, avevo sperato in una diminuzione di pena! In fatto, volendo rigenerarmi nella sofferenza, avevo paura di soffrire: un'atroce paura d'affrontare il vero dolore. La mia anima era già sfinita; e, pur avendo intraveduta la grande via ed essendo agitata da aspirazioni cristiane, si metteva per un sentiero obliquo in fondo al quale era l'abisso inevitabile. Parlando col dottore, mostrando un po' d'incredulità per le sue previsioni rassicuranti, mostrando qualche inquietudine, io trovai il modo di esporgli il mio pensiero. Gli feci intendere che desideravo allontanato per Giuliana il pericolo a qualunque costo e che, se fosse stato necessario, avrei rinunziato al terzogenito senza rammarico. Lo pregai di non nascondermi nulla. Egli di nuovo mi rassicurò. Mi dichiarò che, anche in un caso disperato, non avrebbe ricorso all'aborto perché nelle condizioni in cui trovavasi Giuliana, una emorragia sarebbe stata perniciosissima. Mi ripetè che bisognava anzi tutto promuovere e sostenere la rigenerazione del sangue, ricostruire l'organismo infiacchito, cercare con ogni mezzo che l'incinta giungesse all'epoca del parto restaurata di forze, fiduciosa, tranquilla. Soggiunse: --Credo che la signora abbia specialmente bisogno di consolazioni morali. Io sono un vecchio amico. So che ella ha molto sofferto. Voi potrete sollevarla. XX. Mia madre rianimata moltiplicò verso Giuliana le sue tenerezze. Manifestò il suo caro sogno e il suo presentimento. Ella aspettava il nipote, il piccolo Raimondo. Era _sicura_, questa volta. Mio fratello anche aspettava Raimondo. Maria e Natalia rivolgevano spesso a me, alla madre, alla nonna, domande ingenue e graziose sul compagno futuro. Così con presagi, con augurii, con speranze l'amor familiare incominciava ad avvolgere il frutto invisibile, l'essere ancora informe. E i fianchi di Giuliana incominciavano ad ingrossarsi. Un giorno eravamo rimasti io e Giuliana seduti sotto gli olmi. Mia madre ci aveva lasciati da poco. Nei suoi discorsi affettuosi ella aveva nominato Raimondo; aveva anzi rinnovato il diminutivo: Mondino, richiamando lontanissimi ricordi di mio padre morto. Io e Giuliana le avevamo sorriso. Ella aveva creduto che il suo sogno fosse il nostro sogno. Ci aveva lasciati là perché continuassimo a sognare. Era l'ora che segue lo scomparire del sole, un'ora lucida e calma. I fogliami sul nostro capo non si movevano. A quando a quando uno stormo di rondini veemente fendeva l'aria con un rombo d'ali, con uno scoppio di gridi come a Villalilla. Seguimmo con gli occhi la santa finché disparve. Allora ci guardammo, in silenzio, costernati. Rimanemmo in silenzio per qualche tempo, oppressi dall'immensità della nostra tristezza. E io, con una terribile intensione di tutto il mio essere, astraendo da Giuliana, sentii vivere accanto a me la creatura isolata come se null'altro in quel momento vivesse accanto a me, null'altro. E non fu una sensazione illusoria ma reale e profonda. Fu un raccapriccio che mi pervase tutte le fibre. Sussultai forte; e levai di nuovo lo sguardo al viso della mia compagna, per dissipare quella sensazione d'orrore. Ci guardammo, perduti, non sapendo che dire, che fare contro l'eccesso dello spasimo. E io vedevo nel viso di lei riflessa la mia angoscia, indovinavo il mio aspetto. E, poiché i miei occhi andarono istintivamente al grembo, come li rialzai scorsi nel viso di lei quell'espressione di terror panico che hanno gli infermi d'una infermità mostruosa quando qualcuno osserva la parte difformata dal male incurabile. Ella disse, a voce bassa, dopo un intervallo in cui ambedue avevamo tentato di misurare la nostra pena e non avevamo trovato un termine; ella disse: --Hai tu pensato che questo potrebbe durare tutta la vita? Io non aprii le labbra; ma la risposta sonò dentro di me risoluta: "No, questo non durerà." Ella soggiunse: --Ricordati che con una parola tu puoi troncare ogni cosa, liberarti. Io sono pronta. Ricordatene. Ancora tacqui; ma pensai: "Non tu devi morire." Ella soggiunse, con una voce che tremava di desolata tenerezza: --Io non posso consolarti! Non c'è consolazione per te né per me; non ci potrà essere mai.... Hai tu pensato che _qualcuno_ starà sempre fra noi due? Se il vóto di tua madre fosse esaudito.... Pensa! Pensa! Ma la mia anima fremeva sotto il balenio sinistro d'un solo pensiero. Io dissi: --Tutti già l'amano. Esitai. Guardai Giuliana rapidamente. Riabbassando subito le palpebre, chinando il capo, le chiesi con una voce che mi si spense fra le labbra: --L'ami tu? --Ah, che mi domandi! Non potei non insistere, se bene soffrissi fisicamente come per riconficcare l'unghia in una lacerazione viva. --L'ami? --No no. L'ho in orrore. Ebbi un moto istintivo di gioia come se per quella confessione avessi ottenuto il consenso al mio pensiero segreto e quasi la complicità. Ma aveva ella risposto il vero? O aveva mentito per misericordia di me? M'assalì una cruda smania d'insistere ancora, di costringerla a una confessione lunga ed intera, di penetrarla bene a dentro. Ma il suo aspetto mi trattenne. Rinunziai. Mi sentivo ora disacerbato verso di lei, benché ella portasse dentro di sé la vita su cui pendeva la mia condanna. Inclinavo ora verso di lei con un sentimento di gratitudine. Mi pareva che quell'orrore, da lei confessato con un fremito, la distaccasse dalla creatura che ella nutriva e la ravvicinasse a me. E provavo il bisogno di farle intendere queste cose, di aumentare in lei l'avversione contro il nascituro come contro un nemico d'entrambi inconciliabile. Io le presi una mano; le dissi: --Tu mi sollevi un poco. Ti son grato. Tu intendi.... Soggiunsi, mascherando di speranza cristiana la mia intenzione micidiale: --C'è una Provvidenza. Chi sa! Ci può essere per noi una liberazione.... Tu intendi quale. Chi sa! Prega Iddio. Era un augurio di morte al nascituro; era un vóto. E, inducendo Giuliana a pregare Iddio che l'esaudisse, io la preparavo all'avvenimento funebre, ottenevo da lei una specie di complicità spirituale. Perfino pensai: "Se, dopo le mie parole, entrasse in lei la suggestione del delitto e divenisse a poco a poco tanto forte da trascinarla!... Certo, ella potrebbe convincersi della terribile necessità, esaltarsi al pensiero di liberarmi, avere un impeto di energia selvaggia, compiere il sacrifizio estremo. Non ha ripetuto anche dianzi che ella è pronta sempre a morire? La sua morte implica la morte del fanciullo. Ella dunque non è trattenuta da un pregiudizio religioso, dalla paura del peccato; perché, essendo disposta a morire, ella è disposta a commettere un delitto duplice, contro sè stessa e contro il frutto del suo ventre. Ma ella è convinta che la sua esistenza è utile su la terra, anzi necessaria, alle persone che l'amano e ch'ella ama; ed è convinta che l'esistenza del figliuolo non mio renderà la nostra vita un supplizio insostenibile. Anche sa che noi potremmo ricongiungerci, che potremmo forse nel perdono e nell'oblio ritrovare qualche dolcezza, che potremmo sperare dal tempo la guarigione della piaga, se tra me e lei non si levasse l'intruso. Basterebbe dunque che ella considerasse queste cose perché un vóto inutile, una preghiera inefficace si mutassero a un tratto in un proposito e in un'azione." Pensavo; ed ella anche taceva e pensava, a capo chino, tenendo ancora la sua mano nella mia, mentre cadeva su noi l'ombra dai grandi olmi immobili. Che pensava ella? La sua fronte era pur sempre tenue e pallida come un'ostia. Cadeva forse su lei un'altra ombra, oltre quella della sera? Io vedevo Raimondo: non più in forma del fanciullo perverso e felino dagli occhi grigi ma in forma d'un corpicciuolo rossiccio e molle, a pena a pena respirante, che una lieve pressione poteva far morire. La campana della Badiola diede il primo tocco dell'_Angelus_. Giuliana ritrasse la sua mano dalla mia; e si fece il segno della croce. XXI. Passato il quarto mese, passato il quinto, la gravidanza si svolgeva rapidamente. La figura di Giuliana, alta, snella e flessibile, s'ingrossava, si difformava come quella d'una idropica. Ella n'era umiliata, innanzi a me, come d'una infermità vergognosa. Un'acuta sofferenza appariva nel suo volto, quando ella sorprendeva i miei occhi fissi sul suo ventre gonfio. Io mi sentivo sfinito, incapace di trascinare più oltre il peso di quell'esistenza miserabile. Ogni mattina, veramente, quando aprivo gli occhi dopo un sonno agitato, era come se qualcuno mi presentasse una coppa profonda, dicendomi: "Se tu vuoi bere, oggi, se tu vuoi vivere, bisogna che tu sprema qui dentro, fino all'ultima goccia, il sangue del tuo cuore." Una ripugnanza, un disgusto, un ribrezzo indefinibili mi salivano dall'intimo dell'essere, a ogni risveglio. E, intanto, bisognava vivere! I giorni erano d'una lentezza crudele. Il tempo non fluiva ma stillava, pigro e pesante. E avevo ancora d'innanzi a me l'estate, una parte dell'autunno, una eternità. Mi sforzavo di seguire mio fratello, d'aiutarlo nella grande opera agraria ch'egli aveva intrapreso, d'infiammarmi alla sua fede. Rimanevo a cavallo intere giornate come un buttero; mi stancavo in un lavoro manuale, in qualche bisogna facile e monotona; cercavo di ottundere l'acuità della mia conscienza stando a contatto con la gente della gleba, con gli uomini semplici e diritti, con quelli in cui poche norme morali ereditate compivano le loro funzioni naturalmente come gli organi del corpo. Più d'una volta visitai Giovanni di Scòrdio, il santo solitario; e volli udire la sua voce, volli interrogarlo su le sue sciagure, volli rivedere i suoi occhi tanto tristi e il suo sorriso tanto dolce. Ma egli era taciturno, un poco timido verso di me; rispondeva a pena qualche parola vaga, non amava parlare di sé, non amava lamentarsi, non interrompeva il lavoro a cui era intento. Le sue mani ossute, asciutte, brune, che parevano fuse in un bronzo animato, non si fermavano mai, non conoscevano forse la stanchezza. Un giorno esclamai: --Ma quando si riposeranno le tue mani? L'uomo probo se le guardò, sorridendo; ne considerò il dorso e il cavo, rivolgendole prone e poi supine al sole. Quello sguardo, quel sorriso, quel sole, quel gesto conferivano a quelle grosse mani incallite una nobiltà sovrana. Incallite su gli strumenti dell'agricoltura, santificate dal bene che avevano sparso, dalla vasta opera che avevano fornita, ora quelle mani erano degne di portare la palma. Il vecchio le incrociò sul suo petto, secondo l'uso mortuario cristiano; e rispose, pur sempre sorridendo: --Fra poco, signore, se Dio vorrà. Quando me le metteranno così, nella cassa. Così sia. XXII. Tutti i rimedi erano vani. Il lavoro non mi giovava, non mi consolava; perché era eccessivo, ineguale, disordinato, febrile, interrotto spesso da periodi d'inerzia invincibile, d'abbattimento, d'aridità. Mio fratello ammoniva: --Non è questa la regola. Tu consumi in una settimana l'energia di sei mesi; poi ti lasci ricadere nell'indolenza; poi di nuovo ti getti alla fatica, senza ritegno. Non è questa la regola. Bisogna che la nostra opera sia calma, concorde, armonica, per essere efficace. Intendi? Bisogna che noi ci prescriviamo un metodo. Ma già tu hai il difetto di tutti i novizii: un eccesso di ardore. Ti calmerai, in seguito. Mio fratello diceva: --Tu non hai ancora trovato l'equilibrio. Tu non ti senti ancora sotto i piedi _la terra ferma_. Non temere di nulla. O prima o poi tu potrai afferrare la tua legge. Questo t'accadrà all'improvviso, inaspettatamente, nel tempo. Anche diceva: --Giuliana questa volta, certo, ti darà un erede: Raimondo. Io ho già pensato al patrino. Tuo figlio sarà tenuto a battesimo da Giovanni di Scòrdio. Non potrebbe avere un patrino più degno. Giovanni gli infonderà la bontà e la forza. Quando Raimondo potrà comprendere, noi gli parleremo di questo gran vecchio. E tuo figlio sarà quel che noi non abbiamo potuto e saputo essere. Egli tornava spesso su l'argomento; nominava spesso Raimondo; augurava che il nascituro incarnasse l'ideal tipo umano da lui meditato, l'Esemplare. Non sapeva che ognuna delle sue parole era per me una fitta e rendeva più acre il mio odio e più violenta la mia disperazione. Inconsapevoli, tutti congiuravano contro di me, tutti facevano a gara nel ferirmi. Quando mi avvicinavo a qualcuno dei miei, mi sentivo ansioso e pauroso come se fossi costretto a rimanere al fianco d'una persona che, avendo tra le mani armi terribili, non ne conoscesse l'uso e la terribilità. Stavo in continua attesa d'un colpo. Dovevo cercare la solitudine, fuggire lontano da tutti, per avere un po' di tregua; ma nella solitudine mi ritrovavo a faccia a faccia col mio nemico peggiore: con me medesimo. Mi sentivo segretamente perire; mi pareva di perdere la vita da tutti i pori. Si riproducevano in me talvolta sofferenze appartenute al periodo più oscuro del mio passato omai remotissimo. Non altro conservavo in me talvolta se non il sentimento della mia esistenza isolata tra i fantasmi inerti di tutte le cose. Per lunghe ore non altro sentivo se non la fissità grave, schiacciante, della vita e il piccolo battito di un'arteria nella mia testa. Poi sopravvenivano le ironie, i sarcasmi contro me stesso, improvvise smanie di demolire e di distruggere, derisioni spietate, malignità feroci, un fermento acre del fecciume più basso. Mi pareva di non saper più che cosa fossero indulgenza, misericordia, tenerezza, bontà. Tutte le buone sorgenti interiori si chiudevano, s'inaridivano, come fonti colpite di maledizione. E allora in Giuliana non vedevo più se non il fatto brutale, il ventre gonfio, l'effetto dell'escrezione d'un altro maschio; non vedevo in me se non il ridicolo, il marito gabbato, lo stupido eroe sentimentale d'un cattivo romanzo. Il sarcasmo ulteriore non risparmiava nessuno dei miei atti, nessuno degli atti di Giuliana. Il dramma si mutava per me in una comedia amara e beffarda. Nulla più mi riteneva; tutti i legami si spezzavano; avveniva un distacco violento. E io pensavo: "Perché rimaner qui a recitare questa parte odiosa? Me ne andrò, tornerò al mondo, alla vita di prima, alla licenza. Mi stordirò, mi perderò. Che importa? Non voglio essere se non quel che sono: fango nel fango. Puah!" XXIII. In uno di tali accessi risolsi di lasciare la Badiola, di partire per Roma, di andare alla ventura. Mi si offriva il pretesto. Non prevedendo un'assenza tanto lunga, noi avevamo lasciata la casa in condizioni provvisorie. Bisognava dare assetto a molte cose; bisognava disporre tutto in modo che la nostra assenza potesse prolungarsi fuor d'un termine fisso. Annunziai la mia partenza. Persuasi di questa necessità mia madre, mio fratello, Giuliana. Promisi di sbrigarmi in pochi giorni. Mi preparai. Alla vigilia, la sera, tardi, mentre chiudevo una valigia, udii battere all'uscio della camera. Gridai: --Avanti! Vidi entrare Giuliana, sorpreso. --Oh, sei tu? Le mossi incontro. Ella ansava un poco, forse affaticata dalle scale. La feci sedere. Le offersi una tazza di tè freddo con un sottile disco di limone, una bevanda a lei grata un tempo, che era pronta por me. Ella vi bagnò a pena le labbra e me la rese. I suoi occhi rivelavano l'inquietudine. Disse al fine, timidamente: --Dunque parti? --Sì--io risposi--domattina, come sai. Seguì un intervallo di silenzio, lungo. Dalle finestre aperte entrava una frescura deliziosa; su i davanzali batteva la luna piena; giungeva il canto corale dei grilli, simile al suono d'un flauto un po' roco e indefinitamente lontano. Ella mi domandò, con la voce alterata: --Quando tornerai? Dimmi la verità. --_Non so_--risposi. Seguì un'altra pausa. Il vento leggero ricorreva a volta a volta, e le tende si gonfiavano. Ogni àsolo recava nella stanza, fino a noi, la voluttà della notte d'estate. --Mi abbandoni? Nella sua voce era uno scoramento così profondo che i nodi aspri dentro di me si sciolsero a un tratto; e il rammarico e la pietà mi invasero. --No--risposi--non temere, Giuliana. Ma ho bisogno di una tregua. Non ne posso più. Ho bisogno d'un respiro. Ella disse: --Hai ragione. --Credo che tornerò presto, come ho promesso. Ti scriverò. Anche tu, forse, non vedendomi soffrire, avrai un sollievo. Ella disse: --Nessun sollievo mai. Un pianto soffocato tremava nelle sue parole. Ella soggiunse a un tratto, con un accento di lacerante angoscia: --Tullio, Tullio, dimmi la verità. Mi odii? Dimmi la verità! Ella m'interrogava con gli occhi, assai più angosciosi delle sue parole. Parve fissare in me per un istante la sua stessa anima. E quei poveri occhi dilatati, quella fronte così pura, quella bocca convulsa, quel mento smagrito, tutto quel tenue viso dolente a contrasto con la difformità inferiore ignominiosa, e quelle mani, quelle tenui mani dolenti che si tendevano verso di me con un gesto supplichevole, mi fecero pena come non mai, e m'impietosirono e m'intenerirono. --Credimi, Giuliana, credimi per sempre. Non ho nessun rancore contro di te, non ne avrò mai. Non dimentico che ti debbo il contraccambio; non dimentico nulla. Non ne hai già le prove? Rassicurati. Pensa ora a _liberarti_. E poi.... chi sa! Ma, in qualunque caso, io non ti mancherò, Giuliana. Ora lascia che io parta. Forse qualche giorno di lontananza mi farà bene. Tornerò calmato. Sarà necessaria molta calma, poi. Tu avrai bisogno di tutto il mio aiuto.... Ella disse: --Grazie. Farai di me quel che vorrai. Un canto umano ora giungeva nella notte, coprendo il suono roco del flauto silvestre:--forse un coro di trebbiatori, da qualche aia remota sotto la luna. --Senti?--io dissi. Ascoltammo. Il vento asolava. Tutta la voluttà della notte d'estate veniva a gonfiarmi il cuore. --Vuoi che andiamo a sedere di là, sul terrazzo?--chiesi a Giuliana dolcemente. Ella acconsentì, si levò. Passammo nell'altra stanza, ove non era altro lume che quello del plenilunio. Un gran flutto candido, qualche cosa come un latte immateriale, inondava il pavimento. In quel flutto ella camminò d'avanti a me, per uscire sul terrazzo; e io potei vedere la sua ombra difforme disegnarsi cupa nel chiarore. Ah dov'era la creatura esile e pieghevole che avrei stretta fra le mie braccia? Dov'era l'amante che avevo rinvenuta sotto i fiori di lilla in un meriggio d'aprile?--Ebbi nel cuore, in un attimo, tutti i rimpianti, tutti i desiderii, tutte le disperazioni. Giuliana s'era seduta e aveva poggiata la testa al ferro della ringhiera. La sua faccia illuminata in pieno era più bianca di qualunque cosa intorno, più bianca del muro. Ella teneva le palpebre socchiuse. I cigli le spandevano a sommo delle gote un'ombra che mi turbava più d'uno sguardo. Come avrei potuto parlare? Mi volsi verso la valle, mi piegai su la ringhiera stringendo il ferro freddo tra le dita. Vidi sotto di me un'immensa massa di apparenze confuse, dove non distinsi se non lo scintillio dell'Assoro. Il canto giungeva or sì or no, secondo l'alito della frescura; e nelle pause si riudiva il suono di quel flauto un po' roco e indefinitamente lontano. Nessuna notte m'era parsa mai tanto piena di dolcezza e d'affanno. Dall'estremo fondo della mia anima irruppe un grido, altissimo se bene non udibile, verso la felicità perduta. XXIV. A pena giunsi in Roma, mi pentii d'esser partito. Trovai la città infocata, fiammeggiante, quasi deserta; e n'ebbi sgomento. Trovai la casa muta come un sepolcro, dove le medesime cose, le cose da me ben conosciute, avevano un aspetto diverso, strano; e n'ebbi sgomento. Mi sentii solo, in una solitudine spaventevole; ma non andai in cerca di amici, non volli ricordare né riconoscere amici. Solo mi misi alla caccia di un uomo contro il quale mi spingeva un odio implacabile: alla caccia di Filippo Arborio. Speravo d'incontrarlo subito in qualche luogo publico. Andai alla trattoria che sapevo da lui frequentata. L'aspettai tutta una sera premeditando il modo dell'affronto. Il passo d'ogni nuovo venuto mi rimescolava il sangue. Ma egli non comparve. Interrogai i camerieri. Da lungo tempo non l'avevano visto. Feci una visita alla sala d'armi. La sala era vuota, immersa nell'ombra verdognola prodotta dalle persiane chiuse, piena di quel particolare odore che l'innaffio solleva da un pavimento di tavole. Il maestro, abbandonato dagli allievi, mi accolse con grandi effusioni di benevolenza. Io ascoltai attentamente il racconto minuto dei trionfi riportati nelle gare dell'ultima academia. Poi gli chiesi notizie di alcuni amici frequentatori della sala; infine gli chiesi notizie di Filippo Arborio. --Non è più a Roma, da quattro o cinque mesi--mi rispose il maestro.--Ho sentito dire che è malato, d'una malattia nervosa molto grave, e che difficilmente guarirà. Lo diceva il conte Galiffa. Ma non so altro. Soggiunse: --Era molto fiacco, in fatti. Qui da me ha preso poche lezioni. Temeva la stoccata; non poteva vedersi la punta d'avanti agli occhi.... --È ancora a Roma Galiffa?--gli domandai. --No, è a Rimini. Dopo alcuni momenti mi accomiatai. La notizia inaspettata mi aveva colpito. Pensai: "Fosse vera!" E m'augurai che si trattasse d'una di quelle terribili malattie del midollo spinale o della sostanza cerebrale, che conducono un uomo alle infime degradazioni, all'idiotismo, alle più tristi forme della follia e quindi alla morte. Le nozioni apprese dai libri di scienza, i ricordi d'una visita a un manicomio, le imagini anche più precise lasciatemi impresse dal caso speciale di un mio amico, del povero Spinelli, ora mi tornavano alla memoria rapidamente. E rivedevo il povero Spinelli seduto su la gran poltrona di cuoio rosso, pallido d'un pallor terreo, con tutti i lineamenti della faccia irrigiditi, con la bocca dilatata e aperta, piena di saliva e d'un balbettio incomprensibile. E rivedevo il gesto ch'egli faceva ad ogni tratto per raccogliere nel fazzoletto quella saliva continua che gli colava dagli angoli della bocca. E rivedevo la figura bionda e smilza e dolente della sorella che metteva all'infermo un tovagliolo sotto il mento, come a un bambino, e con la sonda faringea gli introduceva nello stomaco i cibi ch'egli non avrebbe potuto inghiottire. Pensavo: "Ho tutto da guadagnare. Se avessi un duello con un avversario così celebre, se lo ferissi gravemente, se l'uccidessi, il fatto, certo, non rimarrebbe segreto; correrebbe su tutte le bocche, sarebbe divulgato, comentato da tutte le gazzette. E potrebbe anche venire in chiaro la causa vera del duello! In vece questa malattia provvidenziale mi salva da ogni pericolo, da ogni fastidio, da ogni pettegolezzo. Io posso ben rinunziare a una voluttà sanguinaria, a un castigo inflitto con la mia mano (e sono poi certo dell'esito?), quando so paralizzato dalla malattia, ridotto all'impotenza l'uomo che detesto. Ma la notizia sarà vera? E se si trattasse d'un disturbo transitorio?" Mi venne una buona idea. Saltai in una vettura e mi feci condurre alla libreria, dell'editore. Nella strada consideravo mentalmente (con un vóto sincero) i due disturbi cerebrali più terribili per un uomo di lettere, per un artefice della parola, per uno stilista:--l'afasia e l'agrafia. E avevo la visione fantastica dei sintomi. Entrai nella libreria. Da prima non distinsi nulla, con gli occhi abbacinati dalla luce esterna. Udii una voce nasale, dall'accento straniero, che mi chiedeva: --Il signore desidera?... Scorsi dietro il banco un uomo d'età inconoscibile, biondiccio, scarno, dilavato, una specie d'albino; e mi rivolsi a lui, indicandogli i titoli di alcuni libri. Ne comprai parecchi. Poi domandai l'ultimo romanzo di Filippo Arborio. L'albino mi porse _Il Segreto_. Allora m'atteggiai ad ammiratore fanatico del romanziere. --Questo è l'ultimo? --Sì, signore. La nostra casa ne ha annunziato un nuovo, da qualche mese:--_Turris eburnea_! --Ah, _Turris eburnea_! Il cuore mi diede un balzo. --Ma credo che non potremo publicarlo. --Perché mai? --Il romanziere è molto malato. --Malato! Di che male? --D'una paralisi bulbare progressiva--rispose l'albino distaccando le tre parole terribili l'una dall'altra, con una certa affettazione di saccente. "Ah, il male di Giulio Spinelli!" --Il caso è grave, dunque. --Gravissimo--sentenziò l'albino.--Ella sa che la paralisi non si arresta. --Ma ora è al principio. --Al principio; ma su la natura del male non c'è più dubbio. L'ultima volta che fu qui, io l'udii parlare. Già pronunziava con difficoltà alcune parole. --Ah, voi l'udiste? --Sì, signore. Aveva già la pronunzia indecisa, un po' tremolante in alcune parole.... Io incitavo l'albino con l'estrema attenzione, quasi ammirativa, che prestavo alle sue risposte. Credo ch'egli mi avrebbe volentieri distinte le consonanti contro le quali s'era incagliata la lingua del romanziere illustre. --E ora dov'è? --È a Napoli. I medici l'hanno sottoposto a una cura elettrica. --Ah, a una cura elettrica!--ripetevo io con uno stupore ingenuo, come un uomo ignaro, volendo solleticare la vanità dell'albino e prolungare la conversazione. Veramente, nella libreria stretta e lunga come un corridoio spirava un filo di frescura, per un riscontro. La luce era mite. Un commesso dormiva in pace, su una sedia, col mento sul petto, all'ombra d'un globo terraqueo. Nessuno entrava. Il libraio aveva qualche lato ridicolo che mi divertiva, così bianchiccio com'era, con quella bocca di rosicante, con quella voce nasale. E in una quiete di biblioteca era assai gradevole sentir dichiarare con tanta sicurezza l'infermità incurabile dell'uomo detestato. --I medici hanno dunque speranza di salvarlo--dicevo, per incitare l'albino. --Impossibile. --Dobbiamo sperare che sia possibile, per la gloria delle lettere.... --Impossibile. --Ma io credo che, nella paralisi progressiva, si dieno casi di guarigione. --No, signore, no. Egli potrà vivere ancora due, tre, quattro anni; ma non guarire. --E pure, io credo.... Non so da che mi venissero quella leggerezza d'animo nel prendermi gioco del mio informatore e quella curiosa compiacenza nell'assaporare un mio sentimento crudele. Certo, io godevo. E l'albino, punto dalla mia contraddizione, senza opporre altro, montò su una scaletta di legno posta contro uno scaffale elevato. Gracile com'era, pareva uno di quei gatti randagi, scarsi di carne e di pelo, che si spenzolano all'orlo dei tetti. Montando, urtò col capo un nastro ch'era teso da un angolo all'altro della libreria pel riposo delle mosche. Un nuvolo di mosche gli turbinò intorno con un ronzio fierissimo. Egli discese portando un volume: l'autorità da addurre in favore della morte. E le mosche implacabili discendevano con lui. Mi mostrò il frontespizio. Era un trattato di patologia speciale medica. --Ora sentirà. Cercò nelle pagine. Poiché il volume era intonso, discostò con le dita due fogli congiunti; e aguzzando i suoi occhi bianchicci, lesse per entro: "_La prognosi della paralisi bulbare progressiva è sfavorevole...._" Soggiunse: --Ora è persuaso? --Sì. Ma che peccato! Un'intelligenza così rara! Le mosche non si quietavano. Facevano tutte insieme un ronzio irritante. Assalivano me, l'albino, il commesso addormentato sotto il globo terraqueo. --Quanti anni _aveva_?--chiesi io, sbagliando involontariamente il tempo del verbo, come se parlassi d'un defunto. --Chi, signore? --Filippo Arborio. --Trentacinque anni, credo. --Così giovine! Avevo una strana voglia di ridere, una voglia puerile di ridere sul naso all'albino e di lasciarlo là stupefatto. Era una eccitazione singolarissima, un po' convulsiva, non mai provata, indefinita. Mi agitava lo spirito qualche cosa di simile a quella ilarità bizzarra e irrefrenabile che ci agita qualche volta tra le sorprese d'un sogno incoerente. Il trattato era rimasto aperto sul banco; e io mi chinai a guardare su una pagina una vignetta: un volto umano contorto da una smorfia atroce e grottesca. "_Emiatrofia sinistra della faccia._" E le mosche implacabili ronzavano, ronzavano senza posa. Ma una preoccupazione mi tornò. Domandai: --L'editore non ha ricevuto ancora il manoscritto della _Turris eburnea_? --No, signore. L'annunzio fu dato; ma non esiste se non il titolo. --Solo il titolo? --Sì, signore. L'annunzio in fatti è stato soppresso. --Grazie. Vi prego di mandarmi questi libri a casa, dentr'oggi. Diedi il mio indirizzo e uscii. Sul marciapiede ebbi una sensazione particolare di smarrimento. Mi pareva d'aver lasciato dietro di me un lembo di vita artificiale, fittizia, falsa. Quel che avevo fatto, quel che avevo detto, quel che avevo provato, e la figura dell'albino, e la sua voce, e il suo gesto: tutto mi pareva artificiale, assumeva l'inesistenza d'un sogno, il carattere d'una impressione avuta da una lettura recente, non dal contatto della realtà. Montai in vettura; tornai a casa. La sensazione vaga si dissipò. Mi raccolsi per riflettere. Mi assicurai che tutto era reale, indubitabile. Si formarono facilmente dentro di me imagini dell'infermo a similitudine di quelle che mi dava il ricordo del povero Spinelli. Mi punse una nuova curiosità. "Se andassi a Napoli per vederlo?" E mi rappresentai lo spettacolo miserevole di quell'uomo intellettuale degradato dal morbo, balbuziente come un mentecatto. Non provavo più alcuna gioia. Ogni eccitazione d'odio era estinta. Una tristezza cupa mi piombò sopra.--La ruina di quell'uomo non influiva sul mio stato, non riparava alla mia ruina. Nulla era mutato in me, nella mia esistenza, nella previsione del mio avvenire. E ripensai il titolo dell'annunziato libro di Filippo Arborio: _Turris eburnea_. I dubbii mi si affollarono nello spirito.--Si trattava d'un riscontro puramente casuale con l'appellativo della nota dedica? O lo scrittore aveva inteso creare un personaggio letterario a simiglianza di Giuliana Hermil, narrare la sua avventura recente?--E di nuovo la torturante interrogazione mi si ripresentò.--In che modo s'era svolta quell'avventura dal principio alla fine? E riudii le parole gridate da Giuliana nella notte indimenticabile: "T'amo, t'ho amato sempre, sono stata sempre tua, sconto con quest'inferno un minuto di debolezza, intendi?, _un minuto di debolezza...._ È la verità. Non senti che è la verità?" Ahimé, quante volte noi crediamo sentire la verità in una voce che mentisce! Nulla ci può difendere dall'inganno. Ma se quella che io avevo sentita nella voce di Giuliana era la verità pura, allora dunque veramente ella era stata sorpresa da colui in un languore dei sensi, nella mia casa stessa, ed aveva patita la violazione in una specie d'inconsapevolezza, e risvegliandosi aveva provato orrore e disgusto dell'atto irreparabile, e aveva scacciato colui e non l'aveva più riveduto? Questa imaginazione, in fatti, non aveva contro di sé nessuna delle apparenze; le quali a punto davano a supporre che qualunque legame tra Giuliana e colui fosse stato troncato da gran tempo decisamente. "Nella mia casa stessa!" io ripensavo, intanto. E nella casa muta come un sepolcro, nelle stanze deserte e piene d'afa, ero perseguitato dall'imagine inevitabile. XXV. Che fare? Rimanere ancora in Roma ad aspettare un'esplosione di follia dal mio cervello, in mezzo a quel fuoco, sotto quella rabbiosa canicola? Partire per il mare, per la montagna, andare a bevere l'oblio fra la gente, nei ritrovi eleganti d'estate? Risvegliare in me l'antico uomo voluttuario, alla ricerca di un'altra Teresa Raffo, di una qualunque amante vana? Due o tre volte m'indugiai nel ricordo della Biondissima; che pure m'era caduta interamente dal cuore e anche, per un lungo periodo, dalla memoria. "Dove sarà ella? Sarà ancora legata con Eugenio Egano? Che proverei nel rivederla?" Era una curiosità fiacca. M'accorsi che il mio desiderio unico e profondo e invincibile era di tornare laggiù, alla mia casa di pena, al supplizio. Presi con la massima sollecitudine i provvedimenti necessarii; feci una visita al dottor Vebesti, telegrafai alla Badiola il mio ritorno; e partii. L'impazienza mi divorava; un'ansia acuta mi pungeva, quasi che io andassi in contro a straordinarie novità. Il viaggio mi parve interminabile. Disteso su i cuscini, oppresso dal caldo, soffocato dalla polvere che penetrava per gli interstizi, mentre il romore monotono del treno si accordava al canto monotono delle cicale senza sopire il mio fastidio, io pensavo agli eventi prossimi, consideravo le possibilità future, cercavo di scrutare la grande ombra. Il _padre_ era mortalmente colpito. Quale sorte attendeva il _figlio_? XXVI. Nessuna novità, alla Badiola. La mia assenza era stata brevissima. Il mio ritorno fu festeggiato. Il primo sguardo di Giuliana mi espresse un'infinita gratitudine. --Hai fatto bene a tornar subito--mi disse mia madre sorridendo.--Giuliana non aveva requie. Ora non ti moverai più, speriamo. Soggiunse, accennando al ventre dell'incinta: --Non vedi un progresso? Oh, a proposito, ti sei ricordato dei merletti? No? Smemorato! Subito, fin dai primi momenti, ricominciava il supplizio. A pena io e Giuliana rimanemmo soli, ella mi disse: --Non speravo che tu tornassi tanto presto. Come ti sono grata! Nell'attitudine, nella voce ella era timida, umile, teneramente. Mi apparve anche più vivo il contrasto fra il suo volto e il resto della sua persona. Era per me visibile di continuo sul suo volto una particolare espressione penosa che rivelava in lei la continua insofferenza della deturpante e disonorante gravezza da cui il suo corpo era afflitto. Quell'espressione non l'abbandonava mai; era visibile anche a traverso le altre espressioni transitorie che, per quanto forti, non valevano a cancellarla; era inerente e fissa; e m'impietosiva, e mi scioglieva i rancori, e mi velava la brutalità troppo talora manifesta nei momenti d'ironica perspicacia. --Che hai fatto in questi giorni?--io le chiesi. --T'ho aspettato. E tu? --Nulla. Ho desiderato di tornare. --Per me?--ella mi domandò, timida e umile. --Per te. Ella socchiuse le palpebre, e un barlume di sorriso le tremolò sul volto. Sentii che io non ero mai stato amato come in quell'ora. Disse, dopo una pausa, guardandomi con gli occhi umidi: --Grazie. L'accento, il sentimento espresso mi ricordarono un altro _grazie_: quello da lei proferito in un mattino lontanissimo della convalescenza, nel mattino del mio primo delitto. XXVII. E così ricominciò la mia fatica alla Badiola e continuò trista, senza episodii notevoli, mentre l'ora s'indugiava nel quadrante solare aggravata dalla monotonia delle cicale che frinivano su gli olmi. _Hora est benefaciendi!_ E nel mio spirito si avvicendarono i soliti fermenti, le solite inerzie, i soliti sarcasmi, le solite vane aspirazioni, le solite crisi contraddittorie: l'abondanza e l'aridità. E più d'una volta, considerando quella cosa grigia neutra mediocre fluida e onnipossente che è la vita, pensai: "Chi sa! L'uomo è, sopra tutto, un animale accomodativo. Non c'è turpitudine o dolore a cui non s'adatti. Può anche essere che io finisca con un accomodamento. Chi sa!" Mi sterilivo a furia d'ironie. "Chi sa che il figlio di Filippo Arborio non sia, come si dice, _tutto il mio ritratto_. L'accomodamento allora sarà anche più facile." E ripensavo alla triste voglia di ridere che m'era venuta una volta sentendo dire d'un bimbo (che io sapevo sicuramente adulterino) alla presenza dei legittimi coniugi: --Tutto suo padre!--E la somiglianza era straordinaria, per quella misteriosa legge che i fisiologi chiamano _eredità d'influenza_. Per quella legge il figlio talvolta non somiglia né al padre né alla madre, ma somiglia all'uomo che ha avuto con la madre un contatto anteriore alla fecondazione. Una donna maritata in seconde nozze, tre anni dopo la morte del primo marito, genera figli che hanno tutti i lineamenti del marito defunto e non somigliano in nulla a colui che li ha procreati. "Può essere dunque che Raimondo porti la mia impronta e sembri un Hermil autentico" pensavo. "Può essere che io riceva speciali congratulazioni per avere impresso con tanto vigore all'Erede il suggello gentilizio!" "E se l'aspettazione di mia madre, di mio fratello fosse delusa? Se Giuliana desse alla luce una terza femmina?" Questa probabilità mi quietava. Mi pareva che avrei avuta una repulsione minore verso la neonata e che avrei potuto forse anche sopportarla. Ella col tempo si sarebbe allontanata dalla mia casa, avrebbe preso un altro nome, avrebbe vissuto in mezzo a un'altra famiglia. Intanto, come più s'avvicinava il termine, l'impazienza diveniva più fiera. Ero stanco di aver sempre avanti agli occhi quel ventre enorme che cresceva senza misura. Ero stanco di dibattermi sempre nella medesima sterile agitazione, tra i medesimi timori e le medesime perplessità. Avrei voluto che gli eventi precipitassero, che in fine una qualunque catastrofe si producesse. Qualunque catastrofe era preferibile a quell'orribile agonia. Un giorno, mio fratello domandò a Giuliana: --E bene? Quanto tempo ancora? Ella rispose: --Ancora un mese! Io pensai: "Se la storia del minuto di debolezza è vera, ella deve conoscere il giorno preciso del concepimento." Eravamo in settembre. L'estate era per morire. Era prossimo l'equinozio d'autunno, il più dolce tempo dell'anno, quel tempo che sembra portare in sé una specie di ebrietà aerea diffusa dalle uve mature. L'incanto mi penetrava a poco a poco, mi ammolliva l'anima; qualche volta mi dava un bisogno smanioso di tenerezze, di espansioni delicate. Maria e Natalia passavano lunghe ore con me, sole con me, nelle mie stanze o fuori per la campagna. Io non le avevo mai amate d'un amore così profondo e così gentile. Da quelli occhi impregnati di pensiero a pena consciente mi scendeva qualche volta nell'intimo spirito un raggio di pace. XXVIII. Un giorno andavo in cerca di Giuliana, per la Badiola. Erano le prime ore del pomeriggio. Non avendola trovata nelle sue stanze, non avendola trovata altrove, entrai nell'appartamento di mia madre. Le porte erano aperte; non si udivano voci né rumori; le tende leggère delle finestre palpitavano; s'intravedeva pei vani il verde degli olmi; una lene aura di rezzo spirava fra le pareti chiare. Mi avanzai verso il santuario, con cautela. Prevedendo il caso che mia madre dormisse, camminavo piano per non disturbarla. Discostai le portiere, mi affacciai dalla soglia. Udii infatti un respiro di dormiente. Vidi mia madre addormentata su una poltrona accanto alla finestra; vidi, fuor della spalliera d'un'altra poltrona, i capelli di Giuliana. Entrai. Stavano l'una di contro all'altra, e in mezzo a loro stava un tavolo basso con sopra una canestra piena di cuffie minuscole. Mia madre teneva ancora fra le dita una di quelle cuffie, in cui riluceva un ago. Il sonno era venuto a inchinarle il capo, nell'atto del lavoro. Col mento sul petto, ella dormiva; sognava forse. La gugliata bianca era rimasta a mezzo, ma ella filava forse nel sogno un filo più prezioso. Giuliana anche dormiva, ma con la testa abbandonata alla spalliera, con le mani posate lungo i bracciuoli. I suoi lineamenti s'erano come distesi nella dolcezza del sonno; ma la sua bocca conservava una piega triste, un'ombra d'afflizione: socchiusa, mostrava un poco della gengiva esangue; ma alla radice del naso, tra i sopraccigli, rimaneva il piccolo solco scavato dal grande dolore. E la fronte era madida: una stilla rigava lenta una tempia. E le mani, più bianche della mussolina da cui escivano, parevano confessare con la loro posa esse sole una immensa stanchezza. Su nessuna di queste spirituali apparenze io mi fermai come sul grembo che conteneva ormai l'essere già completo. E ancora una volta, astraendo da quelle apparenze, astraendo da Giuliana, sentii vivere quella creatura isolata come se null'altro in quel momento vivesse accanto a me, intorno a me, null'altro. E ancora una volta non fu una sensazione illusoria ma reale e profonda; fu un raccapriccio che mi agitò tutte le fibre. Girai gli occhi; e rividi tra le dita di mia madre la cuffia in cui riluceva l'ago; rividi nella canestra tutti quei merletti leggèri e quei nastri rosei e cilestri che tremolavano al soffio del vento. Mi si strinse il cuore così forte che credetti mancare. Quanta tenerezza rivelavano le dita di mia madre sognante su quella gentile cosa bianca che doveva coprire il capo del figliuolo non mio! Restai là qualche minuto. Quel luogo era veramente il santuario della casa, il penetrale. Su una parete pendeva il ritratto di mio padre, che somigliava molto a Federico; su l'altra, il ritratto di Costanza, che somigliava un poco a Maria. Le due figure, esistenti dell'esistenza superiore che danno le memorie dei cari ai cari scomparsi, avevano gli occhi magnetici e seguaci, una specie d'onniveggenza. Altre reliquie dei due scomparsi santificavano quel luogo. In un angolo, su un plinto, stava chiusa in cristalli, coperta d'un velo nero, la maschera formata sul cadavere dell'uomo che mia madre amava d'un amore più forte della morte. E pure nulla era lugubre là dentro. Una sovrana pace vi regnava e pareva diffondersi per tutta la casa come da un cuore si diffonde la vita, armonicamente. XXIX. Ricordo la gita a Villalilla, con Maria e Natalia e miss Edith, in una mattina un po' velata. È un ricordo velato, in fatti, indistinto, confuso, come d'un lungo sogno straziante e dolce. Il giardino non aveva più le sue miriadi di grappoli turchinicci, non aveva più la sua delicata selva di fiori né il suo profumo triplice armonioso come una musica, né il suo riso aperto, né il clamore continuo delle sue rondini. Non altro aveva di lieto se non le voci e le corse delle due bambine inconsapevoli. Molte rondini erano partite; altre partivano. Eravamo giunti in tempo per salutare l'ultimo stormo. Tutti i nidi erano abbandonati, vacui, esanimi. Qualcuno era infranto, e su gli avanzi della creta tremolava qualche piuma esile. L'ultimo stormo era adunato sul tetto lungo le gronde, e aspettava ancora qualche compagna dispersa. Le migratrici stavano in fila su l'orlo del canale, talune rivolte col becco altre col dorso, per modo che le piccole code forcute e i piccoli petti candidi si alternavano. E, così aspettando, gittavano nell'aria calma i richiami. E di tratto in tratto, a due, a tre, giungevano le compagne in ritardo. E s'approssimava l'ora della dipartita. I richiami cessavano. Un'occhiata di sole languida scendeva su la casa chiusa, su i nidi deserti. Nulla era più triste di quelle esili piume morte che qua e là, trattenute dalla creta, tremolavano. Come sollevato da un colpo di vento subitaneo, da una raffica, lo stormo si levò con un gran frullo di ali, sorse nell'aria in guisa d'un vortice, rimase un istante a perpendicolo su la casa; poi, senza incertezze, quasi che davanti gli si fosse disegnata una traccia, si mise compatto in viaggio, si allontanò, si dileguò, disparve. Maria e Natalia, ritte in piedi su un sedile per seguire più a lungo con lo sguardo le fuggitive, tendevano le braccia e gridavano: --Addio, addio, addio, rondinelle! Ho di tutto il resto un ricordo indistinto, come d'un sogno. Maria volle entrare nella casa. Io stesso aprii la porta. Là, su per quei tre gradini, Giuliana m'aveva seguito furtiva, leggera come un'ombra, e m'aveva allacciato e m'aveva bisbigliato: "Entra, entra." Nell'andito ancora pendeva il nido fra le grottesche della volta. "Ora sono tua, tua, tua!" ella aveva bisbigliato, senza distaccarsi dal mio collo ma girando flessuosamente per venirmi sul petto, per incontrare la mia bocca.--L'andito era muto, le scale erano mute; il silenzio occupava tutta la casa. Là avevo udito il rombo cupo e remoto, simile a quello che conservano in loro certe conchiglie profonde. Ma ora il silenzio era simile a quello delle tombe. Là stava sepolta la mia felicità. Maria, Natalia cianciavano senza tregua, non cessavano mai d'interrogarmi, si mostravano curiose di tutto, andavano ad aprire i cassetti dei canterani, gli armarii. Miss Edith le seguiva per moderarle. --Guarda, guarda che ho trovato!--gridò Maria correndomi in contro. Aveva trovato in fondo a un cassetto un mazzo di spigo e un guanto. Era un guanto di Giuliana; era macchiato di nero su la punta delle dita; nel rovescio, presso all'orlo, portava una scritta ancora leggibile: "_Le more: 27 agosto 1880. Memento!_" Mi tornò chiaro alla memoria, in un lampo, l'episodio delle more, uno dei più lieti episodii della nostra felicità primitiva, un frammento d'idillio. --Non è un guanto della mamma?--mi domandò Maria.--Rendimelo, rendimelo. Voglio portarlo io alla mamma.... Ho di tutto il resto un ricordo indistinto, come d'un sogno. Calisto, il vecchio guardiano, mi parlò di tante cose; e io non capii quasi nulla. Più volte mi ripeté un augurio: --Un maschio, un bel maschio, e Dio lo benedica! Un bel maschio! Quando noi fummo fuori, Calisto chiuse la casa. --E questi benedetti nidi?--egli disse scotendo la bella testa canuta. --Non li toccare, Calisto. Tutti i nidi erano abbandonati, vacui, esanimi. Le ultime ospiti erano partite. Un'occhiata di sole languida scendeva su la casa chiusa, su i nidi deserti. Nulla era più triste di quelle esili piume morte che qua e là, trattenute dalla creta, tremolavano. XXX. Il termine s'approssimava. La prima metà di ottobre era trascorsa. Il dottor Vebesti era stato avvertito. Da un giorno all'altro potevano sopraggiungere le doglie estreme. La mia ansietà cresceva di ora in ora, diveniva intollerabile. Spesso ero assalito da qualche impeto di follia simile a quello che un giorno mi aveva travolto su l'argine dell'Assoro. Fuggivo lontano dalla Badiola, restavo lunghe ore a cavallo, costringevo Orlando a saltare le siepi e i fossi, lo spingevo al galoppo per sentieri perigliosi. Tornavamo, io e il povero animale, grondanti, sfiniti, ma sempre incolumi. Il dottor Vebesti giunse. Tutti, alla Badiola, trassero un respiro, ripresero fiducia, sperarono bene. Giuliana soltanto non si rianimò. Più d'una volta io sorpresi nei suoi occhi il passaggio d'un pensiero sinistro, la cupa luce dell'idea fissa, l'orrore d'un presentimento lugubre. Le doglie del parto incominciarono; durarono per un giorno intero con qualche intervallo di riposo, ora più forti ora più deboli, ora sopportabili ora laceranti. Ella stava in piedi appoggiata a un tavolo, addossata a un armario, stringendo i denti per non gridare; o si sedeva su una poltrona e rimaneva là quasi immobile, col viso tra le mani, emettendo di tratto in tratto un gemito fioco: o mutava continuamente di luogo, andava da un angolo all'altro, si soffermava qua e là per stringere un qualunque oggetto tra le dita convulse. Lo spettacolo della sua sofferenza mi dilaniava. Non potendo più reggere, uscivo dalla stanza, mi allontanavo per qualche minuto; poi rientravo, quasi involontariamente, attirato; e restavo là a guardarla soffrire, senza poterla aiutare, senza poterle dire una parola di conforto. --Tullio, Tullio, che cosa orribile! Ah, che cosa orribile! Non ho mai sofferto tanto, mai, mai. Era verso sera. Mia madre, miss Edith, il dottore erano discesi nella sala da pranzo. Io e Giuliana eravamo rimasti soli. Non avevano ancora portato i lumi. Entrava il crepuscolo violaceo d'ottobre; il vento scoteva i vetri a quando a quando. --Aiutami, Tullio! Aiutami!--ella gridò, fuori di sé per lo spasimo, tendendo le braccia verso di me, guardandomi con gli occhi dilatati ove il bianco era straordinariamente bianco in quella penombra che rendeva livido il viso. --Dimmi tu! Dimmi tu! Come potrei fare per aiutarti?--balbettavo, smarrito, non sapendo che fare, accarezzandole i capelli su le tempie con un gesto in cui avrei voluto mettere un potere soprannaturale.--Dimmi tu! Dimmi tu! Che cosa? Ella non si lamentava più; mi guardava, mi ascoltava, come dimentica del suo dolore, quasi attonita, colpita forse dal suono della mia voce, dall'espressione del mio smarrimento e della mia angoscia, dal tremito delle mie dita su i suoi capelli, dalla desolata tenerezza di quel gesto inefficace. --Tu mi ami; è vero?--ella disse, non cessando di guardarmi come per non perdere nessun segno della mia commozione.--Tu mi perdoni tutto. Ella proruppe, esaltandosi di nuovo: --Bisogna che tu mi ami, bisogna che tu mi ami molto, ora, perché domani non ci sarò più, perché stanotte morirò, forse stasera morirò; e tu ti pentiresti di non avermi amata, di non avermi perdonata, oh certo ti pentiresti.... Ella pareva tanto sicura di morire che io rimasi agghiacciato dal terrore subitamente. --Bisogna che tu mi ami. Vedi: può essere che tu non abbia creduto a quel che ti dissi una notte, può essere che tu non mi creda ora; ma certo mi crederai quando non ci sarò più. Allora ti si farà la luce, allora conoscerai la verità; e ti pentirai di non avermi amata a bastanza, di non avermi perdonata.... Un nodo di pianto la soffocò. --Sai tu perché mi dispiace di morire? Perché muoio senza che tu sappia quanto t'ho amato.... quanto t'ho amato _dopo_, specialmente.... Ah che castigo! Meritavo questa fine? Ella si nascose la faccia tra le mani. Ma subito si scoperse. Mi fissò, pallidissima. Pareva che un'idea più terribile ancora l'avesse fulminata. --E se io morissi--balbettò--se io morissi _lasciando vivo...._ --Taci! --Tu intendi.... --Taci, Giuliana! Io ero più debole di lei. Il terrore m'aveva sopraffatto e non mi lasciava né pure la forza di proferire una parola consolante, di opporre a quelle imaginazioni di morte una parola di vita. Anch'io ero sicuro dell'atroce fine. Guardavo, nell'ombra violacea, Giuliana che mi guardava; e mi parve di scorgere in quel povero viso estenuato i segni dell'agonia, i segni d'un disfacimento già avanzato e inarrestabile. Ed ella non potè soffocare una specie di ululo che non aveva nulla di umano; e si aggrappò al mio braccio. --Aiutami, Tullio! Aiutami! Stringeva forte, assai forte, ma non a bastanza per me che avrei voluto sentirmi penetrare nel braccio le sue unghie, smanioso di uno spasimo fisico che mi accomunasse allo spasimo di lei. E, tenendo puntata la fronte contro il mio omero, metteva un mugolio continuo. Era quel suono che rende irriconoscibile la voce nostra nell'eccesso della sofferenza corporea, quel suono che agguaglia l'uomo che soffre al bruto che soffre: il lamento istintivo d'ogni carne addolorata, umana o bestiale. Ogni tanto ella ritrovava la sua voce per ripetere: --Aiutami! E mi comunicava le vibrazioni violente del suo strazio. E io sentivo il contatto del suo ventre ove il piccolo essere malefico si agitava contro la vita della madre, implacabile, senza darle tregua. Un'onda di odio mi sorse dalle radici più profonde, mi parve affluire alle mani tutta con un impulso micidiale. Era intempestivo l'impulso; ma la visione del delitto già consumato mi balenò dentro. "Tu non vivrai." --Oh, Tullio, Tullio, soffocami, fammi morire! Non posso, non posso, intendi?, non posso più reggere; non voglio più soffrire. Ella gridava esasperata, guardandosi intorno con occhi di pazza, come per cercare qualche cosa o qualcuno che le desse l'aiuto che io non potevo darle. --Càlmati, càlmati, Giuliana.... Forse è venuto il momento. Coraggio! Siediti qui. Coraggio, anima! Ancora un poco! Sono io qui, con te. Non aver paura. E corsi a suonare il campanello. --Il dottore! Che venga subito il dottore! Giuliana non si lamentava più. Ella pareva a un tratto aver cessato di soffrire o almeno d'accorgersi del suo male, colpita da un nuovo pensiero. Visibilmente, ella considerava qualche cosa dentro di sé; era assorta. Io ebbi appena il tempo di notare la mutazione istantanea. --Ascolta, Tullio. Se mi venisse il delirio.... --Che dici? --Se dopo, nella febbre, mi venisse il delirio e io morissi delirando.... --E bene? Ella aveva tale accento di terrore, le sue reticenze erano così affannose che io tremavo a verga a verga come preso dal pànico, non comprendendo ancora dove ella volesse giungere. --E bene? --Tutti saranno là, intorno a me.... Se nel delirio io parlassi, io _rivelassi_.... Intendi? Intendi? Una parola basterebbe. E nel delirio non si sa quel che si dice. Tu dovresti.... Mia madre, il dottore, la levatrice sopraggiunsero, in quel punto. --Ah dottore--sospirò Giuliana--credevo di morire. --Coraggio, coraggio!--fece il dottore, con la sua voce cordiale.--Senza paura. Tutto andrà bene. E mi guardò. --Credo--soggiunse sorridendo--che vostro marito stia peggio di voi. E mi accennò la porta. --Via, via. Non bisogna star qui. Incontrai gli occhi inquieti, sbigottiti e pietosi di mia madre. --Sì, Tullio; è meglio che tu vada--ella disse.--Federico t'aspetta. Guardai Giuliana. Senza curarsi degli altri, ella mi guardava fissamente, con gli occhi lucidi, pieni d'un bagliore straordinario. Era in quello sguardo tutta l'intensione dell'anima disperata. --Non mi moverò dalla stanza accanto--dichiarai con fermezza, seguitando a guardare Giuliana. Mentre uscivo, scorsi la levatrice che disponeva i guanciali sul letto del travaglio, sul letto di miseria; e rabbrividii, come a un soffio di morte. XXXI. Fu tra le quattro e le cinque del mattino. Le doglie s'erano protratte fino a quell'ora, con qualche intervallo di riposo. Verso le tre il sonno m'aveva colto, all'improvviso, sul divano dove stavo seduto, nella stanza contigua. Cristina mi svegliò; mi disse che Giuliana voleva vedermi. Nella confusione del risveglio, balzai in piedi ancora abbacinato dal sonno. --Ho dormito? Che accade mai? Giuliana.... --Non si spaventi. Non è accaduto nulla. I dolori si sono calmati. Venga a vedere. Entrai. Vidi subito Giuliana. Ella era adagiata su i guanciali, pallida come la sua camicia, quasi esanime. Incontrai subito i suoi occhi, perché erano volti alla porta in attesa di me. I suoi occhi mi sembrarono più larghi, più profondi, più cavi, cerchiati d'un maggior cerchio d'ombra. --Vedi--ella disse con una voce spirante--sto ancora così. E non cessò di guardarmi. I suoi occhi, come quelli della principessa Lisa, dicevano: "Aspettavo un aiuto da te, e tu non mi aiuti, né pur tu!" --Il dottore?--domandai a mia madre, ch'era là con un'aria abbattuta. Ella mi accennò una porta. Io mi diressi verso quella. Entrai. Vidi il dottore presso a un tavolo su cui erano varii medicinali, una busta nera, un termometro, fasce, compresse, fiaschi, alcuni tubi di forma speciale. Il dottore aveva tra le mani un tubo elastico a cui stava adattando un catetere; e dava istruzioni a Cristina, sotto voce. --Ma dunque?--io gli chiesi bruscamente. Che c'è? --Nulla di allarmante, per ora. --E tutti questi preparativi? --Precauzioni. --Ma quanto durerà ancora quest'agonia? --Siamo alla fine. --Parlatemi franco; vi prego. Prevedete una disgrazia? Parlatemi franco. --Non si annuncia per ora nessun pericolo grave. Temo però una emorragia; e prendo le mie precauzioni. L'arresterò. Abbiate fiducia in me e siate calmo. Ho notato che la vostra presenza agita molto Giuliana. In quest'ultimo breve periodo ella ha bisogno di tutte le forze che le rimangono. È necessario che voi vi allontaniate. Promettetemi d'obedirmi. Entrerete quando vi chiamerò. Ci giunse un grido. --Ricominciano i dolori--egli disse.--Ci siamo. Calma, dunque! E si diresse verso la porta. Io lo seguii. Ambedue ci avvicinammo a Giuliana. Ella m'afferrò il braccio e me lo strinse come in una morsa. Le restava dunque ancora quella forza? --Coraggio! Coraggio! Ci siamo. Tutto andrà bene. È vero, dottore?--balbettai. --Sì, sì. Non c'è tempo da perdere. Lasciate, Giuliana, che vostro marito esca di qui. Ella guardò il dottore e me, con gli occhi spalancati. Lasciò il mio braccio. --Coraggio!--ripetei soffocato. La baciai su la fronte molle di sudore, mi volsi per andarmene. --Ah, Tullio!--ella gridò dietro di me con un grido lacerante che significava: "Non ti vedrò più." Io feci l'atto di tornare a lei. --Via, via--ordinò il dottore, con un gesto imperioso. Volli obedire. Qualcuno serrò l'uscio dietro di me. Rimasi qualche minuto là, in piedi, ad ascoltare; ma le ginocchia mi vacillavano, ma il battito del cuore soverchiava qualunque altro strepito. Andai a gittarmi sul divano; mi misi il fazzoletto tra i denti, affondai la faccia in un cuscino. Soffrivo anch'io uno strazio fisico, simile forse a quello d'un'amputazione mal praticata e lentissima. Gli urli della partoriente mi giungevano a traverso l'uscio. E ad ognuno di quelli urli io pensavo: "Questo è l'ultimo." Negli intervalli udivo un mormorio di voci feminili: forse i conforti di mia madre, della levatrice. Un urlo più acuto e più inumano degli altri. "Questo è l'ultimo." E balzai in piedi esterrefatto. Non potevo dare un passo. Alcuni minuti trascorsero; trascorse un tempo incalcolabile. Come lampi velocissimi, m'attraversarono il cervello pensieri, imagini. "È nato? E se ella fosse morta? E se ambedue fossero morti? la madre e il figlio? No, no. Ella certamente è morta; ed egli è vivo. Ma perché nessun vagito? L'emorragia, il sangue...." Vidi il lago rosso, e, in mezzo, Giuliana boccheggiante. Vinsi il terrore che m'irrigidiva e mi slanciai contro l'uscio. L'apersi, entrai. Udii subito la voce del chirurgo che mi gridava aspra: --Non v'accostate! Non la scuotete! Volete ucciderla? Giuliana pareva morta, più pallida del suo guanciale, immobile. Mia madre stava china sopra di lei reggendo una compressa. Grandi macchie di sangue rosseggiavano sul letto, macchie di sangue tingevano il pavimento. Il chirurgo preparava un "irrigatore" con una sollecitudine calma ed esatta:--le sue mani non tremavano, se bene la sua fronte fosse corrugata. Un bacino d'acqua bollente fumigava in un angolo. Cristina aggiungeva acqua con una brocca in un altro bacino, tenendovi immerso il termometro. Un'altra donna portava nella stanza contigua un fascio d'ovatta. C'era nell'aria l'odore dell'ammoniaca e dell'aceto. Le minime particolarità della scena, abbracciata con un solo sguardo, mi rimasero impresse indelebilmente. --A 50 gradi--disse il dottore, volgendosi verso Cristina.--Attenta! Io cercavo intorno, non udendo il vagito. Qualcuno mancava là dentro. --E il bambino?--chiesi tremando. --È di là, nell'altra stanza. Andate a vederlo--mi rispose il dottore.--Rimanete là. Gli indicai Giuliana con un gesto disperato. --Non temete. Qua l'acqua, Cristina. Entrai nell'altra stanza. Mi giunse all'orecchio un vagito fievolissimo, a pena udibile. Vidi su uno strato d'ovatta un corpicciuolo rossastro, qua e là violaceo, sotto le mani scarne della levatrice, che lo stropicciavano nel dorso e nelle piante dei piedi. --Venga, venga, signore; venga a vedere--disse la levatrice continuando a stropicciare.--Venga a vedere che bel maschio. Non respirava; ma ora non c'è più pericolo. Guardi che maschio! Ella rivoltò il bambino, lo coricò sul dorso, mi mostrò il sesso. --Guardi! Afferrò il bambino e lo agitò nell'aria. I vagiti divennero un po' più forti. Ma io avevo negli occhi un scintillio strano che m'impediva di veder bene; avevo in tutto l'essere una ottusità strana che m'impediva la percezione esatta di tutte quelle cose reali e violente. --Guardi!--mi ripetè ancora la levatrice coricando di nuovo su l'ovatta il bambino che vagiva. Ora vagiva forte. Respirava, viveva! Mi chinai su quel corpicciuolo palpitante che odorava di licopodio; mi chinai a guardarlo, a esaminarlo, per riconoscere la somiglianza aborrita. Ma la piccola faccia turgida, ancora un po' livida, con i globi oculari sporgenti, con la bocca gonfia, col mento obliquo, difforme, quasi non aveva aspetto umano; e non m'ispirò se non ribrezzo. --A pena nato--balbettai--a pena nato, non respirava.... --No, signore. Un po' d'apoplessia.... --Come mai? --Aveva il cordone attorcigliato intorno al collo. E poi, forse il contatto del sangue nero.... Ella parlava attendendo alla cura del bambino; e io guardavo quelle mani scarne che lo avevano salvato e che ora avviluppavano delicatamente il cordone ombelicale in una pezzetta spalmata di burro. --Giulia, dammi la fascia. E, fasciando il ventre del bambino, soggiunse: --Questo oramai è assicurato. Dio lo benedica! E le sue mani esperte presero la testina molliccia come per plasmarla. Il bambino vagiva sempre più forte; vagiva con una specie di rabbia, agitandosi tutto, conservando quell'apparenza apoplettica, quel rossore paonazzo, quell'aspetto di cosa ributtante. Vagiva sempre più forte come per darmi una prova della sua vitalità, come per provocarmi, per esasperarmi. Viveva, viveva. E la madre? Rientrai nell'altra stanza, all'improvviso, demente. --Tullio! Era la voce di Giuliana, debole come quella d'un'agonizzante. XXXII. La corrente continua di acqua ad alta temperatura aveva arrestata l'emorragia, in circa dieci minuti. Ora la puerpera riposava nel suo letto, dentro l'alcova. Era giorno chiaro. Io stavo seduto al capezzale; e la consideravo in silenzio, dolorosamente. Ella non dormiva, forse. Ma l'estrema debolezza le toglieva ogni moto, ogni segno di vita; la faceva sembrare esanime. Considerando il suo funereo pallore di cera, io vedevo ancora quelle macchie di sangue, tutto quel povero sangue sparso che aveva inzuppato i lenzuoli, attraversato i materassi, arrossato le mani del chirurgo. "Chi le renderà tutto quel sangue?" Iniziavo un gesto istintivo per toccarla, poiché mi pareva che ella dovesse essere diventata fredda, di gelo. Ma mi tratteneva il timore di disturbarla. Più d'una volta, nella mia contemplazione continua, assalito da una paura repentina, feci l'atto di levarmi per andare a chiamare il dottore. Pensando, rivolgevo tra le dita un fiocco di bambagia, lo disfilavo minutamente; e, di tratto in tratto, per una inquietudine invincibile, lo avvicinavo con infinita cautela alle labbra di Giuliana e dal palpito dei fili leggeri misuravo la forza del respiro. Ella giaceva supina, con la testa su un guanciale basso. I capelli castagni un poco rilasciati le circondavano il volto, rendevano più tenui e più cerei i lineamenti. Aveva una camicia chiusa intorno al collo, chiusa intorno ai polsi; e le sue mani posavano sul lenzuolo, prone, così pallide che soltanto le vene azzurre le distinguevano dal lino. Una bontà soprannaturale emanava da quella povera creatura dissanguata e immobile; una bontà che mi penetrava tutto l'essere, mi colmava il cuore. Ed ella pareva ripetere: "Che hai tu fatto di me?" La sua bocca disfiorata, dalli angoli cadenti, rivelatrice d'una mortale stanchezza, e arida, che tanti spasimi avevano torta, che avevano sforzata tanti gridi, sempre pareva ripetere: "Che hai tu fatto di me?" Io consideravo l'esilità della persona che a pena formava rilievo sul piano del letto. Poiché l'evento s'era compiuto, poiché ella s'era al fine liberata dell'orribile peso, poiché alfine l'altra vita s'era distaccata dalla sua vita per sempre, quei moti istintivi di repulsione, quelle improvvise ombre di rancore non più sorgevano a turbare la mia tenerezza e la mia pietà. Ora non avevo per lei se non un sentimento di tenerezza immensa, d'immensa pietà, come per la più buona e per la più sventurata delle creature umane. Ora tutta la mia anima era sospesa a quelle povere labbra che da un momento all'altro avrebbero potuto rendere il respiro estremo. Con una sincerità profonda pensavo, guardando quel pallore: "Come sarei felice se potessi trasfondere la metà del mio sangue nelle sue vene!" Pensavo, udendo il battito lieve d'un orologio posato sul tavolo da notte, sentendo il tempo scorrere per quella fuga di minuti eguali: "Ma _egli_ vive." E la fuga del tempo mi dava un'ansietà singolare, assai diversa da quella altre volte provata, indefinibile. Pensavo: "_Egli_ vive, e la sua vita è tenace. A pena nato, non respirava. Aveva ancora sul corpo, quando io l'ho veduto, tutti i segni dell'asfissia. Se le cure della levatrice non l'avessero salvato, ora non sarebbe più se non un piccolo cadavere livido, una cosa innocua, trascurabile, forse dimenticabile. Io non d'altro dovrei occuparmi che della guarigione di Giuliana. Non mi moverei di qui, sarei il più assiduo e il più dolce degli infermieri, riuscirei a compiere la trasfusione vitale, a compiere il miracolo, per forza d'amore. Ella non potrebbe non guarire. Ella risorgerebbe a poco a poco, rigenerata, con un sangue nuovo. Parrebbe una creatura nuova, scevra d'ogni impurità. Ambedue ci sentiremmo purificati, degni l'uno dell'altra, dopo una espiazione così lunga e così dolorosa. La malattia, la convalescenza darebbero al triste ricordo una lontananza indefinita. E io vorrei cancellare dall'anima di lei perfino l'ombra del ricordo; vorrei darle il perfetto oblio, nell'amore. Qualunque altro amore umano parrebbe futile al confronto del nostro, dopo questa grande prova." Io m'esaltavo nella luce quasi mistica di quell'avvenire imaginato, mentre sotto il mio sguardo fisso il volto di Giuliana assumeva una specie d'immaterialità, un'espressione di bontà soprannaturale, quasi che ella fosse già distaccata dal mondo, quasi che con quel gran flutto di sangue ella avesse espulso quanto ancora eravi d'acre e d'impuro nella sua sostanza e si fosse ridotta a una mera essenza spirituale in conspetto della morte. La muta domanda non più mi feriva, non più mi sembrava terribile: "Che hai tu fatto di me?" Io rispondevo: "Non sei tu divenuta, per opera mia, _la sorella del Dolore_? Non è salita la tua anima, nella sofferenza, a un'altezza vertiginosa da cui ha potuto vedere il mondo in una luce insolita? Non hai tu avuta da me la rivelazione della verità suprema? Che valgono i nostri errori, le nostre cadute, le nostre colpe, se siamo giunti a strappare dai nostri occhi qualche velo, se siamo giunti a sprigionare quanto v'è di men basso nella nostra sostanza miserabile? A noi sarà dato il più alto gaudio a cui possano ambire su la terra gli eletti: rinascere conscientemente." Io m'esaltavo. L'alcova era silenziosa, l'ombra era misteriosa, il volto di Giuliana mi pareva trasumanato; e la mia contemplazione mi pareva solenne, poiché sentivo nell'aria la presenza della morte invisibile. Tutta la mia anima era sospesa a quelle pallide labbra che da un attimo all'altro avrebbero potuto rendere il respiro estremo. E quelle labbra si contrassero, misero un gemito. La contrattura dolorosa alterò le linee del volto, vi si fermò per qualche tempo. Le pieghe della fronte si approfondirono, la pelle delle palpebre ebbe un tremolio leggero, un po' del bianco apparve tra i cigli. Io mi chinai su la sofferente. Ella aprì gli occhi e li richiuse subito. Pareva ch'ella non mi avesse veduto. Gli occhi non avevano avuto sguardo, come colpiti da cecità. Era sopravvenuta forse l'amaurosi anemica? Era ella diventata cieca a un tratto? M'accorsi che entrava gente nella stanza: "Fosse il dottore!" Uscii dall'alcova. Vidi infatti il dottore, mia madre e la levatrice che entravano adagio. Li seguiva Cristina. --Riposa?--mi domandò il dottore sotto voce. --Si lagna. Chi sa quanto soffre ancora! --Ha parlato? --No. --Non bisogna in nessun modo eccitarla. Ricordatevene. --Ha aperto gli occhi, dianzi, per un momento. Pareva che non ci vedesse. Il dottore entrò nell'alcova, accennandoci di restare in dietro. Mia madre mi disse: --Vieni. Ora debbono rinnovare le medicature. Vieni via. Andiamo a vedere Mondino. C'è di là Federico. Ella mi prese una mano. Mi lasciai condurre. --S'è addormentato--soggiunse.--Dorme placidamente. Oggi, dopo mezzogiorno, arriverà la nutrice. Benché ella fosse triste e inquieta per lo stato di Giuliana, gli occhi le sorridevano mentre parlava del bambino; tutto il viso le s'illuminava di tenerezza. Per ordine del dottore era stata scelta una stanza lontana da quella della puerpera: una grande stanza ariosa che custodiva molte memorie della nostra infanzia. Entrando, vidi subito intorno alla culla Federico, Maria e Natalia, che insieme chini guardavano il piccolo dormente. Federico si volse e mi domandò, prima d'ogni altra cosa: --Come sta Giuliana? --Male. --Non riposa? --Soffre. Rispondevo quasi duramente, mio malgrado. Una specie d'aridità m'aveva d'un tratto occupata l'anima. Non altro provavo se non un'avversione indomabile e innascondibile contro l'intruso, e rammarico e impazienza per la tortura che le persone inconsapevoli m'infliggevano. Per quanto mi sforzassi, non riuscivo a dissimulare. Eravamo ora io, mia madre, Federico, Maria e Natalia, intorno alla culla, a guardare il sonno di Raimondo. Egli era stretto nelle fasce ed aveva la testa coperta d'una cuffia ornata di pizzi e di nastri. Il viso appariva meno gonfio ma ancora rossiccio, lucido su le gote come la cuticola delle piaghe cicatrizzate di recente. Un po' di bava gli usciva dalli angoli della bocca chiusa; le palpebre senza cigli, enfiate agli orli, coprivano i globi oculari sporgenti; una lividura segnava la radice del naso ancora deforme. --Ma a chi somiglia?--disse mia madre.--Non so ancora trovare una somiglianza.... --È troppo piccolo,--disse Federico.--Bisogna aspettare qualche giorno. Mia madre due o tre volte guardò me e il bambino, come per meglio confrontarne le fattezze. --No--disse.--Somiglia forse più a Giuliana. --Ora non somiglia a nessuno--interruppi. È orribile. Non vedi? --Orribile! È bellissimo! Guarda quanti capelli! Ed ella sollevò con le dita la cuffia, adagio adagio, e scoprì il cranio molliccio su cui stavano appiccicati pochi capelli bruni. --Lasciami toccare, nonna!--pregò Maria, stendendo la mano verso il capo del fratello. --No, no. Vuoi svegliarlo? Quel cranio pareva composto d'una cera un po' ammollita dal calore, untuosa, nerigna; e pareva che il minimo tocco vi avrebbe lasciata una traccia. Mia madre lo ricoprì. Poi si chinò a baciare la fronte, con infinita delicatezza. --Anch'io, nonna--pregò Maria. --Ma piano, per carità! La culla era troppo alta. --Tirami su!--disse Maria a Federico. Federico la sollevò nelle sue braccia; e io vidi la bella bocca rosea di mia figlia atteggiarsi al bacio prima di giungere a sfiorare quella fronte, e vidi i lunghi riccioli piovere su le fasce bianche. Anche Federico depose il suo bacio. Poi mi guardò. Non sorrisi. --E io? E io? Era Natalia, che s'attaccava alla sponda della culla. --Piano, per carità! Federico sollevò anche lei. E di nuovo io vidi i lunghi riccioli piovere su le fasce bianche, in quell'ultima dolce reclinazione. Stavo là quasi irrigidito: e il mio sguardo doveva certo esprimere il sentimento cupo che mi possedeva. Quei baci di labbra a me tanto care non avevano tolto all'intruso quell'aspetto di cosa ributtante ma me l'avevano anzi reso più odioso. Io sentivo che mi sarebbe stato impossibile toccare quella carne estranea, piegarmi a un qualunque atto apparente di amore paterno. Mia madre mi guardava, inquieta. --Tu non lo baci?--mi domandò. --No, mamma, no. Ha fatto troppo male a Giuliana. Non so perdonargli.... E mi ritrassi, con un moto istintivo, con un moto di manifesta ripugnanza. Mia madre restò un momento attonita, senza parola. --Ma che dici, Tullio? Che colpa ne ha questo povero bambino? Sii giusto! Mia madre aveva certo notata la sincerità della mia avversione. Non riuscivo a dominarmi. Tutti i miei nervi si ribellavano. --Non posso ora, non posso.... Lasciami stare, mamma. Mi passerà. La mia voce era aspra e risoluta. Io ero tutto convulso. Un nodo mi serrava la gola, i muscoli della faccia mi si contraevano. Dopo tante ore d'orgasmo violento, tutto il mio essere aveva bisogno di una distensione. Credo che un grande scoppio di pianto mi avrebbe giovato: ma il nodo era durissimo. --Mi fai molta pena, Tullio,--disse mia madre. --Vuoi che lo baci?--ruppi io, fuori di me. E m'accostai alla culla, mi chinai sul bambino, lo baciai. Il bambino si svegliò; si mise a vagire, da prima fioco, poi con una specie di furore crescente. Vidi che la pelle del volto gli diveniva più rossa e gli si raggrinzava nello sforzo, mentre la lingua bianchiccia gli tremolava nella bocca dilatata. Benché fossi al colmo della disperazione, m'accorsi dell'errore commesso. Sentii gli sguardi di Federico, di Maria, di Natalia fissi sopra di me, intollerabili. --Perdonami, mamma--balbettai.--Non so più quel che faccio. Sono irragionevole. Perdonami. Ella aveva tolto dalla culla il bambino e lo reggeva su le braccia, senza poterlo quietare. I vagiti mi ferivano acutamente, mi laceravano. --Andiamo, Federico. Uscii in fretta. Federico mi seguì. --Giuliana sta molto male. Non comprendo come si possa pensare ad altri che a lei, in questi momenti--dissi, come per giustificarmi.--Tu non l'hai veduta. Sembra che muoia. XXXIII. Per alcuni giorni Giuliana vacillò tra la vita e la morte. La sua debolezza era tale che qualunque più lieve sforzo era seguito da un deliquio. Ella doveva mantenersi costantemente supina, in una immobilità perfetta. Qualunque tentativo di sollevarsi provocava segni di anemia cerebrale. Nulla valeva a vincere le nausee da cui ella era assalita, a toglierle di sul petto l'incubo, ad allontanare il rombo che ella udiva di continuo. Io rimasi giorno e notte al suo capezzale, sempre vigile, tenuto in piedi da una energia instancabile di cui ero meravigliato io stesso. Con tutte le potenze della mia vita io sostenni quella vita che stava per spengersi. Mi pareva che dall'altra parte del capezzale fosse la Morte in agguato pronta a cogliere l'attimo opportuno per strappare la preda. Io aveva talora veramente la sensazione di trasfondermi nel corpo fragile dell'inferma, di comunicarle un po' della mia forza, di dare un impulso al suo cuore stanco. Le miserie della malattia non m'ispirarono mai alcuna ripugnanza, mai alcun disgusto. Nessuna materialità offese mai la delicatezza dei miei sensi. I miei sensi acutissimi non ad altro erano intenti che a percepire le più piccole mutazioni nello stato dell'inferma. Prima ch'ella proferisse una parola, prima ch'ella facesse un cenno, io indovinavo il suo desiderio, il suo bisogno, il grado della sua sofferenza. Per divinazione, fuori d'ogni suggerimento del medico, ero giunto a trovare modi nuovi e ingegnosi di alleviarle un dolore, di calmarle uno spasimo. Io solo sapevo persuaderla al cibo, persuaderla al sonno. Ricorrevo a tutte le arti della preghiera e della blandizia per farle inghiottire qualche sorso di cordiale. L'assediavo così ch'ella, non potendo più rifiutarsi, doveva risolversi allo sforzo salutare, vincere la nausea. E nulla era per me più dolce del sorriso tenuissimo con cui ella si piegava alla mia volontà. Ogni suo più piccolo atto d'obedienza mi dava al cuore una commozione profonda. Quando ella diceva con quella voce tanto debole:--Va bene così? Sono buona?--la gola mi si chiudeva, gli occhi mi si velavano. Spesso ella si lamentava d'un dolore pulsatile alle tempie, che non le dava tregua. Io le passavo lungo le tempie l'estremità delle mie dita, per magnetizzare il suo dolore. Le accarezzavo piano piano i capelli, per addormentarla. Quando m'accorgevo che ella dormiva, dal suo respiro, io avevo una sensazione illusoria di ristoro quasi che il beneficio del sonno si spandesse anche su me. D'innanzi a quel sonno io diventavo religioso, ero invaso da un fervore indefinito, provavo il bisogno di credere in un qualche Essere superiore, onniveggente, onnipotente, a cui rivolgevo i miei voti. Salivano spontanei dall'intimo della mia anima preludii di orazioni, nella forma cristiana. Talvolta l'eloquenza interiore m'esaltava fino alle sommità della vera Fede. Si risvegliavano in me tutte le tendenze mistiche trasmessemi da un lungo ordine di progenitori cattolici. Mentre si svolgeva la mia orazione interna, io contemplavo la dormente. Ella era pur sempre pallida come la sua camicia. Per la trasparenza della pelle, io avrei potuto numerar le sue vene su le guance, sul mento, sul collo. La contemplavo quasi sperando di cogliere gli effetti benefici del riposo, il diffondersi lento del sangue nuovo generato dal cibo, i primi segni iniziali della guarigione. Avrei voluto per una facoltà soprannaturale assistere al misterioso lavorio riparatore che si compieva in quel corpo affranto. E speravo sempre: "Quando si sveglierà, si sentirà più forte." Pareva ch'ella provasse un gran sollievo quando teneva fra le sue mani fredde la mia mano. Talvolta ella me la prendeva e la metteva sul guanciale e sopra ci posava la gota, con un atto infantile; e, così rimanendo, a poco a poco si assopiva. Ero capace di conservare a lungo a lungo l'immobilità del braccio intormentito, per non risvegliarla. Talvolta ella diceva: --Perché non dormi anche tu qui, con me? Tu non dormi mai! E voleva che io posassi la testa sul suo guanciale. --Dormiamo dunque. Io fingevo di addormentarmi, per darle il buon esempio. Quando riaprivo gli occhi, incontravo i suoi occhi sbarrati che mi guardavano. --E bene?--esclamavo.--Che fai? --E tu?--rispondeva ella. Nei suoi occhi era un'espressione di tenerezza così buona che io mi sentivo struggere dentro. Tendevo le labbra e la baciavo su le palpebre. Ella voleva fare la stessa cosa a me. Poi ripeteva: --Ora dormiamo. E scendeva un velo d'oblio su la nostra sventura, talvolta. Spesso i suoi poveri piedi erano gelati. Io li toccavo, di sotto alle coperte, e mi parevano di marmo. Ella diceva in fatti: --Sono morti. Erano scarni, sottili, così minuti che quasi mi entravano nel pugno. Avevo per loro una grande pietà. Io stesso riscaldavo per loro sul braciere il panno di lana, non mi stancavo di prenderne cura. Avrei voluto intiepidirli con l'alito, coprirli di baci. Si mescolavano alla mia nuova pietà ricordi lontani d'amore, ricordi del tempo felice quando io non tralasciavo mai di calzarli al mattino e di nudarli a sera con le mie proprie mani per una consuetudine quasi votiva, stando in ginocchio. Un giorno, dopo lunghe veglie, ero così stanco che un sonno irresistibile mi colse a punto mentre tenevo le mani sotto le coperte e avvolgevo nel panno caldo i piccoli piedi morti. Reclinai la testa, e restai là addormentato nell'atto. Come mi svegliai, vidi nell'alcova mia madre, mio fratello, il dottore, che mi guardavano sorridendo. Rimasi confuso. --Povero figliuolo! Non ne puoi più--disse mia madre ravviandomi i capelli con uno dei suoi gesti più affettuosi. E Giuliana: --Mamma, portalo via tu. Federico, portalo via. --No, no, non sono stanco--io ripetevo.--Non sono stanco. Il dottore annunziò la sua partenza. Dichiarò la puerpera fuor di pericolo, in via di miglioramento accertato.--Bisognava seguitare a promuovere con tutti i mezzi la rigenerazione del sangue. Il suo collega Jemma di Tussi, col quale aveva conferito e s'era trovato d'accordo, avrebbe seguitata la cura, che, del resto, era semplicissima. Più che nei medicinali egli aveva fiducia nell'osservanza rigorosa delle diverse norme igieniche e dietetiche da lui stabilite. --In verità--soggiunse accennando a me--non potrei desiderare un infermiere più intelligente, più vigile, più devoto. Ha fatto miracoli e ne farà ancora. Io parto tranquillo. Mi sembrò che il cuore mi balzasse alla gola e mi soffocasse. L'elogio inaspettato di quell'uomo severo, alla presenza di mia madre, di mio fratello, mi diede una commozione profonda; fu un compenso straordinario. Guardai Giuliana e vidi che i suoi occhi s'erano empiti di lacrime. E, sotto il mio sguardo, all'improvviso ella ruppe in un pianto. Feci uno sforzo sovrumano per frenarmi, ma non riuscii. Mi parve che l'anima mi si stemprasse. Tutte le bontà del mondo erano nel mio petto, raccolte, in quell'ora indimenticabile. XXXIV. Giuliana andava ricuperando le forze di giorno in giorno, con lentezza. La mia assiduità non veniva meno. Delle dichiarazioni fatte dal dottor Vebesti io anzi mi valevo per moltiplicare le mie vigilanze, per non lasciare che altri prendesse le mie veci, per resistere a mia madre e a mio fratello che mi consigliavano il riposo. Il mio corpo s'era oramai abituato alla dura disciplina e non si stancava quasi più. Tutta la mia vita era tra le pareti di quella stanza, nell'intimità di quell'alcova, nel cerchio in cui respirava la cara malata. Avendo ella bisogno d'una calma assoluta, dovendo ella parlar poco per non stancarsi, io m'adoperavo ad allontanar dal suo letto anche le persone familiari. Quell'alcova dunque rimaneva segregata dal resto della casa. Per ore ed ore io e Giuliana rimanemmo soli. E poiché ella era tenuta dal male ed io ero intento al mio ufficio pietoso, talvolta ci avveniva di dimenticare la nostra sventura, di smarrire la nozione della realtà e di non serbare altra conscienza che quella del nostro immenso amore. Mi pareva talvolta che nulla più esistesse di là dalle cortine, tanta era l'intensione di tutto il mio essere verso la sofferente. Nulla veniva a ricordarmi la cosa tremenda. Io vedevo d'innanzi a me una sorella che soffriva e non avevo altra sollecitudine che di alleggerire la sua pena. Non di rado questi veli d'oblio furono lacerati con violenza. Mia madre parlò di Raimondo. Le cortine si aprirono per lasciar passare l'intruso. Lo portò mia madre sulle braccia. Ed io ero là. Sentii d'esser divenuto pallido, perché tutto il sangue m'affluì al cuore. Che provò Giuliana? Io guardavo quel viso rossiccio, grosso come il pugno di un uomo, mezzo nascosto dalla cuffia trapunta; e con un'avversione feroce, che annullava nella mia anima qualunque altro sentimento, pensai: "Come farò a liberarmi di te? Perché non moristi soffocato?" Il mio odio non aveva ritegno; era istintivo, cieco, indomabile, quasi direi carnale; pareva in fatti che avesse la sua sede nella mia carne, che sorgesse da tutte le mie fibre, da tutti i miei nervi, da tutte le mie vene. Nulla poteva reprimerlo, nulla poteva distruggerlo. Bastava la presenza dell'intruso, in qualunque ora, in qualunque congiuntura, perché dentro di me avvenisse una specie d'annullazione istantanea ed io fossi posseduto da un solo unico sentimento: dall'odio contro di lui. Disse mia madre a Giuliana: --Guarda, in pochi giorni, come è già mutato! Somiglia più a te che a Tullio; ma non molto a nessuno dei due. È ancora troppo piccolo. Vedremo in seguito.... Gli vuoi dare un bacio? Ella accostò la fronte del bambino alle labbra dell'inferma. Che provò Giuliana? Ma il bambino cominciò a piangere. Io ebbi la forza di dire a mia madre, senza acredine: --Portalo via; ti prego. Giuliana ha bisogno di calma. Queste scosse le fanno molto male. Mia madre uscì dall'alcova. I vagiti crescevano e mi davano pur sempre la stessa sensazione di laceramento doloroso e la voglia di correre a soffocarli per non udirli più. Li udimmo per qualche istante mentre si allontanavano. Quando al fine cessarono, il silenzio mi parve enorme; mi cadde sopra come un macigno, mi oppresse. Ma non m'indugiai in quella pena, perché subito pensai che Giuliana aveva bisogno di soccorso. --Ah, Tullio, Tullio, non è possibile.... --Taci, taci, se tu mi ami, Giuliana. Taci; ti prego. Io la supplicavo, con la voce, col gesto. Tutto il mio orgasmo ostile era caduto; e io non d'altro mi dolevo se non del dolore di lei, non altro temevo se non il danno recato all'inferma, l'urto ricevuto da quella vita così fragile. --Se tu mi ami, non devi pensare a null'altro che a guarire. Vedi? Io non penso che a te, non soffro che per te. Bisogna che tu non ti tormenti; bisogna che tu ti abbandoni tutta alla mia tenerezza, per guarire.... Ella disse con la sua voce tremante e fievole: --Ma chi sa quel che tu provi dentro! Povera anima! --No, no, Giuliana, non ti tormentare! Io non soffro che per te, nel vederti soffrire. Io dimentico tutto, se tu sorridi. Se tu ti senti bene, io sono felice. Se tu mi ami, dunque devi guarire, devi essere calma, ubbidiente, paziente. Quando sarai guarita, quando sarai più forte allora.... _chi sa_! Dio è buono. Ella mormorò: --Dio, abbi misericordia di noi. "In che modo?" Io pensai. "Facendo morire l'intruso." Ambedue alzavamo dunque un augurio di morte, anch'ella dunque non vedeva altro scampo che nella distruzione del figliuolo. Non v'era altro scampo. E mi tornò alla memoria il breve dialogo che avevamo avuto in un tramonto lontano, sotto gli olmi; e mi tornò alla memoria la confessione dolorosa. "Ma ora ch'egli è nato, l'aborre ella ancora? Può ella provare un'avversione sincera contro la carne della sua carne? Prega ella sinceramente Iddio perché si riprenda la sua creatura?" E mi tornò la folle speranza che mi era balenata in quella sera tragica: "Se entrasse in lei la suggestione del delitto e divenisse a poco a poco tanto forte da trascinarla!..." Non avevo io pensato per un attimo a un mal riuscito tentativo delittuoso, vedendo la levatrice stropicciare sul dorso e su le piante dei piedi il corpicciuolo paonazzo del bimbo tramortito? Era stato, anche quello, un pensiero folle. Certo Giuliana non avrebbe mai osato.... E io guardai le sue mani lungo il lenzuolo, prone, così pallide che soltanto le vene azzurre le distinguevano dal lino. XXXV. Uno strano rammarico mi pungeva, ora che l'inferma andava di giorno in giorno migliorando. Mi si moveva in fondo al cuore un vago rimpianto verso i tristi giorni grigi passati dentro l'alcova, mentre giungeva cupa dalle campagne autunnali la monotonia della pioggia. Quelle mattine, quelle sere, quelle notti, benché penose, avevano una loro grave dolcezza. La mia opera di carità mi pareva ogni giorno più bella. Un'abondanza d'amore m'inondava l'anima e sommergeva talvolta i pensieri oscuri, mi dava talvolta l'oblio della cosa tremenda, mi suscitava qualche illusione consolante, qualche sogno indefinito. Provavo io talvolta là dentro un sentimento simile a quello che si prova nell'ombra delle cappelle segrete: mi sentivo in un rifugio contro le violenze della vita, contro le occasioni del peccato. Mi pareva talvolta che le cortine leggère mi separassero da un abisso. M'assalivano repentine paure dell'ignoto. Ascoltavo nella notte il silenzio di tutta la casa intorno a me; e vedevo, con gli occhi dell'anima, in fondo a una stanza remota, al lume d'una lampada, la culla ove dormiva l'intruso, il diletto di mia madre, il mio erede. Mi scoteva un gran brivido di orrore; e rimanevo a lungo sbigottito sotto il balenìo sinistro d'un solo pensiero. Le cortine mi separavano da un abisso. Ma ora che Giuliana di giorno in giorno andava migliorando, venivano a mancare le ragioni dell'isolamento; e a poco a poco la comune vita domestica invadeva la stanza tranquilla. Mia madre, mio fratello, Maria, Natalia, miss Edith entravano assai più spesso, si trattenevano assai più a lungo. Raimondo s'imponeva alla tenerezza materna. Non era più possibile né a me né a Giuliana evitarlo. Bisognava prodigargli i baci, sorridergli. Bisognava simulare e dissimulare con arte, patire tutte le più raffinate crudeltà del caso, lentamente perire. Nutrito d'un latte sano e sostanziale, circondato d'infinite cure, Raimondo perdeva a poco a poco quel suo aspetto di cosa ributtante, incominciava a ingrossarsi, a sbiancarsi, a prendere forme più chiare, a tenére bene aperti i suoi occhi grigi. Ma tutti i suoi moti m'erano odiosi, dall'atto delle labbra intorno il capezzolo all'agitazione confusa delle piccole mani. Mai gli riconobbi una grazia, un vezzo; mai ebbi per lui un pensiero che non fosse ostile. Quando ero costretto a toccarlo, quando mia madre me lo porgeva perché io lo baciassi, provavo per tutta la pelle lo stesso raccapriccio che m'avrebbe dato il contatto d'un animale immondo. Tutte lo fibre si ribellavano; e i miei sforzi erano disperati. Ogni giorno mi recava un supplizio nuovo; e mia madre era il gran carnefice. Una volta, rientrando nella stanza all'improvviso e discostando le cortine dell'alcova, scorsi sul letto il bambino posato a fianco di Giuliana. Non c'era nessuno presente. Eravamo là riuniti noi tre soli. Il bambino, stretto nelle fasce bianche, dormiva tranquillo. --L'ha lasciato qui la mamma--balbettò Giuliana. Io fuggii come un pazzo. Un'altra volta Cristina venne a chiamarmi. La seguii nella camera della culla. Mia madre stava là seduta tenendo su le ginocchia il bambino ignudo. --Te l'ho voluto far vedere prima d'infasciarlo--ella mi disse.--Guarda! Il bambino sentendosi libero agitava le gambe e le braccia, stravolgeva in qua e in là gli occhi, si ficcava le dita nella bocca sbavazzando. Ai polsi, ai malleoli, dietro le ginocchia, su gli inguini la carne si arrotondava in anelli, velata di cipria; sul ventre gonfio l'ombelico era ancora sporgente, deforme, bianco di cipria. Le mani di mia madre palpavano con delizia le minute membra, mi mostravano a una a una tutte le particolarità, s'indugiavano su quella pelle nitida e liscia pel bagno recente. E pareva che il bambino ne godesse. --Senti, senti com'è già sodo!--diceva ella, invitandomi a palparlo. E bisognò ch'io lo toccassi. --Senti come pesa! E bisognò che io lo sollevassi, che io sentissi palpitare quel corpicciuolo tiepido e morbido tra le mie mani invase da un tremito che non era di tenerezza. --Guarda! E mia madre sorridendo strinse tra l'indice e il pollice le papille su quel petto delicato che chiudeva la vita tenace degli esseri malefici. --Amore, amore, amore della nonna!--ella ripeteva, vellicando con un dito il mento del bambino che non sapeva ridere. La cara testa grigia, che s'era già reclinata col medesimo atto su due culle benedette, ora un poco più canuta si reclinava inconsapevole sul figliuolo d'un altro, su un intruso. Mi pareva che ella non si fosse mostrata così tenera verso Maria, verso Natalia, verso le vere creature del mio sangue. Ella stessa volle fasciarlo. Gli fece sul ventre il segno della croce. --Non sei ancora cristiano! E volgendosi a me: --Bisogna che fissiamo oramai il giorno del battesimo. XXXVI. Il dottor Jemma, cavaliere del Sacro Sepolcro di Gerusalemme, un bel vecchio gioviale, portò a Giuliana in dono matutino un mazzo di crisantemi bianchi. --Oh, i fiori che io prediligo!--disse Giuliana.--Grazie. Prese il mazzo, lo guardò a lungo insinuandovi le dita affilate: e una triste rispondenza correva tra il suo pallore e il pallore dei fiori autunnali. Erano crisantemi ampii come rose aperte, folti, grevi; avevano il colore delle carni malaticce, esangui, quasi disfatte, la bianchezza livida che copre le guance delle piccole mendicanti intirizzite dal gelo. Alcuni portavano lievissime venature violacee, altri pendevano un poco nel giallo, delicatamente. --Tieni--ella mi disse.--Mettili nell'acqua. Era di mattina; era di novembre; era di poco trascorso l'anniversario d'un giorno nefasto che quei fiori rammemoravano. _Che farò senza Euridice?..._ Mi sonò nella memoria l'aria di Orfeo, mentre mettevo in un vaso i crisantemi bianchi. Si risollevarono nel mio spirito alcuni frammenti della scena singolare accaduta un anno innanzi; e rividi Giuliana in quella luce dorata e tepida, in quel profumo così molle, in mezzo a tutti quelli oggetti improntati di grazia feminile, dove il fantasma della melodia antica pareva mettere il palpito d'una vita segreta, spandere l'ombra d'un non so che mistero.--Avevano suscitato anche in lei qualche ricordo quei fiori? Una mortale tristezza mi pesava su l'anima, una tristezza d'amante inconsolabile. L'Altro ricomparve. I suoi occhi erano grigi come quelli dell'intruso. Il dottore mi disse, dall'alcova: --Potete aprire la finestra. È bene che la stanza sia molto aerata, che entri molto sole. --Oh sì, sì, apri!--esclamò l'inferma. Apersi. In quel punto entrò mia madre con la nutrice che portava su le braccia Raimondo. Io restai fra le tende, mi chinai sul davanzale, guardai la campagna. Udivo dietro di me le voci familiari. Era sul finire di novembre, era già passata anche l'estate dei morti. Una grande chiarità vacua si spandeva su la campagna umida, sul lineamento nobile e pacato dei colli. Sembrava che per le cime degli oliveti indistinte vagasse un vapore argenteo. Qualche filo di fumo qua e là biancicava al sole. Ora sì ora no il vento portava un crepito di foglie labili. Il resto era silenzio e pace. Io pensavo: "Perché ella cantava, quella mattina? Perché udendola provai quel turbamento, quell'ansietà? Ella mi pareva _un'altra donna_. Amava ella dunque colui? A quale stato del suo animo rispondeva quell'effusione insolita? Ella cantava, perché amava. Forse anche m'inganno. Ma non saprò mai il vero!" Non era più la torbida gelosia dei sensi ma un rammarico più alto, che mi si partiva dal centro dell'anima. Pensavo: "Quale ricordo ha ella di colui? Quante volte il ricordo l'ha punta? Il figlio è un legame vivente. Ella ritrova in Raimondo qualche cosa dell'uomo che l'ha posseduta: ella ritroverà somiglianze più certe. Non è possibile ch'ella dimentichi il padre di Raimondo. Forse ella lo ha sempre d'avanti agli occhi. Che proverebbe se lo sapesse condannato?" E m'indugiai nell'imaginare i progressi della paralisi, nel formare dentro di me imagini di colui a similitudine di quelle che mi dava il ricordo del povero Spinelli. E me lo rappresentavo seduto su una gran poltrona di cuoio rosso, pallido d'un pallor terreo, con tutti i lineamenti della faccia irrigiditi, con la bocca dilatata e aperta, piena di saliva e d'un balbettio incomprensibile. E lo vedevo fare ad ogni tratto sempre il medesimo gesto per raccogliere in un fazzoletto quella saliva continua che gli colava dagli angoli della bocca.... --Tullio! Era la voce di mia madre. Mi volsi, andai verso l'alcova. Giuliana stava supina, molto abbattuta, silenziosa. Il dottore esaminava sul capo del bambino un principio di crosta lattea. --Faremo dunque il battesimo dopo domani--disse mia madre.--Il dottore crede che Giuliana dovrà rimanere ancora qualche tempo a letto. --Come la trovate, dottore?--domandai al vecchio, accennando l'inferma. --Mi pare che ci sia un po' di sosta nel miglioramento--rispose, scotendo la bella testa canuta.--La trovo debole, molto debole. Bisogna accrescere la nutrizione, fare qualche sforzo.... Giuliana interruppe, guardandomi con un sorriso stanchissimo: --M'ha ascoltato il cuore. --E bene?--io chiesi, volgendomi subito al vecchio. Mi parve di vedergli passare su la fronte un'ombra. --È un cuore sanissimo--rispose subito.--Non ha bisogno che di sangue.... e di tranquillità. Su, su, animo! Come va l'appetito stamani? L'anemica mosse le labbra a un atto quasi di disgusto. Fissava la finestra aperta quel lembo di cielo delicato. --È una giornata fredda, oggi?--domandò con una specie di timidezza, ritraendo le mani sotto le coperte. E rabbrividì visibilmente. XXXVII. Il giorno dopo, io e Federico andammo a visitare Giovanni di Scòrdio, Era l'ultimo pomeriggio di novembre. Andammo a piedi, a traverso i campi arati. Camminavamo in silenzio, pensosi. Il sole inclinava all'orizzonte, lento. Una polvere d'oro impalpabile fluttuava nell'aria quieta sul nostro capo. La terra umida aveva un color bruno vivace, un aspetto di possanza tranquilla, quasi direi una pacata consapevolezza della sua virtù. Dalle glebe saliva un fiato visibile, simile a quello spirante dalle narici dei buoi. Le cose bianche in quella luce mite assumevano una straordinaria bianchezza, una candidezza di neve. Una vacca di lontano, la camicia d'un agricoltore, un telo spaso, le mura d'una cascina risplendevano come in un plenilunio. --Sei triste--mi disse Federico dolcemente. --Sì, amico mio: molto triste. Dispero. Seguì ancora un lungo silenzio. Dalle fratte stormi d'uccelli si levavano frullando. Giungeva fioco lo scampanìo d'una mandra lontana. --Di che disperi?--mi chiese mio fratello, con la stessa benignità. --Della salvezza di Giuliana, della mia salvezza. Egli tacque; non proferì nessuna parola di consolazione. Forse il dolore lo stringeva, dentro. --Ho un presentimento--soggiunsi.--Giuliana non si leverà. Egli tacque. Passavamo per un sentiero alberato; e le foglie cadute stridevano sotto i nostri piedi; e, dove le foglie non erano, il suolo risonava come per cavità sotterranee, cupo. --Quando ella sarà morta--soggiunsi--io che farò? Uno sgomento repentino m'assalse, una specie di pànico; e guardai mio fratello che taceva accigliato, mi guardai d'in torno per la muta desolazione di quell'ora diurna; e mai come in quell'ora sentii il vuoto spaventevole della vita. --No, no, Tullio--disse mio fratello--Giuliana _non può morire_. Egli affermava una cosa vana, senza valore alcuno d'innanzi alla condanna del Destino. E pure egli aveva pronunziato quelle parole con una semplicità che mi scosse, tanto mi parve straordinaria. Così talvolta i fanciulli pronunziano a un tratto parole inaspettate e gravi che ci colpiscono nel mezzo dell'anima; e pare che una voce fatidica parli per le loro labbra inconsapevoli. --Leggi nel futuro?--gli domandai, senz'ombra d'ironia. --No. Ma questo è il mio presentimento; e io ci credo. Ancora una volta mi venne dal buon fratello un lampo di confidenza; ancora una volta per lui s'allargò un poco il duro cerchio che mi serrava il cuore. Il respiro fu breve. Nel resto del cammino egli mi parlò di Raimondo. Come giungemmo in vicinanza del luogo ove abitava Giovanni di Scòrdio, egli scorse nel campo la figura alta del vecchio. --Guarda! È là. Va seminando. Gli portiamo l'invito in un'ora solenne. Ci appressammo. Io tremavo forte, dentro di me, come se mi accingessi a una profanazione. Andavo in fatti a profanare una bella e grande cosa; andavo a chiedere la paternità spirituale di quel vecchio venerabile per un figliuolo adulterino. --Guarda che figura!--esclamò Federico soffermandosi e indicando il seminatore.--Ha l'altezza d'un uomo, e pure sembra un gigante. Ci soffermammo dietro un albero, sul limite del campo a guardare. Intento all'opera, Giovanni non ci aveva ancora veduti. Egli avanzava pel campo dirittamente, con una lentezza misurata. Gli copriva il capo una berretta di lana verde e nera con due ali che scendevano lungo gli orecchi all'antica foggia frigia. Un sàccolo bianco gli pendeva dal collo per una striscia di cuoio, scendendogli davanti alla cintura pieno di grano. Con la manca egli teneva aperto il sàccolo, con la destra prendeva la semenza e la spargeva. Il suo gesto era largo, gagliardo e sapiente, moderato da un ritmo eguale. Il grano involandosi dal pugno brillava talvolta nell'aria come faville d'oro, e cadeva su le porche umide egualmente ripartito. Il seminatore avanzava con lentezza, affondando i piedi nudi nella terra cedevole, levando il capo nella santità della luce. Il suo gesto era largo, gagliardo e sapiente; tutta la sua persona era semplice, sacra e grandiosa. Entrammo nel campo. --Salute, Giovanni!--esclamò Federico, andando incontro al vecchio.--Sia benedetta la tua semenza. Sia benedetto il tuo pane futuro. --Salute!--io ripetei. Il vecchio tralasciò l'opera; si scoperse il capo. --Copriti, Giovanni, se non vuoi che ci scopriamo--disse Federico. Il vecchio si coprì, confuso, quasi timido, sorridendo. Domandò, umile: --Perché tanto onore? Io dissi, con una voce che mi sforzai di rendere ferma: --Sono venuto a pregarti di tenere a battesimo il mio figliuolo. Il vecchio mi guardò attonito, poi guardò mio fratello. La sua confusione crebbe. Egli mormorò: --A me tanto onore! --Che mi rispondi? --Sono il tuo servo. Dio ti renda merito dell'onore che vuoi farmi oggi e Dio sia lodato per questa gioia che dà alla mia vecchiaia. Tutte le benedizioni del cielo scendano sul tuo figliuolo! --Grazie, Giovanni. E gli stesi la mano. E vidi che quei tristi occhi profondi s'inumidirono di tenerezza. Il cuore mi si gonfiò d'un'angoscia smisurata. Il vecchio mi domandò: --Come lo chiami? --Raimondo. --Come tuo padre, di felice memoria. Quello era un uomo! E voi gli somigliate. Disse mio fratello: --Sei solo a seminare il grano. --Solo. Io lo getto e io lo ricopro. E indicò l'erpice e il bidente che rilucevano su la terra bruna. D'in torno si vedevano i semi non anche ricoperti, i buoni germi delle spiche future. Disse mio fratello: --Continua dunque. Ti lasciamo alla tua opera. Tu verrai domattina alla Badiola. Addio, Giovanni. Sia benedetta la tua semenza. Ambedue stringemmo quelle mani infaticabili, santificate dalla semenza che spargevano, dal bene che avevano sparso. Il vecchio fece l'atto d'accompagnarci verso la callaia. Ma si soffermò, esitante. Disse: --Vi chiedo una grazia --Parla, Giovanni. Egli aprì il sacco che gli pendeva dal collo. --Prendete un pugno di grano e gettatelo nel mio campo. Io pel primo affondai la mano nel frumento, ne presi quanto potei, lo sparsi. Mio fratello m'imitò. --Questo ora vi dico--soggiunse Giovanni di Scòrdio, con la voce commossa, guardando la terra seminata.--Dio voglia che il mio figlioccio sia buono come il pane che nascerà da questa semenza. Così sia. XXXVIII. La mattina dopo, la cerimonia del battesimo si compi senza festa, senza pompa, per riguardo allo stato di Giuliana. Il bambino fu portato nella cappella per la comunicazione interna. Mia madre, mio fratello, Maria, Natalia, miss Edith, la levatrice, la nutrice, il cavaliere Jemma andarono ad assistere. Io rimasi al capezzale dell'inferma. Una grave sonnolenza la teneva. Il respiro le esciva affannato dalla bocca semiaperta, pallida come la più pallida delle rose fiorite all'ombra. L'ombra occupava l'alcova. Io pensavo, guardandola: "Dunque non la salverò? Avevo allontanata la morte; ed ecco, la morte ritorna. Certo, se non accade un mutamento repentino, ella morirà. Prima, quando riuscivo a tener lontano da lei Raimondo, quando riuscivo a darle qualche illusione e qualche oblio con la mia tenerezza, pareva ch'ella volesse guarire. Ma da che ella vede il figliuolo, da che è ricominciato il supplizio, va di giorno in giorno perdendosi, dissanguandosi peggio che se l'emorragia le continuasse. Io assisto alla sua agonia. Ella non mi ascolta più, non m'obedisce più, come prima. Da chi le verrà la morte? Da _lui_. Egli, egli l'ucciderà, sicuramente...." Un'onda di odio mi sorse dalle radici più profonde, mi parve affluire alle mani tutta con un impulso micidiale. Vidi il piccolo essere malefico che si gonfiava di latte, che prosperava in pace, senza alcun pericolo, circondato d'infinite cure. "Mia madre ama più lui che Giuliana! Mia madre si occupa più di lui che di questa povera morente! Ah, bisogna che io lo tolga di mezzo, ad ogni costo." E la visione del delitto già consumato mi balenò dentro: la visione del morticino in fasce, del piccolo cadavere innocuo su la bara. "Il battesimo è il suo viatico. E Giovanni lo regge su le sue braccia...." Una curiosità subitanea mi punse. Lo spettacolo doloroso mi attirò. Giuliana era ancora assopita. Uscii dall'alcova adagio; uscii dalla stanza; chiamai Cristina, la misi a guardia; poi mi diressi verso il coretto, a passo veloce, con un'ansia che mi soffocava. L'usciuolo era aperto. Scorsi un uomo inginocchiato d'innanzi alla grata. Riconobbi Pietro, il vecchio servitore fedele, quello che m'aveva veduto nascere ed aveva assistito al mio battesimo. Egli si levò, con un po' di pena. --Rimani, rimani, Pietro--gli dissi sotto voce, mettendogli una mano su la spalla per costringerlo a inginocchiarsi di nuovo. E m'inginocchiai al suo fianco, appoggiai la fronte alla grata, guardai nella cappella sottoposta. Vedevo tutto, con una chiarezza perfetta; udivo le formule rituali. La cerimonia era già incominciata. Seppi da Pietro che il bambino aveva già ricevuto il sale. Era ministro il parroco di Tussi, don Gregorio Artese. Questi e il patrino recitavano ora il Credo: l'uno a voce alta, l'altro a voce bassa di séguito. Giovanni reggeva il bambino sul braccio destro, su la mano che il giorno innanzi aveva seminato il frumento. La sinistra posava tra i nastri e i merletti candidi. E quelle mani ossute, asciutte, brune, che parevano fuse in un bronzo animato, quelle mani incallite su gli strumenti dell'agricoltura, santificate dal bene che avevano sparso, dalla vasta opera che avevano fornita, ora nel reggere quell'infante avevano una delicatezza e quasi una timidezza così gentili che io non potevo desistere dal guardarle. Raimondo non piangeva; moveva di continuo la bocca piena d'una bava liquida che gli colava pel mento sul bavaglio trapunto. Dopo l'esorcismo, il parroco bagnò il dito nella saliva e toccò i piccoli orecchi rosei proferendo la parola miracolosa: --_Ephpheta._ Quindi toccò le nari dicendo: --_In odorem suavitatis...._ Quindi intinse il pollice nell'olio dei Catacumeni; e, mentre Giovanni teneva supino su le sue braccia l'infante, unse a questi in modo di croce il sommo del petto; e, come Giovanni lo rivolse prono, unse il sommo del dorso tra le scapole, in modo di croce, dicendo: --_Ego te linio oleo salutis in Christo Jesu Domino nostro...._ E con un fiocco di bambagia deterse le parti che aveva unte. Allora depose la stola paonazza, il colore della doglia e della tristezza; e prese la stola bianca in segno di gioia, ad annunziare che la macchia originale stava per essere cancellata. E chiamò Raimondo per nome, e gli rivolse le tre domande solenni. E il patrino rispose: --_Credo, credo, credo._ La cappella era singolarmente sonora. Da una delle alte finestre ovali entrava una zona di sole andando a ferire una lapide marmorea del pavimento sotto il quale erano i sepolcri profondi ove molti dei miei maggiori dormivano in pace. Mia madre e mio fratello stavano l'una accanto all'altro, dietro a Giovanni; Maria e Natalia si sollevavano su la punta dei piedi per giungere a vedere il piccolo, curiose, di tratto in tratto sorridendo e bisbigliando fra loro. Giovanni si volgeva un poco, qualche volta, a quei bisbigli, con un atto benigno in cui si mostrava tutta l'ineffabile tenerezza senile verso i fanciulli traboccante da quel gran cuore di avo abbandonato. --_Raymunde, vis baptizari?_--domandò il ministro. --_Volo_--rispose il patrino, ripetendo la parola suggerita. Il chierico presentò il bacile d'argento ove luccicava l'acqua battesimale. Mia madre tolse la cuffia al battezzando, mentre il patrino lo porgeva prono all'abluzione. Il capo rotondo, su cui potei distinguere le eruzioni biancastre della crosta lattea, penzolò verso il bacile. E il parroco, attingendo l'acqua con un vascolo, la versò tre volte su quel capo, facendo ogni volta il segno della croce. --_Ego te baptizo in nomine Patris, et Filii, et Spiritus sancti._ Raimondo si mise a vagire forte; più forte mentre gli asciugavano il capo. E, come Giovanni lo risollevò, io vidi quel viso arrossato dall'afflusso di sangue e dallo sforzo, aggrinzato dai moti della bocca, macchiato di bianchiccio anche su la fronte. Ed ebbi dai vagiti pur sempre la stessa sensazione di laceramento doloroso, la stessa esasperazione d'ira. Nulla di lui m'irritava quanto la voce, quanto quel miagolio ostinato che mi aveva ferito così crudamente la prima volta nell'alba lugubre d'ottobre. Era per i miei nervi un urto intollerabile. Il prete intinse il pollice nel sacro Crisma ed unse la fronte al battezzato, recitando la formula rituale che i vagiti coprivano. Quindi gli impose la veste bianca, il simbolo dell'Innocenza. --_Accipe vestem candidam...._ Diede quindi al patrino il cero benedetto. --_Accipe lampadem ardentem...._ L'Innocente si quietò. I suoi occhi si fissarono su la fiammella che tremolava in cima al lungo cero dipinto. Giovanni di Scòrdio reggeva sul braccio destro il nuovo cristiano e nella mano sinistra il simbolo del fuoco divino, con un'attitudine semplice e grave, guardando il sacerdote che recitava la formula. Egli avanzava di tutto il capo gli astanti. Nessuna cosa d'in torno era candida come la sua canizie, né pure la veste dell'Innocente. --_Vade in pace, et Dominus sit tecum._ --_Amen._ Mia madre prese dal braccio del vecchio l'Innocente, se lo strinse al petto, lo baciò. Mio fratello anche lo baciò. Tutti gli astanti, l'un dopo l'altro, lo baciarono. Pietro, al mio fianco, ancora in ginocchio, piangeva. Sconvolto, fuori di me, balzai in piedi, uscii, attraversai di corsa gli anditi, entrai all'improvviso nella stanza di Giuliana. Cristina mi domandò sotto voce, sbigottita: --Che è accaduto, signore? --Nulla, nulla. È sveglia? --No, signore. Pare che dorma. Discostai le cortine, entrai adagio nell'alcova. Da prima nell'ombra non scorsi se non il biancore del guanciale. M'appressai, mi chinai. Giuliana teneva gli occhi aperti, e mi guardava fissamente. Forse indovinò al mio aspetto tutte le mie angosce; ma non parlò. Richiuse gli occhi, come per non riaprirli più. XXXIX. Incominciò da quel giorno l'ultimo periodo precipitoso di quella lucida demenza che doveva condurmi al delitto. Incominciò da quel giorno la premeditazione del mezzo più facile e più sicuro per far morire l'Innocente. Fu una premeditazione fredda, acuta e assidua che assorbì tutte le mie facoltà interiori. L'idea fissa mi possedeva intero, con una forza e una tenacità incredibili. Mentre tutto il mio essere si agitava in un orgasmo supremo, l'idea fissa lo dirigeva allo scopo come su per una lama d'acciaio chiara, rigida, senza fallo. La mia perspicacia pareva triplicata. Nulla mi sfuggiva, dentro e fuori di me. La mia circospezione non si rilasciò mai un istante. Nulla io dissi, nulla io feci che potesse destare sospetto, muovere stupore. Simulai, dissimulai senza tregua, non soltanto verso mia madre, mio fratello, gli altri inconsapevoli, ma anche verso Giuliana. Io mi mostrai a Giuliana rassegnato, pacificato, talvolta quasi immemore. Evitai studiosamente qualunque allusione all'intruso. Cercai in tutti i modi rianimarla, inspirarle fiducia, indurla all'osservanza delle norme che dovevano renderle la salute. Moltiplicai le mie premure. Volli avere per lei tenerezze così profonde e così obliose che ella potesse in quelle rigustare i sapori della vita più freschi e più sinceri. Ancora una volta ebbi la sensazione di trasfondermi nel corpo fragile dell'inferma, di comunicarle un po' della mia forza, di dare un impulso al suo debole cuore. Pareva che io la spingessi a vivere di giorno in giorno, quasi insufflandole un vigore fittizio, nell'attesa dell'ora tragica e liberatrice. Ripetevo dentro di me: "Domani!" E il domani giungeva, trascorreva, si dileguava senza che l'ora fosse scoccata. Ripetevo: "Domani!" Ero convinto che la salvezza della madre stesse nella morte del figliuolo. Ero convinto che, scomparso l'intruso, ella sarebbe guarita. Pensavo: "Ella non potrebbe non guarire. Ella risorgerebbe a poco a poco, rigenerata, con un sangue nuovo. Parrebbe una creatura nuova, scevra d'ogni impurità. Ambedue ci sentiremo purificati, degni l'uno dell'altra, dopo una espiazione così lunga e così dolorosa. La malattia, la convalescenza darebbero al triste ricordo una lontananza indefinita. E io vorrei cancellare dall'anima di lei perfino l'ombra del ricordo; vorrei darle il perfetto oblio, nell'amore. Qualunque altro amore umano parrebbe futile al confronto del nostro, dopo questa grande prova." La visione dell'avvenire m'accendeva d'impazienza. L'incertezza mi diveniva intollerabile. Il delitto mi appariva scevro di orrore. Io mi rimproveravo acremente le perplessità nelle quali m'indugiavo con troppa prudenza; ma nessun lampo ancora aveva attraversato il mio cervello, non ero ancor riuscito a trovare il _mezzo_ sicuro. Bisognava che Raimondo sembrasse morire di morte naturale. Bisognava che anche al medico non potesse balenare alcun sospetto. Dei diversi _metodi_ studiati nessuno mi parve eligibile, praticabile. E intanto, mentre aspettavo il lampo rivelatore; la trovata luminosa, io mi sentivo attratto da uno strano fascino verso la vittima. Spesso entravo all'improvviso nella stanza della nutrice, palpitando così forte che temevo ella udisse i battiti. Si chiamava Anna; era una femmina di Montegorgo Pausula; esciva da una grande razza di viragini alpestri. Aveva talvolta l'aspetto d'una Cibele di rame, a cui mancasse la corona di torri. Portava la foggia del suo paese: una gonna di scarlatto a mille pieghe diritte e simmetriche, un busto nero a ricami d'oro, da cui pendevano due maniche lunghe dove ella di rado introduceva le braccia. Il suo capo si levava su dalla camicia bianchissima, oscuro; ma il bianco degli occhi e il bianco dei denti vincevano d'intensità il candore del lino. Gli occhi parevano di smalto, rimanevano quasi sempre immobili, senza sguardo, senza sogno, senza pensiero. La bocca era larga, socchiusa, taciturna, illustrata da una chiostra di denti fitti ed eguali. I capelli, così neri che davano riflessi di viola, partiti su la fronte bassa, terminavano in due trecce dietro gli orecchi attorte come le corna dell'ariete. Ella stava quasi di continuo assisa reggendo il poppante, in attitudini statuarie, né triste né lieta. Io entrava. La stanza per lo più era nell'ombra. Io vedevo biancheggiare le fasce di Raimondo su le braccia della cupa femmina possente che mi fissava con quelli occhi d'idolo inanimato senza parlare e senza sorridere. Rimanevo là, talvolta, a guardare il poppante appeso alla mammella rotonda, singolarmente chiara in confronto del viso, rigata di vene azzurrognole. Poppava ora piano ora forte, ora svogliato ora mosso da un'avidità subitanea. La guancia molle secondava il moto delle labbra, la gola palpitava ad ogni sorso, il naso quasi scompariva premuto dalla mammella gonfia. Mi pareva visibile il benessere sparso per quel tenero corpo dall'onda di quel latte fresco, sano e sostanziale. Mi pareva che ad ogni nuovo sorso la vitalità dell'intruso divenisse più tenace, più resistente, più malefica. Provavo un sordo rammarico nel notare ch'egli cresceva, ch'egli fioriva, ch'egli non portava in sé alcun indizio d'infermità tranne quelle lievi croste biancastre innocue. Pensavo: "Ma tutte le agitazioni, tutte le sofferenze della madre, mentre egli era ancora nel ventre, non gli hanno nociuto? O egli ha veramente qualche vizio organico non ancora manifesto, che potrebbe svilupparsi in séguito e ucciderlo?" Un giorno, vincendo la ripugnanza, avendolo trovato senza fasce nella culla, lo palpai, lo esaminai dal capo alle piante, misi l'orecchio sul suo petto per ascoltargli il cuore. Egli ritraeva le piccole gambe e poi spingava forte; agitava le mani piene di fossette e di pieghe; si ficcava in bocca le dita terminate da unghie minuscole che sporgevano in fuori per un cerchiolino chiaro. Gli anelli della carne si arrotondavano morbidi ai polsi, ai malleoli, dietro i ginocchi, su le cosce, su gli inguini, sul pube. Più volte lo guardai anche mentre dormiva, lo guardai a lungo, pensando e ripensando al mezzo, distratto dalla visione interiore del morticino in fasce disteso su la bara tra corone di crisantemi bianchi, tra quattro candele accese. Egli aveva il sonno calmissimo. Giaceva supino, tenendo le mani chiuse a pugno col pollice in dentro. A quando a quando le sue labbra umide facevano l'atto di poppare. Se mi giungeva al cuore l'innocenza di quel sonno, se l'atto inconscio di quelle labbra m'impietosiva, io dicevo a me stesso, come per raffermare il mio proposito: "Deve morire." E mi rappresentavo le sofferenze già patite per lui, le sofferenze recenti, le imminenti, e quanto d'affetto egli usurpava a danno delle mie creature, e l'agonia di Giuliana, e tutti i dolori e tutte le minacce che chiudeva la nuvola ignota sul nostro capo. E così rinfocolavo la mia volontà micidiale, così rinnovavo sul dormente la condanna. In un angolo, all'ombra, stava seduta a custodia la femmina di Montegorgo, taciturna, immobile come un idolo; e il bianco degli occhi e il bianco dei denti non lucevano meno dei larghi cerchi d'oro. XL. Una sera (fu il 14 di dicembre), mentre io e Federico tornavamo alla Badiola, scorgemmo d'innanzi a noi sul viale un uomo che riconoscemmo per Giovanni di Scòrdio. --Giovanni!--gridò mio fratello. Il vecchio si fermò. Noi ci avvicinammo. --Buona sera, Giovanni. Che novità? Il vecchio sorrideva peritoso, impacciato, quasi che noi l'avessimo colto in fallo. --Venivo--balbettò--venivo.... pel mio figlioccio. Era timidissimo. Pareva che stesse lì lì per chiedere perdono di quell'ardire. --Vorresti vederlo?--gli chiese Federico, a bassa voce, come per fargli una proposta in confidenza, avendo certo compreso il sentimento dolce e triste che moveva il cuore di quell'avo abbandonato. --No, no.... Venivo soltanto per domandare.... --Non vuoi vederlo dunque. --No.... sì.... troppo disturbo forse.... a quest'ora.... --Andiamo--concluse Federico, prendendolo per la mano come un fanciullo.--Vieni a vederlo. Rientrammo. Salimmo fino alla stanza della nutrice. Mia madre era là. Sorrise con benignità a Giovanni. Ci accennò di non far rumore. --Dorme--disse. Volgendosi a me, soggiunse con inquietudine: --Oggi, verso sera, ha tossito un poco. La notizia mi turbò; e il mio turbamento apparve così che mia madre credette di rassicurarmi soggiungendo: --Ma poco, sai?, a pena, a pena; una cosa da nulla. Federico e il vecchio già s'erano appressati alla culla e guardavano il piccolo dormente, alla luce della lampada. Il vecchio stava tutto chino. E nessuna cosa d'intorno era candida come la sua canizie. --Bacialo--gli bisbigliò Federico. Egli si sollevò, guardò me e mia madre con un'aria smarrita; poi si passò una mano sulla bocca, sul mento dove la barba era mal rasa. Disse sottovoce a mio fratello col quale aveva maggior confidenza: --Se lo bacio, lo pungo. Certo, si sveglia. Mio fratello, vedendo che il povero vecchio diserto si struggeva dal desiderio di baciare il bambino, lo incorò con un gesto. E allora quel grosso capo canuto si piegò su la culla piano piano, piano piano. XLI. Quando rimanemmo soli io e mia madre nella stanza, d'avanti alla culla dove Raimondo ancora dormiva col bacio in fronte, ella disse pietosa: --Povero vecchio! Sai tu che viene quasi tutte le sere? Ma di nascosto. Me l'ha detto Pietro che l'ha veduto gironzare intorno alla casa. Il giorno del battesimo, volle che gli indicassero di fuori la finestra di questa stanza, forse per venire a guardarla.... Povero vecchio! Come mi fa pena! Io ascoltavo il respiro di Raimondo. Non mi parve mutato. Il suo sonno era tranquillo. Dissi: --Dunque oggi ha tossito.... --Sì, Tullio, un poco. Ma non t'impensierire. --Ha preso freddo, forse.... --Non mi par possibile che abbia preso freddo; con tante cautele! Un lampo mi attraversò il cervello. Un gran tremito interno mi assalì all'improvviso. La vicinanza di mia madre mi divenne a un tratto insopportabile. Mi smarrii, mi confusi, ebbi paura di tradirmi. Il pensiero mi balenava dentro con tale lucidità, con tale intensità che io temetti: "Qualche cosa dalla mia faccia deve trasparire." Era un timore vano, ma non riuscivo a dominarmi. Feci un passo avanti, e mi chinai su la culla. Di qualche cosa mia madre s'accorse ma in mio favore, perché soggiunse: --Come sei apprensivo tu! Non senti che respiro calmo? Non vedi come dorme bene? Ma pur dicendomi questo, ella aveva nella voce l'inquietudine e non sapeva nascondermi la sua apprensione. --Sì, è vero; non sarà nulla--risposi comprimendomi.--Rimani qui? --Finchè non torna Anna. --Io vado. Me n'andai. Andai da Giuliana. Ella m'aspettava. Tutto era pronto per la sua cena a cui solevo prender parte affinché la piccola tavola da malata le sembrasse meno uggiosa e il mio esempio e le mie premure la spingessero a mangiare. Io mi mostrai negli atti, nelle parole eccessivo, quasi allegro, diseguale. Ero in preda a una particolare sovreccitazione, e n'avevo un'esatta conscienza, e potevo sorvegliarmi ma non moderarmi. Bevvi, contro la mia consuetudine, due o tre bicchieri del vino di Borgogna prescritto a Giuliana. Volli che ella anche bevesse qualche sorso di più. --Ti senti un poco meglio; è vero? --Sì, sì. --Se tu sarai obediente, io ti prometto che per Natale ti farò levare. Ci sono ancora dieci giorni. In dieci giorni, se tu vorrai, diventerai forte. Bevi ancora un sorso, Giuliana! Ella mi guardava un po' attonita, un po' curiosa, facendo qualche sforzo per prestarmi tutta la sua attenzione. Ella era già affaticata, forse; le palpebre incominciavano forse a pesarle. Quella positura elevata, dopo un certo tempo, provocava in lei ancora talvolta i sintomi dell'anemia cerebrale. Bagnò le labbra nel bicchiere che le porgevo. --Dimmi--io seguitai--dove ti piacerebbe di passare la convalescenza? Ella sorrise debolmente. --Su la Riviera? Vuoi che scriva ad Augusto Arici perché ci trovi una villa? Se Villa Ginosa fosse disponibile! Ti ricordi? Ella sorrise più debolmente ancora. --Sei stanca? T'affatica forse la mia voce.... M'avvidi ch'ella stava per cadere in deliquio. La sostenni, le tolsi i guanciali che la rialzavano, l'adagiai mettendole il capo più in basso, la soccorsi nei modi consueti. Dopo un poco, parve ch'ella riacquistasse i sensi. Mormorò come in sogno: --Sì, sì, andiamo.... XLII. Un'irrequietudine strana mi teneva. Talvolta era come un godimento, come un assalto di gioia confusa. Talvolta era come un'impazienza acutissima, una smania insofferibile. Talvolta era come un bisogno di vedere qualcuno, d'andare in cerca di qualcuno, di parlare, di espandermi. Talvolta era come un bisogno di solitudine, di correre a rinchiudermi in un luogo sicuro per rimanere solo con me stesso, per guardarmi bene a dentro, per sviluppare il mio pensiero, per considerare e studiare tutte le particolarità dell'evento prossimo, per prepararmi. Questi moti diversi e contrarii, ed altri innumerevoli moti indefinibili inesplicabili, si avvicendavano nel mio spirito rapidamente, con una straordinaria accelerazione della mia vita interiore. Il lampo che aveva attraversato il mio cervello, quel guizzo di luce sinistra, pareva che avesse illuminato a un tratto uno stato di conscienza preesistente se bene immerso nell'oscurità, pareva che avesse risvegliato uno strato profondo della mia memoria. Sentivo di _ricordarmi_ ma, per quanti sforzi io facessi, non giungevo a rintracciare le origini del ricordo né a scoprirne la natura. Certo, mi ricordavo. Era il ricordo d'una lettura lontana? Avevo trovato descritto in qualche libro un caso analogo? O qualcuno, un tempo, m'aveva narrato quel caso come occorso nella vita reale? O pure quel sentimento del _ricordo_ era illusorio, non era se non l'effetto d'una associazione d'idee misteriosa? Certo, mi pareva che il _mezzo_ mi fosse stato suggerito da qualcuno estraneo. Mi pareva che qualcuno a un tratto fosse venuto a togliermi da ogni perplessità dicendomi: "_Bisogna che tu faccia così, come fece quell'altro nel tuo caso._" Ma chi era _quell'altro_? In qualche modo, certo, io dovevo averlo conosciuto. Ma, per quanti sforzi io facessi, non riuscivo a distaccarlo da me, a rendermelo obiettivo. M'è impossibile definire con esattezza il particolare stato di conscienza in cui mi trovavo. Io avevo la nozione completa d'un fatto in tutti i punti del suo svolgimento, avevo cioè la nozione d'una serie di azioni per cui era passato un uomo nel ridurre ad effetto un dato proposito. Ma quell'uomo, il predecessore, m'era ignoto; e io non potevo associare a quella nozione le imagini relative senza mettere me stesso nel luogo di colui. Io dunque vedevo me stesso compiere quelle speciali azioni già compiute da un altro, imitare la condotta tenuta da un altro in un caso simile al mio. Il sentimento della spontaneità originale mi mancava. Quando uscii dalla stanza di Giuliana, passai qualche minuto nell'incertezza girando per gli anditi alla ventura. Non incontrai nessuno. Mi diressi verso la stanza della nutrice. Origliai alla porta; udii la voce sommessa di mia madre; mi allontanai. Ella non s'era mossa forse di là? Il bambino aveva avuto forse qualche accesso di tosse più grave? Io conoscevo bene il catarro bronchiale dei neonati, la malattia terribile dalle apparenze ingannevoli. Mi ricordai del pericolo corso da Maria nel suo terzo mese di vita, mi ricordai di tutti i sintomi. Anche Maria da principio aveva alcune volte sternutato, tossito leggermente: aveva mostrato molta tendenza al sonno. Pensai: "Chi sa! Se aspetto, se non mi lascio trascinare, forse _il buon Dio_ interviene a tempo, io sono salvo." Tornai in dietro; origliai di nuovo; udii ancora la voce di mia madre; entrai. --Dunque, come sta Raimondo?--chiesi, senza nascondere il mio tremito. --Bene. È quieto; non ha più tossito: ha il respiro regolare, il calore naturale. Guarda. Sta poppando. Mia madre mi parve in fatti rassicurata, tranquilla. Anna, seduta sul letto, dava il latte al bambino che lo beveva con avidità, mettendo di tratto in tratto un piccolo rumore con le labbra nel suggere. Anna aveva il volto reclinato, gli occhi fissi al pavimento, un'immobilità bronzea. La fiammella oscillante della lampada le gittava luci ed ombre su la gonna rossa. --Non fa troppo caldo qui dentro?--dissi, provando un po' di soffocazione. La camera in fatti era caldissima. In un angolo, su la cupola d'un braciere si scaldavano alcune pezzuole, una fascia. Si udiva anche un gorgoglio d'acqua in bollore. Si udiva a quando a quando il tintinno dei vetri sotto le ventate che fischiavano o rugghiavano. --Senti che tramontana si rivolta!--mormorò mia madre. Io non avvertii più gli altri rumori. Ascoltai il vento, con un'attenzione ansiosa. Mi corse qualche brivido per le ossa, quasi che m'avesse penetrato un filo di quel freddo. Andai verso la finestra. Nell'aprire uno scuretto, le dita mi tremavano. Appoggiai la fronte contro il vetro gelido e guardai di fuori, ma l'appannatura prodotta subito dall'alito m'impediva di vedere. Levai gli occhi e scorsi a traverso il vetro più alto scintillare il cielo stellato. --È sereno--dissi, uscendo dal vano della finestra. Avevo dentro di me l'imagine della notte adamantina e micidiale, mentre gli occhi mi correvano a Raimondo che pendeva ancora dalla poppa. --Ha mangiato stasera Giuliana?--mi domandò mia madre, con un accento amorevole. --Sì--le risposi, senza dolcezza; e pensai: "In tutta la sera tu non hai trovato un minuto per venire a vederla! Non è la prima volta che la trascuri. Hai dato il cuore a Raimondo." XLIII. La mattina dopo, il dottor Jemma osservò il bambino e lo dichiarò perfettamente sano. Non diede alcuna importanza al fatto della tosse addotto da mia madre. Pur sorridendo delle cure e delle apprensioni eccessive, raccomandò la cautela in quei giorni di freddo crudo, raccomandò la massima prudenza per le lavande e pel bagno. Ero presente mentre egli parlava di queste cose d'avanti a Giuliana. Due o tre volte i miei occhi s'incontrarono con quelli di lei, in lampi fuggevoli. Dunque non veniva aiuto dalla _Provvidenza_. Bisognava operare, bisognava profittare del momento opportuno, affrettare l'evento. Io mi risolsi. Aspettai la sera, deliberato a compiere il delitto. Raccolsi quanto di energia ancora mi rimaneva, aguzzai la mia perspicacia, studiai tutte le mie parole, tutti i miei atti. Nulla io dissi, nulla io feci che potesse destare sospetto, muovere stupore. La mia circospezione non si rilasciò mai un istante. Non ebbi un istante di debolezza sentimentale. La mia sensibilità interiore era compressa, soffocata. Il mio spirito concentrava tutte le sue facoltà utili nel preparativo per arrivare allo scioglimento di un problema materiale. Bisognava che nella sera per alcuni minuti io fossi lasciato solo con l'intruso, e in certe date condizioni di sicurtà. Durante il giorno entrai più volte nella stanza della nutrice, Anna era sempre al suo posto, come una custode impassibile. Se io le rivolgevo qualche domanda, ella mi rispondeva con monosillabi. Aveva una voce roca, d'un timbro singolare. Il suo silenzio, la sua inerzia mi irritavano. Per lo più ella non s'allontanava se non nell'ora dei suoi pasti. Ma era sostituita per lo più da mia madre o da miss Edith o da Cristina o da qualche altra donna di servizio. In quest'ultimo caso io avrei potuto facilmente liberarmi della testimone, dandole un ordine. Ma rimaneva sempre il pericolo che qualcuno sopraggiungesse all'improvviso nel frattempo. E inoltre io ero in balìa della ventura, non potendo io stesso scegliere la persona subentrante. Era probabile che tanto in quella sera quanto nelle sere successive fosse mia madre. D'altronde, mi pareva impossibile prolungare indefinitamente le mie vigilanze e le mie ansietà, stare in agguato per un tempo incerto, vivere nell'aspettazione continua dell'ora funesta. Mentre ero là perplesso, entrò miss Edith con Maria e Natalia. Le due piccole Grazie, animate dalla corsa all'aria aperta, chiuse nei loro mantelli di zibellino, con su' capelli il tòcco della stessa pelliccia, con le mani guantate, con le guance invermigliate dal freddo, a pena mi videro si gettarono su di me allegre e leggère. E per alcuni minuti la stanza fu piena del loro cinguettio. --Sai, sono arrivati i montanari--m'annunziò Maria.--Stasera comincia la novena di Natale, nella cappella. Se tu vedessi il presepe che ha fatto Pietro! Sai che la nonna ci ha promesso l'Albero? È vero, miss Edith? Bisogna metterlo nella stanza della mamma.... La mamma sarà guarita per Natale; è vero? Oh, falla guarire! Natalia s'era fermata a guardare Raimondo; e di tratto in tratto rideva alle smorfie di lui che agitava le gambe senza posa come se volesse liberarsi dalle fasce. Le venne un capriccio. --Voglio tenerlo in braccio! E strepitò per averlo. Raccolse tutta la sua forza per reggere il peso; e il suo volto divenne grave, come quando ella faceva da madre alla sua bambola. --Ora io!--gridò Maria. E il fratellastro passò dall'una all'altra, senza piangere. Ma a un certo punto, mentre Maria lo portava in giro sorvegliata da Edith, pericolò, fu per sfuggirle dalle mani. Edith lo sostenne, lo riprese, lo restituì alla nutrice che pareva profondamente assorta, lontanissima dalle persone e dalle cose che la circondavano. Seguendo un mio pensiero segreto, io dissi: --Dunque stasera comincia la novena.... --Sì, sì, stasera. Io guardavo Anna che parve scuotersi e prestare un'attenzione insolita al discorso. --Quanti sono i montanari? --Cinque--rispose Maria che sembrava minutamente informata di tutto.--Due cornamuse, due ceramelle e un piffero. E si mise a ridere ripetendo molte volte di seguito l'ultima parola per incitare la sorella. --Vengono dalla tua montagna--dissi volgendomi ad Anna.--Ce n'è forse qualcuno di Montegorgo.... Gli occhi di lei avevano perduta la loro durezza di smalto, s'erano animati, rilucevano umidi e tristi. Tutto il volto appariva alterato dall'espressione d'un sentimento straordinario. E io compresi ch'ella soffriva e che la nostalgia era il suo male. XLIV. S'approssimava la sera. Scesi alla cappella, vidi i preparativi della Novena: il presepe, i fiori, le candele vergini. Uscii senza sapere perché; guardai la finestra della stanza di Raimondo. Camminai a passi rapidi su e giù per lo spiazzo, sperando di domare il tremore convulso, il freddo acuto che mi penetrava le ossa, le contratture che mi serravano lo stomaco vacuo. Era un crepuscolo glaciale, polito, quasi direi tagliente. Un lividore verdastro si dilatava su l'orizzonte lontano, in fondo alla valle plumbea ove s'internava l'Assoro tortuoso. Il fiume luccicava, solo. Uno sgomento repentino m'invase. Pensai: "Ho paura?" Mi pareva che qualcuno, invisibile, mi guardasse l'anima. Provavo lo stesso malessere che danno talvolta gli sguardi troppo fissi, magnetici. Pensai: "Ho paura? Di che? Di compiere l'atto o di essere scoperto da qualcuno?" Mi sgomentavano le ombre dei grandi alberi, l'immensità del cielo, i luccichii dell'Assoro, tutte quelle voci vaghe della campagna. Sonò l'Angelus. Rientrai, quasi di fuga, come inseguito. Incontrai mia madre nell'andito non ancora illuminato. --Di dove vieni, Tullio? --Di fuori. Ho passeggiato un poco. --Giuliana t'aspetta. --A che ora comincia la Novena? --Alle sei. Erano le cinque e un quarto. Mancavano tre quarti d'ora. Bisognava vigilare. --Vado, mamma. Dopo qualche passo la richiamai. --Federico non è tornato? --No. Salii alla stanza di Giuliana. Ella m'aspettava. Cristina preparava la piccola tavola. --Dove sei stato fino a ora?--mi chiese la povera malata, con un lieve tono di rimprovero. --Sono stato là, con Maria, con Natalia.... Sono stato a vedere la cappella. --Già, stasera comincia la Novena--ella mormorò tristamente, accorata. --Di qui potrai sentire forse i suoni. Ella restò pensosa per qualche istante. Mi sembrò molto triste, d'una di quelle tristezze un po' molli che rivelano un cuore gonfio di pianto, un bisogno di lacrime. --A che pensi?--le chiesi. --Mi ricordo del mio primo Natale alla Badiola. Te ne ricordi tu? Ella era tenera e commossa; e richiamava la mia tenerezza, si abbandonava a me per essere blandita, per essere cullata, perché io le premessi il cuore e le bevessi le lacrime. Conoscevo quei suoi languori dolenti, quei suoi affanni indefiniti. Ma pensavo, ansioso: "Bisogna che lo non la secondi. Bisogna che io non mi lasci legare. Il tempo fugge. Se ella mi prende, mi sarà difficile distaccarmi da lei. Se ella piange, io non potrò allontanarmi. Bisogna che io mi contenga. Il tempo precipita. Chi rimarrà a guardia di Raimondo? Non mia madre, certo. Probabilmente la nutrice. Tutti gli altri si raccoglieranno nella cappella. Qui metterò Cristina. Io sarò sicuro. Il caso non potrebbe essermi più favorevole. Bisogna che fra venti minuti io sia libero." Evitai di eccitare la malata, finsi di non comprenderla, non corrisposi alle sue effusioni, cercai di distrarla con oggetti materiali, feci in modo che Cristina non ci lasciasse soli come nelle altre sere d'intimità, mi occupai della cena con esagerata premura. --Perché stasera non mangi con me?--ella mi chiese. --Non posso prender nulla, ora; non sto bene. Mangia tu qualche cosa; ti prego! Per quanti sforzi io facessi non riuscivo a dissimulare interamente l'ansietà che mi divorava. Più volte ella mi guardò con l'intenzione manifesta di penetrarmi. Poi d'un tratto s'accigliò, diventò taciturna. Toccò a pena a pena qualche cibo, bagnò a pena a pena le labbra nel bicchiere. Io raccolsi tutto il mio coraggio allora, per andarmene. Finsi di aver udito il rumore d'una vettura. Mi misi in ascolto, dissi: --Forse è tornato Federico. Ho bisogno di vederlo subito.... Permetti che vada giù un momento. Rimane qui Cristina. La vidi alterata nel volto come chi sia per rompere in un pianto. Non aspettai il suo consenso. Uscii in fretta; ma non trascurai di ripetere a Cristina che rimanesse fino a che io non fossi risalito. A pena fuori, fui costretto a fermarmi per resistere alla soffocazione dell'ambascia. Pensai: "Se non riesco a dominare i miei nervi, tutto è perduto." Tesi l'orecchio, ma non udii se non il rombo delle mie arterie. M'avanzai per l'andito fino alle scale. Non incontrai nessuno. La casa era silenziosa. Pensai: "Tutti già sono nella cappella, anche i domestici. Non c'è nulla da temere." Aspettai due o tre minuti ancora, per ricompormi. In quei due o tre minuti l'intensione del mio spirito cadde. Ebbi uno smarrimento strano. Mi passarono pel cervello pensieri vaghi, insignificanti, estranei all'atto che stavo per compiere. Contai macchinalmente i balaustri della ringhiera. "Certo Anna è rimasta. La stanza di Raimondo non è lontana dalla cappella. I suoni annunzieranno il principio della Novena." Mi diressi verso la porta. Prima di giungervi, udii il preludio delle cornamuse. Entrai senza esitare. Non m'ero ingannato. Anna stava in piedi, presso la sua sedia, atteggiata in modo così vivo ch'io subito indovinai ch'ella era allora allora balzata in piedi udendo le cornamuse della sua montagna, il preludio della pastorale antica. --Dorme?--domandai. Ella m'accennò di sì col capo. I suoni continuavano, velati dalla distanza, dolci come in un sogno, un po' rochi, lunghi, lenti. Le voci chiare delle ceramelle modulavano la melodia ingenua e indimenticabile su l'accompagnamento delle cornamuse. --Va anche tu alla Novena--io le dissi.--Resto io qui. Da quanto tempo s'è addormentato? --Ora. --Va, va dunque alla Novena. Gli occhi le brillarono. --Vado? --Sì. Resto io qui. Le aprii la porta io stesso; la chiusi dietro di lei. Corsi verso la culla, su la punta dei piedi; guardai da presso. L'Innocente dormiva nelle sue fasce, supino, tenendo le piccole mani chiuse a pugno col pollice in dentro. A traverso il tessuto delle palpebre apparivano per me le sue iridi grige. Ma non sentii sollevarmi dal profondo nessun impeto cieco di odio né d'ira. La mia avversione contro di lui fu meno acre che nel passato. Mi mancò quell'impulso istintivo che più d'una volta avevo sentito correre fino alle estremità delle mie dita pronte a qualunque violenza criminale. Io non obedii se non all'impulso d'una volontà fredda e lucida, in una perfetta consapevolezza. Tornai alla porta, la riaprii; m'assicurai che l'andito era deserto. Corsi allora alla finestra. Mi vennero alla memoria alcune parole di mia madre; mi balenò il dubbio che Giovanni di Scòrdio potesse trovarsi là sotto, nello spiazzo. Con infinite precauzioni aprii. Una colonna d'aria gelata m'investì. Mi sporsi sul davanzale, ad esplorare. Non vidi nessuna forma sospetta, non udii se non i suoni della Novena diffusi. Mi ritrassi, mi avvicinai alla culla, vinsi con uno sforzo l'estrema ripugnanza; presi adagio adagio il bambino, comprimendo l'ansia; tenendolo discosto dal mio cuore che batteva troppo forte, lo portai alla finestra; l'esposi all'aria che doveva farlo morire. Non mi smarrii; nessuno dei miei sensi s'oscurò. Vidi le stelle del cielo che oscillavano come se un vento superno le agitasse; vidi i moti illusorii ma terrifici che la luce mobile della lampada metteva nella portiera; udii distintamente la ripresa della pastorale, i latrati d'un cane lontano. Un guizzo del bambino mi fece trasalire. Egli si svegliava. Pensai: "Ora piange. Quanto tempo è passato? Un minuto, forse; né pure un minuto. Basterà quest'impressione breve perché egli muoia? È stato egli colpito?" Il bambino agitò le braccia d'innanzi a sé, storse la bocca, l'aprì; tardò un poco a emettere il vagito che mi parve mutato, più esile, più tremulo, ma forse soltanto perché sonava in un'aria diversa mentre io l'avevo udito sempre in luoghi chiusi. Quel vagito esile, tremulo, m'empì di sgomento, mi diede a un tratto una paura folle. Corsi alla culla, posai il bambino. Tornai alla finestra per chiuderla; ma prima di chiuderla, mi sporsi sul davanzale, gittai nell'ombra uno sguardo, non vidi null'altro che le stelle. Chiusi. Benché incalzato dal pànico, evitai il rumore. E dietro di me il bambino piangeva, piangeva più forte. "Sono salvo?" Corsi alla porta, guardai nell'andito, origliai. L'andito era deserto; passava l'onda lenta dei suoni. "Sono salvo dunque. Chi può avermi veduto?" Pensai ancora a Giovanni di Scòrdio, guardando la finestra; ebbi ancora un'inquietudine. "Ma no, giù non c'era nessuno. Ho guardato due volte." Mi ravvicinai alla culla, raddrizzai il corpo del bambino, lo copersi con cura, m'assicurai che nulla era fuor di posto. Ora però avevo una ripugnanza invincibile ai contatti. Egli piangeva, piangeva. Che potevo fare per quietarlo? Aspettai. Ma quel vagito continuo in quella grande stanza solitaria, quel lagno inarticolato della vittima ignara mi straziava così atrocemente che non potendo più resistere m'alzai per sottrarmi in qualche modo alla tortura. Uscii nell'andito, socchiusi la porta dietro di me; rimasi là vigilando. La voce del bambino giungeva a a pena a pena, si confondeva nell'onda lenta dei suoni. I suoni continuavano, velati dalla lontananza, dolci come in un sogno, un po' rochi, lunghi, lenti. Le voci chiare delle ceramelle modulavano la melodia semplice su l'accompagnamento delle cornamuse. La pastorale si spandeva per la grande casa pacifica, giungeva forse alle stanze più remote.--L'udiva Giuliana? Che pensava, che sentiva Giuliana? Piangeva? Non so perché, m'entrò nel cuore questa certezza: "Ella piange." E dalla certezza nacque una visione intensa che mi diede una sensazione reale e profonda. I pensieri e le imagini che mi attraversavano il cervello erano incoerenti, frammentarii, assurdi, composti di elementi che l'uno all'altro non rispondevano, inafferrabili, d'una natura dubbia. M'assalì la paura della follia. Mi domandai: "Quanto tempo è passato?" E m'accorsi che avevo completamente smarrita la nozione del tempo. I suoni cessarono. Pensai: "La divozione è finita. Anna sta per risalire. Verrà forse mia madre. Raimondo non piange più!" Rientrai nella stanza, gittai uno sguardo in torno per assicurarmi ancora una volta che non rimaneva alcuna traccia dell'attentato. M'appressai alla culla, non senza un vago timore di trovare il bambino esanime. Egli dormiva, supino, tenendo le piccole mani chiuse a pugno col pollice in dentro. "Dorme! È incredibile. Pare che nulla sia accaduto." Quel che avevo fatto parve assumere l'inesistenza d'un sogno. Ebbi come un mancamento repentino di pensieri, un intervallo vacuo, aspettando. A pena riconobbi nell'andito il passo greve della nutrice, le andai in contro. Mia madre non la seguiva. Senza guardarla in faccia, le dissi: --Dorme ancora. E m'allontanai rapidamente: salvo! XLV. Da quell'ora s'impadronì del mio spirito una specie d'inerzia quasi stupida, forse perché ero esausto, sfinito, incapace d'altri sforzi. La mia conscienza perse la sua terribile lucidezza, la mia attenzione s'indebolì, la mia curiosità non fu pari all'importanza degli avvenimenti che si svolgevano. I miei ricordi, in fatti, sono confusi, scarsi, composti d'imagini non bene distinte. Quella sera rientrai nell'alcova, rividi Giuliana, mi trattenni al suo capezzale per qualche tempo. Durai una gran fatica a parlare. Le chiesi, guardandola negli occhi: --Hai pianto? Ella rispose: --No. Ma era più triste di prima. Era pallida come la sua camicia. Le chiesi: --Che hai? Ella rispose: --Nulla. E tu? --Io non mi sento bene. Mi duole tanto il capo.... Una immensa stanchezza mi prostrava; tutte le membra mi pesavano. Reclinai il capo sul lembo del guanciale; rimasi alcuni minuti in quell'atto oppresso da una pena indefinita. Sussultai udendo la voce di Giuliana che diceva: --Tu mi nascondi qualche cosa. --No, no. Perché? --Perché _sento_ che tu mi nascondi una cosa. --No, no; t'inganni. --M'inganno. Tacque. Appoggiai di nuovo il capo sul lembo. Dopo alcuni minuti ella mi disse all'improvviso: --Tu _lo_ vedi spesso. Mi sollevai per guardarla, sbigottito. --Per volontà tua vai a vederlo, vai a cercarlo--ella soggiunse.--Lo so. Anche oggi.... --E bene? --Ho paura di questo, ho paura per te. Io ti conosco. Tu ti tormenti, tu vai là a tormentarti, vai a divorarti il cuore.... Io ti conosco. Ho paura, Tu non sei rassegnato, no, no; tu non puoi essere rassegnato. Non m'inganni, Tullio. Anche stasera, dianzi, tu sei stato là.... --Come lo sai? --Lo so, lo _sento_. Il sangue mi s'era ghiacciato. --Vorresti tu che mia madre sospettasse? Vorresti tu che s'accorgesse d'un'avversione? Parlavamo sottovoce. Anch'ella aveva l'aria sbigottita. E io pensavo: "Ecco, ora entra mia madre stravolta gridando:--Raimondo muore!--" Entrarono Maria e Natalia con miss Edith. E l'alcova si rallegrò del loro cinguettio. Parlarono della cappella, del presepe, delle candele, delle cornamuse, minutamente. Lasciai Giuliana per ritirarmi nella mia camera, protestando il dolor di capo. Come fui sul letto, la stanchezza mi vinse quasi subito. Dormii profondo, molte ore. La luce del giorno mi trovò calmo tenuto da una strana indifferenza, da una incuriosità inesplicabile. Nessuno era venuto a interrompermi il sonno, dunque nulla di straordinario era accaduto. Gli avvenimenti della vigilia mi apparivano irreali e lontanissimi. Sentivo un distacco immenso tra me e il mio essere anteriore, tra quel che ero e quel che ero stato. C'era una discontinuità tra il periodo passato e il presente della mia vita psichica. E io non facevo alcuno sforzo per raccogliermi, per comprendere il fenomeno singolare. Avevo ripugnanza per qualunque attività; cercavo di conservarmi in quella specie d'apatia fittizia sotto la quale giaceva il viluppo oscuro di tutte le agitazioni trascorse; evitavo d'investigarmi, per non risvegliare quelle cose che parevano morte, che parevano non appartenere più alla mia esistenza reale. Somigliavo un poco a quei malati che, avendo perduta la sensibilità d'una metà del corpo, si figurano d'avere al loro fianco, nel loro letto, un cadavere. Ma venne Federico a battere alla mia porta. Entrò. Che nuova mi portava? La sua presenza mi scosse. --Iersera non ci vedemmo--disse.--Tornai tardi. Come stai? --Né bene né male. --Iersera ti doleva il capo. È vero? --Sì: per questo andai a letto presto. --Sei un po' verde, stamani. Oh, mio Dio, quando finirà la disgrazia? Tu non stai bene, Giuliana è sempre a letto, ho incontrata la mamma or ora tutta sconvolta perché Raimondo stanotte ha tossito! --Ha tossito? --Già. Si tratta probabilmente d'un po' di raffreddore; ma la mamma, al solito, esagera.... --È venuto il medico? --Non ancora. Ma mi pare che tu sia peggio della mamma. --Sai, qualunque apprensione, quando si tratta di bambini, è giustificabile. Un nulla basta.... Egli mi guardava con i suoi limpidi occhi glauchi, e io ne avevo sgomento e vergogna. Quando se n'andò, balzai dal letto. Pensavo: "Dunque gli effetti cominciano; dunque non c'è più dubbio. Ma quanto tempo ancora vivrà? È anche possibile che non muoia.... Ah no, è impossibile che non muoia. L'aria era gelata, mozzava il respiro." E rividi dentro di me il bambino respirante, la piccola bocca socchiusa, la fossetta della gola. XLVI. Il dottore diceva: --Non c'è nessun motivo d'inquietudine. Si tratta d'un raffreddore leggerissimo. I bronchi sono liberi. Egli si chinò di nuovo sul petto denudato di Raimondo ad ascoltare. --Manca assolutamente qualunque rumore. Potete assicurarvene voi stesso, col vostro orecchio--soggiunse volgendosi a me. Anch'io appoggiai l'orecchio sul fragile petto, e ne sentii il tepore blando. --In fatti.... E guardai mia madre che trepidava dall'altra parte della culla. I soliti sintomi della bronchite mancavano. Il bambino era tranquillo, aveva qualche lieve accesso di tosse a lunghi intervalli, prendeva il latte con la frequenza consueta, dormiva d'un sonno grave ed eguale. Io stesso, ingannato dalle apparenze, dubitavo: "Dunque il mio tentativo è stato inutile. Pare ch'egli non debba morire. Che vita tenace!" E mi tornò il rancore primitivo contro di lui, più acre. Il suo aspetto calmo e roseo mi esasperò. Avevo dunque sofferto tutte quelle angosce, m'ero esposto a quel pericolo per nulla! Si mesceva alla mia collera sorda una specie di stupore superstizioso per la straordinaria tenacità di quella vita: "Credo che non avrò il coraggio di ricominciare. E allora? Sarò io la sua vittima; e non potrò sfuggirgli." E il piccolo fantasma perverso, il fanciullo bilioso e felino, pieno d'intelligenza e d'istinti malvagi, mi riapparve; di nuovo mi fissò con i suoi duri occhi grigi, in atto di sfida. E le scene terribili nell'ombra delle stanze deserte, le scene che aveva un tempo create la mia imaginazione ostile, mi si ripresentarono; di nuovo assunsero il rilievo, il movimento, tutti i caratteri della realtà. Era una giornata bianca, con un presentimento di neve. L'alcova di Giuliana mi parve ancora un rifugio. L'intruso non doveva uscire dalla sua stanza, non poteva venire a perseguitarmi fin là dentro. E io m'abbandonai tutto alla mia tristezza senza nasconderla. Pensavo, guardando la povera malata: "Ella non guarirà, non si leverà." Le strane parole della sera innanzi mi tornavano alla memoria, mi turbavano. Senza dubbio, l'intruso era per lei un carnefice com'era per me. Senza dubbio, ella non poteva pensare ad altro che a lui, morendone a poco a poco. Tutto quel peso su quel cuore così debole! Con la discontinuità delle imagini che si svolgono nel sogno, si risollevavano nel mio spirito alcuni frammenti della vita passata: ricordi d'un'altra malattia, d'una lontana convalescenza. Mi indugiai a ricomporre quei frammenti, a ricostrurre quel periodo così dolce e così doloroso in cui avevo gittato il seme della mia sventura. La diffusa bianchezza della luce mi rammentava quel pomeriggio lento che io e Giuliana avevamo passato leggendo un libro di poesia, chinandoci insieme su la stessa pagina, seguendo con gli occhi la stessa riga. E io rivedevo il suo indice affilato sul margine e il segno dell'unghia. _"Accueillez la voix qui persiste Dans son naïf épithalame. Allez, rien n'est meilleur à l'âme Que de faire une âme moins triste!"_ "Io le presi il polso; e chinando il capo lentamente, fino a porre le labbra nel cavo della sua mano, mormorai: --Tu.... potresti dimenticare? Ella mi chiuse la bocca, e pronunziò la sua gran parola: --Silenzio." Rivivevo quel lembo di vita, in sensazione reale e profonda; e continuavo, continuavo a rivivere, giungevo alla mattina della prima levata, alla mattina terribile. Riudivo la voce ridente e interrotta; rivedevo il gesto dell'offerta, e lei stesa nella poltrona dopo il colpo improvviso, e il séguito. Perché la mia anima non poteva più distaccare da sé quelle imagini? Era vano, era vano il rimpianto. "_Troppo tardi_." --A che pensi?--mi chiese Giuliana che forse fino allora, durante il mio silenzio, non d'altro aveva sofferto che della mia tristezza. Io non le nascosi il mio pensiero. Ella disse, con una voce che le usciva dall'intimo petto fioca ma più penetrante d'un grido: --Ah, io avevo i cieli per te nella mia anima! Soggiunse, dopo una pausa lunga in cui ella forse aveva assorbito nel cuore le lacrime che non apparivano: --Ora, io non posso consolarti! Non c'è consolazione per te né per me; non ci potrà esser mai.... Tutto è perduto. Io dissi: --Chi sa! E ci guardammo; ed era manifesto che ambedue pensavamo in quel punto alla medesima cosa: alla possibile morte di Raimondo. Esitai un istante; e poi volli domandarle, alludendo al dialogo avvenuto una sera sotto gli olmi: --Hai pregato Iddio? La voce mi tremava forte. Ella rispose (l'udii a pena): --Sì. E chiuse gli occhi, e si voltò sul fianco, affondò la testa nel guanciale, si ritrasse, si ristrinse in sé stessa sotto le coperte, come presa da un gran freddo. XLVII. Verso sera andai a rivedere Raimondo. Lo trovai su le braccia di mia madre. Mi parve un poco più pallido; ma era ancora molto tranquillo, respirava bene, non aveva alcun segno sospetto. --Ha dormito fino a ora!--mi disse mia madre. --T'inquieti di questo? --Sì, perché non ha mai dormito tanto. Io guardavo il bambino fissamente. I suoi occhi grigi erano senza vivezza, sotto la fronte sparsa di leggere croste biancastre. Egli moveva di continuo le labbra, come biasciando. A un tratto, riversò un po' di latte grumoso sul bavaglio. --Ah, no, no, questo bambino non sta bene--esclamò mia madre, scotendo il capo. --Ma ha tossito? Come per rispondermi, Raimondo si mise a tossire. --Senti? Era una piccola tosse fioca, non accompagnata da nessun rumore degli organi interni. Durò pochissimo. Io pensai: "Bisogna aspettare." Ma, come risorgeva in me il presagio funesto, la mia avversione contro l'intruso diminuiva, si placava la mia acredine. M'accorgevo che il mio cuore rimaneva stretto e misero, incapace di esultanze. Mi ricordo di quella sera come della più triste ch'io abbia mai passata nel corso della mia sventura. Nel dubbio che Giovanni di Scòrdio fosse pei dintorni, uscii dalla casa, m'inoltrai pel viale dove l'avevamo incontrato io e mio fratello quell'altra volta. Nel chiarore del crepuscolo era l'annunzio della prima neve. Lungo la fila degli alberi si stendeva un tappeto di foglie. I nudi rami stecchiti frastagliavano il cielo. Guardavo innanzi a me, sperando di scorgere la figura del vecchio. Pensavo alla tenerezza del vecchio pel suo figlioccio, a quel desolato amore senile, a quelle grosse mani callose e rugose che avevo visto ingentilirsi e tremare su le fasce bianche. Pensavo: "Come piangerebbe!" Vedevo il morticino in fasce disteso su la bara tra corone di crisantemi bianchi, tra quattro candele accese; e Giovanni inginocchiato piangere. "Mia madre piangerà, sarà disperata. Tutta la casa cadrà nel lutto. Il Natale sarà funebre. Che farà Giuliana quando io comparirò sul limitare dell'alcova, a piè del letto, e le annunzierò:--È morto--?" Ero giunto al limite del viale. Guardai; non vidi nessuno. La campagna s'immergeva nell'ombra, silenziosa; un fuoco rosseggiava su la collina, in lontananza. Tornai in dietro, solo. A un tratto, qualche cosa di bianco mi tremolò d'avanti agli occhi, si dileguò. Era la prima neve. E più tardi, mentre stavo al capezzale di Giuliana, riudii le cornamuse che proseguivano la Novena, _alla medesima ora_. XLVIII. La sera passò, la notte passò, la mattina seguente passò. Nulla di straordinario accadde. Ma, nella sua visita al bambino, il medico non nascose che esisteva un catarro delle narici e dei bronchi maggiori: un'affezione leggèra, senza importanza. M'accorsi però ch'egli voleva dissimulare una certa inquietudine. Diede alcune istruzioni, raccomandò la massima cautela, promise di tornare nella giornata. Mia madre non aveva requie. Entrando nell'alcova, io dissi a Giuliana, sotto voce, senza guardarla in viso: --Sta peggio. Non parlammo più, per lungo tempo. A quando a quando io m'alzavo e andavo alla finestra per guardare la neve. Giravo per la camera, in preda a un'ansietà insostenibile. Giuliana teneva il capo affondato nel guanciale, stava quasi tutta nascosta sotto le coperte. Se m'avvicinavo, ella apriva gli occhi e mi dava uno sguardo rapido dove io non potevo leggere. --Hai freddo? --Sì. Ma la stanza era tiepida. Tornavo sempre alla finestra per guardare la neve, la campagna imbiancata su cui continuavano a cadere i fiocchi lenti. Erano le due dopo mezzogiorno. Che avveniva nella stanza del bambino? Nulla di straordinario, certo, perché nessuno veniva a chiamarmi. Ma l'ansietà mi cresceva così che risolsi di andare a vedere. Aprii l'uscio. --Dove vai?--mi gridò Giuliana sollevandosi sul gomito. --Vado _di là_, un momento. Vengo subito. Ella rimaneva sollevata sul gomito, pallidissima. --Non vuoi?--le chiesi. --No: resta con me. Ella non si lasciava ricadere sul guanciale. Uno strano sbigottimento le alterava il volto; i suoi occhi vagavano inquieti, come dietro a qualche ombra mobile. M'avvicinai, io stesso la riadagiai supina, le toccai la fronte, le domandai con dolcezza: --Che hai, Giuliana? --Non so. Ho paura.... --Di che? --Non so. Non ne ho colpa; sono malata; sono così. Ma i suoi occhi vagavano invece di fissarmi. --Che cerchi? Vedi qualche cosa? --No, nulla. Le toccai di nuovo la fronte. Aveva il calor naturale. Ma la mia imaginazione incominciava a turbarsi. --Vedi, non ti lascio; resto con te. Sedetti, aspettai. Lo stato del mio animo era una sospensione angosciosa nell'attesa di un evento prossimo. Io ero sicuro che qualcuno sarebbe venuto a chiamarmi. Tendevo l'orecchio a qualunque lieve strepito. Udivo di tanto in tanto sonare nella casa i campanelli. Udii il rumore sordo d'una vettura su la neve. Dissi: --Forse è il medico. Giuliana non fiatò. Aspettai. Passò un tempo indefinito. A un tratto, udii un rumore di porte che s'aprivano, un suono di passi che s'avvicinavano. Balzai in piedi. Giuliana si sollevò, nel tempo medesimo. --Che sarà? Ma io già sapevo quel che era, io sapevo perfino le parole precise che mi avrebbe dette la persona entrando. Cristina entrò. Appariva stravolta ma cercava di dissimulare la sua agitazione. Balbettò, senza avanzarsi verso di noi, rivolgendosi a me con lo sguardo: --Senta una parola, signore. Uscii dall'alcova. --Che c'è? Sotto voce, ella aggiunse: --Il bambino sta male. Corra. --Giuliana, vado di là un momento. Ti lascio Cristina. Torno subito. Uscii. Arrivai di corsa nella stanza di Raimondo. --Ah, Tullio, il bambino muore!--gridò mia madre disperata, curva su la culla.--Guardalo! Guardalo! Mi curvai anch'io su la culla. Era avvenuto un cambiamento repentino, inaspettato, inesplicabile in apparenza, spaventevole. La piccola faccia era diventata d'un colore cinereo, le labbra s'erano illividite, gli occhi s'erano come appassiti, appannati, spenti. La povera creatura pareva sotto l'azione d'un veleno violento. Mi raccontava mia madre, con la voce interrotta: --Un'ora fa, stava quasi bene. Tossiva sì, ma non aveva altro. Mi sono allontanata, ho lasciata qui Anna. Credevo di ritrovarlo addormentato. Pareva che gli fosse venuto il sonno.... Torno e lo vedo in questo stato. Sentilo: è quasi freddo! Io gli toccai la fronte, una guancia. La temperatura della pelle era in fatti diminuita. --E il medico? --Non è ancora venuto! Ho mandato a chiamarlo. --Un uomo a cavallo ci voleva. --Sì, è andato Ciriaco. --A cavallo? Sei sicura? Non c'è tempo da perdere. Non era una simulazione la mia. Ero sincero. Non potevo lasciar morire così quell'innocente, senza soccorrerlo, senza fare un tentativo per salvarlo. D'innanzi a quell'aspetto quasi cadaverico, mentre il mio delitto stava per compiersi, la pietà, il rimorso, il dolore mi afferrarono l'anima. Non ero meno smanioso di mia madre, aspettando il medico. Sonai il campanello. Si presentò un domestico. --È partito Ciriaco? --Sì, signore. --A piedi? --No, signore; in calesse. Federico sopraggiunse, ansante. --Che è accaduto? Gridò mia madre, sempre curva su la culla: --Il bambino muore! Federico accorse, guardò. --Soffoca--egli disse.--Non vedete? Non respira più. E afferrò il bambino, lo tolse dalla culla, lo sollevò, lo scosse. --No, no! Che fai? Tu l'uccidi--gridò mia madre. In quel punto la porta s'aprì e una voce annunziò: --Il medico. Entrò il dottor Jemma. --Stavo per arrivare. Ho incontrato il calesse. Che c'è? Senza aspettare la risposta, s'avvicinò a mio fratello che teneva ancora su le braccia Raimondo; glie lo levò, l'esaminò, si oscurò in viso. Disse: --Calma! Calma! Bisogna sfasciarlo. E lo posò sul letto della nutrice, aiutò mia madre a toglierlo dalle fasce. Il corpicciuolo nudo apparve. Aveva lo stesso colore cinereo del volto. Le estremità pendevano rilasciate, flosce. La mano grassa del medico palpò la pelle qua e là. --Fategli qualche cosa, dottore!--supplicava mia madre.--Salvatelo! Ma il medico pareva irresoluto. Tastò il polso, appoggiò l'orecchio sul petto, mormorò: --Un vizio del cuore.... Impossibile. Domandò: --Ma com'è sopravvenuto questo cambiamento? All'improvviso? Mia madre volle raccontargli come, ma prima di finire scoppiò a piangere. Il medico si risolse a far qualche tentativo. Cercò di scuotere il torpore in cui era immerso il bambino, cercò di eccitarlo a gridare, di produrre il vomito, di richiamare un moto respiratorio energico. Mia madre stava a guardarlo, con gli occhi sbarrati da cui sgorgavano le lacrime. --Giuliana lo sa?--mi chiese mio fratello. --No, forse no.... forse ha indovinato.... forse Cristina.... Resta qui tu. Corro a vedere; poi torno. Guardai il bambino tra le mani del medico, guardai mia madre; uscii dalla stanza; corsi a Giuliana. D'innanzi alla porta mi fermai: "Che le dirò? Le dirò il vero?" Entrai, vidi che Cristina era nel vano della finestra; mi presentai nell'alcova, che le cortine ora chiudevano. Ella stava rattratta sotto le coperte. Essendomi avvicinato, m'accorsi ch'ella tremava come nel ribrezzo della febbre. --Giuliana, vedi: sono qui. Ella si scoperse, e volse la faccia verso di me. Mi domandò sotto voce: --Vieni _di là_? --Sì. --Dimmi tutto. Io m'ero chinato su lei; e ci parlavamo da vicino, sommessamente. --Sta male. --Molto? --Sì, molto. --Muore? --Chi sa! Forse. Ella con un moto subitaneo mise fuori le braccia e mi si avviticchiò al collo. La mia guancia premeva la sua; e io la sentivo tremare, sentivo la gracilità di quel povero petto malato; e dentro mi balenavano, mentre stavo così stretto da lei, visioni della stanza lontana: vedevo gli occhi del bambino appassiti appannati opachi, le labbra livide; vedevo scorrere le lacrime di mia madre. Nessuna gioia era in quell'allacciamento. Il mio cuore era serrato; la mia anima era disperata ed era _sola_, così china su l'abisso oscuro di quell'altra anima. XLIX. Quando la sera cadde, Raimondo non viveva più. Tutti i segni d'una intossicazione acuta di acido carbonico erano in quel corpicciuolo incadaverito. La piccola faccia era livida, quasi plumbea; il naso era affilato; le labbra avevano una cupa tinta cerulea; un po' di bianco opaco s'intravedeva di sotto alle palpebre ancora semichiuse; su una coscia, presso l'inguine, appariva una chiazza rossastra. Pareva che fosse già incominciato il disfacimento, tanto era miserabile l'aspetto di quella carne infantile che poche ore innanzi tutta rosea e tenera le dita di mia madre avevano accarezzata. Mi rombavano negli orecchi i gridi, i singhiozzi, le parole insensate che mia madre proferiva mentre Federico e le donne la trasportavano fuori. --Nessuno lo tocchi, nessuno lo tocchi! Io voglio lavarlo, io voglio fasciarlo.... io.... Nulla più. I gridi erano cessati. Giungeva a quando a quando uno sbattere di usci. Ero là, solo. Anche il medico era nella stanza; ma io ero solo. Qualche cosa di straordinario avveniva in me; ma io non ci vedevo ancora. --Andate--mi disse il medico, dolcemente, toccandomi una spalla--andate via di qui. Andate. Io fui docile; obedii. M'allontanavo per l'andito con lentezza, quando mi sentii di nuovo toccare. Ed era Federico; e mi abbracciò. Ma io non piansi, non provai una commozione forte, non compresi le parole ch'egli proferiva. Udii però nominare Giuliana. --Conducimi da Giuliana--gli dissi. Misi il braccio sotto il suo, mi lasciai condurre come un cieco. Quando fummo dinnanzi alla porta, gli dissi: --Lasciami. Egli mi strinse forte il braccio; poi mi lasciò. Entrai solo. L. Nella notte il silenzio della casa era sepolcrale. Un lume ardeva nell'andito. Io camminavo verso quel lume, come un sonnambulo. Qualche cosa di straordinario avveniva in me; ma io non ci vedevo ancora. Mi fermai, quasi avvertito da un istinto. Un uscio era aperto: un chiarore trapelava per la tenda abbassata. Varcai la soglia; scostai la tenda; mi avanzai. La culla era nel mezzo della camera, fra quattro candele accese, parata di bianco. Mio fratello seduto da un lato, Giovanni di Scòrdio dall'altro vegliavano. La presenza del vecchio non mi recò stupore. Mi parve naturale ch'egli fosse là; non gli chiesi niente; non dissi niente. Credo che un poco sorrisi a loro che mi guardavano. Non so veramente se le mie labbra sorrisero, ma io n'ebbi intenzione come per significare: "Non vi prendete pena di me, non cercate di consolarmi. Vedete: io sono calmo. Possiamo tacere." Feci qualche passo; andai a mettermi a piè della culla, tra le due candele; portai a piè della culla la mia anima pavida umile debole, interamente orbata della sua vista primitiva. Mio fratello e il vecchio erano ancora là, ma io ero solo. Il morticino era vestito di bianco: della stessa veste battesimale, o mi parve. Il viso e le mani soltanto erano scoperti. La piccola bocca, che col vagito aveva tante volte esasperato il mio odio, sotto il suggello misterioso era immobile. Il silenzio medesimo che era in quella piccola bocca era dentro di me, era intorno a me. E io guardavo, guardavo. Allora, dal silenzio, una gran luce si fece dentro di me, nel centro della mia anima. _Io compresi._ La parola di mio fratello, il sorriso del vecchio non avevano potuto rivelarmi quel che mi rivelò in un attimo la piccola bocca muta dell'Innocente. _Io compresi_. E allora m'assalì un terribile bisogno di confessare il mio delitto, di palesare il mio segreto, d'affermare al conspetto di quei due uomini:--Io l'ho ucciso. Ambedue mi guardavano; e io m'accorsi che ambedue erano ansiosi per me, per la mia attitudine d'innanzi al cadavere, che ambedue aspettavano la fine di quella mia immobilità ansiosi. Dissi allora: --Sapete voi chi ha ucciso quest'innocente? La voce nel silenzio ebbe un suono così strano che parve irriconoscibile anche a me medesimo; mi parve che non fosse mia. E un terrore subitaneo m'agghiacciò il sangue, m'irrigidì la lingua, m'oscurò la vista. E mi misi a tremare. E sentii che mio fratello mi sorreggeva, mi toccava la fronte. Avevo negli orecchi un rombo così forte che le sue parole mi giungevano indistinte, interrotte. Compresi ch'egli mi credeva perturbato da un parosismo febrile e che cercava di condurmi via. Mi lasciai condurre. Mi condusse alla mia stanza sorreggendomi. Il terrore mi teneva ancora. Vedendo una candela che ardeva sola su un tavolo, trasalii. Non mi ricordavo d'averla lasciata accesa. --Spògliati, mettiti a letto--mi disse Federico, traendomi con tenerezza per le mani. Mi fece sedere sul letto, mi toccò di nuovo la fronte. --Senti? La febbre ti cresce. Cominciati a spogliare. Su, via! Con una tenerezza che mi ricordava quella di mia madre, egli mi aiutava a svestirmi. Mi aiutò a coricarmi. Seduto al mio capezzale, mi toccava a quando a quando la fronte per sentire la mia febbre; mi domandava, sentendomi ancora tremare: --Hai molto freddo? Non ti cessano i brividi? Vuoi che ti copra meglio? Hai sete? Io consideravo, rabbrividendo: "Se avessi parlato! Se avessi potuto continuare! Sono stato proprio io, con le mie labbra, che ho pronunziato quelle parole? Sono stato proprio io? E se Federico, ripensando, riflettendo, fosse preso da un dubbio? Ho domandato:--Sapete voi chi ha ucciso quest'innocente?--e null'altro. Ma non avevo io l'aspetto d'un assassino confesso? Ripensando, Federico dovrà certo chiedersi:--Che voleva egli intendere? Contro chi andava la sua strana accusa?--E la mia esaltazione gli sembrerà oscura. Il medico!.... Bisognerebbe ch'egli pensasse:--Ha voluto alludere al medico, forse.--E bisognerebbe ch'egli avesse qualche altra prova della mia esaltazione, ch'egli seguitasse a credermi perturbato dalla febbre, in uno stato di delirio intermittente." Mentre così ragionavo, imagini rapide e lucide mi attraversavano lo spirito e avevano un'evidenza di cose reali, tangibili: "Ho la febbre, e alta. Se sopravvenisse il vero delirio e inconscio io rivelassi il segreto!" Mi sorvegliavo con un'ansietà paurosa. Dissi: --Il medico, il medico.... non ha saputo.... Mio fratello si chinò su di me, mi toccò di nuovo, inquietamente, sospirando. --Non ti tormentare, Tullio. Càlmati. E andò a bagnare una pezzuola nell'acqua fredda, me la mise su la fronte che ardeva. Il passaggio delle imagini rapide e lucide continuava. Rivedevo, con una terribile intensità di visione, l'agonia del bambino.--Era là agonizzante, nella culla. Aveva il viso cinereo, d'un colore così smorto che su i sopraccigli le croste del lattime parevano gialle. Il suo labbro inferiore depresso non si vedeva più. Di tratto in tratto egli sollevava le palpebre divenute un po' violette e sembrava che le iridi vi aderissero perché le seguivano nel sollevarsi e vi si perdevano sotto mentre appariva il bianco opaco. Il rantolo fioco di tratto in tratto cessava. A un certo punto, il medico diceva, come per un ultimo tentativo: --Su, su, trasportiamo la culla vicino alla finestra, alla luce. Largo, largo! Il bambino ha bisogno di aria. Largo! Io e mio fratello trasportavamo la culla che pareva una bara. Ma alla luce lo spettacolo era più atroce: a quella fredda luce candida della neve diffusa. E mia madre: --Ecco muore! Vedete, vedete: muore! Sentite: non ha più polso. E il medico: --No, no. Respira. Finché c'è fiato, c'è speranza. Coraggio! E introduceva tra le labbra livide del morente un cucchiaino d'etere. Dopo qualche attimo, il morente riapriva gli occhi, torceva in alto le pupille, metteva un vagito fioco. Avveniva una leggera mutazione nel suo colore. Le sue narici palpitavano. E il medico: --Non vedete? Respira. Fino all'ultimo non bisogna disperare. Ed agitava l'aria su la culla con un ventaglio: poi premeva con un dito il mento del bambino per abbassargli il labbro, per aprirgli la bocca. La lingua, che era aderente al palato, si abbassava come una valvoletta; e io intravedevo i fili del muco che si distendevano tra il palato e la lingua, la materia biancastra accumulata nel fondo. Un moto convulso rialzava verso il viso quelle piccole piccole mani divenute violette specialmente nella palma, nelle piegature delle falangi, nelle unghie; quelle mani già incadaverite che mia madre toccava ad ogni momento. Nella destra il mignolo stava sempre discosto dalle altre dita e aveva un lieve tremito all'aria; e nulla era più straziante. Federico cercava di persuadere mia madre a uscire dalla stanza. Ma ella si chinava sul viso di Raimondo, fin quasi a toccarlo; spiava ogni segno. Una delle sue lacrime cadeva sul capo adorato. Ella subito l'asciugava col fazzoletto, ma s'accorgeva che nel cranio la fontanella s'era abbassata, era divenuta cava. --Guardate, dottore!--gridava esterrefatta. E i miei occhi si fissavano su quel cranio molle, sparso di crosta lattea, giallognolo, simile a un pezzo di cera segnata nel mezzo da un incavo. Tutte le suture erano visibili. La vena temporale, cerulea, si perdeva sotto la crosta. --Guardate! Guardate! La lieve reviviscenza fittizia provocata dall'etere si spegneva. Il rantolo aveva ora un suono particolare. Le manine cadevano lungo i fianchi, inerti; il mento si faceva più depresso; la fontanella si faceva più profonda, senza alcun palpito. E a un tratto il morente dava segno d'uno sforzo; il dottore subito gli sollevava il capo. E usciva dalla boccuccia paonazza un po' di liquido biancastro. Ma nello sforzo del vomito la pelle della fronte tendendosi, apparivano a traverso la cute le macchie scure della stasi. Mia madre gittava un grido. --Andiamo, andiamo. Vieni via con me--le ripeteva mio fratello, tentando di trascinarla. --No, no, no. E il medico dava un altro cucchiaino di etere. E l'agonia si prolungava, e lo strazio si prolungava. Le manine si risollevavano ancora, le dita si movevano vagamente; tra le palpebre socchiuse le iridi apparivano e sparivano ritraendosi come due fiorellini appassiti, come due piccole corolle che si richiudessero flosce raggrinzandosi. Cadeva la sera, innanzi all'agonia dell'Innocente. Su i vetri della finestra era come un chiarore d'alba; ed era l'alba che saliva dalla neve in contro alle ombre. --È morto? È morto?--gridava mia madre, non udendo più il rantolo, vedendo apparire intorno al naso un lividore. --No, no; respira. Avevano accesa una candela; e la reggeva una delle donne; e la fiammella gialla oscillava a piè della culla. Mia madre subitamente scopriva il corpicciuolo per palparlo. --È freddo, tutto freddo! Le gambe s'erano affloscite, i piedini erano diventati paonazzi. Nulla era più miserevole di quello straccetto di carne morta, d'avanti a quella finestra su cui cadeva l'ombra, al lume di quella candela. Ma ancora un suono indescrivibile, che non era un vagito né un grido né un rantolo, esciva dalla boccuccia quasi cerulea, insieme con un po' di bava bianchiccia. E mia madre, come una pazza, si gittava sul morticino.-- Così rivedevo tutto, a occhi chiusi; aprivo gli occhi, e rivedevo tutto ancora, con una intensità incredibile. --Quella candela! Leva quella candela!--gridai a Federico, sollevandomi sul letto, atterrito dalla mobilità della fiammella pallida.--Leva quella candela! Federico andò a prenderla, andò a metterla dietro un paravento. Poi tornò al mio capezzale; mi fece ricoricare; mi mutò la pezzuola fredda su la fronte. E a quando a quando, nel silenzio, udivo il suo sospiro. LI. Il giorno dopo, se bene io fossi in uno stato di estrema debolezza e di stupore, volli assistere alla benedizione del parroco, al trasporto, a tutto il rito. Il cadaverino era già chiuso in una cassetta bianca, ricoperta da un cristallo. Aveva su la fronte una corona di crisantemi bianchi, aveva un crisantemo bianco tra le mani congiunte, ma nulla eguagliava la bianchezza cerea di quelle mani esigue ove soltanto le unghie erano rimaste violette. Eravamo presenti io e Federico e Giovanni di Scòrdio e alcuni famigliari. I quattro ceri ardevano lacrimando. Entrò il prete con la stola bianca, seguito dai chierici che portavano l'aspersorio e la croce senz'asta. Tutti c'inginocchiammo. Il prete asperse d'acqua benedetta il feretro dicendo: --_Sit nomen Domini...._ Poi recitò il salmo: --_Laudate pueri Dominum...._ Federico e Giovanni di Scòrdio si sollevarono, presero la bara. Pietro apriva d'innanzi a loro le porte. Io li seguivo. Dietro di me venivano il prete, i chierici, quattro familiari con i ceri accesi. Passando per gli anditi silenziosi, giungemmo alla cappella, mentre il prete recitava il salmo: --_Beati immaculati...._ Come la bara fu dentro la cappella, il prete disse: --_Hic accipiet benedictionem a Domino...._ Federico e il vecchio deposero la bara sul piccolo catafalco, in mezzo alla cappella. Tutti c'inginocchiammo. Il prete recitò altri salmi. Quindi fece l'invocazione perché l'anima dell'Innocente fosse chiamata al cielo. Quindi asperse di nuovo la bara con acqua benedetta. Uscì, seguito dai chierici. Allora ci sollevammo. Tutto era già pronto per la sepoltura. Giovanni di Scòrdio prese la cassa leggiera su le sue braccia; e i suoi occhi si fissarono sul cristallo. Federico scese pel primo nel sotterraneo, dietro di lui scese il vecchio portando la cassa; poi scesi io con un familiare. Nessuno parlava. La camera sepolcrale era ampia, tutta di pietra grigia. Nelle pareti erano scavate le nicchie, talune già chiuse da lapidi, altre aperte, profonde, occupate dall'ombra, aspettanti. Da un arco pendevano tre lampade, nutrite d'olio d'oliva; e ardevano quiete nell'aria umida e grave, con fiammelle tenui ed inestinguibili. Mio fratello disse: --Qui. E indicò una nicchia che si apriva sotto un'altra già chiusa da una lapide. Su quella lapide era inciso il nome di Costanza; e vagamente le lettere rilucevano. Allora Giovanni di Scòrdio tese le braccia su cui posava la cassa, perché noi guardassimo ancora una volta il morticino. E noi guardammo. A traverso il cristallo quel piccolo viso livido, quelle piccole mani congiunte, e quella veste e quei crisantemi e tutte quelle cose bianche parevano indefinitamente lontani, intangibili, quasi che il coperchio diafano di quella cassa su le braccia di quel gran vecchio lasciasse intravedere come per uno spiracolo un lembo d'un mistero soprannaturale tremendo e dolce. Nessuno parlava. Quasi pareva che nessuno respirasse più. Il vecchio si volse alla nicchia mortuaria, si curvò, depose la cassa, la spinse adagio verso il fondo. Poi s'inginocchiò e rimase per alcuni minuti immobile. Vagamente biancheggiava al fondo la cassa deposta. Sotto le lampade la canizie del vecchio era luminosa, così china sul limitare dell'Ombra. _Convento di Santa Maggiore. Francavilla al mare: Aprile--luglio 1891._ FINE. NOTA DEL TRASCRITTORE: Nel libro viene usato l'accento acuto sulla e finale, in contrasto colla prassi dell'epoca. In alcune pagine il tipografo si è confuso ed ha usato la prassi corrente ("perchè") o ha ecceduto, usando É come terza persona del verbo essere. Tali errori sono stati conservati senza menzione. Alcuni refusi sono stati corretti, anche in conformità delle altre occorrenze: ORIGINALE CORREZIONE di grazia feminile di grazia femminile intrapresa? Se Giuliana intrapresa? "Se Giuliana "Perché poggiare tutto l'edifizio Perché poggiare tutto l'edifizio le immagini truci le imagini truci Bignava palesare tutto, Bisognava palesare tutto, Ah, ma la notte che viene --Ah, ma la notte che viene ed occcupò tutto il campo ed occupò tutto il campo la femina di Montegorgo la femmina di Montegorgo --Quando se n'andò, Quando se n'andò, in generale: cosi così Cosi Così End of the Project Gutenberg EBook of L'Innocente, by Gabriele d'Annunzio *** END OF THIS PROJECT GUTENBERG EBOOK L'INNOCENTE *** ***** This file should be named 22642-8.txt or 22642-8.zip ***** This and all associated files of various formats will be found in: http://www.gutenberg.org/2/2/6/4/22642/ Produced by Mark C. Orton and the Online Distributed Proofreading Team at http://www.pgdp.net Updated editions will replace the previous one--the old editions will be renamed. Creating the works from public domain print editions means that no one owns a United States copyright in these works, so the Foundation (and you!) can copy and distribute it in the United States without permission and without paying copyright royalties. Special rules, set forth in the General Terms of Use part of this license, apply to copying and distributing Project Gutenberg-tm electronic works to protect the PROJECT GUTENBERG-tm concept and trademark. Project Gutenberg is a registered trademark, and may not be used if you charge for the eBooks, unless you receive specific permission. If you do not charge anything for copies of this eBook, complying with the rules is very easy. You may use this eBook for nearly any purpose such as creation of derivative works, reports, performances and research. They may be modified and printed and given away--you may do practically ANYTHING with public domain eBooks. Redistribution is subject to the trademark license, especially commercial redistribution. *** START: FULL LICENSE *** THE FULL PROJECT GUTENBERG LICENSE PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK To protect the Project Gutenberg-tm mission of promoting the free distribution of electronic works, by using or distributing this work (or any other work associated in any way with the phrase "Project Gutenberg"), you agree to comply with all the terms of the Full Project Gutenberg-tm License (available with this file or online at http://gutenberg.org/license). Section 1. General Terms of Use and Redistributing Project Gutenberg-tm electronic works 1.A. By reading or using any part of this Project Gutenberg-tm electronic work, you indicate that you have read, understand, agree to and accept all the terms of this license and intellectual property (trademark/copyright) agreement. If you do not agree to abide by all the terms of this agreement, you must cease using and return or destroy all copies of Project Gutenberg-tm electronic works in your possession. If you paid a fee for obtaining a copy of or access to a Project Gutenberg-tm electronic work and you do not agree to be bound by the terms of this agreement, you may obtain a refund from the person or entity to whom you paid the fee as set forth in paragraph 1.E.8. 1.B. "Project Gutenberg" is a registered trademark. It may only be used on or associated in any way with an electronic work by people who agree to be bound by the terms of this agreement. There are a few things that you can do with most Project Gutenberg-tm electronic works even without complying with the full terms of this agreement. See paragraph 1.C below. There are a lot of things you can do with Project Gutenberg-tm electronic works if you follow the terms of this agreement and help preserve free future access to Project Gutenberg-tm electronic works. See paragraph 1.E below. 1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation" or PGLAF), owns a compilation copyright in the collection of Project Gutenberg-tm electronic works. Nearly all the individual works in the collection are in the public domain in the United States. If an individual work is in the public domain in the United States and you are located in the United States, we do not claim a right to prevent you from copying, distributing, performing, displaying or creating derivative works based on the work as long as all references to Project Gutenberg are removed. Of course, we hope that you will support the Project Gutenberg-tm mission of promoting free access to electronic works by freely sharing Project Gutenberg-tm works in compliance with the terms of this agreement for keeping the Project Gutenberg-tm name associated with the work. You can easily comply with the terms of this agreement by keeping this work in the same format with its attached full Project Gutenberg-tm License when you share it without charge with others. 1.D. The copyright laws of the place where you are located also govern what you can do with this work. Copyright laws in most countries are in a constant state of change. If you are outside the United States, check the laws of your country in addition to the terms of this agreement before downloading, copying, displaying, performing, distributing or creating derivative works based on this work or any other Project Gutenberg-tm work. The Foundation makes no representations concerning the copyright status of any work in any country outside the United States. 1.E. Unless you have removed all references to Project Gutenberg: 1.E.1. The following sentence, with active links to, or other immediate access to, the full Project Gutenberg-tm License must appear prominently whenever any copy of a Project Gutenberg-tm work (any work on which the phrase "Project Gutenberg" appears, or with which the phrase "Project Gutenberg" is associated) is accessed, displayed, performed, viewed, copied or distributed: This eBook is for the use of anyone anywhere at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.org 1.E.2. If an individual Project Gutenberg-tm electronic work is derived from the public domain (does not contain a notice indicating that it is posted with permission of the copyright holder), the work can be copied and distributed to anyone in the United States without paying any fees or charges. If you are redistributing or providing access to a work with the phrase "Project Gutenberg" associated with or appearing on the work, you must comply either with the requirements of paragraphs 1.E.1 through 1.E.7 or obtain permission for the use of the work and the Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or 1.E.9. 1.E.3. If an individual Project Gutenberg-tm electronic work is posted with the permission of the copyright holder, your use and distribution must comply with both paragraphs 1.E.1 through 1.E.7 and any additional terms imposed by the copyright holder. Additional terms will be linked to the Project Gutenberg-tm License for all works posted with the permission of the copyright holder found at the beginning of this work. 1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm License terms from this work, or any files containing a part of this work or any other work associated with Project Gutenberg-tm. 1.E.5. Do not copy, display, perform, distribute or redistribute this electronic work, or any part of this electronic work, without prominently displaying the sentence set forth in paragraph 1.E.1 with active links or immediate access to the full terms of the Project Gutenberg-tm License. 1.E.6. You may convert to and distribute this work in any binary, compressed, marked up, nonproprietary or proprietary form, including any word processing or hypertext form. However, if you provide access to or distribute copies of a Project Gutenberg-tm work in a format other than "Plain Vanilla ASCII" or other format used in the official version posted on the official Project Gutenberg-tm web site (www.gutenberg.org), you must, at no additional cost, fee or expense to the user, provide a copy, a means of exporting a copy, or a means of obtaining a copy upon request, of the work in its original "Plain Vanilla ASCII" or other form. Any alternate format must include the full Project Gutenberg-tm License as specified in paragraph 1.E.1. 1.E.7. Do not charge a fee for access to, viewing, displaying, performing, copying or distributing any Project Gutenberg-tm works unless you comply with paragraph 1.E.8 or 1.E.9. 1.E.8. You may charge a reasonable fee for copies of or providing access to or distributing Project Gutenberg-tm electronic works provided that - You pay a royalty fee of 20% of the gross profits you derive from the use of Project Gutenberg-tm works calculated using the method you already use to calculate your applicable taxes. The fee is owed to the owner of the Project Gutenberg-tm trademark, but he has agreed to donate royalties under this paragraph to the Project Gutenberg Literary Archive Foundation. Royalty payments must be paid within 60 days following each date on which you prepare (or are legally required to prepare) your periodic tax returns. Royalty payments should be clearly marked as such and sent to the Project Gutenberg Literary Archive Foundation at the address specified in Section 4, "Information about donations to the Project Gutenberg Literary Archive Foundation." - You provide a full refund of any money paid by a user who notifies you in writing (or by e-mail) within 30 days of receipt that s/he does not agree to the terms of the full Project Gutenberg-tm License. You must require such a user to return or destroy all copies of the works possessed in a physical medium and discontinue all use of and all access to other copies of Project Gutenberg-tm works. - You provide, in accordance with paragraph 1.F.3, a full refund of any money paid for a work or a replacement copy, if a defect in the electronic work is discovered and reported to you within 90 days of receipt of the work. - You comply with all other terms of this agreement for free distribution of Project Gutenberg-tm works. 1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm electronic work or group of works on different terms than are set forth in this agreement, you must obtain permission in writing from both the Project Gutenberg Literary Archive Foundation and Michael Hart, the owner of the Project Gutenberg-tm trademark. Contact the Foundation as set forth in Section 3 below. 1.F. 1.F.1. Project Gutenberg volunteers and employees expend considerable effort to identify, do copyright research on, transcribe and proofread public domain works in creating the Project Gutenberg-tm collection. Despite these efforts, Project Gutenberg-tm electronic works, and the medium on which they may be stored, may contain "Defects," such as, but not limited to, incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or damaged disk or other medium, a computer virus, or computer codes that damage or cannot be read by your equipment. 1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right of Replacement or Refund" described in paragraph 1.F.3, the Project Gutenberg Literary Archive Foundation, the owner of the Project Gutenberg-tm trademark, and any other party distributing a Project Gutenberg-tm electronic work under this agreement, disclaim all liability to you for damages, costs and expenses, including legal fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE. 1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a defect in this electronic work within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending a written explanation to the person you received the work from. If you received the work on a physical medium, you must return the medium with your written explanation. The person or entity that provided you with the defective work may elect to provide a replacement copy in lieu of a refund. If you received the work electronically, the person or entity providing it to you may choose to give you a second opportunity to receive the work electronically in lieu of a refund. If the second copy is also defective, you may demand a refund in writing without further opportunities to fix the problem. 1.F.4. Except for the limited right of replacement or refund set forth in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE. 1.F.5. Some states do not allow disclaimers of certain implied warranties or the exclusion or limitation of certain types of damages. If any disclaimer or limitation set forth in this agreement violates the law of the state applicable to this agreement, the agreement shall be interpreted to make the maximum disclaimer or limitation permitted by the applicable state law. The invalidity or unenforceability of any provision of this agreement shall not void the remaining provisions. 1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the trademark owner, any agent or employee of the Foundation, anyone providing copies of Project Gutenberg-tm electronic works in accordance with this agreement, and any volunteers associated with the production, promotion and distribution of Project Gutenberg-tm electronic works, harmless from all liability, costs and expenses, including legal fees, that arise directly or indirectly from any of the following which you do or cause to occur: (a) distribution of this or any Project Gutenberg-tm work, (b) alteration, modification, or additions or deletions to any Project Gutenberg-tm work, and (c) any Defect you cause. Section 2. Information about the Mission of Project Gutenberg-tm Project Gutenberg-tm is synonymous with the free distribution of electronic works in formats readable by the widest variety of computers including obsolete, old, middle-aged and new computers. It exists because of the efforts of hundreds of volunteers and donations from people in all walks of life. Volunteers and financial support to provide volunteers with the assistance they need, is critical to reaching Project Gutenberg-tm's goals and ensuring that the Project Gutenberg-tm collection will remain freely available for generations to come. In 2001, the Project Gutenberg Literary Archive Foundation was created to provide a secure and permanent future for Project Gutenberg-tm and future generations. To learn more about the Project Gutenberg Literary Archive Foundation and how your efforts and donations can help, see Sections 3 and 4 and the Foundation web page at http://www.pglaf.org. Section 3. Information about the Project Gutenberg Literary Archive Foundation The Project Gutenberg Literary Archive Foundation is a non profit 501(c)(3) educational corporation organized under the laws of the state of Mississippi and granted tax exempt status by the Internal Revenue Service. The Foundation's EIN or federal tax identification number is 64-6221541. Its 501(c)(3) letter is posted at http://pglaf.org/fundraising. Contributions to the Project Gutenberg Literary Archive Foundation are tax deductible to the full extent permitted by U.S. federal laws and your state's laws. The Foundation's principal office is located at 4557 Melan Dr. S. Fairbanks, AK, 99712., but its volunteers and employees are scattered throughout numerous locations. Its business office is located at 809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email business@pglaf.org. Email contact links and up to date contact information can be found at the Foundation's web site and official page at http://pglaf.org For additional contact information: Dr. Gregory B. Newby Chief Executive and Director gbnewby@pglaf.org Section 4. Information about Donations to the Project Gutenberg Literary Archive Foundation Project Gutenberg-tm depends upon and cannot survive without wide spread public support and donations to carry out its mission of increasing the number of public domain and licensed works that can be freely distributed in machine readable form accessible by the widest array of equipment including outdated equipment. Many small donations ($1 to $5,000) are particularly important to maintaining tax exempt status with the IRS. The Foundation is committed to complying with the laws regulating charities and charitable donations in all 50 states of the United States. Compliance requirements are not uniform and it takes a considerable effort, much paperwork and many fees to meet and keep up with these requirements. We do not solicit donations in locations where we have not received written confirmation of compliance. To SEND DONATIONS or determine the status of compliance for any particular state visit http://pglaf.org While we cannot and do not solicit contributions from states where we have not met the solicitation requirements, we know of no prohibition against accepting unsolicited donations from donors in such states who approach us with offers to donate. International donations are gratefully accepted, but we cannot make any statements concerning tax treatment of donations received from outside the United States. U.S. laws alone swamp our small staff. Please check the Project Gutenberg Web pages for current donation methods and addresses. Donations are accepted in a number of other ways including checks, online payments and credit card donations. To donate, please visit: http://pglaf.org/donate Section 5. General Information About Project Gutenberg-tm electronic works. Professor Michael S. Hart is the originator of the Project Gutenberg-tm concept of a library of electronic works that could be freely shared with anyone. For thirty years, he produced and distributed Project Gutenberg-tm eBooks with only a loose network of volunteer support. Project Gutenberg-tm eBooks are often created from several printed editions, all of which are confirmed as Public Domain in the U.S. unless a copyright notice is included. Thus, we do not necessarily keep eBooks in compliance with any particular paper edition. Most people start at our Web site which has the main PG search facility: http://www.gutenberg.org This Web site includes information about Project Gutenberg-tm, including how to make donations to the Project Gutenberg Literary Archive Foundation, how to help produce our new eBooks, and how to subscribe to our email newsletter to hear about new eBooks. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/Makefile.in�����������������������������������������������������������������0000644�0001750�0001750�00000056066�11763440355�014202� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = resources DIST_COMMON = $(dist_pkgdata_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(pkgdatadir)" DATA = $(dist_pkgdata_DATA) $(pkgdata_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = arpa profiles EXTRA_DIST = \ the_picture_of_dorian_gray.txt \ l_innocente.txt \ el_quijote.txt \ abbreviations_en.txt \ abbreviations_it.txt \ presage.svg dist_pkgdata_DATA = \ presage.png \ presage.xpm \ presage.svg \ abbreviations_en.txt \ abbreviations_it.txt @USE_SQLITE_TRUE@BUILT_SOURCES = database_en.db \ @USE_SQLITE_TRUE@ database_it.db \ @USE_SQLITE_TRUE@ database_es.db # Clean out files created during tests. # Required to make distcheck happy. @USE_SQLITE_TRUE@DISTCLEANFILES = database_en.db \ @USE_SQLITE_TRUE@ database_it.db \ @USE_SQLITE_TRUE@ database_es.db @USE_SQLITE_TRUE@pkgdata_DATA = database_en.db \ @USE_SQLITE_TRUE@ database_it.db \ @USE_SQLITE_TRUE@ database_es.db all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu resources/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu resources/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_pkgdataDATA: $(dist_pkgdata_DATA) @$(NORMAL_INSTALL) test -z "$(pkgdatadir)" || $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done uninstall-dist_pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgdatadir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgdatadir)" && rm -f $$files install-pkgdataDATA: $(pkgdata_DATA) @$(NORMAL_INSTALL) test -z "$(pkgdatadir)" || $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done uninstall-pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgdatadir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgdatadir)" && rm -f $$files # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_pkgdataDATA install-pkgdataDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_pkgdataDATA uninstall-pkgdataDATA .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \ ctags-recursive install install-am install-strip \ tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_pkgdataDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-pkgdataDATA install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-dist_pkgdataDATA \ uninstall-pkgdataDATA @USE_SQLITE_TRUE@database_it.db: l_innocente.txt @USE_SQLITE_TRUE@ @rm -f $@ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 1 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 2 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 3 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@database_en.db: the_picture_of_dorian_gray.txt @USE_SQLITE_TRUE@ @rm -f $@ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 1 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 2 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 3 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@database_es.db: el_quijote.txt @USE_SQLITE_TRUE@ @rm -f $@ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 1 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 2 -l -f sqlite -o $@ $^ @USE_SQLITE_TRUE@ @$(top_builddir)/src/tools/text2ngram -n 3 -l -f sqlite -o $@ $^ # 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: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������presage-0.8.8/resources/presage.svg�����������������������������������������������������������������0000644�0001750�0001750�00000007655�11737142176�014305� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="744.09448819" height="1052.3622047" id="svg2" sodipodi:version="0.32" inkscape:version="0.47 r22583" sodipodi:docname="presage.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.1"> <title id="title2819">presage image/svg+xml presage Matteo Vescovi presage, the intelligent predictive text entry system presage predictive text entry presage-0.8.8/resources/arpa/0000755000175000017500000000000011764714756013135 500000000000000presage-0.8.8/resources/arpa/Makefile.am0000644000175000017500000000400511737142176015077 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if BUILD_ARPA_NGRAM BUILT_SOURCES = \ arpa_en.vocab \ arpa_en.arpa \ arpa_it.vocab \ arpa_it.arpa arpa_en.vocab: ../the_picture_of_dorian_gray.txt $(TEXT2WFREQ) < $< | $(WFREQ2VOCAB) -top 20000 > $@ arpa_en.idngram: ../the_picture_of_dorian_gray.txt arpa_en.vocab $(TEXT2IDNGRAM) -n 3 -vocab arpa_en.vocab -temp . < $< > $@ arpa_en.arpa: arpa_en.idngram arpa_en.vocab $(IDNGRAM2LM) -idngram arpa_en.idngram -vocab arpa_en.vocab -arpa arpa_en.arpa arpa_it.vocab: ../the_picture_of_dorian_gray.txt $(TEXT2WFREQ) < $< | $(WFREQ2VOCAB) -top 20000 > $@ arpa_it.idngram: ../the_picture_of_dorian_gray.txt arpa_it.vocab $(TEXT2IDNGRAM) -n 3 -vocab arpa_it.vocab -temp . < $< > $@ arpa_it.arpa: arpa_it.idngram arpa_it.vocab $(IDNGRAM2LM) -idngram arpa_it.idngram -vocab arpa_it.vocab -arpa arpa_it.arpa # ${prefix}/share/${package-name} directory pkgdata_DATA = arpa_en.arpa \ arpa_en.vocab \ arpa_it.arpa \ arpa_it.vocab # Clean out files created during tests. # Required to make distcheck happy. DISTCLEANFILES = *.arpa \ *.vocab \ *.idngram endif presage-0.8.8/resources/arpa/Makefile.in0000644000175000017500000003560211763440355015116 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = resources/arpa DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(pkgdatadir)" DATA = $(pkgdata_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @BUILD_ARPA_NGRAM_TRUE@BUILT_SOURCES = \ @BUILD_ARPA_NGRAM_TRUE@ arpa_en.vocab \ @BUILD_ARPA_NGRAM_TRUE@ arpa_en.arpa \ @BUILD_ARPA_NGRAM_TRUE@ arpa_it.vocab \ @BUILD_ARPA_NGRAM_TRUE@ arpa_it.arpa # ${prefix}/share/${package-name} directory @BUILD_ARPA_NGRAM_TRUE@pkgdata_DATA = arpa_en.arpa \ @BUILD_ARPA_NGRAM_TRUE@ arpa_en.vocab \ @BUILD_ARPA_NGRAM_TRUE@ arpa_it.arpa \ @BUILD_ARPA_NGRAM_TRUE@ arpa_it.vocab # Clean out files created during tests. # Required to make distcheck happy. @BUILD_ARPA_NGRAM_TRUE@DISTCLEANFILES = *.arpa \ @BUILD_ARPA_NGRAM_TRUE@ *.vocab \ @BUILD_ARPA_NGRAM_TRUE@ *.idngram all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu resources/arpa/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu resources/arpa/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgdataDATA: $(pkgdata_DATA) @$(NORMAL_INSTALL) test -z "$(pkgdatadir)" || $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done uninstall-pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgdatadir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgdatadir)" && rm -f $$files tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgdataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-pkgdataDATA .MAKE: all check install install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-pkgdataDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ uninstall uninstall-am uninstall-pkgdataDATA @BUILD_ARPA_NGRAM_TRUE@arpa_en.vocab: ../the_picture_of_dorian_gray.txt @BUILD_ARPA_NGRAM_TRUE@ $(TEXT2WFREQ) < $< | $(WFREQ2VOCAB) -top 20000 > $@ @BUILD_ARPA_NGRAM_TRUE@arpa_en.idngram: ../the_picture_of_dorian_gray.txt arpa_en.vocab @BUILD_ARPA_NGRAM_TRUE@ $(TEXT2IDNGRAM) -n 3 -vocab arpa_en.vocab -temp . < $< > $@ @BUILD_ARPA_NGRAM_TRUE@arpa_en.arpa: arpa_en.idngram arpa_en.vocab @BUILD_ARPA_NGRAM_TRUE@ $(IDNGRAM2LM) -idngram arpa_en.idngram -vocab arpa_en.vocab -arpa arpa_en.arpa @BUILD_ARPA_NGRAM_TRUE@arpa_it.vocab: ../the_picture_of_dorian_gray.txt @BUILD_ARPA_NGRAM_TRUE@ $(TEXT2WFREQ) < $< | $(WFREQ2VOCAB) -top 20000 > $@ @BUILD_ARPA_NGRAM_TRUE@arpa_it.idngram: ../the_picture_of_dorian_gray.txt arpa_it.vocab @BUILD_ARPA_NGRAM_TRUE@ $(TEXT2IDNGRAM) -n 3 -vocab arpa_it.vocab -temp . < $< > $@ @BUILD_ARPA_NGRAM_TRUE@arpa_it.arpa: arpa_it.idngram arpa_it.vocab @BUILD_ARPA_NGRAM_TRUE@ $(IDNGRAM2LM) -idngram arpa_it.idngram -vocab arpa_it.vocab -arpa arpa_it.arpa # 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: presage-0.8.8/resources/el_quijote.txt0000644000175000017500001030663411737142176015037 00000000000000The Project Gutenberg EBook of Don Quijote, by Miguel de Cervantes Saavedra This eBook is for the use of anyone anywhere at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.net Title: Don Quijote Author: Miguel de Cervantes Saavedra Posting Date: April 27, 2010 [EBook #2000] Release Date: December, 1999 Language: Spanish Character set encoding: ISO-8859-1 *** START OF THIS PROJECT GUTENBERG EBOOK DON QUIJOTE *** Produced by an anonymous Project Gutenberg volunteer. Text file corrections and new HTML file by Joaquin Cuenca Abela. El ingenioso hidalgo don Quijote de la Mancha TASA Yo, Juan Gallo de Andrada, escribano de Cámara del Rey nuestro señor, de los que residen en su Consejo, certifico y doy fe que, habiendo visto por los señores dél un libro intitulado El ingenioso hidalgo de la Mancha, compuesto por Miguel de Cervantes Saavedra, tasaron cada pliego del dicho libro a tres maravedís y medio; el cual tiene ochenta y tres pliegos, que al dicho precio monta el dicho libro docientos y noventa maravedís y medio, en que se ha de vender en papel; y dieron licencia para que a este precio se pueda vender, y mandaron que esta tasa se ponga al principio del dicho libro, y no se pueda vender sin ella. Y, para que dello conste, di la presente en Valladolid, a veinte días del mes de deciembre de mil y seiscientos y cuatro años. Juan Gallo de Andrada. TESTIMONIO DE LAS ERRATAS Este libro no tiene cosa digna que no corresponda a su original; en testimonio de lo haber correcto, di esta fee. En el Colegio de la Madre de Dios de los Teólogos de la , en primero de diciembre de 1604 años. El licenciado Francisco Murcia de la Llana. EL REY Por cuanto por parte de vos, Miguel de Cervantes, nos fue fecha relación que habíades compuesto un libro intitulado El ingenioso hidalgo de la Mancha, el cual os había costado mucho trabajo y era muy útil y provechoso, nos pedistes y suplicastes os mandásemos dar licencia y facultad para le poder imprimir, y previlegio por el tiempo que fuésemos servidos, o como la nuestra merced fuese; lo cual visto por los del nuestro Consejo, por cuanto en el dicho libro se hicieron las diligencias que la premática últimamente por nos fecha sobre la impresión de los libros dispone, fue acordado que debíamos mandar dar esta nuestra cédula para vos, en la dicha razón; y nos tuvímoslo por bien. Por la cual, por os hacer bien y merced, os damos licencia y facultad para que vos, o la persona que vuestro poder hubiere, y no otra alguna, podáis imprimir el dicho libro, intitulado El ingenioso hidalgo de la Mancha, que desuso se hace mención, en todos estos nuestros reinos de Castilla, por tiempo y espacio de diez años, que corran y se cuenten desde el dicho día de la data desta nuestra cédula; so pena que la persona o personas que, sin tener vuestro poder, lo imprimiere o vendiere, o hiciere imprimir o vender, por el mesmo caso pierda la impresión que hiciere, con los moldes y aparejos della; y más, incurra en pena de cincuenta mil maravedís cada vez que lo contrario hiciere. La cual dicha pena sea la tercia parte para la persona que lo acusare, y la otra tercia parte para nuestra Cámara, y la otra tercia parte para el juez que lo sentenciare. Con tanto que todas las veces que hubiéredes de hacer imprimir el dicho libro, durante el tiempo de los dichos diez años, le traigáis al nuestro Consejo, juntamente con el original que en él fue visto, que va rubricado cada plana y firmado al fin dél de Juan Gallo de Andrada, nuestro Escribano de Cámara, de los que en él residen, para saber si la dicha impresión está conforme el original; o traigáis fe en pública forma de cómo por corretor nombrado por nuestro mandado, se vio y corrigió la dicha impresión por el original, y se imprimió conforme a él, y quedan impresas las erratas por él apuntadas, para cada un libro de los que así fueren impresos, para que se tase el precio que por cada volume hubiéredes de haber. Y mandamos al impresor que así imprimiere el dicho libro, no imprima el principio ni el primer pliego dél, ni entregue más de un solo libro con el original al autor, o persona a cuya costa lo imprimiere, ni otro alguno, para efeto de la dicha correción y tasa, hasta que antes y primero el dicho libro esté corregido y tasado por los del nuestro Consejo; y, estando hecho, y no de otra manera, pueda imprimir el dicho principio y primer pliego, y sucesivamente ponga esta nuestra cédula y la aprobación, tasa y erratas, so pena de caer e incurrir en las penas contenidas en las leyes y premáticas destos nuestros reinos. Y mandamos a los del nuestro Consejo, y a otras cualesquier justicias dellos, guarden y cumplan esta nuestra cédula y lo en ella contenido. Fecha en Valladolid, a veinte y seis días del mes de setiembre de mil y seiscientos y cuatro años. YO, EL REY. Por mandado del Rey nuestro señor: Juan de Amezqueta. AL DUQUE DE BÉJAR, marqués de Gibraleón, conde de Benalcázar y Bañares, vizconde de La Puebla de Alcocer, señor de las villas de Capilla, Curiel y Burguillos En fe del buen acogimiento y honra que hace Vuestra Excelencia a toda suerte de libros, como príncipe tan inclinado a favorecer las buenas artes, mayormente las que por su nobleza no se abaten al servicio y granjerías del vulgo, he determinado de sacar a luz al Ingenioso hidalgo don Quijote de la Mancha, al abrigo del clarísimo nombre de Vuestra Excelencia, a quien, con el acatamiento que debo a tanta grandeza, suplico le reciba agradablemente en su protección, para que a su sombra, aunque desnudo de aquel precioso ornamento de elegancia y erudición de que suelen andar vestidas las obras que se componen en las casas de los hombres que saben, ose parecer seguramente en el juicio de algunos que, continiéndose en los límites de su ignorancia, suelen condenar con más rigor y menos justicia los trabajos ajenos; que, poniendo los ojos la prudencia de Vuestra Excelencia en mi buen deseo, fío que no desdeñará la cortedad de tan humilde servicio. Miguel de Cervantes Saavedra. PRÓLOGO Desocupado lector: sin juramento me podrás creer que quisiera que este libro, como hijo del entendimiento, fuera el más hermoso, el más gallardo y más discreto que pudiera imaginarse. Pero no he podido yo contravenir al orden de naturaleza; que en ella cada cosa engendra su semejante. Y así, ¿qué podrá engendrar el estéril y mal cultivado ingenio mío, sino la historia de un hijo seco, avellanado, antojadizo y lleno de pensamientos varios y nunca imaginados de otro alguno, bien como quien se engendró en una cárcel, donde toda incomodidad tiene su asiento y donde todo triste ruido hace su habitación? El sosiego, el lugar apacible, la amenidad de los campos, la serenidad de los cielos, el murmurar de las fuentes, la quietud del espíritu son grande parte para que las musas más estériles se muestren fecundas y ofrezcan partos al mundo que le colmen de maravilla y de contento. Acontece tener un padre un hijo feo y sin gracia alguna, y el amor que le tiene le pone una venda en los ojos para que no vea sus faltas, antes las juzga por discreciones y lindezas y las cuenta a sus amigos por agudezas y donaires. Pero yo, que, aunque parezco padre, soy padrastro de Don Quijote, no quiero irme con la corriente del uso, ni suplicarte, casi con las lágrimas en los ojos, como otros hacen, lector carísimo, que perdones o disimules las faltas que en este mi hijo vieres; y ni eres su pariente ni su amigo, y tienes tu alma en tu cuerpo y tu libre albedrío como el más pintado, y estás en tu casa, donde eres señor della, como el rey de sus alcabalas, y sabes lo que comúnmente se dice: que debajo de mi manto, al rey mato. Todo lo cual te esenta y hace libre de todo respecto y obligación; y así, puedes decir de la historia todo aquello que te pareciere, sin temor que te calunien por el mal ni te premien por el bien que dijeres della. Sólo quisiera dártela monda y desnuda, sin el ornato de prólogo, ni de la inumerabilidad y catálogo de los acostumbrados sonetos, epigramas y elogios que al principio de los libros suelen ponerse. Porque te sé decir que, aunque me costó algún trabajo componerla, ninguno tuve por mayor que hacer esta prefación que vas leyendo. Muchas veces tomé la pluma para escribille, y muchas la dejé, por no saber lo que escribiría; y, estando una suspenso, con el papel delante, la pluma en la oreja, el codo en el bufete y la mano en la mejilla, pensando lo que diría, entró a deshora un amigo mío, gracioso y bien entendido, el cual, viéndome tan imaginativo, me preguntó la causa; y, no encubriéndosela yo, le dije que pensaba en el prólogo que había de hacer a la historia de don Quijote, y que me tenía de suerte que ni quería hacerle, ni menos sacar a luz las hazañas de tan noble caballero. -Porque, ¿cómo queréis vos que no me tenga confuso el qué dirá el antiguo legislador que llaman vulgo cuando vea que, al cabo de tantos años como ha que duermo en el silencio del olvido, salgo ahora, con todos mis años a cuestas, con una leyenda seca como un esparto, ajena de invención, menguada de estilo, pobre de concetos y falta de toda erudición y doctrina; sin acotaciones en las márgenes y sin anotaciones en el fin del libro, como veo que están otros libros, aunque sean fabulosos y profanos, tan llenos de sentencias de Aristóteles, de Platón y de toda la caterva de filósofos, que admiran a los leyentes y tienen a sus autores por hombres leídos, eruditos y elocuentes? ¡Pues qué, cuando citan la Divina Escritura! No dirán sino que son unos santos Tomases y otros doctores de la Iglesia; guardando en esto un decoro tan ingenioso, que en un renglón han pintado un enamorado destraído y en otro hacen un sermoncico cristiano, que es un contento y un regalo oílle o leelle. De todo esto ha de carecer mi libro, porque ni tengo qué acotar en el margen, ni qué anotar en el fin, ni menos sé qué autores sigo en él, para ponerlos al principio, como hacen todos, por las letras del A.B.C., comenzando en Aristóteles y acabando en Xenofonte y en Zoílo o Zeuxis, aunque fue maldiciente el uno y pintor el otro. También ha de carecer mi libro de sonetos al principio, a lo menos de sonetos cuyos autores sean duques, marqueses, condes, obispos, damas o poetas celebérrimos; aunque, si yo los pidiese a dos o tres oficiales amigos, yo sé que me los darían, y tales, que no les igualasen los de aquellos que tienen más nombre en nuestra España. En fin, señor y amigo mío -proseguí-, yo determino que el señor don Quijote se quede sepultado en sus archivos en la Mancha, hasta que el cielo depare quien le adorne de tantas cosas como le faltan; porque yo me hallo incapaz de remediarlas, por mi insuficiencia y pocas letras, y porque naturalmente soy poltrón y perezoso de andarme buscando autores que digan lo que yo me sé decir sin ellos. De aquí nace la suspensión y elevamiento, amigo, en que me hallastes; bastante causa para ponerme en ella la que de mí habéis oído. Oyendo lo cual mi amigo, dándose una palmada en la frente y disparando en una carga de risa, me dijo: -Por Dios, hermano, que agora me acabo de desengañar de un engaño en que he estado todo el mucho tiempo que ha que os conozco, en el cual siempre os he tenido por discreto y prudente en todas vuestras aciones. Pero agora veo que estáis tan lejos de serlo como lo está el cielo de la tierra. ¿Cómo que es posible que cosas de tan poco momento y tan fáciles de remediar puedan tener fuerzas de suspender y absortar un ingenio tan maduro como el vuestro, y tan hecho a romper y atropellar por otras dificultades mayores? A la fe, esto no nace de falta de habilidad, sino de sobra de pereza y penuria de discurso. ¿Queréis ver si es verdad lo que digo? Pues estadme atento y veréis cómo, en un abrir y cerrar de ojos, confundo todas vuestras dificultades y remedio todas las faltas que decís que os suspenden y acobardan para dejar de sacar a la luz del mundo la historia de vuestro famoso don Quijote, luz y espejo de toda la caballería andante. -Decid -le repliqué yo, oyendo lo que me decía-: ¿de qué modo pensáis llenar el vacío de mi temor y reducir a claridad el caos de mi confusión? A lo cual él dijo: -Lo primero en que reparáis de los sonetos, epigramas o elogios que os faltan para el principio, y que sean de personajes graves y de título, se puede remediar en que vos mesmo toméis algún trabajo en hacerlos, y después los podéis bautizar y poner el nombre que quisiéredes, ahijándolos al Preste Juan de las Indias o al Emperador de Trapisonda, de quien yo sé que hay noticia que fueron famosos poetas; y cuando no lo hayan sido y hubiere algunos pedantes y bachilleres que por detrás os muerdan y murmuren desta verdad, no se os dé dos maravedís; porque, ya que os averigüen la mentira, no os han de cortar la mano con que lo escribistes. »En lo de citar en las márgenes los libros y autores de donde sacáredes las sentencias y dichos que pusiéredes en vuestra historia, no hay más sino hacer, de manera que venga a pelo, algunas sentencias o latines que vos sepáis de memoria, o, a lo menos, que os cuesten poco trabajo el buscalle; como será poner, tratando de libertad y cautiverio: Non bene pro toto libertas venditur auro. Y luego, en el margen, citar a Horacio, o a quien lo dijo. Si tratáredes del poder de la muerte, acudir luego con: Pallida mors aequo pulsat pede pauperum tabernas, Regumque turres. Si de la amistad y amor que Dios manda que se tenga al enemigo, entraros luego al punto por la Escritura Divina, que lo podéis hacer con tantico de curiosidad, y decir las palabras, por lo menos, del mismo Dios: Ego autem dico vobis: diligite inimicos vestros. Si tratáredes de malos pensamientos, acudid con el Evangelio: De corde exeunt cogitationes malae. Si de la instabilidad de los amigos, ahí está Catón, que os dará su dístico: Donec eris felix, multos numerabis amicos, tempora si fuerint nubila, solus eris. Y con estos latinicos y otros tales os tendrán siquiera por gramático, que el serlo no es de poca honra y provecho el día de hoy. »En lo que toca el poner anotaciones al fin del libro, seguramente lo podéis hacer desta manera: si nombráis algún gigante en vuestro libro, hacelde que sea el gigante Golías, y con sólo esto, que os costará casi nada, tenéis una grande anotación, pues podéis poner: El gigante Golías, o Goliat, fue un filisteo a quien el pastor David mató de una gran pedrada en el valle de Terebinto, según se cuenta en el Libro de los Reyes, en el capítulo que vos halláredes que se escribe. Tras esto, para mostraros hombre erudito en letras humanas y cosmógrafo, haced de modo como en vuestra historia se nombre el río Tajo, y veréisos luego con otra famosa anotación, poniendo: El río Tajo fue así dicho por un rey de las Españas; tiene su nacimiento en tal lugar y muere en el mar océano, besando los muros de la famosa ciudad de Lisboa; y es opinión que tiene las arenas de oro, etc. Si tratáredes de ladrones, yo os diré la historia de Caco, que la sé de coro; si de mujeres rameras, ahí está el obispo de Mondoñedo, que os prestará a Lamia, Laida y Flora, cuya anotación os dará gran crédito; si de crueles, Ovidio os entregará a Medea; si de encantadores y hechiceras, Homero tiene a Calipso, y Virgilio a Circe; si de capitanes valerosos, el mesmo Julio César os prestará a sí mismo en sus Comentarios, y Plutarco os dará mil Alejandros. Si tratáredes de amores, con dos onzas que sepáis de la lengua toscana, toparéis con León Hebreo, que os hincha las medidas. Y si no queréis andaros por tierras extrañas, en vuestra casa tenéis a Fonseca, Del amor de Dios, donde se cifra todo lo que vos y el más ingenioso acertare a desear en tal materia. En resolución, no hay más sino que vos procuréis nombrar estos nombres, o tocar estas historias en la vuestra, que aquí he dicho, y dejadme a mí el cargo de poner las anotaciones y acotaciones; que yo os voto a tal de llenaros las márgenes y de gastar cuatro pliegos en el fin del libro. »Vengamos ahora a la citación de los autores que los otros libros tienen, que en el vuestro os faltan. El remedio que esto tiene es muy fácil, porque no habéis de hacer otra cosa que buscar un libro que los acote todos, desde la A hasta la Z, como vos decís. Pues ese mismo abecedario pondréis vos en vuestro libro; que, puesto que a la clara se vea la mentira, por la poca necesidad que vos teníades de aprovecharos dellos, no importa nada; y quizá alguno habrá tan simple, que crea que de todos os habéis aprovechado en la simple y sencilla historia vuestra; y, cuando no sirva de otra cosa, por lo menos servirá aquel largo catálogo de autores a dar de improviso autoridad al libro. Y más, que no habrá quien se ponga a averiguar si los seguistes o no los seguistes, no yéndole nada en ello. Cuanto más que, si bien caigo en la cuenta, este vuestro libro no tiene necesidad de ninguna cosa de aquellas que vos decís que le falta, porque todo él es una invectiva contra los libros de caballerías, de quien nunca se acordó Aristóteles, ni dijo nada San Basilio, ni alcanzó Cicerón; ni caen debajo de la cuenta de sus fabulosos disparates las puntualidades de la verdad, ni las observaciones de la astrología; ni le son de importancia las medidas geométricas, ni la confutación de los argumentos de quien se sirve la retórica; ni tiene para qué predicar a ninguno, mezclando lo humano con lo divino, que es un género de mezcla de quien no se ha de vestir ningún cristiano entendimiento. Sólo tiene que aprovecharse de la imitación en lo que fuere escribiendo; que, cuanto ella fuere más perfecta, tanto mejor será lo que se escribiere. Y, pues esta vuestra escritura no mira a más que a deshacer la autoridad y cabida que en el mundo y en el vulgo tienen los libros de caballerías, no hay para qué andéis mendigando sentencias de filósofos, consejos de la Divina Escritura, fábulas de poetas, oraciones de retóricos, milagros de santos, sino procurar que a la llana, con palabras significantes, honestas y bien colocadas, salga vuestra oración y período sonoro y festivo; pintando, en todo lo que alcanzáredes y fuere posible, vuestra intención, dando a entender vuestros conceptos sin intricarlos y escurecerlos. Procurad también que, leyendo vuestra historia, el melancólico se mueva a risa, el risueño la acreciente, el simple no se enfade, el discreto se admire de la invención, el grave no la desprecie, ni el prudente deje de alabarla. En efecto, llevad la mira puesta a derribar la máquina mal fundada destos caballerescos libros, aborrecidos de tantos y alabados de muchos más; que si esto alcanzásedes, no habríades alcanzado poco. Con silencio grande estuve escuchando lo que mi amigo me decía, y de tal manera se imprimieron en mí sus razones que, sin ponerlas en disputa, las aprobé por buenas y de ellas mismas quise hacer este prólogo; en el cual verás, lector suave, la discreción de mi amigo, la buena ventura mía en hallar en tiempo tan necesitado tal consejero, y el alivio tuyo en hallar tan sincera y tan sin revueltas la historia del famoso don Quijote de la Mancha, de quien hay opinión, por todos los habitadores del distrito del campo de Montiel, que fue el más casto enamorado y el más valiente caballero que de muchos años a esta parte se vio en aquellos contornos. Yo no quiero encarecerte el servicio que te hago en darte a conocer tan noble y tan honrado caballero, pero quiero que me agradezcas el conocimiento que tendrás del famoso Sancho Panza, su escudero, en quien, a mi parecer, te doy cifradas todas las gracias escuderiles que en la caterva de los libros vanos de caballerías están esparcidas. Y con esto, Dios te dé salud, y a mí no olvide. Vale. AL LIBRO DE DON QUIJOTE DE LA MANCHA Urganda la desconocida Si de llegarte a los bue-, libro, fueres con letu-, no te dirá el boquirru- que no pones bien los de-. Mas si el pan no se te cue- por ir a manos de idio-, verás de manos a bo-, aun no dar una en el cla-, si bien se comen las ma- por mostrar que son curio-. Y, pues la expiriencia ense- que el que a buen árbol se arri- buena sombra le cobi-, en Béjar tu buena estre- un árbol real te ofre- que da príncipes por fru-, en el cual floreció un du- que es nuevo Alejandro Ma-: llega a su sombra, que a osa- favorece la fortu-. De un noble hidalgo manche- contarás las aventu-, a quien ociosas letu-, trastornaron la cabe-: damas, armas, caballe-, le provocaron de mo-, que, cual Orlando furio-, templado a lo enamora-, alcanzó a fuerza de bra- a Dulcinea del Tobo-. No indiscretos hieroglí- estampes en el escu-, que, cuando es todo figu-, con ruines puntos se envi-. Si en la dirección te humi-, no dirá, mofante, algu-: ''¡Qué don Ãlvaro de Lu-, qué Anibal el de Carta-, qué rey Francisco en Espa- se queja de la Fortu-!'' Pues al cielo no le plu- que salieses tan ladi- como el negro Juan Lati-, hablar latines rehú-. No me despuntes de agu-, ni me alegues con filó-, porque, torciendo la bo-, dirá el que entiende la le-, no un palmo de las ore-: ''¿Para qué conmigo flo-?'' No te metas en dibu-, ni en saber vidas aje-, que, en lo que no va ni vie-, pasar de largo es cordu-. Que suelen en caperu- darles a los que grace-; mas tú quémate las ce- sólo en cobrar buena fa-; que el que imprime neceda- dalas a censo perpe-. Advierte que es desati-, siendo de vidrio el teja-, tomar piedras en las ma- para tirar al veci-. Deja que el hombre de jui-, en las obras que compo-, se vaya con pies de plo-; que el que saca a luz pape- para entretener donce- escribe a tontas y a lo-. AMADÃS DE GAULA A DON QUIJOTE DE LA MANCHA Soneto Tú, que imitaste la llorosa vida que tuve, ausente y desdeñado sobre el gran ribazo de la Peña Pobre, de alegre a penitencia reducida; tú, a quien los ojos dieron la bebida de abundante licor, aunque salobre, y alzándote la plata, estaño y cobre, te dio la tierra en tierra la comida, vive seguro de que eternamente, en tanto, al menos, que en la cuarta esfera, sus caballos aguije el rubio Apolo, tendrás claro renombre de valiente; tu patria será en todas la primera; tu sabio autor, al mundo único y solo. DON BELIANÃS DE GRECIA A DON QUIJOTE DE LA MANCHA Soneto Rompí, corté, abollé, y dije y hice más que en el orbe caballero andante; fui diestro, fui valiente, fui arrogante; mil agravios vengué, cien mil deshice. Hazañas di a la Fama que eternice; fui comedido y regalado amante; fue enano para mí todo gigante, y al duelo en cualquier punto satisfice. Tuve a mis pies postrada la Fortuna, y trajo del copete mi cordura a la calva Ocasión al estricote. Más, aunque sobre el cuerno de la luna siempre se vio encumbrada mi ventura, tus proezas envidio, ¡oh gran Quijote! LA SEÑORA ORIANA A DULCINEA DEL TOBOSO Soneto ¡Oh, quién tuviera, hermosa Dulcinea, por más comodidad y más reposo, a Miraflores puesto en el Toboso, y trocara sus Londres con tu aldea! ¡Oh, quién de tus deseos y librea alma y cuerpo adornara, y del famoso caballero que hiciste venturoso mirara alguna desigual pelea! ¡Oh, quién tan castamente se escapara del señor Amadís como tú hiciste del comedido hidalgo don Quijote! Que así envidiada fuera, y no envidiara, y fuera alegre el tiempo que fue triste, y gozara los gustos sin escote. GANDALÃN, ESCUDERO DE AMADÃS DE GAULA, A SANCHO PANZA, ESCUDERO DE DON QUIJOTE Soneto Salve, varón famoso, a quien Fortuna, cuando en el trato escuderil te puso, tan blanda y cuerdamente lo dispuso, que lo pasaste sin desgracia alguna. Ya la azada o la hoz poco repugna al andante ejercicio; ya está en uso la llaneza escudera, con que acuso al soberbio que intenta hollar la luna. Envidio a tu jumento y a tu nombre, y a tus alforjas igualmente invidio, que mostraron tu cuerda providencia. Salve otra vez, ¡oh Sancho!, tan buen hombre, que a solo tú nuestro español Ovidio con buzcorona te hace reverencia. DEL DONOSO, POETA ENTREVERADO, A SANCHO PANZA Y ROCINANTE Soy Sancho Panza, escude- del manchego don Quijo-. Puse pies en polvoro-, por vivir a lo discre-; que el tácito Villadie- toda su razón de esta- cifró en una retira-, según siente Celesti-, libro, en mi opinión, divi- si encubriera más lo huma-. A Rocinante Soy Rocinante, el famo- bisnieto del gran Babie-. Por pecados de flaque-, fui a poder de un don Quijo-. Parejas corrí a lo flo-; mas, por uña de caba-, no se me escapó ceba-; que esto saqué a Lazari- cuando, para hurtar el vi- al ciego, le di la pa-. ORLANDO FURIOSO A DON QUIJOTE DE LA MANCHA Soneto Si no eres par, tampoco le has tenido: que par pudieras ser entre mil pares; ni puede haberle donde tú te hallares, invito vencedor, jamás vencido. Orlando soy, Quijote, que, perdido por Angélica, vi remotos mares, ofreciendo a la Fama en sus altares aquel valor que respetó el olvido. No puedo ser tu igual; que este decoro se debe a tus proezas y a tu fama, puesto que, como yo, perdiste el seso. Mas serlo has mío, si al soberbio moro y cita fiero domas, que hoy nos llama iguales en amor con mal suceso. EL CABALLERO DEL FEBO A DON QUIJOTE DE LA MANCHA Soneto A vuestra espada no igualó la mía, Febo español, curioso cortesano, ni a la alta gloria de valor mi mano, que rayo fue do nace y muere el día. Imperios desprecié; la monarquía que me ofreció el Oriente rojo en vano dejé, por ver el rostro soberano de Claridiana, aurora hermosa mía. Améla por milagro único y raro, y, ausente en su desgracia, el propio infierno temió mi brazo, que domó su rabia. Mas vos, godo Quijote, ilustre y claro, por Dulcinea sois al mundo eterno, y ella, por vos, famosa, honesta y sabia. DE SOLISDÃN A DON QUIJOTE DE LA MANCHA Soneto Maguer, señor Quijote, que sandeces vos tengan el cerbelo derrumbado, nunca seréis de alguno reprochado por home de obras viles y soeces. Serán vuesas fazañas los joeces, pues tuertos desfaciendo habéis andado, siendo vegadas mil apaleado por follones cautivos y raheces. Y si la vuesa linda Dulcinea desaguisado contra vos comete, ni a vuesas cuitas muestra buen talante, en tal desmán, vueso conorte sea que Sancho Panza fue mal alcagüete, necio él, dura ella, y vos no amante. DIÃLOGO ENTRE BABIECA Y ROCINANTE Soneto B. ¿Cómo estáis, Rocinante, tan delgado? R. Porque nunca se come, y se trabaja. B. Pues, ¿qué es de la cebada y de la paja? R. No me deja mi amo ni un bocado. B. Andá, señor, que estáis muy mal criado, pues vuestra lengua de asno al amo ultraja. R. Asno se es de la cuna a la mortaja. ¿Queréislo ver? Miraldo enamorado. B. ¿Es necedad amar? R. No es gran prudencia. B. Metafísico estáis. R. Es que no como. B. Quejaos del escudero. R. No es bastante. ¿Cómo me he de quejar en mi dolencia, si el amo y escudero o mayordomo son tan rocines como Rocinante? Primera parte del ingenioso hidalgo don Quijote de la Mancha Capítulo primero. Que trata de la condición y ejercicio del famoso hidalgo don Quijote de la Mancha En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que carnero, salpicón las más noches, duelos y quebrantos los sábados, lantejas los viernes, algún palomino de añadidura los domingos, consumían las tres partes de su hacienda. El resto della concluían sayo de velarte, calzas de velludo para las fiestas, con sus pantuflos de lo mesmo, y los días de entresemana se honraba con su vellorí de lo más fino. Tenía en su casa una ama que pasaba de los cuarenta, y una sobrina que no llegaba a los veinte, y un mozo de campo y plaza, que así ensillaba el rocín como tomaba la podadera. Frisaba la edad de nuestro hidalgo con los cincuenta años; era de complexión recia, seco de carnes, enjuto de rostro, gran madrugador y amigo de la caza. Quieren decir que tenía el sobrenombre de Quijada, o Quesada, que en esto hay alguna diferencia en los autores que deste caso escriben; aunque, por conjeturas verosímiles, se deja entender que se llamaba Quejana. Pero esto importa poco a nuestro cuento; basta que en la narración dél no se salga un punto de la verdad. Es, pues, de saber que este sobredicho hidalgo, los ratos que estaba ocioso, que eran los más del año, se daba a leer libros de caballerías, con tanta afición y gusto, que olvidó casi de todo punto el ejercicio de la caza, y aun la administración de su hacienda. Y llegó a tanto su curiosidad y desatino en esto, que vendió muchas hanegas de tierra de sembradura para comprar libros de caballerías en que leer, y así, llevó a su casa todos cuantos pudo haber dellos; y de todos, ningunos le parecían tan bien como los que compuso el famoso Feliciano de Silva, porque la claridad de su prosa y aquellas entricadas razones suyas le parecían de perlas, y más cuando llegaba a leer aquellos requiebros y cartas de desafíos, donde en muchas partes hallaba escrito: La razón de la sinrazón que a mi razón se hace, de tal manera mi razón enflaquece, que con razón me quejo de la vuestra fermosura. Y también cuando leía: ...los altos cielos que de vuestra divinidad divinamente con las estrellas os fortifican, y os hacen merecedora del merecimiento que merece la vuestra grandeza. Con estas razones perdía el pobre caballero el juicio, y desvelábase por entenderlas y desentrañarles el sentido, que no se lo sacara ni las entendiera el mesmo Aristóteles, si resucitara para sólo ello. No estaba muy bien con las heridas que don Belianís daba y recebía, porque se imaginaba que, por grandes maestros que le hubiesen curado, no dejaría de tener el rostro y todo el cuerpo lleno de cicatrices y señales. Pero, con todo, alababa en su autor aquel acabar su libro con la promesa de aquella inacabable aventura, y muchas veces le vino deseo de tomar la pluma y dalle fin al pie de la letra, como allí se promete; y sin duda alguna lo hiciera, y aun saliera con ello, si otros mayores y continuos pensamientos no se lo estorbaran. Tuvo muchas veces competencia con el cura de su lugar -que era hombre docto, graduado en Sigüenza-, sobre cuál había sido mejor caballero: Palmerín de Ingalaterra o Amadís de Gaula; mas maese Nicolás, barbero del mesmo pueblo, decía que ninguno llegaba al Caballero del Febo, y que si alguno se le podía comparar, era don Galaor, hermano de Amadís de Gaula, porque tenía muy acomodada condición para todo; que no era caballero melindroso, ni tan llorón como su hermano, y que en lo de la valentía no le iba en zaga. En resolución, él se enfrascó tanto en su letura, que se le pasaban las noches leyendo de claro en claro, y los días de turbio en turbio; y así, del poco dormir y del mucho leer, se le secó el celebro, de manera que vino a perder el juicio. Llenósele la fantasía de todo aquello que leía en los libros, así de encantamentos como de pendencias, batallas, desafíos, heridas, requiebros, amores, tormentas y disparates imposibles; y asentósele de tal modo en la imaginación que era verdad toda aquella máquina de aquellas sonadas soñadas invenciones que leía, que para él no había otra historia más cierta en el mundo. Decía él que el Cid Ruy Díaz había sido muy buen caballero, pero que no tenía que ver con el Caballero de la Ardiente Espada, que de sólo un revés había partido por medio dos fieros y descomunales gigantes. Mejor estaba con Bernardo del Carpio, porque en Roncesvalles había muerto a Roldán el encantado, valiéndose de la industria de Hércules, cuando ahogó a Anteo, el hijo de la Tierra, entre los brazos. Decía mucho bien del gigante Morgante, porque, con ser de aquella generación gigantea, que todos son soberbios y descomedidos, él solo era afable y bien criado. Pero, sobre todos, estaba bien con Reinaldos de Montalbán, y más cuando le veía salir de su castillo y robar cuantos topaba, y cuando en allende robó aquel ídolo de Mahoma que era todo de oro, según dice su historia. Diera él, por dar una mano de coces al traidor de Galalón, al ama que tenía, y aun a su sobrina de añadidura. En efeto, rematado ya su juicio, vino a dar en el más estraño pensamiento que jamás dio loco en el mundo; y fue que le pareció convenible y necesario, así para el aumento de su honra como para el servicio de su república, hacerse caballero andante, y irse por todo el mundo con sus armas y caballo a buscar las aventuras y a ejercitarse en todo aquello que él había leído que los caballeros andantes se ejercitaban, deshaciendo todo género de agravio, y poniéndose en ocasiones y peligros donde, acabándolos, cobrase eterno nombre y fama. Imaginábase el pobre ya coronado por el valor de su brazo, por lo menos, del imperio de Trapisonda; y así, con estos tan agradables pensamientos, llevado del estraño gusto que en ellos sentía, se dio priesa a poner en efeto lo que deseaba. Y lo primero que hizo fue limpiar unas armas que habían sido de sus bisabuelos, que, tomadas de orín y llenas de moho, luengos siglos había que estaban puestas y olvidadas en un rincón. Limpiólas y aderezólas lo mejor que pudo, pero vio que tenían una gran falta, y era que no tenían celada de encaje, sino morrión simple; mas a esto suplió su industria, porque de cartones hizo un modo de media celada, que, encajada con el morrión, hacían una apariencia de celada entera. Es verdad que para probar si era fuerte y podía estar al riesgo de una cuchillada, sacó su espada y le dio dos golpes, y con el primero y en un punto deshizo lo que había hecho en una semana; y no dejó de parecerle mal la facilidad con que la había hecho pedazos, y, por asegurarse deste peligro, la tornó a hacer de nuevo, poniéndole unas barras de hierro por de dentro, de tal manera que él quedó satisfecho de su fortaleza; y, sin querer hacer nueva experiencia della, la diputó y tuvo por celada finísima de encaje. Fue luego a ver su rocín, y, aunque tenía más cuartos que un real y más tachas que el caballo de Gonela, que tantum pellis et ossa fuit, le pareció que ni el Bucéfalo de Alejandro ni Babieca el del Cid con él se igualaban. Cuatro días se le pasaron en imaginar qué nombre le pondría; porque, según se decía él a sí mesmo, no era razón que caballo de caballero tan famoso, y tan bueno él por sí, estuviese sin nombre conocido; y ansí, procuraba acomodársele de manera que declarase quién había sido, antes que fuese de caballero andante, y lo que era entonces; pues estaba muy puesto en razón que, mudando su señor estado, mudase él también el nombre, y le cobrase famoso y de estruendo, como convenía a la nueva orden y al nuevo ejercicio que ya profesaba. Y así, después de muchos nombres que formó, borró y quitó, añadió, deshizo y tornó a hacer en su memoria e imaginación, al fin le vino a llamar Rocinante: nombre, a su parecer, alto, sonoro y significativo de lo que había sido cuando fue rocín, antes de lo que ahora era, que era antes y primero de todos los rocines del mundo. Puesto nombre, y tan a su gusto, a su caballo, quiso ponérsele a sí mismo, y en este pensamiento duró otros ocho días, y al cabo se vino a llamar don Quijote; de donde -como queda dicho- tomaron ocasión los autores desta tan verdadera historia que, sin duda, se debía de llamar Quijada, y no Quesada, como otros quisieron decir. Pero, acordándose que el valeroso Amadís no sólo se había contentado con llamarse Amadís a secas, sino que añadió el nombre de su reino y patria, por Hepila famosa, y se llamó Amadís de Gaula, así quiso, como buen caballero, añadir al suyo el nombre de la suya y llamarse don Quijote de la Mancha, con que, a su parecer, declaraba muy al vivo su linaje y patria, y la honraba con tomar el sobrenombre della. Limpias, pues, sus armas, hecho del morrión celada, puesto nombre a su rocín y confirmándose a sí mismo, se dio a entender que no le faltaba otra cosa sino buscar una dama de quien enamorarse; porque el caballero andante sin amores era árbol sin hojas y sin fruto y cuerpo sin alma. Decíase él a sí: -Si yo, por malos de mis pecados, o por mi buena suerte, me encuentro por ahí con algún gigante, como de ordinario les acontece a los caballeros andantes, y le derribo de un encuentro, o le parto por mitad del cuerpo, o, finalmente, le venzo y le rindo, ¿no será bien tener a quien enviarle presentado y que entre y se hinque de rodillas ante mi dulce señora, y diga con voz humilde y rendido: ''Yo, señora, soy el gigante Caraculiambro, señor de la ínsula Malindrania, a quien venció en singular batalla el jamás como se debe alabado caballero don Quijote de la Mancha, el cual me mandó que me presentase ante vuestra merced, para que la vuestra grandeza disponga de mí a su talante''? ¡Oh, cómo se holgó nuestro buen caballero cuando hubo hecho este discurso, y más cuando halló a quien dar nombre de su dama! Y fue, a lo que se cree, que en un lugar cerca del suyo había una moza labradora de muy buen parecer, de quien él un tiempo anduvo enamorado, aunque, según se entiende, ella jamás lo supo, ni le dio cata dello. Llamábase Aldonza Lorenzo, y a ésta le pareció ser bien darle título de señora de sus pensamientos; y, buscándole nombre que no desdijese mucho del suyo, y que tirase y se encaminase al de princesa y gran señora, vino a llamarla Dulcinea del Toboso, porque era natural del Toboso; nombre, a su parecer, músico y peregrino y significativo, como todos los demás que a él y a sus cosas había puesto. Capítulo II. Que trata de la primera salida que de su tierra hizo el ingenioso don Quijote Hechas, pues, estas prevenciones, no quiso aguardar más tiempo a poner en efeto su pensamiento, apretándole a ello la falta que él pensaba que hacía en el mundo su tardanza, según eran los agravios que pensaba deshacer, tuertos que enderezar, sinrazones que emendar, y abusos que mejorar y deudas que satisfacer. Y así, sin dar parte a persona alguna de su intención, y sin que nadie le viese, una mañana, antes del día, que era uno de los calurosos del mes de julio, se armó de todas sus armas, subió sobre Rocinante, puesta su mal compuesta celada, embrazó su adarga, tomó su lanza, y, por la puerta falsa de un corral, salió al campo con grandísimo contento y alborozo de ver con cuánta facilidad había dado principio a su buen deseo. Mas, apenas se vio en el campo, cuando le asaltó un pensamiento terrible, y tal, que por poco le hiciera dejar la comenzada empresa; y fue que le vino a la memoria que no era armado caballero, y que, conforme a ley de caballería, ni podía ni debía tomar armas con ningún caballero; y, puesto que lo fuera, había de llevar armas blancas, como novel caballero, sin empresa en el escudo, hasta que por su esfuerzo la ganase. Estos pensamientos le hicieron titubear en su propósito; mas, pudiendo más su locura que otra razón alguna, propuso de hacerse armar caballero del primero que topase, a imitación de otros muchos que así lo hicieron, según él había leído en los libros que tal le tenían. En lo de las armas blancas, pensaba limpiarlas de manera, en teniendo lugar, que lo fuesen más que un armiño; y con esto se quietó y prosiguió su camino, sin llevar otro que aquel que su caballo quería, creyendo que en aquello consistía la fuerza de las aventuras. Yendo, pues, caminando nuestro flamante aventurero, iba hablando consigo mesmo y diciendo: -¿Quién duda sino que en los venideros tiempos, cuando salga a luz la verdadera historia de mis famosos hechos, que el sabio que los escribiere no ponga, cuando llegue a contar esta mi primera salidad tan de mañana, desta manera?: «Apenas había el rubicundo Apolo tendido por la faz de la ancha y espaciosa tierra las doradas hebras de sus hermosos cabellos, y apenas los pequeños y pintados pajarillos con sus arpadas lenguas habían saludado con dulce y meliflua armonía la venida de la rosada aurora, que, dejando la blanda cama del celoso marido, por las puertas y balcones del manchego horizonte a los mortales se mostraba, cuando el famoso caballero don Quijote de la Mancha, dejando las ociosas plumas, subió sobre su famoso caballo Rocinante, y comenzó a caminar por el antiguo y conocido campo de Montiel». Y era la verdad que por él caminaba. Y añadió diciendo: -Dichosa edad, y siglo dichoso aquel adonde saldrán a luz las famosas hazañas mías, dignas de entallarse en bronces, esculpirse en mármoles y pintarse en tablas para memoria en lo futuro. ¡Oh tú, sabio encantador, quienquiera que seas, a quien ha de tocar el ser coronista desta peregrina historia, ruégote que no te olvides de mi buen Rocinante, compañero eterno mío en todos mis caminos y carreras! Luego volvía diciendo, como si verdaderamente fuera enamorado: -¡Oh princesa Dulcinea, señora deste cautivo corazón!, mucho agravio me habedes fecho en despedirme y reprocharme con el riguroso afincamiento de mandarme no parecer ante la vuestra fermosura. Plégaos, señora, de membraros deste vuestro sujeto corazón, que tantas cuitas por vuestro amor padece. Con éstos iba ensartando otros disparates, todos al modo de los que sus libros le habían enseñado, imitando en cuanto podía su lenguaje. Con esto, caminaba tan despacio, y el sol entraba tan apriesa y con tanto ardor, que fuera bastante a derretirle los sesos, si algunos tuviera. Casi todo aquel día caminó sin acontecerle cosa que de contar fuese, de lo cual se desesperaba, porque quisiera topar luego luego con quien hacer experiencia del valor de su fuerte brazo. Autores hay que dicen que la primera aventura que le avino fue la del Puerto Lápice; otros dicen que la de los molinos de viento; pero, lo que yo he podido averiguar en este caso, y lo que he hallado escrito en los Anales de la Mancha, es que él anduvo todo aquel día, y, al anochecer, su rocín y él se hallaron cansados y muertos de hambre; y que, mirando a todas partes por ver si descubriría algún castillo o alguna majada de pastores donde recogerse y adonde pudiese remediar su mucha hambre y necesidad, vio, no lejos del camino por donde iba, una venta, que fue como si viera una estrella que, no a los portales, sino a los alcázares de su redención le encaminaba. Diose priesa a caminar, y llegó a ella a tiempo que anochecía. Estaban acaso a la puerta dos mujeres mozas, destas que llaman del partido, las cuales iban a Sevilla con unos arrieros que en la venta aquella noche acertaron a hacer jornada; y, como a nuestro aventurero todo cuanto pensaba, veía o imaginaba le parecía ser hecho y pasar al modo de lo que había leído, luego que vio la venta, se le representó que era un castillo con sus cuatro torres y chapiteles de luciente plata, sin faltarle su puente levadiza y honda cava, con todos aquellos adherentes que semejantes castillos se pintan. Fuese llegando a la venta, que a él le parecía castillo, y a poco trecho della detuvo las riendas a Rocinante, esperando que algún enano se pusiese entre las almenas a dar señal con alguna trompeta de que llegaba caballero al castillo. Pero, como vio que se tardaban y que Rocinante se daba priesa por llegar a la caballeriza, se llegó a la puerta de la venta, y vio a las dos destraídas mozas que allí estaban, que a él le parecieron dos hermosas doncellas o dos graciosas damas que delante de la puerta del castillo se estaban solazando. En esto, sucedió acaso que un porquero que andaba recogiendo de unos rastrojos una manada de puercos -que, sin perdón, así se llaman- tocó un cuerno, a cuya señal ellos se recogen, y al instante se le representó a don Quijote lo que deseaba, que era que algún enano hacía señal de su venida; y así, con estraño contento, llegó a la venta y a las damas, las cuales, como vieron venir un hombre de aquella suerte, armado y con lanza y adarga, llenas de miedo, se iban a entrar en la venta; pero don Quijote, coligiendo por su huida su miedo, alzándose la visera de papelón y descubriendo su seco y polvoroso rostro, con gentil talante y voz reposada, les dijo: -No fuyan las vuestras mercedes ni teman desaguisado alguno; ca a la orden de caballería que profeso non toca ni atañe facerle a ninguno, cuanto más a tan altas doncellas como vuestras presencias demuestran. Mirábanle las mozas, y andaban con los ojos buscándole el rostro, que la mala visera le encubría; mas, como se oyeron llamar doncellas, cosa tan fuera de su profesión, no pudieron tener la risa, y fue de manera que don Quijote vino a correrse y a decirles: -Bien parece la mesura en las fermosas, y es mucha sandez además la risa que de leve causa procede; pero no vos lo digo porque os acuitedes ni mostredes mal talante; que el mío non es de ál que de serviros. El lenguaje, no entendido de las señoras, y el mal talle de nuestro caballero acrecentaba en ellas la risa y en él el enojo; y pasara muy adelante si a aquel punto no saliera el ventero, hombre que, por ser muy gordo, era muy pacífico, el cual, viendo aquella figura contrahecha, armada de armas tan desiguales como eran la brida, lanza, adarga y coselete, no estuvo en nada en acompañar a las doncellas en las muestras de su contento. Mas, en efeto, temiendo la máquina de tantos pertrechos, determinó de hablarle comedidamente; y así, le dijo: -Si vuestra merced, señor caballero, busca posada, amén del lecho (porque en esta venta no hay ninguno), todo lo demás se hallará en ella en mucha abundancia. Viendo don Quijote la humildad del alcaide de la fortaleza, que tal le pareció a él el ventero y la venta, respondió: -Para mí, señor castellano, cualquiera cosa basta, porque mis arreos son las armas, mi descanso el pelear, etc. Pensó el huésped que el haberle llamado castellano había sido por haberle parecido de los sanos de Castilla, aunque él era andaluz, y de los de la playa de Sanlúcar, no menos ladrón que Caco, ni menos maleante que estudiantado paje; y así, le respondió: -Según eso, las camas de vuestra merced serán duras peñas, y su dormir, siempre velar; y siendo así, bien se puede apear, con seguridad de hallar en esta choza ocasión y ocasiones para no dormir en todo un año, cuanto más en una noche. Y, diciendo esto, fue a tener el estribo a don Quijote, el cual se apeó con mucha dificultad y trabajo, como aquel que en todo aquel día no se había desayunado. Dijo luego al huésped que le tuviese mucho cuidado de su caballo, porque era la mejor pieza que comía pan en el mundo. Miróle el ventero, y no le pareció tan bueno como don Quijote decía, ni aun la mitad; y, acomodándole en la caballeriza, volvió a ver lo que su huésped mandaba, al cual estaban desarmando las doncellas, que ya se habían reconciliado con él; las cuales, aunque le habían quitado el peto y el espaldar, jamás supieron ni pudieron desencajarle la gola, ni quitalle la contrahecha celada, que traía atada con unas cintas verdes, y era menester cortarlas, por no poderse quitar los ñudos; mas él no lo quiso consentir en ninguna manera, y así, se quedó toda aquella noche con la celada puesta, que era la más graciosa y estraña figura que se pudiera pensar; y, al desarmarle, como él se imaginaba que aquellas traídas y llevadas que le desarmaban eran algunas principales señoras y damas de aquel castillo, les dijo con mucho donaire: -Nunca fuera caballero de damas tan bien servido como fuera don Quijote cuando de su aldea vino: doncellas curaban dél; princesas, del su rocino, o Rocinante, que éste es el nombre, señoras mías, de mi caballo, y don Quijote de la Mancha el mío; que, puesto que no quisiera descubrirme fasta que las fazañas fechas en vuestro servicio y pro me descubrieran, la fuerza de acomodar al propósito presente este romance viejo de Lanzarote ha sido causa que sepáis mi nombre antes de toda sazón; pero, tiempo vendrá en que las vuestras señorías me manden y yo obedezca, y el valor de mi brazo descubra el deseo que tengo de serviros. Las mozas, que no estaban hechas a oír semejantes retóricas, no respondían palabra; sólo le preguntaron si quería comer alguna cosa. -Cualquiera yantaría yo -respondió don Quijote-, porque, a lo que entiendo, me haría mucho al caso. A dicha, acertó a ser viernes aquel día, y no había en toda la venta sino unas raciones de un pescado que en Castilla llaman abadejo, y en Andalucía bacallao, y en otras partes curadillo, y en otras truchuela. Preguntáronle si por ventura comería su merced truchuela, que no había otro pescado que dalle a comer. -Como haya muchas truchuelas -respondió don Quijote-, podrán servir de una trucha, porque eso se me da que me den ocho reales en sencillos que en una pieza de a ocho. Cuanto más, que podría ser que fuesen estas truchuelas como la ternera, que es mejor que la vaca, y el cabrito que el cabrón. Pero, sea lo que fuere, venga luego, que el trabajo y peso de las armas no se puede llevar sin el gobierno de las tripas. Pusiéronle la mesa a la puerta de la venta, por el fresco, y trújole el huésped una porción del mal remojado y peor cocido bacallao, y un pan tan negro y mugriento como sus armas; pero era materia de grande risa verle comer, porque, como tenía puesta la celada y alzada la visera, no podía poner nada en la boca con sus manos si otro no se lo daba y ponía; y ansí, una de aquellas señoras servía deste menester. Mas, al darle de beber, no fue posible, ni lo fuera si el ventero no horadara una caña, y puesto el un cabo en la boca, por el otro le iba echando el vino; y todo esto lo recebía en paciencia, a trueco de no romper las cintas de la celada. Estando en esto, llegó acaso a la venta un castrador de puercos; y, así como llegó, sonó su silbato de cañas cuatro o cinco veces, con lo cual acabó de confirmar don Quijote que estaba en algún famoso castillo, y que le servían con música, y que el abadejo eran truchas; el pan, candeal; y las rameras, damas; y el ventero, castellano del castillo, y con esto daba por bien empleada su determinación y salida. Mas lo que más le fatigaba era el no verse armado caballero, por parecerle que no se podría poner legítimamente en aventura alguna sin recebir la orden de caballería. Capítulo III. Donde se cuenta la graciosa manera que tuvo don Quijote en armarse caballero Y así, fatigado deste pensamiento, abrevió su venteril y limitada cena; la cual acabada, llamó al ventero, y, encerrándose con él en la caballeriza, se hincó de rodillas ante él, diciéndole: -No me levantaré jamás de donde estoy, valeroso caballero, fasta que la vuestra cortesía me otorgue un don que pedirle quiero, el cual redundará en alabanza vuestra y en pro del género humano. El ventero, que vio a su huésped a sus pies y oyó semejantes razones, estaba confuso mirándole, sin saber qué hacerse ni decirle, y porfiaba con él que se levantase, y jamás quiso, hasta que le hubo de decir que él le otorgaba el don que le pedía. -No esperaba yo menos de la gran magnificencia vuestra, señor mío -respondió don Quijote-; y así, os digo que el don que os he pedido, y de vuestra liberalidad me ha sido otorgado, es que mañana en aquel día me habéis de armar caballero, y esta noche en la capilla deste vuestro castillo velaré las armas; y mañana, como tengo dicho, se cumplirá lo que tanto deseo, para poder, como se debe, ir por todas las cuatro partes del mundo buscando las aventuras, en pro de los menesterosos, como está a cargo de la caballería y de los caballeros andantes, como yo soy, cuyo deseo a semejantes fazañas es inclinado. El ventero, que, como está dicho, era un poco socarrón y ya tenía algunos barruntos de la falta de juicio de su huésped, acabó de creerlo cuando acabó de oírle semejantes razones, y, por tener qué reír aquella noche, determinó de seguirle el humor; y así, le dijo que andaba muy acertado en lo que deseaba y pedía, y que tal prosupuesto era propio y natural de los caballeros tan principales como él parecía y como su gallarda presencia mostraba; y que él, ansimesmo, en los años de su mocedad, se había dado a aquel honroso ejercicio, andando por diversas partes del mundo buscando sus aventuras, sin que hubiese dejado los Percheles de Málaga, Islas de Riarán, Compás de Sevilla, Azoguejo de Segovia, la Olivera de Valencia, Rondilla de Granada, Playa de Sanlúcar, Potro de Córdoba y las Ventillas de Toledo y otras diversas partes, donde había ejercitado la ligereza de sus pies, sutileza de sus manos, haciendo muchos tuertos, recuestando muchas viudas, deshaciendo algunas doncellas y engañando a algunos pupilos, y, finalmente, dándose a conocer por cuantas audiencias y tribunales hay casi en toda España; y que, a lo último, se había venido a recoger a aquel su castillo, donde vivía con su hacienda y con las ajenas, recogiendo en él a todos los caballeros andantes, de cualquiera calidad y condición que fuesen, sólo por la mucha afición que les tenía y porque partiesen con él de sus haberes, en pago de su buen deseo. Díjole también que en aquel su castillo no había capilla alguna donde poder velar las armas, porque estaba derribada para hacerla de nuevo; pero que, en caso de necesidad, él sabía que se podían velar dondequiera, y que aquella noche las podría velar en un patio del castillo; que a la mañana, siendo Dios servido, se harían las debidas ceremonias, de manera que él quedase armado caballero, y tan caballero que no pudiese ser más en el mundo. Preguntóle si traía dineros; respondió don Quijote que no traía blanca, porque él nunca había leído en las historias de los caballeros andantes que ninguno los hubiese traído. A esto dijo el ventero que se engañaba; que, puesto caso que en las historias no se escribía, por haberles parecido a los autores dellas que no era menester escrebir una cosa tan clara y tan necesaria de traerse como eran dineros y camisas limpias, no por eso se había de creer que no los trujeron; y así, tuviese por cierto y averiguado que todos los caballeros andantes, de que tantos libros están llenos y atestados, llevaban bien herradas las bolsas, por lo que pudiese sucederles; y que asimismo llevaban camisas y una arqueta pequeña llena de ungüentos para curar las heridas que recebían, porque no todas veces en los campos y desiertos donde se combatían y salían heridos había quien los curase, si ya no era que tenían algún sabio encantador por amigo, que luego los socorría, trayendo por el aire, en alguna nube, alguna doncella o enano con alguna redoma de agua de tal virtud que, en gustando alguna gota della, luego al punto quedaban sanos de sus llagas y heridas, como si mal alguno hubiesen tenido. Mas que, en tanto que esto no hubiese, tuvieron los pasados caballeros por cosa acertada que sus escuderos fuesen proveídos de dineros y de otras cosas necesarias, como eran hilas y ungüentos para curarse; y, cuando sucedía que los tales caballeros no tenían escuderos, que eran pocas y raras veces, ellos mesmos lo llevaban todo en unas alforjas muy sutiles, que casi no se parecían, a las ancas del caballo, como que era otra cosa de más importancia; porque, no siendo por ocasión semejante, esto de llevar alforjas no fue muy admitido entre los caballeros andantes; y por esto le daba por consejo, pues aún se lo podía mandar como a su ahijado, que tan presto lo había de ser, que no caminase de allí adelante sin dineros y sin las prevenciones referidas, y que vería cuán bien se hallaba con ellas cuando menos se pensase. Prometióle don Quijote de hacer lo que se le aconsejaba con toda puntualidad; y así, se dio luego orden como velase las armas en un corral grande que a un lado de la venta estaba; y, recogiéndolas don Quijote todas, las puso sobre una pila que junto a un pozo estaba, y, embrazando su adarga, asió de su lanza y con gentil continente se comenzó a pasear delante de la pila; y cuando comenzó el paseo comenzaba a cerrar la noche. Contó el ventero a todos cuantos estaban en la venta la locura de su huésped, la vela de las armas y la armazón de caballería que esperaba. Admiráronse de tan estraño género de locura y fuéronselo a mirar desde lejos, y vieron que, con sosegado ademán, unas veces se paseaba; otras, arrimado a su lanza, ponía los ojos en las armas, sin quitarlos por un buen espacio dellas. Acabó de cerrar la noche, pero con tanta claridad de la luna, que podía competir con el que se la prestaba, de manera que cuanto el novel caballero hacía era bien visto de todos. Antojósele en esto a uno de los arrieros que estaban en la venta ir a dar agua a su recua, y fue menester quitar las armas de don Quijote, que estaban sobre la pila; el cual, viéndole llegar, en voz alta le dijo: -¡Oh tú, quienquiera que seas, atrevido caballero, que llegas a tocar las armas del más valeroso andante que jamás se ciñó espada!, mira lo que haces y no las toques, si no quieres dejar la vida en pago de tu atrevimiento. No se curó el arriero destas razones (y fuera mejor que se curara, porque fuera curarse en salud); antes, trabando de las correas, las arrojó gran trecho de sí. Lo cual visto por don Quijote, alzó los ojos al cielo, y, puesto el pensamiento -a lo que pareció- en su señora Dulcinea, dijo: -Acorredme, señora mía, en esta primera afrenta que a este vuestro avasallado pecho se le ofrece; no me desfallezca en este primero trance vuestro favor y amparo. Y, diciendo estas y otras semejantes razones, soltando la adarga, alzó la lanza a dos manos y dio con ella tan gran golpe al arriero en la cabeza, que le derribó en el suelo, tan maltrecho que, si segundara con otro, no tuviera necesidad de maestro que le curara. Hecho esto, recogió sus armas y tornó a pasearse con el mismo reposo que primero. Desde allí a poco, sin saberse lo que había pasado (porque aún estaba aturdido el arriero), llegó otro con la mesma intención de dar agua a sus mulos; y, llegando a quitar las armas para desembarazar la pila, sin hablar don Quijote palabra y sin pedir favor a nadie, soltó otra vez la adarga y alzó otra vez la lanza, y, sin hacerla pedazos, hizo más de tres la cabeza del segundo arriero, porque se la abrió por cuatro. Al ruido acudió toda la gente de la venta, y entre ellos el ventero. Viendo esto don Quijote, embrazó su adarga, y, puesta mano a su espada, dijo: -¡Oh señora de la fermosura, esfuerzo y vigor del debilitado corazón mío! Ahora es tiempo que vuelvas los ojos de tu grandeza a este tu cautivo caballero, que tamaña aventura está atendiendo. Con esto cobró, a su parecer, tanto ánimo, que si le acometieran todos los arrieros del mundo, no volviera el pie atrás. Los compañeros de los heridos, que tales los vieron, comenzaron desde lejos a llover piedras sobre don Quijote, el cual, lo mejor que podía, se reparaba con su adarga, y no se osaba apartar de la pila por no desamparar las armas. El ventero daba voces que le dejasen, porque ya les había dicho como era loco, y que por loco se libraría, aunque los matase a todos. También don Quijote las daba, mayores, llamándolos de alevosos y traidores, y que el señor del castillo era un follón y mal nacido caballero, pues de tal manera consentía que se tratasen los andantes caballeros; y que si él hubiera recebido la orden de caballería, que él le diera a entender su alevosía: -Pero de vosotros, soez y baja canalla, no hago caso alguno: tirad, llegad, venid y ofendedme en cuanto pudiéredes, que vosotros veréis el pago que lleváis de vuestra sandez y demasía. Decía esto con tanto brío y denuedo, que infundió un terrible temor en los que le acometían; y, así por esto como por las persuasiones del ventero, le dejaron de tirar, y él dejó retirar a los heridos y tornó a la vela de sus armas con la misma quietud y sosiego que primero. No le parecieron bien al ventero las burlas de su huésped, y determinó abreviar y darle la negra orden de caballería luego, antes que otra desgracia sucediese. Y así, llegándose a él, se desculpó de la insolencia que aquella gente baja con él había usado, sin que él supiese cosa alguna; pero que bien castigados quedaban de su atrevimiento. Díjole como ya le había dicho que en aquel castillo no había capilla, y para lo que restaba de hacer tampoco era necesaria; que todo el toque de quedar armado caballero consistía en la pescozada y en el espaldarazo, según él tenía noticia del ceremonial de la orden, y que aquello en mitad de un campo se podía hacer, y que ya había cumplido con lo que tocaba al velar de las armas, que con solas dos horas de vela se cumplía, cuanto más, que él había estado más de cuatro. Todo se lo creyó don Quijote, y dijo que él estaba allí pronto para obedecerle, y que concluyese con la mayor brevedad que pudiese; porque si fuese otra vez acometido y se viese armado caballero, no pensaba dejar persona viva en el castillo, eceto aquellas que él le mandase, a quien por su respeto dejaría. Advertido y medroso desto el castellano, trujo luego un libro donde asentaba la paja y cebada que daba a los arrieros, y con un cabo de vela que le traía un muchacho, y con las dos ya dichas doncellas, se vino adonde don Quijote estaba, al cual mandó hincar de rodillas; y, leyendo en su manual, como que decía alguna devota oración, en mitad de la leyenda alzó la mano y diole sobre el cuello un buen golpe, y tras él, con su mesma espada, un gentil espaldazaro, siempre murmurando entre dientes, como que rezaba. Hecho esto, mandó a una de aquellas damas que le ciñese la espada, la cual lo hizo con mucha desenvoltura y discreción, porque no fue menester poca para no reventar de risa a cada punto de las ceremonias; pero las proezas que ya habían visto del novel caballero les tenía la risa a raya. Al ceñirle la espada, dijo la buena señora: -Dios haga a vuestra merced muy venturoso caballero y le dé ventura en lides. Don Quijote le preguntó cómo se llamaba, porque él supiese de allí adelante a quién quedaba obligado por la merced recebida; porque pensaba darle alguna parte de la honra que alcanzase por el valor de su brazo. Ella respondió con mucha humildad que se llamaba la Tolosa, y que era hija de un remendón natural de Toledo que vivía a las tendillas de Sancho Bienaya, y que dondequiera que ella estuviese le serviría y le tendría por señor. Don Quijote le replicó que, por su amor, le hiciese merced que de allí adelante se pusiese don y se llamase doña Tolosa. Ella se lo prometió, y la otra le calzó la espuela, con la cual le pasó casi el mismo coloquio que con la de la espada: preguntóle su nombre, y dijo que se llamaba la Molinera, y que era hija de un honrado molinero de Antequera; a la cual también rogó don Quijote que se pusiese don y se llamase doña Molinera, ofreciéndole nuevos servicios y mercedes. Hechas, pues, de galope y aprisa las hasta allí nunca vistas ceremonias, no vio la hora don Quijote de verse a caballo y salir buscando las aventuras; y, ensillando luego a Rocinante, subió en él, y, abrazando a su huésped, le dijo cosas tan estrañas, agradeciéndole la merced de haberle armado caballero, que no es posible acertar a referirlas. El ventero, por verle ya fuera de la venta, con no menos retóricas, aunque con más breves palabras, respondió a las suyas, y, sin pedirle la costa de la posada, le dejó ir a la buen hora. Capítulo IV. De lo que le sucedió a nuestro caballero cuando salió de la venta La del alba sería cuando don Quijote salió de la venta, tan contento, tan gallardo, tan alborozado por verse ya armado caballero, que el gozo le reventaba por las cinchas del caballo. Mas, viniéndole a la memoria los consejos de su huésped cerca de las prevenciones tan necesarias que había de llevar consigo, especial la de los dineros y camisas, determinó volver a su casa y acomodarse de todo, y de un escudero, haciendo cuenta de recebir a un labrador vecino suyo, que era pobre y con hijos, pero muy a propósito para el oficio escuderil de la caballería. Con este pensamiento guió a Rocinante hacia su aldea, el cual, casi conociendo la querencia, con tanta gana comenzó a caminar, que parecía que no ponía los pies en el suelo. No había andado mucho, cuando le pareció que a su diestra mano, de la espesura de un bosque que allí estaba, salían unas voces delicadas, como de persona que se quejaba; y apenas las hubo oído, cuando dijo: -Gracias doy al cielo por la merced que me hace, pues tan presto me pone ocasiones delante donde yo pueda cumplir con lo que debo a mi profesión, y donde pueda coger el fruto de mis buenos deseos. Estas voces, sin duda, son de algún menesteroso o menesterosa, que ha menester mi favor y ayuda. Y, volviendo las riendas, encaminó a Rocinante hacia donde le pareció que las voces salían. Y, a pocos pasos que entró por el bosque, vio atada una yegua a una encina, y atado en otra a un muchacho, desnudo de medio cuerpo arriba, hasta de edad de quince años, que era el que las voces daba; y no sin causa, porque le estaba dando con una pretina muchos azotes un labrador de buen talle, y cada azote le acompañaba con una reprehensión y consejo. Porque decía: -La lengua queda y los ojos listos. Y el muchacho respondía: -No lo haré otra vez, señor mío; por la pasión de Dios, que no lo haré otra vez; y yo prometo de tener de aquí adelante más cuidado con el hato. Y, viendo don Quijote lo que pasaba, con voz airada dijo: -Descortés caballero, mal parece tomaros con quien defender no se puede; subid sobre vuestro caballo y tomad vuestra lanza -que también tenía una lanza arrimada a la encima adonde estaba arrendada la yegua-, que yo os haré conocer ser de cobardes lo que estáis haciendo. El labrador, que vio sobre sí aquella figura llena de armas blandiendo la lanza sobre su rostro, túvose por muerto, y con buenas palabras respondió: -Señor caballero, este muchacho que estoy castigando es un mi criado, que me sirve de guardar una manada de ovejas que tengo en estos contornos, el cual es tan descuidado, que cada día me falta una; y, porque castigo su descuido, o bellaquería, dice que lo hago de miserable, por no pagalle la soldada que le debo, y en Dios y en mi ánima que miente. -¿"Miente", delante de mí, ruin villano? -dijo don Quijote-. Por el sol que nos alumbra, que estoy por pasaros de parte a parte con esta lanza. Pagadle luego sin más réplica; si no, por el Dios que nos rige, que os concluya y aniquile en este punto. Desatadlo luego. El labrador bajó la cabeza y, sin responder palabra, desató a su criado, al cual preguntó don Quijote que cuánto le debía su amo. Él dijo que nueve meses, a siete reales cada mes. Hizo la cuenta don Quijote y halló que montaban setenta y tres reales, y díjole al labrador que al momento los desembolsase, si no quería morir por ello. Respondió el medroso villano que para el paso en que estaba y juramento que había hecho -y aún no había jurado nada-, que no eran tantos, porque se le habían de descontar y recebir en cuenta tres pares de zapatos que le había dado y un real de dos sangrías que le habían hecho estando enfermo. -Bien está todo eso -replicó don Quijote-, pero quédense los zapatos y las sangrías por los azotes que sin culpa le habéis dado; que si él rompió el cuero de los zapatos que vos pagastes, vos le habéis rompido el de su cuerpo; y si le sacó el barbero sangre estando enfermo, vos en sanidad se la habéis sacado; ansí que, por esta parte, no os debe nada. -El daño está, señor caballero, en que no tengo aquí dineros: véngase Andrés conmigo a mi casa, que yo se los pagaré un real sobre otro. -¿Irme yo con él? -dijo el muchacho-. Mas, ¡mal año! No, señor, ni por pienso; porque, en viéndose solo, me desuelle como a un San Bartolomé. -No hará tal -replicó don Quijote-: basta que yo se lo mande para que me tenga respeto; y con que él me lo jure por la ley de caballería que ha recebido, le dejaré ir libre y aseguraré la paga. -Mire vuestra merced, señor, lo que dice -dijo el muchacho-, que este mi amo no es caballero ni ha recebido orden de caballería alguna; que es Juan Haldudo el rico, el vecino del Quintanar. -Importa eso poco -respondió don Quijote-, que Haldudos puede haber caballeros; cuanto más, que cada uno es hijo de sus obras. -Así es verdad -dijo Andrés-; pero este mi amo, ¿de qué obras es hijo, pues me niega mi soldada y mi sudor y trabajo? -No niego, hermano Andrés -respondió el labrador-; y hacedme placer de veniros conmigo, que yo juro por todas las órdenes que de caballerías hay en el mundo de pagaros, como tengo dicho, un real sobre otro, y aun sahumados. -Del sahumerio os hago gracia -dijo don Quijote-; dádselos en reales, que con eso me contento; y mirad que lo cumpláis como lo habéis jurado; si no, por el mismo juramento os juro de volver a buscaros y a castigaros, y que os tengo de hallar, aunque os escondáis más que una lagartija. Y si queréis saber quién os manda esto, para quedar con más veras obligado a cumplirlo, sabed que yo soy el valeroso don Quijote de la Mancha, el desfacedor de agravios y sinrazones; y a Dios quedad, y no se os parta de las mientes lo prometido y jurado, so pena de la pena pronunciada. Y, en diciendo esto, picó a su Rocinante, y en breve espacio se apartó dellos. Siguióle el labrador con los ojos, y, cuando vio que había traspuesto del bosque y que ya no parecía, volvióse a su criado Andrés y díjole: -Venid acá, hijo mío, que os quiero pagar lo que os debo, como aquel deshacedor de agravios me dejó mandado. -Eso juro yo -dijo Andrés-; y ¡cómo que andará vuestra merced acertado en cumplir el mandamiento de aquel buen caballero, que mil años viva; que, según es de valeroso y de buen juez, vive Roque, que si no me paga, que vuelva y ejecute lo que dijo! -También lo juro yo -dijo el labrador-; pero, por lo mucho que os quiero, quiero acrecentar la deuda por acrecentar la paga. Y, asiéndole del brazo, le tornó a atar a la encina, donde le dio tantos azotes, que le dejó por muerto. -Llamad, señor Andrés, ahora -decía el labrador- al desfacedor de agravios, veréis cómo no desface aquéste; aunque creo que no está acabado de hacer, porque me viene gana de desollaros vivo, como vos temíades. Pero, al fin, le desató y le dio licencia que fuese a buscar su juez, para que ejecutase la pronunciada sentencia. Andrés se partió algo mohíno, jurando de ir a buscar al valeroso don Quijote de la Mancha y contalle punto por punto lo que había pasado, y que se lo había de pagar con las setenas. Pero, con todo esto, él se partió llorando y su amo se quedó riendo. Y desta manera deshizo el agravio el valeroso don Quijote; el cual, contentísimo de lo sucedido, pareciéndole que había dado felicísimo y alto principio a sus caballerías, con gran satisfación de sí mismo iba caminando hacia su aldea, diciendo a media voz: -Bien te puedes llamar dichosa sobre cuantas hoy viven en la tierra, ¡oh sobre las bellas bella Dulcinea del Toboso!, pues te cupo en suerte tener sujeto y rendido a toda tu voluntad e talante a un tan valiente y tan nombrado caballero como lo es y será don Quijote de la Mancha, el cual, como todo el mundo sabe, ayer rescibió la orden de caballería, y hoy ha desfecho el mayor tuerto y agravio que formó la sinrazón y cometió la crueldad: hoy quitó el látigo de la mano a aquel despiadado enemigo que tan sin ocasión vapulaba a aquel delicado infante. En esto, llegó a un camino que en cuatro se dividía, y luego se le vino a la imaginación las encrucejadas donde los caballeros andantes se ponían a pensar cuál camino de aquéllos tomarían, y, por imitarlos, estuvo un rato quedo; y, al cabo de haberlo muy bien pensado, soltó la rienda a Rocinante, dejando a la voluntad del rocín la suya, el cual siguió su primer intento, que fue el irse camino de su caballeriza. Y, habiendo andado como dos millas, descubrió don Quijote un grande tropel de gente, que, como después se supo, eran unos mercaderes toledanos que iban a comprar seda a Murcia. Eran seis, y venían con sus quitasoles, con otros cuatro criados a caballo y tres mozos de mulas a pie. Apenas los divisó don Quijote, cuando se imaginó ser cosa de nueva aventura; y, por imitar en todo cuanto a él le parecía posible los pasos que había leído en sus libros, le pareció venir allí de molde uno que pensaba hacer. Y así, con gentil continente y denuedo, se afirmó bien en los estribos, apretó la lanza, llegó la adarga al pecho, y, puesto en la mitad del camino, estuvo esperando que aquellos caballeros andantes llegasen, que ya él por tales los tenía y juzgaba; y, cuando llegaron a trecho que se pudieron ver y oír, levantó don Quijote la voz, y con ademán arrogante dijo: -Todo el mundo se tenga, si todo el mundo no confiesa que no hay en el mundo todo doncella más hermosa que la emperatriz de la Mancha, la sin par Dulcinea del Toboso. Paráronse los mercaderes al son destas razones, y a ver la estraña figura del que las decía; y, por la figura y por las razones, luego echaron de ver la locura de su dueño; mas quisieron ver despacio en qué paraba aquella confesión que se les pedía, y uno dellos, que era un poco burlón y muy mucho discreto, le dijo: -Señor caballero, nosotros no conocemos quién sea esa buena señora que decís; mostrádnosla: que si ella fuere de tanta hermosura como significáis, de buena gana y sin apremio alguno confesaremos la verdad que por parte vuestra nos es pedida. -Si os la mostrara -replicó don Quijote-, ¿qué hiciérades vosotros en confesar una verdad tan notoria? La importancia está en que sin verla lo habéis de creer, confesar, afirmar, jurar y defender; donde no, conmigo sois en batalla, gente descomunal y soberbia. Que, ahora vengáis uno a uno, como pide la orden de caballería, ora todos juntos, como es costumbre y mala usanza de los de vuestra ralea, aquí os aguardo y espero, confiado en la razón que de mi parte tengo. -Señor caballero -replicó el mercader-, suplico a vuestra merced, en nombre de todos estos príncipes que aquí estamos, que, porque no encarguemos nuestras conciencias confesando una cosa por nosotros jamás vista ni oída, y más siendo tan en perjuicio de las emperatrices y reinas del Alcarria y Estremadura, que vuestra merced sea servido de mostrarnos algún retrato de esa señora, aunque sea tamaño como un grano de trigo; que por el hilo se sacará el ovillo, y quedaremos con esto satisfechos y seguros, y vuestra merced quedará contento y pagado; y aun creo que estamos ya tan de su parte que, aunque su retrato nos muestre que es tuerta de un ojo y que del otro le mana bermellón y piedra azufre, con todo eso, por complacer a vuestra merced, diremos en su favor todo lo que quisiere. -No le mana, canalla infame -respondió don Quijote, encendido en cólera-; no le mana, digo, eso que decís, sino ámbar y algalia entre algodones; y no es tuerta ni corcovada, sino más derecha que un huso de Guadarrama. Pero vosotros pagaréis la grande blasfemia que habéis dicho contra tamaña beldad como es la de mi señora. Y, en diciendo esto, arremetió con la lanza baja contra el que lo había dicho, con tanta furia y enojo que, si la buena suerte no hiciera que en la mitad del camino tropezara y cayera Rocinante, lo pasara mal el atrevido mercader. Cayó Rocinante, y fue rodando su amo una buena pieza por el campo; y, queriéndose levantar, jamás pudo: tal embarazo le causaban la lanza, adarga, espuelas y celada, con el peso de las antiguas armas. Y, entretanto que pugnaba por levantarse y no podía, estaba diciendo: -¡Non fuyáis, gente cobarde; gente cautiva, atended!; que no por culpa mía, sino de mi caballo, estoy aquí tendido. Un mozo de mulas de los que allí venían, que no debía de ser muy bien intencionado, oyendo decir al pobre caído tantas arrogancias, no lo pudo sufrir sin darle la respuesta en las costillas. Y, llegándose a él, tomó la lanza, y, después de haberla hecho pedazos, con uno dellos comenzó a dar a nuestro don Quijote tantos palos que, a despecho y pesar de sus armas, le molió como cibera. Dábanle voces sus amos que no le diese tanto y que le dejase, pero estaba ya el mozo picado y no quiso dejar el juego hasta envidar todo el resto de su cólera; y, acudiendo por los demás trozos de la lanza, los acabó de deshacer sobre el miserable caído, que, con toda aquella tempestad de palos que sobre él vía, no cerraba la boca, amenazando al cielo y a la tierra, y a los malandrines, que tal le parecían. Cansóse el mozo, y los mercaderes siguieron su camino, llevando qué contar en todo él del pobre apaleado. El cual, después que se vio solo, tornó a probar si podía levantarse; pero si no lo pudo hacer cuando sano y bueno, ¿cómo lo haría molido y casi deshecho? Y aún se tenía por dichoso, pareciéndole que aquélla era propia desgracia de caballeros andantes, y toda la atribuía a la falta de su caballo, y no era posible levantarse, según tenía brumado todo el cuerpo. Capítulo V. Donde se prosigue la narración de la desgracia de nuestro caballero Viendo, pues, que, en efeto, no podía menearse, acordó de acogerse a su ordinario remedio, que era pensar en algún paso de sus libros; y trújole su locura a la memoria aquel de Valdovinos y del marqués de Mantua, cuando Carloto le dejó herido en la montiña, historia sabida de los niños, no ignorada de los mozos, celebrada y aun creída de los viejos; y, con todo esto, no más verdadera que los milagros de Mahoma. Ésta, pues, le pareció a él que le venía de molde para el paso en que se hallaba; y así, con muestras de grande sentimiento, se comenzó a volcar por la tierra y a decir con debilitado aliento lo mesmo que dicen decía el herido caballero del bosque: -¿Donde estás, señora mía, que no te duele mi mal? O no lo sabes, señora, o eres falsa y desleal. Y, desta manera, fue prosiguiendo el romance hasta aquellos versos que dicen: -¡Oh noble marqués de Mantua, mi tío y señor carnal! Y quiso la suerte que, cuando llegó a este verso, acertó a pasar por allí un labrador de su mesmo lugar y vecino suyo, que venía de llevar una carga de trigo al molino; el cual, viendo aquel hombre allí tendido, se llegó a él y le preguntó que quién era y qué mal sentía que tan tristemente se quejaba. Don Quijote creyó, sin duda, que aquél era el marqués de Mantua, su tío; y así, no le respondió otra cosa si no fue proseguir en su romance, donde le daba cuenta de su desgracia y de los amores del hijo del Emperante con su esposa, todo de la mesma manera que el romance lo canta. El labrador estaba admirado oyendo aquellos disparates; y, quitándole la visera, que ya estaba hecha pedazos de los palos, le limpió el rostro, que le tenía cubierto de polvo; y apenas le hubo limpiado, cuando le conoció y le dijo: -Señor Quijana -que así se debía de llamar cuando él tenía juicio y no había pasado de hidalgo sosegado a caballero andante-, ¿quién ha puesto a vuestra merced desta suerte? Pero él seguía con su romance a cuanto le preguntaba. Viendo esto el buen hombre, lo mejor que pudo le quitó el peto y espaldar, para ver si tenía alguna herida; pero no vio sangre ni señal alguna. Procuró levantarle del suelo, y no con poco trabajo le subió sobre su jumento, por parecer caballería más sosegada. Recogió las armas, hasta las astillas de la lanza, y liólas sobre Rocinante, al cual tomó de la rienda, y del cabestro al asno, y se encaminó hacia su pueblo, bien pensativo de oír los disparates que don Quijote decía; y no menos iba don Quijote, que, de puro molido y quebrantado, no se podía tener sobre el borrico, y de cuando en cuando daba unos suspiros que los ponía en el cielo; de modo que de nuevo obligó a que el labrador le preguntase le dijese qué mal sentía; y no parece sino que el diablo le traía a la memoria los cuentos acomodados a sus sucesos, porque, en aquel punto, olvidándose de Valdovinos, se acordó del moro Abindarráez, cuando el alcaide de Antequera, Rodrigo de Narváez, le prendió y llevó cautivo a su alcaidía. De suerte que, cuando el labrador le volvió a preguntar que cómo estaba y qué sentía, le respondió las mesmas palabras y razones que el cautivo Abencerraje respondía a Rodrigo de Narváez, del mesmo modo que él había leído la historia en La Diana, de Jorge de Montemayor, donde se escribe; aprovechándose della tan a propósito, que el labrador se iba dando al diablo de oír tanta máquina de necedades; por donde conoció que su vecino estaba loco, y dábale priesa a llegar al pueblo, por escusar el enfado que don Quijote le causaba con su larga arenga. Al cabo de lo cual, dijo: -Sepa vuestra merced, señor don Rodrigo de Narváez, que esta hermosa Jarifa que he dicho es ahora la linda Dulcinea del Toboso, por quien yo he hecho, hago y haré los más famosos hechos de caballerías que se han visto, vean ni verán en el mundo. A esto respondió el labrador: -Mire vuestra merced, señor, pecador de mí, que yo no soy don Rodrigo de Narváez, ni el marqués de Mantua, sino Pedro Alonso, su vecino; ni vuestra merced es Valdovinos, ni Abindarráez, sino el honrado hidalgo del señor Quijana. -Yo sé quién soy -respondió don Quijote-; y sé que puedo ser no sólo los que he dicho, sino todos los Doce Pares de Francia, y aun todos los Nueve de la Fama, pues a todas las hazañas que ellos todos juntos y cada uno por sí hicieron, se aventajarán las mías. En estas pláticas y en otras semejantes, llegaron al lugar a la hora que anochecía, pero el labrador aguardó a que fuese algo más noche, porque no viesen al molido hidalgo tan mal caballero. Llegada, pues, la hora que le pareció, entró en el pueblo, y en la casa de don Quijote, la cual halló toda alborotada; y estaban en ella el cura y el barbero del lugar, que eran grandes amigos de don Quijote, que estaba diciéndoles su ama a voces: -¿Qué le parece a vuestra merced, señor licenciado Pero Pérez -que así se llamaba el cura-, de la desgracia de mi señor? Tres días ha que no parecen él, ni el rocín, ni la adarga, ni la lanza ni las armas. ¡Desventurada de mí!, que me doy a entender, y así es ello la verdad como nací para morir, que estos malditos libros de caballerías que él tiene y suele leer tan de ordinario le han vuelto el juicio; que ahora me acuerdo haberle oído decir muchas veces, hablando entre sí, que quería hacerse caballero andante e irse a buscar las aventuras por esos mundos. Encomendados sean a Satanás y a Barrabás tales libros, que así han echado a perder el más delicado entendimiento que había en toda la Mancha. La sobrina decía lo mesmo, y aun decía más: -Sepa, señor maese Nicolás -que éste era el nombre del barbero-, que muchas veces le aconteció a mi señor tío estarse leyendo en estos desalmados libros de desventuras dos días con sus noches, al cabo de los cuales, arrojaba el libro de las manos, y ponía mano a la espada y andaba a cuchilladas con las paredes; y cuando estaba muy cansado, decía que había muerto a cuatro gigantes como cuatro torres, y el sudor que sudaba del cansancio decía que era sangre de las feridas que había recebido en la batalla; y bebíase luego un gran jarro de agua fría, y quedaba sano y sosegado, diciendo que aquella agua era una preciosísima bebida que le había traído el sabio Esquife, un grande encantador y amigo suyo. Mas yo me tengo la culpa de todo, que no avisé a vuestras mercedes de los disparates de mi señor tío, para que lo remediaran antes de llegar a lo que ha llegado, y quemaran todos estos descomulgados libros, que tiene muchos, que bien merecen ser abrasados, como si fuesen de herejes. -Esto digo yo también -dijo el cura-, y a fee que no se pase el día de mañana sin que dellos no se haga acto público y sean condenados al fuego, porque no den ocasión a quien los leyere de hacer lo que mi buen amigo debe de haber hecho. Todo esto estaban oyendo el labrador y don Quijote, con que acabó de entender el labrador la enfermedad de su vecino; y así, comenzó a decir a voces: -Abran vuestras mercedes al señor Valdovinos y al señor marqués de Mantua, que viene malferido, y al señor moro Abindarráez, que trae cautivo el valeroso Rodrigo de Narváez, alcaide de Antequera. A estas voces salieron todos, y, como conocieron los unos a su amigo, las otras a su amo y tío, que aún no se había apeado del jumento, porque no podía, corrieron a abrazarle. Él dijo: -Ténganse todos, que vengo malferido por la culpa de mi caballo. Llévenme a mi lecho y llámese, si fuere posible, a la sabia Urganda, que cure y cate de mis feridas. -¡Mirá, en hora maza -dijo a este punto el ama-, si me decía a mí bien mi corazón del pie que cojeaba mi señor! Suba vuestra merced en buen hora, que, sin que venga esa Hurgada, le sabremos aquí curar. ¡Malditos, digo, sean otra vez y otras ciento estos libros de caballerías, que tal han parado a vuestra merced! Lleváronle luego a la cama, y, catándole las feridas, no le hallaron ninguna; y él dijo que todo era molimiento, por haber dado una gran caída con Rocinante, su caballo, combatiéndose con diez jayanes, los más desaforados y atrevidos que se pudieran fallar en gran parte de la tierra. -¡Ta, ta! -dijo el cura-. ¿Jayanes hay en la danza? Para mi santiguada, que yo los queme mañana antes que llegue la noche. Hiciéronle a don Quijote mil preguntas, y a ninguna quiso responder otra cosa sino que le diesen de comer y le dejasen dormir, que era lo que más le importaba. Hízose así, y el cura se informó muy a la larga del labrador del modo que había hallado a don Quijote. Él se lo contó todo, con los disparates que al hallarle y al traerle había dicho; que fue poner más deseo en el licenciado de hacer lo que otro día hizo, que fue llamar a su amigo el barbero maese Nicolás, con el cual se vino a casa de don Quijote, Capítulo VI. Del donoso y grande escrutinio que el cura y el barbero hicieron en la librería de nuestro ingenioso hidalgo el cual aún todavía dormía. Pidió las llaves, a la sobrina, del aposento donde estaban los libros, autores del daño, y ella se las dio de muy buena gana. Entraron dentro todos, y la ama con ellos, y hallaron más de cien cuerpos de libros grandes, muy bien encuadernados, y otros pequeños; y, así como el ama los vio, volvióse a salir del aposento con gran priesa, y tornó luego con una escudilla de agua bendita y un hisopo, y dijo: -Tome vuestra merced, señor licenciado: rocíe este aposento, no esté aquí algún encantador de los muchos que tienen estos libros, y nos encanten, en pena de las que les queremos dar echándolos del mundo. Causó risa al licenciado la simplicidad del ama, y mandó al barbero que le fuese dando de aquellos libros uno a uno, para ver de qué trataban, pues podía ser hallar algunos que no mereciesen castigo de fuego. -No -dijo la sobrina-, no hay para qué perdonar a ninguno, porque todos han sido los dañadores; mejor será arrojarlos por las ventanas al patio, y hacer un rimero dellos y pegarles fuego; y si no, llevarlos al corral, y allí se hará la hoguera, y no ofenderá el humo. Lo mismo dijo el ama: tal era la gana que las dos tenían de la muerte de aquellos inocentes; mas el cura no vino en ello sin primero leer siquiera los títulos. Y el primero que maese Nicolás le dio en las manos fue Los cuatro de Amadís de Gaula, y dijo el cura: -Parece cosa de misterio ésta; porque, según he oído decir, este libro fue el primero de caballerías que se imprimió en España, y todos los demás han tomado principio y origen déste; y así, me parece que, como a dogmatizador de una secta tan mala, le debemos, sin escusa alguna, condenar al fuego. -No, señor -dijo el barbero-, que también he oído decir que es el mejor de todos los libros que de este género se han compuesto; y así, como a único en su arte, se debe perdonar. -Así es verdad -dijo el cura-, y por esa razón se le otorga la vida por ahora. Veamos esotro que está junto a él. -Es -dijo el barbero- las Sergas de Esplandián, hijo legítimo de Amadís de Gaula. -Pues, en verdad -dijo el cura- que no le ha de valer al hijo la bondad del padre. Tomad, señora ama: abrid esa ventana y echadle al corral, y dé principio al montón de la hoguera que se ha de hacer. Hízolo así el ama con mucho contento, y el bueno de Esplandián fue volando al corral, esperando con toda paciencia el fuego que le amenazaba. -Adelante -dijo el cura. -Este que viene -dijo el barbero- es Amadís de Grecia; y aun todos los deste lado, a lo que creo, son del mesmo linaje de Amadís. -Pues vayan todos al corral -dijo el cura-; que, a trueco de quemar a la reina Pintiquiniestra, y al pastor Darinel, y a sus églogas, y a las endiabladas y revueltas razones de su autor, quemaré con ellos al padre que me engendró, si anduviera en figura de caballero andante. -De ese parecer soy yo -dijo el barbero. -Y aun yo -añadió la sobrina. -Pues así es -dijo el ama-, vengan, y al corral con ellos. Diéronselos, que eran muchos, y ella ahorró la escalera y dio con ellos por la ventana abajo. -¿Quién es ese tonel? -dijo el cura. -Éste es -respondió el barbero- Don Olivante de Laura. -El autor de ese libro -dijo el cura- fue el mesmo que compuso a Jardín de flores; y en verdad que no sepa determinar cuál de los dos libros es más verdadero, o, por decir mejor, menos mentiroso; sólo sé decir que éste irá al corral por disparatado y arrogante. -Éste que se sigue es Florimorte de Hircania -dijo el barbero. -¿Ahí está el señor Florimorte? -replicó el cura-. Pues a fe que ha de parar presto en el corral, a pesar de su estraño nacimiento y sonadas aventuras; que no da lugar a otra cosa la dureza y sequedad de su estilo. Al corral con él y con esotro, señora ama. -Que me place, señor mío -respondía ella; y con mucha alegría ejecutaba lo que le era mandado. -Éste es El Caballero Platir -dijo el barbero. -Antiguo libro es éste -dijo el cura-, y no hallo en él cosa que merezca venia. Acompañe a los demás sin réplica. Y así fue hecho. Abrióse otro libro y vieron que tenía por título El Caballero de la Cruz. -Por nombre tan santo como este libro tiene, se podía perdonar su ignorancia; mas también se suele decir: "tras la cruz está el diablo"; vaya al fuego. Tomando el barbero otro libro, dijo: -Éste es Espejo de caballerías. -Ya conozco a su merced -dijo el cura-. Ahí anda el señor Reinaldos de Montalbán con sus amigos y compañeros, más ladrones que Caco, y los doce Pares, con el verdadero historiador Turpín; y en verdad que estoy por condenarlos no más que a destierro perpetuo, siquiera porque tienen parte de la invención del famoso Mateo Boyardo, de donde también tejió su tela el cristiano poeta Ludovico Ariosto; al cual, si aquí le hallo, y que habla en otra lengua que la suya, no le guardaré respeto alguno; pero si habla en su idioma, le pondré sobre mi cabeza. -Pues yo le tengo en italiano -dijo el barbero-, mas no le entiendo. -Ni aun fuera bien que vos le entendiérades -respondió el cura-, y aquí le perdonáramos al señor capitán que no le hubiera traído a España y hecho castellano; que le quitó mucho de su natural valor, y lo mesmo harán todos aquellos que los libros de verso quisieren volver en otra lengua: que, por mucho cuidado que pongan y habilidad que muestren, jamás llegarán al punto que ellos tienen en su primer nacimiento. Digo, en efeto, que este libro, y todos los que se hallaren que tratan destas cosas de Francia, se echen y depositen en un pozo seco, hasta que con más acuerdo se vea lo que se ha de hacer dellos, ecetuando a un Bernardo del Carpio que anda por ahí y a otro llamado Roncesvalles; que éstos, en llegando a mis manos, han de estar en las del ama, y dellas en las del fuego, sin remisión alguna. Todo lo confirmó el barbero, y lo tuvo por bien y por cosa muy acertada, por entender que era el cura tan buen cristiano y tan amigo de la verdad, que no diría otra cosa por todas las del mundo. Y, abriendo otro libro, vio que era Palmerín de Oliva, y junto a él estaba otro que se llamaba Palmerín de Ingalaterra; lo cual visto por el licenciado, dijo: -Esa oliva se haga luego rajas y se queme, que aun no queden della las cenizas; y esa palma de Ingalaterra se guarde y se conserve como a cosa única, y se haga para ello otra caja como la que halló Alejandro en los despojos de Dario, que la diputó para guardar en ella las obras del poeta Homero. Este libro, señor compadre, tiene autoridad por dos cosas: la una, porque él por sí es muy bueno, y la otra, porque es fama que le compuso un discreto rey de Portugal. Todas las aventuras del castillo de Miraguarda son bonísimas y de grande artificio; las razones, cortesanas y claras, que guardan y miran el decoro del que habla con mucha propriedad y entendimiento. Digo, pues, salvo vuestro buen parecer, señor maese Nicolás, que éste y Amadís de Gaula queden libres del fuego, y todos los demás, sin hacer más cala y cata, perezcan. -No, señor compadre -replicó el barbero-; que éste que aquí tengo es el afamado Don Belianís. -Pues ése -replicó el cura-, con la segunda, tercera y cuarta parte, tienen necesidad de un poco de ruibarbo para purgar la demasiada cólera suya, y es menester quitarles todo aquello del castillo de la Fama y otras impertinencias de más importancia, para lo cual se les da término ultramarino, y como se enmendaren, así se usará con ellos de misericordia o de justicia; y en tanto, tenedlos vos, compadre, en vuestra casa, mas no los dejéis leer a ninguno. -Que me place -respondió el barbero. Y, sin querer cansarse más en leer libros de caballerías, mandó al ama que tomase todos los grandes y diese con ellos en el corral. No se dijo a tonta ni a sorda, sino a quien tenía más gana de quemallos que de echar una tela, por grande y delgada que fuera; y, asiendo casi ocho de una vez, los arrojó por la ventana. Por tomar muchos juntos, se le cayó uno a los pies del barbero, que le tomó gana de ver de quién era, y vio que decía: Historia del famoso caballero Tirante el Blanco. -¡Válame Dios! -dijo el cura, dando una gran voz-. ¡Que aquí esté Tirante el Blanco! Dádmele acá, compadre; que hago cuenta que he hallado en él un tesoro de contento y una mina de pasatiempos. Aquí está don Quirieleisón de Montalbán, valeroso caballero, y su hermano Tomás de Montalbán, y el caballero Fonseca, con la batalla que el valiente de Tirante hizo con el alano, y las agudezas de la doncella Placerdemivida, con los amores y embustes de la viuda Reposada, y la señora Emperatriz, enamorada de Hipólito, su escudero. Dígoos verdad, señor compadre, que, por su estilo, es éste el mejor libro del mundo: aquí comen los caballeros, y duermen, y mueren en sus camas, y hacen testamento antes de su muerte, con estas cosas de que todos los demás libros deste género carecen. Con todo eso, os digo que merecía el que le compuso, pues no hizo tantas necedades de industria, que le echaran a galeras por todos los días de su vida. Llevadle a casa y leedle, y veréis que es verdad cuanto dél os he dicho. -Así será -respondió el barbero-; pero, ¿qué haremos destos pequeños libros que quedan? -Éstos -dijo el cura- no deben de ser de caballerías, sino de poesía. Y abriendo uno, vio que era La Diana, de Jorge de Montemayor, y dijo, creyendo que todos los demás eran del mesmo género: -Éstos no merecen ser quemados, como los demás, porque no hacen ni harán el daño que los de caballerías han hecho; que son libros de entendimiento, sin perjuicio de tercero. -¡Ay señor! -dijo la sobrina-, bien los puede vuestra merced mandar quemar, como a los demás, porque no sería mucho que, habiendo sanado mi señor tío de la enfermedad caballeresca, leyendo éstos, se le antojase de hacerse pastor y andarse por los bosques y prados cantando y tañendo; y, lo que sería peor, hacerse poeta; que, según dicen, es enfermedad incurable y pegadiza. -Verdad dice esta doncella -dijo el cura-, y será bien quitarle a nuestro amigo este tropiezo y ocasión delante. Y, pues comenzamos por La Diana de Montemayor, soy de parecer que no se queme, sino que se le quite todo aquello que trata de la sabia Felicia y de la agua encantada, y casi todos los versos mayores, y quédesele en hora buena la prosa, y la honra de ser primero en semejantes libros. -Éste que se sigue -dijo el barbero- es La Diana llamada segunda del Salmantino; y éste, otro que tiene el mesmo nombre, cuyo autor es Gil Polo. -Pues la del Salmantino -respondió el cura-, acompañe y acreciente el número de los condenados al corral, y la de Gil Polo se guarde como si fuera del mesmo Apolo; y pase adelante, señor compadre, y démonos prisa, que se va haciendo tarde. -Este libro es -dijo el barbero, abriendo otro- Los diez libros de Fortuna de Amor, compuestos por Antonio de Lofraso, poeta sardo. -Por las órdenes que recebí -dijo el cura-, que, desde que Apolo fue Apolo, y las musas musas, y los poetas poetas, tan gracioso ni tan disparatado libro como ése no se ha compuesto, y que, por su camino, es el mejor y el más único de cuantos deste género han salido a la luz del mundo; y el que no le ha leído puede hacer cuenta que no ha leído jamás cosa de gusto. Dádmele acá, compadre, que precio más haberle hallado que si me dieran una sotana de raja de Florencia. Púsole aparte con grandísimo gusto, y el barbero prosiguió diciendo: -Estos que se siguen son El Pastor de Iberia, Ninfas de Henares y Desengaños de celos. -Pues no hay más que hacer -dijo el cura-, sino entregarlos al brazo seglar del ama; y no se me pregunte el porqué, que sería nunca acabar. -Este que viene es El Pastor de Fílida. -No es ése pastor -dijo el cura-, sino muy discreto cortesano; guárdese como joya preciosa. -Este grande que aquí viene se intitula -dijo el barbero- Tesoro de varias poesías. -Como ellas no fueran tantas -dijo el cura-, fueran más estimadas; menester es que este libro se escarde y limpie de algunas bajezas que entre sus grandezas tiene. Guárdese, porque su autor es amigo mío, y por respeto de otras más heroicas y levantadas obras que ha escrito. -Éste es -siguió el barbero- El Cancionero de López Maldonado. -También el autor de ese libro -replicó el cura- es grande amigo mío, y sus versos en su boca admiran a quien los oye; y tal es la suavidad de la voz con que los canta, que encanta. Algo largo es en las églogas, pero nunca lo bueno fue mucho: guárdese con los escogidos. Pero, ¿qué libro es ese que está junto a él? -La Galatea, de Miguel de Cervantes -dijo el barbero. -Muchos años ha que es grande amigo mío ese Cervantes, y sé que es más versado en desdichas que en versos. Su libro tiene algo de buena invención; propone algo, y no concluye nada: es menester esperar la segunda parte que promete; quizá con la emienda alcanzará del todo la misericordia que ahora se le niega; y, entre tanto que esto se ve, tenedle recluso en vuestra posada, señor compadre. -Que me place -respondió el barbero-. Y aquí vienen tres, todos juntos: La Araucana, de don Alonso de Ercilla; La Austríada, de Juan Rufo, jurado de Córdoba, y El Monserrato, de Cristóbal de Virués, poeta valenciano. -Todos esos tres libros -dijo el cura- son los mejores que, en verso heroico, en lengua castellana están escritos, y pueden competir con los más famosos de Italia: guárdense como las más ricas prendas de poesía que tiene España. Cansóse el cura de ver más libros; y así, a carga cerrada, quiso que todos los demás se quemasen; pero ya tenía abierto uno el barbero, que se llamaba Las lágrimas de Angélica. -Lloráralas yo -dijo el cura en oyendo el nombre- si tal libro hubiera mandado quemar; porque su autor fue uno de los famosos poetas del mundo, no sólo de España, y fue felicísimo en la tradución de algunas fábulas de Ovidio. Capítulo VII. De la segunda salida de nuestro buen caballero don Quijote de la Mancha Estando en esto, comenzó a dar voces don Quijote, diciendo: -Aquí, aquí, valerosos caballeros; aquí es menester mostrar la fuerza de vuestros valerosos brazos, que los cortesanos llevan lo mejor del torneo. Por acudir a este ruido y estruendo, no se pasó adelante con el escrutinio de los demás libros que quedaban; y así, se cree que fueron al fuego, sin ser vistos ni oídos, La Carolea y León de España, con Los Hechos del Emperador, compuestos por don Luis de Ãvila, que, sin duda, debían de estar entre los que quedaban; y quizá, si el cura los viera, no pasaran por tan rigurosa sentencia. Cuando llegaron a don Quijote, ya él estaba levantado de la cama, y proseguía en sus voces y en sus desatinos, dando cuchilladas y reveses a todas partes, estando tan despierto como si nunca hubiera dormido. Abrazáronse con él, y por fuerza le volvieron al lecho; y, después que hubo sosegado un poco, volviéndose a hablar con el cura, le dijo: -Por cierto, señor arzobispo Turpín, que es gran mengua de los que nos llamamos doce Pares dejar, tan sin más ni más, llevar la vitoria deste torneo a los caballeros cortesanos, habiendo nosotros los aventureros ganado el prez en los tres días antecedentes. -Calle vuestra merced, señor compadre -dijo el cura-, que Dios será servido que la suerte se mude, y que lo que hoy se pierde se gane mañana; y atienda vuestra merced a su salud por agora, que me parece que debe de estar demasiadamente cansado, si ya no es que está malferido. -Ferido no -dijo don Quijote-, pero molido y quebrantado, no hay duda en ello; porque aquel bastardo de don Roldán me ha molido a palos con el tronco de una encina, y todo de envidia, porque ve que yo solo soy el opuesto de sus valentías. Mas no me llamaría yo Reinaldos de Montalbán si, en levantándome deste lecho, no me lo pagare, a pesar de todos sus encantamentos; y, por agora, tráiganme de yantar, que sé que es lo que más me hará al caso, y quédese lo del vengarme a mi cargo. Hiciéronlo ansí: diéronle de comer, y quedóse otra vez dormido, y ellos, admirados de su locura. Aquella noche quemó y abrasó el ama cuantos libros había en el corral y en toda la casa, y tales debieron de arder que merecían guardarse en perpetuos archivos; mas no lo permitió su suerte y la pereza del escrutiñador; y así, se cumplió el refrán en ellos de que pagan a las veces justos por pecadores. Uno de los remedios que el cura y el barbero dieron, por entonces, para el mal de su amigo, fue que le murasen y tapiasen el aposento de los libros, porque cuando se levantase no los hallase -quizá quitando la causa, cesaría el efeto-, y que dijesen que un encantador se los había llevado, y el aposento y todo; y así fue hecho con mucha presteza. De allí a dos días se levantó don Quijote, y lo primero que hizo fue ir a ver sus libros; y, como no hallaba el aposento donde le había dejado, andaba de una en otra parte buscándole. Llegaba adonde solía tener la puerta, y tentábala con las manos, y volvía y revolvía los ojos por todo, sin decir palabra; pero, al cabo de una buena pieza, preguntó a su ama que hacia qué parte estaba el aposento de sus libros. El ama, que ya estaba bien advertida de lo que había de responder, le dijo: -¿Qué aposento, o qué nada, busca vuestra merced? Ya no hay aposento ni libros en esta casa, porque todo se lo llevó el mesmo diablo. -No era diablo -replicó la sobrina-, sino un encantador que vino sobre una nube una noche, después del día que vuestra merced de aquí se partió, y, apeándose de una sierpe en que venía caballero, entró en el aposento, y no sé lo que se hizo dentro, que a cabo de poca pieza salió volando por el tejado, y dejó la casa llena de humo; y, cuando acordamos a mirar lo que dejaba hecho, no vimos libro ni aposento alguno; sólo se nos acuerda muy bien a mí y al ama que, al tiempo del partirse aquel mal viejo, dijo en altas voces que, por enemistad secreta que tenía al dueño de aquellos libros y aposento, dejaba hecho el daño en aquella casa que después se vería. Dijo también que se llamaba el sabio Muñatón. -Frestón diría -dijo don Quijote. -No sé -respondió el ama- si se llamaba Frestón o Fritón; sólo sé que acabó en tón su nombre. -Así es -dijo don Quijote-; que ése es un sabio encantador, grande enemigo mío, que me tiene ojeriza, porque sabe por sus artes y letras que tengo de venir, andando los tiempos, a pelear en singular batalla con un caballero a quien él favorece, y le tengo de vencer, sin que él lo pueda estorbar, y por esto procura hacerme todos los sinsabores que puede; y mándole yo que mal podrá él contradecir ni evitar lo que por el cielo está ordenado. -¿Quién duda de eso? -dijo la sobrina-. Pero, ¿quién le mete a vuestra merced, señor tío, en esas pendencias? ¿No será mejor estarse pacífico en su casa y no irse por el mundo a buscar pan de trastrigo, sin considerar que muchos van por lana y vuelven tresquilados? -¡Oh sobrina mía -respondió don Quijote-, y cuán mal que estás en la cuenta! Primero que a mí me tresquilen, tendré peladas y quitadas las barbas a cuantos imaginaren tocarme en la punta de un solo cabello. No quisieron las dos replicarle más, porque vieron que se le encendía la cólera. Es, pues, el caso que él estuvo quince días en casa muy sosegado, sin dar muestras de querer segundar sus primeros devaneos, en los cuales días pasó graciosísimos cuentos con sus dos compadres el cura y el barbero, sobre que él decía que la cosa de que más necesidad tenía el mundo era de caballeros andantes y de que en él se resucitase la caballería andantesca. El cura algunas veces le contradecía y otras concedía, porque si no guardaba este artificio, no había poder averiguarse con él. En este tiempo, solicitó don Quijote a un labrador vecino suyo, hombre de bien -si es que este título se puede dar al que es pobre-, pero de muy poca sal en la mollera. En resolución, tanto le dijo, tanto le persuadió y prometió, que el pobre villano se determinó de salirse con él y servirle de escudero. Decíale, entre otras cosas, don Quijote que se dispusiese a ir con él de buena gana, porque tal vez le podía suceder aventura que ganase, en quítame allá esas pajas, alguna ínsula, y le dejase a él por gobernador della. Con estas promesas y otras tales, Sancho Panza, que así se llamaba el labrador, dejó su mujer y hijos y asentó por escudero de su vecino. Dio luego don Quijote orden en buscar dineros; y, vendiendo una cosa y empeñando otra, y malbaratándolas todas, llegó una razonable cantidad. Acomodóse asimesmo de una rodela, que pidió prestada a un su amigo, y, pertrechando su rota celada lo mejor que pudo, avisó a su escudero Sancho del día y la hora que pensaba ponerse en camino, para que él se acomodase de lo que viese que más le era menester. Sobre todo le encargó que llevase alforjas; e dijo que sí llevaría, y que ansimesmo pensaba llevar un asno que tenía muy bueno, porque él no estaba duecho a andar mucho a pie. En lo del asno reparó un poco don Quijote, imaginando si se le acordaba si algún caballero andante había traído escudero caballero asnalmente, pero nunca le vino alguno a la memoria; mas, con todo esto, determinó que le llevase, con presupuesto de acomodarle de más honrada caballería en habiendo ocasión para ello, quitándole el caballo al primer descortés caballero que topase. Proveyóse de camisas y de las demás cosas que él pudo, conforme al consejo que el ventero le había dado; todo lo cual hecho y cumplido, sin despedirse Panza de sus hijos y mujer, ni don Quijote de su ama y sobrina, una noche se salieron del lugar sin que persona los viese; en la cual caminaron tanto, que al amanecer se tuvieron por seguros de que no los hallarían aunque los buscasen. Iba Sancho Panza sobre su jumento como un patriarca, con sus alforjas y su bota, y con mucho deseo de verse ya gobernador de la ínsula que su amo le había prometido. Acertó don Quijote a tomar la misma derrota y camino que el que él había tomado en su primer viaje, que fue por el campo de Montiel, por el cual caminaba con menos pesadumbre que la vez pasada, porque, por ser la hora de la mañana y herirles a soslayo los rayos del sol, no les fatigaban. Dijo en esto Sancho Panza a su amo: -Mire vuestra merced, señor caballero andante, que no se le olvide lo que de la ínsula me tiene prometido; que yo la sabré gobernar, por grande que sea. A lo cual le respondió don Quijote: -Has de saber, amigo Sancho Panza, que fue costumbre muy usada de los caballeros andantes antiguos hacer gobernadores a sus escuderos de las ínsulas o reinos que ganaban, y yo tengo determinado de que por mí no falte tan agradecida usanza; antes, pienso aventajarme en ella: porque ellos algunas veces, y quizá las más, esperaban a que sus escuderos fuesen viejos; y, ya después de hartos de servir y de llevar malos días y peores noches, les daban algún título de conde, o, por lo mucho, de marqués, de algún valle o provincia de poco más a menos; pero, si tú vives y yo vivo, bien podría ser que antes de seis días ganase yo tal reino que tuviese otros a él adherentes, que viniesen de molde para coronarte por rey de uno dellos. Y no lo tengas a mucho, que cosas y casos acontecen a los tales caballeros, por modos tan nunca vistos ni pensados, que con facilidad te podría dar aún más de lo que te prometo. -De esa manera -respondió Sancho Panza-, si yo fuese rey por algún milagro de los que vuestra merced dice, por lo menos, Juana Gutiérrez, mi oíslo, vendría a ser reina, y mis hijos infantes. -Pues, ¿quién lo duda? -respondió don Quijote. -Yo lo dudo -replicó Sancho Panza-; porque tengo para mí que, aunque lloviese Dios reinos sobre la tierra, ninguno asentaría bien sobre la cabeza de Mari Gutiérrez. Sepa, señor, que no vale dos maravedís para reina; condesa le caerá mejor, y aun Dios y ayuda. -Encomiéndalo tú a Dios, Sancho -respondió don Quijote-, que Él dará lo que más le convenga, pero no apoques tu ánimo tanto, que te vengas a contentar con menos que con ser adelantado. -No lo haré, señor mío -respondió Sancho-; y más teniendo tan principal amo en vuestra merced, que me sabrá dar todo aquello que me esté bien y yo pueda llevar. Capítulo VIII. Del buen suceso que el valeroso don Quijote tuvo en la espantable y jamás imaginada aventura de los molinos de viento, con otros sucesos dignos de felice recordación En esto, descubrieron treinta o cuarenta molinos de viento que hay en aquel campo; y, así como don Quijote los vio, dijo a su escudero: -La ventura va guiando nuestras cosas mejor de lo que acertáramos a desear, porque ves allí, amigo Sancho Panza, donde se descubren treinta, o pocos más, desaforados gigantes, con quien pienso hacer batalla y quitarles a todos las vidas, con cuyos despojos comenzaremos a enriquecer; que ésta es buena guerra, y es gran servicio de Dios quitar tan mala simiente de sobre la faz de la tierra. -¿Qué gigantes? -dijo Sancho Panza. -Aquellos que allí ves -respondió su amo- de los brazos largos, que los suelen tener algunos de casi dos leguas. -Mire vuestra merced -respondió Sancho- que aquellos que allí se parecen no son gigantes, sino molinos de viento, y lo que en ellos parecen brazos son las aspas, que, volteadas del viento, hacen andar la piedra del molino. -Bien parece -respondió don Quijote- que no estás cursado en esto de las aventuras: ellos son gigantes; y si tienes miedo, quítate de ahí, y ponte en oración en el espacio que yo voy a entrar con ellos en fiera y desigual batalla. Y, diciendo esto, dio de espuelas a su caballo Rocinante, sin atender a las voces que su escudero Sancho le daba, advirtiéndole que, sin duda alguna, eran molinos de viento, y no gigantes, aquellos que iba a acometer. Pero él iba tan puesto en que eran gigantes, que ni oía las voces de su escudero Sancho ni echaba de ver, aunque estaba ya bien cerca, lo que eran; antes, iba diciendo en voces altas: -Non fuyades, cobardes y viles criaturas, que un solo caballero es el que os acomete. Levantóse en esto un poco de viento y las grandes aspas comenzaron a moverse, lo cual visto por don Quijote, dijo: -Pues, aunque mováis más brazos que los del gigante Briareo, me lo habéis de pagar. Y, en diciendo esto, y encomendándose de todo corazón a su señora Dulcinea, pidiéndole que en tal trance le socorriese, bien cubierto de su rodela, con la lanza en el ristre, arremetió a todo el galope de Rocinante y embistió con el primero molino que estaba delante; y, dándole una lanzada en el aspa, la volvió el viento con tanta furia que hizo la lanza pedazos, llevándose tras sí al caballo y al caballero, que fue rodando muy maltrecho por el campo. Acudió Sancho Panza a socorrerle, a todo el correr de su asno, y cuando llegó halló que no se podía menear: tal fue el golpe que dio con él Rocinante. -¡Válame Dios! -dijo Sancho-. ¿No le dije yo a vuestra merced que mirase bien lo que hacía, que no eran sino molinos de viento, y no lo podía ignorar sino quien llevase otros tales en la cabeza? -Calla, amigo Sancho -respondió don Quijote-, que las cosas de la guerra, más que otras, están sujetas a continua mudanza; cuanto más, que yo pienso, y es así verdad, que aquel sabio Frestón que me robó el aposento y los libros ha vuelto estos gigantes en molinos por quitarme la gloria de su vencimiento: tal es la enemistad que me tiene; mas, al cabo al cabo, han de poder poco sus malas artes contra la bondad de mi espada. -Dios lo haga como puede -respondió Sancho Panza. Y, ayudándole a levantar, tornó a subir sobre Rocinante, que medio despaldado estaba. Y, hablando en la pasada aventura, siguieron el camino del Puerto Lápice, porque allí decía don Quijote que no era posible dejar de hallarse muchas y diversas aventuras, por ser lugar muy pasajero; sino que iba muy pesaroso por haberle faltado la lanza; y, diciéndoselo a su escudero, le dijo: -Yo me acuerdo haber leído que un caballero español, llamado Diego Pérez de Vargas, habiéndosele en una batalla roto la espada, desgajó de una encina un pesado ramo o tronco, y con él hizo tales cosas aquel día, y machacó tantos moros, que le quedó por sobrenombre Machuca, y así él como sus decendientes se llamaron, desde aquel día en adelante, Vargas y Machuca. Hete dicho esto, porque de la primera encina o roble que se me depare pienso desgajar otro tronco tal y tan bueno como aquél, que me imagino y pienso hacer con él tales hazañas, que tú te tengas por bien afortunado de haber merecido venir a vellas y a ser testigo de cosas que apenas podrán ser creídas. -A la mano de Dios -dijo Sancho-; yo lo creo todo así como vuestra merced lo dice; pero enderécese un poco, que parece que va de medio lado, y debe de ser del molimiento de la caída. -Así es la verdad -respondió don Quijote-; y si no me quejo del dolor, es porque no es dado a los caballeros andantes quejarse de herida alguna, aunque se le salgan las tripas por ella. -Si eso es así, no tengo yo qué replicar -respondió Sancho-, pero sabe Dios si yo me holgara que vuestra merced se quejara cuando alguna cosa le doliera. De mí sé decir que me he de quejar del más pequeño dolor que tenga, si ya no se entiende también con los escuderos de los caballeros andantes eso del no quejarse. No se dejó de reír don Quijote de la simplicidad de su escudero; y así, le declaró que podía muy bien quejarse, como y cuando quisiese, sin gana o con ella; que hasta entonces no había leído cosa en contrario en la orden de caballería. Díjole Sancho que mirase que era hora de comer. Respondióle su amo que por entonces no le hacía menester; que comiese él cuando se le antojase. Con esta licencia, se acomodó Sancho lo mejor que pudo sobre su jumento, y, sacando de las alforjas lo que en ellas había puesto, iba caminando y comiendo detrás de su amo muy de su espacio, y de cuando en cuando empinaba la bota, con tanto gusto, que le pudiera envidiar el más regalado bodegonero de Málaga. Y, en tanto que él iba de aquella manera menudeando tragos, no se le acordaba de ninguna promesa que su amo le hubiese hecho, ni tenía por ningún trabajo, sino por mucho descanso, andar buscando las aventuras, por peligrosas que fuesen. En resolución, aquella noche la pasaron entre unos árboles, y del uno dellos desgajó don Quijote un ramo seco que casi le podía servir de lanza, y puso en él el hierro que quitó de la que se le había quebrado. Toda aquella noche no durmió don Quijote, pensando en su señora Dulcinea, por acomodarse a lo que había leído en sus libros, cuando los caballeros pasaban sin dormir muchas noches en las florestas y despoblados, entretenidos con las memorias de sus señoras. No la pasó ansí Sancho Panza, que, como tenía el estómago lleno, y no de agua de chicoria, de un sueño se la llevó toda; y no fueran parte para despertarle, si su amo no lo llamara, los rayos del sol, que le daban en el rostro, ni el canto de las aves, que, muchas y muy regocijadamente, la venida del nuevo día saludaban. Al levantarse dio un tiento a la bota, y hallóla algo más flaca que la noche antes; y afligiósele el corazón, por parecerle que no llevaban camino de remediar tan presto su falta. No quiso desayunarse don Quijote, porque, como está dicho, dio en sustentarse de sabrosas memorias. Tornaron a su comenzado camino del Puerto Lápice, y a obra de las tres del día le descubrieron. -Aquí -dijo, en viéndole, don Quijote- podemos, hermano Sancho Panza, meter las manos hasta los codos en esto que llaman aventuras. Mas advierte que, aunque me veas en los mayores peligros del mundo, no has de poner mano a tu espada para defenderme, si ya no vieres que los que me ofenden es canalla y gente baja, que en tal caso bien puedes ayudarme; pero si fueren caballeros, en ninguna manera te es lícito ni concedido por las leyes de caballería que me ayudes, hasta que seas armado caballero. -Por cierto, señor -respondió Sancho-, que vuestra merced sea muy bien obedicido en esto; y más, que yo de mío me soy pacífico y enemigo de meterme en ruidos ni pendencias. Bien es verdad que, en lo que tocare a defender mi persona, no tendré mucha cuenta con esas leyes, pues las divinas y humanas permiten que cada uno se defienda de quien quisiere agraviarle. -No digo yo menos -respondió don Quijote-; pero, en esto de ayudarme contra caballeros, has de tener a raya tus naturales ímpetus. -Digo que así lo haré -respondió Sancho-, y que guardaré ese preceto tan bien como el día del domingo. Estando en estas razones, asomaron por el camino dos frailes de la orden de San Benito, caballeros sobre dos dromedarios: que no eran más pequeñas dos mulas en que venían. Traían sus antojos de camino y sus quitasoles. Detrás dellos venía un coche, con cuatro o cinco de a caballo que le acompañaban y dos mozos de mulas a pie. Venía en el coche, como después se supo, una señora vizcaína, que iba a Sevilla, donde estaba su marido, que pasaba a las Indias con un muy honroso cargo. No venían los frailes con ella, aunque iban el mesmo camino; mas, apenas los divisó don Quijote, cuando dijo a su escudero: -O yo me engaño, o ésta ha de ser la más famosa aventura que se haya visto; porque aquellos bultos negros que allí parecen deben de ser, y son sin duda, algunos encantadores que llevan hurtada alguna princesa en aquel coche, y es menester deshacer este tuerto a todo mi poderío. -Peor será esto que los molinos de viento -dijo Sancho-. Mire, señor, que aquéllos son frailes de San Benito, y el coche debe de ser de alguna gente pasajera. Mire que digo que mire bien lo que hace, no sea el diablo que le engañe. -Ya te he dicho, Sancho -respondió don Quijote-, que sabes poco de achaque de aventuras; lo que yo digo es verdad, y ahora lo verás. Y, diciendo esto, se adelantó y se puso en la mitad del camino por donde los frailes venían, y, en llegando tan cerca que a él le pareció que le podrían oír lo que dijese, en alta voz dijo: -Gente endiablada y descomunal, dejad luego al punto las altas princesas que en ese coche lleváis forzadas; si no, aparejaos a recebir presta muerte, por justo castigo de vuestras malas obras. Detuvieron los frailes las riendas, y quedaron admirados, así de la figura de don Quijote como de sus razones, a las cuales respondieron: -Señor caballero, nosotros no somos endiablados ni descomunales, sino dos religiosos de San Benito que vamos nuestro camino, y no sabemos si en este coche vienen, o no, ningunas forzadas princesas. -Para conmigo no hay palabras blandas, que ya yo os conozco, fementida canalla -dijo don Quijote. Y, sin esperar más respuesta, picó a Rocinante y, la lanza baja, arremetió contra el primero fraile, con tanta furia y denuedo que, si el fraile no se dejara caer de la mula, él le hiciera venir al suelo mal de su grado, y aun malferido, si no cayera muerto. El segundo religioso, que vio del modo que trataban a su compañero, puso piernas al castillo de su buena mula, y comenzó a correr por aquella campaña, más ligero que el mesmo viento. Sancho Panza, que vio en el suelo al fraile, apeándose ligeramente de su asno, arremetió a él y le comenzó a quitar los hábitos. Llegaron en esto dos mozos de los frailes y preguntáronle que por qué le desnudaba. Respondióles Sancho que aquello le tocaba a él ligítimamente, como despojos de la batalla que su señor don Quijote había ganado. Los mozos, que no sabían de burlas, ni entendían aquello de despojos ni batallas, viendo que ya don Quijote estaba desviado de allí, hablando con las que en el coche venían, arremetieron con Sancho y dieron con él en el suelo; y, sin dejarle pelo en las barbas, le molieron a coces y le dejaron tendido en el suelo sin aliento ni sentido. Y, sin detenerse un punto, tornó a subir el fraile, todo temeroso y acobardado y sin color en el rostro; y, cuando se vio a caballo, picó tras su compañero, que un buen espacio de allí le estaba aguardando, y esperando en qué paraba aquel sobresalto; y, sin querer aguardar el fin de todo aquel comenzado suceso, siguieron su camino, haciéndose más cruces que si llevaran al diablo a las espaldas. Don Quijote estaba, como se ha dicho, hablando con la señora del coche, diciéndole: -La vuestra fermosura, señora mía, puede facer de su persona lo que más le viniere en talante, porque ya la soberbia de vuestros robadores yace por el suelo, derribada por este mi fuerte brazo; y, porque no penéis por saber el nombre de vuestro libertador, sabed que yo me llamo don Quijote de la Mancha, caballero andante y aventurero, y cautivo de la sin par y hermosa doña Dulcinea del Toboso; y, en pago del beneficio que de mí habéis recebido, no quiero otra cosa sino que volváis al Toboso, y que de mi parte os presentéis ante esta señora y le digáis lo que por vuestra libertad he fecho. Todo esto que don Quijote decía escuchaba un escudero de los que el coche acompañaban, que era vizcaíno; el cual, viendo que no quería dejar pasar el coche adelante, sino que decía que luego había de dar la vuelta al Toboso, se fue para don Quijote y, asiéndole de la lanza, le dijo, en mala lengua castellana y peor vizcaína, desta manera: -Anda, caballero que mal andes; por el Dios que crióme, que, si no dejas coche, así te matas como estás ahí vizcaíno. Entendióle muy bien don Quijote, y con mucho sosiego le respondió: -Si fueras caballero, como no lo eres, ya yo hubiera castigado tu sandez y atrevimiento, cautiva criatura. A lo cual replicó el vizcaíno: -¿Yo no caballero? Juro a Dios tan mientes como cristiano. Si lanza arrojas y espada sacas, ¡el agua cuán presto verás que al gato llevas! Vizcaíno por tierra, hidalgo por mar, hidalgo por el diablo; y mientes que mira si otra dices cosa. -¡Ahora lo veredes, dijo Agrajes! -respondió don Quijote. Y, arrojando la lanza en el suelo, sacó su espada y embrazó su rodela, y arremetió al vizcaíno con determinación de quitarle la vida. El vizcaíno, que así le vio venir, aunque quisiera apearse de la mula, que, por ser de las malas de alquiler, no había que fiar en ella, no pudo hacer otra cosa sino sacar su espada; pero avínole bien que se halló junto al coche, de donde pudo tomar una almohada que le sirvió de escudo, y luego se fueron el uno para el otro, como si fueran dos mortales enemigos. La demás gente quisiera ponerlos en paz, mas no pudo, porque decía el vizcaíno en sus mal trabadas razones que si no le dejaban acabar su batalla, que él mismo había de matar a su ama y a toda la gente que se lo estorbase. La señora del coche, admirada y temerosa de lo que veía, hizo al cochero que se desviase de allí algún poco, y desde lejos se puso a mirar la rigurosa contienda, en el discurso de la cual dio el vizcaíno una gran cuchillada a don Quijote encima de un hombro, por encima de la rodela, que, a dársela sin defensa, le abriera hasta la cintura. Don Quijote, que sintió la pesadumbre de aquel desaforado golpe, dio una gran voz, diciendo: -¡Oh señora de mi alma, Dulcinea, flor de la fermosura, socorred a este vuestro caballero, que, por satisfacer a la vuestra mucha bondad, en este riguroso trance se halla! El decir esto, y el apretar la espada, y el cubrirse bien de su rodela, y el arremeter al vizcaíno, todo fue en un tiempo, llevando determinación de aventurarlo todo a la de un golpe solo. El vizcaíno, que así le vio venir contra él, bien entendió por su denuedo su coraje, y determinó de hacer lo mesmo que don Quijote; y así, le aguardó bien cubierto de su almohada, sin poder rodear la mula a una ni a otra parte; que ya, de puro cansada y no hecha a semejantes niñerías, no podía dar un paso. Venía, pues, como se ha dicho, don Quijote contra el cauto vizcaíno, con la espada en alto, con determinación de abrirle por medio, y el vizcaíno le aguardaba ansimesmo levantada la espada y aforrado con su almohada, y todos los circunstantes estaban temerosos y colgados de lo que había de suceder de aquellos tamaños golpes con que se amenazaban; y la señora del coche y las demás criadas suyas estaban haciendo mil votos y ofrecimientos a todas las imágenes y casas de devoción de España, porque Dios librase a su escudero y a ellas de aquel tan grande peligro en que se hallaban. Pero está el daño de todo esto que en este punto y término deja pendiente el autor desta historia esta batalla, disculpándose que no halló más escrito destas hazañas de don Quijote de las que deja referidas. Bien es verdad que el segundo autor desta obra no quiso creer que tan curiosa historia estuviese entregada a las leyes del olvido, ni que hubiesen sido tan poco curiosos los ingenios de la Mancha que no tuviesen en sus archivos o en sus escritorios algunos papeles que deste famoso caballero tratasen; y así, con esta imaginación, no se desesperó de hallar el fin desta apacible historia, el cual, siéndole el cielo favorable, le halló del modo que se contará en la segunda parte. Segunda parte del ingenioso hidalgo don Quijote de la Mancha Capítulo IX. Donde se concluye y da fin a la estupenda batalla que el gallardo vizcaíno y el valiente manchego tuvieron Dejamos en la primera parte desta historia al valeroso vizcaíno y al famoso don Quijote con las espadas altas y desnudas, en guisa de descargar dos furibundos fendientes, tales que, si en lleno se acertaban, por lo menos se dividirían y fenderían de arriba abajo y abrirían como una granada; y que en aquel punto tan dudoso paró y quedó destroncada tan sabrosa historia, sin que nos diese noticia su autor dónde se podría hallar lo que della faltaba. Causóme esto mucha pesadumbre, porque el gusto de haber leído tan poco se volvía en disgusto, de pensar el mal camino que se ofrecía para hallar lo mucho que, a mi parecer, faltaba de tan sabroso cuento. Parecióme cosa imposible y fuera de toda buena costumbre que a tan buen caballero le hubiese faltado algún sabio que tomara a cargo el escrebir sus nunca vistas hazañas, cosa que no faltó a ninguno de los caballeros andantes, de los que dicen las gentes que van a sus aventuras, porque cada uno dellos tenía uno o dos sabios, como de molde, que no solamente escribían sus hechos, sino que pintaban sus más mínimos pensamientos y niñerías, por más escondidas que fuesen; y no había de ser tan desdichado tan buen caballero, que le faltase a él lo que sobró a Platir y a otros semejantes. Y así, no podía inclinarme a creer que tan gallarda historia hubiese quedado manca y estropeada; y echaba la culpa a la malignidad del tiempo, devorador y consumidor de todas las cosas, el cual, o la tenía oculta o consumida. Por otra parte, me parecía que, pues entre sus libros se habían hallado tan modernos como Desengaño de celos y Ninfas y Pastores de Henares, que también su historia debía de ser moderna; y que, ya que no estuviese escrita, estaría en la memoria de la gente de su aldea y de las a ella circunvecinas. Esta imaginación me traía confuso y deseoso de saber, real y verdaderamente, toda la vida y milagros de nuestro famoso español don Quijote de la Mancha, luz y espejo de la caballería manchega, y el primero que en nuestra edad y en estos tan calamitosos tiempos se puso al trabajo y ejercicio de las andantes armas, y al desfacer agravios, socorrer viudas, amparar doncellas, de aquellas que andaban con sus azotes y palafrenes, y con toda su virginidad a cuestas, de monte en monte y de valle en valle; que, si no era que algún follón, o algún villano de hacha y capellina, o algún descomunal gigante las forzaba, doncella hubo en los pasados tiempos que, al cabo de ochenta años, que en todos ellos no durmió un día debajo de tejado, y se fue tan entera a la sepultura como la madre que la había parido. Digo, pues, que, por estos y otros muchos respetos, es digno nuestro gallardo Quijote de continuas y memorables alabanzas; y aun a mí no se me deben negar, por el trabajo y diligencia que puse en buscar el fin desta agradable historia; aunque bien sé que si el cielo, el caso y la fortuna no me ayudan, el mundo quedará falto y sin el pasatiempo y gusto que bien casi dos horas podrá tener el que con atención la leyere. Pasó, pues, el hallarla en esta manera: Estando yo un día en el Alcaná de Toledo, llegó un muchacho a vender unos cartapacios y papeles viejos a un sedero; y, como yo soy aficionado a leer, aunque sean los papeles rotos de las calles, llevado desta mi natural inclinación, tomé un cartapacio de los que el muchacho vendía, y vile con caracteres que conocí ser arábigos. Y, puesto que, aunque los conocía, no los sabía leer, anduve mirando si parecía por allí algún morisco aljamiado que los leyese; y no fue muy dificultoso hallar intérprete semejante, pues, aunque le buscara de otra mejor y más antigua lengua, le hallara. En fin, la suerte me deparó uno, que, diciéndole mi deseo y poniéndole el libro en las manos, le abrió por medio, y, leyendo un poco en él, se comenzó a reír. Preguntéle yo que de qué se reía, y respondióme que de una cosa que tenía aquel libro escrita en el margen por anotación. Díjele que me la dijese; y él, sin dejar la risa, dijo: -Está, como he dicho, aquí en el margen escrito esto: "Esta Dulcinea del Toboso, tantas veces en esta historia referida, dicen que tuvo la mejor mano para salar puercos que otra mujer de toda la Mancha". Cuando yo oí decir "Dulcinea del Toboso", quedé atónito y suspenso, porque luego se me representó que aquellos cartapacios contenían la historia de don Quijote. Con esta imaginación, le di priesa que leyese el principio, y, haciéndolo ansí, volviendo de improviso el arábigo en castellano, dijo que decía: Historia de don Quijote de la Mancha, escrita por Cide Hamete Benengeli, historiador arábigo. Mucha discreción fue menester para disimular el contento que recebí cuando llegó a mis oídos el título del libro; y, salteándosele al sedero, compré al muchacho todos los papeles y cartapacios por medio real; que, si él tuviera discreción y supiera lo que yo los deseaba, bien se pudiera prometer y llevar más de seis reales de la compra. Apartéme luego con el morisco por el claustro de la iglesia mayor, y roguéle me volviese aquellos cartapacios, todos los que trataban de don Quijote, en lengua castellana, sin quitarles ni añadirles nada, ofreciéndole la paga que él quisiese. Contentóse con dos arrobas de pasas y dos fanegas de trigo, y prometió de traducirlos bien y fielmente y con mucha brevedad. Pero yo, por facilitar más el negocio y por no dejar de la mano tan buen hallazgo, le truje a mi casa, donde en poco más de mes y medio la tradujo toda, del mesmo modo que aquí se refiere. Estaba en el primero cartapacio, pintada muy al natural, la batalla de don Quijote con el vizcaíno, puestos en la mesma postura que la historia cuenta, levantadas las espadas, el uno cubierto de su rodela, el otro de la almohada, y la mula del vizcaíno tan al vivo, que estaba mostrando ser de alquiler a tiro de ballesta. Tenía a los pies escrito el vizcaíno un título que decía: Don Sancho de Azpetia, que, sin duda, debía de ser su nombre, y a los pies de Rocinante estaba otro que decía: Don Quijote. Estaba Rocinante maravillosamente pintado, tan largo y tendido, tan atenuado y flaco, con tanto espinazo, tan hético confirmado, que mostraba bien al descubierto con cuánta advertencia y propriedad se le había puesto el nombre de Rocinante. Junto a él estaba Sancho Panza, que tenía del cabestro a su asno, a los pies del cual estaba otro rétulo que decía: Sancho Zancas, y debía de ser que tenía, a lo que mostraba la pintura, la barriga grande, el talle corto y las zancas largas; y por esto se le debió de poner nombre de Panza y de Zancas, que con estos dos sobrenombres le llama algunas veces la historia. Otras algunas menudencias había que advertir, pero todas son de poca importancia y que no hacen al caso a la verdadera relación de la historia; que ninguna es mala como sea verdadera. Si a ésta se le puede poner alguna objeción cerca de su verdad, no podrá ser otra sino haber sido su autor arábigo, siendo muy propio de los de aquella nación ser mentirosos; aunque, por ser tan nuestros enemigos, antes se puede entender haber quedado falto en ella que demasiado. Y ansí me parece a mí, pues, cuando pudiera y debiera estender la pluma en las alabanzas de tan buen caballero, parece que de industria las pasa en silencio: cosa mal hecha y peor pensada, habiendo y debiendo ser los historiadores puntuales, verdaderos y no nada apasionados, y que ni el interés ni el miedo, el rancor ni la afición, no les hagan torcer del camino de la verdad, cuya madre es la historia, émula del tiempo, depósito de las acciones, testigo de lo pasado, ejemplo y aviso de lo presente, advertencia de lo por venir. En ésta sé que se hallará todo lo que se acertare a desear en la más apacible; y si algo bueno en ella faltare, para mí tengo que fue por culpa del galgo de su autor, antes que por falta del sujeto. En fin, su segunda parte, siguiendo la tradución, comenzaba desta manera: Puestas y levantadas en alto las cortadoras espadas de los dos valerosos y enojados combatientes, no parecía sino que estaban amenazando al cielo, a la tierra y al abismo: tal era el denuedo y continente que tenían. Y el primero que fue a descargar el golpe fue el colérico vizcaíno, el cual fue dado con tanta fuerza y tanta furia que, a no volvérsele la espada en el camino, aquel solo golpe fuera bastante para dar fin a su rigurosa contienda y a todas las aventuras de nuestro caballero; mas la buena suerte, que para mayores cosas le tenía guardado, torció la espada de su contrario, de modo que, aunque le acertó en el hombro izquierdo, no le hizo otro daño que desarmarle todo aquel lado, llevándole de camino gran parte de la celada, con la mitad de la oreja; que todo ello con espantosa ruina vino al suelo, dejándole muy maltrecho. ¡Válame Dios, y quién será aquel que buenamente pueda contar ahora la rabia que entró en el corazón de nuestro manchego, viéndose parar de aquella manera! No se diga más, sino que fue de manera que se alzó de nuevo en los estribos, y, apretando más la espada en las dos manos, con tal furia descargó sobre el vizcaíno, acertándole de lleno sobre la almohada y sobre la cabeza, que, sin ser parte tan buena defensa, como si cayera sobre él una montaña, comenzó a echar sangre por las narices, y por la boca y por los oídos, y a dar muestras de caer de la mula abajo, de donde cayera, sin duda, si no se abrazara con el cuello; pero, con todo eso, sacó los pies de los estribos y luego soltó los brazos; y la mula, espantada del terrible golpe, dio a correr por el campo, y a pocos corcovos dio con su dueño en tierra. Estábaselo con mucho sosiego mirando don Quijote, y, como lo vio caer, saltó de su caballo y con mucha ligereza se llegó a él, y, poniéndole la punta de la espada en los ojos, le dijo que se rindiese; si no, que le cortaría la cabeza. Estaba el vizcaíno tan turbado que no podía responder palabra, y él lo pasara mal, según estaba ciego don Quijote, si las señoras del coche, que hasta entonces con gran desmayo habían mirado la pendencia, no fueran adonde estaba y le pidieran con mucho encarecimiento les hiciese tan gran merced y favor de perdonar la vida a aquel su escudero. A lo cual don Quijote respondió, con mucho entono y gravedad: -Por cierto, fermosas señoras, yo soy muy contento de hacer lo que me pedís; mas ha de ser con una condición y concierto, y es que este caballero me ha de prometer de ir al lugar del Toboso y presentarse de mi parte ante la sin par doña Dulcinea, para que ella haga dél lo que más fuere de su voluntad. La temerosa y desconsolada señora, sin entrar en cuenta de lo que don Quijote pedía, y sin preguntar quién Dulcinea fuese, le prometió que el escudero haría todo aquello que de su parte le fuese mandado. -Pues en fe de esa palabra, yo no le haré más daño, puesto que me lo tenía bien merecido. Capítulo X. De lo que más le avino a don Quijote con el vizcaíno, y del peligro en que se vio con una turba de yangüeses Ya en este tiempo se había levantado Sancho Panza, algo maltratado de los mozos de los frailes, y había estado atento a la batalla de su señor don Quijote, y rogaba a Dios en su corazón fuese servido de darle vitoria y que en ella ganase alguna ínsula de donde le hiciese gobernador, como se lo había prometido. Viendo, pues, ya acabada la pendencia, y que su amo volvía a subir sobre Rocinante, llegó a tenerle el estribo; y antes que subiese se hincó de rodillas delante dél, y, asiéndole de la mano, se la besó y le dijo: -Sea vuestra merced servido, señor don Quijote mío, de darme el gobierno de la ínsula que en esta rigurosa pendencia se ha ganado; que, por grande que sea, yo me siento con fuerzas de saberla gobernar tal y tan bien como otro que haya gobernado ínsulas en el mundo. A lo cual respondió don Quijote: -Advertid, hermano Sancho, que esta aventura y las a ésta semejantes no son aventuras de ínsulas, sino de encrucijadas, en las cuales no se gana otra cosa que sacar rota la cabeza o una oreja menos. Tened paciencia, que aventuras se ofrecerán donde no solamente os pueda hacer gobernador, sino más adelante. Agradecióselo mucho Sancho, y, besándole otra vez la mano y la falda de la loriga, le ayudó a subir sobre Rocinante; y él subió sobre su asno y comenzó a seguir a su señor, que, a paso tirado, sin despedirse ni hablar más con las del coche, se entró por un bosque que allí junto estaba. Seguíale Sancho a todo el trote de su jumento, pero caminaba tanto Rocinante que, viéndose quedar atrás, le fue forzoso dar voces a su amo que se aguardase. Hízolo así don Quijote, teniendo las riendas a Rocinante hasta que llegase su cansado escudero, el cual, en llegando, le dijo: -Paréceme, señor, que sería acertado irnos a retraer a alguna iglesia; que, según quedó maltrecho aquel con quien os combatistes, no será mucho que den noticia del caso a la Santa Hermandad y nos prendan; y a fe que si lo hacen, que primero que salgamos de la cárcel que nos ha de sudar el hopo. -Calla -dijo don Quijote-. Y ¿dónde has visto tú, o leído jamás, que caballero andante haya sido puesto ante la justicia, por más homicidios que hubiese cometido? -Yo no sé nada de omecillos -respondió Sancho-, ni en mi vida le caté a ninguno; sólo sé que la Santa Hermandad tiene que ver con los que pelean en el campo, y en esotro no me entremeto. -Pues no tengas pena, amigo -respondió don Quijote-, que yo te sacaré de las manos de los caldeos, cuanto más de las de la Hermandad. Pero dime, por tu vida: ¿has visto más valeroso caballero que yo en todo lo descubierto de la tierra? ¿Has leído en historias otro que tenga ni haya tenido más brío en acometer, más aliento en el perseverar, más destreza en el herir, ni más maña en el derribar? -La verdad sea -respondió Sancho- que yo no he leído ninguna historia jamás, porque ni sé leer ni escrebir; mas lo que osaré apostar es que más atrevido amo que vuestra merced yo no le he servido en todos los días de mi vida, y quiera Dios que estos atrevimientos no se paguen donde tengo dicho. Lo que le ruego a vuestra merced es que se cure, que le va mucha sangre de esa oreja; que aquí traigo hilas y un poco de ungüento blanco en las alforjas. -Todo eso fuera bien escusado -respondió don Quijote- si a mí se me acordara de hacer una redoma del bálsamo de Fierabrás, que con sola una gota se ahorraran tiempo y medicinas. -¿Qué redoma y qué bálsamo es ése? -dijo Sancho Panza. -Es un bálsamo -respondió don Quijote- de quien tengo la receta en la memoria, con el cual no hay que tener temor a la muerte, ni hay pensar morir de ferida alguna. Y ansí, cuando yo le haga y te le dé, no tienes más que hacer sino que, cuando vieres que en alguna batalla me han partido por medio del cuerpo (como muchas veces suele acontecer), bonitamente la parte del cuerpo que hubiere caído en el suelo, y con mucha sotileza, antes que la sangre se yele, la pondrás sobre la otra mitad que quedare en la silla, advirtiendo de encajallo igualmente y al justo; luego me darás a beber solos dos tragos del bálsamo que he dicho, y verásme quedar más sano que una manzana. -Si eso hay -dijo Panza-, yo renuncio desde aquí el gobierno de la prometida ínsula, y no quiero otra cosa, en pago de mis muchos y buenos servicios, sino que vuestra merced me dé la receta de ese estremado licor; que para mí tengo que valdrá la onza adondequiera más de a dos reales, y no he menester yo más para pasar esta vida honrada y descansadamente. Pero es de saber agora si tiene mucha costa el hacelle. -Con menos de tres reales se pueden hacer tres azumbres -respondió don Quijote. -¡Pecador de mí! -replicó Sancho-. ¿Pues a qué aguarda vuestra merced a hacelle y a enseñármele? -Calla, amigo -respondió don Quijote-, que mayores secretos pienso enseñarte y mayores mercedes hacerte; y, por agora, curémonos, que la oreja me duele más de lo que yo quisiera. Sacó Sancho de las alforjas hilas y ungüento. Mas, cuando don Quijote llegó a ver rota su celada, pensó perder el juicio, y, puesta la mano en la espada y alzando los ojos al cielo, dijo: -Yo hago juramento al Criador de todas las cosas y a los santos cuatro Evangelios, donde más largamente están escritos, de hacer la vida que hizo el grande marqués de Mantua cuando juró de vengar la muerte de su sobrino Valdovinos, que fue de no comer pan a manteles, ni con su mujer folgar, y otras cosas que, aunque dellas no me acuerdo, las doy aquí por expresadas, hasta tomar entera venganza del que tal desaguisado me fizo. Oyendo esto Sancho, le dijo: -Advierta vuestra merced, señor don Quijote, que si el caballero cumplió lo que se le dejó ordenado de irse a presentar ante mi señora Dulcinea del Toboso, ya habrá cumplido con lo que debía, y no merece otra pena si no comete nuevo delito. -Has hablado y apuntado muy bien -respondió don Quijote-; y así, anulo el juramento en cuanto lo que toca a tomar dél nueva venganza; pero hágole y confírmole de nuevo de hacer la vida que he dicho, hasta tanto que quite por fuerza otra celada tal y tan buena como ésta a algún caballero. Y no pienses, Sancho, que así a humo de pajas hago esto, que bien tengo a quien imitar en ello; que esto mesmo pasó, al pie de la letra, sobre el yelmo de Mambrino, que tan caro le costó a Sacripante. -Que dé al diablo vuestra merced tales juramentos, señor mío -replicó Sancho-; que son muy en daño de la salud y muy en perjuicio de la conciencia. Si no, dígame ahora: si acaso en muchos días no topamos hombre armado con celada, ¿qué hemos de hacer? ¿Hase de cumplir el juramento, a despecho de tantos inconvenientes e incomodidades, como será el dormir vestido, y el no dormir en poblado, y otras mil penitencias que contenía el juramento de aquel loco viejo del marqués de Mantua, que vuestra merced quiere revalidar ahora? Mire vuestra merced bien, que por todos estos caminos no andan hombres armados, sino arrieros y carreteros, que no sólo no traen celadas, pero quizá no las han oído nombrar en todos los días de su vida. -Engáñaste en eso -dijo don Quijote-, porque no habremos estado dos horas por estas encrucijadas, cuando veamos más armados que los que vinieron sobre Albraca a la conquista de Angélica la Bella. -Alto, pues; sea ansí -dijo Sancho-, y a Dios prazga que nos suceda bien, y que se llegue ya el tiempo de ganar esta ínsula que tan cara me cuesta, y muérame yo luego. -Ya te he dicho, Sancho, que no te dé eso cuidado alguno; que, cuando faltare ínsula, ahí está el reino de Dinamarca o el de Soliadisa, que te vendrán como anillo al dedo; y más, que, por ser en tierra firme, te debes más alegrar. Pero dejemos esto para su tiempo, y mira si traes algo en esas alforjas que comamos, porque vamos luego en busca de algún castillo donde alojemos esta noche y hagamos el bálsamo que te he dicho; porque yo te voto a Dios que me va doliendo mucho la oreja. -Aquí trayo una cebolla, y un poco de queso y no sé cuántos mendrugos de pan -dijo Sancho-, pero no son manjares que pertenecen a tan valiente caballero como vuestra merced. -¡Qué mal lo entiendes! -respondió don Quijote-. Hágote saber, Sancho, que es honra de los caballeros andantes no comer en un mes; y, ya que coman, sea de aquello que hallaren más a mano; y esto se te hiciera cierto si hubieras leído tantas historias como yo; que, aunque han sido muchas, en todas ellas no he hallado hecha relación de que los caballeros andantes comiesen, si no era acaso y en algunos suntuosos banquetes que les hacían, y los demás días se los pasaban en flores. Y, aunque se deja entender que no podían pasar sin comer y sin hacer todos los otros menesteres naturales, porque, en efeto, eran hombres como nosotros, hase de entender también que, andando lo más del tiempo de su vida por las florestas y despoblados, y sin cocinero, que su más ordinaria comida sería de viandas rústicas, tales como las que tú ahora me ofreces. Así que, Sancho amigo, no te congoje lo que a mí me da gusto. Ni querrás tú hacer mundo nuevo, ni sacar la caballería andante de sus quicios. -Perdóneme vuestra merced -dijo Sancho-; que, como yo no sé leer ni escrebir, como otra vez he dicho, no sé ni he caído en las reglas de la profesión caballeresca; y, de aquí adelante, yo proveeré las alforjas de todo género de fruta seca para vuestra merced, que es caballero, y para mí las proveeré, pues no lo soy, de otras cosas volátiles y de más sustancia. -No digo yo, Sancho -replicó don Quijote-, que sea forzoso a los caballeros andantes no comer otra cosa sino esas frutas que dices, sino que su más ordinario sustento debía de ser dellas, y de algunas yerbas que hallaban por los campos, que ellos conocían y yo también conozco. -Virtud es -respondió Sancho- conocer esas yerbas; que, según yo me voy imaginando, algún día será menester usar de ese conocimiento. Y, sacando, en esto, lo que dijo que traía, comieron los dos en buena paz y compaña. Pero, deseosos de buscar donde alojar aquella noche, acabaron con mucha brevedad su pobre y seca comida. Subieron luego a caballo, y diéronse priesa por llegar a poblado antes que anocheciese; pero faltóles el sol, y la esperanza de alcanzar lo que deseaban, junto a unas chozas de unos cabreros, y así, determinaron de pasarla allí; que cuanto fue de pesadumbre para Sancho no llegar a poblado, fue de contento para su amo dormirla al cielo descubierto, por parecerle que cada vez que esto le sucedía era hacer un acto posesivo que facilitaba la prueba de su caballería. Capítulo XI. De lo que le sucedió a don Quijote con unos cabreros Fue recogido de los cabreros con buen ánimo; y, habiendo Sancho, lo mejor que pudo, acomodado a Rocinante y a su jumento, se fue tras el olor que despedían de sí ciertos tasajos de cabra que hirviendo al fuego en un caldero estaban; y, aunque él quisiera en aquel mesmo punto ver si estaban en sazón de trasladarlos del caldero al estómago, lo dejó de hacer, porque los cabreros los quitaron del fuego, y, tendiendo por el suelo unas pieles de ovejas, aderezaron con mucha priesa su rústica mesa y convidaron a los dos, con muestras de muy buena voluntad, con lo que tenían. Sentáronse a la redonda de las pieles seis dellos, que eran los que en la majada había, habiendo primero con groseras ceremonias rogado a don Quijote que se sentase sobre un dornajo que vuelto del revés le pusieron. Sentóse don Quijote, y quedábase Sancho en pie para servirle la copa, que era hecha de cuerno. Viéndole en pie su amo, le dijo: -Porque veas, Sancho, el bien que en sí encierra la andante caballería, y cuán a pique están los que en cualquiera ministerio della se ejercitan de venir brevemente a ser honrados y estimados del mundo, quiero que aquí a mi lado y en compañía desta buena gente te sientes, y que seas una mesma cosa conmigo, que soy tu amo y natural señor; que comas en mi plato y bebas por donde yo bebiere; porque de la caballería andante se puede decir lo mesmo que del amor se dice: que todas las cosas iguala. -¡Gran merced! -dijo Sancho-; pero sé decir a vuestra merced que, como yo tuviese bien de comer, tan bien y mejor me lo comería en pie y a mis solas como sentado a par de un emperador. Y aun, si va a decir verdad, mucho mejor me sabe lo que como en mi rincón, sin melindres ni respetos, aunque sea pan y cebolla, que los gallipavos de otras mesas donde me sea forzoso mascar despacio, beber poco, limpiarme a menudo, no estornudar ni toser si me viene gana, ni hacer otras cosas que la soledad y la libertad traen consigo. Ansí que, señor mío, estas honras que vuestra merced quiere darme por ser ministro y adherente de la caballería andante, como lo soy siendo escudero de vuestra merced, conviértalas en otras cosas que me sean de más cómodo y provecho; que éstas, aunque las doy por bien recebidas, las renuncio para desde aquí al fin del mundo. -Con todo eso, te has de sentar; porque a quien se humilla, Dios le ensalza. Y, asiéndole por el brazo, le forzó a que junto dél se sentase. No entendían los cabreros aquella jerigonza de escuderos y de caballeros andantes, y no hacían otra cosa que comer y callar, y mirar a sus huéspedes, que, con mucho donaire y gana, embaulaban tasajo como el puño. Acabado el servicio de carne, tendieron sobre las zaleas gran cantidad de bellotas avellanadas, y juntamente pusieron un medio queso, más duro que si fuera hecho de argamasa. No estaba, en esto, ocioso el cuerno, porque andaba a la redonda tan a menudo (ya lleno, ya vacío, como arcaduz de noria) que con facilidad vació un zaque de dos que estaban de manifiesto. Después que don Quijote hubo bien satisfecho su estómago, tomó un puño de bellotas en la mano, y, mirándolas atentamente, soltó la voz a semejantes razones: -Dichosa edad y siglos dichosos aquéllos a quien los antiguos pusieron nombre de dorados, y no porque en ellos el oro, que en esta nuestra edad de hierro tanto se estima, se alcanzase en aquella venturosa sin fatiga alguna, sino porque entonces los que en ella vivían ignoraban estas dos palabras de tuyo y mío. Eran en aquella santa edad todas las cosas comunes; a nadie le era necesario, para alcanzar su ordinario sustento, tomar otro trabajo que alzar la mano y alcanzarle de las robustas encinas, que liberalmente les estaban convidando con su dulce y sazonado fruto. Las claras fuentes y corrientes ríos, en magnífica abundancia, sabrosas y transparentes aguas les ofrecían. En las quiebras de las peñas y en lo hueco de los árboles formaban su república las solícitas y discretas abejas, ofreciendo a cualquiera mano, sin interés alguno, la fértil cosecha de su dulcísimo trabajo. Los valientes alcornoques despedían de sí, sin otro artificio que el de su cortesía, sus anchas y livianas cortezas, con que se comenzaron a cubrir las casas, sobre rústicas estacas sustentadas, no más que para defensa de las inclemencias del cielo. Todo era paz entonces, todo amistad, todo concordia; aún no se había atrevido la pesada reja del corvo arado a abrir ni visitar las entrañas piadosas de nuestra primera madre, que ella, sin ser forzada, ofrecía, por todas las partes de su fértil y espacioso seno, lo que pudiese hartar, sustentar y deleitar a los hijos que entonces la poseían. Entonces sí que andaban las simples y hermosas zagalejas de valle en valle y de otero en otero, en trenza y en cabello, sin más vestidos de aquellos que eran menester para cubrir honestamente lo que la honestidad quiere y ha querido siempre que se cubra; y no eran sus adornos de los que ahora se usan, a quien la púrpura de Tiro y la por tantos modos martirizada seda encarecen, sino de algunas hojas verdes de lampazos y yedra entretejidas, con lo que quizá iban tan pomposas y compuestas como van agora nuestras cortesanas con las raras y peregrinas invenciones que la curiosidad ociosa les ha mostrado. Entonces se decoraban los concetos amorosos del alma simple y sencillamente, del mesmo modo y manera que ella los concebía, sin buscar artificioso rodeo de palabras para encarecerlos. No había la fraude, el engaño ni la malicia mezcládose con la verdad y llaneza. La justicia se estaba en sus proprios términos, sin que la osasen turbar ni ofender los del favor y los del interese, que tanto ahora la menoscaban, turban y persiguen. La ley del encaje aún no se había sentado en el entendimiento del juez, porque entonces no había qué juzgar, ni quién fuese juzgado. Las doncellas y la honestidad andaban, como tengo dicho, por dondequiera, sola y señora, sin temor que la ajena desenvoltura y lascivo intento le menoscabasen, y su perdición nacía de su gusto y propria voluntad. Y agora, en estos nuestros detestables siglos, no está segura ninguna, aunque la oculte y cierre otro nuevo laberinto como el de Creta; porque allí, por los resquicios o por el aire, con el celo de la maldita solicitud, se les entra la amorosa pestilencia y les hace dar con todo su recogimiento al traste. Para cuya seguridad, andando más los tiempos y creciendo más la malicia, se instituyó la orden de los caballeros andantes, para defender las doncellas, amparar las viudas y socorrer a los huérfanos y a los menesterosos. Desta orden soy yo, hermanos cabreros, a quien agradezco el gasaje y buen acogimiento que hacéis a mí y a mi escudero; que, aunque por ley natural están todos los que viven obligados a favorecer a los caballeros andantes, todavía, por saber que sin saber vosotros esta obligación me acogistes y regalastes, es razón que, con la voluntad a mí posible, os agradezca la vuestra. Toda esta larga arenga -que se pudiera muy bien escusar- dijo nuestro caballero porque las bellotas que le dieron le trujeron a la memoria la edad dorada y antojósele hacer aquel inútil razonamiento a los cabreros, que, sin respondelle palabra, embobados y suspensos, le estuvieron escuchando. Sancho, asimesmo, callaba y comía bellotas, y visitaba muy a menudo el segundo zaque, que, porque se enfriase el vino, le tenían colgado de un alcornoque. Más tardó en hablar don Quijote que en acabarse la cena; al fin de la cual, uno de los cabreros dijo: -Para que con más veras pueda vuestra merced decir, señor caballero andante, que le agasajamos con prompta y buena voluntad, queremos darle solaz y contento con hacer que cante un compañero nuestro que no tardará mucho en estar aquí; el cual es un zagal muy entendido y muy enamorado, y que, sobre todo, sabe leer y escrebir y es músico de un rabel, que no hay más que desear. Apenas había el cabrero acabado de decir esto, cuando llegó a sus oídos el son del rabel, y de allí a poco llegó el que le tañía, que era un mozo de hasta veinte y dos años, de muy buena gracia. Preguntáronle sus compañeros si había cenado, y, respondiendo que sí, el que había hecho los ofrecimientos le dijo: -De esa manera, Antonio, bien podrás hacernos placer de cantar un poco, porque vea este señor huésped que tenemos quien; también por los montes y selvas hay quien sepa de música. Hémosle dicho tus buenas habilidades, y deseamos que las muestres y nos saques verdaderos; y así, te ruego por tu vida que te sientes y cantes el romance de tus amores que te compuso el beneficiado tu tío, que en el pueblo ha parecido muy bien. -Que me place -respondió el mozo. Y, sin hacerse más de rogar, se sentó en el tronco de una desmochada encina, y, templando su rabel, de allí a poco, con muy buena gracia, comenzó a cantar, diciendo desta manera: Antonio -Yo sé, Olalla, que me adoras, puesto que no me lo has dicho ni aun con los ojos siquiera, mudas lenguas de amoríos. Porque sé que eres sabida, en que me quieres me afirmo; que nunca fue desdichado amor que fue conocido. Bien es verdad que tal vez, Olalla, me has dado indicio que tienes de bronce el alma y el blanco pecho de risco. Mas allá entre tus reproches y honestísimos desvíos, tal vez la esperanza muestra la orilla de su vestido. Abalánzase al señuelo mi fe, que nunca ha podido, ni menguar por no llamado, ni crecer por escogido. Si el amor es cortesía, de la que tienes colijo que el fin de mis esperanzas ha de ser cual imagino. Y si son servicios parte de hacer un pecho benigno, algunos de los que he hecho fortalecen mi partido. Porque si has mirado en ello, más de una vez habrás visto que me he vestido en los lunes lo que me honraba el domingo. Como el amor y la gala andan un mesmo camino, en todo tiempo a tus ojos quise mostrarme polido. Dejo el bailar por tu causa, ni las músicas te pinto que has escuchado a deshoras y al canto del gallo primo. No cuento las alabanzas que de tu belleza he dicho; que, aunque verdaderas, hacen ser yo de algunas malquisto. Teresa del Berrocal, yo alabándote, me dijo: ''Tal piensa que adora a un ángel, y viene a adorar a un jimio; merced a los muchos dijes y a los cabellos postizos, y a hipócritas hermosuras, que engañan al Amor mismo''. Desmentíla y enojóse; volvió por ella su primo: desafióme, y ya sabes lo que yo hice y él hizo. No te quiero yo a montón, ni te pretendo y te sirvo por lo de barraganía; que más bueno es mi designio. Coyundas tiene la Iglesia que son lazadas de sirgo; pon tú el cuello en la gamella; verás como pongo el mío. Donde no, desde aquí juro, por el santo más bendito, de no salir destas sierras sino para capuchino. Con esto dio el cabrero fin a su canto; y, aunque don Quijote le rogó que algo más cantase, no lo consintió Sancho Panza, porque estaba más para dormir que para oír canciones. Y ansí, dijo a su amo: -Bien puede vuestra merced acomodarse desde luego adonde ha de posar esta noche, que el trabajo que estos buenos hombres tienen todo el día no permite que pasen las noches cantando. -Ya te entiendo, Sancho -le respondió don Quijote-; que bien se me trasluce que las visitas del zaque piden más recompensa de sueño que de música. -A todos nos sabe bien, bendito sea Dios -respondió Sancho. -No lo niego -replicó don Quijote-, pero acomódate tú donde quisieres, que los de mi profesión mejor parecen velando que durmiendo. Pero, con todo esto, sería bien, Sancho, que me vuelvas a curar esta oreja, que me va doliendo más de lo que es menester. Hizo Sancho lo que se le mandaba; y, viendo uno de los cabreros la herida, le dijo que no tuviese pena, que él pondría remedio con que fácilmente se sanase. Y, tomando algunas hojas de romero, de mucho que por allí había, las mascó y las mezcló con un poco de sal, y, aplicándoselas a la oreja, se la vendó muy bien, asegurándole que no había menester otra medicina; y así fue la verdad. Capítulo XII. De lo que contó un cabrero a los que estaban con don Quijote Estando en esto, llegó otro mozo de los que les traían del aldea el bastimento, y dijo: -¿Sabéis lo que pasa en el lugar, compañeros? -¿Cómo lo podemos saber? -respondió uno dellos. -Pues sabed -prosiguió el mozo- que murió esta mañana aquel famoso pastor estudiante llamado Grisóstomo, y se murmura que ha muerto de amores de aquella endiablada moza de Marcela, la hija de Guillermo el rico, aquélla que se anda en hábito de pastora por esos andurriales. -Por Marcela dirás -dijo uno. -Por ésa digo -respondió el cabrero-. Y es lo bueno, que mandó en su testamento que le enterrasen en el campo, como si fuera moro, y que sea al pie de la peña donde está la fuente del alcornoque; porque, según es fama, y él dicen que lo dijo, aquel lugar es adonde él la vio la vez primera. Y también mandó otras cosas, tales, que los abades del pueblo dicen que no se han de cumplir, ni es bien que se cumplan, porque parecen de gentiles. A todo lo cual responde aquel gran su amigo Ambrosio, el estudiante, que también se vistió de pastor con él, que se ha de cumplir todo, sin faltar nada, como lo dejó mandado Grisóstomo, y sobre esto anda el pueblo alborotado; mas, a lo que se dice, en fin se hará lo que Ambrosio y todos los pastores sus amigos quieren; y mañana le vienen a enterrar con gran pompa adonde tengo dicho. Y tengo para mí que ha de ser cosa muy de ver; a lo menos, yo no dejaré de ir a verla, si supiese no volver mañana al lugar. -Todos haremos lo mesmo -respondieron los cabreros-; y echaremos suertes a quién ha de quedar a guardar las cabras de todos. -Bien dices, Pedro -dijo uno-; aunque no será menester usar de esa diligencia, que yo me quedaré por todos. Y no lo atribuyas a virtud y a poca curiosidad mía, sino a que no me deja andar el garrancho que el otro día me pasó este pie. -Con todo eso, te lo agradecemos -respondió Pedro. Y don Quijote rogó a Pedro le dijese qué muerto era aquél y qué pastora aquélla; a lo cual Pedro respondió que lo que sabía era que el muerto era un hijodalgo rico, vecino de un lugar que estaba en aquellas sierras, el cual había sido estudiante muchos años en Salamanca, al cabo de los cuales había vuelto a su lugar, con opinión de muy sabio y muy leído. -«Principalmente, decían que sabía la ciencia de las estrellas, y de lo que pasan, allá en el cielo, el sol y la luna; porque puntualmente nos decía el cris del sol y de la luna.» -Eclipse se llama, amigo, que no cris, el escurecerse esos dos luminares mayores -dijo don Quijote. Mas Pedro, no reparando en niñerías, prosiguió su cuento diciendo: -«Asimesmo adevinaba cuándo había de ser el año abundante o estil.» -Estéril queréis decir, amigo -dijo don Quijote. -Estéril o estil -respondió Pedro-, todo se sale allá. «Y digo que con esto que decía se hicieron su padre y sus amigos, que le daban crédito, muy ricos, porque hacían lo que él les aconsejaba, diciéndoles: ''Sembrad este año cebada, no trigo; en éste podéis sembrar garbanzos y no cebada; el que viene será de guilla de aceite; los tres siguientes no se cogerá gota''.» -Esa ciencia se llama astrología -dijo don Quijote. -No sé yo cómo se llama -replicó Pedro-, mas sé que todo esto sabía, y aún más. «Finalmente, no pasaron muchos meses, después que vino de Salamanca, cuando un día remaneció vestido de pastor, con su cayado y pellico, habiéndose quitado los hábitos largos que como escolar traía; y juntamente se vistió con él de pastor otro su grande amigo, llamado Ambrosio, que había sido su compañero en los estudios. Olvidábaseme de decir como Grisóstomo, el difunto, fue grande hombre de componer coplas; tanto, que él hacía los villancicos para la noche del Nacimiento del Señor, y los autos para el día de Dios, que los representaban los mozos de nuestro pueblo, y todos decían que eran por el cabo. Cuando los del lugar vieron tan de improviso vestidos de pastores a los dos escolares, quedaron admirados, y no podían adivinar la causa que les había movido a hacer aquella tan estraña mudanza. Ya en este tiempo era muerto el padre de nuestro Grisóstomo, y él quedó heredado en mucha cantidad de hacienda, ansí en muebles como en raíces, y en no pequeña cantidad de ganado, mayor y menor, y en gran cantidad de dineros; de todo lo cual quedó el mozo señor desoluto, y en verdad que todo lo merecía, que era muy buen compañero y caritativo y amigo de los buenos, y tenía una cara como una bendición. Después se vino a entender que el haberse mudado de traje no había sido por otra cosa que por andarse por estos despoblados en pos de aquella pastora Marcela que nuestro zagal nombró denantes, de la cual se había enamorado el pobre difunto de Grisóstomo.» Y quiéroos decir agora, porque es bien que lo sepáis, quién es esta rapaza; quizá, y aun sin quizá, no habréis oído semejante cosa en todos los días de vuestra vida, aunque viváis más años que sarna. -Decid Sarra -replicó don Quijote, no pudiendo sufrir el trocar de los vocablos del cabrero. -Harto vive la sarna -respondió Pedro-; y si es, señor, que me habéis de andar zaheriendo a cada paso los vocablos, no acabaremos en un año. -Perdonad, amigo -dijo don Quijote-; que por haber tanta diferencia de sarna a Sarra os lo dije; pero vos respondistes muy bien, porque vive más sarna que Sarra; y proseguid vuestra historia, que no os replicaré más en nada. -«Digo, pues, señor mío de mi alma -dijo el cabrero-, que en nuestra aldea hubo un labrador aún más rico que el padre de Grisóstomo, el cual se llamaba Guillermo, y al cual dio Dios, amén de las muchas y grandes riquezas, una hija, de cuyo parto murió su madre, que fue la más honrada mujer que hubo en todos estos contornos. No parece sino que ahora la veo, con aquella cara que del un cabo tenía el sol y del otro la luna; y, sobre todo, hacendosa y amiga de los pobres, por lo que creo que debe de estar su ánima a la hora de ahora gozando de Dios en el otro mundo. De pesar de la muerte de tan buena mujer murió su marido Guillermo, dejando a su hija Marcela, muchacha y rica, en poder de un tío suyo sacerdote y beneficiado en nuestro lugar. Creció la niña con tanta belleza, que nos hacía acordar de la de su madre, que la tuvo muy grande; y, con todo esto, se juzgaba que le había de pasar la de la hija. Y así fue, que, cuando llegó a edad de catorce a quince años, nadie la miraba que no bendecía a Dios, que tan hermosa la había criado, y los más quedaban enamorados y perdidos por ella. Guardábala su tío con mucho recato y con mucho encerramiento; pero, con todo esto, la fama de su mucha hermosura se estendió de manera que, así por ella como por sus muchas riquezas, no solamente de los de nuestro pueblo, sino de los de muchas leguas a la redonda, y de los mejores dellos, era rogado, solicitado e importunado su tío se la diese por mujer. Mas él, que a las derechas es buen cristiano, aunque quisiera casarla luego, así como la vía de edad, no quiso hacerlo sin su consentimiento, sin tener ojo a la ganancia y granjería que le ofrecía el tener la hacienda de la moza, dilatando su casamiento. Y a fe que se dijo esto en más de un corrillo en el pueblo, en alabanza del buen sacerdote.» Que quiero que sepa, señor andante, que en estos lugares cortos de todo se trata y de todo se murmura; y tened para vos, como yo tengo para mí, que debía de ser demasiadamente bueno el clérigo que obliga a sus feligreses a que digan bien dél, especialmente en las aldeas. -Así es la verdad -dijo don Quijote-, y proseguid adelante, que el cuento es muy bueno, y vos, buen Pedro, le contáis con muy buena gracia. -La del Señor no me falte, que es la que hace al caso. «Y en lo demás sabréis que, aunque el tío proponía a la sobrina y le decía las calidades de cada uno en particular, de los muchos que por mujer la pedían, rogándole que se casase y escogiese a su gusto, jamás ella respondió otra cosa sino que por entonces no quería casarse, y que, por ser tan muchacha, no se sentía hábil para poder llevar la carga del matrimonio. Con estas que daba, al parecer justas escusas, dejaba el tío de importunarla, y esperaba a que entrase algo más en edad y ella supiese escoger compañía a su gusto. Porque decía él, y decía muy bien, que no habían de dar los padres a sus hijos estado contra su voluntad. Pero hételo aquí, cuando no me cato, que remanece un día la melindrosa Marcela hecha pastora; y, sin ser parte su tío ni todos los del pueblo, que se lo desaconsejaban, dio en irse al campo con las demás zagalas del lugar, y dio en guardar su mesmo ganado. Y, así como ella salió en público y su hermosura se vio al descubierto, no os sabré buenamente decir cuántos ricos mancebos, hidalgos y labradores han tomado el traje de Grisóstomo y la andan requebrando por esos campos. Uno de los cuales, como ya está dicho, fue nuestro difunto, del cual decían que la dejaba de querer, y la adoraba. Y no se piense que porque Marcela se puso en aquella libertad y vida tan suelta y de tan poco o de ningún recogimiento, que por eso ha dado indicio, ni por semejas, que venga en menoscabo de su honestidad y recato; antes es tanta y tal la vigilancia con que mira por su honra, que de cuantos la sirven y solicitan ninguno se ha alabado, ni con verdad se podrá alabar, que le haya dado alguna pequeña esperanza de alcanzar su deseo. Que, puesto que no huye ni se esquiva de la compañía y conversación de los pastores, y los trata cortés y amigablemente, en llegando a descubrirle su intención cualquiera dellos, aunque sea tan justa y santa como la del matrimonio, los arroja de sí como con un trabuco. Y con esta manera de condición hace más daño en esta tierra que si por ella entrara la pestilencia; porque su afabilidad y hermosura atrae los corazones de los que la tratan a servirla y a amarla, pero su desdén y desengaño los conduce a términos de desesperarse; y así, no saben qué decirle, sino llamarla a voces cruel y desagradecida, con otros títulos a éste semejantes, que bien la calidad de su condición manifiestan. Y si aquí estuviésedes, señor, algún día, veríades resonar estas sierras y estos valles con los lamentos de los desengañados que la siguen. No está muy lejos de aquí un sitio donde hay casi dos docenas de altas hayas, y no hay ninguna que en su lisa corteza no tenga grabado y escrito el nombre de Marcela; y encima de alguna, una corona grabada en el mesmo árbol, como si más claramente dijera su amante que Marcela la lleva y la merece de toda la hermosura humana. Aquí sospira un pastor, allí se queja otro; acullá se oyen amorosas canciones, acá desesperadas endechas. Cuál hay que pasa todas las horas de la noche sentado al pie de alguna encina o peñasco, y allí, sin plegar los llorosos ojos, embebecido y transportado en sus pensamientos, le halló el sol a la mañana; y cuál hay que, sin dar vado ni tregua a sus suspiros, en mitad del ardor de la más enfadosa siesta del verano, tendido sobre la ardiente arena, envía sus quejas al piadoso cielo. Y déste y de aquél, y de aquéllos y de éstos, libre y desenfadadamente triunfa la hermosa Marcela; y todos los que la conocemos estamos esperando en qué ha de parar su altivez y quién ha de ser el dichoso que ha de venir a domeñar condición tan terrible y gozar de hermosura tan estremada.» Por ser todo lo que he contado tan averiguada verdad, me doy a entender que también lo es la que nuestro zagal dijo que se decía de la causa de la muerte de Grisóstomo. Y así, os aconsejo, señor, que no dejéis de hallaros mañana a su entierro, que será muy de ver, porque Grisóstomo tiene muchos amigos, y no está de este lugar a aquél donde manda enterrarse media legua. -En cuidado me lo tengo -dijo don Quijote-, y agradézcoos el gusto que me habéis dado con la narración de tan sabroso cuento. -¡Oh! -replicó el cabrero-, aún no sé yo la mitad de los casos sucedidos a los amantes de Marcela, mas podría ser que mañana topásemos en el camino algún pastor que nos los dijese. Y, por ahora, bien será que os vais a dormir debajo de techado, porque el sereno os podría dañar la herida, puesto que es tal la medicina que se os ha puesto, que no hay que temer de contrario acidente. Sancho Panza, que ya daba al diablo el tanto hablar del cabrero, solicitó, por su parte, que su amo se entrase a dormir en la choza de Pedro. Hízolo así, y todo lo más de la noche se le pasó en memorias de su señora Dulcinea, a imitación de los amantes de Marcela. Sancho Panza se acomodó entre Rocinante y su jumento, y durmió, no como enamorado desfavorecido, sino como hombre molido a coces. Capítulo XIII. Donde se da fin al cuento de la pastora Marcela, con otros sucesos Mas, apenas comenzó a descubrirse el día por los balcones del oriente, cuando los cinco de los seis cabreros se levantaron y fueron a despertar a don Quijote, y a decille si estaba todavía con propósito de ir a ver el famoso entierro de Grisóstomo, y que ellos le harían compañía. Don Quijote, que otra cosa no deseaba, se levantó y mandó a Sancho que ensillase y enalbardase al momento, lo cual él hizo con mucha diligencia, y con la mesma se pusieron luego todos en camino. Y no hubieron andado un cuarto de legua, cuando, al cruzar de una senda, vieron venir hacia ellos hasta seis pastores, vestidos con pellicos negros y coronadas las cabezas con guirnaldas de ciprés y de amarga adelfa. Traía cada uno un grueso bastón de acebo en la mano. Venían con ellos, asimesmo, dos gentiles hombres de a caballo, muy bien aderezados de camino, con otros tres mozos de a pie que los acompañaban. En llegándose a juntar, se saludaron cortésmente, y, preguntándose los unos a los otros dónde iban, supieron que todos se encaminaban al lugar del entierro; y así, comenzaron a caminar todos juntos. Uno de los de a caballo, hablando con su compañero, le dijo: -Paréceme, señor Vivaldo, que habemos de dar por bien empleada la tardanza que hiciéremos en ver este famoso entierro, que no podrá dejar de ser famoso, según estos pastores nos han contado estrañezas, ansí del muerto pastor como de la pastora homicida. -Así me lo parece a mí -respondió Vivaldo-; y no digo yo hacer tardanza de un día, pero de cuatro la hiciera a trueco de verle. Preguntóles don Quijote qué era lo que habían oído de Marcela y de Grisóstomo. El caminante dijo que aquella madrugada habían encontrado con aquellos pastores, y que, por haberles visto en aquel tan triste traje, les habían preguntado la ocasión por que iban de aquella manera; que uno dellos se lo contó, contando la estrañeza y hermosura de una pastora llamada Marcela, y los amores de muchos que la recuestaban, con la muerte de aquel Grisóstomo a cuyo entierro iban. Finalmente, él contó todo lo que Pedro a don Quijote había contado. Cesó esta plática y comenzóse otra, preguntando el que se llamaba Vivaldo a don Quijote qué era la ocasión que le movía a andar armado de aquella manera por tierra tan pacífica. A lo cual respondió don Quijote: -La profesión de mi ejercicio no consiente ni permite que yo ande de otra manera. El buen paso, el regalo y el reposo, allá se inventó para los blandos cortesanos; mas el trabajo, la inquietud y las armas sólo se inventaron e hicieron para aquellos que el mundo llama caballeros andantes, de los cuales yo, aunque indigno, soy el menor de todos. Apenas le oyeron esto, cuando todos le tuvieron por loco; y, por averiguarlo más y ver qué género de locura era el suyo, le tornó a preguntar Vivaldo que qué quería decir "caballeros andantes". -¿No han vuestras mercedes leído -respondió don Quijote- los anales e historias de Ingalaterra, donde se tratan las famosas fazañas del rey Arturo, que continuamente en nuestro romance castellano llamamos el rey Artús, de quien es tradición antigua y común en todo aquel reino de la Gran Bretaña que este rey no murió, sino que, por arte de encantamento, se convirtió en cuervo, y que, andando los tiempos, ha de volver a reinar y a cobrar su reino y cetro; a cuya causa no se probará que desde aquel tiempo a éste haya ningún inglés muerto cuervo alguno? Pues en tiempo de este buen rey fue instituida aquella famosa orden de caballería de los caballeros de la Tabla Redonda, y pasaron, sin faltar un punto, los amores que allí se cuentan de don Lanzarote del Lago con la reina Ginebra, siendo medianera dellos y sabidora aquella tan honrada dueña Quintañona, de donde nació aquel tan sabido romance, y tan decantado en nuestra España, de: Nunca fuera caballero de damas tan bien servido como fuera Lanzarote cuando de Bretaña vino; con aquel progreso tan dulce y tan suave de sus amorosos y fuertes fechos. Pues desde entonces, de mano en mano, fue aquella orden de caballería estendiéndose y dilatándose por muchas y diversas partes del mundo; y en ella fueron famosos y conocidos por sus fechos el valiente Amadís de Gaula, con todos sus hijos y nietos, hasta la quinta generación, y el valeroso Felixmarte de Hircania, y el nunca como se debe alabado Tirante el Blanco, y casi que en nuestros días vimos y comunicamos y oímos al invencible y valeroso caballero don Belianís de Grecia. Esto, pues, señores, es ser caballero andante, y la que he dicho es la orden de su caballería; en la cual, como otra vez he dicho, yo, aunque pecador, he hecho profesión, y lo mesmo que profesaron los caballeros referidos profeso yo. Y así, me voy por estas soledades y despoblados buscando las aventuras, con ánimo deliberado de ofrecer mi brazo y mi persona a la más peligrosa que la suerte me deparare, en ayuda de los flacos y menesterosos. Por estas razones que dijo, acabaron de enterarse los caminantes que era don Quijote falto de juicio, y del género de locura que lo señoreaba, de lo cual recibieron la mesma admiración que recibían todos aquellos que de nuevo venían en conocimiento della. Y Vivaldo, que era persona muy discreta y de alegre condición, por pasar sin pesadumbre el poco camino que decían que les faltaba, al llegar a la sierra del entierro, quiso darle ocasión a que pasase más adelante con sus disparates. Y así, le dijo: -Paréceme, señor caballero andante, que vuestra merced ha profesado una de las más estrechas profesiones que hay en la tierra, y tengo para mí que aun la de los frailes cartujos no es tan estrecha. -Tan estrecha bien podía ser -respondió nuestro don Quijote-, pero tan necesaria en el mundo no estoy en dos dedos de ponello en duda. Porque, si va a decir verdad, no hace menos el soldado que pone en ejecución lo que su capitán le manda que el mesmo capitán que se lo ordena. Quiero decir que los religiosos, con toda paz y sosiego, piden al cielo el bien de la tierra; pero los soldados y caballeros ponemos en ejecución lo que ellos piden, defendiéndola con el valor de nuestros brazos y filos de nuestras espadas; no debajo de cubierta, sino al cielo abierto, puestos por blanco de los insufribles rayos del sol en verano y de los erizados yelos del invierno. Así que, somos ministros de Dios en la tierra, y brazos por quien se ejecuta en ella su justicia. Y, como las cosas de la guerra y las a ellas tocantes y concernientes no se pueden poner en ejecución sino sudando, afanando y trabajando, síguese que aquellos que la profesan tienen, sin duda, mayor trabajo que aquellos que en sosegada paz y reposo están rogando a Dios favorezca a los que poco pueden. No quiero yo decir, ni me pasa por pensamiento, que es tan buen estado el de caballero andante como el del encerrado religioso; sólo quiero inferir, por lo que yo padezco, que, sin duda, es más trabajoso y más aporreado, y más hambriento y sediento, miserable, roto y piojoso; porque no hay duda sino que los caballeros andantes pasados pasaron mucha malaventura en el discurso de su vida. Y si algunos subieron a ser emperadores por el valor de su brazo, a fe que les costó buen porqué de su sangre y de su sudor; y que si a los que a tal grado subieron les faltaran encantadores y sabios que los ayudaran, que ellos quedaran bien defraudados de sus deseos y bien engañados de sus esperanzas. -De ese parecer estoy yo -replicó el caminante-; pero una cosa, entre otras muchas, me parece muy mal de los caballeros andantes, y es que, cuando se ven en ocasión de acometer una grande y peligrosa aventura, en que se vee manifiesto peligro de perder la vida, nunca en aquel instante de acometella se acuerdan de encomendarse a Dios, como cada cristiano está obligado a hacer en peligros semejantes; antes, se encomiendan a sus damas, con tanta gana y devoción como si ellas fueran su Dios: cosa que me parece que huele algo a gentilidad. -Señor -respondió don Quijote-, eso no puede ser menos en ninguna manera, y caería en mal caso el caballero andante que otra cosa hiciese; que ya está en uso y costumbre en la caballería andantesca que el caballero andante que, al acometer algún gran fecho de armas, tuviese su señora delante,vuelva a ella los ojos blanda y amorosamente, como que le pide con ellos le favorezca y ampare en el dudoso trance que acomete; y aun si nadie le oye, está obligado a decir algunas palabras entre dientes, en que de todo corazón se le encomiende; y desto tenemos innumerables ejemplos en las historias. Y no se ha de entender por esto que han de dejar de encomendarse a Dios; que tiempo y lugar les queda para hacerlo en el discurso de la obra. -Con todo eso -replicó el caminante-, me queda un escrúpulo, y es que muchas veces he leído que se traban palabras entre dos andantes caballeros, y, de una en otra, se les viene a encender la cólera, y a volver los caballos y tomar una buena pieza del campo, y luego, sin más ni más, a todo el correr dellos, se vuelven a encontrar; y, en mitad de la corrida, se encomiendan a sus damas; y lo que suele suceder del encuentro es que el uno cae por las ancas del caballo, pasado con la lanza del contrario de parte a parte, y al otro le viene también que, a no tenerse a las crines del suyo, no pudiera dejar de venir al suelo. Y no sé yo cómo el muerto tuvo lugar para encomendarse a Dios en el discurso de esta tan acelerada obra. Mejor fuera que las palabras que en la carrera gastó encomendándose a su dama las gastara en lo que debía y estaba obligado como cristiano. Cuanto más, que yo tengo para mí que no todos los caballeros andantes tienen damas a quien encomendarse, porque no todos son enamorados. -Eso no puede ser -respondió don Quijote-: digo que no puede ser que haya caballero andante sin dama, porque tan proprio y tan natural les es a los tales ser enamorados como al cielo tener estrellas, y a buen seguro que no se haya visto historia donde se halle caballero andante sin amores; y por el mesmo caso que estuviese sin ellos, no sería tenido por legítimo caballero, sino por bastardo, y que entró en la fortaleza de la caballería dicha, no por la puerta, sino por las bardas, como salteador y ladrón. -Con todo eso -dijo el caminante-, me parece, si mal no me acuerdo, haber leído que don Galaor, hermano del valeroso Amadís de Gaula, nunca tuvo dama señalada a quien pudiese encomendarse; y, con todo esto, no fue tenido en menos, y fue un muy valiente y famoso caballero. A lo cual respondió nuestro don Quijote: -Señor, una golondrina sola no hace verano. Cuanto más, que yo sé que de secreto estaba ese caballero muy bien enamorado; fuera que, aquello de querer a todas bien cuantas bien le parecían era condición natural, a quien no podía ir a la mano. Pero, en resolución, averiguado está muy bien que él tenía una sola a quien él había hecho señora de su voluntad, a la cual se encomendaba muy a menudo y muy secretamente, porque se preció de secreto caballero. -Luego, si es de esencia que todo caballero andante haya de ser enamorado -dijo el caminante-, bien se puede creer que vuestra merced lo es, pues es de la profesión. Y si es que vuestra merced no se precia de ser tan secreto como don Galaor, con las veras que puedo le suplico, en nombre de toda esta compañía y en el mío, nos diga el nombre, patria, calidad y hermosura de su dama; que ella se tendría por dichosa de que todo el mundo sepa que es querida y servida de un tal caballero como vuestra merced parece. Aquí dio un gran suspiro don Quijote, y dijo: -Yo no podré afirmar si la dulce mi enemiga gusta, o no, de que el mundo sepa que yo la sirvo; sólo sé decir, respondiendo a lo que con tanto comedimiento se me pide, que su nombre es Dulcinea; su patria, el Toboso, un lugar de la Mancha; su calidad, por lo menos, ha de ser de princesa, pues es reina y señora mía; su hermosura, sobrehumana, pues en ella se vienen a hacer verdaderos todos los imposibles y quiméricos atributos de belleza que los poetas dan a sus damas: que sus cabellos son oro, su frente campos elíseos, sus cejas arcos del cielo, sus ojos soles, sus mejillas rosas, sus labios corales, perlas sus dientes, alabastro su cuello, mármol su pecho, marfil sus manos, su blancura nieve, y las partes que a la vista humana encubrió la honestidad son tales, según yo pienso y entiendo, que sólo la discreta consideración puede encarecerlas, y no compararlas. -El linaje, prosapia y alcurnia querríamos saber -replicó Vivaldo. A lo cual respondió don Quijote: -No es de los antiguos Curcios, Gayos y Cipiones romanos, ni de los modernos Colonas y Ursinos; ni de los Moncadas y Requesenes de Cataluña, ni menos de los Rebellas y Villanovas de Valencia; Palafoxes, Nuzas, Rocabertis, Corellas, Lunas, Alagones, Urreas, Foces y Gurreas de Aragón; Cerdas, Manriques, Mendozas y Guzmanes de Castilla; Alencastros, Pallas y Meneses de Portogal; pero es de los del Toboso de la Mancha, linaje, aunque moderno, tal, que puede dar generoso principio a las más ilustres familias de los venideros siglos. Y no se me replique en esto, si no fuere con las condiciones que puso Cervino al pie del trofeo de las armas de Orlando, que decía: nadie las mueva que estar no pueda con Roldán a prueba. -Aunque el mío es de los Cachopines de Laredo -respondió el caminante-, no le osaré yo poner con el del Toboso de la Mancha, puesto que, para decir verdad, semejante apellido hasta ahora no ha llegado a mis oídos. -¡Como eso no habrá llegado! -replicó don Quijote. Con gran atención iban escuchando todos los demás la plática de los dos, y aun hasta los mesmos cabreros y pastores conocieron la demasiada falta de juicio de nuestro don Quijote. Sólo Sancho Panza pensaba que cuanto su amo decía era verdad, sabiendo él quién era y habiéndole conocido desde su nacimiento; y en lo que dudaba algo era en creer aquello de la linda Dulcinea del Toboso, porque nunca tal nombre ni tal princesa había llegado jamás a su noticia, aunque vivía tan cerca del Toboso. En estas pláticas iban, cuando vieron que, por la quiebra que dos altas montañas hacían, bajaban hasta veinte pastores, todos con pellicos de negra lana vestidos y coronados con guirnaldas, que, a lo que después pareció, eran cuál de tejo y cuál de ciprés. Entre seis dellos traían unas andas, cubiertas de mucha diversidad de flores y de ramos. Lo cual visto por uno de los cabreros, dijo: -Aquellos que allí vienen son los que traen el cuerpo de Grisóstomo, y el pie de aquella montaña es el lugar donde él mandó que le enterrasen. Por esto se dieron priesa a llegar, y fue a tiempo que ya los que venían habían puesto las andas en el suelo; y cuatro dellos con agudos picos estaban cavando la sepultura a un lado de una dura peña. Recibiéronse los unos y los otros cortésmente; y luego don Quijote y los que con él venían se pusieron a mirar las andas, y en ellas vieron cubierto de flores un cuerpo muerto, vestido como pastor, de edad, al parecer, de treinta años; y, aunque muerto, mostraba que vivo había sido de rostro hermoso y de disposición gallarda. Alrededor dél tenía en las mesmas andas algunos libros y muchos papeles, abiertos y cerrados. Y así los que esto miraban, como los que abrían la sepultura, y todos los demás que allí había, guardaban un maravilloso silencio, hasta que uno de los que al muerto trujeron dijo a otro: -Mirá bien, Ambrosio, si es éste el lugar que Grisóstomo dijo, ya que queréis que tan puntualmente se cumpla lo que dejó mandado en su testamento. -Éste es -respondió Ambrosio-; que muchas veces en él me contó mi desdichado amigo la historia de su desventura. Allí me dijo él que vio la vez primera a aquella enemiga mortal del linaje humano, y allí fue también donde la primera vez le declaró su pensamiento, tan honesto como enamorado, y allí fue la última vez donde Marcela le acabó de desengañar y desdeñar, de suerte que puso fin a la tragedia de su miserable vida. Y aquí, en memoria de tantas desdichas, quiso él que le depositasen en las entrañas del eterno olvido. Y, volviéndose a don Quijote y a los caminantes, prosiguió diciendo: -Ese cuerpo, señores, que con piadosos ojos estáis mirando, fue depositario de un alma en quien el cielo puso infinita parte de sus riquezas. Ése es el cuerpo de Grisóstomo, que fue único en el ingenio, solo en la cortesía, estremo en la gentileza, fénix en la amistad, magnífico sin tasa, grave sin presunción, alegre sin bajeza, y, finalmente, primero en todo lo que es ser bueno, y sin segundo en todo lo que fue ser desdichado. Quiso bien, fue aborrecido; adoró, fue desdeñado; rogó a una fiera, importunó a un mármol, corrió tras el viento, dio voces a la soledad, sirvió a la ingratitud, de quien alcanzó por premio ser despojos de la muerte en la mitad de la carrera de su vida, a la cual dio fin una pastora a quien él procuraba eternizar para que viviera en la memoria de las gentes, cual lo pudieran mostrar bien esos papeles que estáis mirando, si él no me hubiera mandado que los entregara al fuego en habiendo entregado su cuerpo a la tierra. -De mayor rigor y crueldad usaréis vos con ellos -dijo Vivaldo- que su mesmo dueño, pues no es justo ni acertado que se cumpla la voluntad de quien lo que ordena va fuera de todo razonable discurso. Y no le tuviera bueno Augusto César si consintiera que se pusiera en ejecución lo que el divino Mantuano dejó en su testamento mandado. Ansí que, señor Ambrosio, ya que deis el cuerpo de vuestro amigo a la tierra, no queráis dar sus escritos al olvido; que si él ordenó como agraviado, no es bien que vos cumpláis como indiscreto. Antes haced, dando la vida a estos papeles, que la tenga siempre la crueldad de Marcela, para que sirva de ejemplo, en los tiempos que están por venir, a los vivientes, para que se aparten y huyan de caer en semejantes despeñaderos; que ya sé yo, y los que aquí venimos, la historia deste vuestro enamorado y desesperado amigo, y sabemos la amistad vuestra, y la ocasión de su muerte, y lo que dejó mandado al acabar de la vida; de la cual lamentable historia se puede sacar cuánto haya sido la crueldad de Marcela, el amor de Grisóstomo, la fe de la amistad vuestra, con el paradero que tienen los que a rienda suelta corren por la senda que el desvariado amor delante de los ojos les pone. Anoche supimos la muerte de Grisóstomo, y que en este lugar había de ser enterrado; y así, de curiosidad y de lástima, dejamos nuestro derecho viaje, y acordamos de venir a ver con los ojos lo que tanto nos había lastimado en oíllo. Y, en pago desta lástima y del deseo que en nosotros nació de remedialla si pudiéramos, te rogamos, ¡oh discreto Ambrosio! (a lo menos, yo te lo suplico de mi parte), que, dejando de abrasar estos papeles, me dejes llevar algunos dellos. Y, sin aguardar que el pastor respondiese, alargó la mano y tomó algunos de los que más cerca estaban; viendo lo cual Ambrosio, dijo: -Por cortesía consentiré que os quedéis, señor, con los que ya habéis tomado; pero pensar que dejaré de abrasar los que quedan es pensamiento vano. Vivaldo, que deseaba ver lo que los papeles decían, abrió luego el uno dellos y vio que tenía por título: Canción desesperada. Oyólo Ambrosio y dijo: -Ése es el último papel que escribió el desdichado; y, porque veáis, señor, en el término que le tenían sus desventuras, leelde de modo que seáis oído; que bien os dará lugar a ello el que se tardare en abrir la sepultura. -Eso haré yo de muy buena gana -dijo Vivaldo. Y, como todos los circunstantes tenían el mesmo deseo, se le pusieron a la redonda; y él, leyendo en voz clara, vio que así decía: Capítulo XIV. Donde se ponen los versos desesperados del difunto pastor, con otros no esperados sucesos Canción de Grisóstomo Ya que quieres, cruel, que se publique, de lengua en lengua y de una en otra gente, del áspero rigor tuyo la fuerza, haré que el mesmo infierno comunique al triste pecho mío un son doliente, con que el uso común de mi voz tuerza. Y al par de mi deseo, que se esfuerza a decir mi dolor y tus hazañas, de la espantable voz irá el acento, y en él mezcladas, por mayor tormento, pedazos de las míseras entrañas. Escucha, pues, y presta atento oído, no al concertado son, sino al rüido que de lo hondo de mi amargo pecho, llevado de un forzoso desvarío, por gusto mío sale y tu despecho. El rugir del león, del lobo fiero el temeroso aullido, el silbo horrendo de escamosa serpiente, el espantable baladro de algún monstruo, el agorero graznar de la corneja, y el estruendo del viento contrastado en mar instable; del ya vencido toro el implacable bramido, y de la viuda tortolilla el sentible arrullar; el triste canto del envidiado búho, con el llanto de toda la infernal negra cuadrilla, salgan con la doliente ánima fuera, mezclados en un son, de tal manera que se confundan los sentidos todos, pues la pena cruel que en mí se halla para contalla pide nuevos modos. De tanta confusión no las arenas del padre Tajo oirán los tristes ecos, ni del famoso Betis las olivas: que allí se esparcirán mis duras penas en altos riscos y en profundos huecos, con muerta lengua y con palabras vivas; o ya en escuros valles, o en esquivas playas, desnudas de contrato humano, o adonde el sol jamás mostró su lumbre, o entre la venenosa muchedumbre de fieras que alimenta el libio llano; que, puesto que en los páramos desiertos los ecos roncos de mi mal, inciertos, suenen con tu rigor tan sin segundo, por privilegio de mis cortos hados, serán llevados por el ancho mundo. Mata un desdén, atierra la paciencia, o verdadera o falsa, una sospecha; matan los celos con rigor más fuerte; desconcierta la vida larga ausencia; contra un temor de olvido no aprovecha firme esperanza de dichosa suerte. En todo hay cierta, inevitable muerte; mas yo, ¡milagro nunca visto!, vivo celoso, ausente, desdeñado y cierto de las sospechas que me tienen muerto; y en el olvido en quien mi fuego avivo, y, entre tantos tormentos, nunca alcanza mi vista a ver en sombra a la esperanza, ni yo, desesperado, la procuro; antes, por estremarme en mi querella, estar sin ella eternamente juro. ¿Puédese, por ventura, en un instante esperar y temer, o es bien hacello, siendo las causas del temor más ciertas? ¿Tengo, si el duro celo está delante, de cerrar estos ojos, si he de vello por mil heridas en el alma abiertas? ¿Quién no abrirá de par en par las puertas a la desconfianza, cuando mira descubierto el desdén, y las sospechas, ¡oh amarga conversión!, verdades hechas, y la limpia verdad vuelta en mentira? ¡Oh, en el reino de amor fieros tiranos celos, ponedme un hierro en estas manos! Dame, desdén, una torcida soga. Mas, ¡ay de mí!, que, con cruel vitoria, vuestra memoria el sufrimiento ahoga. Yo muero, en fin; y, porque nunca espere buen suceso en la muerte ni en la vida, pertinaz estaré en mi fantasía. Diré que va acertado el que bien quiere, y que es más libre el alma más rendida a la de amor antigua tiranía. Diré que la enemiga siempre mía hermosa el alma como el cuerpo tiene, y que su olvido de mi culpa nace, y que, en fe de los males que nos hace, amor su imperio en justa paz mantiene. Y, con esta opinión y un duro lazo, acelerando el miserable plazo a que me han conducido sus desdenes, ofreceré a los vientos cuerpo y alma, sin lauro o palma de futuros bienes. Tú, que con tantas sinrazones muestras la razón que me fuerza a que la haga a la cansada vida que aborrezco, pues ya ves que te da notorias muestras esta del corazón profunda llaga, de cómo, alegre, a tu rigor me ofrezco, si, por dicha, conoces que merezco que el cielo claro de tus bellos ojos en mi muerte se turbe, no lo hagas; que no quiero que en nada satisfagas, al darte de mi alma los despojos. Antes, con risa en la ocasión funesta, descubre que el fin mío fue tu fiesta; mas gran simpleza es avisarte desto, pues sé que está tu gloria conocida en que mi vida llegue al fin tan presto. Venga, que es tiempo ya, del hondo abismo Tántalo con su sed; Sísifo venga con el peso terrible de su canto; Ticio traya su buitre, y ansimismo con su rueda Egïón no se detenga, ni las hermanas que trabajan tanto; y todos juntos su mortal quebranto trasladen en mi pecho, y en voz baja -si ya a un desesperado son debidas- canten obsequias tristes, doloridas, al cuerpo a quien se niegue aun la mortaja. Y el portero infernal de los tres rostros, con otras mil quimeras y mil monstros, lleven el doloroso contrapunto; que otra pompa mejor no me parece que la merece un amador difunto. Canción desesperada, no te quejes cuando mi triste compañía dejes; antes, pues que la causa do naciste con mi desdicha augmenta su ventura, aun en la sepultura no estés triste. Bien les pareció, a los que escuchado habían, la canción de Grisóstomo, puesto que el que la leyó dijo que no le parecía que conformaba con la relación que él había oído del recato y bondad de Marcela, porque en ella se quejaba Grisóstomo de celos, sospechas y de ausencia, todo en perjuicio del buen crédito y buena fama de Marcela. A lo cual respondió Ambrosio, como aquel que sabía bien los más escondidos pensamientos de su amigo: -Para que, señor, os satisfagáis desa duda, es bien que sepáis que cuando este desdichado escribió esta canción estaba ausente de Marcela, de quien él se había ausentado por su voluntad, por ver si usaba con él la ausencia de sus ordinarios fueros. Y, como al enamorado ausente no hay cosa que no le fatigue ni temor que no le dé alcance, así le fatigaban a Grisóstomo los celos imaginados y las sospechas temidas como si fueran verdaderas. Y con esto queda en su punto la verdad que la fama pregona de la bondad de Marcela; la cual, fuera de ser cruel, y un poco arrogante y un mucho desdeñosa, la mesma envidia ni debe ni puede ponerle falta alguna. -Así es la verdad -respondió Vivaldo. Y, queriendo leer otro papel de los que había reservado del fuego, lo estorbó una maravillosa visión -que tal parecía ella- que improvisamente se les ofreció a los ojos; y fue que, por cima de la peña donde se cavaba la sepultura, pareció la pastora Marcela, tan hermosa que pasaba a su fama su hermosura. Los que hasta entonces no la habían visto la miraban con admiración y silencio, y los que ya estaban acostumbrados a verla no quedaron menos suspensos que los que nunca la habían visto. Mas, apenas la hubo visto Ambrosio, cuando, con muestras de ánimo indignado, le dijo: -¿Vienes a ver, por ventura, ¡oh fiero basilisco destas montañas!, si con tu presencia vierten sangre las heridas deste miserable a quien tu crueldad quitó la vida? ¿O vienes a ufanarte en las crueles hazañas de tu condición, o a ver desde esa altura, como otro despiadado Nero, el incendio de su abrasada Roma, o a pisar, arrogante, este desdichado cadáver, como la ingrata hija al de su padre Tarquino? Dinos presto a lo que vienes, o qué es aquello de que más gustas; que, por saber yo que los pensamientos de Grisóstomo jamás dejaron de obedecerte en vida, haré que, aun él muerto, te obedezcan los de todos aquellos que se llamaron sus amigos. -No vengo, ¡oh Ambrosio!, a ninguna cosa de las que has dicho -respondió Marcela-, sino a volver por mí misma, y a dar a entender cuán fuera de razón van todos aquellos que de sus penas y de la muerte de Grisóstomo me culpan; y así, ruego a todos los que aquí estáis me estéis atentos, que no será menester mucho tiempo ni gastar muchas palabras para persuadir una verdad a los discretos. »Hízome el cielo, según vosotros decís, hermosa, y de tal manera que, sin ser poderosos a otra cosa, a que me améis os mueve mi hermosura; y, por el amor que me mostráis, decís, y aun queréis, que esté yo obligada a amaros. Yo conozco, con el natural entendimiento que Dios me ha dado, que todo lo hermoso es amable; mas no alcanzo que, por razón de ser amado, esté obligado lo que es amado por hermoso a amar a quien le ama. Y más, que podría acontecer que el amador de lo hermoso fuese feo, y, siendo lo feo digno de ser aborrecido, cae muy mal el decir ''Quiérote por hermosa; hasme de amar aunque sea feo''. Pero, puesto caso que corran igualmente las hermosuras, no por eso han de correr iguales los deseos, que no todas hermosuras enamoran; que algunas alegran la vista y no rinden la voluntad; que si todas las bellezas enamorasen y rindiesen, sería un andar las voluntades confusas y descaminadas, sin saber en cuál habían de parar; porque, siendo infinitos los sujetos hermosos, infinitos habían de ser los deseos. Y, según yo he oído decir, el verdadero amor no se divide, y ha de ser voluntario, y no forzoso. Siendo esto así, como yo creo que lo es, ¿por qué queréis que rinda mi voluntad por fuerza, obligada no más de que decís que me queréis bien? Si no, decidme: si como el cielo me hizo hermosa me hiciera fea, ¿fuera justo que me quejara de vosotros porque no me amábades? Cuanto más, que habéis de considerar que yo no escogí la hermosura que tengo; que, tal cual es, el cielo me la dio de gracia, sin yo pedilla ni escogella. Y, así como la víbora no merece ser culpada por la ponzoña que tiene, puesto que con ella mata, por habérsela dado naturaleza, tampoco yo merezco ser reprehendida por ser hermosa; que la hermosura en la mujer honesta es como el fuego apartado o como la espada aguda, que ni él quema ni ella corta a quien a ellos no se acerca. La honra y las virtudes son adornos del alma, sin las cuales el cuerpo, aunque lo sea, no debe de parecer hermoso. Pues si la honestidad es una de las virtudes que al cuerpo y al alma más adornan y hermosean, ¿por qué la ha de perder la que es amada por hermosa, por corresponder a la intención de aquel que, por sólo su gusto, con todas sus fuerzas e industrias procura que la pierda? »Yo nací libre, y para poder vivir libre escogí la soledad de los campos. Los árboles destas montañas son mi compañía, las claras aguas destos arroyos mis espejos; con los árboles y con las aguas comunico mis pensamientos y hermosura. Fuego soy apartado y espada puesta lejos. A los que he enamorado con la vista he desengañado con las palabras. Y si los deseos se sustentan con esperanzas, no habiendo yo dado alguna a Grisóstomo ni a otro alguno, el fin de ninguno dellos bien se puede decir que antes le mató su porfía que mi crueldad. Y si se me hace cargo que eran honestos sus pensamientos, y que por esto estaba obligada a corresponder a ellos, digo que, cuando en ese mismo lugar donde ahora se cava su sepultura me descubrió la bondad de su intención, le dije yo que la mía era vivir en perpetua soledad, y de que sola la tierra gozase el fruto de mi recogimiento y los despojos de mi hermosura; y si él, con todo este desengaño, quiso porfiar contra la esperanza y navegar contra el viento, ¿qué mucho que se anegase en la mitad del golfo de su desatino? Si yo le entretuviera, fuera falsa; si le contentara, hiciera contra mi mejor intención y prosupuesto. Porfió desengañado, desesperó sin ser aborrecido: ¡mirad ahora si será razón que de su pena se me dé a mí la culpa! Quéjese el engañado, desespérese aquel a quien le faltaron las prometidas esperanzas, confíese el que yo llamare, ufánese el que yo admitiere; pero no me llame cruel ni homicida aquel a quien yo no prometo, engaño, llamo ni admito. »El cielo aún hasta ahora no ha querido que yo ame por destino, y el pensar que tengo de amar por elección es escusado. Este general desengaño sirva a cada uno de los que me solicitan de su particular provecho; y entiéndase, de aquí adelante, que si alguno por mí muriere, no muere de celoso ni desdichado, porque quien a nadie quiere, a ninguno debe dar celos; que los desengaños no se han de tomar en cuenta de desdenes. El que me llama fiera y basilisco, déjeme como cosa perjudicial y mala; el que me llama ingrata, no me sirva; el que desconocida, no me conozca; quien cruel, no me siga; que esta fiera, este basilisco, esta ingrata, esta cruel y esta desconocida, ni los buscará, servirá, conocerá ni seguirá en ninguna manera. Que si a Grisóstomo mató su impaciencia y arrojado deseo, ¿por qué se ha de culpar mi honesto proceder y recato? Si yo conservo mi limpieza con la compañía de los árboles, ¿por qué ha de querer que la pierda el que quiere que la tenga con los hombres? Yo, como sabéis, tengo riquezas propias y no codicio las ajenas; tengo libre condición y no gusto de sujetarme: ni quiero ni aborrezco a nadie. No engaño a éste ni solicito aquél, ni burlo con uno ni me entretengo con el otro. La conversación honesta de las zagalas destas aldeas y el cuidado de mis cabras me entretiene. Tienen mis deseos por término estas montañas, y si de aquí salen, es a contemplar la hermosura del cielo, pasos con que camina el alma a su morada primera. Y, en diciendo esto, sin querer oír respuesta alguna, volvió las espaldas y se entró por lo más cerrado de un monte que allí cerca estaba, dejando admirados, tanto de su discreción como de su hermosura, a todos los que allí estaban. Y algunos dieron muestras -de aquellos que de la poderosa flecha de los rayos de sus bellos ojos estaban heridos- de quererla seguir, sin aprovecharse del manifiesto desengaño que habían oído. Lo cual visto por don Quijote, pareciéndole que allí venía bien usar de su caballería, socorriendo a las doncellas menesterosas, puesta la mano en el puño de su espada, en altas e inteligibles voces, dijo: -Ninguna persona, de cualquier estado y condición que sea, se atreva a seguir a la hermosa Marcela, so pena de caer en la furiosa indignación mía. Ella ha mostrado con claras y suficientes razones la poca o ninguna culpa que ha tenido en la muerte de Grisóstomo, y cuán ajena vive de condescender con los deseos de ninguno de sus amantes, a cuya causa es justo que, en lugar de ser seguida y perseguida, sea honrada y estimada de todos los buenos del mundo, pues muestra que en él ella es sola la que con tan honesta intención vive. O ya que fuese por las amenazas de don Quijote, o porque Ambrosio les dijo que concluyesen con lo que a su buen amigo debían, ninguno de los pastores se movió ni apartó de allí hasta que, acabada la sepultura y abrasados los papeles de Grisóstomo, pusieron su cuerpo en ella, no sin muchas lágrimas de los circunstantes. Cerraron la sepultura con una gruesa peña, en tanto que se acababa una losa que, según Ambrosio dijo, pensaba mandar hacer, con un epitafio que había de decir desta manera: Yace aquí de un amador el mísero cuerpo helado, que fue pastor de ganado, perdido por desamor. Murió a manos del rigor de una esquiva hermosa ingrata, con quien su imperio dilata la tiranía de su amor. Luego esparcieron por cima de la sepultura muchas flores y ramos, y, dando todos el pésame a su amigo Ambrosio, se despidieron dél. Lo mesmo hicieron Vivaldo y su compañero, y don Quijote se despidió de sus huéspedes y de los caminantes, los cuales le rogaron se viniese con ellos a Sevilla, por ser lugar tan acomodado a hallar aventuras, que en cada calle y tras cada esquina se ofrecen más que en otro alguno. Don Quijote les agradeció el aviso y el ánimo que mostraban de hacerle merced, y dijo que por entonces no quería ni debía ir a Sevilla, hasta que hubiese despojado todas aquellas sierras de ladrones malandrines, de quien era fama que todas estaban llenas. Viendo su buena determinación, no quisieron los caminantes importunarle más, sino, tornándose a despedir de nuevo, le dejaron y prosiguieron su camino, en el cual no les faltó de qué tratar, así de la historia de Marcela y Grisóstomo como de las locuras de don Quijote. El cual determinó de ir a buscar a la pastora Marcela y ofrecerle todo lo que él podía en su servicio. Mas no le avino como él pensaba, según se cuenta en el discurso desta verdadera historia, dando aquí fin la segunda parte. Tercera parte del ingenioso hidalgo don Quijote de la Mancha Capítulo XV. Donde se cuenta la desgraciada aventura que se topó don Quijote en topar con unos desalmados yangüeses Cuenta el sabio Cide Hamete Benengeli que, así como don Quijote se despidió de sus huéspedes y de todos los que se hallaron al entierro del pastor Grisóstomo, él y su escudero se entraron por el mesmo bosque donde vieron que se había entrado la pastora Marcela; y, habiendo andado más de dos horas por él, buscándola por todas partes sin poder hallarla, vinieron a parar a un prado lleno de fresca yerba, junto del cual corría un arroyo apacible y fresco; tanto, que convidó y forzó a pasar allí las horas de la siesta, que rigurosamente comenzaba ya a entrar. Apeáronse don Quijote y Sancho, y, dejando al jumento y a Rocinante a sus anchuras pacer de la mucha yerba que allí había, dieron saco a las alforjas, y, sin cerimonia alguna, en buena paz y compañía, amo y mozo comieron lo que en ellas hallaron. No se había curado Sancho de echar sueltas a Rocinante, seguro de que le conocía por tan manso y tan poco rijoso que todas las yeguas de la dehesa de Córdoba no le hicieran tomar mal siniestro. Ordenó, pues, la suerte, y el diablo, que no todas veces duerme, que andaban por aquel valle paciendo una manada de hacas galicianas de unos arrieros gallegos, de los cuales es costumbre sestear con su recua en lugares y sitios de yerba y agua; y aquel donde acertó a hallarse don Quijote era muy a propósito de los gallegos. Sucedió, pues, que a Rocinante le vino en deseo de refocilarse con las señoras facas; y saliendo, así como las olió, de su natural paso y costumbre, sin pedir licencia a su dueño, tomó un trotico algo picadillo y se fue a comunicar su necesidad con ellas. Mas ellas, que, a lo que pareció, debían de tener más gana de pacer que de ál, recibiéronle con las herraduras y con los dientes, de tal manera que, a poco espacio, se le rompieron las cinchas y quedó, sin silla, en pelota. Pero lo que él debió más de sentir fue que, viendo los arrieros la fuerza que a sus yeguas se les hacía, acudieron con estacas, y tantos palos le dieron que le derribaron malparado en el suelo. Ya en esto don Quijote y Sancho, que la paliza de Rocinante habían visto, llegaban ijadeando; y dijo don Quijote a Sancho: -A lo que yo veo, amigo Sancho, éstos no son caballeros, sino gente soez y de baja ralea. Dígolo porque bien me puedes ayudar a tomar la debida venganza del agravio que delante de nuestros ojos se le ha hecho a Rocinante. -¿Qué diablos de venganza hemos de tomar -respondió Sancho-, si éstos son más de veinte y nosotros no más de dos, y aun, quizá, nosotros sino uno y medio? -Yo valgo por ciento -replicó don Quijote. Y, sin hacer más discursos, echó mano a su espada y arremetió a los gallegos, y lo mesmo hizo Sancho Panza, incitado y movido del ejemplo de su amo. Y, a las primeras, dio don Quijote una cuchillada a uno, que le abrió un sayo de cuero de que venía vestido, con gran parte de la espalda. Los gallegos, que se vieron maltratar de aquellos dos hombres solos, siendo ellos tantos, acudieron a sus estacas, y, cogiendo a los dos en medio, comenzaron a menudear sobre ellos con grande ahínco y vehemencia. Verdad es que al segundo toque dieron con Sancho en el suelo, y lo mesmo le avino a don Quijote, sin que le valiese su destreza y buen ánimo; y quiso su ventura que viniese a caer a los pies de Rocinante, que aún no se había levantado; donde se echa de ver la furia con que machacan estacas puestas en manos rústicas y enojadas. Viendo, pues, los gallegos el mal recado que habían hecho, con la mayor presteza que pudieron, cargaron su recua y siguieron su camino, dejando a los dos aventureros de mala traza y de peor talante. El primero que se resintió fue Sancho Panza; y, hallándose junto a su señor, con voz enferma y lastimada, dijo: -¡Señor don Quijote! ¡Ah, señor don Quijote! -¿Qué quieres, Sancho hermano? -respondió don Quijote con el mesmo tono afeminado y doliente que Sancho. -Querría, si fuese posible -respondió Sancho Panza-, que vuestra merced me diese dos tragos de aquella bebida del feo Blas, si es que la tiene vuestra merced ahí a mano. Quizá será de provecho para los quebrantamientos de huesos como lo es para las feridas. -Pues, a tenerla yo aquí, desgraciado yo, ¿qué nos faltaba? -respondió don Quijote-. Mas yo te juro, Sancho Panza, a fe de caballero andante, que antes que pasen dos días, si la fortuna no ordena otra cosa, la tengo de tener en mi poder, o mal me han de andar las manos. -Pues, ¿en cuántos le parece a vuestra merced que podremos mover los pies? -replicó Sancho Panza. -De mí sé decir -dijo el molido caballero don Quijote- que no sabré poner término a esos días. Mas yo me tengo la culpa de todo, que no había de poner mano a la espada contra hombres que no fuesen armados caballeros como yo; y así, creo que, en pena de haber pasado las leyes de la caballería, ha permitido el dios de las batallas que se me diese este castigo. Por lo cual, Sancho Panza, conviene que estés advertido en esto que ahora te diré, porque importa mucho a la salud de entrambos; y es que, cuando veas que semejante canalla nos hace algún agravio, no aguardes a que yo ponga mano al espada para ellos, porque no lo haré en ninguna manera, sino pon tú mano a tu espada y castígalos muy a tu sabor; que si en su ayuda y defensa acudieren caballeros, yo te sabré defender y ofendellos con todo mi poder; que ya habrás visto por mil señales y experiencias hasta adónde se estiende el valor de este mi fuerte brazo. Tal quedó de arrogante el pobre señor con el vencimiento del valiente vizcaíno. Mas no le pareció tan bien a Sancho Panza el aviso de su amo que dejase de responder, diciendo: -Señor, yo soy hombre pacífico, manso, sosegado, y sé disimilar cualquiera injuria, porque tengo mujer y hijos que sustentar y criar. Así que, séale a vuestra merced también aviso, pues no puede ser mandato, que en ninguna manera pondré mano a la espada, ni contra villano ni contra caballero; y que, desde aquí para delante de Dios, perdono cuantos agravios me han hecho y han de hacer: ora me los haya hecho, o haga o haya de hacer, persona alta o baja, rico o pobre, hidalgo o pechero, sin eceptar estado ni condición alguna. Lo cual oído por su amo, le respondió: -Quisiera tener aliento para poder hablar un poco descansado, y que el dolor que tengo en esta costilla se aplacara tanto cuanto, para darte a entender, Panza, en el error en que estás. Ven acá, pecador; si el viento de la fortuna, hasta ahora tan contrario, en nuestro favor se vuelve, llevándonos las velas del deseo para que seguramente y sin contraste alguno tomemos puerto en alguna de las ínsulas que te tengo prometida, ¿qué sería de ti si, ganándola yo, te hiciese señor della? Pues ¿lo vendrás a imposibilitar por no ser caballero, ni quererlo ser, ni tener valor ni intención de vengar tus injurias y defender tu señorío? Porque has de saber que en los reinos y provincias nuevamente conquistados nunca están tan quietos los ánimos de sus naturales, ni tan de parte del nuevo señor que no se tengan temor de que han de hacer alguna novedad para alterar de nuevo las cosas, y volver, como dicen, a probar ventura; y así, es menester que el nuevo posesor tenga entendimiento para saberse gobernar, y valor para ofender y defenderse en cualquiera acontecimiento. -En este que ahora nos ha acontecido -respondió Sancho-, quisiera yo tener ese entendimiento y ese valor que vuestra merced dice; mas yo le juro, a fe de pobre hombre, que más estoy para bizmas que para pláticas. Mire vuestra merced si se puede levantar, y ayudaremos a Rocinante, aunque no lo merece, porque él fue la causa principal de todo este molimiento. Jamás tal creí de Rocinante, que le tenía por persona casta y tan pacífica como yo. En fin, bien dicen que es menester mucho tiempo para venir a conocer las personas, y que no hay cosa segura en esta vida. ¿Quién dijera que tras de aquellas tan grandes cuchilladas como vuestra merced dio a aquel desdichado caballero andante, había de venir, por la posta y en seguimiento suyo, esta tan grande tempestad de palos que ha descargado sobre nuestras espaldas? -Aun las tuyas, Sancho -replicó don Quijote-, deben de estar hechas a semejantes nublados; pero las mías, criadas entre sinabafas y holandas, claro está que sentirán más el dolor desta desgracia. Y si no fuese porque imagino..., ¿qué digo imagino?, sé muy cierto, que todas estas incomodidades son muy anejas al ejercicio de las armas, aquí me dejaría morir de puro enojo. A esto replicó el escudero: -Señor, ya que estas desgracias son de la cosecha de la caballería, dígame vuestra merced si suceden muy a menudo, o si tienen sus tiempos limitados en que acaecen; porque me parece a mí que a dos cosechas quedaremos inútiles para la tercera, si Dios, por su infinita misericordia, no nos socorre. -Sábete, amigo Sancho -respondió don Quijote-, que la vida de los caballeros andantes está sujeta a mil peligros y desventuras; y, ni más ni menos, está en potencia propincua de ser los caballeros andantes reyes y emperadores, como lo ha mostrado la experiencia en muchos y diversos caballeros, de cuyas historias yo tengo entera noticia. Y pudiérate contar agora, si el dolor me diera lugar, de algunos que, sólo por el valor de su brazo, han subido a los altos grados que he contado; y estos mesmos se vieron antes y después en diversas calamidades y miserias. Porque el valeroso Amadís de Gaula se vio en poder de su mortal enemigo Arcaláus el encantador, de quien se tiene por averiguado que le dio, teniéndole preso, más de docientos azotes con las riendas de su caballo, atado a una coluna de un patio. Y aun hay un autor secreto, y de no poco crédito, que dice que, habiendo cogido al Caballero del Febo con una cierta trampa que se le hundió debajo de los pies, en un cierto castillo, y al caer, se halló en una honda sima debajo de tierra, atado de pies y manos, y allí le echaron una destas que llaman melecinas, de agua de nieve y arena, de lo que llegó muy al cabo; y si no fuera socorrido en aquella gran cuita de un sabio grande amigo suyo, lo pasara muy mal el pobre caballero. Ansí que, bien puedo yo pasar entre tanta buena gente; que mayores afrentas son las que éstos pasaron, que no las que ahora nosotros pasamos. Porque quiero hacerte sabidor, Sancho, que no afrentan las heridas que se dan con los instrumentos que acaso se hallan en las manos; y esto está en la ley del duelo, escrito por palabras expresas: que si el zapatero da a otro con la horma que tiene en la mano, puesto que verdaderamente es de palo, no por eso se dirá que queda apaleado aquel a quien dio con ella. Digo esto porque no pienses que, puesto que quedamos desta pendencia molidos, quedamos afrentados; porque las armas que aquellos hombres traían, con que nos machacaron, no eran otras que sus estacas, y ninguno dellos, a lo que se me acuerda, tenía estoque, espada ni puñal. -No me dieron a mí lugar -respondió Sancho- a que mirase en tanto; porque, apenas puse mano a mi tizona, cuando me santiguaron los hombros con sus pinos, de manera que me quitaron la vista de los ojos y la fuerza de los pies, dando conmigo adonde ahora yago, y adonde no me da pena alguna el pensar si fue afrenta o no lo de los estacazos, como me la da el dolor de los golpes, que me han de quedar tan impresos en la memoria como en las espaldas. -Con todo eso, te hago saber, hermano Panza -replicó don Quijote-, que no hay memoria a quien el tiempo no acabe, ni dolor que muerte no le consuma. -Pues, ¿qué mayor desdicha puede ser -replicó Panza- de aquella que aguarda al tiempo que la consuma y a la muerte que la acabe? Si esta nuestra desgracia fuera de aquellas que con un par de bizmas se curan, aun no tan malo; pero voy viendo que no han de bastar todos los emplastos de un hospital para ponerlas en buen término siquiera. -Déjate deso y saca fuerzas de flaqueza, Sancho -respondió don Quijote-, que así haré yo, y veamos cómo está Rocinante; que, a lo que me parece, no le ha cabido al pobre la menor parte desta desgracia. -No hay de qué maravillarse deso -respondió Sancho-, siendo él tan buen caballero andante; de lo que yo me maravillo es de que mi jumento haya quedado libre y sin costas donde nosotros salimos sin costillas. -Siempre deja la ventura una puerta abierta en las desdichas, para dar remedio a ellas -dijo don Quijote-. Dígolo porque esa bestezuela podrá suplir ahora la falta de Rocinante, llevándome a mí desde aquí a algún castillo donde sea curado de mis feridas. Y más, que no tendré a deshonra la tal caballería, porque me acuerdo haber leído que aquel buen viejo Sileno, ayo y pedagogo del alegre dios de la risa, cuando entró en la ciudad de las cien puertas iba, muy a su placer, caballero sobre un muy hermoso asno. -Verdad será que él debía de ir caballero, como vuestra merced dice -respondió Sancho-, pero hay grande diferencia del ir caballero al ir atravesado como costal de basura. A lo cual respondió don Quijote: -Las feridas que se reciben en las batallas, antes dan honra que la quitan. Así que, Panza amigo, no me repliques más, sino, como ya te he dicho, levántate lo mejor que pudieres y ponme de la manera que más te agradare encima de tu jumento, y vamos de aquí antes que la noche venga y nos saltee en este despoblado. -Pues yo he oído decir a vuestra merced -dijo Panza- que es muy de caballeros andantes el dormir en los páramos y desiertos lo más del año, y que lo tienen a mucha ventura. -Eso es -dijo don Quijote- cuando no pueden más, o cuando están enamorados; y es tan verdad esto, que ha habido caballero que se ha estado sobre una peña, al sol y a la sombra, y a las inclemencias del cielo, dos años, sin que lo supiese su señora. Y uno déstos fue Amadís, cuando, llamándose Beltenebros, se alojó en la Peña Pobre, ni sé si ocho años o ocho meses, que no estoy muy bien en la cuenta: basta que él estuvo allí haciendo penitencia, por no sé qué sinsabor que le hizo la señora Oriana. Pero dejemos ya esto, Sancho, y acaba, antes que suceda otra desgracia al jumento, como a Rocinante. -Aun ahí sería el diablo -dijo Sancho. Y, despidiendo treinta ayes, y sesenta sospiros, y ciento y veinte pésetes y reniegos de quien allí le había traído, se levantó, quedándose agobiado en la mitad del camino, como arco turquesco, sin poder acabar de enderezarse; y con todo este trabajo aparejó su asno, que también había andado algo destraído con la demasiada libertad de aquel día. Levantó luego a Rocinante, el cual, si tuviera lengua con que quejarse, a buen seguro que Sancho ni su amo no le fueran en zaga. En resolución, Sancho acomodó a don Quijote sobre el asno y puso de reata a Rocinante; y, llevando al asno de cabestro, se encaminó, poco más a menos, hacia donde le pareció que podía estar el camino real. Y la suerte, que sus cosas de bien en mejor iba guiando, aún no hubo andado una pequeña legua, cuando le deparó el camino, en el cual descubrió una venta que, a pesar suyo y gusto de don Quijote, había de ser castillo. Porfiaba Sancho que era venta, y su amo que no, sino castillo; y tanto duró la porfía, que tuvieron lugar, sin acabarla, de llegar a ella, en la cual Sancho se entró, sin más averiguación, con toda su recua. Capítulo XVI. De lo que le sucedió al ingenioso hidalgo en la venta que él imaginaba ser castillo El ventero, que vio a don Quijote atravesado en el asno, preguntó a Sancho qué mal traía. Sancho le respondió que no era nada, sino que había dado una caída de una peña abajo, y que venía algo brumadas las costillas. Tenía el ventero por mujer a una, no de la condición que suelen tener las de semejante trato, porque naturalmente era caritativa y se dolía de las calamidades de sus prójimos; y así, acudió luego a curar a don Quijote y hizo que una hija suya, doncella, muchacha y de muy buen parecer, la ayudase a curar a su huésped. Servía en la venta, asimesmo, una moza asturiana, ancha de cara, llana de cogote, de nariz roma, del un ojo tuerta y del otro no muy sana. Verdad es que la gallardía del cuerpo suplía las demás faltas: no tenía siete palmos de los pies a la cabeza, y las espaldas, que algún tanto le cargaban, la hacían mirar al suelo más de lo que ella quisiera. Esta gentil moza, pues, ayudó a la doncella, y las dos hicieron una muy mala cama a don Quijote en un camaranchón que, en otros tiempos, daba manifiestos indicios que había servido de pajar muchos años. En la cual también alojaba un arriero, que tenía su cama hecha un poco más allá de la de nuestro don Quijote. Y, aunque era de las enjalmas y mantas de sus machos, hacía mucha ventaja a la de don Quijote, que sólo contenía cuatro mal lisas tablas, sobre dos no muy iguales bancos, y un colchón que en lo sutil parecía colcha, lleno de bodoques, que, a no mostrar que eran de lana por algunas roturas, al tiento, en la dureza, semejaban de guijarro, y dos sábanas hechas de cuero de adarga, y una frazada, cuyos hilos, si se quisieran contar, no se perdiera uno solo de la cuenta. En esta maldita cama se acostó don Quijote, y luego la ventera y su hija le emplastaron de arriba abajo, alumbrándoles Maritornes, que así se llamaba la asturiana; y, como al bizmalle viese la ventera tan acardenalado a partes a don Quijote, dijo que aquello más parecían golpes que caída. -No fueron golpes -dijo Sancho-, sino que la peña tenía muchos picos y tropezones. Y que cada uno había hecho su cardenal. Y también le dijo: -Haga vuestra merced, señora, de manera que queden algunas estopas, que no faltará quien las haya menester; que también me duelen a mí un poco los lomos. -Desa manera -respondió la ventera-, también debistes vos de caer. -No caí -dijo Sancho Panza-, sino que del sobresalto que tomé de ver caer a mi amo, de tal manera me duele a mí el cuerpo que me parece que me han dado mil palos. -Bien podrá ser eso -dijo la doncella-; que a mí me ha acontecido muchas veces soñar que caía de una torre abajo y que nunca acababa de llegar al suelo, y, cuando despertaba del sueño, hallarme tan molida y quebrantada como si verdaderamente hubiera caído. -Ahí está el toque, señora -respondió Sancho Panza-: que yo, sin soñar nada, sino estando más despierto que ahora estoy, me hallo con pocos menos cardenales que mi señor don Quijote. -¿Cómo se llama este caballero? -preguntó la asturiana Maritornes. -Don Quijote de la Mancha -respondió Sancho Panza-, y es caballero aventurero, y de los mejores y más fuertes que de luengos tiempos acá se han visto en el mundo. -¿Qué es caballero aventurero? -replicó la moza. -¿Tan nueva sois en el mundo que no lo sabéis vos? -respondió Sancho Panza-. Pues sabed, hermana mía, que caballero aventurero es una cosa que en dos palabras se ve apaleado y emperador. Hoy está la más desdichada criatura del mundo y la más menesterosa, y mañana tendría dos o tres coronas de reinos que dar a su escudero. -Pues, ¿cómo vos, siéndolo deste tan buen señor -dijo la ventera-, no tenéis, a lo que parece, siquiera algún condado? -Aún es temprano -respondió Sancho-, porque no ha sino un mes que andamos buscando las aventuras, y hasta ahora no hemos topado con ninguna que lo sea. Y tal vez hay que se busca una cosa y se halla otra. Verdad es que, si mi señor don Quijote sana desta herida o caída y yo no quedo contrecho della, no trocaría mis esperanzas con el mejor título de España. Todas estas pláticas estaba escuchando, muy atento, don Quijote, y, sentándose en el lecho como pudo, tomando de la mano a la ventera, le dijo: -Creedme, fermosa señora, que os podéis llamar venturosa por haber alojado en este vuestro castillo a mi persona, que es tal, que si yo no la alabo, es por lo que suele decirse que la alabanza propria envilece; pero mi escudero os dirá quién soy. Sólo os digo que tendré eternamente escrito en mi memoria el servicio que me habedes fecho, para agradecéroslo mientras la vida me durare; y pluguiera a los altos cielos que el amor no me tuviera tan rendido y tan sujeto a sus leyes, y los ojos de aquella hermosa ingrata que digo entre mis dientes; que los desta fermosa doncella fueran señores de mi libertad. Confusas estaban la ventera y su hija y la buena de Maritornes oyendo las razones del andante caballero, que así las entendían como si hablara en griego, aunque bien alcanzaron que todas se encaminaban a ofrecimiento y requiebros; y, como no usadas a semejante lenguaje, mirábanle y admirábanse, y parecíales otro hombre de los que se usaban; y, agradeciéndole con venteriles razones sus ofrecimientos, le dejaron; y la asturiana Maritornes curó a Sancho, que no menos lo había menester que su amo. Había el arriero concertado con ella que aquella noche se refocilarían juntos, y ella le había dado su palabra de que, en estando sosegados los huéspedes y durmiendo sus amos, le iría a buscar y satisfacerle el gusto en cuanto le mandase. Y cuéntase desta buena moza que jamás dio semejantes palabras que no las cumpliese, aunque las diese en un monte y sin testigo alguno; porque presumía muy de hidalga, y no tenía por afrenta estar en aquel ejercicio de servir en la venta, porque decía ella que desgracias y malos sucesos la habían traído a aquel estado. El duro, estrecho, apocado y fementido lecho de don Quijote estaba primero en mitad de aquel estrellado establo, y luego, junto a él, hizo el suyo Sancho, que sólo contenía una estera de enea y una manta, que antes mostraba ser de anjeo tundido que de lana. Sucedía a estos dos lechos el del arriero, fabricado, como se ha dicho, de las enjalmas y todo el adorno de los dos mejores mulos que traía, aunque eran doce, lucios, gordos y famosos, porque era uno de los ricos arrieros de Arévalo, según lo dice el autor desta historia, que deste arriero hace particular mención, porque le conocía muy bien, y aun quieren decir que era algo pariente suyo. Fuera de que Cide Mahamate Benengeli fue historiador muy curioso y muy puntual en todas las cosas; y échase bien de ver, pues las que quedan referidas, con ser tan mínimas y tan rateras, no las quiso pasar en silencio; de donde podrán tomar ejemplo los historiadores graves, que nos cuentan las acciones tan corta y sucintamente que apenas nos llegan a los labios, dejándose en el tintero, ya por descuido, por malicia o ignorancia, lo más sustancial de la obra. ¡Bien haya mil veces el autor de Tablante de Ricamonte, y aquel del otro libro donde se cuenta los hechos del conde Tomillas; y con qué puntualidad lo describen todo! Digo, pues, que después de haber visitado el arriero a su recua y dádole el segundo pienso, se tendió en sus enjalmas y se dio a esperar a su puntualísima Maritornes. Ya estaba Sancho bizmado y acostado, y, aunque procuraba dormir, no lo consentía el dolor de sus costillas; y don Quijote, con el dolor de las suyas, tenía los ojos abiertos como liebre. Toda la venta estaba en silencio, y en toda ella no había otra luz que la que daba una lámpara que colgada en medio del portal ardía. Esta maravillosa quietud, y los pensamientos que siempre nuestro caballero traía de los sucesos que a cada paso se cuentan en los libros autores de su desgracia, le trujo a la imaginación una de las estrañas locuras que buenamente imaginarse pueden. Y fue que él se imaginó haber llegado a un famoso castillo -que, como se ha dicho, castillos eran a su parecer todas las ventas donde alojaba-, y que la hija del ventero lo era del señor del castillo, la cual, vencida de su gentileza, se había enamorado dél y prometido que aquella noche, a furto de sus padres, vendría a yacer con él una buena pieza; y, teniendo toda esta quimera, que él se había fabricado, por firme y valedera, se comenzó a acuitar y a pensar en el peligroso trance en que su honestidad se había de ver, y propuso en su corazón de no cometer alevosía a su señora Dulcinea del Toboso, aunque la mesma reina Ginebra con su dama Quintañona se le pusiesen delante. Pensando, pues, en estos disparates, se llegó el tiempo y la hora -que para él fue menguada- de la venida de la asturiana, la cual, en camisa y descalza, cogidos los cabellos en una albanega de fustán, con tácitos y atentados pasos, entró en el aposento donde los tres alojaban en busca del arriero. Pero, apenas llegó a la puerta, cuando don Quijote la sintió, y, sentándose en la cama, a pesar de sus bizmas y con dolor de sus costillas, tendió los brazos para recebir a su fermosa doncella. La asturiana, que, toda recogida y callando, iba con las manos delante buscando a su querido, topó con los brazos de don Quijote, el cual la asió fuertemente de una muñeca y, tirándola hacía sí, sin que ella osase hablar palabra, la hizo sentar sobre la cama. Tentóle luego la camisa, y, aunque ella era de harpillera, a él le pareció ser de finísimo y delgado cendal. Traía en las muñecas unas cuentas de vidro, pero a él le dieron vislumbres de preciosas perlas orientales. Los cabellos, que en alguna manera tiraban a crines, él los marcó por hebras de lucidísimo oro de Arabia, cuyo resplandor al del mesmo sol escurecía. Y el aliento, que, sin duda alguna, olía a ensalada fiambre y trasnochada, a él le pareció que arrojaba de su boca un olor suave y aromático; y, finalmente, él la pintó en su imaginación de la misma traza y modo que lo había leído en sus libros de la otra princesa que vino a ver el mal ferido caballero, vencida de sus amores, con todos los adornos que aquí van puestos. Y era tanta la ceguedad del pobre hidalgo, que el tacto, ni el aliento, ni otras cosas que traía en sí la buena doncella, no le desengañaban, las cuales pudieran hacer vomitar a otro que no fuera arriero; antes, le parecía que tenía entre sus brazos a la diosa de la hermosura. Y, teniéndola bien asida, con voz amorosa y baja le comenzó a decir: -Quisiera hallarme en términos, fermosa y alta señora, de poder pagar tamaña merced como la que con la vista de vuestra gran fermosura me habedes fecho, pero ha querido la fortuna, que no se cansa de perseguir a los buenos, ponerme en este lecho, donde yago tan molido y quebrantado que, aunque de mi voluntad quisiera satisfacer a la vuestra, fuera imposible. Y más, que se añade a esta imposibilidad otra mayor, que es la prometida fe que tengo dada a la sin par Dulcinea del Toboso, única señora de mis más escondidos pensamientos; que si esto no hubiera de por medio, no fuera yo tan sandio caballero que dejara pasar en blanco la venturosa ocasión en que vuestra gran bondad me ha puesto. Maritornes estaba congojadísima y trasudando, de verse tan asida de don Quijote, y, sin entender ni estar atenta a las razones que le decía, procuraba, sin hablar palabra, desasirse. El bueno del arriero, a quien tenían despierto sus malos deseos, desde el punto que entró su coima por la puerta, la sintió; estuvo atentamente escuchando todo lo que don Quijote decía, y, celoso de que la asturiana le hubiese faltado la palabra por otro, se fue llegando más al lecho de don Quijote, y estúvose quedo hasta ver en qué paraban aquellas razones, que él no podía entender. Pero, como vio que la moza forcejaba por desasirse y don Quijote trabajaba por tenella, pareciéndole mal la burla, enarboló el brazo en alto y descargó tan terrible puñada sobre las estrechas quijadas del enamorado caballero, que le bañó toda la boca en sangre; y, no contento con esto, se le subió encima de las costillas, y con los pies más que de trote, se las paseó todas de cabo a cabo. El lecho, que era un poco endeble y de no firmes fundamentos, no pudiendo sufrir la añadidura del arriero, dio consigo en el suelo, a cuyo gran ruido despertó el ventero, y luego imaginó que debían de ser pendencias de Maritornes, porque, habiéndola llamado a voces, no respondía. Con esta sospecha se levantó, y, encendiendo un candil, se fue hacia donde había sentido la pelaza. La moza, viendo que su amo venía, y que era de condición terrible, toda medrosica y alborotada, se acogió a la cama de Sancho Panza, que aún dormía, y allí se acorrucó y se hizo un ovillo. El ventero entró diciendo: -¿Adónde estás, puta? A buen seguro que son tus cosas éstas. En esto, despertó Sancho, y, sintiendo aquel bulto casi encima de sí, pensó que tenía la pesadilla, y comenzó a dar puñadas a una y otra parte, y entre otras alcanzó con no sé cuántas a Maritornes, la cual, sentida del dolor, echando a rodar la honestidad, dio el retorno a Sancho con tantas que, a su despecho, le quitó el sueño; el cual, viéndose tratar de aquella manera y sin saber de quién, alzándose como pudo, se abrazó con Maritornes, y comenzaron entre los dos la más reñida y graciosa escaramuza del mundo. Viendo, pues, el arriero, a la lumbre del candil del ventero, cuál andaba su dama, dejando a don Quijote, acudió a dalle el socorro necesario. Lo mismo hizo el ventero, pero con intención diferente, porque fue a castigar a la moza, creyendo sin duda que ella sola era la ocasión de toda aquella armonía. Y así como suele decirse: el gato al rato, el rato a la cuerda, la cuerda al palo, daba el arriero a Sancho, Sancho a la moza, la moza a él, el ventero a la moza, y todos menudeaban con tanta priesa que no se daban punto de reposo; y fue lo bueno que al ventero se le apagó el candil, y, como quedaron ascuras, dábanse tan sin compasión todos a bulto que, a doquiera que ponían la mano, no dejaban cosa sana. Alojaba acaso aquella noche en la venta un cuadrillero de los que llaman de la Santa Hermandad Vieja de Toledo, el cual, oyendo ansimesmo el estraño estruendo de la pelea, asió de su media vara y de la caja de lata de sus títulos, y entró ascuras en el aposento, diciendo: -¡Ténganse a la justicia! ¡Ténganse a la Santa Hermandad! Y el primero con quien topó fue con el apuñeado de don Quijote, que estaba en su derribado lecho, tendido boca arriba, sin sentido alguno, y, echándole a tiento mano a las barbas, no cesaba de decir: -¡Favor a la justicia! Pero, viendo que el que tenía asido no se bullía ni meneaba, se dio a entender que estaba muerto, y que los que allí dentro estaban eran sus matadores; y con esta sospecha reforzó la voz, diciendo: -¡Ciérrese la puerta de la venta! ¡Miren no se vaya nadie, que han muerto aquí a un hombre! Esta voz sobresaltó a todos, y cada cual dejó la pendencia en el grado que le tomó la voz. Retiróse el ventero a su aposento, el arriero a sus enjalmas, la moza a su rancho; solos los desventurados don Quijote y Sancho no se pudieron mover de donde estaban. Soltó en esto el cuadrillero la barba de don Quijote, y salió a buscar luz para buscar y prender los delincuentes; mas no la halló, porque el ventero, de industria, había muerto la lámpara cuando se retiró a su estancia, y fuele forzoso acudir a la chimenea, donde, con mucho trabajo y tiempo, encendió el cuadrillero otro candil. Capítulo XVII. Donde se prosiguen los innumerables trabajos que el bravo don Quijote y su buen escudero Sancho Panza pasaron en la venta que, por su mal, pensó que era castillo Había ya vuelto en este tiempo de su parasismo don Quijote, y, con el mesmo tono de voz con que el día antes había llamado a su escudero, cuando estaba tendido en el val de las estacas, le comenzó a llamar, diciendo: -Sancho amigo, ¿duermes? ¿Duermes, amigo Sancho? -¿Qué tengo de dormir, pesia a mí -respondió Sancho, lleno de pesadumbre y de despecho-; que no parece sino que todos los diablos han andado conmigo esta noche? -Puédeslo creer ansí, sin duda -respondió don Quijote-, porque, o yo sé poco, o este castillo es encantado. Porque has de saber... Mas, esto que ahora quiero decirte hasme de jurar que lo tendrás secreto hasta después de mi muerte. -Sí juro -respondió Sancho. -Dígolo -replicó don Quijote-, porque soy enemigo de que se quite la honra a nadie. -Digo que sí juro -tornó a decir Sancho- que lo callaré hasta después de los días de vuestra merced, y plega a Dios que lo pueda descubrir mañana. -¿Tan malas obras te hago, Sancho -respondió don Quijote-, que me querrías ver muerto con tanta brevedad? -No es por eso -respondió Sancho-, sino porque soy enemigo de guardar mucho las cosas, y no querría que se me pudriesen de guardadas. -Sea por lo que fuere -dijo don Quijote-; que más fío de tu amor y de tu cortesía; y así, has de saber que esta noche me ha sucedido una de las más estrañas aventuras que yo sabré encarecer; y, por contártela en breve, sabrás que poco ha que a mí vino la hija del señor deste castillo, que es la más apuesta y fermosa doncella que en gran parte de la tierra se puede hallar. ¿Qué te podría decir del adorno de su persona? ¿Qué de su gallardo entendimiento? ¿Qué de otras cosas ocultas, que, por guardar la fe que debo a mi señora Dulcinea del Toboso, dejaré pasar intactas y en silencio? Sólo te quiero decir que, envidioso el cielo de tanto bien como la ventura me había puesto en las manos, o quizá, y esto es lo más cierto, que, como tengo dicho, es encantado este castillo, al tiempo que yo estaba con ella en dulcísimos y amorosísimos coloquios, sin que yo la viese ni supiese por dónde venía, vino una mano pegada a algún brazo de algún descomunal gigante y asentóme una puñada en las quijadas, tal, que las tengo todas bañadas en sangre; y después me molió de tal suerte que estoy peor que ayer cuando los gallegos, que, por demasías de Rocinante, nos hicieron el agravio que sabes. Por donde conjeturo que el tesoro de la fermosura desta doncella le debe de guardar algún encantado moro, y no debe de ser para mí. -Ni para mí tampoco -respondió Sancho-, porque más de cuatrocientos moros me han aporreado a mí, de manera que el molimiento de las estacas fue tortas y pan pintado. Pero dígame, señor, ¿cómo llama a ésta buena y rara aventura, habiendo quedado della cual quedamos? Aun vuestra merced menos mal, pues tuvo en sus manos aquella incomparable fermosura que ha dicho, pero yo, ¿qué tuve sino los mayores porrazos que pienso recebir en toda mi vida? ¡Desdichado de mí y de la madre que me parió, que ni soy caballero andante, ni lo pienso ser jamás, y de todas las malandanzas me cabe la mayor parte! -Luego, ¿también estás tú aporreado? -respondió don Quijote. -¿No le he dicho que sí, pesia a mi linaje? -dijo Sancho. -No tengas pena, amigo -dijo don Quijote-, que yo haré agora el bálsamo precioso con que sanaremos en un abrir y cerrar de ojos. Acabó en esto de encender el candil el cuadrillero, y entró a ver el que pensaba que era muerto; y, así como le vio entrar Sancho, viéndole venir en camisa y con su paño de cabeza y candil en la mano, y con una muy mala cara, preguntó a su amo: -Señor, ¿si será éste, a dicha, el moro encantado, que nos vuelve a castigar, si se dejó algo en el tintero? -No puede ser el moro -respondió don Quijote-, porque los encantados no se dejan ver de nadie. -Si no se dejan ver, déjanse sentir -dijo Sancho-; si no, díganlo mis espaldas. -También lo podrían decir las mías -respondió don Quijote-, pero no es bastante indicio ése para creer que este que se vee sea el encantado moro. Llegó el cuadrillero, y, como los halló hablando en tan sosegada conversación, quedó suspenso. Bien es verdad que aún don Quijote se estaba boca arriba, sin poderse menear, de puro molido y emplastado. Llegóse a él el cuadrillero y díjole: -Pues, ¿cómo va, buen hombre? -Hablara yo más bien criado -respondió don Quijote-, si fuera que vos. ¿Úsase en esta tierra hablar desa suerte a los caballeros andantes, majadero? El cuadrillero, que se vio tratar tan mal de un hombre de tan mal parecer, no lo pudo sufrir, y, alzando el candil con todo su aceite, dio a don Quijote con él en la cabeza, de suerte que le dejó muy bien descalabrado; y, como todo quedó ascuras, salióse luego; y Sancho Panza dijo: -Sin duda, señor, que éste es el moro encantado, y debe de guardar el tesoro para otros, y para nosotros sólo guarda las puñadas y los candilazos. -Así es -respondió don Quijote-, y no hay que hacer caso destas cosas de encantamentos, ni hay para qué tomar cólera ni enojo con ellas; que, como son invisibles y fantásticas, no hallaremos de quién vengarnos, aunque más lo procuremos. Levántate, Sancho, si puedes, y llama al alcaide desta fortaleza, y procura que se me dé un poco de aceite, vino, sal y romero para hacer el salutífero bálsamo; que en verdad que creo que lo he bien menester ahora, porque se me va mucha sangre de la herida que esta fantasma me ha dado. Levántose Sancho con harto dolor de sus huesos, y fue ascuras donde estaba el ventero; y, encontrándose con el cuadrillero, que estaba escuchando en qué paraba su enemigo, le dijo: -Señor, quien quiera que seáis, hacednos merced y beneficio de darnos un poco de romero, aceite, sal y vino, que es menester para curar uno de los mejores caballeros andantes que hay en la tierra, el cual yace en aquella cama, malferido por las manos del encantado moro que está en esta venta. Cuando el cuadrillero tal oyó, túvole por hombre falto de seso; y, porque ya comenzaba a amanecer, abrió la puerta de la venta, y, llamando al ventero, le dijo lo que aquel buen hombre quería. El ventero le proveyó de cuanto quiso, y Sancho se lo llevó a don Quijote, que estaba con las manos en la cabeza, quejándose del dolor del candilazo, que no le había hecho más mal que levantarle dos chichones algo crecidos, y lo que él pensaba que era sangre no era sino sudor que sudaba con la congoja de la pasada tormenta. En resolución, él tomó sus simples, de los cuales hizo un compuesto, mezclándolos todos y cociéndolos un buen espacio, hasta que le pareció que estaban en su punto. Pidió luego alguna redoma para echallo, y, como no la hubo en la venta, se resolvió de ponello en una alcuza o aceitera de hoja de lata, de quien el ventero le hizo grata donación. Y luego dijo sobre la alcuza más de ochenta paternostres y otras tantas avemarías, salves y credos, y a cada palabra acompañaba una cruz, a modo de bendición; a todo lo cual se hallaron presentes Sancho, el ventero y cuadrillero; que ya el arriero sosegadamente andaba entendiendo en el beneficio de sus machos. Hecho esto, quiso él mesmo hacer luego la esperiencia de la virtud de aquel precioso bálsamo que él se imaginaba; y así, se bebió, de lo que no pudo caber en la alcuza y quedaba en la olla donde se había cocido, casi media azumbre; y apenas lo acabó de beber, cuando comenzó a vomitar de manera que no le quedó cosa en el estómago; y con las ansias y agitación del vómito le dio un sudor copiosísimo, por lo cual mandó que le arropasen y le dejasen solo. Hiciéronlo ansí, y quedóse dormido más de tres horas, al cabo de las cuales despertó y se sintió aliviadísimo del cuerpo, y en tal manera mejor de su quebrantamiento que se tuvo por sano; y verdaderamente creyó que había acertado con el bálsamo de Fierabrás, y que con aquel remedio podía acometer desde allí adelante, sin temor alguno, cualesquiera ruinas, batallas y pendencias, por peligrosas que fuesen. Sancho Panza, que también tuvo a milagro la mejoría de su amo, le rogó que le diese a él lo que quedaba en la olla, que no era poca cantidad. Concedióselo don Quijote, y él, tomándola a dos manos, con buena fe y mejor talante, se la echó a pechos, y envasó bien poco menos que su amo. Es, pues, el caso que el estómago del pobre Sancho no debía de ser tan delicado como el de su amo, y así, primero que vomitase, le dieron tantas ansias y bascas, con tantos trasudores y desmayos que él pensó bien y verdaderamente que era llegada su última hora; y, viéndose tan afligido y congojado, maldecía el bálsamo y al ladrón que se lo había dado. Viéndole así don Quijote, le dijo: -Yo creo, Sancho, que todo este mal te viene de no ser armado caballero, porque tengo para mí que este licor no debe de aprovechar a los que no lo son. -Si eso sabía vuestra merced -replicó Sancho-, ¡mal haya yo y toda mi parentela!, ¿para qué consintió que lo gustase? En esto, hizo su operación el brebaje, y comenzó el pobre escudero a desaguarse por entrambas canales, con tanta priesa que la estera de enea, sobre quien se había vuelto a echar, ni la manta de anjeo con que se cubría, fueron más de provecho. Sudaba y trasudaba con tales parasismos y accidentes, que no solamente él, sino todos pensaron que se le acababa la vida. Duróle esta borrasca y mala andanza casi dos horas, al cabo de las cuales no quedó como su amo, sino tan molido y quebrantado que no se podía tener. Pero don Quijote, que, como se ha dicho, se sintió aliviado y sano, quiso partirse luego a buscar aventuras, pareciéndole que todo el tiempo que allí se tardaba era quitársele al mundo y a los en él menesterosos de su favor y amparo; y más con la seguridad y confianza que llevaba en su bálsamo. Y así, forzado deste deseo, él mismo ensilló a Rocinante y enalbardó al jumento de su escudero, a quien también ayudó a vestir y a subir en el asno. Púsose luego a caballo, y, llegándose a un rincón de la venta, asió de un lanzón que allí estaba, para que le sirviese de lanza. Estábanle mirando todos cuantos había en la venta, que pasaban de más de veinte personas; mirábale también la hija del ventero, y él también no quitaba los ojos della, y de cuando en cuando arrojaba un sospiro que parecía que le arrancaba de lo profundo de sus entrañas, y todos pensaban que debía de ser del dolor que sentía en las costillas; a lo menos, pensábanlo aquellos que la noche antes le habían visto bizmar. Ya que estuvieron los dos a caballo, puesto a la puerta de la venta, llamó al ventero, y con voz muy reposada y grave le dijo: -Muchas y muy grandes son las mercedes, señor alcaide, que en este vuestro castillo he recebido, y quedo obligadísimo a agradecéroslas todos los días de mi vida. Si os las puedo pagar en haceros vengado de algún soberbio que os haya fecho algún agravio, sabed que mi oficio no es otro sino valer a los que poco pueden, y vengar a los que reciben tuertos, y castigar alevosías. Recorred vuestra memoria, y si halláis alguna cosa deste jaez que encomendarme, no hay sino decilla; que yo os prometo, por la orden de caballero que recebí, de faceros satisfecho y pagado a toda vuestra voluntad. El ventero le respondió con el mesmo sosiego: -Señor caballero, yo no tengo necesidad de que vuestra merced me vengue ningún agravio, porque yo sé tomar la venganza que me parece, cuando se me hacen. Sólo he menester que vuestra merced me pague el gasto que esta noche ha hecho en la venta, así de la paja y cebada de sus dos bestias, como de la cena y camas. -Luego, ¿venta es ésta? -replicó don Quijote. -Y muy honrada -respondió el ventero. -Engañado he vivido hasta aquí -respondió don Quijote-, que en verdad que pensé que era castillo, y no malo; pero, pues es ansí que no es castillo sino venta, lo que se podrá hacer por agora es que perdonéis por la paga, que yo no puedo contravenir a la orden de los caballeros andantes, de los cuales sé cierto, sin que hasta ahora haya leído cosa en contrario, que jamás pagaron posada ni otra cosa en venta donde estuviesen, porque se les debe de fuero y de derecho cualquier buen acogimiento que se les hiciere, en pago del insufrible trabajo que padecen buscando las aventuras de noche y de día, en invierno y en verano, a pie y a caballo, con sed y con hambre, con calor y con frío, sujetos a todas las inclemencias del cielo y a todos los incómodos de la tierra. -Poco tengo yo que ver en eso -respondió el ventero-; págueseme lo que se me debe, y dejémonos de cuentos ni de caballerías, que yo no tengo cuenta con otra cosa que con cobrar mi hacienda. -Vos sois un sandio y mal hostalero -respondió don Quijote. Y, poniendo piernas al Rocinante y terciando su lanzón, se salió de la venta sin que nadie le detuviese, y él, sin mirar si le seguía su escudero, se alongó un buen trecho. El ventero, que le vio ir y que no le pagaba, acudió a cobrar de Sancho Panza, el cual dijo que, pues su señor no había querido pagar, que tampoco él pagaría; porque, siendo él escudero de caballero andante, como era, la mesma regla y razón corría por él como por su amo en no pagar cosa alguna en los mesones y ventas. Amohinóse mucho desto el ventero, y amenazóle que si no le pagaba, que lo cobraría de modo que le pesase. A lo cual Sancho respondió que, por la ley de caballería que su amo había recebido, no pagaría un solo cornado, aunque le costase la vida; porque no había de perder por él la buena y antigua usanza de los caballeros andantes, ni se habían de quejar dél los escuderos de los tales que estaban por venir al mundo, reprochándole el quebrantamiento de tan justo fuero. Quiso la mala suerte del desdichado Sancho que, entre la gente que estaba en la venta, se hallasen cuatro perailes de Segovia, tres agujeros del Potro de Córdoba y dos vecinos de la Heria de Sevilla, gente alegre, bien intencionada, maleante y juguetona, los cuales, casi como instigados y movidos de un mesmo espíritu, se llegaron a Sancho, y, apeándole del asno, uno dellos entró por la manta de la cama del huésped, y, echándole en ella, alzaron los ojos y vieron que el techo era algo más bajo de lo que habían menester para su obra, y determinaron salirse al corral, que tenía por límite el cielo. Y allí, puesto Sancho en mitad de la manta, comenzaron a levantarle en alto y a holgarse con él como con perro por carnestolendas. Las voces que el mísero manteado daba fueron tantas, que llegaron a los oídos de su amo; el cual, determinándose a escuchar atentamente, creyó que alguna nueva aventura le venía, hasta que claramente conoció que el que gritaba era su escudero; y, volviendo las riendas, con un penado galope llegó a la venta, y, hallándola cerrada, la rodeó por ver si hallaba por donde entrar; pero no hubo llegado a las paredes del corral, que no eran muy altas, cuando vio el mal juego que se le hacía a su escudero. Viole bajar y subir por el aire, con tanta gracia y presteza que, si la cólera le dejara, tengo para mí que se riera. Probó a subir desde el caballo a las bardas, pero estaba tan molido y quebrantado que aun apearse no pudo; y así, desde encima del caballo, comenzó a decir tantos denuestos y baldones a los que a Sancho manteaban, que no es posible acertar a escribillos; mas no por esto cesaban ellos de su risa y de su obra, ni el volador Sancho dejaba sus quejas, mezcladas ya con amenazas, ya con ruegos; mas todo aprovechaba poco, ni aprovechó, hasta que de puro cansados le dejaron. Trujéronle allí su asno, y, subiéndole encima, le arroparon con su gabán. Y la compasiva de Maritornes, viéndole tan fatigado, le pareció ser bien socorrelle con un jarro de agua, y así, se le trujo del pozo, por ser más frío. Tomóle Sancho, y llevándole a la boca, se paró a las voces que su amo le daba, diciendo: -¡Hijo Sancho, no bebas agua! ¡Hijo, no la bebas, que te matará! ¿Ves? Aquí tengo el santísimo bálsamo -y enseñábale la alcuza del brebaje-, que con dos gotas que dél bebas sanarás sin duda. A estas voces volvió Sancho los ojos, como de través, y dijo con otras mayores: -¿Por dicha hásele olvidado a vuestra merced como yo no soy caballero, o quiere que acabe de vomitar las entrañas que me quedaron de anoche? Guárdese su licor con todos los diablos y déjeme a mí. Y el acabar de decir esto y el comenzar a beber todo fue uno; mas, como al primer trago vio que era agua, no quiso pasar adelante, y rogó a Maritornes que se le trujese de vino, y así lo hizo ella de muy buena voluntad, y lo pagó de su mesmo dinero; porque, en efecto, se dice della que, aunque estaba en aquel trato, tenía unas sombras y lejos de cristiana. Así como bebió Sancho, dio de los carcaños a su asno, y, abriéndole la puerta de la venta de par en par, se salió della, muy contento de no haber pagado nada y de haber salido con su intención, aunque había sido a costa de sus acostumbrados fiadores, que eran sus espaldas. Verdad es que el ventero se quedó con sus alforjas en pago de lo que se le debía; mas Sancho no las echó menos, según salió turbado. Quiso el ventero atrancar bien la puerta así como le vio fuera, mas no lo consintieron los manteadores, que eran gente que, aunque don Quijote fuera verdaderamente de los caballeros andantes de la Tabla Redonda, no le estimaran en dos ardites. Capítulo XVIII. Donde se cuentan las razones que pasó Sancho Panza con su señor Don Quijote, con otras aventuras dignas de ser contadas Llegó Sancho a su amo marchito y desmayado; tanto, que no podía arrear a su jumento. Cuando así le vio don Quijote, le dijo: -Ahora acabo de creer, Sancho bueno, que aquel castillo o venta, de que es encantado sin duda; porque aquellos que tan atrozmente tomaron pasatiempo contigo, ¿qué podían ser sino fantasmas y gente del otro mundo? Y confirmo esto por haber visto que, cuando estaba por las bardas del corral mirando los actos de tu triste tragedia, no me fue posible subir por ellas, ni menos pude apearme de Rocinante, porque me debían de tener encantado; que te juro, por la fe de quien soy, que si pudiera subir o apearme, que yo te hiciera vengado de manera que aquellos follones y malandrines se acordaran de la burla para siempre, aunque en ello supiera contravenir a las leyes de la caballería, que, como ya muchas veces te he dicho, no consienten que caballero ponga mano contra quien no lo sea, si no fuere en defensa de su propria vida y persona, en caso de urgente y gran necesidad. -También me vengara yo si pudiera, fuera o no fuera armado caballero, pero no pude; aunque tengo para mí que aquellos que se holgaron conmigo no eran fantasmas ni hombres encantados, como vuestra merced dice, sino hombres de carne y hueso como nosotros; y todos, según los oí nombrar cuando me volteaban, tenían sus nombres: que el uno se llamaba Pedro Martínez, y el otro Tenorio Hernández, y el ventero oí que se llamaba Juan Palomeque el Zurdo. Así que, señor, el no poder saltar las bardas del corral, ni apearse del caballo, en ál estuvo que en encantamentos. Y lo que yo saco en limpio de todo esto es que estas aventuras que andamos buscando, al cabo al cabo, nos han de traer a tantas desventuras que no sepamos cuál es nuestro pie derecho. Y lo que sería mejor y más acertado, según mi poco entendimiento, fuera el volvernos a nuestro lugar, ahora que es tiempo de la siega y de entender en la hacienda, dejándonos de andar de Ceca en Meca y de zoca en colodra, como dicen. -¡Qué poco sabes, Sancho -respondió don Quijote-, de achaque de caballería! Calla y ten paciencia, que día vendrá donde veas por vista de ojos cuán honrosa cosa es andar en este ejercicio. Si no, dime: ¿qué mayor contento puede haber en el mundo, o qué gusto puede igualarse al de vencer una batalla y al de triunfar de su enemigo? Ninguno, sin duda alguna. -Así debe de ser -respondió Sancho-, puesto que yo no lo sé; sólo sé que, después que somos caballeros andantes, o vuestra merced lo es (que yo no hay para qué me cuente en tan honroso número), jamás hemos vencido batalla alguna, si no fue la del vizcaíno, y aun de aquélla salió vuestra merced con media oreja y media celada menos; que, después acá, todo ha sido palos y más palos, puñadas y más puñadas, llevando yo de ventaja el manteamiento y haberme sucedido por personas encantadas, de quien no puedo vengarme, para saber hasta dónde llega el gusto del vencimiento del enemigo, como vuestra merced dice. -Ésa es la pena que yo tengo y la que tú debes tener, Sancho -respondió don Quijote-; pero, de aquí adelante, yo procuraré haber a las manos alguna espada hecha por tal maestría, que al que la trujere consigo no le puedan hacer ningún género de encantamentos; y aun podría ser que me deparase la ventura aquella de Amadís, cuando se llamaba el Caballero de la Ardiente Espada, que fue una de las mejores espadas que tuvo caballero en el mundo, porque, fuera que tenía la virtud dicha, cortaba como una navaja, y no había armadura, por fuerte y encantada que fuese, que se le parase delante. -Yo soy tan venturoso -dijo Sancho- que, cuando eso fuese y vuestra merced viniese a hallar espada semejante, sólo vendría a servir y aprovechar a los armados caballeros, como el bálsamo; y los escuderos, que se los papen duelos. -No temas eso, Sancho -dijo don Quijote-, que mejor lo hará el cielo contigo. Es estos coloquios iban don Quijote y su escudero, cuando vio don Quijote que por el camino que iban venía hacia ellos una grande y espesa polvareda; y, en viéndola, se volvió a Sancho y le dijo: -Éste es el día, ¡oh Sancho!, en el cual se ha de ver el bien que me tiene guardado mi suerte; éste es el día, digo, en que se ha de mostrar, tanto como en otro alguno, el valor de mi brazo, y en el que tengo de hacer obras que queden escritas en el libro de la Fama por todos los venideros siglos. ¿Ves aquella polvareda que allí se levanta, Sancho? Pues toda es cuajada de un copiosísimo ejército que de diversas e innumerables gentes por allí viene marchando. -A esa cuenta, dos deben de ser -dijo Sancho-, porque desta parte contraria se levanta asimesmo otra semejante polvareda. Volvió a mirarlo don Quijote, y vio que así era la verdad; y, alegrándose sobremanera, pensó, sin duda alguna, que eran dos ejércitos que venían a embestirse y a encontrarse en mitad de aquella espaciosa llanura; porque tenía a todas horas y momentos llena la fantasía de aquellas batallas, encantamentos, sucesos, desatinos, amores, desafíos, que en los libros de caballerías se cuentan, y todo cuanto hablaba, pensaba o hacía era encaminado a cosas semejantes. Y la polvareda que había visto la levantaban dos grandes manadas de ovejas y carneros que, por aquel mesmo camino, de dos diferentes partes venían, las cuales, con el polvo, no se echaron de ver hasta que llegaron cerca. Y con tanto ahínco afirmaba don Quijote que eran ejércitos, que Sancho lo vino a creer y a decirle: -Señor, ¿pues qué hemos de hacer nosotros? -¿Qué? -dijo don Quijote-: favorecer y ayudar a los menesterosos y desvalidos. Y has de saber, Sancho, que este que viene por nuestra frente le conduce y guía el grande emperador Alifanfarón, señor de la grande isla Trapobana; este otro que a mis espaldas marcha es el de su enemigo, el rey de los garamantas, Pentapolén del Arremangado Brazo, porque siempre entra en las batallas con el brazo derecho desnudo. -Pues, ¿por qué se quieren tan mal estos dos señores? -preguntó Sancho. -Quierénse mal -respondió don Quijote- porque este Alefanfarón es un foribundo pagano y está enamorado de la hija de Pentapolín, que es una muy fermosa y además agraciada señora, y es cristiana, y su padre no se la quiere entregar al rey pagano si no deja primero la ley de su falso profeta Mahoma y se vuelve a la suya. -¡Para mis barbas -dijo Sancho-, si no hace muy bien Pentapolín, y que le tengo de ayudar en cuanto pudiere! -En eso harás lo que debes, Sancho -dijo don Quijote-, porque, para entrar en batallas semejantes, no se requiere ser armado caballero. -Bien se me alcanza eso -respondió Sancho-, pero, ¿dónde pondremos a este asno que estemos ciertos de hallarle después de pasada la refriega? Porque el entrar en ella en semejante caballería no creo que está en uso hasta agora. -Así es verdad -dijo don Quijote-. Lo que puedes hacer dél es dejarle a sus aventuras, ora se pierda o no, porque serán tantos los caballos que tendremos, después que salgamos vencedores, que aun corre peligro Rocinante no le trueque por otro. Pero estáme atento y mira, que te quiero dar cuenta de los caballeros más principales que en estos dos ejércitos vienen. Y, para que mejor los veas y notes, retirémonos a aquel altillo que allí se hace, de donde se deben de descubrir los dos ejércitos. Hiciéronlo ansí, y pusierónse sobre una loma, desde la cual se vieran bien las dos manadas que a don Quijote se le hicieron ejército, si las nubes del polvo que levantaban no les turbara y cegara la vista; pero, con todo esto, viendo en su imaginación lo que no veía ni había, con voz levantada comenzó a decir: -Aquel caballero que allí ves de las armas jaldes, que trae en el escudo un león coronado, rendido a los pies de una doncella, es el valeroso Laurcalco, señor de la Puente de Plata; el otro de las armas de las flores de oro, que trae en el escudo tres coronas de plata en campo azul, es el temido Micocolembo, gran duque de Quirocia; el otro de los miembros giganteos, que está a su derecha mano, es el nunca medroso Brandabarbarán de Boliche, señor de las tres Arabias, que viene armado de aquel cuero de serpiente, y tiene por escudo una puerta que, según es fama, es una de las del templo que derribó Sansón, cuando con su muerte se vengó de sus enemigos. Pero vuelve los ojos a estotra parte y verás delante y en la frente destotro ejército al siempre vencedor y jamás vencido Timonel de Carcajona, príncipe de la Nueva Vizcaya, que viene armado con las armas partidas a cuarteles, azules, verdes, blancas y amarillas, y trae en el escudo un gato de oro en campo leonado, con una letra que dice: Miau, que es el principio del nombre de su dama, que, según se dice, es la sin par Miulina, hija del duque Alfeñiquén del Algarbe; el otro, que carga y oprime los lomos de aquella poderosa alfana, que trae las armas como nieve blancas y el escudo blanco y sin empresa alguna, es un caballero novel, de nación francés, llamado Pierres Papín, señor de las baronías de Utrique; el otro, que bate las ijadas con los herrados carcaños a aquella pintada y ligera cebra, y trae las armas de los veros azules, es el poderoso duque de Nerbia, Espartafilardo del Bosque, que trae por empresa en el escudo una esparraguera, con una letra en castellano que dice así: Rastrea mi suerte. Y desta manera fue nombrando muchos caballeros del uno y del otro escuadrón, que él se imaginaba, y a todos les dio sus armas, colores, empresas y motes de improviso, llevado de la imaginación de su nunca vista locura; y, sin parar, prosiguió diciendo: -A este escuadrón frontero forman y hacen gentes de diversas naciones: aquí están los que bebían las dulces aguas del famoso Janto; los montuosos que pisan los masílicos campos; los que criban el finísimo y menudo oro en la felice Arabia; los que gozan las famosas y frescas riberas del claro Termodonte; los que sangran por muchas y diversas vías al dorado Pactolo; los númidas, dudosos en sus promesas; los persas, arcos y flechas famosos; los partos, los medos, que pelean huyendo; los árabes, de mudables casas; los citas, tan crueles como blancos; los etiopes, de horadados labios, y otras infinitas naciones, cuyos rostros conozco y veo, aunque de los nombres no me acuerdo. En estotro escuadrón vienen los que beben las corrientes cristalinas del olivífero Betis; los que tersan y pulen sus rostros con el licor del siempre rico y dorado Tajo; los que gozan las provechosas aguas del divino Genil; los que pisan los tartesios campos, de pastos abundantes; los que se alegran en los elíseos jerezanos prados; los manchegos, ricos y coronados de rubias espigas; los de hierro vestidos, reliquias antiguas de la sangre goda; los que en Pisuerga se bañan, famoso por la mansedumbre de su corriente; los que su ganado apacientan en las estendidas dehesas del tortuoso Guadiana, celebrado por su escondido curso; los que tiemblan con el frío del silvoso Pirineo y con los blancos copos del levantado Apenino; finalmente, cuantos toda la Europa en sí contiene y encierra. ¡Válame Dios, y cuántas provincias dijo, cuántas naciones nombró, dándole a cada una, con maravillosa presteza, los atributos que le pertenecían, todo absorto y empapado en lo que había leído en sus libros mentirosos! Estaba Sancho Panza colgado de sus palabras, sin hablar ninguna, y, de cuando en cuando, volvía la cabeza a ver si veía los caballeros y gigantes que su amo nombraba; y, como no descubría a ninguno, le dijo: -Señor, encomiendo al diablo hombre, ni gigante, ni caballero de cuantos vuestra merced dice parece por todo esto; a lo menos, yo no los veo; quizá todo debe ser encantamento, como las fantasmas de anoche. -¿Cómo dices eso? -respondió don Quijote-. ¿No oyes el relinchar de los caballos, el tocar de los clarines, el ruido de los atambores? -No oigo otra cosa -respondió Sancho- sino muchos balidos de ovejas y carneros. Y así era la verdad, porque ya llegaban cerca los dos rebaños. -El miedo que tienes -dijo don Quijote- te hace, Sancho, que ni veas ni oyas a derechas; porque uno de los efectos del miedo es turbar los sentidos y hacer que las cosas no parezcan lo que son; y si es que tanto temes, retírate a una parte y déjame solo, que solo basto a dar la victoria a la parte a quien yo diere mi ayuda. Y, diciendo esto, puso las espuelas a Rocinante, y, puesta la lanza en el ristre, bajó de la costezuela como un rayo. Diole voces Sancho, diciéndole: -¡Vuélvase vuestra merced, señor don Quijote, que voto a Dios que son carneros y ovejas las que va a embestir! ¡Vuélvase, desdichado del padre que me engendró! ¿Qué locura es ésta? Mire que no hay gigante ni caballero alguno, ni gatos, ni armas, ni escudos partidos ni enteros, ni veros azules ni endiablados. ¿Qué es lo que hace? ¡Pecador soy yo a Dios! Ni por ésas volvió don Quijote; antes, en altas voces, iba diciendo: -¡Ea, caballeros, los que seguís y militáis debajo de las banderas del valeroso emperador Pentapolín del Arremangado Brazo, seguidme todos: veréis cuán fácilmente le doy venganza de su enemigo Alefanfarón de la Trapobana! Esto diciendo, se entró por medio del escuadrón de las ovejas, y comenzó de alanceallas con tanto coraje y denuedo como si de veras alanceara a sus mortales enemigos. Los pastores y ganaderos que con la manada venían dábanle voces que no hiciese aquello; pero, viendo que no aprovechaban, desciñéronse las hondas y comenzaron a saludalle los oídos con piedras como el puño. Don Quijote no se curaba de las piedras; antes, discurriendo a todas partes, decía: -¿Adónde estás, soberbio Alifanfuón? Vente a mí; que un caballero solo soy, que desea, de solo a solo, probar tus fuerzas y quitarte la vida, en pena de la que das al valeroso Pentapolín Garamanta. Llegó en esto una peladilla de arroyo, y, dándole en un lado, le sepultó dos costillas en el cuerpo. Viéndose tan maltrecho, creyó sin duda que estaba muerto o malferido, y, acordándose de su licor, sacó su alcuza y púsosela a la boca, y comenzó a echar licor en el estómago; mas, antes que acabase de envasar lo que a él le parecía que era bastante, llegó otra almendra y diole en la mano y en el alcuza tan de lleno que se la hizo pedazos, llevándole de camino tres o cuatro dientes y muelas de la boca, y machucándole malamente dos dedos de la mano. Tal fue el golpe primero, y tal el segundo, que le fue forzoso al pobre caballero dar consigo del caballo abajo. Llegáronse a él los pastores y creyeron que le habían muerto; y así, con mucha priesa, recogieron su ganado, y cargaron de las reses muertas, que pasaban de siete, y, sin averiguar otra cosa, se fueron. Estábase todo este tiempo Sancho sobre la cuesta, mirando las locuras que su amo hacía, y arrancábase las barbas, maldiciendo la hora y el punto en que la fortuna se le había dado a conocer. Viéndole, pues, caído en el suelo, y que ya los pastores se habían ido, bajó de la cuesta y llegóse a él, y hallóle de muy mal arte, aunque no había perdido el sentido, y díjole: -¿No le decía yo, señor don Quijote, que se volviese, que los que iba a acometer no eran ejércitos, sino manadas de carneros? -Como eso puede desparecer y contrahacer aquel ladrón del sabio mi enemigo. Sábete, Sancho, que es muy fácil cosa a los tales hacernos parecer lo que quieren, y este maligno que me persigue, envidioso de la gloria que vio que yo había de alcanzar desta batalla, ha vuelto los escuadrones de enemigos en manadas de ovejas. Si no, haz una cosa, Sancho, por mi vida, porque te desengañes y veas ser verdad lo que te digo: sube en tu asno y síguelos bonitamente, y verás cómo, en alejándose de aquí algún poco, se vuelven en su ser primero, y, dejando de ser carneros, son hombres hechos y derechos, como yo te los pinté primero... Pero no vayas agora, que he menester tu favor y ayuda; llégate a mí y mira cuántas muelas y dientes me faltan, que me parece que no me ha quedado ninguno en la boca. Llegóse Sancho tan cerca que casi le metía los ojos en la boca, y fue a tiempo que ya había obrado el bálsamo en el estómago de don Quijote; y, al tiempo que Sancho llegó a mirarle la boca, arrojó de sí, más recio que una escopeta, cuanto dentro tenía, y dio con todo ello en las barbas del compasivo escudero. -¡Santa María! -dijo Sancho-, ¿y qué es esto que me ha sucedido? Sin duda, este pecador está herido de muerte, pues vomita sangre por la boca. Pero, reparando un poco más en ello, echó de ver en la color, sabor y olor, que no era sangre, sino el bálsamo de la alcuza que él le había visto beber; y fue tanto el asco que tomó que, revolviéndosele el estómago, vomitó las tripas sobre su mismo señor, y quedaron entrambos como de perlas. Acudió Sancho a su asno para sacar de las alforjas con qué limpiarse y con qué curar a su amo; y, como no las halló, estuvo a punto de perder el juicio. Maldíjose de nuevo, y propuso en su corazón de dejar a su amo y volverse a su tierra, aunque perdiese el salario de lo servido y las esperanzas del gobierno de la prometida ínsula. Levantóse en esto don Quijote, y, puesta la mano izquierda en la boca, porque no se le acabasen de salir los dientes, asió con la otra las riendas de Rocinante, que nunca se había movido de junto a su amo -tal era de leal y bien acondicionado-, y fuese adonde su escudero estaba, de pechos sobre su asno, con la mano en la mejilla, en guisa de hombre pensativo además. Y, viéndole don Quijote de aquella manera, con muestras de tanta tristeza, le dijo: -Sábete, Sancho, que no es un hombre más que otro si no hace más que otro. Todas estas borrascas que nos suceden son señales de que presto ha de serenar el tiempo y han de sucedernos bien las cosas; porque no es posible que el mal ni el bien sean durables, y de aquí se sigue que, habiendo durado mucho el mal, el bien está ya cerca. Así que, no debes congojarte por las desgracias que a mí me suceden, pues a ti no te cabe parte dellas. -¿Cómo no? -respondió Sancho-. Por ventura, el que ayer mantearon, ¿era otro que el hijo de mi padre? Y las alforjas que hoy me faltan, con todas mis alhajas, ¿son de otro que del mismo? -¿Que te faltan las alforjas, Sancho? -dijo don Quijote. -Sí que me faltan -respondió Sancho. -Dese modo, no tenemos qué comer hoy -replicó don Quijote. -Eso fuera -respondió Sancho- cuando faltaran por estos prados las yerbas que vuestra merced dice que conoce, con que suelen suplir semejantes faltas los tan malaventurados andantes caballeros como vuestra merced es. -Con todo eso -respondió don Quijote-, tomara yo ahora más aína un cuartal de pan, o una hogaza y dos cabezas de sardinas arenques, que cuantas yerbas describe Dioscórides, aunque fuera el ilustrado por el doctor Laguna. Mas, con todo esto, sube en tu jumento, Sancho el bueno, y vente tras mí; que Dios, que es proveedor de todas las cosas, no nos ha de faltar, y más andando tan en su servicio como andamos, pues no falta a los mosquitos del aire, ni a los gusanillos de la tierra, ni a los renacuajos del agua; y es tan piadoso que hace salir su sol sobre los buenos y los malos, y llueve sobre los injustos y justos. -Más bueno era vuestra merced -dijo Sancho- para predicador que para caballero andante. -De todo sabían y han de saber los caballeros andantes, Sancho -dijo don Quijote-, porque caballero andante hubo en los pasados siglos que así se paraba a hacer un sermón o plática, en mitad de un campo real, como si fuera graduado por la Universidad de París; de donde se infiere que nunca la lanza embotó la pluma, ni la pluma la lanza. -Ahora bien, sea así como vuestra merced dice -respondió Sancho-, vamos ahora de aquí, y procuremos donde alojar esta noche, y quiera Dios que sea en parte donde no haya mantas, ni manteadores, ni fantasmas, ni moros encantados; que si los hay, daré al diablo el hato y el garabato. -Pídeselo tú a Dios, hijo -dijo don Quijote-, y guía tú por donde quisieres, que esta vez quiero dejar a tu eleción el alojarnos. Pero dame acá la mano y atiéntame con el dedo, y mira bien cuántos dientes y muelas me faltan deste lado derecho de la quijada alta, que allí siento el dolor. Metió Sancho los dedos, y, estándole tentando, le dijo: -¿Cuántas muelas solía vuestra merced tener en esta parte? -Cuatro -respondió don Quijote-, fuera de la cordal, todas enteras y muy sanas. -Mire vuestra merced bien lo que dice, señor -respondió Sancho. -Digo cuatro, si no eran cinco -respondió don Quijote-, porque en toda mi vida me han sacado diente ni muela de la boca, ni se me ha caído ni comido de neguijón ni de reuma alguna. -Pues en esta parte de abajo -dijo Sancho- no tiene vuestra merced más de dos muelas y media, y en la de arriba, ni media ni ninguna, que toda está rasa como la palma de la mano. -¡Sin ventura yo! -dijo don Quijote, oyendo las tristes nuevas que su escudero le daba-, que más quisiera que me hubieran derribado un brazo, como no fuera el de la espada; porque te hago saber, Sancho, que la boca sin muelas es como molino sin piedra, y en mucho más se ha de estimar un diente que un diamante. Mas a todo esto estamos sujetos los que profesamos la estrecha orden de la caballería. Sube, amigo, y guía, que yo te seguiré al paso que quisieres. Hízolo así Sancho, y encaminóse hacia donde le pareció que podía hallar acogimiento, sin salir del camino real, que por allí iba muy seguido. Yéndose, pues, poco a poco, porque el dolor de las quijadas de don Quijote no le dejaba sosegar ni atender a darse priesa, quiso Sancho entretenelle y divertille diciéndole alguna cosa; y, entre otras que le dijo, fue lo que se dirá en el siguiente capítulo. Capítulo XIX. De las discretas razones que Sancho pasaba con su amo, y de la aventura que le sucedió con un cuerpo muerto, con otros acontecimientos famosos -Paréceme, señor mío, que todas estas desventuras que estos días nos han sucedido, sin duda alguna han sido pena del pecado cometido por vuestra merced contra la orden de su caballería, no habiendo cumplido el juramento que hizo de no comer pan a manteles ni con la reina folgar, con todo aquello que a esto se sigue y vuestra merced juró de cumplir, hasta quitar aquel almete de Malandrino, o como se llama el moro, que no me acuerdo bien. -Tienes mucha razón, Sancho -dijo don Quijote-; mas, para decirte verdad, ello se me había pasado de la memoria; y también puedes tener por cierto que por la culpa de no habérmelo tú acordado en tiempo te sucedió aquello de la manta; pero yo haré la enmienda, que modos hay de composición en la orden de la caballería para todo. -Pues, ¿juré yo algo, por dicha? -respondió Sancho. -No importa que no hayas jurado -dijo don Quijote-: basta que yo entiendo que de participantes no estás muy seguro, y, por sí o por no, no será malo proveernos de remedio. -Pues si ello es así -dijo Sancho-, mire vuestra merced no se le torne a olvidar esto, como lo del juramento; quizá les volverá la gana a las fantasmas de solazarse otra vez conmigo, y aun con vuestra merced si le ven tan pertinaz. En estas y otras pláticas les tomó la noche en mitad del camino, sin tener ni descubrir donde aquella noche se recogiesen; y lo que no había de bueno en ello era que perecían de hambre; que, con la falta de las alforjas, les faltó toda la despensa y matalotaje. Y, para acabar de confirmar esta desgracia, les sucedió una aventura que, sin artificio alguno, verdaderamente lo parecía. Y fue que la noche cerró con alguna escuridad; pero, con todo esto, caminaban, creyendo Sancho que, pues aquel camino era real, a una o dos leguas, de buena razón, hallaría en él alguna venta. Yendo, pues, desta manera, la noche escura, el escudero hambriento y el amo con gana de comer, vieron que por el mesmo camino que iban venían hacia ellos gran multitud de lumbres, que no parecían sino estrellas que se movían. Pasmóse Sancho en viéndolas, y don Quijote no las tuvo todas consigo; tiró el uno del cabestro a su asno, y el otro de las riendas a su rocino, y estuvieron quedos, mirando atentamente lo que podía ser aquello, y vieron que las lumbres se iban acercando a ellos, y mientras más se llegaban, mayores parecían; a cuya vista Sancho comenzó a temblar como un azogado, y los cabellos de la cabeza se le erizaron a don Quijote; el cual, animándose un poco, dijo: -Ésta, sin duda, Sancho, debe de ser grandísima y peligrosísima aventura, donde será necesario que yo muestre todo mi valor y esfuerzo. -¡Desdichado de mí! -respondió Sancho-; si acaso esta aventura fuese de fantasmas, como me lo va pareciendo, ¿adónde habrá costillas que la sufran? -Por más fantasmas que sean -dijo don Quijote-, no consentiré yo que te toque en el pelo de la ropa; que si la otra vez se burlaron contigo, fue porque no pude yo saltar las paredes del corral, pero ahora estamos en campo raso, donde podré yo como quisiere esgremir mi espada. -Y si le encantan y entomecen, como la otra vez lo hicieron -dijo Sancho-, ¿qué aprovechará estar en campo abierto o no? -Con todo eso -replicó don Quijote-, te ruego, Sancho, que tengas buen ánimo, que la experiencia te dará a entender el que yo tengo. -Sí tendré, si a Dios place -respondió Sancho. Y, apartándose los dos a un lado del camino, tornaron a mirar atentamente lo que aquello de aquellas lumbres que caminaban podía ser; y de allí a muy poco descubrieron muchos encamisados, cuya temerosa visión de todo punto remató el ánimo de Sancho Panza, el cual comenzó a dar diente con diente, como quien tiene frío de cuartana; y creció más el batir y dentellear cuando distintamente vieron lo que era, porque descubrieron hasta veinte encamisados, todos a caballo, con sus hachas encendidas en las manos; detrás de los cuales venía una litera cubierta de luto, a la cual seguían otros seis de a caballo, enlutados hasta los pies de las mulas; que bien vieron que no eran caballos en el sosiego con que caminaban. Iban los encamisados murmurando entre sí, con una voz baja y compasiva. Esta estraña visión, a tales horas y en tal despoblado, bien bastaba para poner miedo en el corazón de Sancho, y aun en el de su amo; y así fuera en cuanto a don Quijote, que ya Sancho había dado al través con todo su esfuerzo. Lo contrario le avino a su amo, al cual en aquel punto se le representó en su imaginación al vivo que aquélla era una de las aventuras de sus libros. Figurósele que la litera eran andas donde debía de ir algún mal ferido o muerto caballero, cuya venganza a él solo estaba reservada; y, sin hacer otro discurso, enristró su lanzón, púsose bien en la silla, y con gentil brío y continente se puso en la mitad del camino por donde los encamisados forzosamente habían de pasar, y cuando los vio cerca alzó la voz y dijo: -Deteneos, caballeros, o quienquiera que seáis, y dadme cuenta de quién sois, de dónde venís, adónde vais, qué es lo que en aquellas andas lleváis; que, según las muestras, o vosotros habéis fecho, o vos han fecho, algún desaguisado, y conviene y es menester que yo lo sepa, o bien para castigaros del mal que fecistes, o bien para vengaros del tuerto que vos ficieron. -Vamos de priesa -respondió uno de los encamisados- y está la venta lejos, y no nos podemos detener a dar tanta cuenta como pedís. Y, picando la mula, pasó adelante. Sintióse desta respuesta grandemente don Quijote, y, trabando del freno, dijo: -Deteneos y sed más bien criado, y dadme cuenta de lo que os he preguntado; si no, conmigo sois todos en batalla. Era la mula asombradiza, y al tomarla del freno se espantó de manera que, alzándose en los pies, dio con su dueño por las ancas en el suelo. Un mozo que iba a pie, viendo caer al encamisado, comenzó a denostar a don Quijote, el cual, ya encolerizado, sin esperar más, enristrando su lanzón, arremetió a uno de los enlutados, y, mal ferido, dio con él en tierra; y, revolviéndose por los demás, era cosa de ver con la presteza que los acometía y desbarataba; que no parecía sino que en aquel instante le habían nacido alas a Rocinante, según andaba de ligero y orgulloso. Todos los encamisados era gente medrosa y sin armas, y así, con facilidad, en un momento dejaron la refriega y comenzaron a correr por aquel campo con las hachas encendidas, que no parecían sino a los de las máscaras que en noche de regocijo y fiesta corren. Los enlutados, asimesmo, revueltos y envueltos en sus faldamentos y lobas, no se podían mover; así que, muy a su salvo, don Quijote los apaleó a todos y les hizo dejar el sitio mal de su grado, porque todos pensaron que aquél no era hombre, sino diablo del infierno que les salía a quitar el cuerpo muerto que en la litera llevaban. Todo lo miraba Sancho, admirado del ardimiento de su señor, y decía entre sí: -Sin duda este mi amo es tan valiente y esforzado como él dice. Estaba una hacha ardiendo en el suelo, junto al primero que derribó la mula, a cuya luz le pudo ver don Quijote; y, llegándose a él, le puso la punta del lanzón en el rostro, diciéndole que se rindiese; si no, que le mataría. A lo cual respondió el caído: -Harto rendido estoy, pues no me puedo mover, que tengo una pierna quebrada; suplico a vuestra merced, si es caballero cristiano, que no me mate; que cometerá un gran sacrilegio, que soy licenciado y tengo las primeras órdenes. -Pues, ¿quién diablos os ha traído aquí -dijo don Quijote-, siendo hombre de Iglesia? -¿Quién, señor? -replicó el caído-: mi desventura. -Pues otra mayor os amenaza -dijo don Quijote-, si no me satisfacéis a todo cuanto primero os pregunté. -Con facilidad será vuestra merced satisfecho -respondió el licenciado-; y así, sabrá vuestra merced que, aunque denantes dije que yo era licenciado, no soy sino bachiller, y llámome Alonso López; soy natural de Alcobendas; vengo de la ciudad de Baeza con otros once sacerdotes, que son los que huyeron con las hachas; vamos a la ciudad de Segovia acompañando un cuerpo muerto, que va en aquella litera, que es de un caballero que murió en Baeza, donde fue depositado; y ahora, como digo, llevábamos sus huesos a su sepultura, que está en Segovia, de donde es natural. -¿Y quién le mató? -preguntó don Quijote. -Dios, por medio de unas calenturas pestilentes que le dieron -respondió el bachiller. -Desa suerte -dijo don Quijote-, quitado me ha Nuestro Señor del trabajo que había de tomar en vengar su muerte si otro alguno le hubiera muerto; pero, habiéndole muerto quien le mató, no hay sino callar y encoger los hombros, porque lo mesmo hiciera si a mí mismo me matara. Y quiero que sepa vuestra reverencia que yo soy un caballero de la Mancha, llamado don Quijote, y es mi oficio y ejercicio andar por el mundo enderezando tuertos y desfaciendo agravios. -No sé cómo pueda ser eso de enderezar tuertos -dijo el bachiller-, pues a mí de derecho me habéis vuelto tuerto, dejándome una pierna quebrada, la cual no se verá derecha en todos los días de su vida; y el agravio que en mí habéis deshecho ha sido dejarme agraviado de manera que me quedaré agraviado para siempre; y harta desventura ha sido topar con vos, que vais buscando aventuras. -No todas las cosas -respondió don Quijote- suceden de un mismo modo. El daño estuvo, señor bachiller Alonso López, en venir, como veníades, de noche, vestidos con aquellas sobrepellices, con las hachas encendidas, rezando, cubiertos de luto, que propiamente semejábades cosa mala y del otro mundo; y así, yo no pude dejar de cumplir con mi obligación acometiéndoos, y os acometiera aunque verdaderamente supiera que érades los memos satanases del infierno, que por tales os juzgué y tuve siempre. -Ya que así lo ha querido mi suerte -dijo el bachiller-, suplico a vuestra merced, señor caballero andante (que tan mala andanza me ha dado), me ayude a salir de debajo desta mula, que me tiene tomada una pierna entre el estribo y la silla. -¡Hablara yo para mañana! -dijo don Quijote-. Y ¿hasta cuándo aguardábades a decirme vuestro afán? Dio luego voces a Sancho Panza que viniese; pero él no se curó de venir, porque andaba ocupado desvalijando una acémila de repuesto que traían aquellos buenos señores, bien bastecida de cosas de comer. Hizo Sancho costal de su gabán, y, recogiendo todo lo que pudo y cupo en el talego, cargó su jumento, y luego acudió a las voces de su amo y ayudó a sacar al señor bachiller de la opresión de la mula; y, poniéndole encima della, le dio la hacha, y don Quijote le dijo que siguiese la derrota de sus compañeros, a quien de su parte pidiese perdón del agravio, que no había sido en su mano dejar de haberle hecho. Díjole también Sancho: -Si acaso quisieren saber esos señores quién ha sido el valeroso que tales los puso, diráles vuestra merced que es el famoso don Quijote de la Mancha, que por otro nombre se llama el Caballero de la Triste Figura. Con esto, se fue el bachiller; y don Quijote preguntó a Sancho que qué le había movido a llamarle el Caballero de la Triste Figura, más entonces que nunca. -Yo se lo diré -respondió Sancho-: porque le he estado mirando un rato a la luz de aquella hacha que lleva aquel malandante, y verdaderamente tiene vuestra merced la más mala figura, de poco acá, que jamás he visto; y débelo de haber causado, o ya el cansancio deste combate, o ya la falta de las muelas y dientes. -No es eso -respondió don Quijote-, sino que el sabio, a cuyo cargo debe de estar el escribir la historia de mis hazañas, le habrá parecido que será bien que yo tome algún nombre apelativo, como lo tomaban todos los caballeros pasados: cuál se llamaba el de la Ardiente Espada; cuál, el del Unicornio; aquel, de las Doncellas; aquéste, el del Ave Fénix; el otro, el Caballero del Grifo; estotro, el de la Muerte; y por estos nombres e insignias eran conocidos por toda la redondez de la tierra. Y así, digo que el sabio ya dicho te habrá puesto en la lengua y en el pensamiento ahora que me llamases el Caballero de la Triste Figura, como pienso llamarme desde hoy en adelante; y, para que mejor me cuadre tal nombre, determino de hacer pintar, cuando haya lugar, en mi escudo una muy triste figura. -No hay para qué gastar tiempo y dineros en hacer esa figura -dijo Sancho-, sino lo que se ha de hacer es que vuestra merced descubra la suya y dé rostro a los que le miraren; que, sin más ni más, y sin otra imagen ni escudo, le llamarán el de la Triste Figura; y créame que le digo verdad, porque le prometo a vuestra merced, señor, y esto sea dicho en burlas, que le hace tan mala cara la hambre y la falta de las muelas, que, como ya tengo dicho, se podrá muy bien escusar la triste pintura. Rióse don Quijote del donaire de Sancho, pero, con todo, propuso de llamarse de aquel nombre en pudiendo pintar su escudo, o rodela, como había imaginado. En esto volvió el bachiller y le dijo a don Quijote: -Olvidábaseme de decir que advierta vuestra merced que queda descomulgado por haber puesto las manos violentamente en cosa sagrada: juxta illud: Si quis suadente diabolo, etc. -No entiendo ese latín -respondió don Quijote-, mas yo sé bien que no puse las manos, sino este lanzón; cuanto más, que yo no pensé que ofendía a sacerdotes ni a cosas de la Iglesia, a quien respeto y adoro como católico y fiel cristiano que soy, sino a fantasmas y a vestiglos del otro mundo; y, cuando eso así fuese, en la memoria tengo lo que le pasó al Cid Ruy Díaz, cuando quebró la silla del embajador de aquel rey delante de Su Santidad del Papa, por lo cual lo descomulgó, y anduvo aquel día el buen Rodrigo de Vivar como muy honrado y valiente caballero. En oyendo esto el bachiller, se fue, como queda dicho, sin replicarle palabra. Quisiera don Quijote mirar si el cuerpo que venía en la litera eran huesos o no, pero no lo consintió Sancho, diciéndole: -Señor, vuestra merced ha acabado esta peligrosa aventura lo más a su salvo de todas las que yo he visto; esta gente, aunque vencida y desbaratada, podría ser que cayese en la cuenta de que los venció sola una persona, y, corridos y avergonzados desto, volviesen a rehacerse y a buscarnos, y nos diesen en qué entender. El jumento está como conviene, la montaña cerca, la hambre carga, no hay que hacer sino retirarnos con gentil compás de pies, y, como dicen, váyase el muerto a la sepultura y el vivo a la hogaza. Y, antecogiendo su asno, rogó a su señor que le siguiese; el cual, pareciéndole que Sancho tenía razón, sin volverle a replicar, le siguió. Y, a poco trecho que caminaban por entre dos montañuelas, se hallaron en un espacioso y escondido valle, donde se apearon; y Sancho alivió el jumento, y, tendidos sobre la verde yerba, con la salsa de su hambre, almorzaron, comieron, merendaron y cenaron a un mesmo punto, satisfaciendo sus estómagos con más de una fiambrera que los señores clérigos del difunto -que pocas veces se dejan mal pasar- en la acémila de su repuesto traían. Mas sucedióles otra desgracia, que Sancho la tuvo por la peor de todas, y fue que no tenían vino que beber, ni aun agua que llegar a la boca; y, acosados de la sed, dijo Sancho, viendo que el prado donde estaban estaba colmado de verde y menuda yerba, lo que se dirá en el siguiente capítulo. Capítulo XX. De la jamás vista ni oída aventura que con más poco peligro fue acabada de famoso caballero en el mundo, como la que acabó el valeroso don Quijote de la Mancha -No es posible, señor mío, sino que estas yerbas dan testimonio de que por aquí cerca debe de estar alguna fuente o arroyo que estas yerbas humedece; y así, será bien que vamos un poco más adelante, que ya toparemos donde podamos mitigar esta terrible sed que nos fatiga, que, sin duda, causa mayor pena que la hambre. Parecióle bien el consejo a don Quijote, y, tomando de la rienda a Rocinante, y Sancho del cabestro a su asno, después de haber puesto sobre él los relieves que de la cena quedaron, comenzaron a caminar por el prado arriba a tiento, porque la escuridad de la noche no les dejaba ver cosa alguna; mas, no hubieron andado docientos pasos, cuando llegó a sus oídos un grande ruido de agua, como que de algunos grandes y levantados riscos se despeñaba. Alegróles el ruido en gran manera, y, parándose a escuchar hacia qué parte sonaba, oyeron a deshora otro estruendo que les aguó el contento del agua, especialmente a Sancho, que naturalmente era medroso y de poco ánimo. Digo que oyeron que daban unos golpes a compás, con un cierto crujir de hierros y cadenas, que, acompañados del furioso estruendo del agua, que pusieran pavor a cualquier otro corazón que no fuera el de don Quijote. Era la noche, como se ha dicho, escura, y ellos acertaron a entrar entre unos árboles altos, cuyas hojas, movidas del blando viento, hacían un temeroso y manso ruido; de manera que la soledad, el sitio, la escuridad, el ruido del agua con el susurro de las hojas, todo causaba horror y espanto, y más cuando vieron que ni los golpes cesaban, ni el viento dormía, ni la mañana llegaba; añadiéndose a todo esto el ignorar el lugar donde se hallaban. Pero don Quijote, acompañado de su intrépido corazón, saltó sobre Rocinante, y, embrazando su rodela, terció su lanzón y dijo: -Sancho amigo, has de saber que yo nací, por querer del cielo, en esta nuestra edad de hierro, para resucitar en ella la de oro, o la dorada, como suele llamarse. Yo soy aquél para quien están guardados los peligros, las grandes hazañas, los valerosos hechos. Yo soy, digo otra vez, quien ha de resucitar los de la Tabla Redonda, los Doce de Francia y los Nueve de la Fama, y el que ha de poner en olvido los Platires, los Tablantes, Olivantes y Tirantes, los Febos y Belianises, con toda la caterva de los famosos caballeros andantes del pasado tiempo, haciendo en este en que me hallo tales grandezas, estrañezas y fechos de armas, que escurezcan las más claras que ellos ficieron. Bien notas, escudero fiel y legal, las tinieblas desta noche, su estraño silencio, el sordo y confuso estruendo destos árboles, el temeroso ruido de aquella agua en cuya busca venimos, que parece que se despeña y derrumba desde los altos montes de la luna, y aquel incesable golpear que nos hiere y lastima los oídos; las cuales cosas, todas juntas y cada una por sí, son bastantes a infundir miedo, temor y espanto en el pecho del mesmo Marte, cuanto más en aquel que no está acostumbrado a semejantes acontecimientos y aventuras. Pues todo esto que yo te pinto son incentivos y despertadores de mi ánimo, que ya hace que el corazón me reviente en el pecho, con el deseo que tiene de acometer esta aventura, por más dificultosa que se muestra. Así que, aprieta un poco las cinchas a Rocinante y quédate a Dios, y espérame aquí hasta tres días no más, en los cuales, si no volviere, puedes tú volverte a nuestra aldea, y desde allí, por hacerme merced y buena obra, irás al Toboso, donde dirás a la incomparable señora mía Dulcinea que su cautivo caballero murió por acometer cosas que le hiciesen digno de poder llamarse suyo. Cuando Sancho oyó las palabras de su amo, comenzó a llorar con la mayor ternura del mundo y a decille: -Señor, yo no sé por qué quiere vuestra merced acometer esta tan temerosa aventura: ahora es de noche, aquí no nos vee nadie, bien podemos torcer el camino y desviarnos del peligro, aunque no bebamos en tres días; y, pues no hay quien nos vea, menos habrá quien nos note de cobardes; cuanto más, que yo he oído predicar al cura de nuestro lugar, que vuestra merced bien conoce, que quien busca el peligro perece en él; así que, no es bien tentar a Dios acometiendo tan desaforado hecho, donde no se puede escapar sino por milagro; y basta los que ha hecho el cielo con vuestra merced en librarle de ser manteado, como yo lo fui, y en sacarle vencedor, libre y salvo de entre tantos enemigos como acompañaban al difunto. Y, cuando todo esto no mueva ni ablande ese duro corazón, muévale el pensar y creer que apenas se habrá vuestra merced apartado de aquí, cuando yo, de miedo, dé mi ánima a quien quisiere llevarla. Yo salí de mi tierra y dejé hijos y mujer por venir a servir a vuestra merced, creyendo valer más y no menos; pero, como la cudicia rompe el saco, a mí me ha rasgado mis esperanzas, pues cuando más vivas las tenía de alcanzar aquella negra y malhadada ínsula que tantas veces vuestra merced me ha prometido, veo que, en pago y trueco della, me quiere ahora dejar en un lugar tan apartado del trato humano. Por un solo Dios, señor mío, que non se me faga tal desaguisado; y ya que del todo no quiera vuestra merced desistir de acometer este fecho, dilátelo, a lo menos, hasta la mañana; que, a lo que a mí me muestra la ciencia que aprendí cuando era pastor, no debe de haber desde aquí al alba tres horas, porque la boca de la Bocina está encima de la cabeza, y hace la media noche en la línea del brazo izquierdo. -¿Cómo puedes tú, Sancho -dijo don Quijote-, ver dónde hace esa línea, ni dónde está esa boca o ese colodrillo que dices, si hace la noche tan escura que no parece en todo el cielo estrella alguna? -Así es -dijo Sancho-, pero tiene el miedo muchos ojos y vee las cosas debajo de tierra, cuanto más encima en el cielo; puesto que, por buen discurso, bien se puede entender que hay poco de aquí al día. -Falte lo que faltare -respondió don Quijote-; que no se ha de decir por mí, ahora ni en ningún tiempo, que lágrimas y ruegos me apartaron de hacer lo que debía a estilo de caballero; y así, te ruego, Sancho, que calles; que Dios, que me ha puesto en corazón de acometer ahora esta tan no vista y tan temerosa aventura, tendrá cuidado de mirar por mi salud y de consolar tu tristeza. Lo que has de hacer es apretar bien las cinchas a Rocinante y quedarte aquí, que yo daré la vuelta presto, o vivo o muerto. Viendo, pues, Sancho la última resolución de su amo y cuán poco valían con él sus lágrimas, consejos y ruegos, determinó de aprovecharse de su industria y hacerle esperar hasta el día, si pudiese; y así, cuando apretaba las cinchas al caballo, bonitamente y sin ser sentido, ató con el cabestro de su asno ambos pies a Rocinante, de manera que cuando don Quijote se quiso partir, no pudo, porque el caballo no se podía mover sino a saltos. Viendo Sancho Panza el buen suceso de su embuste, dijo: -Ea, señor, que el cielo, conmovido de mis lágrimas y plegarias, ha ordenado que no se pueda mover Rocinante; y si vos queréis porfiar, y espolear, y dalle, será enojar a la fortuna y dar coces, como dicen, contra el aguijón. Desesperábase con esto don Quijote, y, por más que ponía las piernas al caballo, menos le podía mover; y, sin caer en la cuenta de la ligadura, tuvo por bien de sosegarse y esperar, o a que amaneciese, o a que Rocinante se menease, creyendo, sin duda, que aquello venía de otra parte que de la industria de Sancho; y así, le dijo: -Pues así es, Sancho, que Rocinante no puede moverse, yo soy contento de esperar a que ría el alba, aunque yo llore lo que ella tardare en venir. -No hay que llorar -respondió Sancho-, que yo entretendré a vuestra merced contando cuentos desde aquí al día, si ya no es que se quiere apear y echarse a dormir un poco sobre la verde yerba, a uso de caballeros andantes, para hallarse más descansado cuando llegue el día y punto de acometer esta tan desemejable aventura que le espera. -¿A qué llamas apear o a qué dormir? -dijo don Quijote-. ¿Soy yo, por ventura, de aquellos caballeros que toman reposo en los peligros? Duerme tú, que naciste para dormir, o haz lo que quisieres, que yo haré lo que viere que más viene con mi pretensión. No se enoje vuestra merced, señor mío -respondió Sancho-, que no lo dije por tanto. Y, llegándose a él, puso la una mano en el arzón delantero y la otra en el otro, de modo que quedó abrazado con el muslo izquierdo de su amo, sin osarse apartar dél un dedo: tal era el miedo que tenía a los golpes, que todavía alternativamente sonaban. Díjole don Quijote que contase algún cuento para entretenerle, como se lo había prometido, a lo que Sancho dijo que sí hiciera si le dejara el temor de lo que oía. -Pero, con todo eso, yo me esforzaré a decir una historia que, si la acierto a contar y no me van a la mano, es la mejor de las historias; y estéme vuestra merced atento, que ya comienzo. «Érase que se era, el bien que viniere para todos sea, y el mal, para quien lo fuere a buscar...» Y advierta vuestra merced, señor mío, que el principio que los antiguos dieron a sus consejas no fue así comoquiera, que fue una sentencia de Catón Zonzorino, romano, que dice: "Y el mal, para quien le fuere a buscar", que viene aquí como anillo al dedo, para que vuestra merced se esté quedo y no vaya a buscar el mal a ninguna parte, sino que nos volvamos por otro camino, pues nadie nos fuerza a que sigamos éste, donde tantos miedos nos sobresaltan. -Sigue tu cuento, Sancho -dijo don Quijote-, y del camino que hemos de seguir déjame a mí el cuidado. -«Digo, pues -prosiguió Sancho-, que en un lugar de Estremadura había un pastor cabrerizo (quiero decir que guardaba cabras), el cual pastor o cabrerizo, como digo, de mi cuento, se llamaba Lope Ruiz; y este Lope Ruiz andaba enamorado de una pastora que se llamaba Torralba, la cual pastora llamada Torralba era hija de un ganadero rico, y este ganadero rico...» -Si desa manera cuentas tu cuento, Sancho -dijo don Quijote-, repitiendo dos veces lo que vas diciendo, no acabarás en dos días; dilo seguidamente y cuéntalo como hombre de entendimiento, y si no, no digas nada. -De la misma manera que yo lo cuento -respondió Sancho-, se cuentan en mi tierra todas las consejas, y yo no sé contarlo de otra, ni es bien que vuestra merced me pida que haga usos nuevos. -Di como quisieres -respondió don Quijote-; que, pues la suerte quiere que no pueda dejar de escucharte, prosigue. -«Así que, señor mío de mi ánima -prosiguió Sancho-, que, como ya tengo dicho, este pastor andaba enamorado de Torralba, la pastora, que era una moza rolliza, zahareña y tiraba algo a hombruna, porque tenía unos pocos de bigotes, que parece que ahora la veo.» -Luego, ¿conocístela tú? -dijo don Quijote. -No la conocí yo -respondió Sancho-, pero quien me contó este cuento me dijo que era tan cierto y verdadero que podía bien, cuando lo contase a otro, afirmar y jurar que lo había visto todo. «Así que, yendo días y viniendo días, el diablo, que no duerme y que todo lo añasca, hizo de manera que el amor que el pastor tenía a la pastora se volviese en omecillo y mala voluntad; y la causa fue, según malas lenguas, una cierta cantidad de celillos que ella le dio, tales que pasaban de la raya y llegaban a lo vedado; y fue tanto lo que el pastor la aborreció de allí adelante que, por no verla, se quiso ausentar de aquella tierra e irse donde sus ojos no la viesen jamás. La Torralba, que se vio desdeñada del Lope, luego le quiso bien, mas que nunca le había querido.» -Ésa es natural condición de mujeres -dijo don Quijote-: desdeñar a quien las quiere y amar a quien las aborrece. Pasa adelante, Sancho. -«Sucedió -dijo Sancho- que el pastor puso por obra su determinación, y, antecogiendo sus cabras, se encaminó por los campos de Estremadura, para pasarse a los reinos de Portugal. La Torralba, que lo supo, se fue tras él, y seguíale a pie y descalza desde lejos, con un bordón en la mano y con unas alforjas al cuello, donde llevaba, según es fama, un pedazo de espejo y otro de un peine, y no sé qué botecillo de mudas para la cara; mas, llevase lo que llevase, que yo no me quiero meter ahora en averiguallo, sólo diré que dicen que el pastor llegó con su ganado a pasar el río Guadiana, y en aquella sazón iba crecido y casi fuera de madre, y por la parte que llegó no había barca ni barco, ni quien le pasase a él ni a su ganado de la otra parte, de lo que se congojó mucho, porque veía que la Torralba venía ya muy cerca y le había de dar mucha pesadumbre con sus ruegos y lágrimas; mas, tanto anduvo mirando, que vio un pescador que tenía junto a sí un barco, tan pequeño que solamente podían caber en él una persona y una cabra; y, con todo esto, le habló y concertó con él que le pasase a él y a trecientas cabras que llevaba. Entró el pescador en el barco, y pasó una cabra; volvió, y pasó otra; tornó a volver, y tornó a pasar otra.» Tenga vuestra merced cuenta en las cabras que el pescador va pasando, porque si se pierde una de la memoria, se acabará el cuento y no será posible contar más palabra dél. «Sigo, pues, y digo que el desembarcadero de la otra parte estaba lleno de cieno y resbaloso, y tardaba el pescador mucho tiempo en ir y volver. Con todo esto, volvió por otra cabra, y otra, y otra...» -Haz cuenta que las pasó todas -dijo don Quijote-: no andes yendo y viniendo desa manera, que no acabarás de pasarlas en un año. -¿Cuántas han pasado hasta agora? -dijo Sancho. -¡Yo qué diablos sé! -respondió don Quijote-. -He ahí lo que yo dije: que tuviese buena cuenta. Pues, por Dios, que se ha acabado el cuento, que no hay pasar adelante. -¿Cómo puede ser eso? -respondió don Quijote-. ¿Tan de esencia de la historia es saber las cabras que han pasado, por estenso, que si se yerra una del número no puedes seguir adelante con la historia? -No señor, en ninguna manera -respondió Sancho-; porque, así como yo pregunté a vuestra merced que me dijese cuántas cabras habían pasado y me respondió que no sabía, en aquel mesmo instante se me fue a mí de la memoria cuanto me quedaba por decir, y a fe que era de mucha virtud y contento. -¿De modo -dijo don Quijote- que ya la historia es acabada? -Tan acabada es como mi madre -dijo Sancho. -Dígote de verdad -respondió don Quijote- que tú has contado una de las más nuevas consejas, cuento o historia, que nadie pudo pensar en el mundo; y que tal modo de contarla ni dejarla, jamás se podrá ver ni habrá visto en toda la vida, aunque no esperaba yo otra cosa de tu buen discurso; mas no me maravillo, pues quizá estos golpes, que no cesan, te deben de tener turbado el entendimiento. -Todo puede ser -respondió Sancho-, mas yo sé que en lo de mi cuento no hay más que decir: que allí se acaba do comienza el yerro de la cuenta del pasaje de las cabras. -Acabe norabuena donde quisiere -dijo don Quijote-, y veamos si se puede mover Rocinante. Tornóle a poner las piernas, y él tornó a dar saltos y a estarse quedo: tanto estaba de bien atado. En esto, parece ser, o que el frío de la mañana, que ya venía, o que Sancho hubiese cenado algunas cosas lenitivas, o que fuese cosa natural -que es lo que más se debe creer-, a él le vino en voluntad y deseo de hacer lo que otro no pudiera hacer por él; mas era tanto el miedo que había entrado en su corazón, que no osaba apartarse un negro de uña de su amo. Pues pensar de no hacer lo que tenía gana, tampoco era posible; y así, lo que hizo, por bien de paz, fue soltar la mano derecha, que tenía asida al arzón trasero, con la cual, bonitamente y sin rumor alguno, se soltó la lazada corrediza con que los calzones se sostenían, sin ayuda de otra alguna, y, en quitándosela, dieron luego abajo y se le quedaron como grillos. Tras esto, alzó la camisa lo mejor que pudo y echó al aire entrambas posaderas, que no eran muy pequeñas. Hecho esto -que él pensó que era lo más que tenía que hacer para salir de aquel terrible aprieto y angustia-, le sobrevino otra mayor, que fue que le pareció que no podía mudarse sin hacer estrépito y ruido, y comenzó a apretar los dientes y a encoger los hombros, recogiendo en sí el aliento todo cuanto podía; pero, con todas estas diligencias, fue tan desdichado que, al cabo al cabo, vino a hacer un poco de ruido, bien diferente de aquel que a él le ponía tanto miedo. Oyólo don Quijote y dijo: -¿Qué rumor es ése, Sancho? -No sé, señor -respondió él-. Alguna cosa nueva debe de ser, que las aventuras y desventuras nunca comienzan por poco. Tornó otra vez a probar ventura, y sucedióle tan bien que, sin más ruido ni alboroto que el pasado, se halló libre de la carga que tanta pesadumbre le había dado. Mas, como don Quijote tenía el sentido del olfato tan vivo como el de los oídos, y Sancho estaba tan junto y cosido con él que casi por línea recta subían los vapores hacia arriba, no se pudo escusar de que algunos no llegasen a sus narices; y, apenas hubieron llegado, cuando él fue al socorro, apretándolas entre los dos dedos; y, con tono algo gangoso, dijo: -Paréceme, Sancho, que tienes mucho miedo. -Sí tengo -respondió Sancho-; mas, ¿en qué lo echa de ver vuestra merced ahora más que nunca? -En que ahora más que nunca hueles, y no a ámbar -respondió don Quijote. -Bien podrá ser -dijo Sancho-, mas yo no tengo la culpa, sino vuestra merced, que me trae a deshoras y por estos no acostumbrados pasos. -Retírate tres o cuatro allá, amigo -dijo don Quijote (todo esto sin quitarse los dedos de las narices)-, y desde aquí adelante ten más cuenta con tu persona y con lo que debes a la mía; que la mucha conversación que tengo contigo ha engendrado este menosprecio. -Apostaré -replicó Sancho- que piensa vuestra merced que yo he hecho de mi persona alguna cosa que no deba. -Peor es meneallo, amigo Sancho -respondió don Quijote. En estos coloquios y otros semejantes pasaron la noche amo y mozo. Mas, viendo Sancho que a más andar se venía la mañana, con mucho tiento desligó a Rocinante y se ató los calzones. Como Rocinante se vio libre, aunque él de suyo no era nada brioso, parece que se resintió, y comenzó a dar manotadas; porque corvetas -con perdón suyo- no las sabía hacer. Viendo, pues, don Quijote que ya Rocinante se movía, lo tuvo a buena señal, y creyó que lo era de que acometiese aquella temerosa aventura. Acabó en esto de descubrirse el alba y de parecer distintamente las cosas, y vio don Quijote que estaba entre unos árboles altos, que ellos eran castaños, que hacen la sombra muy escura. Sintió también que el golpear no cesaba, pero no vio quién lo podía causar; y así, sin más detenerse, hizo sentir las espuelas a Rocinante, y, tornando a despedirse de Sancho, le mandó que allí le aguardase tres días, a lo más largo, como ya otra vez se lo había dicho; y que, si al cabo dellos no hubiese vuelto, tuviese por cierto que Dios había sido servido de que en aquella peligrosa aventura se le acabasen sus días. Tornóle a referir el recado y embajada que había de llevar de su parte a su señora Dulcinea, y que, en lo que tocaba a la paga de sus servicios, no tuviese pena, porque él había dejado hecho su testamento antes que saliera de su lugar, donde se hallaría gratificado de todo lo tocante a su salario, rata por cantidad, del tiempo que hubiese servido; pero que si Dios le sacaba de aquel peligro sano y salvo y sin cautela, se podía tener por muy más que cierta la prometida ínsula. De nuevo tornó a llorar Sancho, oyendo de nuevo las lastimeras razones de su buen señor, y determinó de no dejarle hasta el último tránsito y fin de aquel negocio. Destas lágrimas y determinación tan honrada de Sancho Panza saca el autor desta historia que debía de ser bien nacido, y, por lo menos, cristiano viejo. Cuyo sentimiento enterneció algo a su amo, pero no tanto que mostrase flaqueza alguna; antes, disimulando lo mejor que pudo, comenzó a caminar hacia la parte por donde le pareció que el ruido del agua y del golpear venía. Seguíale Sancho a pie, llevando, como tenía de costumbre, del cabestro a su jumento, perpetuo compañero de sus prósperas y adversas fortunas; y, habiendo andado una buena pieza por entre aquellos castaños y árboles sombríos, dieron en un pradecillo que al pie de unas altas peñas se hacía, de las cuales se precipitaba un grandísimo golpe de agua. Al pie de las peñas, estaban unas casas mal hechas, que más parecían ruinas de edificios que casas, de entre las cuales advirtieron que salía el ruido y estruendo de aquel golpear, que aún no cesaba. Alborotóse Rocinante con el estruendo del agua y de los golpes, y, sosegándole don Quijote, se fue llegando poco a poco a las casas, encomendándose de todo corazón a su señora, suplicándole que en aquella temerosa jornada y empresa le favoreciese, y de camino se encomendaba también a Dios, que no le olvidase. No se le quitaba Sancho del lado, el cual alargaba cuanto podía el cuello y la vista por entre las piernas de Rocinante, por ver si vería ya lo que tan suspenso y medroso le tenía. Otros cien pasos serían los que anduvieron, cuando, al doblar de una punta, pareció descubierta y patente la misma causa, sin que pudiese ser otra, de aquel horrísono y para ellos espantable ruido, que tan suspensos y medrosos toda la noche los había tenido. Y eran -si no lo has, ¡oh lector!, por pesadumbre y enojo- seis mazos de batán, que con sus alternativos golpes aquel estruendo formaban. Cuando don Quijote vio lo que era, enmudeció y pasmóse de arriba abajo. Miróle Sancho, y vio que tenía la cabeza inclinada sobre el pecho, con muestras de estar corrido. Miró también don Quijote a Sancho, y viole que tenía los carrillos hinchados y la boca llena de risa, con evidentes señales de querer reventar con ella, y no pudo su melanconía tanto con él que, a la vista de Sancho, pudiese dejar de reírse; y, como vio Sancho que su amo había comenzado, soltó la presa de manera que tuvo necesidad de apretarse las ijadas con los puños, por no reventar riendo. Cuatro veces sosegó, y otras tantas volvió a su risa con el mismo ímpetu que primero; de lo cual ya se daba al diablo don Quijote, y más cuando le oyó decir, como por modo de fisga: -«Has de saber, ¡oh Sancho amigo!, que yo nací, por querer del cielo, en esta nuestra edad de hierro, para resucitar en ella la dorada, o de oro. Yo soy aquél para quien están guardados los peligros, las hazañas grandes, los valerosos fechos...» Y por aquí fue repitiendo todas o las más razones que don Quijote dijo la vez primera que oyeron los temerosos golpes. Viendo, pues, don Quijote que Sancho hacía burla dél, se corrió y enojó en tanta manera, que alzó el lanzón y le asentó dos palos, tales que, si, como los recibió en las espaldas, los recibiera en la cabeza, quedara libre de pagarle el salario, si no fuera a sus herederos. Viendo Sancho que sacaba tan malas veras de sus burlas, con temor de que su amo no pasase adelante en ellas, con mucha humildad le dijo: -Sosiéguese vuestra merced; que, por Dios, que me burlo. -Pues, porque os burláis, no me burlo yo -respondió don Quijote-. Venid acá, señor alegre: ¿paréceos a vos que, si como éstos fueron mazos de batán, fueran otra peligrosa aventura, no había yo mostrado el ánimo que convenía para emprendella y acaballa? ¿Estoy yo obligado, a dicha, siendo, como soy, caballero, a conocer y destinguir los sones y saber cuáles son de batán o no? Y más, que podría ser, como es verdad, que no los he visto en mi vida, como vos los habréis visto, como villano ruin que sois, criado y nacido entre ellos. Si no, haced vos que estos seis mazos se vuelvan en seis jayanes, y echádmelos a las barbas uno a uno, o todos juntos, y, cuando yo no diere con todos patas arriba, haced de mí la burla que quisiéredes. -No haya más, señor mío -replicó Sancho-, que yo confieso que he andado algo risueño en demasía. Pero dígame vuestra merced, ahora que estamos en paz (así Dios le saque de todas las aventuras que le sucedieren tan sano y salvo como le ha sacado désta), ¿no ha sido cosa de reír, y lo es de contar, el gran miedo que hemos tenido? A lo menos, el que yo tuve; que de vuestra merced ya yo sé que no le conoce, ni sabe qué es temor ni espanto. -No niego yo -respondió don Quijote- que lo que nos ha sucedido no sea cosa digna de risa, pero no es digna de contarse; que no son todas las personas tan discretas que sepan poner en su punto las cosas. -A lo menos -respondió Sancho-, supo vuestra merced poner en su punto el lanzón, apuntándome a la cabeza, y dándome en las espaldas, gracias a Dios y a la diligencia que puse en ladearme. Pero vaya, que todo saldrá en la colada; que yo he oído decir: "Ése te quiere bien, que te hace llorar"; y más, que suelen los principales señores, tras una mala palabra que dicen a un criado, darle luego unas calzas; aunque no sé lo que le suelen dar tras haberle dado de palos, si ya no es que los caballeros andantes dan tras palos ínsulas o reinos en tierra firme. -Tal podría correr el dado -dijo don Quijote- que todo lo que dices viniese a ser verdad; y perdona lo pasado, pues eres discreto y sabes que los primeros movimientos no son en mano del hombre, y está advertido de aquí adelante en una cosa, para que te abstengas y reportes en el hablar demasiado conmigo; que en cuantos libros de caballerías he leído, que son infinitos, jamás he hallado que ningún escudero hablase tanto con su señor como tú con el tuyo. Y en verdad que lo tengo a gran falta, tuya y mía: tuya, en que me estimas en poco; mía, en que no me dejo estimar en más. Sí, que Gandalín, escudero de Amadís de Gaula, conde fue de la ínsula Firme; y se lee dél que siempre hablaba a su señor con la gorra en la mano, inclinada la cabeza y doblado el cuerpo more turquesco. Pues, ¿qué diremos de Gasabal, escudero de don Galaor, que fue tan callado que, para declararnos la excelencia de su maravilloso silencio, sola una vez se nombra su nombre en toda aquella tan grande como verdadera historia? De todo lo que he dicho has de inferir, Sancho, que es menester hacer diferencia de amo a mozo, de señor a criado y de caballero a escudero. Así que, desde hoy en adelante, nos hemos de tratar con más respeto, sin darnos cordelejo, porque, de cualquiera manera que yo me enoje con vos, ha de ser mal para el cántaro. Las mercedes y beneficios que yo os he prometido llegarán a su tiempo; y si no llegaren, el salario, a lo menos, no se ha de perder, como ya os he dicho. -Está bien cuanto vuestra merced dice -dijo Sancho-, pero querría yo saber, por si acaso no llegase el tiempo de las mercedes y fuese necesario acudir al de los salarios, cuánto ganaba un escudero de un caballero andante en aquellos tiempos, y si se concertaban por meses, o por días, como peones de albañir. -No creo yo -respondió don Quijote- que jamás los tales escuderos estuvieron a salario, sino a merced. Y si yo ahora te le he señalado a ti en el testamento cerrado que dejé en mi casa, fue por lo que podía suceder; que aún no sé cómo prueba en estos tan calamitosos tiempos nuestros la caballería, y no querría que por pocas cosas penase mi ánima en el otro mundo. Porque quiero que sepas, Sancho, que en él no hay estado más peligroso que el de los aventureros. -Así es verdad -dijo Sancho-, pues sólo el ruido de los mazos de un batán pudo alborotar y desasosegar el corazón de un tan valeroso andante aventurero como es vuestra merced. Mas, bien puede estar seguro que, de aquí adelante, no despliegue mis labios para hacer donaire de las cosas de vuestra merced, si no fuere para honrarle, como a mi amo y señor natural. -Desa manera -replicó don Quijote-, vivirás sobre la haz de la tierra; porque, después de a los padres, a los amos se ha de respetar como si lo fuesen. Capítulo XXI. Que trata de la alta aventura y rica ganancia del yelmo de Mambrino, con otras cosas sucedidas a nuestro invencible caballero En esto, comenzó a llover un poco, y quisiera Sancho que se entraran en el molino de los batanes; mas habíales cobrado tal aborrecimiento don Quijote, por la pesada burla, que en ninguna manera quiso entrar dentro; y así, torciendo el camino a la derecha mano, dieron en otro como el que habían llevado el día de antes. De allí a poco, descubrió don Quijote un hombre a caballo, que traía en la cabeza una cosa que relumbraba como si fuera de oro, y aún él apenas le hubo visto, cuando se volvió a Sancho y le dijo: -Paréceme, Sancho, que no hay refrán que no sea verdadero, porque todos son sentencias sacadas de la mesma experiencia, madre de las ciencias todas, especialmente aquel que dice: "Donde una puerta se cierra, otra se abre". Dígolo porque si anoche nos cerró la ventura la puerta de la que buscábamos, engañándonos con los batanes, ahora nos abre de par en par otra, para otra mejor y más cierta aventura; que si yo no acertare a entrar por ella, mía será la culpa, sin que la pueda dar a la poca noticia de batanes ni a la escuridad de la noche. Digo esto porque, si no me engaño, hacia nosotros viene uno que trae en su cabeza puesto el yelmo de Mambrino, sobre que yo hice el juramento que sabes. -Mire vuestra merced bien lo que dice, y mejor lo que hace -dijo Sancho-, que no querría que fuesen otros batanes que nos acabasen de abatanar y aporrear el sentido. -¡Válate el diablo por hombre! -replicó don Quijote-. ¿Qué va de yelmo a batanes? -No sé nada -respondió Sancho-; mas, a fe que si yo pudiera hablar tanto como solía, que quizá diera tales razones que vuestra merced viera que se engañaba en lo que dice. -¿Cómo me puedo engañar en lo que digo, traidor escrupuloso? -dijo don Quijote-. Dime, ¿no ves aquel caballero que hacia nosotros viene, sobre un caballo rucio rodado, que trae puesto en la cabeza un yelmo de oro? -Lo que yo veo y columbro -respondió Sancho- no es sino un hombre sobre un asno pardo, como el mío, que trae sobre la cabeza una cosa que relumbra. -Pues ése es el yelmo de Mambrino -dijo don Quijote-. Apártate a una parte y déjame con él a solas: verás cuán sin hablar palabra, por ahorrar del tiempo, concluyo esta aventura y queda por mío el yelmo que tanto he deseado. -Yo me tengo en cuidado el apartarme -replicó Sancho-, mas quiera Dios, torno a decir, que orégano sea, y no batanes. -Ya os he dicho, hermano, que no me mentéis, ni por pienso, más eso de los batanes -dijo don Quijote-; que voto..., y no digo más, que os batanee el alma. Calló Sancho, con temor que su amo no cumpliese el voto que le había echado, redondo como una bola. Es, pues, el caso que el yelmo, y el caballo y caballero que don Quijote veía, era esto: que en aquel contorno había dos lugares, el uno tan pequeño que ni tenía botica ni barbero, y el otro, que estaba junto, sí; y así, el barbero del mayor servía al menor, en el cual tuvo necesidad un enfermo de sangrarse y otro de hacerse la barba, para lo cual venía el barbero, y traía una bacía de azófar; y quiso la suerte que, al tiempo que venía, comenzó a llover, y, porque no se le manchase el sombrero, que debía de ser nuevo, se puso la bacía sobre la cabeza; y, como estaba limpia, desde media legua relumbraba. Venía sobre un asno pardo, como Sancho dijo, y ésta fue la ocasión que a don Quijote le pareció caballo rucio rodado, y caballero, y yelmo de oro; que todas las cosas que veía, con mucha facilidad las acomodaba a sus desvariadas caballerías y malandantes pensamientos. Y cuando él vio que el pobre caballero llegaba cerca, sin ponerse con él en razones, a todo correr de Rocinante le enristró con el lanzón bajo, llevando intención de pasarle de parte a parte; mas cuando a él llegaba, sin detener la furia de su carrera, le dijo: -¡Defiéndete, cautiva criatura, o entriégame de tu voluntad lo que con tanta razón se me debe! El barbero, que, tan sin pensarlo ni temerlo, vio venir aquella fantasma sobre sí, no tuvo otro remedio, para poder guardarse del golpe de la lanza, si no fue el dejarse caer del asno abajo; y no hubo tocado al suelo, cuando se levantó más ligero que un gamo y comenzó a correr por aquel llano, que no le alcanzara el viento. Dejóse la bacía en el suelo, con la cual se contentó don Quijote, y dijo que el pagano había andado discreto y que había imitado al castor, el cual, viéndose acosado de los cazadores, se taraza y arpa con los dientes aquéllo por lo que él, por distinto natural, sabe que es perseguido. Mandó a Sancho que alzase el yelmo, el cual, tomándola en las manos, dijo: -Por Dios, que la bacía es buena y que vale un real de a ocho como un maravedí. Y, dándosela a su amo, se la puso luego en la cabeza, rodeándola a una parte y a otra, buscándole el encaje; y, como no se le hallaba, dijo: -Sin duda que el pagano, a cuya medida se forjó primero esta famosa celada, debía de tener grandísima cabeza, y lo peor dello es que le falta la mitad. Cuando Sancho oyó llamar a la bacía celada, no pudo tener la risa; mas vínosele a las mientes la cólera de su amo, y calló en la mitad della. -¿De qué te ríes, Sancho? -dijo don Quijote. -Ríome -respondió él- de considerar la gran cabeza que tenía el pagano dueño deste almete, que no semeja sino una bacía de barbero pintiparada. -¿Sabes qué imagino, Sancho? Que esta famosa pieza deste encantado yelmo, por algún estraño acidente, debió de venir a manos de quien no supo conocer ni estimar su valor, y, sin saber lo que hacía, viéndola de oro purísimo, debió de fundir la otra mitad para aprovecharse del precio, y de la otra mitad hizo ésta, que parece bacía de barbero, como tú dices. Pero, sea lo que fuere; que para mí que la conozco no hace al caso su trasmutación; que yo la aderezaré en el primer lugar donde haya herrero, y de suerte que no le haga ventaja, ni aun le llegue, la que hizo y forjó el dios de las herrerías para el dios de las batallas; y, en este entretanto, la traeré como pudiere, que más vale algo que no nada; cuanto más, que bien será bastante para defenderme de alguna pedrada. -Eso será -dijo Sancho- si no se tira con honda, como se tiraron en la pelea de los dos ejércitos, cuando le santiguaron a vuestra merced las muelas y le rompieron el alcuza donde venía aquel benditísimo brebaje que me hizo vomitar las asaduras.along -No me da mucha pena el haberle perdido, que ya sabes tú, Sancho -dijo don Quijote-, que yo tengo la receta en la memoria. -También la tengo yo -respondió Sancho-, pero si yo le hiciere ni le probare más en mi vida, aquí sea mi hora. Cuanto más, que no pienso ponerme en ocasión de haberle menester, porque pienso guardarme con todos mis cinco sentidos de ser ferido ni de ferir a nadie. De lo del ser otra vez manteado, no digo nada, que semejantes desgracias mal se pueden prevenir, y si vienen, no hay que hacer otra cosa sino encoger los hombros, detener el aliento, cerrar los ojos y dejarse ir por donde la suerte y la manta nos llevare. -Mal cristiano eres, Sancho -dijo, oyendo esto, don Quijote-, porque nunca olvidas la injuria que una vez te han hecho; pues sábete que es de pechos nobles y generosos no hacer caso de niñerías. ¿Qué pie sacaste cojo, qué costilla quebrada, qué cabeza rota, para que no se te olvide aquella burla? Que, bien apurada la cosa, burla fue y pasatiempo; que, a no entenderlo yo ansí, ya yo hubiera vuelto allá y hubiera hecho en tu venganza más daño que el que hicieron los griegos por la robada Elena. La cual, si fuera en este tiempo, o mi Dulcinea fuera en aquél, pudiera estar segura que no tuviera tanta fama de hermosa como tiene. Y aquí dio un sospiro, y le puso en las nubes. Y dijo Sancho: -Pase por burlas, pues la venganza no puede pasar en veras; pero yo sé de qué calidad fueron las veras y las burlas, y sé también que no se me caerán de la memoria, como nunca se quitarán de las espaldas. Pero, dejando esto aparte, dígame vuestra merced qué haremos deste caballo rucio rodado, que parece asno pardo, que dejó aquí desamparado aquel Martino que vuestra merced derribó; que, según él puso los pies en polvorosa y cogió las de Villadiego, no lleva pergenio de volver por él jamás; y ¡para mis barbas, si no es bueno el rucio! -Nunca yo acostumbro -dijo don Quijote- despojar a los que venzo, ni es uso de caballería quitarles los caballos y dejarlos a pie, si ya no fuese que el vencedor hubiese perdido en la pendencia el suyo; que, en tal caso, lícito es tomar el del vencido, como ganado en guerra lícita. Así que, Sancho, deja ese caballo, o asno, o lo que tú quisieres que sea, que, como su dueño nos vea alongados de aquí, volverá por él. -Dios sabe si quisiera llevarle -replicó Sancho-, o, por lo menos, trocalle con este mío, que no me parece tan bueno. Verdaderamente que son estrechas las leyes de caballería, pues no se estienden a dejar trocar un asno por otro; y querría saber si podría trocar los aparejos siquiera. -En eso no estoy muy cierto -respondió don Quijote-; y, en caso de duda, hasta estar mejor informado, digo que los trueques, si es que tienes dellos necesidad estrema. -Tan estrema es -respondió Sancho- que si fueran para mi misma persona, no los hubiera menester más. Y luego, habilitado con aquella licencia, hizo mutatio caparum y puso su jumento a las mil lindezas, dejándole mejorado en tercio y quinto. Hecho esto, almorzaron de las sobras del real que del acémila despojaron, bebieron del agua del arroyo de los batanes, sin volver la cara a mirallos: tal era el aborrecimiento que les tenían por el miedo en que les habían puesto. Cortada, pues, la cólera, y aun la malenconía, subieron a caballo, y, sin tomar determinado camino, por ser muy de caballeros andantes el no tomar ninguno cierto, se pusieron a caminar por donde la voluntad de Rocinante quiso, que se llevaba tras sí la de su amo, y aun la del asno, que siempre le seguía por dondequiera que guiaba, en buen amor y compañía. Con todo esto, volvieron al camino real y siguieron por él a la ventura, sin otro disignio alguno. Yendo, pues, así caminando, dijo Sancho a su amo: -Señor, ¿quiere vuestra merced darme licencia que departa un poco con él? Que, después que me puso aquel áspero mandamiento del silencio, se me han podrido más de cuatro cosas en el estómago, y una sola que ahora tengo en el pico de la lengua no querría que se mal lograse. -Dila -dijo don Quijote-, y sé breve en tus razonamientos, que ninguno hay gustoso si es largo. -Digo, pues, señor -respondió Sancho-, que, de algunos días a esta parte, he considerado cuán poco se gana y granjea de andar buscando estas aventuras que vuestra merced busca por estos desiertos y encrucijadas de caminos, donde, ya que se venzan y acaben las más eligrosas, no hay quien las vea ni sepa; y así, se han de quedar en perpetuo silencio, y en perjuicio de la intención de vuestra merced y de lo que ellas merecen. Y así, me parece que sería mejor, salvo el mejor parecer de vuestra merced, que nos fuésemos a servir a algún emperador, o a otro príncipe grande que tenga alguna guerra, en cuyo servicio vuestra merced muestre el valor de su persona, sus grandes fuerzas y mayor entendimiento; que, visto esto del señor a quien sirviéremos, por fuerza nos ha de remunerar, a cada cual según sus méritos, y allí no faltará quien ponga en escrito las hazañas de vuestra merced, para perpetua memoria. De las mías no digo nada, pues no han de salir de los límites escuderiles; aunque sé decir que, si se usa en la caballería escribir hazañas de escuderos, que no pienso que se han de quedar las mías entre renglones. -No dices mal, Sancho -respondió don Quijote-; mas, antes que se llegue a ese término, es menester andar por el mundo, como en aprobación, buscando las aventuras, para que, acabando algunas, se cobre nombre y fama tal que, cuando se fuere a la corte de algún gran monarca, ya sea el caballero conocido por sus obras; y que, apenas le hayan visto entrar los muchachos por la puerta de la ciudad, cuando todos le sigan y rodeen, dando voces, diciendo: ''Éste es el Caballero del Sol'', o de la Sierpe, o de otra insignia alguna, debajo de la cual hubiere acabado grandes hazañas. ''Éste es -dirán- el que venció en singular batalla al gigantazo Brocabruno de la Gran Fuerza; el que desencantó al Gran Mameluco de Persia del largo encantamento en que había estado casi novecientos años''. Así que, de mano en mano, irán pregonando tus hechos, y luego, al alboroto de los muchachos y de la demás gente, se parará a las fenestras de su real palacio el rey de aquel reino, y así como vea al caballero, conociéndole por las armas o por la empresa del escudo, forzosamente ha de decir: ''¡Ea, sus! ¡Salgan mis caballeros, cuantos en mi corte están, a recebir a la flor de la caballería, que allí viene!'' A cuyo mandamiento saldrán todos, y él llegará hasta la mitad de la escalera, y le abrazará estrechísimamente, y le dará paz besándole en el rostro; y luego le llevará por la mano al aposento de la señora reina, adonde el caballero la hallará con la infanta, su hija, que ha de ser una de las más fermosas y acabadas doncellas que, en gran parte de lo descubierto de la tierra, a duras penas se pueda hallar. Sucederá tras esto, luego en continente, que ella ponga los ojos en el caballero y él en los della, y cada uno parezca a otro cosa más divina que humana; y, sin saber cómo ni cómo no, han de quedar presos y enlazados en la intricable red amorosa, y con gran cuita en sus corazones por no saber cómo se han de fablar para descubrir sus ansias y sentimientos. Desde allí le llevarán, sin duda, a algún cuarto del palacio, ricamente aderezado, donde, habiéndole quitado las armas, le traerán un rico manto de escarlata con que se cubra; y si bien pareció armado, tan bien y mejor ha de parecer en farseto. Venida la noche, cenará con el rey, reina e infanta, donde nunca quitará los ojos della, mirándola a furto de los circustantes, y ella hará lo mesmo con la mesma sagacidad, porque, como tengo dicho, es muy discreta doncella. Levantarse han las tablas, y entrará a deshora por la puerta de la sala un feo y pequeño enano con una fermosa dueña, que, entre dos gigantes, detrás del enano viene, con cierta aventura, hecha por un antiquísimo sabio, que el que la acabare será tenido por el mejor caballero del mundo. Mandará luego el rey que todos los que están presentes la prueben, y ninguno le dará fin y cima sino el caballero huésped, en mucho pro de su fama, de lo cual quedará contentísima la infanta, y se tendrá por contenta y pagada además, por haber puesto y colocado sus pensamientos en tan alta parte. Y lo bueno es que este rey, o príncipe, o lo que es, tiene una muy reñida guerra con otro tan poderoso como él, y el caballero huésped le pide (al cabo de algunos días que ha estado en su corte) licencia para ir a servirle en aquella guerra dicha. Darásela el rey de muy buen talante, y el caballero le besará cortésmente las manos por la merced que le face. Y aquella noche se despedirá de su señora la infanta por las rejas de un jardín, que cae en el aposento donde ella duerme, por las cuales ya otras muchas veces la había fablado, siendo medianera y sabidora de todo una doncella de quien la infanta mucho se fiaba. Sospirará él, desmayaráse ella, traerá agua la doncella, acuitaráse mucho porque viene la mañana, y no querría que fuesen descubiertos, por la honra de su señora. Finalmente, la infanta volverá en sí y dará sus blancas manos por la reja al caballero, el cual se las besará mil y mil veces y se las bañará en lágrimas. Quedará concertado entre los dos del modo que se han de hacer saber sus buenos o malos sucesos, y rogarále la princesa que se detenga lo menos que pudiere; prometérselo ha él con muchos juramentos; tórnale a besar las manos, y despídese con tanto sentimiento que estará poco por acabar la vida. Vase desde allí a su aposento, échase sobre su lecho, no puede dormir del dolor de la partida, madruga muy de mañana, vase a despedir del rey y de la reina y de la infanta; dícenle, habiéndose despedido de los dos, que la señora infanta está mal dispuesta y que no puede recebir visita; piensa el caballero que es de pena de su partida, traspásasele el corazón, y falta poco de no dar indicio manifiesto de su pena. Está la doncella medianera delante, halo de notar todo, váselo a decir a su señora, la cual la recibe con lágrimas y le dice que una de las mayores penas que tiene es no saber quién sea su caballero, y si es de linaje de reyes o no; asegúrala la doncella que no puede caber tanta cortesía, gentileza y valentía como la de su caballero sino en subjeto real y grave; consuélase con esto la cuitada; procura consolarse, por no dar mal indicio de sí a sus padres, y, a cabo de dos días, sale en público. Ya se es ido el caballero: pelea en la guerra, vence al enemigo del rey, gana muchas ciudades, triunfa de muchas batallas, vuelve a la corte, ve a su señora por donde suele, conciértase que la pida a su padre por mujer en pago de sus servicios. No se la quiere dar el rey, porque no sabe quién es; pero, con todo esto, o robada o de otra cualquier suerte que sea, la infanta viene a ser su esposa y su padre lo viene a tener a gran ventura, porque se vino a averiguar que el tal caballero es hijo de un valeroso rey de no sé qué reino, porque creo que no debe de estar en el mapa. Muérese el padre, hereda la infanta, queda rey el caballero en dos palabras. Aquí entra luego el hacer mercedes a su escudero y a todos aquellos que le ayudaron a subir a tan alto estado: casa a su escudero con una doncella de la infanta, que será, sin duda, la que fue tercera en sus amores, que es hija de un duque muy principal. -Eso pido, y barras derechas -dijo Sancho-; a eso me atengo, porque todo, al pie de la letra, ha de suceder por vuestra merced, llamándose el Caballero de la Triste Figura. -No lo dudes, Sancho -replicó don Quijote-, porque del mesmo y por los mesmos pasos que esto he contado suben y han subido los caballeros andantes a ser reyes y emperadores. Sólo falta agora mirar qué rey de los cristianos o de los paganos tenga guerra y tenga hija hermosa; pero tiempo habrá para pensar esto, pues, como te tengo dicho, primero se ha de cobrar fama por otras partes que se acuda a la corte. También me falta otra cosa; que, puesto caso que se halle rey con guerra y con hija hermosa, y que yo haya cobrado fama increíble por todo el universo, no sé yo cómo se podía hallar que yo sea de linaje de reyes, o, por lo menos, primo segundo de emperador; porque no me querrá el rey dar a su hija por mujer si no está primero muy enterado en esto, aunque más lo merezcan mis famosos hechos. Así que, por esta falta, temo perder lo que mi brazo tiene bien merecido. Bien es verdad que yo soy hijodalgo de solar conocido, de posesión y propriedad y de devengar quinientos sueldos; y podría ser que el sabio que escribiese mi historia deslindase de tal manera mi parentela y decendencia, que me hallase quinto o sesto nieto de rey. Porque te hago saber, Sancho, que hay dos maneras de linajes en el mundo: unos que traen y derriban su decendencia de príncipes y monarcas, a quien poco a poco el tiempo ha deshecho, y han acabado en punta, como pirámide puesta al revés; otros tuvieron principio de gente baja, y van subiendo de grado en grado, hasta llegar a ser grandes señores. De manera que está la diferencia en que unos fueron, que ya no son, y otros son, que ya no fueron; y podría ser yo déstos que, después de averiguado, hubiese sido mi principio grande y famoso, con lo cual se debía de contentar el rey, mi suegro, que hubiere de ser. Y cuando no, la infanta me ha de querer de manera que, a pesar de su padre, aunque claramente sepa que soy hijo de un azacán, me ha de admitir por señor y por esposo; y si no, aquí entra el roballa y llevalla donde más gusto me diere; que el tiempo o la muerte ha de acabar el enojo de sus padres. -Ahí entra bien también -dijo Sancho- lo que algunos desalmados dicen: "No pidas de grado lo que puedes tomar por fuerza"; aunque mejor cuadra decir: "Más vale salto de mata que ruego de hombres buenos". Dígolo porque si el señor rey, suegro de vuestra merced, no se quisiere domeñar a entregalle a mi señora la infanta, no hay sino, como vuestra merced dice, roballa y trasponella. Pero está el daño que, en tanto que se hagan las paces y se goce pacíficamente el reino, el pobre escudero se podrá estar a diente en esto de las mercedes. Si ya no es que la doncella tercera, que ha de ser su mujer, se sale con la infanta, y él pasa con ella su mala ventura, hasta que el cielo ordene otra cosa; porque bien podrá, creo yo, desde luego dársela su señor por ligítima esposa. -Eso no hay quien la quite -dijo don Quijote. -Pues, como eso sea -respondió Sancho-, no hay sino encomendarnos a Dios, y dejar correr la suerte por donde mejor lo encaminare. -Hágalo Dios -respondió don Quijote- como yo deseo y tú, Sancho, has menester; y ruin sea quien por ruin se tiene. -Sea par Dios -dijo Sancho-, que yo cristiano viejo soy, y para ser conde esto me basta. -Y aun te sobra -dijo don Quijote-; y cuando no lo fueras, no hacía nada al caso, porque, siendo yo el rey, bien te puedo dar nobleza, sin que la compres ni me sirvas con nada. Porque, en haciéndote conde, cátate ahí caballero, y digan lo que dijeren; que a buena fe que te han de llamar señoría, mal que les pese. -Y ¡montas que no sabría yo autorizar el litado! -dijo Sancho. -Dictado has de decir, que no litado -dijo su amo. -Sea ansí -respondió Sancho Panza-. Digo que le sabría bien acomodar, porque, por vida mía, que un tiempo fui muñidor de una cofradía, y que me asentaba tan bien la ropa de muñidor, que decían todos que tenía presencia para poder ser prioste de la mesma cofradía. Pues, ¿qué será cuando me ponga un ropón ducal a cuestas, o me vista de oro y de perlas, a uso de conde estranjero? Para mí tengo que me han de venir a ver de cien leguas. -Bien parecerás -dijo don Quijote-, pero será menester que te rapes las barbas a menudo; que, según las tienes de espesas, aborrascadas y mal puestas, si no te las rapas a navaja, cada dos días por lo menos, a tiro de escopeta se echará de ver lo que eres. -¿Qué hay más -dijo Sancho-, sino tomar un barbero y tenelle asalariado en casa? Y aun, si fuere menester, le haré que ande tras mí, como caballerizo de grande. -Pues, ¿cómo sabes tú -preguntó don Quijote- que los grandes llevan detrás de sí a sus caballerizos? -Yo se lo diré -respondió Sancho-: los años pasados estuve un mes en la corte, y allí vi que, paseándose un señor muy pequeño, que decían que era muy grande, un hombre le seguía a caballo a todas las vueltas que daba, que no parecía sino que era su rabo. Pregunté que cómo aquel hombre no se juntaba con el otro, sino que siempre andaba tras dél. Respondiéronme que era su caballerizo y que era uso de los grandes llevar tras sí a los tales. Desde entonces lo sé tan bien que nunca se me ha olvidado. -Digo que tienes razón -dijo don Quijote-, y que así puedes tú llevar a tu barbero; que los usos no vinieron todos juntos, ni se inventaron a una, y puedes ser tú el primero conde que lleve tras sí su barbero; y aun es de más confianza el hacer la barba que ensillar un caballo. -Quédese eso del barbero a mi cargo -dijo Sancho-, y al de vuestra merced se quede el procurar venir a ser rey y el hacerme conde. -Así será -respondió don Quijote. Y, alzando los ojos, vio lo que se dirá en el siguiente capítulo. Capítulo XXII. De la libertad que dio don Quijote a muchos desdichados que, mal de su grado, los llevaban donde no quisieran ir Cuenta Cide Hamete Benengeli, autor arábigo y manchego, en esta gravísima, altisonante, mínima, dulce e imaginada historia que, después que entre el famoso don Quijote de la Mancha y Sancho Panza, su escudero, pasaron aquellas razones que en el fin del capítulo veinte y uno quedan referidas, que don Quijote alzó los ojos y vio que por el camino que llevaba venían hasta doce hombres a pie, ensartados, como cuentas, en una gran cadena de hierro por los cuellos, y todos con esposas a las manos. Venían ansimismo con ellos dos hombres de a caballo y dos de a pie; los de a caballo, con escopetas de rueda, y los de a pie, con dardos y espadas; y que así como Sancho Panza los vido, dijo: -Ésta es cadena de galeotes, gente forzada del rey, que va a las galeras. -¿Cómo gente forzada? -preguntó don Quijote-. ¿Es posible que el rey haga fuerza a ninguna gente? -No digo eso -respondió Sancho-, sino que es gente que, por sus delitos, va condenada a servir al rey en las galeras de por fuerza. -En resolución -replicó don Quijote-, comoquiera que ello sea, esta gente, aunque los llevan, van de por fuerza, y no de su voluntad. -Así es -dijo Sancho. -Pues desa manera -dijo su amo-, aquí encaja la ejecución de mi oficio: desfacer fuerzas y socorrer y acudir a los miserables. -Advierta vuestra merced -dijo Sancho- que la justicia, que es el mesmo rey, no hace fuerza ni agravio a semejante gente, sino que los castiga en pena de sus delitos. Llegó, en esto, la cadena de los galeotes, y don Quijote, con muy corteses razones, pidió a los que iban en su guarda fuesen servidos de informalle y decille la causa, o causas, por que llevan aquella gente de aquella manera. Una de las guardas de a caballo respondió que eran galeotes, gente de Su Majestad que iba a galeras, y que no había más que decir, ni él tenía más que saber. -Con todo eso -replicó don Quijote-, querría saber de cada uno dellos en particular la causa de su desgracia. Añadió a éstas otras tales y tan comedidas razones, para moverlos a que dijesen lo que deseaba, que la otra guarda de a caballo le dijo: -Aunque llevamos aquí el registro y la fe de las sentencias de cada uno destos malaventurados, no es tiempo éste de detenerles a sacarlas ni a leellas; vuestra merced llegue y se lo pregunte a ellos mesmos, que ellos lo dirán si quisieren, que sí querrán, porque es gente que recibe gusto de hacer y decir bellaquerías. Con esta licencia, que don Quijote se tomara aunque no se la dieran, se llegó a la cadena, y al primero le preguntó que por qué pecados iba de tan mala guisa. Él le respondió que por enamorado iba de aquella manera. -¿Por eso no más? -replicó don Quijote-. Pues, si por enamorados echan a galeras, días ha que pudiera yo estar bogando en ellas. -No son los amores como los que vuestra merced piensa -dijo el galeote-; que los míos fueron que quise tanto a una canasta de colar, atestada de ropa blanca, que la abracé conmigo tan fuertemente que, a no quitármela la justicia por fuerza, aún hasta agora no la hubiera dejado de mi voluntad. Fue en fragante, no hubo lugar de tormento; concluyóse la causa, acomodáronme las espaldas con ciento, y por añadidura tres precisos de gurapas, y acabóse la obra. -¿Qué son gurapas? -preguntó don Quijote. -Gurapas son galeras -respondió el galeote. El cual era un mozo de hasta edad de veinte y cuatro años, y dijo que era natural de Piedrahíta. Lo mesmo preguntó don Quijote al segundo, el cual no respondió palabra, según iba de triste y malencónico; mas respondió por él el primero, y dijo: -Éste, señor, va por canario; digo, por músico y cantor. -Pues, ¿cómo -repitió don Quijote-, por músicos y cantores van también a galeras? -Sí, señor -respondió el galeote-, que no hay peor cosa que cantar en el ansia. -Antes, he yo oído decir -dijo don Quijote- que quien canta sus males espanta. -Acá es al revés -dijo el galeote-, que quien canta una vez llora toda la vida. -No lo entiendo -dijo don Quijote. Mas una de las guardas le dijo: -Señor caballero, cantar en el ansia se dice, entre esta gente non santa, confesar en el tormento. A este pecador le dieron tormento y confesó su delito, que era ser cuatrero, que es ser ladrón de bestias, y, por haber confesado, le condenaron por seis años a galeras, amén de docientos azotes que ya lleva en las espaldas. Y va siempre pensativo y triste, porque los demás ladrones que allá quedan y aquí van le maltratan y aniquilan, y escarnecen y tienen en poco, porque confesó y no tuvo ánimo de decir nones. Porque dicen ellos que tantas letras tiene un no como un sí, y que harta ventura tiene un delincuente, que está en su lengua su vida o su muerte, y no en la de los testigos y probanzas; y para mí tengo que no van muy fuera de camino. -Y yo lo entiendo así -respondió don Quijote. El cual, pasando al tercero, preguntó lo que a los otros; el cual, de presto y con mucho desenfado, respondió y dijo: -Yo voy por cinco años a las señoras gurapas por faltarme diez ducados. -Yo daré veinte de muy buena gana -dijo don Quijote- por libraros desa pesadumbre. -Eso me parece -respondió el galeote- como quien tiene dineros en mitad del golfo y se está muriendo de hambre, sin tener adonde comprar lo que ha menester. Dígolo porque si a su tiempo tuviera yo esos veinte ducados que vuestra merced ahora me ofrece, hubiera untado con ellos la péndola del escribano y avivado el ingenio del procurador, de manera que hoy me viera en mitad de la plaza de Zocodover, de Toledo, y no en este camino, atraillado como galgo; pero Dios es grande: paciencia y basta. Pasó don Quijote al cuarto, que era un hombre de venerable rostro con una barba blanca que le pasaba del pecho; el cual, oyéndose preguntar la causa por que allí venía, comenzó a llorar y no respondió palabra; mas el quinto condenado le sirvió de lengua, y dijo: -Este hombre honrado va por cuatro años a galeras, habiendo paseado las acostumbradas vestido en pompa y a caballo. -Eso es -dijo Sancho Panza-, a lo que a mí me parece, haber salido a la vergüenza. -Así es -replicó el galeote-; y la culpa por que le dieron esta pena es por haber sido corredor de oreja, y aun de todo el cuerpo. En efecto, quiero decir que este caballero va por alcahuete, y por tener asimesmo sus puntas y collar de hechicero. -A no haberle añadido esas puntas y collar -dijo don Quijote-, por solamente el alcahuete limpio, no merecía él ir a bogar en las galeras, sino a mandallas y a ser general dellas; porque no es así comoquiera el oficio de alcahuete, que es oficio de discretos y necesarísimo en la república bien ordenada, y que no le debía ejercer sino gente muy bien nacida; y aun había de haber veedor y examinador de los tales, como le hay de los demás oficios, con número deputado y conocido, como corredores de lonja; y desta manera se escusarían muchos males que se causan por andar este oficio y ejercicio entre gente idiota y de poco entendimiento, como son mujercillas de poco más a menos, pajecillos y truhanes de pocos años y de poca experiencia, que, a la más necesaria ocasión y cuando es menester dar una traza que importe, se les yelan las migas entre la boca y la mano y no saben cuál es su mano derecha. Quisiera pasar adelante y dar las razones por que convenía hacer elección de los que en la república habían de tener tan necesario oficio, pero no es el lugar acomodado para ello: algún día lo diré a quien lo pueda proveer y remediar. Sólo digo ahora que la pena que me ha causado ver estas blancas canas y este rostro venerable en tanta fatiga, por alcahuete, me la ha quitado el adjunto de ser hechicero; aunque bien sé que no hay hechizos en el mundo que puedan mover y forzar la voluntad, como algunos simples piensan; que es libre nuestro albedrío, y no hay yerba ni encanto que le fuerce. Lo que suelen hacer algunas mujercillas simples y algunos embusteros bellacos es algunas misturas y venenos con que vuelven locos a los hombres, dando a entender que tienen fuerza para hacer querer bien, siendo, como digo, cosa imposible forzar la voluntad. -Así es -dijo el buen viejo-, y, en verdad, señor, que en lo de hechicero que no tuve culpa; en lo de alcahuete, no lo pude negar. Pero nunca pensé que hacía mal en ello: que toda mi intención era que todo el mundo se holgase y viviese en paz y quietud, sin pendencias ni penas; pero no me aprovechó nada este buen deseo para dejar de ir adonde no espero volver, según me cargan los años y un mal de orina que llevo, que no me deja reposar un rato. Y aquí tornó a su llanto, como de primero; y túvole Sancho tanta compasión, que sacó un real de a cuatro del seno y se le dio de limosna. Pasó adelante don Quijote, y preguntó a otro su delito, el cual respondió con no menos, sino con mucha más gallardía que el pasado: -Yo voy aquí porque me burlé demasiadamente con dos primas hermanas mías, y con otras dos hermanas que no lo eran mías; finalmente, tanto me burlé con todas, que resultó de la burla crecer la parentela, tan intricadamente que no hay diablo que la declare. Probóseme todo, faltó favor, no tuve dineros, víame a pique de perder los tragaderos, sentenciáronme a galeras por seis años, consentí: castigo es de mi culpa; mozo soy: dure la vida, que con ella todo se alcanza. Si vuestra merced, señor caballero, lleva alguna cosa con que socorrer a estos pobretes, Dios se lo pagará en el cielo, y nosotros tendremos en la tierra cuidado de rogar a Dios en nuestras oraciones por la vida y salud de vuestra merced, que sea tan larga y tan buena como su buena presencia merece. Éste iba en hábito de estudiante, y dijo una de las guardas que era muy grande hablador y muy gentil latino. Tras todos éstos, venía un hombre de muy buen parecer, de edad de treinta años, sino que al mirar metía el un ojo en el otro un poco. Venía diferentemente atado que los demás, porque traía una cadena al pie, tan grande que se la liaba por todo el cuerpo, y dos argollas a la garganta, la una en la cadena, y la otra de las que llaman guardaamigo o piedeamigo, de la cual decendían dos hierros que llegaban a la cintura, en los cuales se asían dos esposas, donde llevaba las manos, cerradas con un grueso candado, de manera que ni con las manos podía llegar a la boca, ni podía bajar la cabeza a llegar a las manos. Preguntó don Quijote que cómo iba aquel hombre con tantas prisiones más que los otros. Respondióle la guarda porque tenía aquel solo más delitos que todos los otros juntos, y que era tan atrevido y tan grande bellaco que, aunque le llevaban de aquella manera, no iban seguros dél, sino que temían que se les había de huir. -¿Qué delitos puede tener -dijo don Quijote-, si no han merecido más pena que echalle a las galeras? -Va por diez años -replicó la guarda-, que es como muerte cevil. No se quiera saber más, sino que este buen hombre es el famoso Ginés de Pasamonte, que por otro nombre llaman Ginesillo de Parapilla. -Señor comisario -dijo entonces el galeote-, váyase poco a poco, y no andemos ahora a deslindar nombres y sobrenombres. Ginés me llamo y no Ginesillo, y Pasamonte es mi alcurnia, y no Parapilla, como voacé dice; y cada uno se dé una vuelta a la redonda, y no hará poco. -Hable con menos tono -replicó el comisario-, señor ladrón de más de la marca, si no quiere que le haga callar, mal que le pese. -Bien parece -respondió el galeote- que va el hombre como Dios es servido, pero algún día sabrá alguno si me llamo Ginesillo de Parapilla o no. -Pues, ¿no te llaman ansí, embustero? -dijo la guarda. -Sí llaman -respondió Ginés-, mas yo haré que no me lo llamen, o me las pelaría donde yo digo entre mis dientes. Señor caballero, si tiene algo que darnos, dénoslo ya, y vaya con Dios, que ya enfada con tanto querer saber vidas ajenas; y si la mía quiere saber, sepa que yo soy Ginés de Pasamonte, cuya vida está escrita por estos pulgares. -Dice verdad -dijo el comisario-: que él mesmo ha escrito su historia, que no hay más, y deja empeñado el libro en la cárcel en docientos reales. -Y le pienso quitar -dijo Ginés-, si quedara en docientos ducados. -¿Tan bueno es? -dijo don Quijote. -Es tan bueno -respondió Ginés- que mal año para Lazarillo de Tormes y para todos cuantos de aquel género se han escrito o escribieren. Lo que le sé decir a voacé es que trata verdades, y que son verdades tan lindas y tan donosas que no pueden haber mentiras que se le igualen. -¿Y cómo se intitula el libro? -preguntó don Quijote. -La vida de Ginés de Pasamonte -respondió el mismo. -¿Y está acabado? -preguntó don Quijote. -¿Cómo puede estar acabado -respondió él-, si aún no está acabada mi vida? Lo que está escrito es desde mi nacimiento hasta el punto que esta última vez me han echado en galeras. -Luego, ¿otra vez habéis estado en ellas? -dijo don Quijote. -Para servir a Dios y al rey, otra vez he estado cuatro años, y ya sé a qué sabe el bizcocho y el corbacho -respondió Ginés-; y no me pesa mucho de ir a ellas, porque allí tendré lugar de acabar mi libro, que me quedan muchas cosas que decir, y en las galeras de España hay mas sosiego de aquel que sería menester, aunque no es menester mucho más para lo que yo tengo de escribir, porque me lo sé de coro. -Hábil pareces -dijo don Quijote. -Y desdichado -respondió Ginés-; porque siempre las desdichas persiguen al buen ingenio. -Persiguen a los bellacos -dijo el comisario. -Ya le he dicho, señor comisario -respondió Pasamonte-, que se vaya poco a poco, que aquellos señores no le dieron esa vara para que maltratase a los pobretes que aquí vamos, sino para que nos guiase y llevase adonde Su Majestad manda. Si no, ¡por vida de...! ¡Basta!, que podría ser que saliesen algún día en la colada las manchas que se hicieron en la venta; y todo el mundo calle, y viva bien, y hable mejor y caminemos, que ya es mucho regodeo éste. Alzó la vara en alto el comisario para dar a Pasamonte en respuesta de sus amenazas, mas don Quijote se puso en medio y le rogó que no le maltratase, pues no era mucho que quien llevaba tan atadas las manos tuviese algún tanto suelta la lengua. Y, volviéndose a todos los de la cadena, dijo: -De todo cuanto me habéis dicho, hermanos carísimos, he sacado en limpio que, aunque os han castigado por vuestras culpas, las penas que vais a padecer no os dan mucho gusto, y que vais a ellas muy de mala gana y muy contra vuestra voluntad; y que podría ser que el poco ánimo que aquél tuvo en el tormento, la falta de dineros déste, el poco favor del otro y, finalmente, el torcido juicio del juez, hubiese sido causa de vuestra perdición y de no haber salido con la justicia que de vuestra parte teníades. Todo lo cual se me representa a mí ahora en la memoria de manera que me está diciendo, persuadiendo y aun forzando que muestre con vosotros el efeto para que el cielo me arrojó al mundo, y me hizo profesar en él la orden de caballería que profeso, y el voto que en ella hice de favorecer a los menesterosos y opresos de los mayores. Pero, porque sé que una de las partes de la prudencia es que lo que se puede hacer por bien no se haga por mal, quiero rogar a estos señores guardianes y comisario sean servidos de desataros y dejaros ir en paz, que no faltarán otros que sirvan al rey en mejores ocasiones; porque me parece duro caso hacer esclavos a los que Dios y naturaleza hizo libres. Cuanto más, señores guardas -añadió don Quijote-, que estos pobres no han cometido nada contra vosotros. Allá se lo haya cada uno con su pecado; Dios hay en el cielo, que no se descuida de castigar al malo ni de premiar al bueno, y no es bien que los hombres honrados sean verdugos de los otros hombres, no yéndoles nada en ello. Pido esto con esta mansedumbre y sosiego, porque tenga, si lo cumplís, algo que agradeceros; y, cuando de grado no lo hagáis, esta lanza y esta espada, con el valor de mi brazo, harán que lo hagáis por fuerza. -¡Donosa majadería! -respondió el comisario- ¡Bueno está el donaire con que ha salido a cabo de rato! ¡Los forzados del rey quiere que le dejemos, como si tuviéramos autoridad para soltarlos o él la tuviera para mandárnoslo! Váyase vuestra merced, señor, norabuena, su camino adelante, y enderécese ese bacín que trae en la cabeza, y no ande buscando tres pies al gato. -¡Vos sois el gato, y el rato, y el bellaco! -respondió don Quijote. Y, diciendo y haciendo, arremetió con él tan presto que, sin que tuviese lugar de ponerse en defensa, dio con él en el suelo, malherido de una lanzada; y avínole bien, que éste era el de la escopeta. Las demás guardas quedaron atónitas y suspensas del no esperado acontecimiento; pero, volviendo sobre sí, pusieron mano a sus espadas los de a caballo, y los de a pie a sus dardos, y arremetieron a don Quijote, que con mucho sosiego los aguardaba; y, sin duda, lo pasara mal si los galeotes, viendo la ocasión que se les ofrecía de alcanzar libertad, no la procuraran, procurando romper la cadena donde venían ensartados. Fue la revuelta de manera que las guardas, ya por acudir a los galeotes, que se desataban, ya por acometer a don Quijote, que los acometía, no hicieron cosa que fuese de provecho. Ayudó Sancho, por su parte, a la soltura de Ginés de Pasamonte, que fue el primero que saltó en la campaña libre y desembarazado, y, arremetiendo al comisario caído, le quitó la espada y la escopeta, con la cual, apuntando al uno y señalando al otro, sin disparalla jamás, no quedó guarda en todo el campo, porque se fueron huyendo, así de la escopeta de Pasamonte como de las muchas pedradas que los ya sueltos galeotes les tiraban. Entristecióse mucho Sancho deste suceso, porque se le representó que los que iban huyendo habían de dar noticia del caso a la Santa Hermandad, la cual, a campana herida, saldría a buscar los delincuentes, y así se lo dijo a su amo, y le rogó que luego de allí se partiesen y se emboscasen en la sierra, que estaba cerca. -Bien está eso -dijo don Quijote-, pero yo sé lo que ahora conviene que se haga. Y, llamando a todos los galeotes, que andaban alborotados y habían despojado al comisario hasta dejarle en cueros, se le pusieron todos a la redonda para ver lo que les mandaba, y así les dijo: -De gente bien nacida es agradecer los beneficios que reciben, y uno de los pecados que más a Dios ofende es la ingratitud. Dígolo porque ya habéis visto, señores, con manifiesta experiencia, el que de mí habéis recebido; en pago del cual querría, y es mi voluntad, que, cargados de esa cadena que quité de vuestros cuellos, luego os pongáis en camino y vais a la ciudad del Toboso, y allí os presentéis ante la señora Dulcinea del Toboso y le digáis que su caballero, el de la Triste Figura, se le envía a encomendar, y le contéis, punto por punto, todos los que ha tenido esta famosa aventura hasta poneros en la deseada libertad; y, hecho esto, os podréis ir donde quisiéredes a la buena ventura. Respondió por todos Ginés de Pasamonte, y dijo: -Lo que vuestra merced nos manda, señor y libertador nuestro, es imposible de toda imposibilidad cumplirlo, porque no podemos ir juntos por los caminos, sino solos y divididos, y cada uno por su parte, procurando meterse en las entrañas de la tierra, por no ser hallado de la Santa Hermandad, que, sin duda alguna, ha de salir en nuestra busca. Lo que vuestra merced puede hacer, y es justo que haga, es mudar ese servicio y montazgo de la señora Dulcinea del Toboso en alguna cantidad de avemarías y credos, que nosotros diremos por la intención de vuestra merced; y ésta es cosa que se podrá cumplir de noche y de día, huyendo o reposando, en paz o en guerra; pero pensar que hemos de volver ahora a las ollas de Egipto, digo, a tomar nuestra cadena y a ponernos en camino del Toboso, es pensar que es ahora de noche, que aún no son las diez del día, y es pedir a nosotros eso como pedir peras al olmo. -Pues ¡voto a tal! -dijo don Quijote, ya puesto en cólera-, don hijo de la puta, don Ginesillo de Paropillo, o como os llamáis, que habéis de ir vos solo, rabo entre piernas, con toda la cadena a cuestas. Pasamonte, que no era nada bien sufrido, estando ya enterado que don Quijote no era muy cuerdo, pues tal disparate había cometido como el de querer darles libertad, viéndose tratar de aquella manera, hizo del ojo a los compañeros, y, apartándose aparte, comenzaron a llover tantas piedras sobre don Quijote, que no se daba manos a cubrirse con la rodela; y el pobre de Rocinante no hacía más caso de la espuela que si fuera hecho de bronce. Sancho se puso tras su asno, y con él se defendía de la nube y pedrisco que sobre entrambos llovía. No se pudo escudar tan bien don Quijote que no le acertasen no sé cuántos guijarros en el cuerpo, con tanta fuerza que dieron con él en el suelo; y apenas hubo caído, cuando fue sobre él el estudiante y le quitó la bacía de la cabeza, y diole con ella tres o cuatro golpes en las espaldas y otros tantos en la tierra, con que la hizo pedazos. Quitáronle una ropilla que traía sobre las armas, y las medias calzas le querían quitar si las grebas no lo estorbaran. A Sancho le quitaron el gabán, y, dejándole en pelota, repartiendo entre sí los demás despojos de la batalla, se fueron cada uno por su parte, con más cuidado de escaparse de la Hermandad, que temían, que de cargarse de la cadena e ir a presentarse ante la señora Dulcinea del Toboso. Solos quedaron jumento y Rocinante, Sancho y Don Quijote; el jumento, cabizbajo y pensativo, sacudiendo de cuando en cuando las orejas, pensando que aún no había cesado la borrasca de las piedras, que le perseguían los oídos; Rocinante, tendido junto a su amo, que también vino al suelo de otra pedrada; Sancho, en pelota y temeroso de la Santa Hermandad; don Quijote, mohinísimo de verse tan malparado por los mismos a quien tanto bien había hecho. Capítulo XXIII. De lo que le aconteció al famoso don Quijote en Sierra Morena, que fue una de las más raras aventuras que en esta verdadera historia se cuentan Viéndose tan malparado don Quijote, dijo a su escudero: -Siempre, Sancho, lo he oído decir, que el hacer bien a villanos es echar agua en la mar. Si yo hubiera creído lo que me dijiste, yo hubiera escusado esta pesadumbre; pero ya está hecho: paciencia, y escarmentar para desde aquí adelante. -Así escarmentará vuestra merced -respondió Sancho- como yo soy turco; pero, pues dice que si me hubiera creído se hubiera escusado este daño, créame ahora y escusará otro mayor; porque le hago saber que con la Santa Hermandad no hay usar de caballerías, que no se le da a ella por cuantos caballeros andantes hay dos maravedís; y sepa que ya me parece que sus saetas me zumban por los oídos. -Naturalmente eres cobarde, Sancho -dijo don Quijote-, pero, porque no digas que soy contumaz y que jamás hago lo que me aconsejas, por esta vez quiero tomar tu consejo y apartarme de la furia que tanto temes; mas ha de ser con una condición: que jamás, en vida ni en muerte, has de decir a nadie que yo me retiré y aparté deste peligro de miedo, sino por complacer a tus ruegos; que si otra cosa dijeres, mentirás en ello, y desde ahora para entonces, y desde entonces para ahora, te desmiento, y digo que mientes y mentirás todas las veces que lo pensares o lo dijeres. Y no me repliques más, que en sólo pensar que me aparto y retiro de algún peligro, especialmente déste, que parece que lleva algún es no es de sombra de miedo, estoy ya para quedarme, y para aguardar aquí solo, no solamente a la Santa Hermandad que dices y temes, sino a los hermanos de los doce tribus de Israel, y a los siete Macabeos, y a Cástor y a Pólux, y aun a todos los hermanos y hermandades que hay en el mundo. -Señor -respondió Sancho-, que el retirar no es huir, ni el esperar es cordura, cuando el peligro sobrepuja a la esperanza, y de sabios es guardarse hoy para mañana y no aventurarse todo en un día. Y sepa que, aunque zafio y villano, todavía se me alcanza algo desto que llaman buen gobierno; así que, no se arrepienta de haber tomado mi consejo, sino suba en Rocinante, si puede, o si no yo le ayudaré, y sígame, que el caletre me dice que hemos menester ahora más los pies que las manos. Subió don Quijote, sin replicarle más palabra, y, guiando Sancho sobre su asno, se entraron por una parte de Sierra Morena, que allí junto estaba, llevando Sancho intención de atravesarla toda e ir a salir al Viso, o a Almodóvar del Campo, y esconderse algunos días por aquellas asperezas, por no ser hallados si la Hermandad los buscase. Animóle a esto haber visto que de la refriega de los galeotes se había escapado libre la despensa que sobre su asno venía, cosa que la juzgó a milagro, según fue lo que llevaron y buscaron los galeotes. Así como don Quijote entró por aquellas montañas, se le alegró el corazón, pareciéndole aquellos lugares acomodados para las aventuras que buscaba. Reducíansele a la memoria los maravillosos acaecimientos que en semejantes soledades y asperezas habían sucedido a caballeros andantes. Iba pensando en estas cosas, tan embebecido y trasportado en ellas que de ninguna otra se acordaba. Ni Sancho llevaba otro cuidado -después que le pareció que caminaba por parte segura- sino de satisfacer su estómago con los relieves que del despojo clerical habían quedado; y así, iba tras su amo sentado a la mujeriega sobre su jumento, sacando de un costal y embaulando en su panza; y no se le diera por hallar otra ventura, entretanto que iba de aquella manera, un ardite. En esto, alzó los ojos y vio que su amo estaba parado, procurando con la punta del lanzón alzar no sé qué bulto que estaba caído en el suelo, por lo cual se dio priesa a llegar a ayudarle si fuese menester; y cuando llegó fue a tiempo que alzaba con la punta del lanzón un cojín y una maleta asida a él, medio podridos, o podridos del todo, y deshechos; mas, pesaba tanto, que fue necesario que Sancho se apease a tomarlos, y mandóle su amo que viese lo que en la maleta venía. Hízolo con mucha presteza Sancho, y, aunque la maleta venía cerrada con una cadena y su candado, por lo roto y podrido della vio lo que en ella había, que eran cuatro camisas de delgada holanda y otras cosas de lienzo, no menos curiosas que limpias, y en un pañizuelo halló un buen montoncillo de escudos de oro; y, así como los vio, dijo: -¡Bendito sea todo el cielo, que nos ha deparado una aventura que sea de provecho! Y buscando más, halló un librillo de memoria, ricamente guarnecido. Éste le pidió don Quijote, y mandóle que guardase el dinero y lo tomase para él. Besóle las manos Sancho por la merced, y, desvalijando a la valija de su lencería, la puso en el costal de la despensa. Todo lo cual visto por don Quijote, dijo: -Paréceme, Sancho, y no es posible que sea otra cosa, que algún caminante descaminado debió de pasar por esta sierra, y, salteándole malandrines, le debieron de matar, y le trujeron a enterrar en esta tan escondida parte. -No puede ser eso -respondió Sancho-, porque si fueran ladrones, no se dejaran aquí este dinero. -Verdad dices -dijo don Quijote-, y así, no adivino ni doy en lo que esto pueda ser; mas, espérate: veremos si en este librillo de memoria hay alguna cosa escrita por donde podamos rastrear y venir en conocimiento de lo que deseamos. Abrióle, y lo primero que halló en él escrito, como en borrador, aunque de muy buena letra, fue un soneto, que, leyéndole alto porque Sancho también lo oyese, vio que decía desta manera: O le falta al Amor conocimiento, o le sobra crueldad, o no es mi pena igual a la ocasión que me condena al género más duro de tormento. Pero si Amor es dios, es argumento que nada ignora, y es razón muy buena que un dios no sea cruel. Pues, ¿quién ordena el terrible dolor que adoro y siento? Si digo que sois vos, Fili, no acierto; que tanto mal en tanto bien no cabe, ni me viene del cielo esta rüina. Presto habré de morir, que es lo más cierto; que al mal de quien la causa no se sabe milagro es acertar la medicina. -Por esa trova -dijo Sancho- no se puede saber nada, si ya no es que por ese hilo que está ahí se saque el ovillo de todo. -¿Qué hilo está aquí? -dijo don Quijote. -Paréceme -dijo Sancho- que vuestra merced nombró ahí hilo. -No dije sino Fili -respondió don Quijote-, y éste, sin duda, es el nombre de la dama de quien se queja el autor deste soneto; y a fe que debe de ser razonable poeta, o yo sé poco del arte. -Luego, ¿también -dijo Sancho- se le entiende a vuestra merced de trovas? -Y más de lo que tú piensas -respondió don Quijote-, y veráslo cuando lleves una carta, escrita en verso de arriba abajo, a mi señora Dulcinea del Toboso. Porque quiero que sepas, Sancho, que todos o los más caballeros andantes de la edad pasada eran grandes trovadores y grandes músicos; que estas dos habilidades, o gracias, por mejor decir, son anexas a los enamorados andantes. Verdad es que las coplas de los pasados caballeros tienen más de espíritu que de primor. -Lea más vuestra merced -dijo Sancho-, que ya hallará algo que nos satisfaga. Volvió la hoja don Quijote y dijo: -Esto es prosa, y parece carta. -¿Carta misiva, señor? -preguntó Sancho. -En el principio no parece sino de amores -respondió don Quijote. -Pues lea vuestra merced alto -dijo Sancho-, que gusto mucho destas cosas de amores. -Que me place -dijo don Quijote. Y, leyéndola alto, como Sancho se lo había rogado, vio que decía desta manera: Tu falsa promesa y mi cierta desventura me llevan a parte donde antes volverán a tus oídos las nuevas de mi muerte que las razones de mis quejas. Desechásteme, ¡oh ingrata!, por quien tiene más, no por quien vale más que yo; mas si la virtud fuera riqueza que se estimara, no envidiara yo dichas ajenas ni llorara desdichas propias. Lo que levantó tu hermosura han derribado tus obras: por ella entendí que eras ángel, y por ellas conozco que eres mujer. Quédate en paz, causadora de mi guerra, y haga el cielo que los engaños de tu esposo estén siempre encubiertos, porque tú no quedes arrepentida de lo que heciste y yo no tome venganza de lo que no deseo. Acabando de leer la carta, dijo don Quijote: -Menos por ésta que por los versos se puede sacar más de que quien la escribió es algún desdeñado amante. Y, hojeando casi todo el librillo, halló otros versos y cartas, que algunos pudo leer y otros no; pero lo que todos contenían eran quejas, lamentos, desconfianzas, sabores y sinsabores, favores y desdenes, solenizados los unos y llorados los otros. En tanto que don Quijote pasaba el libro, pasaba Sancho la maleta, sin dejar rincón en toda ella, ni en el cojín, que no buscase, escudriñase e inquiriese, ni costura que no deshiciese, ni vedija de lana que no escarmenase, porque no se quedase nada por diligencia ni mal recado: tal golosina habían despertado en él los hallados escudos, que pasaban de ciento. Y, aunque no halló mas de lo hallado, dio por bien empleados los vuelos de la manta, el vomitar del brebaje, las bendiciones de las estacas, las puñadas del arriero, la falta de las alforjas, el robo del gabán y toda la hambre, sed y cansancio que había pasado en servicio de su buen señor, pareciéndole que estaba más que rebién pagado con la merced recebida de la entrega del hallazgo. Con gran deseo quedó el Caballero de la Triste Figura de saber quién fuese el dueño de la maleta, conjeturando, por el soneto y carta, por el dinero en oro y por las tan buenas camisas, que debía de ser de algún principal enamorado, a quien desdenes y malos tratamientos de su dama debían de haber conducido a algún desesperado término. Pero, como por aquel lugar inhabitable y escabroso no parecía persona alguna de quien poder informarse, no se curó de más que de pasar adelante, sin llevar otro camino que aquel que Rocinante quería, que era por donde él podía caminar, siempre con imaginación que no podía faltar por aquellas malezas alguna estraña aventura. Yendo, pues, con este pensamiento, vio que, por cima de una montañuela que delante de los ojos se le ofrecía, iba saltando un hombre, de risco en risco y de mata en mata, con estraña ligereza. Figurósele que iba desnudo, la barba negra y espesa, los cabellos muchos y rabultados, los pies descalzos y las piernas sin cosa alguna; los muslos cubrían unos calzones, al parecer de terciopelo leonado, mas tan hechos pedazos que por muchas partes se le descubrían las carnes. Traía la cabeza descubierta, y, aunque pasó con la ligereza que se ha dicho, todas estas menudencias miró y notó el Caballero de la Triste Figura; y, aunque lo procuró, no pudo seguille, porque no era dado a la debilidad de Rocinante andar por aquellas asperezas, y más siendo él de suyo pisacorto y flemático. Luego imaginó don Quijote que aquél era el dueño del cojín y de la maleta, y propuso en sí de buscalle, aunque supiese andar un año por aquellas montañas hasta hallarle; y así, mandó a Sancho que se apease del asno y atajase por la una parte de la montaña, que él iría por la otra y podría ser que topasen, con esta diligencia, con aquel hombre que con tanta priesa se les había quitado de delante. -No podré hacer eso -respondió Sancho-, porque, en apartándome de vuestra merced, luego es conmigo el miedo, que me asalta con mil géneros de sobresaltos y visiones. Y sírvale esto que digo de aviso, para que de aquí adelante no me aparte un dedo de su presencia. -Así será -dijo el de la Triste Figura-, y yo estoy muy contento de que te quieras valer de mi ánimo, el cual no te ha de faltar, aunque te falte el ánima del cuerpo. Y vente ahora tras mí poco a poco, o como pudieres, y haz de los ojos lanternas; rodearemos esta serrezuela: quizá toparemos con aquel hombre que vimos, el cual, sin duda alguna, no es otro que el dueño de nuestro hallazgo. A lo que Sancho respondió: -Harto mejor sería no buscalle, porque si le hallamos y acaso fuese el dueño del dinero, claro está que lo tengo de restituir; y así, fuera mejor, sin hacer esta inútil diligencia, poseerlo yo con buena fe hasta que, por otra vía menos curiosa y diligente, pareciera su verdadero señor; y quizá fuera a tiempo que lo hubiera gastado, y entonces el rey me hacía franco. -Engáñaste en eso, Sancho -respondió don Quijote-; que, ya que hemos caído en sospecha de quién es el dueño, cuasi delante, estamos obligados a buscarle y volvérselos; y, cuando no le buscásemos, la vehemente sospecha que tenemos de que él lo sea nos pone ya en tanta culpa como si lo fuese. Así que, Sancho amigo, no te dé pena el buscalle, por la que a mí se me quitará si le hallo. Y así, picó a Rocinante, y siguióle Sancho con su acostumbrado jumento; y, habiendo rodeado parte de la montaña, hallaron en un arroyo, caída, muerta y medio comida de perros y picada de grajos, una mula ensillada y enfrenada; todo lo cual confirmó en ellos más la sospecha de que aquel que huía era el dueño de la mula y del cojín. Estándola mirando, oyeron un silbo como de pastor que guardaba ganado, y a deshora, a su siniestra mano, parecieron una buena cantidad de cabras, y tras ellas, por cima de la montaña, pareció el cabrero que las guardaba, que era un hombre anciano. Diole voces don Quijote, y rogóle que bajase donde estaban. Él respondió a gritos que quién les había traído por aquel lugar, pocas o ningunas veces pisado sino de pies de cabras o de lobos y otras fieras que por allí andaban. Respondióle Sancho que bajase, que de todo le darían buena cuenta. Bajó el cabrero, y, en llegando adonde don Quijote estaba, dijo: -Apostaré que está mirando la mula de alquiler que está muerta en esa hondonada. Pues a buena fe que ha ya seis meses que está en ese lugar. Díganme: ¿han topado por ahí a su dueño? -No hemos topado a nadie -respondió don Quijote-, sino a un cojín y a una maletilla que no lejos deste lugar hallamos. -También la hallé yo -respondió el cabrero-, mas nunca la quise alzar ni llegar a ella, temeroso de algún desmán y de que no me la pidiesen por de hurto; que es el diablo sotil, y debajo de los pies se levanta allombre cosa donde tropiece y caya, sin saber cómo ni cómo no. -Eso mesmo es lo que yo digo -respondió Sancho-: que también la hallé yo, y no quise llegar a ella con un tiro de piedra; allí la dejé y allí se queda como se estaba, que no quiero perro con cencerro. -Decidme, buen hombre -dijo don Quijote-, ¿sabéis vos quién sea el dueño destas prendas? -Lo que sabré yo decir -dijo el cabrero- es que «habrá al pie de seis meses, poco más a menos, que llegó a una majada de pastores, que estará como tres leguas deste lugar, un mancebo de gentil talle y apostura, caballero sobre esa mesma mula que ahí está muerta, y con el mesmo cojín y maleta que decís que hallastes y no tocastes. Preguntónos que cuál parte desta sierra era la más áspera y escondida; dijímosle que era esta donde ahora estamos; y es ansí la verdad, porque si entráis media legua más adentro, quizá no acertaréis a salir; y estoy maravillado de cómo habéis podido llegar aquí, porque no hay camino ni senda que a este lugar encamine. Digo, pues, que, en oyendo nuestra respuesta el mancebo, volvió las riendas y encaminó hacia el lugar donde le señalamos, dejándonos a todos contentos de su buen talle, y admirados de su demanda y de la priesa con que le víamos caminar y volverse hacia la sierra; y desde entonces nunca más le vimos, hasta que desde allí a algunos días salió al camino a uno de nuestros pastores, y, sin decille nada, se llegó a él y le dio muchas puñadas y coces, y luego se fue a la borrica del hato y le quitó cuanto pan y queso en ella traía; y, con estraña ligereza, hecho esto, se volvió a emboscar en la sierra. Como esto supimos algunos cabreros, le anduvimos a buscar casi dos días por lo más cerrado desta sierra, al cabo de los cuales le hallamos metido en el hueco de un grueso y valiente alcornoque. Salió a nosotros con mucha mansedumbre, ya roto el vestido, y el rostro disfigurado y tostado del sol, de tal suerte que apenas le conocíamos, sino que los vestidos, aunque rotos, con la noticia que dellos teníamos, nos dieron a entender que era el que buscábamos. Saludónos cortésmente, y en pocas y muy buenas razones nos dijo que no nos maravillásemos de verle andar de aquella suerte, porque así le convenía para cumplir cierta penitencia que por sus muchos pecados le había sido impuesta. Rogámosle que nos dijese quién era, mas nunca lo pudimos acabar con él. Pedímosle también que, cuando hubiese menester el sustento, sin el cual no podía pasar, nos dijese dónde le hallaríamos, porque con mucho amor y cuidado se lo llevaríamos; y que si esto tampoco fuese de su gusto, que, a lo menos, saliese a pedirlo, y no a quitarlo a los pastores. Agradeció nuestro ofrecimiento, pidió perdón de los asaltos pasados, y ofreció de pedillo de allí adelante por amor de Dios, sin dar molestia alguna a nadie. En cuanto lo que tocaba a la estancia de su habitación, dijo que no tenía otra que aquella que le ofrecía la ocasión donde le tomaba la noche; y acabó su plática con un tan tierno llanto, que bien fuéramos de piedra los que escuchado le habíamos, si en él no le acompañáramos, considerándole cómo le habíamos visto la vez primera, y cuál le veíamos entonces. Porque, como tengo dicho, era un muy gentil y agraciado mancebo, y en sus corteses y concertadas razones mostraba ser bien nacido y muy cortesana persona; que, puesto que éramos rústicos los que le escuchábamos, su gentileza era tanta, que bastaba a darse a conocer a la mesma rusticidad. Y, estando en lo mejor de su plática, paró y enmudecióse; clavó los ojos en el suelo por un buen espacio, en el cual todos estuvimos quedos y suspensos, esperando en qué había de parar aquel embelesamiento, con no poca lástima de verlo; porque, por lo que hacía de abrir los ojos, estar fijo mirando al suelo sin mover pestaña gran rato, y otras veces cerrarlos, apretando los labios y enarcando las cejas, fácilmente conocimos que algún accidente de locura le había sobrevenido. Mas él nos dio a entender presto ser verdad lo que pensábamos, porque se levantó con gran furia del suelo, donde se había echado, y arremetió con el primero que halló junto a sí, con tal denuedo y rabia que, si no se le quitáramos, le matara a puñadas y a bocados; y todo esto hacía, diciendo: ''¡Ah, fementido Fernando! ¡Aquí, aquí me pagarás la sinrazón que me heciste: estas manos te sacarán el corazón, donde albergan y tienen manida todas las maldades juntas, principalmente la fraude y el engaño!'' Y a éstas añadía otras razones, que todas se encaminaban a decir mal de aquel Fernando y a tacharle de traidor y fementido. Quitámossele, pues, con no poca pesadumbre, y él, sin decir más palabra, se apartó de nosotros y se emboscó corriendo por entre estos jarales y malezas, de modo que nos imposibilitó el seguille. Por esto conjeturamos que la locura le venía a tiempos, y que alguno que se llamaba Fernando le debía de haber hecho alguna mala obra, tan pesada cuanto lo mostraba el término a que le había conducido. Todo lo cual se ha confirmado después acá con las veces, que han sido muchas, que él ha salido al camino, unas a pedir a los pastores le den de lo que llevan para comer y otras a quitárselo por fuerza; porque cuando está con el accidente de la locura, aunque los pastores se lo ofrezcan de buen grado, no lo admite, sino que lo toma a puñadas; y cuando está en su seso, lo pide por amor de Dios, cortés y comedidamente, y rinde por ello muchas gracias, y no con falta de lágrimas. Y en verdad os digo, señores -prosiguió el cabrero-, que ayer determinamos yo y cuatro zagales, los dos criados y los dos amigos míos, de buscarle hasta tanto que le hallemos, y, después de hallado, ya por fuerza ya por grado, le hemos de llevar a la villa de Almodóvar, que está de aquí ocho leguas, y allí le curaremos, si es que su mal tiene cura, o sabremos quién es cuando esté en sus seso, y si tiene parientes a quien dar noticia de su desgracia». Esto es, señores, lo que sabré deciros de lo que me habéis preguntado; y entended que el dueño de las prendas que hallastes es el mesmo que vistes pasar con tanta ligereza como desnudez -que ya le había dicho don Quijote cómo había visto pasar aquel hombre saltando por la sierra. El cual quedó admirado de lo que al cabrero había oído, y quedó con más deseo de saber quién era el desdichado loco; y propuso en sí lo mesmo que ya tenía pensado: de buscalle por toda la montaña, sin dejar rincón ni cueva en ella que no mirase, hasta hallarle. Pero hízolo mejor la suerte de lo que él pensaba ni esperaba, porque en aquel mesmo instante pareció, por entre una quebrada de una sierra que salía donde ellos estaban, el mancebo que buscaba, el cual venía hablando entre sí cosas que no podían ser entendidas de cerca, cuanto más de lejos. Su traje era cual se ha pintado, sólo que, llegando cerca, vio don Quijote que un coleto hecho pedazos que sobre sí traía era de ámbar; por donde acabó de entender que persona que tales hábitos traía no debía de ser de ínfima calidad. En llegando el mancebo a ellos, les saludó con una voz desentonada y bronca, pero con mucha cortesía. Don Quijote le volvió las saludes con no menos comedimiento, y, apeándose de Rocinante, con gentil continente y donaire, le fue a abrazar y le tuvo un buen espacio estrechamente entre sus brazos, como si de luengos tiempos le hubiera conocido. El otro, a quien podemos llamar el Roto de la Mala Figura -como a don Quijote el de la Triste-, después de haberse dejado abrazar, le apartó un poco de sí, y, puestas sus manos en los hombros de don Quijote, le estuvo mirando, como que quería ver si le conocía; no menos admirado quizá de ver la figura, talle y armas de don Quijote, que don Quijote lo estaba de verle a él. En resolución, el primero que habló después del abrazamiento fue el Roto, y dijo lo que se dirá adelante. Capítulo XXIV. Donde se prosigue la aventura de la Sierra Morena Dice la historia que era grandísima la atención con que don Quijote escuchaba al astroso Caballero de la Sierra, el cual, prosiguiendo su plática, dijo: -Por cierto, señor, quienquiera que seáis, que yo no os conozco, yo os agradezco las muestras y la cortesía que conmigo habéis usado; y quisiera yo hallarme en términos que con más que la voluntad pudiera servir la que habéis mostrado tenerme en el buen acogimiento que me habéis hecho, mas no quiere mi suerte darme otra cosa con que corresponda a las buenas obras que me hacen, que buenos deseos de satisfacerlas. -Los que yo tengo -respondió don Quijote- son de serviros; tanto, que tenía determinado de no salir destas sierras hasta hallaros y saber de vos si el dolor que en la estrañeza de vuestra vida mostráis tener se podía hallar algún género de remedio; y si fuera menester buscarle, buscarle con la diligencia posible. Y, cuando vuestra desventura fuera de aquellas que tienen cerradas las puertas a todo género de consuelo, pensaba ayudaros a llorarla y plañirla como mejor pudiera, que todavía es consuelo en las desgracias hallar quien se duela dellas. Y, si es que mi buen intento merece ser agradecido con algún género de cortesía, yo os suplico, señor, por la mucha que veo que en vos se encierra, y juntamente os conjuro por la cosa que en esta vida más habéis amado o amáis, que me digáis quién sois y la causa que os ha traído a vivir y a morir entre estas soledades como bruto animal, pues moráis entre ellos tan ajeno de vos mismo cual lo muestra vuestro traje y persona. Y juro -añadió don Quijote-, por la orden de caballería que recebí, aunque indigno y pecador, y por la profesión de caballero andante, que si en esto, señor, me complacéis, de serviros con las veras a que me obliga el ser quien soy: ora remediando vuestra desgracia, si tiene remedio, ora ayudándoos a llorarla, como os lo he prometido. El Caballero del Bosque, que de tal manera oyó hablar al de la Triste Figura, no hacía sino mirarle, y remirarle y tornarle a mirar de arriba abajo; y, después que le hubo bien mirado, le dijo: -Si tienen algo que darme a comer, por amor de Dios que me lo den; que, después de haber comido, yo haré todo lo que se me manda, en agradecimiento de tan buenos deseos como aquí se me han mostrado. Luego sacaron, Sancho de su costal y el cabrero de su zurrón, con que satisfizo el Roto su hambre, comiendo lo que le dieron como persona atontada, tan apriesa que no daba espacio de un bocado al otro, pues antes los engullía que tragaba; y, en tanto que comía, ni él ni los que le miraban hablaban palabra. Como acabó de comer, les hizo de señas que le siguiesen, como lo hicieron, y él los llevó a un verde pradecillo que a la vuelta de una peña poco desviada de allí estaba. En llegando a él se tendió en el suelo, encima de la yerba, y los demás hicieron lo mismo; y todo esto sin que ninguno hablase, hasta que el Roto, después de haberse acomodado en su asiento, dijo: -Si gustáis, señores, que os diga en breves razones la inmensidad de mis desventuras, habéisme de prometer de que con ninguna pregunta, ni otra cosa, no interromperéis el hilo de mi triste historia; porque en el punto que lo hagáis, en ése se quedará lo que fuere contando. Estas razones del Roto trujeron a la memoria a don Quijote el cuento que le había contado su escudero, cuando no acertó el número de las cabras que habían pasado el río y se quedó la historia pendiente. Pero, volviendo al Roto, prosiguió diciendo: -Esta prevención que hago es porque querría pasar brevemente por el cuento de mis desgracias; que el traerlas a la memoria no me sirve de otra cosa que añadir otras de nuevo, y, mientras menos me preguntáredes, más presto acabaré yo de decillas, puesto que no dejaré por contar cosa alguna que sea de importancia para no satisfacer del todo a vuestro deseo. Don Quijote se lo prometió, en nombre de los demás, y él, con este seguro, comenzó desta manera: -«Mi nombre es Cardenio; mi patria, una ciudad de las mejores desta Andalucía; mi linaje, noble; mis padres, ricos; mi desventura, tanta que la deben de haber llorado mis padres y sentido mi linaje, sin poderla aliviar con su riqueza; que para remediar desdichas del cielo poco suelen valer los bienes de fortuna. Vivía en esta mesma tierra un cielo, donde puso el amor toda la gloria que yo acertara a desearme: tal es la hermosura de Luscinda, doncella tan noble y tan rica como yo, pero de más ventura y de menos firmeza de la que a mis honrados pensamientos se debía. A esta Luscinda amé, quise y adoré desde mis tiernos y primeros años, y ella me quiso a mí con aquella sencillez y buen ánimo que su poca edad permitía. Sabían nuestros padres nuestros intentos, y no les pesaba dello, porque bien veían que, cuando pasaran adelante, no podían tener otro fin que el de casarnos, cosa que casi la concertaba la igualdad de nuestro linaje y riquezas. Creció la edad, y con ella el amor de entrambos, que al padre de Luscinda le pareció que por buenos respetos estaba obligado a negarme la entrada de su casa, casi imitando en esto a los padres de aquella Tisbe tan decantada de los poetas. Y fue esta negación añadir llama a llama y deseo a deseo, porque, aunque pusieron silencio a las lenguas, no le pudieron poner a las plumas, las cuales, con más libertad que las lenguas, suelen dar a entender a quien quieren lo que en el alma está encerrado; que muchas veces la presencia de la cosa amada turba y enmudece la intención más determinada y la lengua más atrevida. ¡Ay cielos, y cuántos billetes le escribí! ¡Cuán regaladas y honestas respuestas tuve! ¡Cuántas canciones compuse y cuántos enamorados versos, donde el alma declaraba y trasladaba sus sentimientos, pintaba sus encendidos deseos, entretenía sus memorias y recreaba su voluntad! »En efeto, viéndome apurado, y que mi alma se consumía con el deseo de verla, determiné poner por obra y acabar en un punto lo que me pareció que más convenía para salir con mi deseado y merecido premio; y fue el pedírsela a su padre por legítima esposa, como lo hice; a lo que él me respondió que me agradecía la voluntad que mostraba de honralle, y de querer honrarme con prendas suyas, pero que, siendo mi padre vivo, a él tocaba de justo derecho hacer aquella demanda; porque, si no fuese con mucha voluntad y gusto suyo, no era Luscinda mujer para tomarse ni darse a hurto. »Yo le agradecí su buen intento, pareciéndome que llevaba razón en lo que decía, y que mi padre vendría en ello como yo se lo dijese; y con este intento, luego en aquel mismo instante, fui a decirle a mi padre lo que deseaba. Y, al tiempo que entré en un aposento donde estaba, le hallé con una carta abierta en la mano, la cual, antes que yo le dijese palabra, me la dio y me dijo: ''Por esa carta verás, Cardenio, la voluntad que el duque Ricardo tiene de hacerte merced''.» Este duque Ricardo, como ya vosotros, señores, debéis de saber, es un grande de España que tiene su estado en lo mejor desta Andalucía. «Tomé y leí la carta, la cual venía tan encarecida que a mí mesmo me pareció mal si mi padre dejaba de cumplir lo que en ella se le pedía, que era que me enviase luego donde él estaba; que quería que fuese compañero, no criado, de su hijo el mayor, y que él tomaba a cargo el ponerme en estado que correspondiese a la estimación en que me tenía. Leí la carta y enmudecí leyéndola, y más cuando oí que mi padre me decía: ''De aquí a dos días te partirás, Cardenio, a hacer la voluntad del duque; y da gracias a Dios que te va abriendo camino por donde alcances lo que yo sé que mereces''. Añadió a éstas otras razones de padre consejero. »Llegóse el término de mi partida, hablé una noche a Luscinda, díjele todo lo que pasaba, y lo mesmo hice a su padre, suplicándole se entretuviese algunos días y dilatase el darle estado hasta que yo viese lo que Ricardo me quería. Él me lo prometió y ella me lo confirmó con mil juramentos y mil desmayos. Vine, en fin, donde el duque Ricardo estaba. Fui dél tan bien recebido y tratado, que desde luego comenzó la envidia a hacer su oficio, teniéndomela los criados antiguos, pareciéndoles que las muestras que el duque daba de hacerme merced habían de ser en perjuicio suyo. Pero el que más se holgó con mi ida fue un hijo segundo del duque, llamado Fernando, mozo gallardo, gentilhombre, liberal y enamorado, el cual, en poco tiempo, quiso que fuese tan su amigo, que daba que decir a todos; y, aunque el mayor me quería bien y me hacía merced, no llegó al estremo con que don Fernando me quería y trataba. »Es, pues, el caso que, como entre los amigos no hay cosa secreta que no se comunique, y la privanza que yo tenía con don Fernando dejada de serlo por ser amistad, todos sus pensamientos me declaraba, especialmente uno enamorado, que le traía con un poco de desasosiego. Quería bien a una labradora, vasalla de su padre (y ella los tenía muy ricos), y era tan hermosa, recatada, discreta y honesta que nadie que la conocía se determinaba en cuál destas cosas tuviese más excelencia ni más se aventajase. Estas tan buenas partes de la hermosa labradora redujeron a tal término los deseos de don Fernando, que se determinó, para poder alcanzarlo y conquistar la entereza de la labradora, darle palabra de ser su esposo, porque de otra manera era procurar lo imposible. Yo, obligado de su amistad, con las mejores razones que supe y con los más vivos ejemplos que pude, procuré estorbarle y apartarle de tal propósito. Pero, viendo que no aprovechaba, determiné de decirle el caso al duque Ricardo, su padre. Mas don Fernando, como astuto y discreto, se receló y temió desto, por parecerle que estaba yo obligado, en vez de buen criado, no tener encubierta cosa que tan en perjuicio de la honra de mi señor el duque venía; y así, por divertirme y engañarme, me dijo que no hallaba otro mejor remedio para poder apartar de la memoria la hermosura que tan sujeto le tenía, que el ausentarse por algunos meses; y que quería que el ausencia fuese que los dos nos viniésemos en casa de mi padre, con ocasión que darían al duque que venía a ver y a feriar unos muy buenos caballos que en mi ciudad había, que es madre de los mejores del mundo. »Apenas le oí yo decir esto, cuando, movido de mi afición, aunque su determinación no fuera tan buena, la aprobara yo por una de las más acertadas que se podían imaginar, por ver cuán buena ocasión y coyuntura se me ofrecía de volver a ver a mi Luscinda. Con este pensamiento y deseo, aprobé su parecer y esforcé su propósito, diciéndole que lo pusiese por obra con la brevedad posible, porque, en efeto, la ausencia hacía su oficio, a pesar de los más firmes pensamientos. Ya cuando él me vino a decir esto, según después se supo, había gozado a la labradora con título de esposo, y esperaba ocasión de descubrirse a su salvo, temeroso de lo que el duque su padre haría cuando supiese su disparate. »Sucedió, pues, que, como el amor en los mozos, por la mayor parte, no lo es, sino apetito, el cual, como tiene por último fin el deleite, en llegando a alcanzarle se acaba y ha de volver atrás aquello que parecía amor, porque no puede pasar adelante del término que le puso naturaleza, el cual término no le puso a lo que es verdadero amor...; quiero decir que, así como don Fernando gozó a la labradora, se le aplacaron sus deseos y se resfriaron sus ahíncos; y si primero fingía quererse ausentar, por remediarlos, ahora de veras procuraba irse, por no ponerlos en ejecución. Diole el duque licencia, y mandóme que le acompañase. Venimos a mi ciudad, recibióle mi padre como quien era; vi yo luego a Luscinda, tornaron a vivir, aunque no habían estado muertos ni amortiguados, mis deseos, de los cuales di cuenta, por mi mal, a don Fernando, por parecerme que, en la ley de la mucha amistad que mostraba, no le debía encubrir nada. Alabéle la hermosura, donaire y discreción de Luscinda de tal manera, que mis alabanzas movieron en él los deseos de querer ver doncella de tantas buenas partes adornada. Cumplíselos yo, por mi corta suerte, enseñándosela una noche, a la luz de una vela, por una ventana por donde los dos solíamos hablarnos. Viola en sayo, tal, que todas las bellezas hasta entonces por él vistas las puso en olvido. Enmudeció, perdió el sentido, quedó absorto y, finalmente, tan enamorado cual lo veréis en el discurso del cuento de mi desventura. Y, para encenderle más el deseo, que a mí me celaba y al cielo a solas descubría, quiso la fortuna que hallase un día un billete suyo pidiéndome que la pidiese a su padre por esposa, tan discreto, tan honesto y tan enamorado que, en leyéndolo, me dijo que en sola Luscinda se encerraban todas las gracias de hermosura y de entendimiento que en las demás mujeres del mundo estaban repartidas. »Bien es verdad que quiero confesar ahora que, puesto que yo veía con cuán justas causas don Fernando a Luscinda alababa, me pesaba de oír aquellas alabanzas de su boca, y comencé a temer y a recelarme dél, porque no se pasaba momento donde no quisiese que tratásemos de Luscinda, y él movía la plática, aunque la trujese por los cabellos; cosa que despertaba en mí un no sé qué de celos, no porque yo temiese revés alguno de la bondad y de la fe de Luscinda, pero, con todo eso, me hacía temer mi suerte lo mesmo que ella me aseguraba. Procuraba siempre don Fernando leer los papeles que yo a Luscinda enviaba y los que ella me respondía, a título que de la discreción de los dos gustaba mucho. Acaeció, pues, que, habiéndome pedido Luscinda un libro de caballerías en que leer, de quien era ella muy aficionada, que era el de Amadís de Gaula...» No hubo bien oído don Quijote nombrar libro de caballerías, cuando dijo: -Con que me dijera vuestra merced, al principio de su historia, que su merced de la señora Luscinda era aficionada a libros de caballerías, no fuera menester otra exageración para darme a entender la alteza de su entendimiento, porque no le tuviera tan bueno como vos, señor, le habéis pintado, si careciera del gusto de tan sabrosa leyenda: así que, para conmigo, no es menester gastar más palabras en declararme su hermosura, valor y entendimiento; que, con sólo haber entendido su afición, la confirmo por la más hermosa y más discreta mujer del mundo. Y quisiera yo, señor, que vuestra merced le hubiera enviado junto con Amadís de Gaula al bueno de Don Rugel de Grecia, que yo sé que gustara la señora Luscinda mucho de Daraida y Geraya, y de las discreciones del pastor Darinel y de aquellos admirables versos de sus bucólicas, cantadas y representadas por él con todo donaire, discreción y desenvoltura. Pero tiempo podrá venir en que se enmiende esa falta, y no dura más en hacerse la enmienda de cuanto quiera vuestra merced ser servido de venirse conmigo a mi aldea, que allí le podré dar más de trecientos libros, que son el regalo de mi alma y el entretenimiento de mi vida; aunque tengo para mí que ya no tengo ninguno, merced a la malicia de malos y envidiosos encantadores. Y perdóneme vuestra merced el haber contravenido a lo que prometimos de no interromper su plática, pues, en oyendo cosas de caballerías y de caballeros andantes, así es en mi mano dejar de hablar en ellos, como lo es en la de los rayos del sol dejar de calentar, ni humedecer en los de la luna. Así que, perdón y proseguir, que es lo que ahora hace más al caso. En tanto que don Quijote estaba diciendo lo que queda dicho, se le había caído a Cardenio la cabeza sobre el pecho, dando muestras de estar profundamente pensativo. Y, puesto que dos veces le dijo don Quijote que prosiguiese su historia, ni alzaba la cabeza ni respondía palabra; pero, al cabo de un buen espacio, la levantó y dijo: -No se me puede quitar del pensamiento, ni habrá quien me lo quite en el mundo, ni quien me dé a entender otra cosa (y sería un majadero el que lo contrario entendiese o creyese), sino que aquel bellaconazo del maestro Elisabat estaba amancebado con la reina Madésima. -Eso no, ¡voto a tal! -respondió con mucha cólera don Quijote (y arrojóle, como tenía de costumbre)-; y ésa es una muy gran malicia, o bellaquería, por mejor decir: la reina Madásima fue muy principal señora, y no se ha de presumir que tan alta princesa se había de amancebar con un sacapotras; y quien lo contrario entendiere, miente como muy gran bellaco. Y yo se lo daré a entender, a pie o a caballo, armado o desarmado, de noche o de día, o como más gusto le diere. Estábale mirando Cardenio muy atentamente, al cual ya había venido el accidente de su locura y no estaba para proseguir su historia; ni tampoco don Quijote se la oyera, según le había disgustado lo que de Madásima le había oído. ¡Estraño caso; que así volvió por ella como si verdaderamente fuera su verdadera y natural señora: tal le tenían sus descomulgados libros! Digo, pues, que, como ya Cardenio estaba loco y se oyó tratar de mentís y de bellaco, con otros denuestos semejantes, parecióle mal la burla, y alzó un guijarro que halló junto a sí, y dio con él en los pechos tal golpe a don Quijote que le hizo caer de espaldas. Sancho Panza, que de tal modo vio parar a su señor, arremetió al loco con el puño cerrado; y el Roto le recibió de tal suerte que con una puñada dio con él a sus pies, y luego se subió sobre él y le brumó las costillas muy a su sabor. El cabrero, que le quiso defender, corrió el mesmo peligro. Y, después que los tuvo a todos rendidos y molidos, los dejó y se fue, con gentil sosiego, a emboscarse en la montaña. Levantóse Sancho, y, con la rabia que tenía de verse aporreado tan sin merecerlo, acudió a tomar la venganza del cabrero, diciéndole que él tenía la culpa de no haberles avisado que a aquel hombre le tomaba a tiempos la locura; que, si esto supieran, hubieran estado sobre aviso para poderse guardar. Respondió el cabrero que ya lo había dicho, y que si él no lo había oído, que no era suya la culpa. Replicó Sancho Panza, y tornó a replicar el cabrero, y fue el fin de las réplicas asirse de las barbas y darse tales puñadas que, si don Quijote no los pusiera en paz, se hicieran pedazos. Decía Sancho, asido con el cabrero: -Déjeme vuestra merced, señor Caballero de la Triste Figura, que en éste, que es villano como yo y no está armado caballero, bien puedo a mi salvo satisfacerme del agravio que me ha hecho, peleando con él mano a mano, como hombre honrado. -Así es -dijo don Quijote-, pero yo sé que él no tiene ninguna culpa de lo sucedido. Con esto los apaciguó, y don Quijote volvió a preguntar al cabrero si sería posible hallar a Cardenio, porque quedaba con grandísimo deseo de saber el fin de su historia. Díjole el cabrero lo que primero le había dicho, que era no saber de cierto su manida; pero que, si anduviese mucho por aquellos contornos, no dejaría de hallarle, o cuerdo o loco. Capítulo XXV. Que trata de las estrañas cosas que en Sierra Morena sucedieron al valiente caballero de la Mancha, y de la imitación que hizo a la penitencia de Beltenebros Despidióse del cabrero don Quijote, y, subiendo otra vez sobre Rocinante, mandó a Sancho que le siguiese, el cual lo hizo, con su jumento, de muy mala gana. Ãbanse poco a poco entrando en lo más áspero de la montaña, y Sancho iba muerto por razonar con su amo, y deseaba que él comenzase la plática, por no contravenir a lo que le tenía mandado; mas, no pudiendo sufrir tanto silencio, le dijo: -Señor don Quijote, vuestra merced me eche su bendición y me dé licencia; que desde aquí me quiero volver a mi casa, y a mi mujer y a mis hijos, con los cuales, por lo menos, hablaré y departiré todo lo que quisiere; porque querer vuestra merced que vaya con él por estas soledades, de día y de noche, y que no le hable cuando me diere gusto es enterrarme en vida. Si ya quisiera la suerte que los animales hablaran, como hablaban en tiempos de Guisopete, fuera menos mal, porque departiera yo con mi jumento lo que me viniera en gana, y con esto pasara mi mala ventura; que es recia cosa, y que no se puede llevar en paciencia, andar buscando aventuras toda la vida y no hallar sino coces y manteamientos, ladrillazos y puñadas, y, con todo esto, nos hemos de coser la boca, sin osar decir lo que el hombre tiene en su corazón, como si fuera mudo. -Ya te entiendo, Sancho -respondió don Quijote-: tú mueres porque te alce el entredicho que te tengo puesto en la lengua. Dale por alzado y di lo que quisieres, con condición que no ha de durar este alzamiento más de en cuanto anduviéremos por estas sierras. -Sea ansí -dijo Sancho-: hable yo ahora, que después Dios sabe lo que será; y, comenzando a gozar de ese salvoconduto, digo que ¿qué le iba a vuestra merced en volver tanto por aquella reina Magimasa, o como se llama? O, ¿qué hacía al caso que aquel abad fuese su amigo o no? Que, si vuestra merced pasara con ello, pues no era su juez, bien creo yo que el loco pasara adelante con su historia, y se hubieran ahorrado el golpe del guijarro, y las coces, y aun más de seis torniscones. -A fe, Sancho -respondió don Quijote-, que si tú supieras, como yo lo sé, cuán honrada y cuán principal señora era la reina Madásima, yo sé que dijeras que tuve mucha paciencia, pues no quebré la boca por donde tales blasfemias salieron; porque es muy gran blasfemia decir ni pensar que una reina esté amancebada con un cirujano. La verdad del cuento es que aquel maestro Elisabat, que el loco dijo, fue un hombre muy prudente y de muy sanos consejos, y sirvió de ayo y de médico a la reina; pero pensar que ella era su amiga es disparate digno de muy gran castigo. Y, porque veas que Cardenio no supo lo que dijo, has de advertir que cuando lo dijo ya estaba sin juicio. -Eso digo yo -dijo Sancho-: que no había para qué hacer cuenta de las palabras de un loco, porque si la buena suerte no ayudara a vuestra merced y encaminara el guijarro a la cabeza, como le encaminó al pecho, buenos quedáramos por haber vuelto por aquella mi señora, que Dios cohonda. Pues, ¡montas que no se librara Cardenio por loco! -Contra cuerdos y contra locos está obligado cualquier caballero andante a volver por la honra de las mujeres, cualesquiera que sean, cuanto más por las reinas de tan alta guisa y pro como fue la reina Madásima, a quien yo tengo particular afición por sus buenas partes; porque, fuera de haber sido fermosa, además fue muy prudente y muy sufrida en sus calamidades, que las tuvo muchas; y los consejos y compañía del maestro Elisabat le fue y le fueron de mucho provecho y alivio para poder llevar sus trabajos con prudencia y paciencia. Y de aquí tomó ocasión el vulgo ignorante y mal intencionado de decir y pensar que ella era su manceba; y mienten, digo otra vez, y mentirán otras docientas, todos los que tal pensaren y dijeren. -Ni yo lo digo ni lo pienso -respondió Sancho-: allá se lo hayan; con su pan se lo coman. Si fueron amancebados, o no, a Dios habrán dado la cuenta. De mis viñas vengo, no sé nada; no soy amigo de saber vidas ajenas; que el que compra y miente, en su bolsa lo siente. Cuanto más, que desnudo nací, desnudo me hallo: ni pierdo ni gano; mas que lo fuesen, ¿qué me va a mí? Y muchos piensan que hay tocinos y no hay estacas. Mas, ¿quién puede poner puertas al campo? Cuanto más, que de Dios dijeron. -¡Válame Dios -dijo don Quijote-, y qué de necedades vas, Sancho, ensartando! ¿Qué va de lo que tratamos a los refranes que enhilas? Por tu vida, Sancho, que calles; y de aquí adelante, entremétete en espolear a tu asno, y deja de hacello en lo que no te importa. Y entiende con todos tus cinco sentidos que todo cuanto yo he hecho, hago e hiciere, va muy puesto en razón y muy conforme a las reglas de caballería, que las sé mejor que cuantos caballeros las profesaron en el mundo. -Señor -respondió Sancho-, y ¿es buena regla de caballería que andemos perdidos por estas montañas, sin senda ni camino, buscando a un loco, el cual, después de hallado, quizá le vendrá en voluntad de acabar lo que dejó comenzado, no de su cuento, sino de la cabeza de vuestra merced y de mis costillas, acabándonoslas de romper de todo punto? -Calla, te digo otra vez, Sancho -dijo don Quijote-; porque te hago saber que no sólo me trae por estas partes el deseo de hallar al loco, cuanto el que tengo de hacer en ellas una hazaña con que he de ganar perpetuo nombre y fama en todo lo descubierto de la tierra; y será tal, que he de echar con ella el sello a todo aquello que puede hacer perfecto y famoso a un andante caballero. -Y ¿es de muy gran peligro esa hazaña? -preguntó Sancho Panza. -No -respondió el de la Triste Figura-, puesto que de tal manera podía correr el dado, que echásemos azar en lugar de encuentro; pero todo ha de estar en tu diligencia. -¿En mi diligencia? -dijo Sancho. -Sí -dijo don Quijote-, porque si vuelves presto de adonde pienso enviarte, presto se acabará mi pena y presto comenzará mi gloria. Y, porque no es bien que te tenga más suspenso, esperando en lo que han de parar mis razones, quiero, Sancho, que sepas que el famoso Amadís de Gaula fue uno de los más perfectos caballeros andantes. No he dicho bien fue uno: fue el solo, el primero, el único, el señor de todos cuantos hubo en su tiempo en el mundo. Mal año y mal mes para don Belianís y para todos aquellos que dijeren que se le igualó en algo, porque se engañan, juro cierto. Digo asimismo que, cuando algún pintor quiere salir famoso en su arte, procura imitar los originales de los más únicos pintores que sabe; y esta mesma regla corre por todos los más oficios o ejercicios de cuenta que sirven para adorno de las repúblicas. Y así lo ha de hacer y hace el que quiere alcanzar nombre de prudente y sufrido, imitando a Ulises, en cuya persona y trabajos nos pinta Homero un retrato vivo de prudencia y de sufrimiento; como también nos mostró Virgilio, en persona de Eneas, el valor de un hijo piadoso y la sagacidad de un valiente y entendido capitán, no pintándolo ni descubriéndolo como ellos fueron, sino como habían de ser, para quedar ejemplo a los venideros hombres de sus virtudes. Desta mesma suerte, Amadís fue el norte, el lucero, el sol de los valientes y enamorados caballeros, a quien debemos de imitar todos aquellos que debajo de la bandera de amor y de la caballería militamos. Siendo, pues, esto ansí, como lo es, hallo yo, Sancho amigo, que el caballero andante que más le imitare estará más cerca de alcanzar la perfeción de la caballería. Y una de las cosas en que más este caballero mostró su prudencia, valor, valentía, sufrimiento, firmeza y amor, fue cuando se retiró, desdeñado de la señora Oriana, a hacer penitencia en la Peña Pobre, mudado su nombre en el de Beltenebros, nombre, por cierto, significativo y proprio para la vida que él de su voluntad había escogido. Ansí que, me es a mí más fácil imitarle en esto que no en hender gigantes, descabezar serpientes, matar endriagos, desbaratar ejércitos, fracasar armadas y deshacer encantamentos. Y, pues estos lugares son tan acomodados para semejantes efectos, no hay para qué se deje pasar la ocasión, que ahora con tanta comodidad me ofrece sus guedejas. -En efecto -dijo Sancho-, ¿qué es lo que vuestra merced quiere hacer en este tan remoto lugar? -¿Ya no te he dicho -respondió don Quijote- que quiero imitar a Amadís, haciendo aquí del desesperado, del sandio y del furioso, por imitar juntamente al valiente don Roldán, cuando halló en una fuente las señales de que Angélica la Bella había cometido vileza con Medoro, de cuya pesadumbre se volvió loco y arrancó los árboles, enturbió las aguas de las claras fuentes, mató pastores, destruyó ganados, abrasó chozas, derribó casas, arrastró yeguas y hizo otras cien mil insolencias, dignas de eterno nombre y escritura? Y, puesto que yo no pienso imitar a Roldán, o Orlando, o Rotolando (que todos estos tres nombres tenía), parte por parte en todas las locuras que hizo, dijo y pensó, haré el bosquejo, como mejor pudiere, en las que me pareciere ser más esenciales. Y podrá ser que viniese a contentarme con sola la imitación de Amadís, que sin hacer locuras de daño, sino de lloros y sentimientos, alcanzó tanta fama como el que más. -Paréceme a mí -dijo Sancho- que los caballeros que lo tal ficieron fueron provocados y tuvieron causa para hacer esas necedades y penitencias, pero vuestra merced, ¿qué causa tiene para volverse loco? ¿Qué dama le ha desdeñado, o qué señales ha hallado que le den a entender que la señora Dulcinea del Toboso ha hecho alguna niñería con moro o cristiano? -Ahí esta el punto -respondió don Quijote- y ésa es la fineza de mi negocio; que volverse loco un caballero andante con causa, ni grado ni gracias: el toque está desatinar sin ocasión y dar a entender a mi dama que si en seco hago esto, ¿qué hiciera en mojado? Cuanto más, que harta ocasión tengo en la larga ausencia que he hecho de la siempre señora mía Dulcinea del Toboso; que, como ya oíste decir a aquel pastor de marras, Ambrosio: quien está ausente todos los males tiene y teme. Así que, Sancho amigo, no gastes tiempo en aconsejarme que deje tan rara, tan felice y tan no vista imitación. Loco soy, loco he de ser hasta tanto que tú vuelvas con la respuesta de una carta que contigo pienso enviar a mi señora Dulcinea; y si fuere tal cual a mi fe se le debe, acabarse ha mi sandez y mi penitencia; y si fuere al contrario, seré loco de veras, y, siéndolo, no sentiré nada. Ansí que, de cualquiera manera que responda, saldré del conflito y trabajo en que me dejares, gozando el bien que me trujeres, por cuerdo, o no sintiendo el mal que me aportares, por loco. Pero dime, Sancho, ¿traes bien guardado el yelmo de Mambrino?; que ya vi que le alzaste del suelo cuando aquel desagradecido le quiso hacer pedazos. Pero no pudo, donde se puede echar de ver la fineza de su temple. A lo cual respondió Sancho: -Vive Dios, señor Caballero de la Triste Figura, que no puedo sufrir ni llevar en paciencia algunas cosas que vuestra merced dice, y que por ellas vengo a imaginar que todo cuanto me dice de caballerías y de alcanzar reinos e imperios, de dar ínsulas y de hacer otras mercedes y grandezas, como es uso de caballeros andantes, que todo debe de ser cosa de viento y mentira, y todo pastraña, o patraña, o como lo llamáremos. Porque quien oyere decir a vuestra merced que una bacía de barbero es el yelmo de Mambrino, y que no salga de este error en más de cuatro días, ¿qué ha de pensar, sino que quien tal dice y afirma debe de tener güero el juicio? La bacía yo la llevo en el costal, toda abollada, y llévola para aderezarla en mi casa y hacerme la barba en ella, si Dios me diere tanta gracia que algún día me vea con mi mujer y hijos. -Mira, Sancho, por el mismo que denantes juraste, te juro -dijo don Quijote- que tienes el más corto entendimiento que tiene ni tuvo escudero en el mundo. ¿Que es posible que en cuanto ha que andas conmigo no has echado de ver que todas las cosas de los caballeros andantes parecen quimeras, necedades y desatinos, y que son todas hechas al revés? Y no porque sea ello ansí, sino porque andan entre nosotros siempre una caterva de encantadores que todas nuestras cosas mudan y truecan y les vuelven según su gusto, y según tienen la gana de favorecernos o destruirnos; y así, eso que a ti te parece bacía de barbero, me parece a mí el yelmo de Mambrino, y a otro le parecerá otra cosa. Y fue rara providencia del sabio que es de mi parte hacer que parezca bacía a todos lo que real y verdaderamente es yelmo de Mambrino, a causa que, siendo él de tanta estima, todo el mundo me perseguirá por quitármele; pero, como ven que no es más de un bacín de barbero, no se curan de procuralle, como se mostró bien en el que quiso rompelle y le dejó en el suelo sin llevarle; que a fe que si le conociera, que nunca él le dejara. Guárdale, amigo, que por ahora no le he menester; que antes me tengo de quitar todas estas armas y quedar desnudo como cuando nací, si es que me da en voluntad de seguir en mi penitencia más a Roldán que a Amadís. Llegaron, en estas pláticas, al pie de una alta montaña que, casi como peñón tajado, estaba sola entre otras muchas que la rodeaban. Corría por su falda un manso arroyuelo, y hacíase por toda su redondez un prado tan verde y vicioso, que daba contento a los ojos que le miraban. Había por allí muchos árboles silvestres y algunas plantas y flores, que hacían el lugar apacible. Este sitio escogió el Caballero de la Triste Figura para hacer su penitencia; y así, en viéndole, comenzó a decir en voz alta, como si estuviera sin juicio: -Éste es el lugar, ¡oh cielos!, que diputo y escojo para llorar la desventura en que vosotros mesmos me habéis puesto. Éste es el sitio donde el humor de mis ojos acrecentará las aguas deste pequeño arroyo, y mis continos y profundos sospiros moverán a la contina las hojas destos montaraces árboles, en testimonio y señal de la pena que mi asendereado corazón padece. ¡Oh vosotros, quienquiera que seáis, rústicos dioses que en este inhabitable lugar tenéis vuestra morada, oíd las quejas deste desdichado amante, a quien una luenga ausencia y unos imaginados celos han traído a lamentarse entre estas asperezas, y a quejarse de la dura condición de aquella ingrata y bella, término y fin de toda humana hermosura! ¡Oh vosotras, napeas y dríadas, que tenéis por costumbre de habitar en las espesuras de los montes, así los ligeros y lascivos sátiros, de quien sois, aunque en vano, amadas, no perturben jamás vuestro dulce sosiego, que me ayudéis a lamentar mi desventura, o, a lo menos, no os canséis de oílla! ¡Oh Dulcinea del Toboso, día de mi noche, gloria de mi pena, norte de mis caminos, estrella de mi ventura, así el cielo te la dé buena en cuanto acertares a pedirle, que consideres el lugar y el estado a que tu ausencia me ha conducido, y que con buen término correspondas al que a mi fe se le debe! ¡Oh solitarios árboles, que desde hoy en adelante habéis de hacer compañía a mi soledad, dad indicio, con el blando movimiento de vuestras ramas, que no os desagrade mi presencia! ¡Oh tú, escudero mío, agradable compañero en más prósperos y adversos sucesos, toma bien en la memoria lo que aquí me verás hacer, para que lo cuentes y recetes a la causa total de todo ello! Y, diciendo esto, se apeó de Rocinante, y en un momento le quitó el freno y la silla; y, dándole una palmada en las ancas, le dijo: -Libertad te da el que sin ella queda, ¡oh caballo tan estremado por tus obras cuan desdichado por tu suerte! Vete por do quisieres, que en la frente llevas escrito que no te igualó en ligereza el Hipogrifo de Astolfo, ni el nombrado Frontino, que tan caro le costó a Bradamante. Viendo esto Sancho, dijo: -Bien haya quien nos quitó ahora del trabajo de desenalbardar al rucio; que a fe que no faltaran palmadicas que dalle, ni cosas que decille en su alabanza; pero si él aquí estuviera, no consintiera yo que nadie le desalbardara, pues no había para qué, que a él no le tocaban las generales de enamorado ni de desesperado, pues no lo estaba su amo, que era yo, cuando Dios quería. Y en verdad, señor Caballero de la Triste Figura, que si es que mi partida y su locura de vuestra merced va de veras, que será bien tornar a ensillar a Rocinante, para que supla la falta del rucio, porque será ahorrar tiempo a mi ida y vuelta; que si la hago a pie, no sé cuándo llegaré ni cuándo volveré, porque, en resolución, soy mal caminante. -Digo, Sancho -respondió don Quijote-, que sea como tú quisieres, que no me parece mal tu designio; y digo que de aquí a tres días te partirás, porque quiero que en este tiempo veas lo que por ella hago y digo, para que se lo digas. -Pues, ¿qué más tengo de ver -dijo Sancho- que lo que he visto? -¡Bien estás en el cuento! -respondió don Quijote-. Ahora me falta rasgar las vestiduras, esparcir las armas y darme de calabazadas por estas peñas, con otras cosas deste jaez que te han de admirar. -Por amor de Dios -dijo Sancho-, que mire vuestra merced cómo se da esas calabazadas; que a tal peña podrá llegar, y en tal punto, que con la primera se acabase la máquina desta penitencia; y sería yo de parecer que, ya que vuestra merced le parece que son aquí necesarias calabazadas y que no se puede hacer esta obra sin ellas, se contentase, pues todo esto es fingido y cosa contrahecha y de burla, se contentase, digo, con dárselas en el agua, o en alguna cosa blanda, como algodón; y déjeme a mí el cargo, que yo diré a mi señora que vuestra merced se las daba en una punta de peña más dura que la de un diamante. -Yo agradezco tu buena intención, amigo Sancho -respondió don Quijote-, mas quiérote hacer sabidor de que todas estas cosas que hago no son de burlas, sino muy de veras; porque de otra manera, sería contravenir a las órdenes de caballería, que nos mandan que no digamos mentira alguna, pena de relasos, y el hacer una cosa por otra lo mesmo es que mentir. Ansí que, mis calabazadas han de ser verdaderas, firmes y valederas, sin que lleven nada del sofístico ni del fantástico. Y será necesario que me dejes algunas hilas para curarme, pues que la ventura quiso que nos faltase el bálsamo que perdimos. -Más fue perder el asno -respondió Sancho-, pues se perdieron en él las hilas y todo. Y ruégole a vuestra merced que no se acuerde más de aquel maldito brebaje; que en sólo oírle mentar se me revuelve el alma, no que el estómago. Y más le ruego: que haga cuenta que son ya pasados los tres días que me ha dado de término para ver las locuras que hace, que ya las doy por vistas y por pasadas en cosa juzgada, y diré maravillas a mi señora; y escriba la carta y despácheme luego, porque tengo gran deseo de volver a sacar a vuestra merced deste purgatorio donde le dejo. -¿Purgatorio le llamas, Sancho? -dijo don Quijote-. Mejor hicieras de llamarle infierno, y aun peor, si hay otra cosa que lo sea. -Quien ha infierno -respondió Sancho-, nula es retencio, según he oído decir. -No entiendo qué quiere decir retencio -dijo don Quijote. -Retencio es -respondió Sancho- que quien está en el infierno nunca sale dél, ni puede. Lo cual será al revés en vuestra merced, o a mí me andarán mal los pies, si es que llevo espuelas para avivar a Rocinante; y póngame yo una por una en el Toboso, y delante de mi señora Dulcinea, que yo le diré tales cosas de las necedades y locuras, que todo es uno, que vuestra merced ha hecho y queda haciendo, que la venga a poner más blanda que un guante, aunque la halle más dura que un alcornoque; con cuya respuesta dulce y melificada volveré por los aires, como brujo, y sacaré a vuestra merced deste purgatorio, que parece infierno y no lo es, pues hay esperanza de salir dél, la cual, como tengo dicho, no la tienen de salir los que están en el infierno, ni creo que vuestra merced dirá otra cosa. -Así es la verdad -dijo el de la Triste Figura-; pero, ¿qué haremos para escribir la carta? -Y la libranza pollinesca también -añadió Sancho. -Todo irá inserto -dijo don Quijote-; y sería bueno, ya que no hay papel, que la escribiésemos, como hacían los antiguos, en hojas de árboles, o en unas tablitas de cera; aunque tan dificultoso será hallarse eso ahora como el papel. Mas ya me ha venido a la memoria dónde será bien, y aun más que bien, escribilla: que es en el librillo de memoria que fue de Cardenio; y tú tendrás cuidado de hacerla trasladar en papel, de buena letra, en el primer lugar que hallares, donde haya maestro de escuela de muchachos, o si no, cualquiera sacristán te la trasladará; y no se la des a trasladar a ningún escribano, que hacen letra procesada, que no la entenderá Satanás. -Pues, ¿qué se ha de hacer de la firma? -dijo Sancho. -Nunca las cartas de Amadís se firman -respondió don Quijote. -Está bien -respondió Sancho-, pero la libranza forzosamente se ha de firmar, y ésa, si se traslada, dirán que la firma es falsa y quedaréme sin pollinos. -La libranza irá en el mesmo librillo firmada; que, en viéndola, mi sobrina no pondrá dificultad en cumplilla. Y, en lo que toca a la carta de amores, pondrás por firma: "Vuestro hasta la muerte, el Caballero de la Triste Figura". Y hará poco al caso que vaya de mano ajena, porque, a lo que yo me sé acordar, Dulcinea no sabe escribir ni leer, y en toda su vida ha visto letra mía ni carta mía, porque mis amores y los suyos han sido siempre platónicos, sin estenderse a más que a un honesto mirar. Y aun esto tan de cuando en cuando, que osaré jurar con verdad que en doce años que ha que la quiero más que a la lumbre destos ojos que han de comer la tierra, no la he visto cuatro veces; y aun podrá ser que destas cuatro veces no hubiese ella echado de ver la una que la miraba: tal es el recato y encerramiento con que sus padres, Lorenzo Corchuelo, y su madre, Aldonza Nogales, la han criado. -¡Ta, ta! -dijo Sancho-. ¿Que la hija de Lorenzo Corchuelo es la señora Dulcinea del Toboso, llamada por otro nombre Aldonza Lorenzo? -Ésa es -dijo don Quijote-, y es la que merece ser señora de todo el universo. -Bien la conozco -dijo Sancho-, y sé decir que tira tan bien una barra como el más forzudo zagal de todo el pueblo. ¡Vive el Dador, que es moza de chapa, hecha y derecha y de pelo en pecho, y que puede sacar la barba del lodo a cualquier caballero andante, o por andar, que la tuviere por señora! ¡Oh hideputa, qué rejo que tiene, y qué voz! Sé decir que se puso un día encima del campanario del aldea a llamar unos zagales suyos que andaban en un barbecho de su padre, y, aunque estaban de allí más de media legua, así la oyeron como si estuvieran al pie de la torre. Y lo mejor que tiene es que no es nada melindrosa, porque tiene mucho de cortesana: con todos se burla y de todo hace mueca y donaire. Ahora digo, señor Caballero de la Triste Figura, que no solamente puede y debe vuestra merced hacer locuras por ella, sino que, con justo título, puede desesperarse y ahorcarse; que nadie habrá que lo sepa que no diga que hizo demasiado de bien, puesto que le lleve el diablo. Y querría ya verme en camino, sólo por vella; que ha muchos días que no la veo, y debe de estar ya trocada, porque gasta mucho la faz de las mujeres andar siempre al campo, al sol y al aire. Y confieso a vuestra merced una verdad, señor don Quijote: que hasta aquí he estado en una grande ignorancia; que pensaba bien y fielmente que la señora Dulcinea debía de ser alguna princesa de quien vuestra merced estaba enamorado, o alguna persona tal, que mereciese los ricos presentes que vuestra merced le ha enviado: así el del vizcaíno como el de los galeotes, y otros muchos que deben ser, según deben de ser muchas las vitorias que vuestra merced ha ganado y ganó en el tiempo que yo aún no era su escudero. Pero, bien considerado, ¿qué se le ha de dar a la señora Aldonza Lorenzo, digo, a la señora Dulcinea del Toboso, de que se le vayan a hincar de rodillas delante della los vencidos que vuestra merced le envía y ha de enviar? Porque podría ser que, al tiempo que ellos llegasen, estuviese ella rastrillando lino, o trillando en las eras, y ellos se corriesen de verla, y ella se riese y enfadase del presente. -Ya te tengo dicho antes de agora muchas veces, Sancho -dijo don Quijote-, que eres muy grande hablador, y que, aunque de ingenio boto, muchas veces despuntas de agudo. Mas, para que veas cuán necio eres tú y cuán discreto soy yo, quiero que me oyas un breve cuento. «Has de saber que una viuda hermosa, moza, libre y rica, y, sobre todo, desenfadada, se enamoró de un mozo motilón, rollizo y de buen tomo. Alcanzólo a saber su mayor, y un día dijo a la buena viuda, por vía de fraternal reprehensión: ''Maravillado estoy, señora, y no sin mucha causa, de que una mujer tan principal, tan hermosa y tan rica como vuestra merced, se haya enamorado de un hombre tan soez, tan bajo y tan idiota como fulano, habiendo en esta casa tantos maestros, tantos presentados y tantos teólogos, en quien vuestra merced pudiera escoger como entre peras, y decir: "Éste quiero, aquéste no quiero"''. Mas ella le respondió, con mucho donaire y desenvoltura: ''Vuestra merced, señor mío, está muy engañado, y piensa muy a lo antiguo si piensa que yo he escogido mal en fulano, por idiota que le parece, pues, para lo que yo le quiero, tanta filosofía sabe, y más, que Aristóteles''». Así que, Sancho, por lo que yo quiero a Dulcinea del Toboso, tanto vale como la más alta princesa de la tierra. Sí, que no todos los poetas que alaban damas, debajo de un nombre que ellos a su albedrío les ponen, es verdad que las tienen. ¿Piensas tú que las Amariles, las Filis, las Silvias, las Dianas, las Galateas, las Alidas y otras tales de que los libros, los romances, las tiendas de los barberos, los teatros de las comedias, están llenos, fueron verdaderamente damas de carne y hueso, y de aquéllos que las celebran y celebraron? No, por cierto, sino que las más se las fingen, por dar subjeto a sus versos y porque los tengan por enamorados y por hombres que tienen valor para serlo. Y así, bástame a mí pensar y creer que la buena de Aldonza Lorenzo es hermosa y honesta; y en lo del linaje importa poco, que no han de ir a hacer la información dél para darle algún hábito, y yo me hago cuenta que es la más alta princesa del mundo. Porque has de saber, Sancho, si no lo sabes, que dos cosas solas incitan a amar más que otras, que son la mucha hermosura y la buena fama; y estas dos cosas se hallan consumadamente en Dulcinea, porque en ser hermosa ninguna le iguala, y en la buena fama, pocas le llegan. Y para concluir con todo, yo imagino que todo lo que digo es así, sin que sobre ni falte nada; y píntola en mi imaginación como la deseo, así en la belleza como en la principalidad, y ni la llega Elena, ni la alcanza Lucrecia, ni otra alguna de las famosas mujeres de las edades pretéritas, griega, bárbara o latina. Y diga cada uno lo que quisiere; que si por esto fuere reprehendido de los ignorantes, no seré castigado de los rigurosos. -Digo que en todo tiene vuestra merced razón -respondió Sancho-, y que yo soy un asno. Mas no sé yo para qué nombro asno en mi boca, pues no se ha de mentar la soga en casa del ahorcado. Pero venga la carta, y a Dios, que me mudo. Sacó el libro de memoria don Quijote, y, apartándose a una parte, con mucho sosiego comenzó a escribir la carta; y, en acabándola, llamó a Sancho y le dijo que se la quería leer, porque la tomase de memoria, si acaso se le perdiese por el camino, porque de su desdicha todo se podía temer. A lo cual respondió Sancho: -Escríbala vuestra merced dos o tres veces ahí en el libro y démele, que yo le llevaré bien guardado, porque pensar que yo la he de tomar en la memoria es disparate: que la tengo tan mala que muchas veces se me olvida cómo me llamo. Pero, con todo eso, dígamela vuestra merced, que me holgaré mucho de oílla, que debe de ir como de molde. -Escucha, que así dice -dijo don Quijote: Carta de don Quijote a Dulcinea del Toboso Soberana y alta señora: El ferido de punta de ausencia y el llagado de las telas del corazón, dulcísima Dulcinea del Toboso, te envía la salud que él no tiene. Si tu fermosura me desprecia, si tu valor no es en mi pro, si tus desdenes son en mi afincamiento, maguer que yo sea asaz de sufrido, mal podré sostenerme en esta cuita, que, además de ser fuerte, es muy duradera. Mi buen escudero Sancho te dará entera relación, ¡oh bella ingrata, amada enemiga mía!, del modo que por tu causa quedo. Si gustares de acorrerme, tuyo soy; y si no, haz lo que te viniere en gusto; que, con acabar mi vida, habré satisfecho a tu crueldad y a mi deseo. Tuyo hasta la muerte, El Caballero de la Triste Figura. -Por vida de mi padre -dijo Sancho en oyendo la carta-, que es la más alta cosa que jamás he oído. ¡Pesia a mí, y cómo que le dice vuestra merced ahí todo cuanto quiere, y qué bien que encaja en la firma El Caballero de la Triste Figura! Digo de verdad que es vuestra merced el mesmo diablo, y que no haya cosa que no sepa. -Todo es menester -respondió don Quijote- para el oficio que trayo. -Ea, pues -dijo Sancho-, ponga vuestra merced en esotra vuelta la cédula de los tres pollinos y fírmela con mucha claridad, porque la conozcan en viéndola. -Que me place -dijo don Quijote. Y, habiéndola escrito,se la leyó; que decía ansí: Mandará vuestra merced, por esta primera de pollinos, señora sobrina, dar a Sancho Panza, mi escudero, tres de los cinco que dejé en casa y están a cargo de vuestra merced. Los cuales tres pollinos se los mando librar y pagar por otros tantos aquí recebidos de contado, que consta, y con su carta de pago serán bien dados. Fecha en las entrañas de Sierra Morena, a veinte y dos de agosto deste presente año. -Buena está -dijo Sancho-; fírmela vuestra merced. -No es menester firmarla -dijo don Quijote-, sino solamente poner mi rúbrica, que es lo mesmo que firma, y para tres asnos, y aun para trecientos, fuera bastante. -Yo me confío de vuestra merced -respondió Sancho-. Déjeme, iré a ensillar a Rocinante, y aparéjese vuestra merced a echarme su bendición, que luego pienso partirme, sin ver las sandeces que vuestra merced ha de hacer, que yo diré que le vi hacer tantas que no quiera más. -Por lo menos quiero, Sancho, y porque es menester ansí, quiero, digo, que me veas en cueros, y hacer una o dos docenas de locuras, que las haré en menos de media hora, porque, habiéndolas tú visto por tus ojos, puedas jurar a tu salvo en las demás que quisieres añadir; y asegúrote que no dirás tú tantas cuantas yo pienso hacer. -Por amor de Dios, señor mío, que no vea yo en cueros a vuestra merced, que me dará mucha lástima y no podré dejar de llorar; y tengo tal la cabeza, del llanto que anoche hice por el rucio, que no estoy para meterme en nuevos lloros; y si es que vuestra merced gusta de que yo vea algunas locuras, hágalas vestido, breves y las que le vinieren más a cuento. Cuanto más, que para mí no era menester nada deso, y, como ya tengo dicho, fuera ahorrar el camino de mi vuelta, que ha de ser con las nuevas que vuestra merced desea y merece. Y si no, aparéjese la señora Dulcinea; que si no responde como es razón, voto hago solene a quien puedo que le tengo de sacar la buena respuesta del estómago a coces y a bofetones. Porque, ¿dónde se ha de sufrir que un caballero andante, tan famoso como vuestra merced, se vuelva loco, sin qué ni para qué, por una...? No me lo haga decir la señora, porque por Dios que despotrique y lo eche todo a doce, aunque nunca se venda. ¡Bonico soy yo para eso! ¡Mal me conoce! ¡Pues, a fe que si me conociese, que me ayunase! -A fe, Sancho -dijo don Quijote-, que, a lo que parece, que no estás tú más cuerdo que yo. -No estoy tan loco -respondió Sancho-, mas estoy más colérico. Pero, dejando esto aparte, ¿qué es lo que ha de comer vuestra merced en tanto que yo vuelvo? ¿Ha de salir al camino, como Cardenio, a quitárselo a los pastores? -No te dé pena ese cuidado -respondió don Quijote-, porque, aunque tuviera, no comiera otra cosa que las yerbas y frutos que este prado y estos árboles me dieren, que la fineza de mi negocio está en no comer y en hacer otras asperezas equivalentes. -A Dios, pues. Pero, ¿sabe vuestra merced qué temo? Que no tengo de acertar a volver a este lugar donde agora le dejo, según está de escondido. -Toma bien las señas, que yo procuraré no apartarme destos contornos -dijo don Quijote-, y aun tendré cuidado de subirme por estos más altos riscos, por ver si te descubro cuando vuelvas. Cuanto más, que lo más acertado será, para que no me yerres y te pierdas, que cortes algunas retamas de las muchas que por aquí hay y las vayas poniendo de trecho a trecho, hasta salir a lo raso, las cuales te servirán de mojones y señales para que me halles cuando vuelvas, a imitación del hilo del laberinto de Teseo. -Así lo haré -respondió Sancho Panza. Y, cortando algunos, pidió la bendición a su señor, y, no sin muchas lágrimas de entrambos, se despidió dél. Y, subiendo sobre Rocinante, a quien don Quijote encomendó mucho, y que mirase por él como por su propria persona, se puso en camino del llano, esparciendo de trecho a trecho los ramos de la retama, como su amo se lo había aconsejado. Y así, se fue, aunque todavía le importunaba don Quijote que le viese siquiera hacer dos locuras. Mas no hubo andado cien pasos, cuando volvió y dijo: -Digo, señor, que vuestra merced ha dicho muy bien: que, para que pueda jurar sin cargo de conciencia que le he visto hacer locuras, será bien que vea siquiera una, aunque bien grande la he visto en la quedada de vuestra merced. -¿No te lo decía yo? -dijo don Quijote-. Espérate, Sancho, que en un credo las haré. Y, desnudándose con toda priesa las calzones, quedó en carnes y en pañales, y luego, sin más ni más, dio dos zapatetas en el aire y dos tumbas, la cabeza abajo y los pies en alto, descubriendo cosas que, por no verlas otra vez, volvió Sancho la rienda a Rocinante y se dio por contento y satisfecho de que podía jurar que su amo quedaba loco. Y así, le dejaremos ir su camino, hasta la vuelta, que fue breve. Capítulo XXVI. Donde se prosiguen las finezas que de enamorado hizo don Quijote en Sierra Morena Y, volviendo a contar lo que hizo el de la Triste Figura después que se vio solo, dice la historia que, así como don Quijote acabó de dar las tumbas o vueltas, de medio abajo desnudo y de medio arriba vestido, y que vio que Sancho se había ido sin querer aguardar a ver más sandeces, se subió sobre una punta de una alta peña y allí tornó a pensar lo que otras muchas veces había pensado, sin haberse jamás resuelto en ello. Y era que cuál sería mejor y le estaría más a cuento: imitar a Roldán en las locuras desaforadas que hizo, o Amadís en las malencónicas. Y, hablando entre sí mesmo, decía: -Si Roldán fue tan buen caballero y tan valiente como todos dicen, ¿qué maravilla?, pues, al fin, era encantado y no le podía matar nadie si no era metiéndole un alfiler de a blanca por la planta del pie, y él traía siempre los zapatos con siete suelas de hierro. Aunque no le valieron tretas contra Bernardo del Carpio, que se las entendió y le ahogó entre los brazos, en Roncesvalles. Pero, dejando en él lo de la valentía a una parte, vengamos a lo de perder el juicio, que es cierto que le perdió, por las señales que halló en la fontana y por las nuevas que le dio el pastor de que Angélica había dormido más de dos siestas con Medoro, un morillo de cabellos enrizados y paje de Agramante; y si él entendió que esto era verdad y que su dama le había cometido desaguisado, no hizo mucho en volverse loco. Pero yo, ¿cómo puedo imitalle en las locuras, si no le imito en la ocasión dellas? Porque mi Dulcinea del Toboso osaré yo jurar que no ha visto en todos los días de su vida moro alguno, ansí como él es, en su mismo traje, y que se está hoy como la madre que la parió; y haríale agravio manifiesto si, imaginando otra cosa della, me volviese loco de aquel género de locura de Roldán el furioso. Por otra parte, veo que Amadís de Gaula, sin perder el juicio y sin hacer locuras, alcanzó tanta fama de enamorado como el que más; porque lo que hizo, según su historia, no fue más de que, por verse desdeñado de su señora Oriana, que le había mandado que no pareciese ante su presencia hasta que fuese su voluntad, de que se retiró a la Peña Pobre en compañía de un ermitaño, y allí se hartó de llorar y de encomendarse a Dios, hasta que el cielo le acorrió, en medio de su mayor cuita y necesidad. Y si esto es verdad, como lo es, ¿para qué quiero yo tomar trabajo agora de desnudarme del todo, ni dar pesadumbre a estos árboles, que no me han hecho mal alguno? Ni tengo para qué enturbiar el agua clara destos arroyos, los cuales me han de dar de beber cuando tenga gana. Viva la memoria de Amadís, y sea imitado de don Quijote de la Mancha en todo lo que pudiere; del cual se dirá lo que del otro se dijo: que si no acabó grandes cosas, murió por acometellas; y si yo no soy desechado ni desdeñado de Dulcinea del Toboso, bástame, como ya he dicho, estar ausente della. Ea, pues, manos a la obra: venid a mi memoria, cosas de Amadís, y enseñadme por dónde tengo de comenzar a imitaros. Mas ya sé que lo más que él hizo fue rezar y encomendarse a Dios; pero, ¿qué haré de rosario, que no le tengo? En esto le vino al pensamiento cómo le haría, y fue que rasgó una gran tira de las faldas de la camisa, que andaban colgando, y diole once ñudos, el uno más gordo que los demás, y esto le sirvió de rosario el tiempo que allí estuvo, donde rezó un millón de avemarías. Y lo que le fatigaba mucho era no hallar por allí otro ermitaño que le confesase y con quien consolarse. Y así, se entretenía paseándose por el pradecillo, escribiendo y grabando por las cortezas de los árboles y por la menuda arena muchos versos, todos acomodados a su tristeza, y algunos en alabanza de Dulcinea. Mas los que se pudieron hallar enteros y que se pudiesen leer, después que a él allí le hallaron, no fueron más que estos que aquí se siguen: Ãrboles, yerbas y plantas que en aqueste sitio estáis, tan altos, verdes y tantas, si de mi mal no os holgáis, escuchad mis quejas santas. Mi dolor no os alborote, aunque más terrible sea, pues, por pagaros escote, aquí lloró don Quijote ausencias de Dulcinea del Toboso. Es aquí el lugar adonde el amador más leal de su señora se esconde, y ha venido a tanto mal sin saber cómo o por dónde. Tráele amor al estricote, que es de muy mala ralea; y así, hasta henchir un pipote, aquí lloró don Quijote ausencias de Dulcinea del Toboso. Buscando las aventuras por entre las duras peñas, maldiciendo entrañas duras, que entre riscos y entre breñas halla el triste desventuras, hirióle amor con su azote, no con su blanda correa; y, en tocándole el cogote, aquí lloró don Quijote ausencias de Dulcinea del Toboso. No causó poca risa en los que hallaron los versos referidos el añadidura del Toboso al nombre de Dulcinea, porque imaginaron que debió de imaginar don Quijote que si, en nombrando a Dulcinea, no decía también del Toboso, no se podría entender la copla; y así fue la verdad, como él después confesó. Otros muchos escribió, pero, como se ha dicho, no se pudieron sacar en limpio, ni enteros, más destas tres coplas. En esto, y en suspirar y en llamar a los faunos y silvanos de aquellos bosques, a las ninfas de los ríos, a la dolorosa y húmida Eco, que le respondiese, consolasen y escuchasen, se entretenía, y en buscar algunas yerbas con que sustentarse en tanto que Sancho volvía; que, si como tardó tres días, tardara tres semanas, el Caballero de la Triste Figura quedara tan desfigurado que no le conociera la madre que lo parió. Y será bien dejalle, envuelto entre sus suspiros y versos, por contar lo que le avino a Sancho Panza en su mandadería. Y fue que, en saliendo al camino real, se puso en busca del Toboso, y otro día llegó a la venta donde le había sucedido la desgracia de la manta; y no la hubo bien visto, cuando le pareció que otra vez andaba en los aires, y no quiso entrar dentro, aunque llegó a hora que lo pudiera y debiera hacer, por ser la del comer y llevar en deseo de gustar algo caliente; que había grandes días que todo era fiambre. Esta necesidad le forzó a que llegase junto a la venta, todavía dudoso si entraría o no. Y, estando en esto, salieron de la venta dos personas que luego le conocieron; y dijo el uno al otro: -Dígame, señor licenciado, aquel del caballo, ¿no es Sancho Panza, el que dijo el ama de nuestro aventurero que había salido con su señor por escudero? -Sí es -dijo el licenciado-; y aquél es el caballo de nuestro don Quijote. Y conociéronle tan bien como aquellos que eran el cura y el barbero de su mismo lugar, y los que hicieron el escrutinio y acto general de los libros. Los cuales, así como acabaron de conocer a Sancho Panza y a Rocinante, deseosos de saber de don Quijote, se fueron a él; y el cura le llamó por su nombre, diciéndole: -Amigo Sancho Panza, ¿adónde queda vuestro amo? Conociólos luego Sancho Panza, y determinó de encubrir el lugar y la suerte donde y como su amo quedaba; y así, les respondió que su amo quedaba ocupado en cierta parte y en cierta cosa que le era de mucha importancia, la cual él no podía descubrir, por los ojos que en la cara tenía. -No, no -dijo el barbero-, Sancho Panza; si vos no nos decís dónde queda, imaginaremos, como ya imaginamos, que vos le habéis muerto y robado, pues venís encima de su caballo. En verdad que nos habéis de dar el dueño del rocín, o sobre eso, morena. -No hay para qué conmigo amenazas, que yo no soy hombre que robo ni mato a nadie: a cada uno mate su ventura, o Dios, que le hizo. Mi amo queda haciendo penitencia en la mitad desta montaña, muy a su sabor. Y luego, de corrida y sin parar, les contó de la suerte que quedaba, las aventuras que le habían sucedido y cómo llevaba la carta a la señora Dulcinea del Toboso, que era la hija de Lorenzo Corchuelo, de quien estaba enamorado hasta los hígados. Quedaron admirados los dos de lo que Sancho Panza les contaba; y, aunque ya sabían la locura de don Quijote y el género della, siempre que la oían se admiraban de nuevo. Pidiéronle a Sancho Panza que les enseñase la carta que llevaba a la señora Dulcinea del Toboso. Él dijo que iba escrita en un libro de memoria y que era orden de su señor que la hiciese trasladar en papel en el primer lugar que llegase; a lo cual dijo el cura que se la mostrase, que él la trasladaría de muy buena letra. Metió la mano en el seno Sancho Panza, buscando el librillo, pero no le halló, ni le podía hallar si le buscara hasta agora, porque se había quedado don Quijote con él y no se le había dado, ni a él se le acordó de pedírsele. Cuando Sancho vio que no hallaba el libro, fuésele parando mortal el rostro; y, tornándose a tentar todo el cuerpo muy apriesa, tornó a echar de ver que no le hallaba; y, sin más ni más, se echó entrambos puños a las barbas y se arrancó la mitad de ellas, y luego, apriesa y sin cesar, se dio media docena de puñadas en el rostro y en las narices, que se las bañó todas en sangre. Visto lo cual por el cura y el barbero, le dijeron que qué le había sucedido, que tan mal se paraba. -¿Qué me ha de suceder -respondió Sancho-, sino el haber perdido de una mano a otra, en un estante, tres pollinos, que cada uno era como un castillo? -¿Cómo es eso? -replicó el barbero. -He perdido el libro de memoria -respondió Sancho-, donde venía carta para Dulcinea y una cédula firmada de su señor, por la cual mandaba que su sobrina me diese tres pollinos, de cuatro o cinco que estaban en casa. Y, con esto, les contó la pérdida del rucio. Consolóle el cura, y díjole que, en hallando a su señor, él le haría revalidar la manda y que tornase a hacer la libranza en papel, como era uso y costumbre, porque las que se hacían en libros de memoria jamás se acetaban ni cumplían. Con esto se consoló Sancho, y dijo que, como aquello fuese ansí, que no le daba mucha pena la pérdida de la carta de Dulcinea, porque él la sabía casi de memoria, de la cual se podría trasladar donde y cuando quisiesen. -Decildo, Sancho, pues -dijo el barbero-, que después la trasladaremos. Paróse Sancho Panza a rascar la cabeza para traer a la memoria la carta, y ya se ponía sobre un pie, y ya sobre otro; unas veces miraba al suelo, otras al cielo; y, al cabo de haberse roído la mitad de la yema de un dedo, teniendo suspensos a los que esperaban que ya la dijese, dijo al cabo de grandísimo rato: -Por Dios, señor licenciado, que los diablos lleven la cosa que de la carta se me acuerda; aunque en el principio decía: «Alta y sobajada señora». -No diría -dijo el barbero- sobajada, sino sobrehumana o soberana señora. -Así es -dijo Sancho-. Luego, si mal no me acuerdo, proseguía..., si mal no me acuerdo: «el llego y falto de sueño, y el ferido besa a vuestra merced las manos, ingrata y muy desconocida hermosa», y no sé qué decía de salud y de enfermedad que le enviaba, y por aquí iba escurriendo, hasta que acababa en «Vuestro hasta la muerte, el Caballero de la Triste Figura». No poco gustaron los dos de ver la buena memoria de Sancho Panza, y alabáronsela mucho, y le pidieron que dijese la carta otras dos veces, para que ellos, ansimesmo, la tomasen de memoria para trasladalla a su tiempo. Tornóla a decir Sancho otras tres veces, y otras tantas volvió a decir otros tres mil disparates. Tras esto, contó asimesmo las cosas de su amo, pero no habló palabra acerca del manteamiento que le había sucedido en aquella venta, en la cual rehusaba entrar. Dijo también como su señor, en trayendo que le trujese buen despacho de la señora Dulcinea del Toboso, se había de poner en camino a procurar cómo ser emperador, o, por lo menos, monarca; que así lo tenían concertado entre los dos, y era cosa muy fácil venir a serlo, según era el valor de su persona y la fuerza de su brazo; y que, en siéndolo, le había de casar a él, porque ya sería viudo, que no podía ser menos, y le había de dar por mujer a una doncella de la emperatriz, heredera de un rico y grande estado de tierra firme, sin ínsulos ni ínsulas, que ya no las quería. Decía esto Sancho con tanto reposo, limpiándose de cuando en cuando las narices, y con tan poco juicio, que los dos se admiraron de nuevo, considerando cuán vehemente había sido la locura de don Quijote, pues había llevado tras sí el juicio de aquel pobre hombre. No quisieron cansarse en sacarle del error en que estaba, pareciéndoles que, pues no le dañaba nada la conciencia, mejor era dejarle en él, y a ellos les sería de más gusto oír sus necedades. Y así, le dijeron que rogase a Dios por la salud de su señor, que cosa contingente y muy agible era venir, con el discurso del tiempo, a ser emperador, como él decía, o, por lo menos, arzobispo, o otra dignidad equivalente. A lo cual respondió Sancho: -Señores, si la fortuna rodease las cosas de manera que a mi amo le viniese en voluntad de no ser emperador, sino de ser arzobispo, querría yo saber agora qué suelen dar los arzobispos andantes a sus escuderos. -Suélenles dar -respondió el cura- algún beneficio, simple o curado, o alguna sacristanía, que les vale mucho de renta rentada, amén del pie de altar, que se suele estimar en otro tanto. -Para eso será menester -replicó Sancho- que el escudero no sea casado y que sepa ayudar a misa, por lo menos; y si esto es así, ¡desdichado de yo, que soy casado y no sé la primera letra del ABC! ¿Qué será de mí si a mi amo le da antojo de ser arzobispo, y no emperador, como es uso y costumbre de los caballeros andantes? -No tengáis pena, Sancho amigo -dijo el barbero-, que aquí rogaremos a vuestro amo y se lo aconsejaremos, y aun se lo pondremos en caso de conciencia, que sea emperador y no arzobispo, porque le será más fácil, a causa de que él es más valiente que estudiante. -Así me ha parecido a mí -respondió Sancho-, aunque sé decir que para todo tiene habilidad. Lo que yo pienso hacer de mi parte es rogarle a Nuestro Señor que le eche a aquellas partes donde él más se sirva y adonde a mí más mercedes me haga. -Vos lo decís como discreto -dijo el cura- y lo haréis como buen cristiano. Mas lo que ahora se ha de hacer es dar orden como sacar a vuestro amo de aquella inútil penitencia que decís que queda haciendo; y, para pensar el modo que hemos de tener, y para comer, que ya es hora, será bien nos entremos en esta venta. Sancho dijo que entrasen ellos, que él esperaría allí fuera y que después les diría la causa por que no entraba ni le convenía entrar en ella; mas que les rogaba que le sacasen allí algo de comer que fuese cosa caliente, y, ansimismo, cebada para Rocinante. Ellos se entraron y le dejaron, y, de allí a poco, el barbero le sacó de comer. Después, habiendo bien pensado entre los dos el modo que tendrían para conseguir lo que deseaban, vino el cura en un pensamiento muy acomodado al gusto de don Quijote y para lo que ellos querían. Y fue que dijo al barbero que lo que había pensado era que él se vestiría en hábito de doncella andante, y que él procurase ponerse lo mejor que pudiese como escudero, y que así irían adonde don Quijote estaba, fingiendo ser ella una doncella afligida y menesterosa, y le pediría un don, el cual él no podría dejársele de otorgar, como valeroso caballero andante. Y que el don que le pensaba pedir era que se viniese con ella donde ella le llevase, a desfacelle un agravio que un mal caballero le tenía fecho; y que le suplicaba, ansimesmo, que no la mandase quitar su antifaz, ni la demandase cosa de su facienda, fasta que la hubiese fecho derecho de aquel mal caballero; y que creyese, sin duda, que don Quijote vendría en todo cuanto le pidiese por este término; y que desta manera le sacarían de allí y le llevarían a su lugar, donde procurarían ver si tenía algún remedio su estraña locura. Capítulo XXVII. De cómo salieron con su intención el cura y el barbero, con otras cosas dignas de que se cuenten en esta grande historia No le pareció mal al barbero la invención del cura, sino tan bien, que luego la pusieron por obra. Pidiéronle a la ventera una saya y unas tocas, dejándole en prendas una sotana nueva del cura. El barbero hizo una gran barba de una cola rucia o roja de buey, donde el ventero tenía colgado el peine. Preguntóles la ventera que para qué le pedían aquellas cosas. El cura le contó en breves razones la locura de don Quijote, y cómo convenía aquel disfraz para sacarle de la montaña, donde a la sazón estaba. Cayeron luego el ventero y la ventera en que el loco era su huésped, el del bálsamo, y el amo del manteado escudero, y contaron al cura todo lo que con él les había pasado, sin callar lo que tanto callaba Sancho. En resolución, la ventera vistió al cura de modo que no había más que ver: púsole una saya de paño, llena de fajas de terciopelo negro de un palmo en ancho, todas acuchilladas, y unos corpiños de terciopelo verde, guarnecidos con unos ribetes de raso blanco, que se debieron de hacer, ellos y la saya, en tiempo del rey Wamba. No consintió el cura que le tocasen, sino púsose en la cabeza un birretillo de lienzo colchado que llevaba para dormir de noche, y ciñóse por la frente una liga de tafetán negro, y con otra liga hizo un antifaz, con que se cubrió muy bien las barbas y el rostro; encasquetóse su sombrero, que era tan grande que le podía servir de quitasol, y, cubriéndose su herreruelo, subió en su mula a mujeriegas, y el barbero en la suya, con su barba que le llegaba a la cintura, entre roja y blanca, como aquella que, como se ha dicho, era hecha de la cola de un buey barroso. Despidiéronse de todos, y de la buena de Maritornes, que prometió de rezar un rosario, aunque pecadora, porque Dios les diese buen suceso en tan arduo y tan cristiano negocio como era el que habían emprendido. Mas, apenas hubo salido de la venta, cuando le vino al cura un pensamiento: que hacía mal en haberse puesto de aquella manera, por ser cosa indecente que un sacerdote se pusiese así, aunque le fuese mucho en ello; y, diciéndoselo al barbero, le rogó que trocasen trajes, pues era más justo que él fuese la doncella menesterosa, y que él haría el escudero, y que así se profanaba menos su dignidad; y que si no lo quería hacer, determinaba de no pasar adelante, aunque a don Quijote se le llevase el diablo. En esto, llegó Sancho, y de ver a los dos en aquel traje no pudo tener la risa. En efeto, el barbero vino en todo aquello que el cura quiso, y, trocando la invención, el cura le fue informando el modo que había de tener y las palabras que había de decir a don Quijote para moverle y forzarle a que con él se viniese, y dejase la querencia del lugar que había escogido para su vana penitencia. El barbero respondió que, sin que se le diese lición, él lo pondría bien en su punto. No quiso vestirse por entonces, hasta que estuviesen junto de donde don Quijote estaba; y así, dobló sus vestidos, y el cura acomodó su barba, y siguieron su camino, guiándolos Sancho Panza; el cual les fue contando lo que les aconteció con el loco que hallaron en la sierra, encubriendo, empero, el hallazgo de la maleta y de cuanto en ella venía; que, maguer que tonto, era un poco codicioso el mancebo. Otro día llegaron al lugar donde Sancho había dejado puestas las señales de las ramas para acertar el lugar donde había dejado a su señor; y, en reconociéndole, les dijo como aquélla era la entrada, y que bien se podían vestir, si era que aquello hacía al caso para la libertad de su señor; porque ellos le habían dicho antes que el ir de aquella suerte y vestirse de aquel modo era toda la importancia para sacar a su amo de aquella mala vida que había escogido, y que le encargaban mucho que no dijese a su amo quien ellos eran, ni que los conocía; y que si le preguntase, como se lo había de preguntar, si dio la carta a Dulcinea, dijese que sí, y que, por no saber leer, le había respondido de palabra, diciéndole que le mandaba, so pena de la su desgracia, que luego al momento se viniese a ver con ella, que era cosa que le importaba mucho; porque con esto y con lo que ellos pensaban decirle tenían por cosa cierta reducirle a mejor vida, y hacer con él que luego se pusiese en camino para ir a ser emperador o monarca; que en lo de ser arzobispo no había de qué temer. Todo lo escuchó Sancho, y lo tomó muy bien en la memoria, y les agradeció mucho la intención que tenían de aconsejar a su señor fuese emperador y no arzobispo, porque él tenía para sí que, para hacer mercedes a sus escuderos, más podían los emperadores que los arzobispos andantes. También les dijo que sería bien que él fuese delante a buscarle y darle la respuesta de su señora, que ya sería ella bastante a sacarle de aquel lugar, sin que ellos se pusiesen en tanto trabajo. Parecióles bien lo que Sancho Panza decía, y así, determinaron de aguardarle hasta que volviese con las nuevas del hallazgo de su amo. Entróse Sancho por aquellas quebradas de la sierra, dejando a los dos en una por donde corría un pequeño y manso arroyo, a quien hacían sombra agradable y fresca otras peñas y algunos árboles que por allí estaban. El calor, y el día que allí llegaron, era de los del mes de agosto, que por aquellas partes suele ser el ardor muy grande; la hora, las tres de la tarde: todo lo cual hacía al sitio más agradable, y que convidase a que en él esperasen la vuelta de Sancho, como lo hicieron. Estando, pues, los dos allí, sosegados y a la sombra, llegó a sus oídos una voz que, sin acompañarla son de algún otro instrumento, dulce y regaladamente sonaba, de que no poco se admiraron, por parecerles que aquél no era lugar donde pudiese haber quien tan bien cantase. Porque, aunque suele decirse que por las selvas y campos se hallan pastores de voces estremadas, más son encarecimientos de poetas que verdades; y más, cuando advirtieron que lo que oían cantar eran versos, no de rústicos ganaderos, sino de discretos cortesanos. Y confirmó esta verdad haber sido los versos que oyeron éstos: ¿Quién menoscaba mis bienes? Desdenes. Y ¿quién aumenta mis duelos? Los celos. Y ¿quién prueba mi paciencia? Ausencia. De ese modo, en mi dolencia ningún remedio se alcanza, pues me matan la esperanza desdenes, celos y ausencia. ¿Quién me causa este dolor? Amor. Y ¿quién mi gloria repugna? Fortuna. Y ¿quién consiente en mi duelo? El cielo De ese modo, yo recelo morir deste mal estraño, pues se aumentan en mi daño, amor, fortuna y el cielo. ¿Quién mejorará mi suerte? La muerte. Y el bien de amor, ¿quién le alcanza? Mudanza. Y sus males, ¿quién los cura? Locura. De ese modo, no es cordura querer curar la pasión cuando los remedios son muerte, mudanza y locura. La hora, el tiempo, la soledad, la voz y la destreza del que cantaba causó admiración y contento en los dos oyentes, los cuales se estuvieron quedos, esperando si otra alguna cosa oían; pero, viendo que duraba algún tanto el silencio, determinaron de salir a buscar el músico que con tan buena voz cantaba. Y, queriéndolo poner en efeto, hizo la mesma voz que no se moviesen, la cual llegó de nuevo a sus oídos, cantando este soneto: Soneto Santa amistad, que con ligeras alas, tu apariencia quedándose en el suelo, entre benditas almas, en el cielo, subiste alegre a las impíreas salas, desde allá, cuando quieres, nos señalas la justa paz cubierta con un velo, por quien a veces se trasluce el celo de buenas obras que, a la fin, son malas. Deja el cielo, ¡oh amistad!, o no permitas que el engaño se vista tu librea, con que destruye a la intención sincera; que si tus apariencias no le quitas, presto ha de verse el mundo en la pelea de la discorde confusión primera. El canto se acabó con un profundo suspiro, y los dos, con atención, volvieron a esperar si más se cantaba; pero, viendo que la música se había vuelto en sollozos y en lastimeros ayes, acordaron de saber quién era el triste, tan estremado en la voz como doloroso en los gemidos; y no anduvieron mucho, cuando, al volver de una punta de una peña, vieron a un hombre del mismo talle y figura que Sancho Panza les había pintado cuando les contó el cuento de Cardenio; el cual hombre, cuando los vio, sin sobresaltarse, estuvo quedo, con la cabeza inclinada sobre el pecho a guisa de hombre pensativo, sin alzar los ojos a mirarlos más de la vez primera, cuando de improviso llegaron. El cura, que era hombre bien hablado (como el que ya tenía noticia de su desgracia, pues por las señas le había conocido), se llegó a él, y con breves aunque muy discretas razones le rogó y persuadió que aquella tan miserable vida dejase, porque allí no la perdiese, que era la desdicha mayor de las desdichas. Estaba Cardenio entonces en su entero juicio, libre de aquel furioso accidente que tan a menudo le sacaba de sí mismo; y así, viendo a los dos en traje tan no usado de los que por aquellas soledades andaban, no dejó de admirarse algún tanto, y más cuando oyó que le habían hablado en su negocio como en cosa sabida -porque las razones que el cura le dijo así lo dieron a entender-; y así, respondió desta manera: -Bien veo yo, señores, quienquiera que seáis, que el cielo, que tiene cuidado de socorrer a los buenos, y aun a los malos muchas veces, sin yo merecerlo, me envía, en estos tan remotos y apartados lugares del trato común de las gentes, algunas personas que, poniéndome delante de los ojos con vivas y varias razones cuán sin ella ando en hacer la vida que hago, han procurado sacarme désta a mejor parte; pero, como no saben que sé yo que en saliendo deste daño he de caer en otro mayor, quizá me deben de tener por hombre de flacos discursos, y aun, lo que peor sería, por de ningún juicio. Y no sería maravilla que así fuese, porque a mí se me trasluce que la fuerza de la imaginación de mis desgracias es tan intensa y puede tanto en mi perdición que, sin que yo pueda ser parte a estobarlo, vengo a quedar como piedra, falto de todo buen sentido y conocimiento; y vengo a caer en la cuenta desta verdad, cuando algunos me dicen y muestran señales de las cosas que he hecho en tanto que aquel terrible accidente me señorea, y no sé más que dolerme en vano y maldecir sin provecho mi ventura, y dar por disculpa de mis locuras el decir la causa dellas a cuantos oírla quieren; porque, viendo los cuerdos cuál es la causa, no se maravillarán de los efetos, y si no me dieren remedio, a lo menos no me darán culpa, convirtiéndoseles el enojo de mi desenvoltura en lástima de mis desgracias. Y si es que vosotros, señores, venís con la mesma intención que otros han venido, antes que paséis adelante en vuestras discretas persuasiones, os ruego que escuchéis el cuento, que no le tiene, de mis desventuras; porque quizá, después de entendido, ahorraréis del trabajo que tomaréis en consolar un mal que de todo consuelo es incapaz. Los dos, que no deseaban otra cosa que saber de su mesma boca la causa de su daño, le rogaron se la contase, ofreciéndole de no hacer otra cosa de la que él quisiese, en su remedio o consuelo; y con esto, el triste caballero comenzó su lastimera historia, casi por las mesmas palabras y pasos que la había contado a don Quijote y al cabrero pocos días atrás, cuando, por ocasión del maestro Elisabat y puntualidad de don Quijote en guardar el decoro a la caballería, se quedó el cuento imperfeto, como la historia lo deja contado. Pero ahora quiso la buena suerte que se detuvo el accidente de la locura y le dio lugar de contarlo hasta el fin; y así, llegando al paso del billete que había hallado don Fernando entre el libro de Amadís de Gaula, dijo Cardenio que le tenía bien en la memoria, y que decía desta manera: «Luscinda a Cardenio Cada día descubro en vos valores que me obligan y fuerzan a que en más os estime; y así, si quisiéredes sacarme desta deuda sin ejecutarme en la honra, lo podréis muy bien hacer. Padre tengo, que os conoce y que me quiere bien, el cual, sin forzar mi voluntad, cumplirá la que será justo que vos tengáis, si es que me estimáis como decís y como yo creo. -»Por este billete me moví a pedir a Luscinda por esposa, como ya os he contado, y éste fue por quien quedó Luscinda en la opinión de don Fernando por una de las más discretas y avisadas mujeres de su tiempo; y este billete fue el que le puso en deseo de destruirme, antes que el mío se efetuase. Díjele yo a don Fernando en lo que reparaba el padre de Luscinda, que era en que mi padre se la pidiese, lo cual yo no le osaba decir, temeroso que no vendría en ello, no porque no tuviese bien conocida la calidad, bondad, virtud y hermosura de Luscinda, y que tenía partes bastantes para enoblecer cualquier otro linaje de España, sino porque yo entendía dél que deseaba que no me casase tan presto, hasta ver lo que el duque Ricardo hacía conmigo. En resolución, le dije que no me aventuraba a decírselo a mi padre, así por aquel inconveniente como por otros muchos que me acobardaban, sin saber cuáles eran, sino que me parecía que lo que yo desease jamás había de tener efeto. »A todo esto me respondió don Fernando que él se encargaba de hablar a mi padre y hacer con él que hablase al de Luscinda. ¡Oh Mario ambicioso, oh Catilina cruel, oh Sila facinoroso, oh Galalón embustero, oh Vellido traidor, oh Julián vengativo, oh Judas codicioso! Traidor, cruel, vengativo y embustero, ¿qué deservicios te había hecho este triste, que con tanta llaneza te descubrió los secretos y contentos de su corazón? ¿Qué ofensa te hice? ¿Qué palabras te dije, o qué consejos te di, que no fuesen todos encaminados a acrecentar tu honra y tu provecho? Mas, ¿de qué me quejo?, ¡desventurado de mí!, pues es cosa cierta que cuando traen las desgracias la corriente de las estrellas, como vienen de alto a bajo, despeñándose con furor y con violencia, no hay fuerza en la tierra que las detenga, ni industria humana que prevenirlas pueda. ¿Quién pudiera imaginar que don Fernando, caballero ilustre, discreto, obligado de mis servicios, poderoso para alcanzar lo que el deseo amoroso le pidiese dondequiera que le ocupase, se había de enconar, como suele decirse, en tomarme a mí una sola oveja, que aún no poseía? Pero quédense estas consideraciones aparte, como inútiles y sin provecho, y añudemos el roto hilo de mi desdichada historia. »Digo, pues, que, pareciéndole a don Fernando que mi presencia le era inconveniente para poner en ejecución su falso y mal pensamiento, determinó de enviarme a su hermano mayor, con ocasión de pedirle unos dineros para pagar seis caballos, que de industria, y sólo para este efeto de que me ausentase (para poder mejor salir con su dañado intento), el mesmo día que se ofreció hablar a mi padre los compró, y quiso que yo viniese por el dinero. ¿Pude yo prevenir esta traición? ¿Pude, por ventura, caer en imaginarla? No, por cierto; antes, con grandísimo gusto, me ofrecí a partir luego, contento de la buena compra hecha. Aquella noche hablé con Luscinda, y le dije lo que con don Fernando quedaba concertado, y que tuviese firme esperanza de que tendrían efeto nuestros buenos y justos deseos. Ella me dijo, tan segura como yo de la traición de don Fernando, que procurase volver presto, porque creía que no tardaría más la conclusión de nuestras voluntades que tardase mi padre de hablar al suyo. No sé qué se fue, que, en acabando de decirme esto, se le llenaron los ojos de lágrimas y un nudo se le atravesó en la garganta, que no le dejaba hablar palabra de otras muchas que me pareció que procuraba decirme. »Quedé admirado deste nuevo accidente, hasta allí jamás en ella visto, porque siempre nos hablábamos, las veces que la buena fortuna y mi diligencia lo concedía, con todo regocijo y contento, sin mezclar en nuestras pláticas lágrimas, suspiros, celos, sospechas o temores. Todo era engrandecer yo mi ventura, por habérmela dado el cielo por señora: exageraba su belleza, admirábame de su valor y entendimiento. Volvíame ella el recambio, alabando en mí lo que, como enamorada, le parecía digno de alabanza. Con esto, nos contábamos cien mil niñerías y acaecimientos de nuestros vecinos y conocidos, y a lo que más se entendía mi desenvoltura era a tomarle, casi por fuerza, una de sus bellas y blancas manos, y llegarla a mi boca, según daba lugar la estrecheza de una baja reja que nos dividía. Pero la noche que precedió al triste día de mi partida, ella lloró, gimió y suspiró, y se fue, y me dejó lleno de confusión y sobresalto, espantado de haber visto tan nuevas y tan tristes muestras de dolor y sentimiento en Luscinda. Pero, por no destruir mis esperanzas, todo lo atribuí a la fuerza del amor que me tenía y al dolor que suele causar la ausencia en los que bien se quieren. »En fin, yo me partí triste y pensativo, llena el alma de imaginaciones y sospechas, sin saber lo que sospechaba ni imaginaba: claros indicios que me mostraban el triste suceso y desventura que me estaba guardada. Llegué al lugar donde era enviado. Di las cartas al hermano de don Fernando. Fui bien recebido, pero no bien despachado, porque me mandó aguardar, bien a mi disgusto, ocho días, y en parte donde el duque, su padre, no me viese, porque su hermano le escribía que le enviase cierto dinero sin su sabiduría. Y todo fue invención del falso don Fernando, pues no le faltaban a su hermano dineros para despacharme luego. Orden y mandato fue éste que me puso en condición de no obedecerle, por parecerme imposible sustentar tantos días la vida en el ausencia de Luscinda, y más, habiéndola dejado con la tristeza que os he contado; pero, con todo esto, obedecí, como buen criado, aunque veía que había de ser a costa de mi salud. »Pero, a los cuatro días que allí llegué, llegó un hombre en mi busca con una carta, que me dio, que en el sobrescrito conocí ser de Luscinda, porque la letra dél era suya. Abríla, temeroso y con sobresalto, creyendo que cosa grande debía de ser la que la había movido a escribirme estando ausente, pues presente pocas veces lo hacía. Preguntéle al hombre, antes de leerla, quién se la había dado y el tiempo que había tardado en el camino. Díjome que acaso, pasando por una calle de la ciudad a la hora de medio día, una señora muy hermosa le llamó desde una ventana, los ojos llenos de lágrimas, y que con mucha priesa le dijo: ''Hermano: si sois cristiano, como parecéis, por amor de Dios os ruego que encaminéis luego luego esta carta al lugar y a la persona que dice el sobrescrito, que todo es bien conocido, y en ello haréis un gran servicio a nuestro Señor; y, para que no os falte comodidad de poderlo hacer, tomad lo que va en este pañuelo''. ''Y, diciendo esto, me arrojó por la ventana un pañuelo, donde venían atados cien reales y esta sortija de oro que aquí traigo, con esa carta que os he dado. Y luego, sin aguardar respuesta mía, se quitó de la ventana; aunque primero vio cómo yo tomé la carta y el pañuelo, y, por señas, le dije que haría lo que me mandaba. Y así, viéndome tan bien pagado del trabajo que podía tomar en traérosla y conociendo por el sobrescrito que érades vos a quien se enviaba, porque yo, señor, os conozco muy bien, y obligado asimesmo de las lágrimas de aquella hermosa señora, determiné de no fiarme de otra persona, sino venir yo mesmo a dárosla; y en diez y seis horas que ha que se me dio, he hecho el camino, que sabéis que es de diez y ocho leguas''. »En tanto que el agradecido y nuevo correo esto me decía, estaba yo colgado de sus palabras, temblándome las piernas de manera que apenas podía sostenerme. En efeto, abrí la carta y vi que contenía estas razones: La palabra que don Fernando os dio de hablar a vuestro padre para que hablase al mío, la ha cumplido más en su gusto que en vuestro provecho. Sabed, señor, que él me ha pedido por esposa, y mi padre, llevado de la ventaja que él piensa que don Fernando os hace, ha venido en lo que quiere, con tantas veras que de aquí a dos días se ha de hacer el desposorio, tan secreto y tan a solas, que sólo han de ser testigos los cielos y alguna gente de casa. Cual yo quedo, imaginaldo; si os cumple venir, veldo; y si os quiero bien o no, el suceso deste negocio os lo dará a entender. A Dios plega que ésta llegue a vuestras manos antes que la mía se vea en condición de juntarse con la de quien tan mal sabe guardar la fe que promete. ȃstas, en suma, fueron las razones que la carta contenía y las que me hicieron poner luego en camino, sin esperar otra respuesta ni otros dineros; que bien claro conocí entonces que no la compra de los caballos, sino la de su gusto, había movido a don Fernando a enviarme a su hermano. El enojo que contra don Fernando concebí, junto con el temor de perder la prenda que con tantos años de servicios y deseos tenía granjeada, me pusieron alas, pues, casi como en vuelo, otro día me puse en mi lugar, al punto y hora que convenía para ir a hablar a Luscinda. Entré secreto, y dejé una mula en que venía en casa del buen hombre que me había llevado la carta; y quiso la suerte que entonces la tuviese tan buena que hallé a Luscinda puesta a la reja, testigo de nuestros amores. Conocióme Luscinda luego, y conocíla yo; mas no como debía ella conocerme y yo conocerla. Pero, ¿quién hay en el mundo que se pueda alabar que ha penetrado y sabido el confuso pensamiento y condición mudable de una mujer? Ninguno, por cierto. »Digo, pues, que, así como Luscinda me vio, me dijo: ''Cardenio, de boda estoy vestida; ya me están aguardando en la sala don Fernando el traidor y mi padre el codicioso, con otros testigos, que antes lo serán de mi muerte que de mi desposorio. No te turbes, amigo, sino procura hallarte presente a este sacrificio, el cual si no pudiere ser estorbado de mis razones, una daga llevo escondida que podrá estorbar más determinadas fuerzas, dando fin a mi vida y principio a que conozcas la voluntad que te he tenido y tengo''. Yo le respondí turbado y apriesa, temeroso no me faltase lugar para responderla: ''Hagan, señora, tus obras verdaderas tus palabras; que si tú llevas daga para acreditarte, aquí llevo yo espada para defenderte con ella o para matarme si la suerte nos fuere contraria''. No creo que pudo oír todas estas razones, porque sentí que la llamaban apriesa, porque el desposado aguardaba. Cerróse con esto la noche de mi tristeza, púsoseme el sol de mi alegría: quedé sin luz en los ojos y sin discurso en el entendimiento. No acertaba a entrar en su casa, ni podía moverme a parte alguna; pero, considerando cuánto importaba mi presencia para lo que suceder pudiese en aquel caso, me animé lo más que pude y entré en su casa. Y, como ya sabía muy bien todas sus entradas y salidas, y más con el alboroto que de secreto en ella andaba, nadie me echó de ver. Así que, sin ser visto, tuve lugar de ponerme en el hueco que hacía una ventana de la mesma sala, que con las puntas y remates de dos tapices se cubría, por entre las cuales podía yo ver, sin ser visto, todo cuanto en la sala se hacía. »¿Quién pudiera decir ahora los sobresaltos que me dio el corazón mientras allí estuve, los pensamientos que me ocurrieron, las consideraciones que hice?, que fueron tantas y tales, que ni se pueden decir ni aun es bien que se digan. Basta que sepáis que el desposado entró en la sala sin otro adorno que los mesmos vestidos ordinarios que solía. Traía por padrino a un primo hermano de Luscinda, y en toda la sala no había persona de fuera, sino los criados de casa. De allí a un poco, salió de una recámara Luscinda, acompañada de su madre y de dos doncellas suyas, tan bien aderezada y compuesta como su calidad y hermosura merecían, y como quien era la perfeción de la gala y bizarría cortesana. No me dio lugar mi suspensión y arrobamiento para que mirase y notase en particular lo que traía vestido; sólo pude advertir a las colores, que eran encarnado y blanco, y en las vislumbres que las piedras y joyas del tocado y de todo el vestido hacían, a todo lo cual se aventajaba la belleza singular de sus hermosos y rubios cabellos; tales que, en competencia de las preciosas piedras y de las luces de cuatro hachas que en la sala estaban, la suya con más resplandor a los ojos ofrecían. ¡Oh memoria, enemiga mortal de mi descanso! ¿De qué sirve representarme ahora la incomparable belleza de aquella adorada enemiga mía? ¿No será mejor, cruel memoria, que me acuerdes y representes lo que entonces hizo, para que, movido de tan manifiesto agravio, procure, ya que no la venganza, a lo menos perder la vida?» No os canséis, señores, de oír estas digresiones que hago; que no es mi pena de aquellas que puedan ni deban contarse sucintamente y de paso, pues cada circunstancia suya me parece a mí que es digna de un largo discurso. A esto le respondió el cura que no sólo no se cansaban en oírle, sino que les daba mucho gusto las menudencias que contaba, por ser tales, que merecían no pasarse en silencio, y la mesma atención que lo principal del cuento. -«Digo, pues -prosiguió Cardenio-, que, estando todos en la sala, entró el cura de la perroquia, y, tomando a los dos por la mano para hacer lo que en tal acto se requiere, al decir: ''¿Queréis, señora Luscinda, al señor don Fernando, que está presente, por vuestro legítimo esposo, como lo manda la Santa Madre Iglesia?'', yo saqué toda la cabeza y cuello de entre los tapices, y con atentísimos oídos y alma turbada me puse a escuchar lo que Luscinda respondía, esperando de su respuesta la sentencia de mi muerte o la confirmación de mi vida. ¡Oh, quién se atreviera a salir entonces, diciendo a voces!: ''¡Ah Luscinda, Luscinda, mira lo que haces, considera lo que me debes, mira que eres mía y que no puedes ser de otro! Advierte que el decir tú sí y el acabárseme la vida ha de ser todo a un punto. ¡Ah traidor don Fernando, robador de mi gloria, muerte de mi vida! ¿Qué quieres? ¿Qué pretendes? Considera que no puedes cristianamente llegar al fin de tus deseos, porque Luscinda es mi esposa y yo soy su marido''. ¡Ah, loco de mí, ahora que estoy ausente y lejos del peligro, digo que había de hacer lo que no hice! ¡Ahora que dejé robar mi cara prenda, maldigo al robador, de quien pudiera vengarme si tuviera corazón para ello como le tengo para quejarme! En fin, pues fui entonces cobarde y necio, no es mucho que muera ahora corrido, arrepentido y loco. »Estaba esperando el cura la respuesta de Luscinda, que se detuvo un buen espacio en darla, y, cuando yo pensé que sacaba la daga para acreditarse, o desataba la lengua para decir alguna verdad o desengaño que en mi provecho redundase, oigo que dijo con voz desmayada y flaca: ''Sí quiero''; y lo mesmo dijo don Fernando; y, dándole el anillo, quedaron en disoluble nudo ligados. Llegó el desposado a abrazar a su esposa, y ella, poniéndose la mano sobre el corazón, cayó desmayada en los brazos de su madre. Resta ahora decir cuál quedé yo viendo, en el sí que había oído, burladas mis esperanzas, falsas las palabras y promesas de Luscinda: imposibilitado de cobrar en algún tiempo el bien que en aquel instante había perdido. Quedé falto de consejo, desamparado, a mi parecer, de todo el cielo, hecho enemigo de la tierra que me sustentaba, negándome el aire aliento para mis suspiros y el agua humor para mis ojos; sólo el fuego se acrecentó de manera que todo ardía de rabia y de celos. »Alborotáronse todos con el desmayo de Luscinda, y, desabrochándole su madre el pecho para que le diese el aire, se descubrió en él un papel cerrado, que don Fernando tomó luego y se le puso a leer a la luz de una de las hachas; y, en acabando de leerle, se sentó en una silla y se puso la mano en la mejilla, con muestras de hombre muy pensativo, sin acudir a los remedios que a su esposa se hacían para que del desmayo volviese. Yo, viendo alborotada toda la gente de casa, me aventuré a salir, ora fuese visto o no, con determinación que si me viesen, de hacer un desatino tal, que todo el mundo viniera a entender la justa indignación de mi pecho en el castigo del falso don Fernando, y aun en el mudable de la desmayada traidora. Pero mi suerte, que para mayores males, si es posible que los haya, me debe tener guardado, ordenó que en aquel punto me sobrase el entendimiento que después acá me ha faltado; y así, sin querer tomar venganza de mis mayores enemigos (que, por estar tan sin pensamiento mío, fuera fácil tomarla), quise tomarla de mi mano y ejecutar en mí la pena que ellos merecían; y aun quizá con más rigor del que con ellos se usara si entonces les diera muerte, pues la que se recibe repentina presto acaba la pena; mas la que se dilata con tormentos siempre mata, sin acabar la vida. »En fin, yo salí de aquella casa y vine a la de aquél donde había dejado la mula; hice que me la ensillase, sin despedirme dél subí en ella, y salí de la ciudad, sin osar, como otro Lot, volver el rostro a miralla; y cuando me vi en el campo solo, y que la escuridad de la noche me encubría y su silencio convidaba a quejarme, sin respeto o miedo de ser escuchado ni conocido, solté la voz y desaté la lengua en tantas maldiciones de Luscinda y de don Fernando, como si con ellas satisficiera el agravio que me habían hecho. Dile títulos de cruel, de ingrata, de falsa y desagradecida; pero, sobre todos, de codiciosa, pues la riqueza de mi enemigo la había cerrado los ojos de la voluntad, para quitármela a mí y entregarla a aquél con quien más liberal y franca la fortuna se había mostrado; y, en mitad de la fuga destas maldiciones y vituperios, la desculpaba, diciendo que no era mucho que una doncella recogida en casa de sus padres, hecha y acostumbrada siempre a obedecerlos, hubiese querido condecender con su gusto, pues le daban por esposo a un caballero tan principal, tan rico y tan gentil hombre que, a no querer recebirle, se podía pensar, o que no tenía juicio, o que en otra parte tenía la voluntad: cosa que redundaba tan en perjuicio de su buena opinión y fama. Luego volvía diciendo que, puesto que ella dijera que yo era su esposo, vieran ellos que no había hecho en escogerme tan mala elección, que no la disculparan, pues antes de ofrecérseles don Fernando no pudieran ellos mesmos acertar a desear, si con razón midiesen su deseo, otro mejor que yo para esposo de su hija; y que bien pudiera ella, antes de ponerse en el trance forzoso y último de dar la mano, decir que ya yo le había dado la mía; que yo viniera y concediera con todo cuanto ella acertara a fingir en este caso. »En fin, me resolví en que poco amor, poco juicio, mucha ambición y deseos de grandezas hicieron que se olvidase de las palabras con que me había engañado, entretenido y sustentado en mis firmes esperanzas y honestos deseos. Con estas voces y con esta inquietud caminé lo que quedaba de aquella noche, y di al amanecer en una entrada destas sierras, por las cuales caminé otros tres días, sin senda ni camino alguno, hasta que vine a parar a unos prados, que no sé a qué mano destas montañas caen, y allí pregunté a unos ganaderos que hacia dónde era lo más áspero destas sierras. Dijéronme que hacia esta parte. Luego me encaminé a ella, con intención de acabar aquí la vida, y, en entrando por estas asperezas, del cansancio y de la hambre se cayó mi mula muerta, o, lo que yo más creo, por desechar de sí tan inútil carga como en mí llevaba. Yo quedé a pie, rendido de la naturaleza, traspasado de hambre, sin tener, ni pensar buscar, quien me socorriese. »De aquella manera estuve no sé qué tiempo, tendido en el suelo, al cabo del cual me levanté sin hambre, y hallé junto a mí a unos cabreros, que, sin duda, debieron ser los que mi necesidad remediaron, porque ellos me dijeron de la manera que me habían hallado, y cómo estaba diciendo tantos disparates y desatinos, que daba indicios claros de haber perdido el juicio; y yo he sentido en mí, después acá, que no todas veces le tengo cabal, sino tan desmedrado y flaco que hago mil locuras, rasgándome los vestidos, dando voces por estas soledades, maldiciendo mi ventura y repitiendo en vano el nombre amado de mi enemiga, sin tener otro discurso ni intento entonces que procurar acabar la vida voceando; y cuando en mí vuelvo, me hallo tan cansado y molido, que apenas puedo moverme. Mi más común habitación es en el hueco de un alcornoque, capaz de cubrir este miserable cuerpo. Los vaqueros y cabreros que andan por estas montañas, movidos de caridad, me sustentan, poniéndome el manjar por los caminos y por las peñas por donde entienden que acaso podré pasar y hallarlo; y así, aunque entonces me falte el juicio, la necesidad natural me da a conocer el mantenimiento, y despierta en mí el deseo de apetecerlo y la voluntad de tomarlo. Otras veces me dicen ellos, cuando me encuentran con juicio, que yo salgo a los caminos y que se lo quito por fuerza, aunque me lo den de grado, a los pastores que vienen con ello del lugar a las majadas. »Desta manera paso mi miserable y estrema vida, hasta que el cielo sea servido de conducirle a su último fin, o de ponerle en mi memoria, para que no me acuerde de la hermosura y de la traición de Luscinda y del agravio de don Fernando; que si esto él hace sin quitarme la vida, yo volveré a mejor discurso mis pensamientos; donde no, no hay sino rogarle que absolutamente tenga misericordia de mi alma, que yo no siento en mí valor ni fuerzas para sacar el cuerpo desta estrecheza en que por mi gusto he querido ponerle». Ésta es, ¡oh señores!, la amarga historia de mi desgracia: decidme si es tal, que pueda celebrarse con menos sentimientos que los que en mí habéis visto; y no os canséis en persuadirme ni aconsejarme lo que la razón os dijere que puede ser bueno para mi remedio, porque ha de aprovechar conmigo lo que aprovecha la medicina recetada de famoso médico al enfermo que recebir no la quiere. Yo no quiero salud sin Luscinda; y, pues ella gustó de ser ajena, siendo, o debiendo ser, mía, guste yo de ser de la desventura, pudiendo haber sido de la buena dicha. Ella quiso, con su mudanza, hacer estable mi perdición; yo querré, con procurar perderme, hacer contenta su voluntad, y será ejemplo a los por venir de que a mí solo faltó lo que a todos los desdichados sobra, a los cuales suele ser consuelo la imposibilidad de tenerle, y en mí es causa de mayores sentimientos y males, porque aun pienso que no se han de acabar con la muerte. Aquí dio fin Cardenio a su larga plática y tan desdichada como amorosa historia. Y, al tiempo que el cura se prevenía para decirle algunas razones de consuelo, le suspendió una voz que llegó a sus oídos, que en lastimados acentos oyeron que decía lo que se dirá en la cuarta parte desta narración, que en este punto dio fin a la tercera el sabio y atentado historiador Cide Hamete Benengeli. Cuarta parte del ingenioso hidalgo don Quijote de la Mancha Capítulo XXVIII. Que trata de la nueva y agradable aventura que al cura y barbero sucedió en la mesma sierra Felicísimos y venturosos fueron los tiempos donde se echó al mundo el audacísimo caballero don Quijote de la Mancha, pues por haber tenido tan honrosa determinación como fue el querer resucitar y volver al mundo la ya perdida y casi muerta orden de la andante caballería, gozamos ahora, en esta nuestra edad, necesitada de alegres entretenimientos, no sólo de la dulzura de su verdadera historia, sino de los cuentos y episodios della, que, en parte, no son menos agradables y artificiosos y verdaderos que la misma historia; la cual, prosiguiendo su rastrillado, torcido y aspado hilo, cuenta que, así como el cura comenzó a prevenirse para consolar a Cardenio, lo impidió una voz que llegó a sus oídos, que, con tristes acentos, decía desta manera: -¡Ay Dios! ¿Si será posible que he ya hallado lugar que pueda servir de escondida sepultura a la carga pesada deste cuerpo, que tan contra mi voluntad sostengo? Sí será, si la soledad que prometen estas sierras no me miente. ¡Ay, desdichada, y cuán más agradable compañía harán estos riscos y malezas a mi intención, pues me darán lugar para que con quejas comunique mi desgracia al cielo, que no la de ningún hombre humano, pues no hay ninguno en la tierra de quien se pueda esperar consejo en las dudas, alivio en las quejas, ni remedio en los males! Todas estas razones oyeron y percibieron el cura y los que con él estaban, y por parecerles, como ello era, que allí junto las decían, se levantaron a buscar el dueño, y no hubieron andado veinte pasos, cuando detrás de un peñasco vieron, sentado al pie de un fresno, a un mozo vestido como labrador, al cual, por tener inclinado el rostro, a causa de que se lavaba los pies en el arroyo que por allí corría, no se le pudieron ver por entonces. Y ellos llegaron con tanto silencio que dél no fueron sentidos, ni él estaba a otra cosa atento que a lavarse los pies, que eran tales, que no parecían sino dos pedazos de blanco cristal que entre las otras piedras del arroyo se habían nacido. Suspendióles la blancura y belleza de los pies, pareciéndoles que no estaban hechos a pisar terrones, ni a andar tras el arado y los bueyes, como mostraba el hábito de su dueño; y así, viendo que no habían sido sentidos, el cura, que iba delante, hizo señas a los otros dos que se agazapasen o escondiesen detrás de unos pedazos de peña que allí había, y así lo hicieron todos, mirando con atención lo que el mozo hacía; el cual traía puesto un capotillo pardo de dos haldas, muy ceñido al cuerpo con una toalla blanca. Traía, ansimesmo, unos calzones y polainas de paño pardo, y en la cabeza una montera parda. Tenía las polainas levantadas hasta la mitad de la pierna, que, sin duda alguna, de blanco alabastro parecía. Acabóse de lavar los hermosos pies, y luego, con un paño de tocar, que sacó debajo de la montera, se los limpió; y, al querer quitársele, alzó el rostro, y tuvieron lugar los que mirándole estaban de ver una hermosura incomparable; tal, que Cardenio dijo al cura, con voz baja: -Ésta, ya que no es Luscinda, no es persona humana, sino divina. El mozo se quitó la montera, y, sacudiendo la cabeza a una y a otra parte, se comenzaron a descoger y desparcir unos cabellos, que pudieran los del sol tenerles envidia. Con esto conocieron que el que parecía labrador era mujer, y delicada, y aun la más hermosa que hasta entonces los ojos de los dos habían visto, y aun los de Cardenio, si no hubieran mirado y conocido a Luscinda; que después afirmó que sola la belleza de Luscinda podía contender con aquélla. Los luengos y rubios cabellos no sólo le cubrieron las espaldas, mas toda en torno la escondieron debajo de ellos; que si no eran los pies, ninguna otra cosa de su cuerpo se parecía: tales y tantos eran. En esto, les sirvió de peine unas manos, que si los pies en el agua habían parecido pedazos de cristal, las manos en los cabellos semejaban pedazos de apretada nieve; todo lo cual, en más admiración y en más deseo de saber quién era ponía a los tres que la miraban. Por esto determinaron de mostrarse, y, al movimiento que hicieron de ponerse en pie, la hermosa moza alzó la cabeza, y, apartándose los cabellos de delante de los ojos con entrambas manos, miró los que el ruido hacían; y apenas los hubo visto, cuando se levantó en pie, y, sin aguardar a calzarse ni a recoger los cabellos, asió con mucha presteza un bulto, como de ropa, que junto a sí tenía, y quiso ponerse en huida, llena de turbación y sobresalto; mas no hubo dado seis pasos cuando, no pudiendo sufrir los delicados pies la aspereza de las piedras, dio consigo en el suelo. Lo cual visto por los tres, salieron a ella, y el cura fue el primero que le dijo: -Deteneos, señora, quienquiera que seáis, que los que aquí veis sólo tienen intención de serviros. No hay para qué os pongáis en tan impertinente huida, porque ni vuestros pies lo podrán sufrir ni nosotros consentir. A todo esto, ella no respondía palabra, atónita y confusa. Llegaron, pues, a ella, y, asiéndola por la mano el cura, prosiguió diciendo: -Lo que vuestro traje, señora, nos niega, vuestros cabellos nos descubren: señales claras que no deben de ser de poco momento las causas que han disfrazado vuestra belleza en hábito tan indigno, y traídola a tanta soledad como es ésta, en la cual ha sido ventura el hallaros, si no para dar remedio a vuestros males, a lo menos para darles consejo, pues ningún mal puede fatigar tanto, ni llegar tan al estremo de serlo, mientras no acaba la vida, que rehúya de no escuchar siquiera el consejo que con buena intención se le da al que lo padece. Así que, señora mía, o señor mío, o lo que vos quisierdes ser, perded el sobresalto que nuestra vista os ha causado y contadnos vuestra buena o mala suerte; que en nosotros juntos, o en cada uno, hallaréis quien os ayude a sentir vuestras desgracias. En tanto que el cura decía estas razones, estaba la disfrazada moza como embelesada, mirándolos a todos, sin mover labio ni decir palabra alguna: bien así como rústico aldeano que de improviso se le muestran cosas raras y dél jamás vistas. Mas, volviendo el cura a decirle otras razones al mesmo efeto encaminadas, dando ella un profundo suspiro, rompió el silencio y dijo: -Pues que la soledad destas sierras no ha sido parte para encubrirme, ni la soltura de mis descompuestos cabellos no ha permitido que sea mentirosa mi lengua, en balde sería fingir yo de nuevo ahora lo que, si se me creyese, sería más por cortesía que por otra razón alguna. Presupuesto esto, digo, señores, que os agradezco el ofrecimiento que me habéis hecho, el cual me ha puesto en obligación de satisfaceros en todo lo que me habéis pedido, puesto que temo que la relación que os hiciere de mis desdichas os ha de causar, al par de la compasión, la pesadumbre, porque no habéis de hallar remedio para remediarlas ni consuelo para entretenerlas. Pero, con todo esto, porque no ande vacilando mi honra en vuestras intenciones, habiéndome ya conocido por mujer y viéndome moza, sola y en este traje, cosas todas juntas, y cada una por sí, que pueden echar por tierra cualquier honesto crédito, os habré de decir lo que quisiera callar si pudiera. Todo esto dijo sin parar la que tan hermosa mujer parecía, con tan suelta lengua, con voz tan suave, que no menos les admiró su discreción que su hermosura. Y, tornándole a hacer nuevos ofrecimientos y nuevos ruegos para que lo prometido cumpliese, ella, sin hacerse más de rogar, calzándose con toda honestidad y recogiendo sus cabellos, se acomodó en el asiento de una piedra, y, puestos los tres alrededor della, haciéndose fuerza por detener algunas lágrimas que a los ojos se le venían, con voz reposada y clara, comenzó la historia de su vida desta manera: -«En esta Andalucía hay un lugar de quien toma título un duque, que le hace uno de los que llaman grandes en España. Éste tiene dos hijos: el mayor, heredero de su estado, y, al parecer, de sus buenas costumbres; y el menor, no sé yo de qué sea heredero, sino de las traiciones de Vellido y de los embustes de Galalón. Deste señor son vasallos mis padres, humildes en linaje, pero tan ricos que si los bienes de su naturaleza igualaran a los de su fortuna, ni ellos tuvieran más que desear ni yo temiera verme en la desdicha en que me veo; porque quizá nace mi poca ventura de la que no tuvieron ellos en no haber nacido ilustres. Bien es verdad que no son tan bajos que puedan afrentarse de su estado, ni tan altos que a mí me quiten la imaginación que tengo de que de su humildad viene mi desgracia. Ellos, en fin, son labradores, gente llana, sin mezcla de alguna raza mal sonante, y, como suele decirse, cristianos viejos ranciosos; pero tan ricos que su riqueza y magnífico trato les va poco a poco adquiriendo nombre de hidalgos, y aun de caballeros. Puesto que de la mayor riqueza y nobleza que ellos se preciaban era de tenerme a mí por hija; y, así por no tener otra ni otro que los heredase como por ser padres, y aficionados, yo era una de las más regaladas hijas que padres jamás regalaron. Era el espejo en que se miraban, el báculo de su vejez, y el sujeto a quien encaminaban, midiéndolos con el cielo, todos sus deseos; de los cuales, por ser ellos tan buenos, los míos no salían un punto. Y del mismo modo que yo era señora de sus ánimos, ansí lo era de su hacienda: por mí se recebían y despedían los criados; la razón y cuenta de lo que se sembraba y cogía pasaba por mi mano; los molinos de aceite, los lagares de vino, el número del ganado mayor y menor, el de las colmenas. Finalmente, de todo aquello que un tan rico labrador como mi padre puede tener y tiene, tenía yo la cuenta, y era la mayordoma y señora, con tanta solicitud mía y con tanto gusto suyo, que buenamente no acertaré a encarecerlo. Los ratos que del día me quedaban, después de haber dado lo que convenía a los mayorales, a capataces y a otros jornaleros, los entretenía en ejercicios que son a las doncellas tan lícitos como necesarios, como son los que ofrece la aguja y la almohadilla, y la rueca muchas veces; y si alguna, por recrear el ánimo, estos ejercicios dejaba, me acogía al entretenimiento de leer algún libro devoto, o a tocar una arpa, porque la experiencia me mostraba que la música compone los ánimos descompuestos y alivia los trabajos que nacen del espíritu. ȃsta, pues, era la vida que yo tenía en casa de mis padres, la cual, si tan particularmente he contado, no ha sido por ostentación ni por dar a entender que soy rica, sino porque se advierta cuán sin culpa me he venido de aquel buen estado que he dicho al infelice en que ahora me hallo. Es, pues, el caso que, pasando mi vida en tantas ocupaciones y en un encerramiento tal que al de un monesterio pudiera compararse, sin ser vista, a mi parecer, de otra persona alguna que de los criados de casa, porque los días que iba a misa era tan de mañana, y tan acompañada de mi madre y de otras criadas, y yo tan cubierta y recatada que apenas vían mis ojos más tierra de aquella donde ponía los pies; y, con todo esto, los del amor, o los de la ociosidad, por mejor decir, a quien los de lince no pueden igualarse, me vieron, puestos en la solicitud de don Fernando, que éste es el nombre del hijo menor del duque que os he contado». No hubo bien nombrado a don Fernando la que el cuento contaba, cuando a Cardenio se le mudó la color del rostro, y comenzó a trasudar, con tan grande alteración que el cura y el barbero, que miraron en ello, temieron que le venía aquel accidente de locura que habían oído decir que de cuando en cuando le venía. Mas Cardenio no hizo otra cosa que trasudar y estarse quedo, mirando de hito en hito a la labradora, imaginando quién ella era; la cual, sin advertir en los movimientos de Cardenio, prosiguió su historia, diciendo: -«Y no me hubieron bien visto cuando, según él dijo después, quedó tan preso de mis amores cuanto lo dieron bien a entender sus demostraciones. Mas, por acabar presto con el cuento, que no le tiene, de mis desdichas, quiero pasar en silencio las diligencias que don Fernando hizo para declararme su voluntad. Sobornó toda la gente de mi casa, dio y ofreció dádivas y mercedes a mis parientes. Los días eran todos de fiesta y de regocijo en mi calle; las noches no dejaban dormir a nadie las músicas. Los billetes que, sin saber cómo, a mis manos venían, eran infinitos, llenos de enamoradas razones y ofrecimientos, con menos letras que promesas y juramentos. Todo lo cual no sólo no me ablandaba, pero me endurecía de manera como si fuera mi mortal enemigo, y que todas las obras que para reducirme a su voluntad hacía, las hiciera para el efeto contrario; no porque a mí me pareciese mal la gentileza de don Fernando, ni que tuviese a demasía sus solicitudes; porque me daba un no sé qué de contento verme tan querida y estimada de un tan principal caballero, y no me pesaba ver en sus papeles mis alabanzas: que en esto, por feas que seamos las mujeres, me parece a mí que siempre nos da gusto el oír que nos llaman hermosas. »Pero a todo esto se opone mi honestidad y los consejos continuos que mis padres me daban, que ya muy al descubierto sabían la voluntad de don Fernando, porque ya a él no se le daba nada de que todo el mundo la supiese. Decíanme mis padres que en sola mi virtud y bondad dejaban y depositaban su honra y fama, y que considerase la desigualdad que había entre mí y don Fernando, y que por aquí echaría de ver que sus pensamientos, aunque él dijese otra cosa, mas se encaminaban a su gusto que a mi provecho; y que si yo quisiese poner en alguna manera algún inconveniente para que él se dejase de su injusta pretensión, que ellos me casarían luego con quien yo más gustase: así de los más principales de nuestro lugar como de todos los circunvecinos, pues todo se podía esperar de su mucha hacienda y de mi buena fama. Con estos ciertos prometimientos, y con la verdad que ellos me decían, fortificaba yo mi entereza, y jamás quise responder a don Fernando palabra que le pudiese mostrar, aunque de muy lejos, esperanza de alcanzar su deseo. »Todos estos recatos míos, que él debía de tener por desdenes, debieron de ser causa de avivar más su lascivo apetito, que este nombre quiero dar a la voluntad que me mostraba; la cual, si ella fuera como debía, no la supiérades vosotros ahora, porque hubiera faltado la ocasión de decírosla. Finalmente, don Fernando supo que mis padres andaban por darme estado, por quitalle a él la esperanza de poseerme, o, a lo menos, porque yo tuviese más guardas para guardarme; y esta nueva o sospecha fue causa para que hiciese lo que ahora oiréis. Y fue que una noche, estando yo en mi aposento con sola la compañía de una doncella que me servía, teniendo bien cerradas las puertas, por temor que, por descuido, mi honestidad no se viese en peligro, sin saber ni imaginar cómo, en medio destos recatos y prevenciones, y en la soledad deste silencio y encierro, me le hallé delante, cuya vista me turbó de manera que me quitó la de mis ojos y me enmudeció la lengua; y así, no fui poderosa de dar voces, ni aun él creo que me las dejara dar, porque luego se llegó a mí, y, tomándome entre sus brazos (porque yo, como digo, no tuve fuerzas para defenderme, según estaba turbada), comenzó a decirme tales razones, que no sé cómo es posible que tenga tanta habilidad la mentira que las sepa componer de modo que parezcan tan verdaderas. Hacía el traidor que sus lágrimas acreditasen sus palabras y los suspiros su intención. Yo, pobrecilla, sola entre los míos, mal ejercitada en casos semejantes, comencé, no sé en qué modo, a tener por verdaderas tantas falsedades, pero no de suerte que me moviesen a compasión menos que buena sus lágrimas y suspiros. »Y así, pasándoseme aquel sobresalto primero, torné algún tanto a cobrar mis perdidos espíritus, y con más ánimo del que pensé que pudiera tener, le dije: ''Si como estoy, señor, en tus brazos, estuviera entre los de un león fiero y el librarme dellos se me asegurara con que hiciera, o dijera, cosa que fuera en perjuicio de mi honestidad, así fuera posible hacella o decilla como es posible dejar de haber sido lo que fue. Así que, si tú tienes ceñido mi cuerpo con tus brazos, yo tengo atada mi alma con mis buenos deseos, que son tan diferentes de los tuyos como lo verás si con hacerme fuerza quisieres pasar adelante en ellos. Tu vasalla soy, pero no tu esclava; ni tiene ni debe tener imperio la nobleza de tu sangre para deshonrar y tener en poco la humildad de la mía; y en tanto me estimo yo, villana y labradora, como tú, señor y caballero. Conmigo no han de ser de ningún efecto tus fuerzas, ni han de tener valor tus riquezas, ni tus palabras han de poder engañarme, ni tus suspiros y lágrimas enternecerme. Si alguna de todas estas cosas que he dicho viera yo en el que mis padres me dieran por esposo, a su voluntad se ajustara la mía, y mi voluntad de la suya no saliera; de modo que, como quedara con honra, aunque quedara sin gusto, de grado te entregara lo que tú, señor, ahora con tanta fuerza procuras. Todo esto he dicho porque no es pensar que de mí alcance cosa alguna el que no fuere mi ligítimo esposo''. ''Si no reparas más que en eso, bellísima Dorotea -(que éste es el nombre desta desdichada), dijo el desleal caballero-, ves: aquí te doy la mano de serlo tuyo, y sean testigos desta verdad los cielos, a quien ninguna cosa se asconde, y esta imagen de Nuestra Señora que aquí tienes''.» Cuando Cardenio le oyó decir que se llamaba Dorotea, tornó de nuevo a sus sobresaltos y acabó de confirmar por verdadera su primera opinión; pero no quiso interromper el cuento, por ver en qué venía a parar lo que él ya casi sabía; sólo dijo: -¿Que Dorotea es tu nombre, señora? Otra he oído yo decir del mesmo, que quizá corre parejas con tus desdichas. Pasa adelante, que tiempo vendrá en que te diga cosas que te espanten en el mesmo grado que te lastimen. Reparó Dorotea en las razones de Cardenio y en su estraño y desastrado traje, y rogóle que si alguna cosa de su hacienda sabía, se la dijese luego; porque si algo le había dejado bueno la fortuna, era el ánimo que tenía para sufrir cualquier desastre que le sobreviniese, segura de que, a su parecer, ninguno podía llegar que el que tenía acrecentase un punto. -No le perdiera yo, señora -respondió Cardenio-, en decirte lo que pienso, si fuera verdad lo que imagino; y hasta ahora no se pierde coyuntura, ni a ti te importa nada el saberlo. -Sea lo que fuere -respondió Dorotea-, «lo que en mi cuento pasa fue que, tomando don Fernando una imagen que en aquel aposento estaba, la puso por testigo de nuestro desposorio. Con palabras eficacísimas y juramentos estraordinarios, me dio la palabra de ser mi marido, puesto que, antes que acabase de decirlas, le dije que mirase bien lo que hacía y que considerase el enojo que su padre había de recebir de verle casado con una villana vasalla suya; que no le cegase mi hermosura, tal cual era, pues no era bastante para hallar en ella disculpa de su yerro, y que si algún bien me quería hacer, por el amor que me tenía, fuese dejar correr mi suerte a lo igual de lo que mi calidad podía, porque nunca los tan desiguales casamientos se gozan ni duran mucho en aquel gusto con que se comienzan. »Todas estas razones que aquí he dicho le dije, y otras muchas de que no me acuerdo, pero no fueron parte para que él dejase de seguir su intento, bien ansí como el que no piensa pagar, que, al concertar de la barata, no repara en inconvenientes. Yo, a esta sazón, hice un breve discurso conmigo, y me dije a mí mesma: ''Sí, que no seré yo la primera que por vía de matrimonio haya subido de humilde a grande estado, ni será don Fernando el primero a quien hermosura, o ciega afición, que es lo más cierto, haya hecho tomar compañía desigual a su grandeza. Pues si no hago ni mundo ni uso nuevo, bien es acudir a esta honra que la suerte me ofrece, puesto que en éste no dure más la voluntad que me muestra de cuanto dure el cumplimiento de su deseo; que, en fin, para con Dios seré su esposa. Y si quiero con desdenes despedille, en término le veo que, no usando el que debe, usará el de la fuerza y vendré a quedar deshonrada y sin disculpa de la culpa que me podía dar el que no supiere cuán sin ella he venido a este punto. Porque, ¿qué razones serán bastantes para persuadir a mis padres, y a otros, que este caballero entró en mi aposento sin consentimiento mío?'' »Todas estas demandas y respuestas revolví yo en un instante en la imaginación; y, sobre todo, me comenzaron a hacer fuerza y a inclinarme a lo que fue, sin yo pensarlo, mi perdición: los juramentos de don Fernando, los testigos que ponía, las lágrimas que derramaba, y, finalmente, su dispusición y gentileza, que, acompañada con tantas muestras de verdadero amor, pudieran rendir a otro tan libre y recatado corazón como el mío. Llamé a mi criada, para que en la tierra acompañase a los testigos del cielo; tornó don Fernando a reiterar y confirmar sus juramentos; añadió a los primeros nuevos santos por testigos; echóse mil futuras maldiciones, si no cumpliese lo que me prometía; volvió a humedecer sus ojos y a acrecentar sus suspiros; apretóme más entre sus brazos, de los cuales jamás me había dejado; y con esto, y con volverse a salir del aposento mi doncella, yo dejé de serlo y él acabó de ser traidor y fementido. »El día que sucedió a la noche de mi desgracia se venía aun no tan apriesa como yo pienso que don Fernando deseaba, porque, después de cumplido aquello que el apetito pide, el mayor gusto que puede venir es apartarse de donde le alcanzaron. Digo esto porque don Fernando dio priesa por partirse de mí, y, por industria de mi doncella, que era la misma que allí le había traído, antes que amaneciese se vio en la calle. Y, al despedirse de mí, aunque no con tanto ahínco y vehemencia como cuando vino, me dijo que estuviese segura de su fe y de ser firmes y verdaderos sus juramentos; y, para más confirmación de su palabra, sacó un rico anillo del dedo y lo puso en el mío. En efecto, él se fue y yo quedé ni sé si triste o alegre; esto sé bien decir: que quedé confusa y pensativa, y casi fuera de mí con el nuevo acaecimiento, y no tuve ánimo, o no se me acordó, de reñir a mi doncella por la traición cometida de encerrar a don Fernando en mi mismo aposento, porque aún no me determinaba si era bien o mal el que me había sucedido. Díjele, al partir, a don Fernando que por el mesmo camino de aquélla podía verme otras noches, pues ya era suya, hasta que, cuando él quisiese, aquel hecho se publicase. Pero no vino otra alguna, si no fue la siguiente, ni yo pude verle en la calle ni en la iglesia en más de un mes; que en vano me cansé en solicitallo, puesto que supe que estaba en la villa y que los más días iba a caza, ejercicio de que él era muy aficionado. »Estos días y estas horas bien sé yo que para mí fueron aciagos y menguadas, y bien sé que comencé a dudar en ellos, y aun a descreer de la fe de don Fernando; y sé también que mi doncella oyó entonces las palabras que en reprehensión de su atrevimiento antes no había oído; y sé que me fue forzoso tener cuenta con mis lágrimas y con la compostura de mi rostro, por no dar ocasión a que mis padres me preguntasen que de qué andaba descontenta y me obligasen a buscar mentiras que decilles. Pero todo esto se acabó en un punto, llegándose uno donde se atropellaron respectos y se acabaron los honrados discursos, y adonde se perdió la paciencia y salieron a plaza mis secretos pensamientos. Y esto fue porque, de allí a pocos días, se dijo en el lugar como en una ciudad allí cerca se había casado don Fernando con una doncella hermosísima en todo estremo, y de muy principales padres, aunque no tan rica que, por la dote, pudiera aspirar a tan noble casamiento. Díjose que se llamaba Luscinda, con otras cosas que en sus desposorios sucedieron dignas de admiración.» Oyó Cardenio el nombre de Luscinda, y no hizo otra cosa que encoger los hombros, morderse los labios, enarcar las cejas y dejar de allí a poco caer por sus ojos dos fuentes de lágrimas. Mas no por esto dejó Dorotea de seguir su cuento, diciendo: -«Llegó esta triste nueva a mis oídos, y, en lugar de helárseme el corazón en oílla, fue tanta la cólera y rabia que se encendió en él, que faltó poco para no salirme por las calles dando voces, publicando la alevosía y traición que se me había hecho. Mas templóse esta furia por entonces con pensar de poner aquella mesma noche por obra lo que puse: que fue ponerme en este hábito, que me dio uno de los que llaman zagales en casa de los labradores, que era criado de mi padre, al cual descubrí toda mi desventura, y le rogué me acompañase hasta la ciudad donde entendí que mi enemigo estaba. Él, después que hubo reprehendido mi atrevimiento y afeado mi determinación, viéndome resuelta en mi parecer, se ofreció a tenerme compañía, como él dijo, hasta el cabo del mundo. Luego, al momento, encerré en una almohada de lienzo un vestido de mujer, y algunas joyas y dineros, por lo que podía suceder. Y en el silencio de aquella noche, sin dar cuenta a mi traidora doncella, salí de mi casa, acompañada de mi criado y de muchas imaginaciones, y me puse en camino de la ciudad a pie, llevada en vuelo del deseo de llegar, ya que no a estorbar lo que tenía por hecho, a lo menos a decir a don Fernando me dijese con qué alma lo había hecho. »Llegué en dos días y medio donde quería, y, en entrando por la ciudad, pregunté por la casa de los padres de Luscinda, y al primero a quien hice la pregunta me respondió más de lo que yo quisiera oír. Díjome la casa y todo lo que había sucedido en el desposorio de su hija, cosa tan pública en la ciudad, que se hace en corrillos para contarla por toda ella. Díjome que la noche que don Fernando se desposó con Luscinda, después de haber ella dado el sí de ser su esposa, le había tomado un recio desmayo, y que, llegando su esposo a desabrocharle el pecho para que le diese el aire, le halló un papel escrito de la misma letra de Luscinda, en que decía y declaraba que ella no podía ser esposa de don Fernando, porque lo era de Cardenio, que, a lo que el hombre me dijo, era un caballero muy principal de la mesma ciudad; y que si había dado el sí a don Fernando, fue por no salir de la obediencia de sus padres. En resolución, tales razones dijo que contenía el papel, que daba a entender que ella había tenido intención de matarse en acabándose de desposar, y daba allí las razones por que se había quitado la vida. Todo lo cual dicen que confirmó una daga que le hallaron no sé en qué parte de sus vestidos. Todo lo cual visto por don Fernando, pareciéndole que Luscinda le había burlado y escarnecido y tenido en poco, arremetió a ella, antes que de su desmayo volviese, y con la misma daga que le hallaron la quiso dar de puñaladas; y lo hiciera si sus padres y los que se hallaron presentes no se lo estorbaran. Dijeron más: que luego se ausentó don Fernando, y que Luscinda no había vuelto de su parasismo hasta otro día, que contó a sus padres cómo ella era verdadera esposa de aquel Cardenio que he dicho. Supe más: que el Cardenio, según decían, se halló presente en los desposorios, y que, en viéndola desposada, lo cual él jamás pensó, se salió de la ciudad desesperado, dejándole primero escrita una carta, donde daba a entender el agravio que Luscinda le había hecho, y de cómo él se iba adonde gentes no le viesen. »Esto todo era público y notorio en toda la ciudad, y todos hablaban dello; y más hablaron cuando supieron que Luscinda había faltado de casa de sus padres y de la ciudad, pues no la hallaron en toda ella, de que perdían el juicio sus padres y no sabían qué medio se tomar para hallarla. Esto que supe puso en bando mis esperanzas, y tuve por mejor no haber hallado a don Fernando, que no hallarle casado, pareciéndome que aún no estaba del todo cerrada la puerta a mi remedio, dándome yo a entender que podría ser que el cielo hubiese puesto aquel impedimento en el segundo matrimonio, por atraerle a conocer lo que al primero debía, y a caer en la cuenta de que era cristiano y que estaba más obligado a su alma que a los respetos humanos. Todas estas cosas revolvía en mi fantasía, y me consolaba sin tener consuelo, fingiendo unas esperanzas largas y desmayadas, para entretener la vida, que ya aborrezco. »Estando, pues, en la ciudad, sin saber qué hacerme, pues a don Fernando no hallaba, llegó a mis oídos un público pregón, donde se prometía grande hallazgo a quien me hallase, dando las señas de la edad y del mesmo traje que traía; y oí decir que se decía que me había sacado de casa de mis padres el mozo que conmigo vino, cosa que me llegó al alma, por ver cuán de caída andaba mi crédito, pues no bastaba perderle con mi venida, sino añadir el con quién, siendo subjeto tan bajo y tan indigno de mis buenos pensamientos. Al punto que oí el pregón, me salí de la ciudad con mi criado, que ya comenzaba a dar muestras de titubear en la fe que de fidelidad me tenía prometida, y aquella noche nos entramos por lo espeso desta montaña, con el miedo de no ser hallados. Pero, como suele decirse que un mal llama a otro, y que el fin de una desgracia suele ser principio de otra mayor, así me sucedió a mí, porque mi buen criado, hasta entonces fiel y seguro, así como me vio en esta soledad, incitado de su mesma bellaquería antes que de mi hermosura, quiso aprovecharse de la ocasión que, a su parecer, estos yermos le ofrecían; y, con poca vergüenza y menos temor de Dios ni respeto mío, me requirió de amores; y, viendo que yo con feas y justas palabras respondía a las desvergüenzas de sus propósitos, dejó aparte los ruegos, de quien primero pensó aprovecharse, y comenzó a usar de la fuerza. Pero el justo cielo, que pocas o ningunas veces deja de mirar y favorecer a las justas intenciones, favoreció las mías, de manera que con mis pocas fuerzas, y con poco trabajo, di con él por un derrumbadero, donde le dejé, ni sé si muerto o si vivo; y luego, con más ligereza que mi sobresalto y cansancio pedían, me entré por estas montañas, sin llevar otro pensamiento ni otro disignio que esconderme en ellas y huir de mi padre y de aquellos que de su parte me andaban buscando. »Con este deseo, ha no sé cuántos meses que entré en ellas, donde hallé un ganadero que me llevó por su criado a un lugar que está en las entrañas desta sierra, al cual he servido de zagal todo este tiempo, procurando estar siempre en el campo por encubrir estos cabellos que ahora, tan si pensarlo, me han descubierto. Pero toda mi industria y toda mi solicitud fue y ha sido de ningún provecho, pues mi amo vino en conocimiento de que yo no era varón, y nació en él el mesmo mal pensamiento que en mi criado; y, como no siempre la fortuna con los trabajos da los remedios, no hallé derrumbadero ni barranco de donde despeñar y despenar al amo, como le hallé para el criado; y así, tuve por menor inconveniente dejalle y asconderme de nuevo entre estas asperezas que probar con él mis fuerzas o mis disculpas. Digo, pues, que me torné a emboscar, y a buscar donde sin impedimento alguno pudiese con suspiros y lágrimas rogar al cielo se duela de mi desventura y me dé industria y favor para salir della, o para dejar la vida entre estas soledades, sin que quede memoria desta triste, que tan sin culpa suya habrá dado materia para que de ella se hable y murmure en la suya y en las ajenas tierras.» Capítulo XXIX. Que trata de la discreción de la hermosa Dorotea, con otras cosas de mucho gusto y pasatiempo -Esta es, señores, la verdadera historia de mi tragedia: mirad y juzgad ahora si los suspiros que escuchastes, las palabras que oístes y las lágrimas que de mis ojos salían, tenían ocasión bastante para mostrarse en mayor abundancia; y, considerada la calidad de mi desgracia, veréis que será en vano el consuelo, pues es imposible el remedio della. Sólo os ruego (lo que con facilidad podréis y debéis hacer) que me aconsejéis dónde podré pasar la vida sin que me acabe el temor y sobresalto que tengo de ser hallada de los que me buscan; que, aunque sé que el mucho amor que mis padres me tienen me asegura que seré dellos bien recebida, es tanta la vergüenza que me ocupa sólo el pensar que, no como ellos pensaban, tengo de parecer a su presencia, que tengo por mejor desterrarme para siempre de ser vista que no verles el rostro, con pensamiento que ellos miran el mío ajeno de la honestidad que de mí se debían de tener prometida. Calló en diciendo esto, y el rostro se le cubrió de un color que mostró bien claro el sentimiento y vergüenza del alma. En las suyas sintieron los que escuchado la habían tanta lástima como admiración de su desgracia; y, aunque luego quisiera el cura consolarla y aconsejarla, tomó primero la mano Cardenio, diciendo: -En fin, señora, que tú eres la hermosa Dorotea, la hija única del rico Clenardo. Admirada quedó Dorotea cuando oyó el nombre de su padre, y de ver cuán de poco era el que le nombraba, porque ya se ha dicho de la mala manera que Cardenio estaba vestido; y así, le dijo: -Y ¿quién sois vos, hermano, que así sabéis el nombre de mi padre? Porque yo, hasta ahora, si mal no me acuerdo, en todo el discurso del cuento de mi desdicha no le he nombrado. -Soy -respondió Cardenio- aquel sin ventura que, según vos, señora, habéis dicho, Luscinda dijo que era su esposa. Soy el desdichado Cardenio, a quien el mal término de aquel que a vos os ha puesto en el que estáis me ha traído a que me veáis cual me veis: roto, desnudo, falto de todo humano consuelo y, lo que es peor de todo, falto de juicio, pues no le tengo sino cuando al cielo se le antoja dármele por algún breve espacio. Yo, Teodora, soy el que me hallé presente a las sinrazones de don Fernando, y el que aguardó oír el sí que de ser su esposa pronunció Luscinda. Yo soy el que no tuvo ánimo para ver en qué paraba su desmayo, ni lo que resultaba del papel que le fue hallado en el pecho, porque no tuvo el alma sufrimiento para ver tantas desventuras juntas; y así, dejé la casa y la paciencia, y una carta que dejé a un huésped mío, a quien rogué que en manos de Luscinda la pusiese, y víneme a estas soledades, con intención de acabar en ellas la vida, que desde aquel punto aborrecí como mortal enemiga mía. Mas no ha querido la suerte quitármela, contentándose con quitarme el juicio, quizá por guardarme para la buena ventura que he tenido en hallaros; pues, siendo verdad, como creo que lo es, lo que aquí habéis contado, aún podría ser que a entrambos nos tuviese el cielo guardado mejor suceso en nuestros desastres que nosotros pensamos. Porque, presupuesto que Luscinda no puede casarse con don Fernando, por ser mía, ni don Fernando con ella, por ser vuestro, y haberlo ella tan manifiestamente declarado, bien podemos esperar que el cielo nos restituya lo que es nuestro, pues está todavía en ser, y no se ha enajenado ni deshecho. Y, pues este consuelo tenemos, nacido no de muy remota esperanza, ni fundado en desvariadas imaginaciones, suplícoos, señora, que toméis otra resolución en vuestros honrados pensamientos, pues yo la pienso tomar en los míos, acomodándoos a esperar mejor fortuna; que yo os juro, por la fe de caballero y de cristiano, de no desampararos hasta veros en poder de don Fernando, y que, cuando con razones no le pudiere atraer a que conozca lo que os debe, de usar entonces la libertad que me concede el ser caballero, y poder con justo título desafialle, en razón de la sinrazón que os hace, sin acordarme de mis agravios, cuya venganza dejaré al cielo por acudir en la tierra a los vuestros. Con lo que Cardenio dijo se acabó de admirar Dorotea, y, por no saber qué gracias volver a tan grandes ofrecimientos, quiso tomarle los pies para besárselos; mas no lo consintió Cardenio, y el licenciado respondió por entrambos, y aprobó el buen discurso de Cardenio, y, sobre todo, les rogó, aconsejó y persuadió que se fuesen con él a su aldea, donde se podrían reparar de las cosas que les faltaban, y que allí se daría orden cómo buscar a don Fernando, o cómo llevar a Dorotea a sus padres, o hacer lo que más les pareciese conveniente. Cardenio y Dorotea se lo agradecieron, y acetaron la merced que se les ofrecía. El barbero, que a todo había estado suspenso y callado, hizo también su buena plática y se ofreció con no menos voluntad que el cura a todo aquello que fuese bueno para servirles. Contó asimesmo con brevedad la causa que allí los había traído, con la estrañeza de la locura de don Quijote, y cómo aguardaban a su escudero, que había ido a buscalle. Vínosele a la memoria a Cardenio, como por sueños, la pendencia que con don Quijote había tenido y contóla a los demás, mas no supo decir por qué causa fue su quistión. En esto, oyeron voces, y conocieron que el que las daba era Sancho Panza, que, por no haberlos hallado en el lugar donde los dejó, los llamaba a voces. Saliéronle al encuentro, y, preguntándole por don Quijote, les dijo cómo le había hallado desnudo en camisa, flaco, amarillo y muerto de hambre, y suspirando por su señora Dulcinea; y que, puesto que le había dicho que ella le mandaba que saliese de aquel lugar y se fuese al del Toboso, donde le quedaba esperando, había respondido que estaba determinado de no parecer ante su fermosura fasta que hobiese fecho fazañas que le ficiesen digno de su gracia. Y que si aquello pasaba adelante, corría peligro de no venir a ser emperador, como estaba obligado, ni aun arzobispo, que era lo menos que podía ser. Por eso, que mirasen lo que se había de hacer para sacarle de allí. El licenciado le respondió que no tuviese pena, que ellos le sacarían de allí, mal que le pesase. Contó luego a Cardenio y a Dorotea lo que tenían pensado para remedio de don Quijote, a lo menos para llevarle a su casa. A lo cual dijo Dorotea que ella haría la doncella menesterosa mejor que el barbero, y más, que tenía allí vestidos con que hacerlo al natural, y que la dejasen el cargo de saber representar todo aquello que fuese menester para llevar adelante su intento, porque ella había leído muchos libros de caballerías y sabía bien el estilo que tenían las doncellas cuitadas cuando pedían sus dones a los andantes caballeros. -Pues no es menester más -dijo el cura- sino que luego se ponga por obra; que, sin duda, la buena suerte se muestra en favor nuestro, pues, tan sin pensarlo, a vosotros, señores, se os ha comenzado a abrir puerta para vuestro remedio y a nosotros se nos ha facilitado la que habíamos menester. Sacó luego Dorotea de su almohada una saya entera de cierta telilla rica y una mantellina de otra vistosa tela verde, y de una cajita un collar y otras joyas, con que en un instante se adornó de manera que una rica y gran señora parecía. Todo aquello, y más, dijo que había sacado de su casa para lo que se ofreciese, y que hasta entonces no se le había ofrecido ocasión de habello menester. A todos contentó en estremo su mucha gracia, donaire y hermosura, y confirmaron a don Fernando por de poco conocimiento, pues tanta belleza desechaba. Pero el que más se admiró fue Sancho Panza, por parecerle -como era así verdad- que en todos los días de su vida había visto tan hermosa criatura; y así, preguntó al cura con grande ahínco le dijese quién era aquella tan fermosa señora, y qué era lo que buscaba por aquellos andurriales. -Esta hermosa señora -respondió el cura-, Sancho hermano, es, como quien no dice nada, es la heredera por línea recta de varón del gran reino de Micomicón, la cual viene en busca de vuestro amo a pedirle un don, el cual es que le desfaga un tuerto o agravio que un mal gigante le tiene fecho; y, a la fama que de buen caballero vuestro amo tiene por todo lo descubierto, de Guinea ha venido a buscarle esta princesa. -Dichosa buscada y dichoso hallazgo -dijo a esta sazón Sancho Panza-, y más si mi amo es tan venturoso que desfaga ese agravio y enderece ese tuerto, matando a ese hideputa dese gigante que vuestra merced dice; que sí matará si él le encuentra, si ya no fuese fantasma, que contra las fantasmas no tiene mi señor poder alguno. Pero una cosa quiero suplicar a vuestra merced, entre otras, señor licenciado, y es que, porque a mi amo no le tome gana de ser arzobispo, que es lo que yo temo, que vuestra merced le aconseje que se case luego con esta princesa, y así quedará imposibilitado de recebir órdenes arzobispales y vendrá con facilidad a su imperio y yo al fin de mis deseos; que yo he mirado bien en ello y hallo por mi cuenta que no me está bien que mi amo sea arzobispo, porque yo soy inútil para la Iglesia, pues soy casado, y andarme ahora a traer dispensaciones para poder tener renta por la Iglesia, teniendo, como tengo, mujer y hijos, sería nunca acabar. Así que, señor, todo el toque está en que mi amo se case luego con esta señora, que hasta ahora no sé su gracia, y así, no la llamo por su nombre. -Llámase -respondió el cura- la princesa Micomicona, porque, llamándose su reino Micomicón, claro está que ella se ha de llamar así. -No hay duda en eso -respondió Sancho-, que yo he visto a muchos tomar el apellido y alcurnia del lugar donde nacieron, llamándose Pedro de Alcalá, Juan de Úbeda y Diego de Valladolid; y esto mesmo se debe de usar allá en Guinea: tomar las reinas los nombres de sus reinos. -Así debe de ser -dijo el cura-; y en lo del casarse vuestro amo, yo haré en ello todos mis poderíos. Con lo que quedó tan contento Sancho cuanto el cura admirado de su simplicidad, y de ver cuán encajados tenía en la fantasía los mesmos disparates que su amo, pues sin alguna duda se daba a entender que había de venir a ser emperador. Ya, en esto, se había puesto Dorotea sobre la mula del cura y el barbero se había acomodado al rostro la barba de la cola de buey, y dijeron a Sancho que los guiase adonde don Quijote estaba; al cual advirtieron que no dijese que conocía al licenciado ni al barbero, porque en no conocerlos consistía todo el toque de venir a ser emperador su amo; puesto que ni el cura ni Cardenio quisieron ir con ellos, porque no se le acordase a don Quijote la pendencia que con Cardenio había tenido, y el cura porque no era menester por entonces su presencia. Y así, los dejaron ir delante, y ellos los fueron siguiendo a pie, poco a poco. No dejó de avisar el cura lo que había de hacer Dorotea; a lo que ella dijo que descuidasen, que todo se haría, sin faltar punto, como lo pedían y pintaban los libros de caballerías. Tres cuartos de legua habrían andado, cuando descubrieron a don Quijote entre unas intricadas peñas, ya vestido, aunque no armado; y, así como Dorotea le vio y fue informada de Sancho que aquél era don Quijote, dio del azote a su palafrén, siguiéndole el bien barbado barbero. Y, en llegando junto a él, el escudero se arrojó de la mula y fue a tomar en los brazos a Dorotea, la cual, apeándose con grande desenvoltura, se fue a hincar de rodillas ante las de don Quijote; y, aunque él pugnaba por levantarla, ella, sin levantarse, le fabló en esta guisa: -De aquí no me levantaré, ¡oh valeroso y esforzado caballero!, fasta que la vuestra bondad y cortesía me otorgue un don, el cual redundará en honra y prez de vuestra persona, y en pro de la más desconsolada y agraviada doncella que el sol ha visto. Y si es que el valor de vuestro fuerte brazo corresponde a la voz de vuestra inmortal fama, obligado estáis a favorecer a la sin ventura que de tan lueñes tierras viene, al olor de vuestro famoso nombre, buscándoos para remedio de sus desdichas. -No os responderé palabra, fermosa señora -respondió don Quijote-, ni oiré más cosa de vuestra facienda, fasta que os levantéis de tierra. -No me levantaré, señor -respondió la afligida doncella-, si primero, por la vuestra cortesía, no me es otorgado el don que pido. -Yo vos le otorgo y concedo -respondió don Quijote-, como no se haya de cumplir en daño o mengua de mi rey, de mi patria y de aquella que de mi corazón y libertad tiene la llave. -No será en daño ni en mengua de los que decís, mi buen señor -replicó la dolorosa doncella. Y, estando en esto, se llegó Sancho Panza al oído de su señor y muy pasito le dijo: -Bien puede vuestra merced, señor, concederle el don que pide, que no es cosa de nada: sólo es matar a un gigantazo, y esta que lo pide es la alta princesa Micomicona, reina del gran reino Micomicón de Etiopía. -Sea quien fuere -respondió don Quijote-, que yo haré lo que soy obligado y lo que me dicta mi conciencia, conforme a lo que profesado tengo. Y, volviéndose a la doncella, dijo: -La vuestra gran fermosura se levante, que yo le otorgo el don que pedirme quisiere. -Pues el que pido es -dijo la doncella- que la vuestra magnánima persona se venga luego conmigo donde yo le llevare, y me prometa que no se ha de entremeter en otra aventura ni demanda alguna hasta darme venganza de un traidor que, contra todo derecho divino y humano, me tiene usurpado mi reino. -Digo que así lo otorgo -respondió don Quijote-, y así podéis, señora, desde hoy más, desechar la malenconía que os fatiga y hacer que cobre nuevos bríos y fuerzas vuestra desmayada esperanza; que, con el ayuda de Dios y la de mi brazo, vos os veréis presto restituida en vuestro reino y sentada en la silla de vuestro antiguo y grande estado, a pesar y a despecho de los follones que contradecirlo quisieren. Y manos a labor, que en la tardanza dicen que suele estar el peligro. La menesterosa doncella pugnó, con mucha porfía, por besarle las manos, mas don Quijote, que en todo era comedido y cortés caballero, jamás lo consintió; antes, la hizo levantar y la abrazó con mucha cortesía y comedimiento, y mandó a Sancho que requiriese las cinchas a Rocinante y le armase luego al punto. Sancho descolgó las armas, que, como trofeo, de un árbol estaban pendientes, y, requiriendo las cinchas, en un punto armó a su señor; el cual, viéndose armado, dijo: -Vamos de aquí, en el nombre de Dios, a favorecer esta gran señora. Estábase el barbero aún de rodillas, teniendo gran cuenta de disimular la risa y de que no se le cayese la barba, con cuya caída quizá quedaran todos sin conseguir su buena intención; y, viendo que ya el don estaba concedido y con la diligencia que don Quijote se alistaba para ir a cumplirle, se levantó y tomó de la otra mano a su señora, y entre los dos la subieron en la mula. Luego subió don Quijote sobre Rocinante, y el barbero se acomodó en su cabalgadura, quedándose Sancho a pie, donde de nuevo se le renovó la pérdida del rucio, con la falta que entonces le hacía; mas todo lo llevaba con gusto, por parecerle que ya su señor estaba puesto en camino, y muy a pique, de ser emperador; porque sin duda alguna pensaba que se había de casar con aquella princesa, y ser, por lo menos, rey de Micomicón. Sólo le daba pesadumbre el pensar que aquel reino era en tierra de negros, y que la gente que por sus vasallos le diesen habían de ser todos negros; a lo cual hizo luego en su imaginación un buen remedio, y díjose a sí mismo: -¿Qué se me da a mí que mis vasallos sean negros? ¿Habrá más que cargar con ellos y traerlos a España, donde los podré vender, y adonde me los pagarán de contado, de cuyo dinero podré comprar algún título o algún oficio con que vivir descansado todos los días de mi vida? ¡No, sino dormíos, y no tengáis ingenio ni habilidad para disponer de las cosas y para vender treinta o diez mil vasallos en dácame esas pajas! Par Dios que los he de volar, chico con grande, o como pudiere, y que, por negros que sean, los he de volver blancos o amarillos. ¡Llegaos, que me mamo el dedo! Con esto, andaba tan solícito y tan contento que se le olvidaba la pesadumbre de caminar a pie. Todo esto miraban de entre unas breñas Cardenio y el cura, y no sabían qué hacerse para juntarse con ellos; pero el cura, que era gran tracista, imaginó luego lo que harían para conseguir lo que deseaban; y fue que con unas tijeras que traía en un estuche quitó con mucha presteza la barba a Cardenio, y vistióle un capotillo pardo que él traía y diole un herreruelo negro, y él se quedó en calzas y en jubón; y quedó tan otro de lo que antes parecía Cardenio, que él mesmo no se conociera, aunque a un espejo se mirara. Hecho esto, puesto ya que los otros habían pasado adelante en tanto que ellos se disfrazaron, con facilidad salieron al camino real antes que ellos, porque las malezas y malos pasos de aquellos lugares no concedían que anduviesen tanto los de a caballo como los de a pie. En efeto, ellos se pusieron en el llano, a la salida de la sierra, y, así como salió della don Quijote y sus camaradas, el cura se le puso a mirar muy de espacio, dando señales de que le iba reconociendo; y, al cabo de haberle una buena pieza estado mirando, se fue a él abiertos los brazos y diciendo a voces: -Para bien sea hallado el espejo de la caballería, el mi buen compatriote don Quijote de la Mancha, la flor y la nata de la gentileza, el amparo y remedio de los menesterosos, la quintaesencia de los caballeros andantes. Y, diciendo esto, tenía abrazado por la rodilla de la pierna izquierda a don Quijote; el cual, espantado de lo que veía y oía decir y hacer aquel hombre, se le puso a mirar con atención, y, al fin, le conoció y quedó como espantado de verle, y hizo grande fuerza por apearse; mas el cura no lo consintió, por lo cual don Quijote decía: -Déjeme vuestra merced, señor licenciado, que no es razón que yo esté a caballo, y una tan reverenda persona como vuestra merced esté a pie. -Eso no consentiré yo en ningún modo -dijo el cura-: estése la vuestra grandeza a caballo, pues estando a caballo acaba las mayores fazañas y aventuras que en nuestra edad se han visto; que a mí, aunque indigno sacerdote, bastaráme subir en las ancas de una destas mulas destos señores que con vuestra merced caminan, si no lo han por enojo. Y aun haré cuenta que voy caballero sobre el caballo Pegaso, o sobre la cebra o alfana en que cabalgaba aquel famoso moro Muzaraque, que aún hasta ahora yace encantado en la gran cuesta Zulema, que dista poco de la gran Compluto. -Aún no caía yo en tanto, mi señor licenciado -respondió don Quijote-; y yo sé que mi señora la princesa será servida, por mi amor, de mandar a su escudero dé a vuestra merced la silla de su mula, que él podrá acomodarse en las ancas, si es que ella las sufre. -Sí sufre, a lo que yo creo -respondió la princesa-; y también sé que no será menester mandárselo al señor mi escudero, que él es tan cortés y tan cortesano que no consentirá que una persona eclesiástica vaya a pie, pudiendo ir a caballo. -Así es -respondió el barbero. Y, apeándose en un punto, convidó al cura con la silla, y él la tomó sin hacerse mucho de rogar. Y fue el mal que al subir a las ancas el barbero, la mula, que, en efeto, era de alquiler, que para decir que era mala esto basta, alzó un poco los cuartos traseros y dio dos coces en el aire, que, a darlas en el pecho de maese Nicolás, o en la cabeza, él diera al diablo la venida por don Quijote. Con todo eso, le sobresaltaron de manera que cayó en el suelo, con tan poco cuidado de las barbas, que se le cayeron en el suelo; y, como se vio sin ellas, no tuvo otro remedio sino acudir a cubrirse el rostro con ambas manos y a quejarse que le habían derribado las muelas. Don Quijote, como vio todo aquel mazo de barbas, sin quijadas y sin sangre, lejos del rostro del escudero caído, dijo: -¡Vive Dios, que es gran milagro éste! ¡Las barbas le ha derribado y arrancado del rostro, como si las quitaran aposta! El cura, que vio el peligro que corría su invención de ser descubierta, acudió luego a las barbas y fuese con ellas adonde yacía maese Nicolás, dando aún voces todavía, y de un golpe, llegándole la cabeza a su pecho, se las puso, murmurando sobre él unas palabras, que dijo que era cierto ensalmo apropiado para pegar barbas, como lo verían; y, cuando se las tuvo puestas, se apartó, y quedó el escudero tan bien barbado y tan sano como de antes, de que se admiró don Quijote sobremanera, y rogó al cura que cuando tuviese lugar le enseñase aquel ensalmo; que él entendía que su virtud a más que pegar barbas se debía de estender, pues estaba claro que de donde las barbas se quitasen había de quedar la carne llagada y maltrecha, y que, pues todo lo sanaba, a más que barbas aprovechaba. -Así es -dijo el cura, y prometió de enseñársele en la primera ocasión. Concertáronse que por entonces subiese el cura, y a trechos se fuesen los tres mudando, hasta que llegasen a la venta, que estaría hasta dos leguas de allí. Puestos los tres a caballo, es a saber, don Quijote, la princesa y el cura, y los tres a pie, Cardenio, el barbero y Sancho Panza, don Quijote dijo a la doncella: -Vuestra grandeza, señora mía, guíe por donde más gusto le diere. Y, antes que ella respondiese, dijo el licenciado: -¿Hacia qué reino quiere guiar la vuestra señoría? ¿Es, por ventura, hacia el de Micomicón?; que sí debe de ser, o yo sé poco de reinos. Ella, que estaba bien en todo, entendió que había de responder que sí; y así, dijo: -Sí, señor, hacia ese reino es mi camino. -Si así es -dijo el cura-, por la mitad de mi pueblo hemos de pasar, y de allí tomará vuestra merced la derrota de Cartagena, donde se podrá embarcar con la buena ventura; y si hay viento próspero, mar tranquilo y sin borrasca, en poco menos de nueve años se podrá estar a vista de la gran laguna Meona, digo, Meótides, que está poco más de cien jornadas más acá del reino de vuestra grandeza. -Vuestra merced está engañado, señor mío -dijo ella-, porque no ha dos años que yo partí dél, y en verdad que nunca tuve buen tiempo, y, con todo eso, he llegado a ver lo que tanto deseaba, que es al señor don Quijote de la Mancha, cuyas nuevas llegaron a mis oídos así como puse los pies en España, y ellas me movieron a buscarle, para encomendarme en su cortesía y fiar mi justicia del valor de su invencible brazo. -No más: cesen mis alabanzas -dijo a esta sazón don Quijote-, porque soy enemigo de todo género de adulación; y, aunque ésta no lo sea, todavía ofenden mis castas orejas semejantes pláticas. Lo que yo sé decir, señora mía, que ora tenga valor o no, el que tuviere o no tuviere se ha de emplear en vuestro servicio hasta perder la vida; y así, dejando esto para su tiempo, ruego al señor licenciado me diga qué es la causa que le ha traído por estas partes, tan solo, y tan sin criados, y tan a la ligera, que me pone espanto. -A eso yo responderé con brevedad -respondió el cura-, porque sabrá vuestra merced, señor don Quijote, que yo y maese Nicolás, nuestro amigo y nuestro barbero, íbamos a Sevilla a cobrar cierto dinero que un pariente mío que ha muchos años que pasó a Indias me había enviado, y no tan pocos que no pasan de sesenta mil pesos ensayados, que es otro que tal; y, pasando ayer por estos lugares, nos salieron al encuentro cuatro salteadores y nos quitaron hasta las barbas; y de modo nos las quitaron, que le convino al barbero ponérselas postizas; y aun a este mancebo que aquí va -señalando a Cardenio- le pusieron como de nuevo. Y es lo bueno que es pública fama por todos estos contornos que los que nos saltearon son de unos galeotes que dicen que libertó, casi en este mesmo sitio, un hombre tan valiente que, a pesar del comisario y de las guardas, los soltó a todos; y, sin duda alguna, él debía de estar fuera de juicio, o debe de ser tan grande bellaco como ellos, o algún hombre sin alma y sin conciencia, pues quiso soltar al lobo entre las ovejas, a la raposa entre las gallinas, a la mosca entre la miel; quiso defraudar la justicia, ir contra su rey y señor natural, pues fue contra sus justos mandamientos. Quiso, digo, quitar a las galeras sus pies, poner en alboroto a la Santa Hermandad, que había muchos años que reposaba; quiso, finalmente, hacer un hecho por donde se pierda su alma y no se gane su cuerpo. Habíales contado Sancho al cura y al barbero la aventura de los galeotes, que acabó su amo con tanta gloria suya, y por esto cargaba la mano el cura refiriéndola, por ver lo que hacía o decía don Quijote; al cual se le mudaba la color a cada palabra, y no osaba decir que él había sido el libertador de aquella buena gente. -Éstos, pues -dijo el cura-, fueron los que nos robaron; que Dios, por su misericordia, se lo perdone al que no los dejó llevar al debido suplicio. Capítulo XXX. Que trata del gracioso artificio y orden que se tuvo en sacar a nuestro enamorado caballero de la asperísima penitencia en que se había puesto No hubo bien acabado el cura, cuando Sancho dijo: -Pues mía fe, señor licenciado, el que hizo esa fazaña fue mi amo, y no porque yo no le dije antes y le avisé que mirase lo que hacía, y que era pecado darles libertad, porque todos iban allí por grandísimos bellacos. -¡Majadero! -dijo a esta sazón don Quijote-, a los caballeros andantes no les toca ni atañe averiguar si los afligidos, encadenados y opresos que encuentran por los caminos van de aquella manera, o están en aquella angustia, por sus culpas o por sus gracias; sólo le toca ayudarles como a menesterosos, poniendo los ojos en sus penas y no en sus bellaquerías. Yo topé un rosario y sarta de gente mohína y desdichada, y hice con ellos lo que mi religión me pide, y lo demás allá se avenga; y a quien mal le ha parecido, salvo la santa dignidad del señor licenciado y su honrada persona, digo que sabe poco de achaque de caballería, y que miente como un hideputa y mal nacido; y esto le haré conocer con mi espada, donde más largamente se contiene. Y esto dijo afirmándose en los estribos y calándose el morrión; porque la bacía de barbero, que a su cuenta era el yelmo de Mambrino, llevaba colgado del arzón delantero, hasta adobarla del mal tratamiento que la hicieron los galeotes. Dorotea, que era discreta y de gran donaire, como quien ya sabía el menguado humor de don Quijote y que todos hacían burla dél, sino Sancho Panza, no quiso ser para menos, y, viéndole tan enojado, le dijo: -Señor caballero, miémbresele a la vuestra merced el don que me tiene prometido, y que, conforme a él, no puede entremeterse en otra aventura, por urgente que sea; sosiegue vuestra merced el pecho, que si el señor licenciado supiera que por ese invicto brazo habían sido librados los galeotes, él se diera tres puntos en la boca, y aun se mordiera tres veces la lengua, antes que haber dicho palabra que en despecho de vuestra merced redundara. -Eso juro yo bien -dijo el cura-, y aun me hubiera quitado un bigote. -Yo callaré, señora mía -dijo don Quijote-, y reprimiré la justa cólera que ya en mi pecho se había levantado, y iré quieto y pacífico hasta tanto que os cumpla el don prometido; pero, en pago deste buen deseo, os suplico me digáis, si no se os hace de mal, cuál es la vuestra cuita y cuántas, quiénes y cuáles son las personas de quien os tengo de dar debida, satisfecha y entera venganza. -Eso haré yo de gana -respondió Dorotea-, si es que no os enfadan oír lástimas y desgracias. -No enfadará, señora mía -respondió don Quijote. A lo que respondió Dorotea: -Pues así es, esténme vuestras mercedes atentos. No hubo ella dicho esto, cuando Cardenio y el barbero se le pusieron al lado, deseosos de ver cómo fingía su historia la discreta Dorotea; y lo mismo hizo Sancho, que tan engañado iba con ella como su amo. Y ella, después de haberse puesto bien en la silla y prevenídose con toser y hacer otros ademanes, con mucho donaire, comenzó a decir desta manera: -«Primeramente, quiero que vuestras mercedes sepan, señores míos, que a mí me llaman...» Y detúvose aquí un poco, porque se le olvidó el nombre que el cura le había puesto; pero él acudió al remedio, porque entendió en lo que reparaba, y dijo: -No es maravilla, señora mía, que la vuestra grandeza se turbe y empache contando sus desventuras, que ellas suelen ser tales, que muchas veces quitan la memoria a los que maltratan, de tal manera que aun de sus mesmos nombres no se les acuerda, como han hecho con vuestra gran señoría, que se ha olvidado que se llama la princesa Micomicona, legítima heredera del gran reino Micomicón; y con este apuntamiento puede la vuestra grandeza reducir ahora fácilmente a su lastimada memoria todo aquello que contar quisiere. -Así es la verdad -respondió la doncella-, y desde aquí adelante creo que no será menester apuntarme nada, que yo saldré a buen puerto con mi verdadera historia. «La cual es que el rey mi padre, que se llama Tinacrio el Sabidor, fue muy docto en esto que llaman el arte mágica, y alcanzó por su ciencia que mi madre, que se llamaba la reina Jaramilla, había de morir primero que él, y que de allí a poco tiempo él también había de pasar desta vida y yo había de quedar huérfana de padre y madre. Pero decía él que no le fatigaba tanto esto cuanto le ponía en confusión saber, por cosa muy cierta, que un descomunal gigante, señor de una grande ínsula, que casi alinda con nuestro reino, llamado Pandafilando de la Fosca Vista (porque es cosa averiguada que, aunque tiene los ojos en su lugar y derechos, siempre mira al revés, como si fuese bizco, y esto lo hace él de maligno y por poner miedo y espanto a los que mira); digo que supo que este gigante, en sabiendo mi orfandad, había de pasar con gran poderío sobre mi reino y me lo había de quitar todo, sin dejarme una pequeña aldea donde me recogiese; pero que podía escusar toda esta ruina y desgracia si yo me quisiese casar con él; mas, a lo que él entendía, jamás pensaba que me vendría a mí en voluntad de hacer tan desigual casamiento; y dijo en esto la pura verdad, porque jamás me ha pasado por el pensamiento casarme con aquel gigante, pero ni con otro alguno, por grande y desaforado que fuese. Dijo también mi padre que, después que él fuese muerto y viese yo que Pandafilando comenzaba a pasar sobre mi reino, que no aguardase a ponerme en defensa, porque sería destruirme, sino que libremente le dejase desembarazado el reino, si quería escusar la muerte y total destruición de mis buenos y leales vasallos, porque no había de ser posible defenderme de la endiablada fuerza del gigante; sino que luego, con algunos de los míos, me pusiese en camino de las Españas, donde hallaría el remedio de mis males hallando a un caballero andante, cuya fama en este tiempo se estendería por todo este reino, el cual se había de llamar, si mal no me acuerdo, don Azote o don Gigote.» -Don Quijote diría, señora -dijo a esta sazón Sancho Panza-, o, por otro nombre, el Caballero de la Triste Figura. -Así es la verdad -dijo Dorotea-. «Dijo más: que había de ser alto de cuerpo, seco de rostro, y que en el lado derecho, debajo del hombro izquierdo, o por allí junto, había de tener un lunar pardo con ciertos cabellos a manera de cerdas.» En oyendo esto don Quijote, dijo a su escudero: -Ten aquí, Sancho, hijo, ayúdame a desnudar, que quiero ver si soy el caballero que aquel sabio rey dejó profetizado. -Pues, ¿para qué quiere vuestra merced desnudarse? -dijo Dorotea. -Para ver si tengo ese lunar que vuestro padre dijo -respondió don Quijote. -No hay para qué desnudarse -dijo Sancho-, que yo sé que tiene vuestra merced un lunar desas señas en la mitad del espinazo, que es señal de ser hombre fuerte. -Eso basta -dijo Dorotea-, porque con los amigos no se ha de mirar en pocas cosas, y que esté en el hombro o que esté en el espinazo, importa poco; basta que haya lunar, y esté donde estuviere, pues todo es una mesma carne; y, sin duda, acertó mi buen padre en todo, y yo he acertado en encomendarme al señor don Quijote, que él es por quien mi padre dijo, pues las señales del rostro vienen con las de la buena fama que este caballero tiene no sólo en España, pero en toda la Mancha, pues apenas me hube desembarcado en Osuna, cuando oí decir tantas hazañas suyas, que luego me dio el alma que era el mesmo que venía a buscar. -Pues, ¿cómo se desembarcó vuestra merced en Osuna, señora mía -preguntó don Quijote-, si no es puerto de mar? Mas, antes que Dorotea respondiese, tomó el cura la mano y dijo: -Debe de querer decir la señora princesa que, después que desembarcó en Málaga, la primera parte donde oyó nuevas de vuestra merced fue en Osuna. -Eso quise decir -dijo Dorotea. -Y esto lleva camino -dijo el cura-, y prosiga vuestra majestad adelante. -No hay que proseguir -respondió Dorotea-, sino que, finalmente, mi suerte ha sido tan buena en hallar al señor don Quijote, que ya me cuento y tengo por reina y señora de todo mi reino, pues él, por su cortesía y magnificencia, me ha prometido el don de irse conmigo dondequiera que yo le llevare, que no será a otra parte que a ponerle delante de Pandafilando de la Fosca Vista, para que le mate y me restituya lo que tan contra razón me tiene usurpado: que todo esto ha de suceder a pedir de boca, pues así lo dejó profetizado Tinacrio el Sabidor, mi buen padre; el cual también dejó dicho y escrito en letras caldeas, o griegas, que yo no las sé leer, que si este caballero de la profecía, después de haber degollado al gigante, quisiese casarse conmigo, que yo me otorgase luego sin réplica alguna por su legítima esposa, y le diese la posesión de mi reino, junto con la de mi persona. -¿Qué te parece, Sancho amigo? -dijo a este punto don Quijote-. ¿No oyes lo que pasa? ¿No te lo dije yo? Mira si tenemos ya reino que mandar y reina con quien casar. -¡Eso juro yo -dijo Sancho- para el puto que no se casare en abriendo el gaznatico al señor Pandahilado! Pues, ¡monta que es mala la reina! ¡Así se me vuelvan las pulgas de la cama! Y, diciendo esto, dio dos zapatetas en el aire, con muestras de grandísimo contento, y luego fue a tomar las riendas de la mula de Dorotea, y, haciéndola detener, se hincó de rodillas ante ella, suplicándole le diese las manos para besárselas, en señal que la recibía por su reina y señora. ¿Quién no había de reír de los circustantes, viendo la locura del amo y la simplicidad del criado? En efecto, Dorotea se las dio, y le prometió de hacerle gran señor en su reino, cuando el cielo le hiciese tanto bien que se lo dejase cobrar y gozar. Agradecióselo Sancho con tales palabras que renovó la risa en todos. -Ésta, señores -prosiguió Dorotea-, es mi historia: sólo resta por deciros que de cuanta gente de acompañamiento saqué de mi reino no me ha quedado sino sólo este buen barbado escudero, porque todos se anegaron en una gran borrasca que tuvimos a vista del puerto, y él y yo salimos en dos tablas a tierra, como por milagro; y así, es todo milagro y misterio el discurso de mi vida, como lo habréis notado. Y si en alguna cosa he andado demasiada, o no tan acertada como debiera, echad la culpa a lo que el señor licenciado dijo al principio de mi cuento: que los trabajos continuos y extraordinarios quitan la memoria al que los padece. -Ésa no me quitarán a mí, ¡oh alta y valerosa señora! -dijo don Quijote-, cuantos yo pasare en serviros, por grandes y no vistos que sean; y así, de nuevo confirmo el don que os he prometido, y juro de ir con vos al cabo del mundo, hasta verme con el fiero enemigo vuestro, a quien pienso, con el ayuda de Dios y de mi brazo, tajar la cabeza soberbia con los filos desta... no quiero decir buena espada, merced a Ginés de Pasamonte, que me llevó la mía. Esto dijo entre dientes, y prosiguió diciendo: -Y después de habérsela tajado y puéstoos en pacífica posesión de vuestro estado, quedará a vuestra voluntad hacer de vuestra persona lo que más en talante os viniere; porque, mientras que yo tuviere ocupada la memoria y cautiva la voluntad, perdido el entendimiento, a aquella..., y no digo más, no es posible que yo arrostre, ni por pienso, el casarme, aunque fuese con el ave fénix. Parecióle tan mal a Sancho lo que últimamente su amo dijo acerca de no querer casarse, que, con grande enojo, alzando la voz, dijo: -Voto a mí, y juro a mí, que no tiene vuestra merced, señor don Quijote, cabal juicio. Pues, ¿cómo es posible que pone vuestra merced en duda el casarse con tan alta princesa como aquésta? ¿Piensa que le ha de ofrecer la fortuna, tras cada cantillo, semejante ventura como la que ahora se le ofrece? ¿Es, por dicha, más hermosa mi señora Dulcinea? No, por cierto, ni aun con la mitad, y aun estoy por decir que no llega a su zapato de la que está delante. Así, noramala alcanzaré yo el condado que espero, si vuestra merced se anda a pedir cotufas en el golfo. Cásese, cásese luego, encomiéndole yo a Satanás, y tome ese reino que se le viene a las manos de vobis, vobis, y, en siendo rey, hágame marqués o adelantado, y luego, siquiera se lo lleve el diablo todo. Don Quijote, que tales blasfemias oyó decir contra su señora Dulcinea, no lo pudo sufrir, y, alzando el lanzón, sin hablalle palabra a Sancho y sin decirle esta boca es mía, le dio tales dos palos que dio con él en tierra; y si no fuera porque Dorotea le dio voces que no le diera más, sin duda le quitara allí la vida. -¿Pensáis -le dijo a cabo de rato-, villano ruin, que ha de haber lugar siempre para ponerme la mano en la horcajadura, y que todo ha de ser errar vos y perdonaros yo? Pues no lo penséis, bellaco descomulgado, que sin duda lo estás, pues has puesto lengua en la sin par Dulcinea. ¿Y no sabéis vos, gañán, faquín, belitre, que si no fuese por el valor que ella infunde en mi brazo, que no le tendría yo para matar una pulga? Decid, socarrón de lengua viperina, ¿y quién pensáis que ha ganado este reino y cortado la cabeza a este gigante, y héchoos a vos marqués, que todo esto doy ya por hecho y por cosa pasada en cosa juzgada, si no es el valor de Dulcinea, tomando a mi brazo por instrumento de sus hazañas? Ella pelea en mí, y vence en mí, y yo vivo y respiro en ella, y tengo vida y ser. ¡Oh hideputa bellaco, y cómo sois desagradecido: que os veis levantado del polvo de la tierra a ser señor de título, y correspondéis a tan buena obra con decir mal de quien os la hizo! No estaba tan maltrecho Sancho que no oyese todo cuanto su amo le decía, y, levantándose con un poco de presteza, se fue a poner detrás del palafrén de Dorotea, y desde allí dijo a su amo: -Dígame, señor: si vuestra merced tiene determinado de no casarse con esta gran princesa, claro está que no será el reino suyo; y, no siéndolo, ¿qué mercedes me puede hacer? Esto es de lo que yo me quejo; cásese vuestra merced una por una con esta reina, ahora que la tenemos aquí como llovida del cielo, y después puede volverse con mi señora Dulcinea; que reyes debe de haber habido en el mundo que hayan sido amancebados. En lo de la hermosura no me entremeto; que, en verdad, si va a decirla, que entrambas me parecen bien, puesto que yo nunca he visto a la señora Dulcinea. -¿Cómo que no la has visto, traidor blasfemo? -dijo don Quijote-. Pues, ¿no acabas de traerme ahora un recado de su parte? -Digo que no la he visto tan despacio -dijo Sancho- que pueda haber notado particularmente su hermosura y sus buenas partes punto por punto; pero así, a bulto, me parece bien. -Ahora te disculpo -dijo don Quijote-, y perdóname el enojo que te he dado, que los primeros movimientos no son en manos de los hombres. -Ya yo lo veo -respondió Sancho-; y así, en mí la gana de hablar siempre es primero movimiento, y no puedo dejar de decir, por una vez siquiera, lo que me viene a la lengua. -Con todo eso -dijo don Quijote-, mira, Sancho, lo que hablas, porque tantas veces va el cantarillo a la fuente..., y no te digo más. -Ahora bien -respondió Sancho-, Dios está en el cielo, que ve las trampas, y será juez de quién hace más mal: yo en no hablar bien, o vuestra merced en obrallo. -No haya más -dijo Dorotea-: corred, Sancho, y besad la mano a vuestro señor, y pedilde perdón, y de aquí adelante andad más atentado en vuestras alabanzas y vituperios, y no digáis mal de aquesa señora Tobosa, a quien yo no conozco si no es para servilla, y tened confianza en Dios, que no os ha de faltar un estado donde viváis como un príncipe. Fue Sancho cabizbajo y pidió la mano a su señor, y él se la dio con reposado continente; y, después que se la hubo besado, le echó la bendición, y dijo a Sancho que se adelantasen un poco, que tenía que preguntalle y que departir con él cosas de mucha importancia. Hízolo así Sancho y apartáronse los dos algo adelante, y díjole don Quijote: -Después que veniste, no he tenido lugar ni espacio para preguntarte muchas cosas de particularidad acerca de la embajada que llevaste y de la respuesta que trujiste; y ahora, pues la fortuna nos ha concedido tiempo y lugar, no me niegues tú la ventura que puedes darme con tan buenas nuevas. -Pregunte vuestra merced lo que quisiere -respondió Sancho-, que a todo daré tan buena salida como tuve la entrada. Pero suplico a vuestra merced, señor mío, que no sea de aquí adelante tan vengativo. -¿Por qué lo dices, Sancho? -dijo don Quijote. -Dígolo -respondió- porque estos palos de agora más fueron por la pendencia que entre los dos trabó el diablo la otra noche, que por lo que dije contra mi señora Dulcinea, a quien amo y reverencio como a una reliquia, aunque en ella no lo haya, sólo por ser cosa de vuestra merced. -No tornes a esas pláticas, Sancho, por tu vida -dijo don Quijote-, que me dan pesadumbre; ya te perdoné entonces, y bien sabes tú que suele decirse: a pecado nuevo, penitencia nueva. En tanto que los dos iban en estas pláticas, dijo el cura a Dorotea que había andado muy discreta, así en el cuento como en la brevedad dél, y en la similitud que tuvo con los de los libros de caballerías. Ella dijo que muchos ratos se había entretenido en leellos, pero que no sabía ella dónde eran las provincias ni puertos de mar, y que así había dicho a tiento que se había desembarcado en Osuna. -Yo lo entendí así -dijo el cura-, y por eso acudí luego a decir lo que dije, con que se acomodó todo. Pero, ¿no es cosa estraña ver con cuánta facilidad cree este desventurado hidalgo todas estas invenciones y mentiras, sólo porque llevan el estilo y modo de las necedades de sus libros? -Sí es -dijo Cardenio-, y tan rara y nunca vista, que yo no sé si queriendo inventarla y fabricarla mentirosamente, hubiera tan agudo ingenio que pudiera dar en ella. -Pues otra cosa hay en ello -dijo el cura-: que fuera de las simplicidades que este buen hidalgo dice tocantes a su locura, si le tratan de otras cosas, discurre con bonísimas razones y muestra tener un entendimiento claro y apacible en todo. De manera que, como no le toquen en sus caballerías, no habrá nadie que le juzgue sino por de muy buen entendimiento. En tanto que ellos iban en esta conversación, prosiguió don Quijote con la suya y dijo a Sancho: -Echemos, Panza amigo, pelillos a la mar en esto de nuestras pendencias, y dime ahora, sin tener cuenta con enojo ni rencor alguno: ¿Dónde, cómo y cuándo hallaste a Dulcinea? ¿Qué hacía? ¿Qué le dijiste? ¿Qué te respondió? ¿Qué rostro hizo cuando leía mi carta? ¿Quién te la trasladó? Y todo aquello que vieres que en este caso es digno de saberse, de preguntarse y satisfacerse, sin que añadas o mientas por darme gusto, ni menos te acortes por no quitármele. -Señor -respondió Sancho-, si va a decir la verdad, la carta no me la trasladó nadie, porque yo no llevé carta alguna. -Así es como tú dices -dijo don Quijote-, porque el librillo de memoria donde yo la escribí le hallé en mi poder a cabo de dos días de tu partida, lo cual me causó grandísima pena, por no saber lo que habías tú de hacer cuando te vieses sin carta, y creí siempre que te volvieras desde el lugar donde la echaras menos. -Así fuera -respondió Sancho-, si no la hubiera yo tomado en la memoria cuando vuestra merced me la leyó, de manera que se la dije a un sacristán, que me la trasladó del entendimiento, tan punto por punto, que dijo que en todos los días de su vida, aunque había leído muchas cartas de descomunión, no había visto ni leído tan linda carta como aquélla. -Y ¿tiénesla todavía en la memoria, Sancho? -dijo don Quijote. -No, señor -respondió Sancho-, porque después que la di, como vi que no había de ser de más provecho, di en olvidalla. Y si algo se me acuerda, es aquello del sobajada, digo, del soberana señora, y lo último: Vuestro hasta la muerte, el Caballero de la Triste Figura. Y, en medio destas dos cosas, le puse más de trecientas almas, y vidas, y ojos míos. Capítulo XXXI. De los sabrosos razonamientos que pasaron entre don Quijote y Sancho Panza, su escudero, con otros sucesos -Todo eso no me descontenta; prosigue adelante -dijo don Quijote-. Llegaste, ¿y qué hacía aquella reina de la hermosura? A buen seguro que la hallaste ensartando perlas, o bordando alguna empresa con oro de cañutillo para este su cautivo caballero. -No la hallé -respondió Sancho- sino ahechando dos hanegas de trigo en un corral de su casa. -Pues haz cuenta -dijo don Quijote- que los granos de aquel trigo eran granos de perlas, tocados de sus manos. Y si miraste, amigo, el trigo ¿era candeal, o trechel? -No era sino rubión -respondió Sancho. -Pues yo te aseguro -dijo don Quijote- que, ahechado por sus manos, hizo pan candeal, sin duda alguna. Pero pasa adelante: cuando le diste mi carta, ¿besóla? ¿Púsosela sobre la cabeza? ¿Hizo alguna ceremonia digna de tal carta, o qué hizo? -Cuando yo se la iba a dar -respondió Sancho-, ella estaba en la fuga del meneo de una buena parte de trigo que tenía en la criba, y díjome: ''Poned, amigo, esa carta sobre aquel costal, que no la puedo leer hasta que acabe de acribar todo lo que aquí está''. -¡Discreta señora! -dijo don Quijote-. Eso debió de ser por leerla despacio y recrearse con ella. Adelante, Sancho: y, en tanto que estaba en su menester, ¿qué coloquios pasó contigo? ¿Qué te preguntó de mí? Y tú, ¿qué le respondiste? Acaba, cuéntamelo todo; no se te quede en el tintero una mínima. -Ella no me preguntó nada -dijo Sancho-, mas yo le dije de la manera que vuestra merced, por su servicio, quedaba haciendo penitencia, desnudo de la cintura arriba, metido entre estas sierras como si fuera salvaje, durmiendo en el suelo, sin comer pan a manteles ni sin peinarse la barba, llorando y maldiciendo su fortuna. -En decir que maldecía mi fortuna dijiste mal -dijo don Quijote-, porque antes la bendigo y bendeciré todos los días de mi vida, por haberme hecho digno de merecer amar tan alta señora como Dulcinea del Toboso. -Tan alta es -respondió Sancho-, que a buena fe que me lleva a mí más de un coto. -Pues, ¿cómo, Sancho? -dijo don Quijote-. ¿Haste medido tú con ella? -Medíme en esta manera -respondió Sancho-: que, llegándole a ayudar a poner un costal de trigo sobre un jumento, llegamos tan juntos que eché de ver que me llevaba más de un gran palmo. -Pues ¡es verdad -replicó don Quijote- que no acompaña esa grandeza y la adorna con mil millones y gracias del alma! Pero no me negarás, Sancho, una cosa: cuando llegaste junto a ella, ¿no sentiste un olor sabeo, una fragancia aromática, y un no sé qué de bueno, que yo no acierto a dalle nombre? Digo, ¿un tuho o tufo como si estuvieras en la tienda de algún curioso guantero? -Lo que sé decir -dijo Sancho- es que sentí un olorcillo algo hombruno; y debía de ser que ella, con el mucho ejercicio, estaba sudada y algo correosa. -No sería eso -respondió don Quijote-, sino que tú debías de estar romadizado, o te debiste de oler a ti mismo; porque yo sé bien a lo que huele aquella rosa entre espinas, aquel lirio del campo, aquel ámbar desleído. -Todo puede ser -respondió Sancho-, que muchas veces sale de mí aquel olor que entonces me pareció que salía de su merced de la señora Dulcinea; pero no hay de qué maravillarse, que un diablo parece a otro. -Y bien -prosiguió don Quijote-, he aquí que acabó de limpiar su trigo y de enviallo al molino. ¿Qué hizo cuando leyó la carta? -La carta -dijo Sancho- no la leyó, porque dijo que no sabía leer ni escribir; antes, la rasgó y la hizo menudas piezas, diciendo que no la quería dar a leer a nadie, porque no se supiesen en el lugar sus secretos, y que bastaba lo que yo le había dicho de palabra acerca del amor que vuestra merced le tenía y de la penitencia extraordinaria que por su causa quedaba haciendo. Y, finalmente, me dijo que dijese a vuestra merced que le besaba las manos, y que allí quedaba con más deseo de verle que de escribirle; y que, así, le suplicaba y mandaba que, vista la presente, saliese de aquellos matorrales y se dejase de hacer disparates, y se pusiese luego luego en camino del Toboso, si otra cosa de más importancia no le sucediese, porque tenía gran deseo de ver a vuestra merced. Rióse mucho cuando le dije como se llamaba vuestra merced el Caballero de la Triste Figura. Preguntéle si había ido allá el vizcaíno de marras; díjome que sí, y que era un hombre muy de bien. También le pregunté por los galeotes, mas díjome que no había visto hasta entonces alguno. -Todo va bien hasta agora -dijo don Quijote-. Pero dime: ¿qué joya fue la que te dio, al despedirte, por las nuevas que de mí le llevaste? Porque es usada y antigua costumbre entre los caballeros y damas andantes dar a los escuderos, doncellas o enanos que les llevan nuevas, de sus damas a ellos, a ellas de sus andantes, alguna rica joya en albricias, en agradecimiento de su recado. -Bien puede eso ser así, y yo la tengo por buena usanza; pero eso debió de ser en los tiempos pasados, que ahora sólo se debe de acostumbrar a dar un pedazo de pan y queso, que esto fue lo que me dio mi señora Dulcinea, por las bardas de un corral, cuando della me despedí; y aun, por más señas, era el queso ovejuno. -Es liberal en estremo -dijo don Quijote-, y si no te dio joya de oro, sin duda debió de ser porque no la tendría allí a la mano para dártela; pero buenas son mangas después de Pascua: yo la veré, y se satisfará todo. ¿Sabes de qué estoy maravillado, Sancho? De que me parece que fuiste y veniste por los aires, pues poco más de tres días has tardado en ir y venir desde aquí al Toboso, habiendo de aquí allá más de treinta leguas; por lo cual me doy a entender que aquel sabio nigromante que tiene cuenta con mis cosas y es mi amigo (porque por fuerza le hay, y le ha de haber, so pena que yo no sería buen caballero andante); digo que este tal te debió de ayudar a caminar, sin que tú lo sintieses; que hay sabio déstos que coge a un caballero andante durmiendo en su cama, y, sin saber cómo o en qué manera, amanece otro día más de mil leguas de donde anocheció. Y si no fuese por esto, no se podrían socorrer en sus peligros los caballeros andantes unos a otros, como se socorren a cada paso. Que acaece estar uno peleando en las sierras de Armenia con algún endriago, o con algún fiero vestiglo, o con otro caballero, donde lleva lo peor de la batalla y está ya a punto de muerte, y cuando no os me cato, asoma por acullá, encima de una nube, o sobre un carro de fuego, otro caballero amigo suyo, que poco antes se hallaba en Ingalaterra, que le favorece y libra de la muerte, y a la noche se halla en su posada, cenando muy a su sabor; y suele haber de la una a la otra parte dos o tres mil leguas. Y todo esto se hace por industria y sabiduría destos sabios encantadores que tienen cuidado destos valerosos caballeros. Así que, amigo Sancho, no se me hace dificultoso creer que en tan breve tiempo hayas ido y venido desde este lugar al del Toboso, pues, como tengo dicho, algún sabio amigo te debió de llevar en volandillas, sin que tú lo sintieses. -Así sería -dijo Sancho-; porque a buena fe que andaba Rocinante como si fuera asno de gitano con azogue en los oídos. -Y ¡cómo si llevaba azogue! -dijo don Quijote-, y aun una legión de demonios, que es gente que camina y hace caminar, sin cansarse, todo aquello que se les antoja. Pero, dejando esto aparte, ¿qué te parece a ti que debo yo de hacer ahora cerca de lo que mi señora me manda que la vaya a ver?; que, aunque yo veo que estoy obligado a cumplir su mandamiento, véome también imposibilitado del don que he prometido a la princesa que con nosotros viene, y fuérzame la ley de caballería a cumplir mi palabra antes que mi gusto. Por una parte, me acosa y fatiga el deseo de ver a mi señora; por otra, me incita y llama la prometida fe y la gloria que he de alcanzar en esta empresa. Pero lo que pienso hacer será caminar apriesa y llegar presto donde está este gigante, y, en llegando, le cortaré la cabeza, y pondré a la princesa pacíficamente en su estado, y al punto daré la vuelta a ver a la luz que mis sentidos alumbra, a la cual daré tales disculpas que ella venga a tener por buena mi tardanza, pues verá que todo redunda en aumento de su gloria y fama, pues cuanta yo he alcanzado, alcanzo y alcanzare por las armas en esta vida, toda me viene del favor que ella me da y de ser yo suyo. -¡Ay -dijo Sancho-, y cómo está vuestra merced lastimado de esos cascos! Pues dígame, señor: ¿piensa vuestra merced caminar este camino en balde, y dejar pasar y perder un tan rico y tan principal casamiento como éste, donde le dan en dote un reino, que a buena verdad que he oído decir que tiene más de veinte mil leguas de contorno, y que es abundantísimo de todas las cosas que son necesarias para el sustento de la vida humana, y que es mayor que Portugal y que Castilla juntos? Calle, por amor de Dios, y tenga vergüenza de lo que ha dicho, y tome mi consejo, y perdóneme, y cásese luego en el primer lugar que haya cura; y si no, ahí está nuestro licenciado, que lo hará de perlas. Y advierta que ya tengo edad para dar consejos, y que este que le doy le viene de molde, y que más vale pájaro en mano que buitre volando, porque quien bien tiene y mal escoge, por bien que se enoja no se venga. -Mira, Sancho -respondió don Quijote-: si el consejo que me das de que me case es porque sea luego rey, en matando al gigante, y tenga cómodo para hacerte mercedes y darte lo prometido, hágote saber que sin casarme podré cumplir tu deseo muy fácilmente, porque yo sacaré de adahala, antes de entrar en la batalla, que, saliendo vencedor della, ya que no me case, me han de dar una parte del reino, para que la pueda dar a quien yo quisiere; y, en dándomela, ¿a quién quieres tú que la dé sino a ti? -Eso está claro -respondió Sancho-, pero mire vuestra merced que la escoja hacia la marina, porque, si no me contentare la vivienda, pueda embarcar mis negros vasallos y hacer dellos lo que ya he dicho. Y vuestra merced no se cure de ir por agora a ver a mi señora Dulcinea, sino váyase a matar al gigante, y concluyamos este negocio; que por Dios que se me asienta que ha de ser de mucha honra y de mucho provecho. -Dígote, Sancho -dijo don Quijote-, que estás en lo cierto, y que habré de tomar tu consejo en cuanto el ir antes con la princesa que a ver a Dulcinea. Y avísote que no digas nada a nadie, ni a los que con nosotros vienen, de lo que aquí hemos departido y tratado; que, pues Dulcinea es tan recatada que no quiere que se sepan sus pensamientos, no será bien que yo, ni otro por mí, los descubra. -Pues si eso es así -dijo Sancho-, ¿cómo hace vuestra merced que todos los que vence por su brazo se vayan a presentar ante mi señora Dulcinea, siendo esto firma de su nombre que la quiere bien y que es su enamorado? Y, siendo forzoso que los que fueren se han de ir a hincar de finojos ante su presencia, y decir que van de parte de vuestra merced a dalle la obediencia, ¿cómo se pueden encubrir los pensamientos de entrambos? -¡Oh, qué necio y qué simple que eres! -dijo don Quijote-. ¿Tú no ves, Sancho, que eso todo redunda en su mayor ensalzamiento? Porque has de saber que en este nuestro estilo de caballería es gran honra tener una dama muchos caballeros andantes que la sirvan, sin que se estiendan más sus pensamientos que a servilla, por sólo ser ella quien es, sin esperar otro premio de sus muchos y buenos deseos, sino que ella se contente de acetarlos por sus caballeros. -Con esa manera de amor -dijo Sancho- he oído yo predicar que se ha de amar a Nuestro Señor, por sí solo, sin que nos mueva esperanza de gloria o temor de pena. Aunque yo le querría amar y servir por lo que pudiese. -¡Válate el diablo por villano -dijo don Quijote-, y qué de discreciones dices a las veces! No parece sino que has estudiado. -Pues a fe mía que no sé leer -respondió Sancho. En esto, les dio voces maese Nicolás que esperasen un poco, que querían detenerse a beber en una fontecilla que allí estaba. Detúvose don Quijote, con no poco gusto de Sancho, que ya estaba cansado de mentir tanto y temía no le cogiese su amo a palabras; porque, puesto que él sabía que Dulcinea era una labradora del Toboso, no la había visto en toda su vida. Habíase en este tiempo vestido Cardenio los vestidos que Dorotea traía cuando la hallaron, que, aunque no eran muy buenos, hacían mucha ventaja a los que dejaba. Apeáronse junto a la fuente, y con lo que el cura se acomodó en la venta satisficieron, aunque poco, la mucha hambre que todos traían. Estando en esto, acertó a pasar por allí un muchacho que iba de camino, el cual, poniéndose a mirar con mucha atención a los que en la fuente estaban, de allí a poco arremetió a don Quijote, y, abrazándole por las piernas, comenzó a llorar muy de propósito, diciendo: -¡Ay, señor mío! ¿No me conoce vuestra merced? Pues míreme bien, que yo soy aquel mozo Andrés que quitó vuestra merced de la encina donde estaba atado. Reconocióle don Quijote, y, asiéndole por la mano, se volvió a los que allí estaban y dijo: -Porque vean vuestras mercedes cuán de importancia es haber caballeros andantes en el mundo, que desfagan los tuertos y agravios que en él se hacen por los insolentes y malos hombres que en él viven, sepan vuestras mercedes que los días pasados, pasando yo por un bosque, oí unos gritos y unas voces muy lastimosas, como de persona afligida y menesterosa; acudí luego, llevado de mi obligación, hacia la parte donde me pareció que las lamentables voces sonaban, y hallé atado a una encina a este muchacho que ahora está delante (de lo que me huelgo en el alma, porque será testigo que no me dejará mentir en nada); digo que estaba atado a la encina, desnudo del medio cuerpo arriba, y estábale abriendo a azotes con las riendas de una yegua un villano, que después supe que era amo suyo; y, así como yo le vi, le pregunté la causa de tan atroz vapulamiento; respondió el zafio que le azotaba porque era su criado, y que ciertos descuidos que tenía nacían más de ladrón que de simple; a lo cual este niño dijo: ''Señor, no me azota sino porque le pido mi salario''. El amo replicó no sé qué arengas y disculpas, las cuales, aunque de mí fueron oídas, no fueron admitidas. En resolución, yo le hice desatar, y tomé juramento al villano de que le llevaría consigo y le pagaría un real sobre otro, y aun sahumados. ¿No es verdad todo esto, hijo Andrés? ¿No notaste con cuánto imperio se lo mandé, y con cuánta humildad prometió de hacer todo cuanto yo le impuse, y notifiqué y quise? Responde; no te turbes ni dudes en nada: di lo que pasó a estos señores, porque se vea y considere ser del provecho que digo haber caballeros andantes por los caminos. -Todo lo que vuestra merced ha dicho es mucha verdad -respondió el muchacho-, pero el fin del negocio sucedió muy al revés de lo que vuestra merced se imagina. -¿Cómo al revés? -replicó don Quijote-; luego, ¿no te pagó el villano? -No sólo no me pagó -respondió el muchacho-, pero, así como vuestra merced traspuso del bosque y quedamos solos, me volvió a atar a la mesma encina, y me dio de nuevo tantos azotes que quedé hecho un San Bartolomé desollado; y, a cada azote que me daba, me decía un donaire y chufeta acerca de hacer burla de vuestra merced, que, a no sentir yo tanto dolor, me riera de lo que decía. En efeto: él me paró tal, que hasta ahora he estado curándome en un hospital del mal que el mal villano entonces me hizo. De todo lo cual tiene vuestra merced la culpa, porque si se fuera su camino adelante y no viniera donde no le llamaban, ni se entremetiera en negocios ajenos, mi amo se contentara con darme una o dos docenas de azotes, y luego me soltara y pagara cuanto me debía. Mas, como vuestra merced le deshonró tan sin propósito y le dijo tantas villanías, encendiósele la cólera, y, como no la pudo vengar en vuestra merced, cuando se vio solo descargó sobre mí el nublado, de modo que me parece que no seré más hombre en toda mi vida. -El daño estuvo -dijo don Quijote- en irme yo de allí; que no me había de ir hasta dejarte pagado, porque bien debía yo de saber, por luengas experiencias, que no hay villano que guarde palabra que tiene, si él vee que no le está bien guardalla. Pero ya te acuerdas, Andrés, que yo juré que si no te pagaba, que había de ir a buscarle, y que le había de hallar, aunque se escondiese en el vientre de la ballena. -Así es la verdad -dijo Andrés-, pero no aprovechó nada. -Ahora verás si aprovecha -dijo don Quijote. Y, diciendo esto, se levantó muy apriesa y mandó a Sancho que enfrenase a Rocinante, que estaba paciendo en tanto que ellos comían. Preguntóle Dorotea qué era lo que hacer quería. Él le respondió que quería ir a buscar al villano y castigalle de tan mal término, y hacer pagado a Andrés hasta el último maravedí, a despecho y pesar de cuantos villanos hubiese en el mundo. A lo que ella respondió que advirtiese que no podía, conforme al don prometido, entremeterse en ninguna empresa hasta acabar la suya; y que, pues esto sabía él mejor que otro alguno, que sosegase el pecho hasta la vuelta de su reino. -Así es verdad -respondió don Quijote-, y es forzoso que Andrés tenga paciencia hasta la vuelta, como vos, señora, decís; que yo le torno a jurar y a prometer de nuevo de no parar hasta hacerle vengado y pagado. -No me creo desos juramentos -dijo Andrés-; más quisiera tener agora con qué llegar a Sevilla que todas las venganzas del mundo: déme, si tiene ahí, algo que coma y lleve, y quédese con Dios su merced y todos los caballeros andantes; que tan bien andantes sean ellos para consigo como lo han sido para conmigo. Sacó de su repuesto Sancho un pedazo de pan y otro de queso, y, dándoselo al mozo, le dijo: -Tomá, hermano Andrés, que a todos nos alcanza parte de vuestra desgracia. -Pues, ¿qué parte os alcanza a vos? -preguntó Andrés. -Esta parte de queso y pan que os doy -respondió Sancho-, que Dios sabe si me ha de hacer falta o no; porque os hago saber, amigo, que los escuderos de los caballeros andantes estamos sujetos a mucha hambre y a mala ventura, y aun a otras cosas que se sienten mejor que se dicen. Andrés asió de su pan y queso, y, viendo que nadie le daba otra cosa, abajó su cabeza y tomó el camino en las manos, como suele decirse. Bien es verdad que, al partirse, dijo a don Quijote: -Por amor de Dios, señor caballero andante, que si otra vez me encontrare, aunque vea que me hacen pedazos, no me socorra ni ayude, sino déjeme con mi desgracia; que no será tanta, que no sea mayor la que me vendrá de su ayuda de vuestra merced, a quien Dios maldiga, y a todos cuantos caballeros andantes han nacido en el mundo. Ãbase a levantar don Quijote para castigalle, mas él se puso a correr de modo que ninguno se atrevió a seguille. Quedó corridísimo don Quijote del cuento de Andrés, y fue menester que los demás tuviesen mucha cuenta con no reírse, por no acaballe de correr del todo. Capítulo XXXII. Que trata de lo que sucedió en la venta a toda la cuadrilla de don Quijote Acabóse la buena comida, ensillaron luego, y, sin que les sucediese cosa digna de contar, llegaron otro día a la venta, espanto y asombro de Sancho Panza; y, aunque él quisiera no entrar en ella, no lo pudo huir. La ventera, ventero, su hija y Maritornes, que vieron venir a don Quijote y a Sancho, les salieron a recebir con muestras de mucha alegría, y él las recibió con grave continente y aplauso, y díjoles que le aderezasen otro mejor lecho que la vez pasada; a lo cual le respondió la huéspeda que como la pagase mejor que la otra vez, que ella se la daría de príncipes. Don Quijote dijo que sí haría, y así, le aderezaron uno razonable en el mismo caramanchón de marras, y él se acostó luego, porque venía muy quebrantado y falto de juicio. No se hubo bien encerrado, cuando la huéspeda arremetió al barbero, y, asiéndole de la barba, dijo: -Para mi santiguada, que no se ha aún de aprovechar más de mi rabo para su barba, y que me ha de volver mi cola; que anda lo de mi marido por esos suelos, que es vergüenza; digo, el peine, que solía yo colgar de mi buena cola. No se la quería dar el barbero, aunque ella más tiraba, hasta que el licenciado le dijo que se la diese, que ya no era menester más usar de aquella industria, sino que se descubriese y mostrase en su misma forma, y dijese a don Quijote que cuando le despojaron los ladrones galeotes se habían venido a aquella venta huyendo; y que si preguntase por el escudero de la princesa, le dirían que ella le había enviado adelante a dar aviso a los de su reino como ella iba y llevaba consigo el libertador de todos. Con esto, dio de buena gana la cola a la ventera el barbero, y asimismo le volvieron todos los adherentes que había prestado para la libertad de don Quijote. Espantáronse todos los de la venta de la hermosura de Dorotea, y aun del buen talle del zagal Cardenio. Hizo el cura que les aderezasen de comer de lo que en la venta hubiese, y el huésped, con esperanza de mejor paga, con diligencia les aderezó una razonable comida; y a todo esto dormía don Quijote, y fueron de parecer de no despertalle, porque más provecho le haría por entonces el dormir que el comer. Trataron sobre comida, estando delante el ventero, su mujer, su hija, Maritornes, todos los pasajeros, de la estraña locura de don Quijote y del modo que le habían hallado. La huéspeda les contó lo que con él y con el arriero les había acontecido, y, mirando si acaso estaba allí Sancho, como no le viese, contó todo lo de su manteamiento, de que no poco gusto recibieron. Y, como el cura dijese que los libros de caballerías que don Quijote había leído le habían vuelto el juicio, dijo el ventero: -No sé yo cómo puede ser eso; que en verdad que, a lo que yo entiendo, no hay mejor letrado en el mundo, y que tengo ahí dos o tres dellos, con otros papeles, que verdaderamente me han dado la vida, no sólo a mí, sino a otros muchos. Porque, cuando es tiempo de la siega, se recogen aquí, las fiestas, muchos segadores, y siempre hay algunos que saben leer, el cual coge uno destos libros en las manos, y rodeámonos dél más de treinta, y estámosle escuchando con tanto gusto que nos quita mil canas; a lo menos, de mí sé decir que cuando oyo decir aquellos furibundos y terribles golpes que los caballeros pegan, que me toma gana de hacer otro tanto, y que querría estar oyéndolos noches y días. -Y yo ni más ni menos -dijo la ventera-, porque nunca tengo buen rato en mi casa sino aquel que vos estáis escuchando leer: que estáis tan embobado, que no os acordáis de reñir por entonces. -Así es la verdad -dijo Maritornes-, y a buena fe que yo también gusto mucho de oír aquellas cosas, que son muy lindas; y más, cuando cuentan que se está la otra señora debajo de unos naranjos abrazada con su caballero, y que les está una dueña haciéndoles la guarda, muerta de envidia y con mucho sobresalto. Digo que todo esto es cosa de mieles. -Y a vos ¿qué os parece, señora doncella? -dijo el cura, hablando con la hija del ventero. -No sé, señor, en mi ánima -respondió ella-; también yo lo escucho, y en verdad que, aunque no lo entiendo, que recibo gusto en oíllo; pero no gusto yo de los golpes de que mi padre gusta, sino de las lamentaciones que los caballeros hacen cuando están ausentes de sus señoras: que en verdad que algunas veces me hacen llorar de compasión que les tengo. -Luego, ¿bien las remediárades vos, señora doncella -dijo Dorotea-, si por vos lloraran? -No sé lo que me hiciera -respondió la moza-; sólo sé que hay algunas señoras de aquéllas tan crueles, que las llaman sus caballeros tigres y leones y otras mil inmundicias. Y, ¡Jesús!, yo no sé qué gente es aquélla tan desalmada y tan sin conciencia, que por no mirar a un hombre honrado, le dejan que se muera, o que se vuelva loco. Yo no sé para qué es tanto melindre: si lo hacen de honradas, cásense con ellos, que ellos no desean otra cosa. -Calla, niña -dijo la ventera-, que parece que sabes mucho destas cosas, y no está bien a las doncellas saber ni hablar tanto. -Como me lo pregunta este señor -respondió ella-, no pude dejar de respondelle. -Ahora bien -dijo el cura-, traedme, señor huésped, aquesos libros, que los quiero ver. -Que me place -respondió él. Y, entrando en su aposento, sacó dél una maletilla vieja, cerrada con una cadenilla, y, abriéndola, halló en ella tres libros grandes y unos papeles de muy buena letra, escritos de mano. El primer libro que abrió vio que era Don Cirongilio de Tracia; y el otro, de Felixmarte de Hircania; y el otro, la Historia del Gran Capitán Gonzalo Hernández de Córdoba, con la vida de Diego García de Paredes. Así como el cura leyó los dos títulos primeros, volvió el rostro al barbero y dijo: -Falta nos hacen aquí ahora el ama de mi amigo y su sobrina. -No hacen -respondió el barbero-, que también sé yo llevallos al corral o a la chimenea; que en verdad que hay muy buen fuego en ella. -Luego, ¿quiere vuestra merced quemar más libros? -dijo el ventero. -No más -dijo el cura- que estos dos: el de Don Cirongilio y el de Felixmarte. -Pues, ¿por ventura -dijo el ventero- mis libros son herejes o flemáticos, que los quiere quemar? -Cismáticos queréis decir, amigo -dijo el barbero-, que no flemáticos. -Así es -replicó el ventero-; mas si alguno quiere quemar, sea ese del Gran Capitán y dese Diego García, que antes dejaré quemar un hijo que dejar quemar ninguno desotros. -Hermano mío -dijo el cura-, estos dos libros son mentirosos y están llenos de disparates y devaneos; y este del Gran Capitán es historia verdadera, y tiene los hechos de Gonzalo Hernández de Córdoba, el cual, por sus muchas y grandes hazañas, mereció ser llamado de todo el mundo Gran Capitán, renombre famoso y claro, y dél sólo merecido. Y este Diego García de Paredes fue un principal caballero, natural de la ciudad de Trujillo, en Estremadura, valentísimo soldado, y de tantas fuerzas naturales que detenía con un dedo una rueda de molino en la mitad de su furia; y, puesto con un montante en la entrada de una puente, detuvo a todo un innumerable ejército, que no pasase por ella; y hizo otras tales cosas que, como si él las cuenta y las escribe él asimismo, con la modestia de caballero y de coronista propio, las escribiera otro, libre y desapasionado, pusieran en su olvido las de los Hétores, Aquiles y Roldanes. -¡Tomaos con mi padre! -dijo el dicho ventero-. ¡Mirad de qué se espanta: de detener una rueda de molino! Por Dios, ahora había vuestra merced de leer lo que hizo Felixmarte de Hircania, que de un revés solo partió cinco gigantes por la cintura, como si fueran hechos de habas, como los frailecicos que hacen los niños. Y otra vez arremetió con un grandísimo y poderosísimo ejército, donde llevó más de un millón y seiscientos mil soldados, todos armados desde el pie hasta la cabeza, y los desbarató a todos, como si fueran manadas de ovejas. Pues, ¿qué me dirán del bueno de don Cirongilio de Tracia, que fue tan valiente y animoso como se verá en el libro, donde cuenta que, navegando por un río, le salió de la mitad del agua una serpiente de fuego, y él, así como la vio, se arrojó sobre ella, y se puso a horcajadas encima de sus escamosas espaldas, y le apretó con ambas manos la garganta, con tanta fuerza que, viendo la serpiente que la iba ahogando, no tuvo otro remedio sino dejarse ir a lo hondo del río, llevándose tras sí al caballero, que nunca la quiso soltar? Y, cuando llegaron allá bajo, se halló en unos palacios y en unos jardines tan lindos que era maravilla; y luego la sierpe se volvió en un viejo anciano, que le dijo tantas de cosas que no hay más que oír. Calle, señor, que si oyese esto, se volvería loco de placer. ¡Dos higas para el Gran Capitán y para ese Diego García que dice! Oyendo esto Dorotea, dijo callando a Cardenio: -Poco le falta a nuestro huésped para hacer la segunda parte de don Quijote. -Así me parece a mí -respondió Cardenio-, porque, según da indicio, él tiene por cierto que todo lo que estos libros cuentan pasó ni más ni menos que lo escriben, y no le harán creer otra cosa frailes descalzos. -Mirad, hermano -tornó a decir el cura-, que no hubo en el mundo Felixmarte de Hircania, ni don Cirongilio de Tracia, ni otros caballeros semejantes que los libros de caballerías cuentan, porque todo es compostura y ficción de ingenios ociosos, que los compusieron para el efeto que vos decís de entretener el tiempo, como lo entretienen leyéndolos vuestros segadores; porque realmente os juro que nunca tales caballeros fueron en el mundo, ni tales hazañas ni disparates acontecieron en él. -¡A otro perro con ese hueso! -respondió el ventero-. ¡Como si yo no supiese cuántas son cinco y adónde me aprieta el zapato! No piense vuestra merced darme papilla, porque por Dios que no soy nada blanco. ¡Bueno es que quiera darme vuestra merced a entender que todo aquello que estos buenos libros dicen sea disparates y mentiras, estando impreso con licencia de los señores del Consejo Real, como si ellos fueran gente que habían de dejar imprimir tanta mentira junta, y tantas batallas y tantos encantamentos que quitan el juicio! -Ya os he dicho, amigo -replicó el cura-, que esto se hace para entretener nuestros ociosos pensamientos; y, así como se consiente en las repúblicas bien concertadas que haya juegos de ajedrez, de pelota y de trucos, para entretener a algunos que ni tienen, ni deben, ni pueden trabajar, así se consiente imprimir y que haya tales libros, creyendo, como es verdad, que no ha de haber alguno tan ignorante que tenga por historia verdadera ninguna destos libros. Y si me fuera lícito agora, y el auditorio lo requiriera, yo dijera cosas acerca de lo que han de tener los libros de caballerías para ser buenos, que quizá fueran de provecho y aun de gusto para algunos; pero yo espero que vendrá tiempo en que lo pueda comunicar con quien pueda remediallo, y en este entretanto creed, señor ventero, lo que os he dicho, y tomad vuestros libros, y allá os avenid con sus verdades o mentiras, y buen provecho os hagan, y quiera Dios que no cojeéis del pie que cojea vuestro huésped don Quijote. -Eso no -respondió el ventero-, que no seré yo tan loco que me haga caballero andante: que bien veo que ahora no se usa lo que se usaba en aquel tiempo, cuando se dice que andaban por el mundo estos famosos caballeros. A la mitad desta plática se halló Sancho presente, y quedó muy confuso y pensativo de lo que había oído decir que ahora no se usaban caballeros andantes, y que todos los libros de caballerías eran necedades y mentiras, y propuso en su corazón de esperar en lo que paraba aquel viaje de su amo, y que si no salía con la felicidad que él pensaba, determinaba de dejalle y volverse con su mujer y sus hijos a su acostumbrado trabajo. Llevábase la maleta y los libros el ventero, mas el cura le dijo: -Esperad, que quiero ver qué papeles son esos que de tan buena letra están escritos. Sacólos el huésped, y, dándoselos a leer, vio hasta obra de ocho pliegos escritos de mano, y al principio tenían un título grande que decía: Novela del curioso impertinente. Leyó el cura para sí tres o cuatro renglones y dijo: -Cierto que no me parece mal el título desta novela, y que me viene voluntad de leella toda. A lo que respondió el ventero: -Pues bien puede leella su reverencia, porque le hago saber que algunos huéspedes que aquí la han leído les ha contentado mucho, y me la han pedido con muchas veras; mas yo no se la he querido dar, pensando volvérsela a quien aquí dejó esta maleta olvidada con estos libros y esos papeles; que bien puede ser que vuelva su dueño por aquí algún tiempo, y, aunque sé que me han de hacer falta los libros, a fe que se los he de volver: que, aunque ventero, todavía soy cristiano. -Vos tenéis mucha razón, amigo -dijo el cura-, mas, con todo eso, si la novela me contenta, me la habéis de dejar trasladar. -De muy buena gana -respondió el ventero. Mientras los dos esto decían, había tomado Cardenio la novela y comenzado a leer en ella; y, pareciéndole lo mismo que al cura, le rogó que la leyese de modo que todos la oyesen. -Sí leyera -dijo el cura-, si no fuera mejor gastar este tiempo en dormir que en leer. -Harto reposo será para mí -dijo Dorotea- entretener el tiempo oyendo algún cuento, pues aún no tengo el espíritu tan sosegado que me conceda dormir cuando fuera razón. -Pues desa manera -dijo el cura-, quiero leerla, por curiosidad siquiera; quizá tendrá alguna de gusto. Acudió maese Nicolás a rogarle lo mesmo, y Sancho también; lo cual visto del cura, y entendiendo que a todos daría gusto y él le recibiría, dijo: -Pues así es, esténme todos atentos, que la novela comienza desta manera: Capítulo XXXIII. Donde se cuenta la novela del Curioso impertinente «En Florencia, ciudad rica y famosa de Italia, en la provincia que llaman Toscana, vivían Anselmo y Lotario, dos caballeros ricos y principales, y tan amigos que, por excelencia y antonomasia, de todos los que los conocían los dos amigos eran llamados. Eran solteros, mozos de una misma edad y de unas mismas costumbres; todo lo cual era bastante causa a que los dos con recíproca amistad se correspondiesen. Bien es verdad que el Anselmo era algo más inclinado a los pasatiempos amorosos que el Lotario, al cual llevaban tras sí los de la caza; pero, cuando se ofrecía, dejaba Anselmo de acudir a sus gustos por seguir los de Lotario, y Lotario dejaba los suyos por acudir a los de Anselmo; y, desta manera, andaban tan a una sus voluntades, que no había concertado reloj que así lo anduviese. »Andaba Anselmo perdido de amores de una doncella principal y hermosa de la misma ciudad, hija de tan buenos padres y tan buena ella por sí, que se determinó, con el parecer de su amigo Lotario, sin el cual ninguna cosa hacía, de pedilla por esposa a sus padres, y así lo puso en ejecución; y el que llevó la embajada fue Lotario, y el que concluyó el negocio tan a gusto de su amigo, que en breve tiempo se vio puesto en la posesión que deseaba, y Camila tan contenta de haber alcanzado a Anselmo por esposo, que no cesaba de dar gracias al cielo, y a Lotario, por cuyo medio tanto bien le había venido. »Los primeros días, como todos los de boda suelen ser alegres, continuó Lotario, como solía, la casa de su amigo Anselmo, procurando honralle, festejalle y regocijalle con todo aquello que a él le fue posible; pero, acabadas las bodas y sosegada ya la frecuencia de las visitas y parabienes, comenzó Lotario a descuidarse con cuidado de las idas en casa de Anselmo, por parecerle a él -como es razón que parezca a todos los que fueren discretos- que no se han de visitar ni continuar las casas de los amigos casados de la misma manera que cuando eran solteros; porque, aunque la buena y verdadera amistad no puede ni debe de ser sospechosa en nada, con todo esto, es tan delicada la honra del casado, que parece que se puede ofender aun de los mesmos hermanos, cuanto más de los amigos. »Notó Anselmo la remisión de Lotario, y formó dél quejas grandes, diciéndole que si él supiera que el casarse había de ser parte para no comunicalle como solía, que jamás lo hubiera hecho, y que si, por la buena correspondencia que los dos tenían mientras él fue soltero, habían alcanzado tan dulce nombre como el de ser llamados los dos amigos, que no permitiese, por querer hacer del circunspecto, sin otra ocasión alguna, que tan famoso y tan agradable nombre se perdiese; y que así, le suplicaba, si era lícito que tal término de hablar se usase entre ellos, que volviese a ser señor de su casa, y a entrar y salir en ella como de antes, asegurándole que su esposa Camila no tenía otro gusto ni otra voluntad que la que él quería que tuviese, y que, por haber sabido ella con cuántas veras los dos se amaban, estaba confusa de ver en él tanta esquiveza. »A todas estas y otras muchas razones que Anselmo dijo a Lotario para persuadille volviese como solía a su casa, respondió Lotario con tanta prudencia, discreción y aviso, que Anselmo quedó satisfecho de la buena intención de su amigo, y quedaron de concierto que dos días en la semana y las fiestas fuese Lotario a comer con él; y, aunque esto quedó así concertado entre los dos, propuso Lotario de no hacer más de aquello que viese que más convenía a la honra de su amigo, cuyo crédito estimaba en más que el suyo proprio. Decía él, y decía bien, que el casado a quien el cielo había concedido mujer hermosa, tanto cuidado había de tener qué amigos llevaba a su casa como en mirar con qué amigas su mujer conversaba, porque lo que no se hace ni concierta en las plazas, ni en los templos, ni en las fiestas públicas, ni estaciones -cosas que no todas veces las han de negar los maridos a sus mujeres-, se concierta y facilita en casa de la amiga o la parienta de quien más satisfación se tiene. »También decía Lotario que tenían necesidad los casados de tener cada uno algún amigo que le advirtiese de los descuidos que en su proceder hiciese, porque suele acontecer que con el mucho amor que el marido a la mujer tiene, o no le advierte o no le dice, por no enojalla, que haga o deje de hacer algunas cosas, que el hacellas o no, le sería de honra o de vituperio; de lo cual, siendo del amigo advertido, fácilmente pondría remedio en todo. Pero, ¿dónde se hallará amigo tan discreto y tan leal y verdadero como aquí Lotario le pide? No lo sé yo, por cierto; sólo Lotario era éste, que con toda solicitud y advertimiento miraba por la honra de su amigo y procuraba dezmar, frisar y acortar los días del concierto del ir a su casa, porque no pareciese mal al vulgo ocioso y a los ojos vagabundos y maliciosos la entrada de un mozo rico, gentilhombre y bien nacido, y de las buenas partes que él pensaba que tenía, en la casa de una mujer tan hermosa como Camila; que, puesto que su bondad y valor podía poner freno a toda maldiciente lengua, todavía no quería poner en duda su crédito ni el de su amigo, y por esto los más de los días del concierto los ocupaba y entretenía en otras cosas, que él daba a entender ser inexcusables. Así que, en quejas del uno y disculpas del otro se pasaban muchos ratos y partes del día. »Sucedió, pues, que uno que los dos se andaban paseando por un prado fuera de la ciudad, Anselmo dijo a Lotario las semejantes razones: »-Pensabas, amigo Lotario, que a las mercedes que Dios me ha hecho en hacerme hijo de tales padres como fueron los míos y al darme, no con mano escasa, los bienes, así los que llaman de naturaleza como los de fortuna, no puedo yo corresponder con agradecimiento que llegue al bien recebido, y sobre al que me hizo en darme a ti por amigo y a Camila por mujer propria: dos prendas que las estimo, si no en el grado que debo, en el que puedo. Pues con todas estas partes, que suelen ser el todo con que los hombres suelen y pueden vivir contentos, vivo yo el más despechado y el más desabrido hombre de todo el universo mundo; porque no sé qué días a esta parte me fatiga y aprieta un deseo tan estraño, y tan fuera del uso común de otros, que yo me maravillo de mí mismo, y me culpo y me riño a solas, y procuro callarlo y encubrirlo de mis proprios pensamientos; y así me ha sido posible salir con este secreto como si de industria procurara decillo a todo el mundo. Y, pues que, en efeto, él ha de salir a plaza,quiero que sea en la del archivo de tu secreto, confiado que, con él y con la diligencia que pondrás, como mi amigo verdadero, en remediarme, yo me veré presto libre de la angustia que me causa, y llegará mi alegría por tu solicitud al grado que ha llegado mi descontento por mi locura. »Suspenso tenían a Lotario las razones de Anselmo, y no sabía en qué había de parar tan larga prevención o preámbulo; y, aunque iba revolviendo en su imaginación qué deseo podría ser aquel que a su amigo tanto fatigaba, dio siempre muy lejos del blanco de la verdad; y, por salir presto de la agonía que le causaba aquella suspensión, le dijo que hacía notorio agravio a su mucha amistad en andar buscando rodeos para decirle sus más encubiertos pensamientos, pues tenía cierto que se podía prometer dél, o ya consejos para entretenellos, o ya remedio para cumplillos. »-Así es la verdad -respondió Anselmo-, y con esa confianza te hago saber, amigo Lotario, que el deseo que me fatiga es pensar si Camila, mi esposa, es tan buena y tan perfeta como yo pienso; y no puedo enterarme en esta verdad, si no es probándola de manera que la prueba manifieste los quilates de su bondad, como el fuego muestra los del oro. Porque yo tengo para mí, ¡oh amigo!, que no es una mujer más buena de cuanto es o no es solicitada, y que aquella sola es fuerte que no se dobla a las promesas, a las dádivas, a las lágrimas y a las continuas importunidades de los solícitos amantes. Porque, ¿qué hay que agradecer -decía él- que una mujer sea buena, si nadie le dice que sea mala? ¿Qué mucho que esté recogida y temerosa la que no le dan ocasión para que se suelte, y la que sabe que tiene marido que, en cogiéndola en la primera desenvoltura, la ha de quitar la vida? Ansí que, la que es buena por temor, o por falta de lugar, yo no la quiero tener en aquella estima en que tendré a la solicitada y perseguida que salió con la corona del vencimiento. De modo que, por estas razones y por otras muchas que te pudiera decir para acreditar y fortalecer la opinión que tengo, deseo que Camila, mi esposa, pase por estas dificultades y se acrisole y quilate en el fuego de verse requerida y solicitada, y de quien tenga valor para poner en ella sus deseos; y si ella sale, como creo que saldrá, con la palma desta batalla, tendré yo por sin igual mi ventura; podré yo decir que está colmo el vacío de mis deseos; diré que me cupo en suerte la mujer fuerte, de quien el Sabio dice que ¿quién la hallará? Y, cuando esto suceda al revés de lo que pienso, con el gusto de ver que acerté en mi opinión, llevaré sin pena la que de razón podrá causarme mi tan costosa experiencia. Y, prosupuesto que ninguna cosa de cuantas me dijeres en contra de mi deseo ha de ser de algún provecho para dejar de ponerle por la obra, quiero, ¡oh amigo Lotario!, que te dispongas a ser el instrumento que labre aquesta obra de mi gusto; que yo te daré lugar para que lo hagas, sin faltarte todo aquello que yo viere ser necesario para solicitar a una mujer honesta, honrada, recogida y desinteresada. Y muéveme, entre otras cosas, a fiar de ti esta tan ardua empresa, el ver que si de ti es vencida Camila, no ha de llegar el vencimiento a todo trance y rigor, sino a sólo a tener por hecho lo que se ha de hacer, por buen respeto; y así, no quedaré yo ofendido más de con el deseo, y mi injuria quedará escondida en la virtud de tu silencio, que bien sé que en lo que me tocare ha de ser eterno como el de la muerte. Así que, si quieres que yo tenga vida que pueda decir que lo es, desde luego has de entrar en esta amorosa batalla, no tibia ni perezosamente, sino con el ahínco y diligencia que mi deseo pide, y con la confianza que nuestra amistad me asegura. ȃstas fueron las razones que Anselmo dijo a Lotario, a todas las cuales estuvo tan atento, que si no fueron las que quedan escritas que le dijo, no desplegó sus labios hasta que hubo acabado; y, viendo que no decía más, después que le estuvo mirando un buen espacio, como si mirara otra cosa que jamás hubiera visto, que le causara admiración y espanto, le dijo: »-No me puedo persuadir, ¡oh amigo Anselmo!, a que no sean burlas las cosas que me has dicho; que, a pensar que de veras las decías, no consintiera que tan adelante pasaras, porque con no escucharte previniera tu larga arenga. Sin duda imagino, o que no me conoces, o que yo no te conozco. Pero no; que bien sé que eres Anselmo, y tú sabes que yo soy Lotario; el daño está en que yo pienso que no eres el Anselmo que solías, y tú debes de haber pensado que tampoco yo soy el Lotario que debía ser, porque las cosas que me has dicho, ni son de aquel Anselmo mi amigo, ni las que me pides se han de pedir a aquel Lotario que tú conoces; porque los buenos amigos han de probar a sus amigos y valerse dellos, como dijo un poeta, usque ad aras; que quiso decir que no se habían de valer de su amistad en cosas que fuesen contra Dios. Pues, si esto sintió un gentil de la amistad, ¿cuánto mejor es que lo sienta el cristiano, que sabe que por ninguna humana ha de perder la amistad divina? Y cuando el amigo tirase tanto la barra que pusiese aparte los respetos del cielo por acudir a los de su amigo, no ha de ser por cosas ligeras y de poco momento, sino por aquellas en que vaya la honra y la vida de su amigo. Pues dime tú ahora, Anselmo: ¿cuál destas dos cosas tienes en peligro para que yo me aventure a complacerte y a hacer una cosa tan detestable como me pides? Ninguna, por cierto; antes, me pides, según yo entiendo, que procure y solicite quitarte la honra y la vida, y quitármela a mí juntamente. Porque si yo he de procurar quitarte la honra, claro está que te quito la vida, pues el hombre sin honra peor es que un muerto; y, siendo yo el instrumento, como tú quieres que lo sea, de tanto mal tuyo, ¿no vengo a quedar deshonrado, y, por el mesmo consiguiente, sin vida? Escucha, amigo Anselmo, y ten paciencia de no responderme hasta que acabe de decirte lo que se me ofreciere acerca de lo que te ha pedido tu deseo; que tiempo quedará para que tú me repliques y yo te escuche. »-Que me place -dijo Anselmo-: di lo que quisieres. »Y Lotario prosiguió diciendo: »-Paréceme, ¡oh Anselmo!, que tienes tú ahora el ingenio como el que siempre tienen los moros, a los cuales no se les puede dar a entender el error de su secta con las acotaciones de la Santa Escritura, ni con razones que consistan en especulación del entendimiento, ni que vayan fundadas en artículos de fe, sino que les han de traer ejemplos palpables, fáciles, intelegibles, demonstrativos, indubitables, con demostraciones matemáticas que no se pueden negar, como cuando dicen: "Si de dos partes iguales quitamos partes iguales, las que quedan también son iguales"; y, cuando esto no entiendan de palabra, como, en efeto, no lo entienden, háseles de mostrar con las manos y ponérselo delante de los ojos, y, aun con todo esto, no basta nadie con ellos a persuadirles las verdades de mi sacra religión. Y este mesmo término y modo me convendrá usar contigo, porque el deseo que en ti ha nacido va tan descaminado y tan fuera de todo aquello que tenga sombra de razonable, que me parece que ha de ser tiempo gastado el que ocupare en darte a entender tu simplicidad, que por ahora no le quiero dar otro nombre, y aun estoy por dejarte en tu desatino, en pena de tu mal deseo; mas no me deja usar deste rigor la amistad que te tengo, la cual no consiente que te deje puesto en tan manifiesto peligro de perderte. Y, porque claro lo veas, dime, Anselmo: ¿tú no me has dicho que tengo de solicitar a una retirada, persuadir a una honesta, ofrecer a una desinteresada, servir a una prudente? Sí que me lo has dicho. Pues si tú sabes que tienes mujer retirada, honesta, desinteresada y prudente, ¿qué buscas? Y si piensas que de todos mis asaltos ha de salir vencedora, como saldrá sin duda, ¿qué mejores títulos piensas darle después que los que ahora tiene, o qué será más después de lo que es ahora? O es que tú no la tienes por la que dices, o tú no sabes lo que pides. Si no la tienes por lo que dices, ¿para qué quieres probarla, sino, como a mala, hacer della lo que más te viniere en gusto? Mas si es tan buena como crees, impertinente cosa será hacer experiencia de la mesma verdad, pues, después de hecha, se ha de quedar con la estimación que primero tenía. Así que, es razón concluyente que el intentar las cosas de las cuales antes nos puede suceder daño que provecho es de juicios sin discurso y temerarios, y más cuando quieren intentar aquellas a que no son forzados ni compelidos, y que de muy lejos traen descubierto que el intentarlas es manifiesta locura. Las cosas dificultosas se intentan por Dios, o por el mundo, o por entrambos a dos: las que se acometen por Dios son las que acometieron los santos, acometiendo a vivir vida de ángeles en cuerpos humanos; las que se acometen por respeto del mundo son las de aquellos que pasan tanta infinidad de agua, tanta diversidad de climas, tanta estrañeza de gentes, por adquirir estos que llaman bienes de fortuna. Y las que se intentan por Dios y por el mundo juntamente son aquellas de los valerosos soldados, que apenas veen en el contrario muro abierto tanto espacio cuanto es el que pudo hacer una redonda bala de artillería, cuando, puesto aparte todo temor, sin hacer discurso ni advertir al manifiesto peligro que les amenaza, llevados en vuelo de las alas del deseo de volver por su fe, por su nación y por su rey, se arrojan intrépidamente por la mitad de mil contrapuestas muertes que los esperan. Estas cosas son las que suelen intentarse, y es honra, gloria y provecho intentarlas, aunque tan llenas de inconvenientes y peligros. Pero la que tú dices que quieres intentar y poner por obra, ni te ha de alcanzar gloria de Dios, bienes de la fortuna, ni fama con los hombres; porque, puesto que salgas con ella como deseas, no has de quedar ni más ufano, ni más rico, ni más honrado que estás ahora; y si no sales, te has de ver en la mayor miseria que imaginarse pueda, porque no te ha de aprovechar pensar entonces que no sabe nadie la desgracia que te ha sucedido, porque bastará para afligirte y deshacerte que la sepas tú mesmo. Y, para confirmación desta verdad, te quiero decir una estancia que hizo el famoso poeta Luis Tansilo, en el fin de su primera parte de Las lágrimas de San Pedro, que dice así: Crece el dolor y crece la vergüenza en Pedro, cuando el día se ha mostrado; y, aunque allí no ve a nadie, se avergüenza de sí mesmo, por ver que había pecado: que a un magnánimo pecho a haber vergüenza no sólo ha de moverle el ser mirado; que de sí se avergüenza cuando yerra, si bien otro no vee que cielo y tierra. Así que, no escusarás con el secreto tu dolor; antes, tendrás que llorar contino, si no lágrimas de los ojos, lágrimas de sangre del corazón, como las lloraba aquel simple doctor que nuestro poeta nos cuenta que hizo la prueba del vaso, que, con mejor discurso, se escusó de hacerla el prudente Reinaldos; que, puesto que aquello sea ficción poética, tiene en sí encerrados secretos morales dignos de ser advertidos y entendidos e imitados. Cuanto más que, con lo que ahora pienso decirte, acabarás de venir en conocimiento del grande error que quieres cometer. Dime, Anselmo, si el cielo, o la suerte buena, te hubiera hecho señor y legítimo posesor de un finísimo diamante, de cuya bondad y quilates estuviesen satisfechos cuantos lapidarios le viesen, y que todos a una voz y de común parecer dijesen que llegaba en quilates, bondad y fineza a cuanto se podía estender la naturaleza de tal piedra, y tú mesmo lo creyeses así, sin saber otra cosa en contrario, ¿sería justo que te viniese en deseo de tomar aquel diamante, y ponerle entre un ayunque y un martillo, y allí, a pura fuerza de golpes y brazos, probar si es tan duro y tan fino como dicen? Y más, si lo pusieses por obra; que, puesto caso que la piedra hiciese resistencia a tan necia prueba, no por eso se le añadiría más valor ni más fama; y si se rompiese, cosa que podría ser, ¿no se perdería todo? Sí, por cierto, dejando a su dueño en estimación de que todos le tengan por simple. Pues haz cuenta, Anselmo amigo, que Camila es fínisimo diamante, así en tu estimación como en la ajena, y que no es razón ponerla en contingencia de que se quiebre, pues, aunque se quede con su entereza, no puede subir a más valor del que ahora tiene; y si faltase y no resistiese, considera desde ahora cuál quedarías sin ella, y con cuánta razón te podrías quejar de ti mesmo, por haber sido causa de su perdición y la tuya. Mira que no hay joya en el mundo que tanto valga como la mujer casta y honrada, y que todo el honor de las mujeres consiste en la opinión buena que dellas se tiene; y, pues la de tu esposa es tal que llega al estremo de bondad que sabes, ¿para qué quieres poner esta verdad en duda? Mira, amigo, que la mujer es animal imperfecto, y que no se le han de poner embarazos donde tropiece y caiga, sino quitárselos y despejalle el camino de cualquier inconveniente, para que sin pesadumbre corra ligera a alcanzar la perfeción que le falta, que consiste en el ser virtuosa. Cuentan los naturales que el arminio es un animalejo que tiene una piel blanquísima, y que cuando quieren cazarle, los cazadores usan deste artificio: que, sabiendo las partes por donde suele pasar y acudir, las atajan con lodo, y después, ojeándole, le encaminan hacia aquel lugar, y así como el arminio llega al lodo, se está quedo y se deja prender y cautivar, a trueco de no pasar por el cieno y perder y ensuciar su blancura, que la estima en más que la libertad y la vida. La honesta y casta mujer es arminio, y es más que nieve blanca y limpia la virtud de la honestidad; y el que quisiere que no la pierda, antes la guarde y conserve, ha de usar de otro estilo diferente que con el arminio se tiene, porque no le han de poner delante el cieno de los regalos y servicios de los importunos amantes, porque quizá, y aun sin quizá, no tiene tanta virtud y fuerza natural que pueda por sí mesma atropellar y pasar por aquellos embarazos, y es necesario quitárselos y ponerle delante la limpieza de la virtud y la belleza que encierra en sí la buena fama. Es asimesmo la buena mujer como espejo de cristal luciente y claro; pero está sujeto a empañarse y escurecerse con cualquiera aliento que le toque. Hase de usar con la honesta mujer el estilo que con las reliquias: adorarlas y no tocarlas. Hase de guardar y estimar la mujer buena como se guarda y estima un hermoso jardín que está lleno de flores y rosas, cuyo dueño no consiente que nadie le pasee ni manosee; basta que desde lejos, y por entre las verjas de hierro, gocen de su fragrancia y hermosura. Finalmente, quiero decirte unos versos que se me han venido a la memoria, que los oí en una comedia moderna, que me parece que hacen al propósito de lo que vamos tratando. Aconsejaba un prudente viejo a otro, padre de una doncella, que la recogiese, guardase y encerrase, y entre otras razones, le dijo éstas: Es de vidrio la mujer; pero no se ha de probar si se puede o no quebrar, porque todo podría ser. Y es más fácil el quebrarse, y no es cordura ponerse a peligro de romperse lo que no puede soldarse. Y en esta opinión estén todos, y en razón la fundo: que si hay Dánaes en el mundo, hay pluvias de oro también. Cuanto hasta aquí te he dicho, ¡oh Anselmo!, ha sido por lo que a ti te toca; y ahora es bien que se oiga algo de lo que a mí me conviene; y si fuere largo, perdóname, que todo lo requiere el laberinto donde te has entrado y de donde quieres que yo te saque. Tú me tienes por amigo y quieres quitarme la honra, cosa que es contra toda amistad; y aun no sólo pretendes esto, sino que procuras que yo te la quite a ti. Que me la quieres quitar a mí está claro, pues, cuando Camila vea que yo la solicito, como me pides, cierto está que me ha de tener por hombre sin honra y mal mirado, pues intento y hago una cosa tan fuera de aquello que el ser quien soy y tu amistad me obliga. De que quieres que te la quite a ti no hay duda, porque, viendo Camila que yo la solicito, ha de pensar que yo he visto en ella alguna liviandad que me dio atrevimiento a descubrirle mi mal deseo; y, teniéndose por deshonrada, te toca a ti, como a cosa suya, su mesma deshonra. Y de aquí nace lo que comúnmente se platica: que el marido de la mujer adúltera, puesto que él no lo sepa ni haya dado ocasión para que su mujer no sea la que debe, ni haya sido en su mano, ni en su descuido y poco recato estorbar su desgracia, con todo, le llaman y le nombran con nombre de vituperio y bajo; y en cierta manera le miran, los que la maldad de su mujer saben, con ojos de menosprecio, en cambio de mirarle con los de lástima, viendo que no por su culpa, sino por el gusto de su mala compañera, está en aquella desventura. Pero quiérote decir la causa por que con justa razón es deshonrado el marido de la mujer mala, aunque él no sepa que lo es, ni tenga culpa, ni haya sido parte, ni dado ocasión, para que ella lo sea. Y no te canses de oírme, que todo ha de redundar en tu provecho. Cuando Dios crió a nuestro primero padre en el Paraíso terrenal, dice la Divina Escritura que infundió Dios sueño en Adán, y que, estando durmiendo, le sacó una costilla del lado siniestro, de la cual formó a nuestra madre Eva; y, así como Adán despertó y la miró, dijo: ''Ésta es carne de mi carne y hueso de mis huesos''. Y Dios dijo: ''Por ésta dejará el hombre a su padre y madre, y serán dos en una carne misma''. Y entonces fue instituido el divino sacramento del matrimonio, con tales lazos que sola la muerte puede desatarlos. Y tiene tanta fuerza y virtud este milagroso sacramento, que hace que dos diferentes personas sean una mesma carne; y aún hace más en los buenos casados, que, aunque tienen dos almas, no tienen más de una voluntad. Y de aquí viene que, como la carne de la esposa sea una mesma con la del esposo, las manchas que en ella caen, o los defectos que se procura, redundan en la carne del marido, aunque él no haya dado, como queda dicho, ocasión para aquel daño. Porque, así como el dolor del pie o de cualquier miembro del cuerpo humano le siente todo el cuerpo, por ser todo de una carne mesma, y la cabeza siente el daño del tobillo, sin que ella se le haya causado, así el marido es participante de la deshonra de la mujer, por ser una mesma cosa con ella. Y como las honras y deshonras del mundo sean todas y nazcan de carne y sangre, y las de la mujer mala sean deste género, es forzoso que al marido le quepa parte dellas, y sea tenido por deshonrado sin que él lo sepa. Mira, pues, ¡oh Anselmo!, al peligro que te pones en querer turbar el sosiego en que tu buena esposa vive. Mira por cuán vana e impertinente curiosidad quieres revolver los humores que ahora están sosegados en el pecho de tu casta esposa. Advierte que lo que aventuras a ganar es poco, y que lo que perderás será tanto que lo dejaré en su punto, porque me faltan palabras para encarecerlo. Pero si todo cuanto he dicho no basta a moverte de tu mal propósito, bien puedes buscar otro instrumento de tu deshonra y desventura, que yo no pienso serlo, aunque por ello pierda tu amistad, que es la mayor pérdida que imaginar puedo. »Calló, en diciendo esto, el virtuoso y prudente Lotario, y Anselmo quedó tan confuso y pensativo que por un buen espacio no le pudo responder palabra; pero, en fin, le dijo: »-Con la atención que has visto he escuchado, Lotario amigo, cuanto has querido decirme, y en tus razones, ejemplos y comparaciones he visto la mucha discreción que tienes y el estremo de la verdadera amistad que alcanzas; y ansimesmo veo y confieso que si no sigo tu parecer y me voy tras el mío, voy huyendo del bien y corriendo tras el mal. Prosupuesto esto, has de considerar que yo padezco ahora la enfermedad que suelen tener algunas mujeres, que se les antoja comer tierra, yeso, carbón y otras cosas peores, aun asquerosas para mirarse, cuanto más para comerse; así que, es menester usar de algún artificio para que yo sane, y esto se podía hacer con facilidad, sólo con que comiences, aunque tibia y fingidamente, a solicitar a Camila, la cual no ha de ser tan tierna que a los primeros encuentros dé con su honestidad por tierra; y con solo este principio quedaré contento y tú habrás cumplido con lo que debes a nuestra amistad, no solamente dándome la vida, sino persuadiéndome de no verme sin honra. Y estás obligado a hacer esto por una razón sola; y es que, estando yo, como estoy, determinado de poner en plática esta prueba, no has tú de consentir que yo dé cuenta de mi desatino a otra persona, con que pondría en aventura el honor que tú procuras que no pierda; y, cuando el tuyo no esté en el punto que debe en la intención de Camila en tanto que la solicitares, importa poco o nada, pues con brevedad, viendo en ella la entereza que esperamos, le podrás decir la pura verdad de nuestro artificio, con que volverá tu crédito al ser primero. Y, pues tan poco aventuras y tanto contento me puedes dar aventurándote, no lo dejes de hacer, aunque más inconvenientes se te pongan delante, pues, como ya he dicho, con sólo que comiences daré por concluida la causa. »Viendo Lotario la resoluta voluntad de Anselmo, y no sabiendo qué más ejemplos traerle ni qué más razones mostrarle para que no la siguiese, y viendo que le amenazaba que daría a otro cuenta de su mal deseo, por evitar mayor mal, determinó de contentarle y hacer lo que le pedía, con propósito e intención de guiar aquel negocio de modo que, sin alterar los pensamientos de Camila, quedase Anselmo satisfecho; y así, le respondió que no comunicase su pensamiento con otro alguno, que él tomaba a su cargo aquella empresa, la cual comenzaría cuando a él le diese más gusto. Abrazóle Anselmo tierna y amorosamente, y agradecióle su ofrecimiento, como si alguna grande merced le hubiera hecho; y quedaron de acuerdo entre los dos que desde otro día siguiente se comenzase la obra; que él le daría lugar y tiempo como a sus solas pudiese hablar a Camila, y asimesmo le daría dineros y joyas que darla y que ofrecerla. Aconsejóle que le diese músicas, que escribiese versos en su alabanza, y que, cuando él no quisiese tomar trabajo de hacerlos, él mesmo los haría. A todo se ofreció Lotario, bien con diferente intención que Anselmo pensaba. »Y con este acuerdo se volvieron a casa de Anselmo, donde hallaron a Camila con ansia y cuidado, esperando a su esposo, porque aquel día tardaba en venir más de lo acostumbrado. »Fuese Lotario a su casa, y Anselmo quedó en la suya, tan contento como Lotario fue pensativo, no sabiendo qué traza dar para salir bien de aquel impertinente negocio. Pero aquella noche pensó el modo que tendría para engañar a Anselmo, sin ofender a Camila; y otro día vino a comer con su amigo, y fue bien recebido de Camila, la cual le recebía y regalaba con mucha voluntad, por entender la buena que su esposo le tenía. »Acabaron de comer, levantaron los manteles y Anselmo dijo a Lotario que se quedase allí con Camila, en tanto que él iba a un negocio forzoso, que dentro de hora y media volvería. Rogóle Camila que no se fuese y Lotario se ofreció a hacerle compañía, más nada aprovechó con Anselmo; antes, importunó a Lotario que se quedase y le aguardase, porque tenía que tratar con él una cosa de mucha importancia. Dijo también a Camila que no dejase solo a Lotario en tanto que él volviese. En efeto, él supo tan bien fingir la necesidad, o necedad, de su ausencia, que nadie pudiera entender que era fingida. Fuese Anselmo, y quedaron solos a la mesa Camila y Lotario, porque la demás gente de casa toda se había ido a comer. Viose Lotario puesto en la estacada que su amigo deseaba y con el enemigo delante, que pudiera vencer con sola su hermosura a un escuadrón de caballeros armados: mirad si era razón que le temiera Lotario. »Pero lo que hizo fue poner el codo sobre el brazo de la silla y la mano abierta en la mejilla, y, pidiendo perdón a Camila del mal comedimiento, dijo que quería reposar un poco en tanto que Anselmo volvía. Camila le respondió que mejor reposaría en el estrado que en la silla, y así, le rogó se entrase a dormir en él. No quiso Lotario, y allí se quedó dormido hasta que volvió Anselmo, el cual, como halló a Camila en su aposento y a Lotario durmiendo, creyó que, como se había tardado tanto, ya habrían tenido los dos lugar para hablar, y aun para dormir, y no vio la hora en que Lotario despertase, para volverse con él fuera y preguntarle de su ventura. »Todo le sucedió como él quiso: Lotario despertó, y luego salieron los dos de casa, y así, le preguntó lo que deseaba, y le respondió Lotario que no le había parecido ser bien que la primera vez se descubriese del todo; y así, no había hecho otra cosa que alabar a Camila de hermosa, diciéndole que en toda la ciudad no se trataba de otra cosa que de su hermosura y discreción, y que éste le había parecido buen principio para entrar ganando la voluntad, y disponiéndola a que otra vez le escuchase con gusto, usando en esto del artificio que el demonio usa cuando quiere engañar a alguno que está puesto en atalaya de mirar por sí: que se transforma en ángel de luz, siéndolo él de tinieblas, y, poniéndole delante apariencias buenas, al cabo descubre quién es y sale con su intención, si a los principios no es descubierto su engaño. Todo esto le contentó mucho a Anselmo, y dijo que cada día daría el mesmo lugar, aunque no saliese de casa, porque en ella se ocuparía en cosas que Camila no pudiese venir en conocimiento de su artificio. »Sucedió, pues, que se pasaron muchos días que, sin decir Lotario palabra a Camila, respondía a Anselmo que la hablaba y jamás podía sacar della una pequeña muestra de venir en ninguna cosa que mala fuese, ni aun dar una señal de sombra de esperanza; antes, decía que le amenazaba que si de aquel mal pensamiento no se quitaba, que lo había de decir a su esposo. »-Bien está -dijo Anselmo-. Hasta aquí ha resistido Camila a las palabras; es menester ver cómo resiste a las obras: yo os daré mañana dos mil escudos de oro para que se los ofrezcáis, y aun se los deis, y otros tantos para que compréis joyas con que cebarla; que las mujeres suelen ser aficionadas, y más si son hermosas, por más castas que sean, a esto de traerse bien y andar galanas; y si ella resiste a esta tentación, yo quedaré satisfecho y no os daré más pesadumbre. »Lotario respondió que ya que había comenzado, que él llevaría hasta el fin aquella empresa, puesto que entendía salir della cansado y vencido. Otro día recibió los cuatro mil escudos, y con ellos cuatro mil confusiones, porque no sabía qué decirse para mentir de nuevo; pero, en efeto, determinó de decirle que Camila estaba tan entera a las dádivas y promesas como a las palabras, y que no había para qué cansarse más, porque todo el tiempo se gastaba en balde. »Pero la suerte, que las cosas guiaba de otra manera, ordenó que, habiendo dejado Anselmo solos a Lotario y a Camila, como otras veces solía, él se encerró en un aposento y por los agujeros de la cerradura estuvo mirando y escuchando lo que los dos trataban, y vio que en más de media hora Lotario no habló palabra a Camila, ni se la hablara si allí estuviera un siglo, y cayó en la cuenta de que cuanto su amigo le había dicho de las respuestas de Camila todo era ficción y mentira. Y, para ver si esto era ansí, salió del aposento, y, llamando a Lotario aparte, le preguntó qué nuevas había y de qué temple estaba Camila. Lotario le respondió que no pensaba más darle puntada en aquel negocio, porque respondía tan áspera y desabridamente, que no tendría ánimo para volver a decirle cosa alguna. »-¡Ah! -dijo Anselmo-, Lotario, Lotario, y cuán mal correspondes a lo que me debes y a lo mucho que de ti confío! Ahora te he estado mirando por el lugar que concede la entrada desta llave, y he visto que no has dicho palabra a Camila, por donde me doy a entender que aun las primeras le tienes por decir; y si esto es así, como sin duda lo es, ¿para qué me engañas, o por qué quieres quitarme con tu industria los medios que yo podría hallar para conseguir mi deseo? »No dijo más Anselmo, pero bastó lo que había dicho para dejar corrido y confuso a Lotario; el cual, casi como tomando por punto de honra el haber sido hallado en mentira, juró a Anselmo que desde aquel momento tomaba tan a su cargo el contentalle y no mentille, cual lo vería si con curiosidad lo espiaba; cuanto más, que no sería menester usar de ninguna diligencia, porque la que él pensaba poner en satisfacelle le quitaría de toda sospecha. Creyóle Anselmo, y para dalle comodidad más segura y menos sobresaltada, determinó de hacer ausencia de su casa por ocho días, yéndose a la de un amigo suyo, que estaba en una aldea, no lejos de la ciudad, con el cual amigo concertó que le enviase a llamar con muchas veras, para tener ocasión con Camila de su partida. »¡Desdichado y mal advertido de ti, Anselmo! ¿Qué es lo que haces? ¿Qué es lo que trazas? ¿Qué es lo que ordenas? Mira que haces contra ti mismo, trazando tu deshonra y ordenando tu perdición. Buena es tu esposa Camila, quieta y sosegadamente la posees, nadie sobresalta tu gusto, sus pensamientos no salen de las paredes de su casa, tú eres su cielo en la tierra, el blanco de sus deseos, el cumplimiento de sus gustos y la medida por donde mide su voluntad, ajustándola en todo con la tuya y con la del cielo. Pues si la mina de su honor, hermosura, honestidad y recogimiento te da sin ningún trabajo toda la riqueza que tiene y tú puedes desear, ¿para qué quieres ahondar la tierra y buscar nuevas vetas de nuevo y nunca visto tesoro, poniéndote a peligro que toda venga abajo, pues, en fin, se sustenta sobre los débiles arrimos de su flaca naturaleza? Mira que el que busca lo imposible es justo que lo posible se le niegue, como lo dijo mejor un poeta, diciendo: Busco en la muerte la vida, salud en la enfermedad, en la prisión libertad, en lo cerrado salida y en el traidor lealtad. Pero mi suerte, de quien jamás espero algún bien, con el cielo ha estatuido que, pues lo imposible pido, lo posible aun no me den. »Fuese otro día Anselmo a la aldea, dejando dicho a Camila que el tiempo que él estuviese ausente vendría Lotario a mirar por su casa y a comer con ella; que tuviese cuidado de tratalle como a su mesma persona. Afligióse Camila, como mujer discreta y honrada, de la orden que su marido le dejaba, y díjole que advirtiese que no estaba bien que nadie, él ausente, ocupase la silla de su mesa, y que si lo hacía por no tener confianza que ella sabría gobernar su casa, que probase por aquella vez, y vería por experiencia como para mayores cuidados era bastante. Anselmo le replicó que aquél era su gusto, y que no tenía más que hacer que bajar la cabeza y obedecelle. Camila dijo que ansí lo haría, aunque contra su voluntad. »Partióse Anselmo, y otro día vino a su casa Lotario, donde fue rescebido de Camila con amoroso y honesto acogimiento; la cual jamás se puso en parte donde Lotario la viese a solas, porque siempre andaba rodeada de sus criados y criadas, especialmente de una doncella suya, llamada Leonela, a quien ella mucho quería, por haberse criado desde niñas las dos juntas en casa de los padres de Camila, y cuando se casó con Anselmo la trujo consigo. »En los tres días primeros nunca Lotario le dijo nada, aunque pudiera, cuando se levantaban los manteles y la gente se iba a comer con mucha priesa, porque así se lo tenía mandado Camila. Y aun tenía orden Leonela que comiese primero que Camila, y que de su lado jamás se quitase; mas ella, que en otras cosas de su gusto tenía puesto el pensamiento y había menester aquellas horas y aquel lugar para ocuparle en sus contentos, no cumplía todas veces el mandamiento de su señora; antes, los dejaba solos, como si aquello le hubieran mandado. Mas la honesta presencia de Camila, la gravedad de su rostro, la compostura de su persona era tanta, que ponía freno a la lengua de Lotario. »Pero el provecho que las muchas virtudes de Camila hicieron, poniendo silencio en la lengua de Lotario, redundó más en daño de los dos, porque si la lengua callaba, el pensamiento discurría y tenía lugar de contemplar, parte por parte, todos los estremos de bondad y de hermosura que Camila tenía, bastantes a enamorar una estatua de mármol, no que un corazón de carne. »Mirábala Lotario en el lugar y espacio que había de hablarla, y consideraba cuán digna era de ser amada; y esta consideración comenzó poco a poco a dar asaltos a los respectos que a Anselmo tenía, y mil veces quiso ausentarse de la ciudad y irse donde jamás Anselmo le viese a él, ni él viese a Camila; mas ya le hacía impedimento y detenía el gusto que hallaba en mirarla. Hacíase fuerza y peleaba consigo mismo por desechar y no sentir el contento que le llevaba a mirar a Camila. Culpábase a solas de su desatino, llamábase mal amigo y aun mal cristiano; hacía discursos y comparaciones entre él y Anselmo, y todos paraban en decir que más había sido la locura y confianza de Anselmo que su poca fidelidad, y que si así tuviera disculpa para con Dios como para con los hombres de lo que pensaba hacer, que no temiera pena por su culpa. »En efecto, la hermosura y la bondad de Camila, juntamente con la ocasión que el ignorante marido le había puesto en las manos, dieron con la lealtad de Lotario en tierra. Y, sin mirar a otra cosa que aquella a que su gusto le inclinaba, al cabo de tres días de la ausencia de Anselmo, en los cuales estuvo en continua batalla por resistir a sus deseos, comenzó a requebrar a Camila, con tanta turbación y con tan amorosas razones que Camila quedó suspensa, y no hizo otra cosa que levantarse de donde estaba y entrarse a su aposento, sin respondelle palabra alguna. Mas no por esta sequedad se desmayó en Lotario la esperanza, que siempre nace juntamente con el amor; antes, tuvo en más a Camila. La cual, habiendo visto en Lotario lo que jamás pensara, no sabía qué hacerse. Y, pareciéndole no ser cosa segura ni bien hecha darle ocasión ni lugar a que otra vez la hablase, determinó de enviar aquella mesma noche, como lo hizo, a un criado suyo con un billete a Anselmo, donde le escribió estas razones: Capítulo XXXIV. Donde se prosigue la novela del Curioso impertinente »Así como suele decirse que parece mal el ejército sin su general y el castillo sin su castellano, digo yo que parece muy peor la mujer casada y moza sin su marido, cuando justísimas ocasiones no lo impiden. Yo me hallo tan mal sin vos, y tan imposibilitada de no poder sufrir esta ausencia, que si presto no venís, me habré de ir a entretener en casa de mis padres, aunque deje sin guarda la vuestra; porque la que me dejastes, si es que quedó con tal título, creo que mira más por su gusto que por lo que a vos os toca; y, pues sois discreto, no tengo más que deciros, ni aun es bien que más os diga. »Esta carta recibió Anselmo, y entendió por ella que Lotario había ya comenzado la empresa, y que Camila debía de haber respondido como él deseaba; y, alegre sobremanera de tales nuevas, respondió a Camila, de palabra, que no hiciese mudamiento de su casa en modo ninguno, porque él volvería con mucha brevedad. Admirada quedó Camila de la respuesta de Anselmo, que la puso en más confusión que primero, porque ni se atrevía a estar en su casa, ni menos irse a la de sus padres; porque en la quedada corría peligro su honestidad, y en la ida iba contra el mandamiento de su esposo. »En fin, se resolvió en lo que le estuvo peor, que fue en el quedarse, con determinación de no huir la presencia de Lotario, por no dar que decir a sus criados; y ya le pesaba de haber escrito lo que escribió a su esposo, temerosa de que no pensase que Lotario había visto en ella alguna desenvoltura que le hubiese movido a no guardalle el decoro que debía. Pero, fiada en su bondad, se fió en Dios y en su buen pensamiento, con que pensaba resistir callando a todo aquello que Lotario decirle quisiese, sin dar más cuenta a su marido, por no ponerle en alguna pendencia y trabajo. Y aun andaba buscando manera como disculpar a Lotario con Anselmo, cuando le preguntase la ocasión que le había movido a escribirle aquel papel. Con estos pensamientos, más honrados que acertados ni provechosos, estuvo otro día escuchando a Lotario, el cual cargó la mano de manera que comenzó a titubear la firmeza de Camila, y su honestidad tuvo harto que hacer en acudir a los ojos, para que no diesen muestra de alguna amorosa compasión que las lágrimas y las razones de Lotario en su pecho habían despertado. Todo esto notaba Lotario, y todo le encendía. »Finalmente, a él le pareció que era menester, en el espacio y lugar que daba la ausencia de Anselmo, apretar el cerco a aquella fortaleza. Y así, acometió a su presunción con las alabanzas de su hermosura, porque no hay cosa que más presto rinda y allane las encastilladas torres de la vanidad de las hermosas que la mesma vanidad, puesta en las lenguas de la adulación. En efecto, él, con toda diligencia, minó la roca de su entereza, con tales pertrechos que, aunque Camila fuera toda de bronce, viniera al suelo. Lloró, rogó, ofreció, aduló, porfió, y fingió Lotario con tantos sentimientos, con muestras de tantas veras, que dio al través con el recato de Camila y vino a triunfar de lo que menos se pensaba y más deseaba. »Rindióse Camila, Camila se rindió; pero, ¿qué mucho, si la amistad de Lotario no quedó en pie? Ejemplo claro que nos muestra que sólo se vence la pasión amorosa con huilla, y que nadie se ha de poner a brazos con tan poderoso enemigo, porque es menester fuerzas divinas para vencer las suyas humanas. Sólo supo Leonela la flaqueza de su señora, porque no se la pudieron encubrir los dos malos amigos y nuevos amantes. No quiso Lotario decir a Camila la pretensión de Anselmo, ni que él le había dado lugar para llegar a aquel punto, porque no tuviese en menos su amor y pensase que así, acaso y sin pensar, y no de propósito, la había solicitado. »Volvió de allí a pocos días Anselmo a su casa, y no echó de ver lo que faltaba en ella, que era lo que en menos tenía y más estimaba. Fuese luego a ver a Lotario, y hallóle en su casa; abrazáronse los dos, y el uno preguntó por las nuevas de su vida o de su muerte. »-Las nuevas que te podré dar, ¡oh amigo Anselmo! -dijo Lotario-, son de que tienes una mujer que dignamente puede ser ejemplo y corona de todas las mujeres buenas. Las palabras que le he dicho se las ha llevado el aire, los ofrecimientos se han tenido en poco, las dádivas no se han admitido, de algunas lágrimas fingidas mías se ha hecho burla notable. En resolución, así como Camila es cifra de toda belleza, es archivo donde asiste la honestidad y vive el comedimiento y el recato, y todas las virtudes que pueden hacer loable y bien afortunada a una honrada mujer. Vuelve a tomar tus dineros, amigo, que aquí los tengo, sin haber tenido necesidad de tocar a ellos; que la entereza de Camila no se rinde a cosas tan bajas como son dádivas ni promesas. Conténtate, Anselmo, y no quieras hacer más pruebas de las hechas; y, pues a pie enjuto has pasado el mar de las dificultades y sospechas que de las mujeres suelen y pueden tenerse, no quieras entrar de nuevo en el profundo piélago de nuevos inconvenientes, ni quieras hacer experiencia con otro piloto de la bondad y fortaleza del navío que el cielo te dio en suerte para que en él pasases la mar deste mundo, sino haz cuenta que estás ya en seguro puerto, y aférrate con las áncoras de la buena consideración, y déjate estar hasta que te vengan a pedir la deuda que no hay hidalguía humana que de pagarla se escuse. »Contentísimo quedó Anselmo de las razones de Lotario, y así se las creyó como si fueran dichas por algún oráculo. Pero, con todo eso, le rogó que no dejase la empresa, aunque no fuese más de por curiosidad y entretenimiento, aunque no se aprovechase de allí adelante de tan ahincadas diligencias como hasta entonces; y que sólo quería que le escribiese algunos versos en su alabanza, debajo del nombre de Clori, porque él le daría a entender a Camila que andaba enamorado de una dama, a quien le había puesto aquel nombre por poder celebrarla con el decoro que a su honestidad se le debía; y que, cuando Lotario no quisiera tomar trabajo de escribir los versos, que él los haría. »-No será menester eso -dijo Lotario-, pues no me son tan enemigas las musas que algunos ratos del año no me visiten. Dile tú a Camila lo que has dicho del fingimiento de mis amores, que los versos yo los haré; si no tan buenos como el subjeto merece, serán, por lo menos, los mejores que yo pudiere. »Quedaron deste acuerdo el impertinente y el traidor amigo; y, vuelto Anselmo a su casa, preguntó a Camila lo que ella ya se maravillaba que no se lo hubiese preguntado: que fue que le dijese la ocasión por que le había escrito el papel que le envió. Camila le respondió que le había parecido que Lotario la miraba un poco más desenvueltamente que cuando él estaba en casa; pero que ya estaba desengañada y creía que había sido imaginación suya, porque ya Lotario huía de vella y de estar con ella a solas. Díjole Anselmo que bien podía estar segura de aquella sospecha, porque él sabía que Lotario andaba enamorado de una doncella principal de la ciudad, a quien él celebraba debajo del nombre de Clori, y que, aunque no lo estuviera, no había que temer de la verdad de Lotario y de la mucha amistad de entrambos. Y, a no estar avisada Camila de Lotario de que eran fingidos aquellos amores de Clori, y que él se lo había dicho a Anselmo por poder ocuparse algunos ratos en las mismas alabanzas de Camila, ella, sin duda, cayera en la desesperada red de los celos; mas, por estar ya advertida, pasó aquel sobresalto sin pesadumbre. »Otro día, estando los tres sobre mesa, rogó Anselmo a Lotario dijese alguna cosa de las que había compuesto a su amada Clori; que, pues Camila no la conocía, seguramente podía decir lo que quisiese. »-Aunque la conociera -respondió Lotario-, no encubriera yo nada, porque cuando algún amante loa a su dama de hermosa y la nota de cruel, ningún oprobrio hace a su buen crédito. Pero, sea lo que fuere, lo que sé decir, que ayer hice un soneto a la ingratitud desta Clori, que dice ansí: Soneto En el silencio de la noche, cuando ocupa el dulce sueño a los mortales, la pobre cuenta de mis ricos males estoy al cielo y a mi Clori dando. Y, al tiempo cuando el sol se va mostrando por las rosadas puertas orientales, con suspiros y acentos desiguales, voy la antigua querella renovando. Y cuando el sol, de su estrellado asiento, derechos rayos a la tierra envía, el llanto crece y doblo los gemidos. Vuelve la noche, y vuelvo al triste cuento, y siempre hallo, en mi mortal porfía, al cielo, sordo; a Clori, sin oídos. »Bien le pareció el soneto a Camila, pero mejor a Anselmo, pues le alabó, y dijo que era demasiadamente cruel la dama que a tan claras verdades no correspondía. A lo que dijo Camila: »-Luego, ¿todo aquello que los poetas enamorados dicen es verdad? »-En cuanto poetas, no la dicen -respondió Lotario-; mas, en cuanto enamorados, siempre quedan tan cortos como verdaderos. »-No hay duda deso -replicó Anselmo, todo por apoyar y acreditar los pensamientos de Lotario con Camila, tan descuidada del artificio de Anselmo como ya enamorada de Lotario. »Y así, con el gusto que de sus cosas tenía, y más, teniendo por entendido que sus deseos y escritos a ella se encaminaban, y que ella era la verdadera Clori, le rogó que si otro soneto o otros versos sabía, los dijese: »-Sí sé -respondió Lotario-, pero no creo que es tan bueno como el primero, o, por mejor decir, menos malo. Y podréislo bien juzgar, pues es éste: Soneto Yo sé que muero; y si no soy creído, es más cierto el morir, como es más cierto verme a tus pies, ¡oh bella ingrata!, muerto, antes que de adorarte arrepentido. Podré yo verme en la región de olvido, de vida y gloria y de favor desierto, y allí verse podrá en mi pecho abierto cómo tu hermoso rostro está esculpido. Que esta reliquia guardo para el duro trance que me amenaza mi porfía, que en tu mismo rigor se fortalece. ¡Ay de aquel que navega, el cielo escuro, por mar no usado y peligrosa vía, adonde norte o puerto no se ofrece! »También alabó este segundo soneto Anselmo, como había hecho el primero, y desta manera iba añadiendo eslabón a eslabón a la cadena con que se enlazaba y trababa su deshonra, pues cuando más Lotario le deshonraba, entonces le decía que estaba más honrado; y, con esto, todos los escalones que Camila bajaba hacia el centro de su menosprecio, los subía, en la opinión de su marido, hacia la cumbre de la virtud y de su buena fama. »Sucedió en esto que, hallándose una vez, entre otras, sola Camila con su doncella, le dijo: »-Corrida estoy, amiga Leonela, de ver en cuán poco he sabido estimarme, pues siquiera no hice que con el tiempo comprara Lotario la entera posesión que le di tan presto de mi voluntad. Temo que ha de estimar mi presteza o ligereza, sin que eche de ver la fuerza que él me hizo para no poder resistirle. »-No te dé pena eso, señora mía -respondió Leonela-, que no está la monta, ni es causa para menguar la estimación, darse lo que se da presto, si, en efecto, lo que se da es bueno, y ello por sí digno de estimarse. Y aun suele decirse que el que luego da, da dos veces. »-También se suele decir -dijo Camila- que lo que cuesta poco se estima en menos. »-No corre por ti esa razón -respondió Leonela-, porque el amor, según he oído decir, unas veces vuela y otras anda, con éste corre y con aquél va despacio, a unos entibia y a otros abrasa, a unos hiere y a otros mata, en un mesmo punto comienza la carrera de sus deseos y en aquel mesmo punto la acaba y concluye, por la mañana suele poner el cerco a una fortaleza y a la noche la tiene rendida, porque no hay fuerza que le resista. Y, siendo así, ¿de qué te espantas, o de qué temes, si lo mismo debe de haber acontecido a Lotario, habiendo tomado el amor por instrumento de rendirnos la ausencia de mi señor? Y era forzoso que en ella se concluyese lo que el amor tenía determinado, sin dar tiempo al tiempo para que Anselmo le tuviese de volver, y con su presencia quedase imperfecta la obra. Porque el amor no tiene otro mejor ministro para ejecutar lo que desea que es la ocasión: de la ocasión se sirve en todos sus hechos, principalmente en los principios. Todo esto sé yo muy bien, más de experiencia que de oídas, y algún día te lo diré, señora, que yo también soy de carne y de sangre moza. Cuanto más, señora Camila, que no te entregaste ni diste tan luego, que primero no hubieses visto en los ojos, en los suspiros, en las razones y en las promesas y dádivas de Lotario toda su alma, viendo en ella y en sus virtudes cuán digno era Lotario de ser amado. Pues si esto es ansí, no te asalten la imaginación esos escrupulosos y melindrosos pensamientos, sino asegúrate que Lotario te estima como tú le estimas a él, y vive con contento y satisfación de que, ya que caíste en el lazo amoroso, es el que te aprieta de valor y de estima. Y que no sólo tiene las cuatro eses que dicen que han de tener los buenos enamorados, sino todo un ABC entero: si no, escúchame y verás como te le digo de coro. Él es, según yo veo y a mí me parece, agradecido, bueno, caballero, dadivoso, enamorado, firme, gallardo, honrado, ilustre, leal, mozo, noble, onesto, principal, quantioso, rico, y las eses que dicen; y luego, tácito, verdadero. La X no le cuadra, porque es letra áspera; la Y ya está dicha; la Z, zelador de tu honra. »Rióse Camila del ABC de su doncella, y túvola por más plática en las cosas de amor que ella decía; y así lo confesó ella, descubriendo a Camila como trataba amores con un mancebo bien nacido, de la mesma ciudad; de lo cual se turbó Camila, temiendo que era aquél camino por donde su honra podía correr riesgo. Apuróla si pasaban sus pláticas a más que serlo. Ella, con poca vergüenza y mucha desenvoltura, le respondió que sí pasaban; porque es cosa ya cierta que los descuidos de las señoras quitan la vergüenza a las criadas, las cuales, cuando ven a las amas echar traspiés, no se les da nada a ellas de cojear, ni de que lo sepan. »No pudo hacer otra cosa Camila sino rogar a Leonela no dijese nada de su hecho al que decía ser su amante, y que tratase sus cosas con secreto, porque no viniesen a noticia de Anselmo ni de Lotario. Leonela respondió que así lo haría, mas cumpliólo de manera que hizo cierto el temor de Camila de que por ella había de perder su crédito. Porque la deshonesta y atrevida Leonela, después que vio que el proceder de su ama no era el que solía, atrevióse a entrar y poner dentro de casa a su amante, confiada que, aunque su señora le viese, no había de osar descubrille; que este daño acarrean, entre otros, los pecados de las señoras: que se hacen esclavas de sus mesmas criadas y se obligan a encubrirles sus deshonestidades y vilezas, como aconteció con Camila; que, aunque vio una y muchas veces que su Leonela estaba con su galán en un aposento de su casa, no sólo no la osaba reñir, mas dábale lugar a que lo encerrase, y quitábale todos los estorbos, para que no fuese visto de su marido. »Pero no los pudo quitar que Lotario no le viese una vez salir, al romper del alba; el cual, sin conocer quién era, pensó primero que debía de ser alguna fantasma; mas, cuando le vio caminar, embozarse y encubrirse con cuidado y recato, cayó de su simple pensamiento y dio en otro, que fuera la perdición de todos si Camila no lo remediara. Pensó Lotario que aquel hombre que había visto salir tan a deshora de casa de Anselmo no había entrado en ella por Leonela, ni aun se acordó si Leonela era en el mundo; sólo creyó que Camila, de la misma manera que había sido fácil y ligera con él, lo era para otro; que estas añadiduras trae consigo la maldad de la mujer mala: que pierde el crédito de su honra con el mesmo a quien se entregó rogada y persuadida, y cree que con mayor facilidad se entrega a otros, y da infalible crédito a cualquiera sospecha que desto le venga. Y no parece sino que le faltó a Lotario en este punto todo su buen entendimiento, y se le fueron de la memoria todos sus advertidos discursos, pues, sin hacer alguno que bueno fuese, ni aun razonable, sin más ni más, antes que Anselmo se levantase, impaciente y ciego de la celosa rabia que las entrañas le roía, muriendo por vengarse de Camila, que en ninguna cosa le había ofendido, se fue a Anselmo y le dijo: »-Sábete, Anselmo, que ha muchos días que he andado peleando conmigo mesmo, haciéndome fuerza a no decirte lo que ya no es posible ni justo que más te encubra. Sábete que la fortaleza de Camila está ya rendida y sujeta a todo aquello que yo quisiere hacer della; y si he tardado en descubrirte esta verdad, ha sido por ver si era algún liviano antojo suyo, o si lo hacía por probarme y ver si eran con propósito firme tratados los amores que, con tu licencia, con ella he comenzado. Creí, ansimismo, que ella, si fuera la que debía y la que entrambos pensábamos, ya te hubiera dado cuenta de mi solicitud, pero, habiendo visto que se tarda, conozco que son verdaderas las promesas que me ha dado de que, cuando otra vez hagas ausencia de tu casa, me hablará en la recámara, donde está el repuesto de tus alhajas -y era la verdad, que allí le solía hablar Camila-; y no quiero que precipitosamente corras a hacer alguna venganza, pues no está aún cometido el pecado sino con pensamiento, y podría ser que, desde éste hasta el tiempo de ponerle por obra, se mudase el de Camila y naciese en su lugar el arrepentimiento. Y así, ya que, en todo o en parte, has seguido siempre mis consejos, sigue y guarda uno que ahora te diré, para que sin engaño y con medroso advertimento te satisfagas de aquello que más vieres que te convenga. Finge que te ausentas por dos o tres días, como otras veces sueles, y haz de manera que te quedes escondido en tu recámara, pues los tapices que allí hay y otras cosas con que te puedas encubrir te ofrecen mucha comodidad, y entonces verás por tus mismos ojos, y yo por los míos, lo que Camila quiere; y si fuere la maldad que se puede temer antes que esperar, con silencio, sagacidad y discreción podrás ser el verdugo de tu agravio. »Absorto, suspenso y admirado quedó Anselmo con las razones de Lotario, porque le cogieron en tiempo donde menos las esperaba oír, porque ya tenía a Camila por vencedora de los fingidos asaltos de Lotario y comenzaba a gozar la gloria del vencimiento. Callando estuvo por un buen espacio, mirando al suelo sin mover pestaña, y al cabo dijo: »-Tú lo has hecho, Lotario, como yo esperaba de tu amistad; en todo he de seguir tu consejo: haz lo que quisieres y guarda aquel secreto que ves que conviene en caso tan no pensado. »Prometióselo Lotario, y, en apartándose dél, se arrepintió totalmente de cuanto le había dicho, viendo cuán neciamente había andado, pues pudiera él vengarse de Camila, y no por camino tan cruel y tan deshonrado. Maldecía su entendimiento, afeaba su ligera determinación, y no sabía qué medio tomarse para deshacer lo hecho, o para dalle alguna razonable salida. Al fin, acordó de dar cuenta de todo a Camila; y, como no faltaba lugar para poderlo hacer, aquel mismo día la halló sola, y ella, así como vio que le podía hablar, le dijo. »-Sabed, amigo Lotario, que tengo una pena en el corazón que me le aprieta de suerte que parece que quiere reventar en el pecho, y ha de ser maravilla si no lo hace, pues ha llegado la desvergüenza de Leonela a tanto, que cada noche encierra a un galán suyo en esta casa y se está con él hasta el día, tan a costa de mi crédito cuanto le quedará campo abierto de juzgarlo al que le viere salir a horas tan inusitadas de mi casa. Y lo que me fatiga es que no la puedo castigar ni reñir: que el ser ella secretario de nuestros tratos me ha puesto un freno en la boca para callar los suyos, y temo que de aquí ha de nacer algún mal suceso. »Al principio que Camila esto decía creyó Lotario que era artificio para desmentille que el hombre que había visto salir era de Leonela, y no suyo; pero, viéndola llorar y afligirse, y pedirle remedio, vino a creer la verdad, y, en creyéndola, acabó de estar confuso y arrepentido del todo. Pero, con todo esto, respondió a Camila que no tuviese pena, que él ordenaría remedio para atajar la insolencia de Leonela. Díjole asimismo lo que, instigado de la furiosa rabia de los celos, había dicho a Anselmo, y cómo estaba concertado de esconderse en la recámara, para ver desde allí a la clara la poca lealtad que ella le guardaba. Pidióle perdón desta locura, y consejo para poder remedialla y salir bien de tan revuelto laberinto como su mal discurso le había puesto. »Espantada quedó Camila de oír lo que Lotario le decía, y con mucho enojo y muchas y discretas razones le riñó y afeó su mal pensamiento y la simple y mala determinación que había tenido. Pero, como naturalmente tiene la mujer ingenio presto para el bien y para el mal más que el varón, puesto que le va faltando cuando de propósito se pone a hacer discursos, luego al instante halló Camila el modo de remediar tan al parecer inremediable negocio, y dijo a Lotario que procurase que otro día se escondiese Anselmo donde decía, porque ella pensaba sacar de su escondimiento comodidad para que desde allí en adelante los dos se gozasen sin sobresalto alguno; y, sin declararle del todo su pensamiento, le advirtió que tuviese cuidado que, en estando Anselmo escondido, él viniese cuando Leonela le llamase, y que a cuanto ella le dijese le respondiese como respondiera aunque no supiera que Anselmo le escuchaba. Porfió Lotario que le acabase de declarar su intención, porque con más seguridad y aviso guardase todo lo que viese ser necesario. »-Digo -dijo Camila- que no hay más que guardar, si no fuere responderme como yo os preguntare (no queriendo Camila darle antes cuenta de lo que pensaba hacer, temerosa que no quisiese seguir el parecer que a ella tan bueno le parecía, y siguiese o buscase otros que no podrían ser tan buenos). »Con esto, se fue Lotario; y Anselmo, otro día, con la escusa de ir aquella aldea de su amigo, se partió y volvió a esconderse: que lo pudo hacer con comodidad, porque de industria se la dieron Camila y Leonela. »Escondido, pues, Anselmo, con aquel sobresalto que se puede imaginar que tendría el que esperaba ver por sus ojos hacer notomía de las entrañas de su honra, íbase a pique de perder el sumo bien que él pensaba que tenía en su querida Camila. Seguras ya y ciertas Camila y Leonela que Anselmo estaba escondido, entraron en la recámara; y apenas hubo puesto los pies en ella Camilia, cuando, dando un grande suspiro, dijo: »-¡Ay, Leonela amiga! ¿No sería mejor que, antes que llegase a poner en ejecución lo que no quiero que sepas, porque no procures estorbarlo, que tomases la daga de Anselmo, que te he pedido, y pasases con ella este infame pecho mío? Pero no hagas tal, que no será razón que yo lleve la pena de la ajena culpa. Primero quiero saber qué es lo que vieron en mí los atrevidos y deshonestos ojos de Lotario que fuese causa de darle atrevimiento a descubrirme un tan mal deseo como es el que me ha descubierto, en desprecio de su amigo y en deshonra mía. Ponte, Leonela, a esa ventana y llámale, que, sin duda alguna, él debe de estar en la calle, esperando poner en efeto su mala intención. Pero primero se pondrá la cruel cuanto honrada mía. »-¡Ay, señora mía! -respondió la sagaz y advertida Leonela-, y ¿qué es lo que quieres hacer con esta daga? ¿Quieres por ventura quitarte la vida o quitársela a Lotario? Que cualquiera destas cosas que quieras ha de redundar en pérdida de tu crédito y fama. Mejor es que disimules tu agravio, y no des lugar a que este mal hombre entre ahora en esta casa y nos halle solas. Mira, señora, que somos flacas mujeres, y él es hombre y determinado; y, como viene con aquel mal propósito, ciego y apasionado, quizá antes que tú pongas en ejecución el tuyo, hará él lo que te estaría más mal que quitarte la vida. ¡Mal haya mi señor Anselmo, que tanto mal ha querido dar a este desuellacaras en su casa! Y ya, señora, que le mates, como yo pienso que quieres hacer, ¿qué hemos de hacer dél después de muerto? »-¿Qué, amiga? -respondió Camila-: dejarémosle para que Anselmo le entierre, pues será justo que tenga por descanso el trabajo que tomare en poner debajo de la tierra su misma infamia. Llámale, acaba, que todo el tiempo que tardo en tomar la debida venganza de mi agravio parece que ofendo a la lealtad que a mi esposo debo. »Todo esto escuchaba Anselmo, y, a cada palabra que Camila decía, se le mudaban los pensamientos; mas, cuando entendió que estaba resuelta en matar a Lotario, quiso salir y descubrirse, porque tal cosa no se hiciese; pero detúvole el deseo de ver en qué paraba tanta gallardía y honesta resolución, con propósito de salir a tiempo que la estorbase. »Tomóle en esto a Camila un fuerte desmayo, y, arrojándose encima de una cama que allí estaba, comenzó Leonela a llorar muy amargamente y a decir: »-¡Ay, desdichada de mí si fuese tan sin ventura que se me muriese aquí entre mis brazos la flor de la honestidad del mundo, la corona de las buenas mujeres, el ejemplo de la castidad...! »Con otras cosas a éstas semejantes, que ninguno la escuchara que no la tuviera por la más lastimada y leal doncella del mundo, y a su señora por otra nueva y perseguida Penélope. Poco tardó en volver de su desmayo Camila; y, al volver en sí, dijo: »-¿Por qué no vas, Leonela, a llamar al más leal amigo de amigo que vio el sol o cubrió la noche? Acaba, corre, aguija, camina, no se esfogue con la tardanza el fuego de la cólera que tengo, y se pase en amenazas y maldiciones la justa venganza que espero. »-Ya voy a llamarle, señora mía -dijo Leonela-, mas hasme de dar primero esa daga, porque no hagas cosa, en tanto que falto, que dejes con ella que llorar toda la vida a todos los que bien te quieren. »-Ve segura, Leonela amiga, que no haré -respondió Camila-; porque, ya que sea atrevida y simple a tu parecer en volver por mi honra, no lo he de ser tanto como aquella Lucrecia de quien dicen que se mató sin haber cometido error alguno, y sin haber muerto primero a quien tuvo la causa de su desgracia. Yo moriré, si muero, pero ha de ser vengada y satisfecha del que me ha dado ocasión de venir a este lugar a llorar sus atrevimientos, nacidos tan sin culpa mía. »Mucho se hizo de rogar Leonela antes que saliese a llamar a Lotario, pero, en fin, salió; y, entre tanto que volvía, quedó Camilia diciendo, como que hablaba consigo misma: »-¡Válame Dios! ¿No fuera más acertado haber despedido a Lotario, como otras muchas veces lo he hecho, que no ponerle en condición, como ya le he puesto, que me tenga por deshonesta y mala, siquiera este tiempo que he de tardar en desengañarle? Mejor fuera, sin duda; pero no quedara yo vengada, ni la honra de mi marido satisfecha, si tan a manos lavadas y tan a paso llano se volviera a salir de donde sus malos pensamientos le entraron. Pague el traidor con la vida lo que intentó con tan lascivo deseo: sepa el mundo, si acaso llegare a saberlo, de que Camila no sólo guardó la lealtad a su esposo, sino que le dio venganza del que se atrevió a ofendelle. Mas, con todo, creo que fuera mejor dar cuenta desto a Anselmo, pero ya se la apunté a dar en la carta que le escribí al aldea, y creo que el no acudir él al remedio del daño que allí le señalé, debió de ser que, de puro bueno y confiado, no quiso ni pudo creer que en el pecho de su tan firme amigo pudiese caber género de pensamiento que contra su honra fuese; ni aun yo lo creí después, por muchos días, ni lo creyera jamás, si su insolencia no llegara a tanto, que las manifiestas dádivas y las largas promesas y las continuas lágrimas no me lo manifestaran. Mas, ¿para qué hago yo ahora estos discursos? ¿Tiene, por ventura, una resulución gallarda necesidad de consejo alguno? No, por cierto. ¡Afuera, pues, traidores; aquí, venganzas! ¡Entre el falso, venga, llegue, muera y acabe, y suceda lo que sucediere! Limpia entré en poder del que el cielo me dio por mío, limpia he de salir dél; y, cuando mucho, saldré bañada en mi casta sangre, y en la impura del más falso amigo que vio la amistad en el mundo. »Y, diciendo esto, se paseaba por la sala con la daga desenvainada, dando tan desconcertados y desaforados pasos, y haciendo tales ademanes, que no parecía sino que le faltaba el juicio, y que no era mujer delicada, sino un rufián desesperado. »Todo lo miraba Anselmo, cubierto detrás de unos tapices donde se había escondido, y de todo se admiraba, y ya le parecía que lo que había visto y oído era bastante satisfación para mayores sospechas; y ya quisiera que la prueba de venir Lotario faltara, temeroso de algún mal repentino suceso. Y, estando ya para manifestarse y salir, para abrazar y desengañar a su esposa, se detuvo porque vio que Leonela volvía con Lotario de la mano; y, así como Camila le vio, haciendo con la daga en el suelo una gran raya delante della, le dijo: »-Lotario, advierte lo que te digo: si a dicha te atrevieres a pasar desta raya que ves, ni aun llegar a ella, en el punto que viere que lo intentas, en ese mismo me pasaré el pecho con esta daga que en las manos tengo. Y, antes que a esto me respondas palabra, quiero que otras algunas me escuches; que después responderás lo que más te agradare. Lo primero, quiero, Lotario, que me digas si conoces a Anselmo, mi marido, y en qué opinión le tienes; y lo segundo, quiero saber también si me conoces a mí. Respóndeme a esto, y no te turbes, ni pienses mucho lo que has de responder, pues no son dificultades las que te pregunto. »No era tan ignorante Lotario que, desde el primer punto que Camila le dijo que hiciese esconder a Anselmo, no hubiese dado en la cuenta de lo que ella pensaba hacer; y así, correspondió con su intención tan discretamente, y tan a tiempo, que hicieran los dos pasar aquella mentira por más que cierta verdad; y así, respondió a Camila desta manera: »-No pensé yo, hermosa Camila, que me llamabas para preguntarme cosas tan fuera de la intención con que yo aquí vengo. Si lo haces por dilatarme la prometida merced, desde más lejos pudieras entretenerla, porque tanto más fatiga el bien deseado cuanto la esperanza está más cerca de poseello; pero, porque no digas que no respondo a tus preguntas, digo que conozco a tu esposo Anselmo, y nos conocemos los dos desde nuestros más tiernos años; y no quiero decir lo que tú tan bien sabes de nuestra amistad, por no me hacer testigo del agravio que el amor hace que le haga, poderosa disculpa de mayores yerros. A ti te conozco y tengo en la misma posesión que él te tiene; que, a no ser así, por menos prendas que las tuyas no había yo de ir contra lo que debo a ser quien soy y contra las santas leyes de la verdadera amistad, ahora por tan poderoso enemigo como el amor por mí rompidas y violadas. »-Si eso confiesas -respondió Camila-, enemigo mortal de todo aquello que justamente merece ser amado, ¿con qué rostro osas parecer ante quien sabes que es el espejo donde se mira aquel en quien tú te debieras mirar, para que vieras con cuán poca ocasión le agravias? Pero ya cayo, ¡ay, desdichada de mí!, en la cuenta de quién te ha hecho tener tan poca con lo que a ti mismo debes, que debe de haber sido alguna desenvoltura mía, que no quiero llamarla deshonestidad, pues no habrá procedido de deliberada determinación, sino de algún descuido de los que las mujeres que piensan que no tienen de quién recatarse suelen hacer inadvertidamente. Si no, dime: ¿cuándo, ¡oh traidor!, respondí a tus ruegos con alguna palabra o señal que pudiese despertar en ti alguna sombra de esperanza de cumplir tus infames deseos? ¿Cuándo tus amorosas palabras no fueron deshechas y reprehendidas de las mías con rigor y con aspereza? ¿Cuándo tus muchas promesas y mayores dádivas fueron de mí creídas, ni admitidas? Pero, por parecerme que alguno no puede perseverar en el intento amoroso luengo tiempo, si no es sustentado de alguna esperanza, quiero atribuirme a mí la culpa de tu impertinencia, pues, sin duda, algún descuido mío ha sustentado tanto tiempo tu cuidado; y así, quiero castigarme y darme la pena que tu culpa merece. Y, porque vieses que, siendo conmigo tan inhumana, no era posible dejar de serlo contigo, quise traerte a ser testigo del sacrificio que pienso hacer a la ofendida honra de mi tan honrado marido, agraviado de ti con el mayor cuidado que te ha sido posible, y de mí también con el poco recato que he tenido del huir la ocasión, si alguna te di, para favorecer y canonizar tus malas intenciones. Torno a decir que la sospecha que tengo que algún descuido mío engendró en ti tan desvariados pensamientos es la que más me fatiga, y la que yo más deseo castigar con mis propias manos, porque, castigándome otro verdugo, quizá sería más pública mi culpa; pero, antes que esto haga, quiero matar muriendo, y llevar conmigo quien me acabe de satisfacer el deseo de la venganza que espero y tengo, viendo allá, dondequiera que fuere, la pena que da la justicia desinteresada y que no se dobla al que en términos tan desesperados me ha puesto. »Y, diciendo estas razones, con una increíble fuerza y ligereza arremetió a Lotario con la daga desenvainada, con tales muestras de querer enclavársela en el pecho, que casi él estuvo en duda si aquellas demostraciones eran falsas o verdaderas, porque le fue forzoso valerse de su industria y de su fuerza para estorbar que Camila no le diese. La cual tan vivamente fingía aquel estraño embuste y fealdad que, por dalle color de verdad, la quiso matizar con su misma sangre; porque, viendo que no podía haber a Lotario, o fingiendo que no podía, dijo: »-Pues la suerte no quiere satisfacer del todo mi tan justo deseo, a lo menos, no será tan poderosa que, en parte, me quite que no le satisfaga. Y, haciendo fuerza para soltar la mano de la daga, que Lotario la tenía asida, la sacó, y, guiando su punta por parte que pudiese herir no profundamente, se la entró y escondió por más arriba de la islilla del lado izquierdo, junto al hombro, y luego se dejó caer en el suelo, como desmayada. »Estaban Leonela y Lotario suspensos y atónitos de tal suceso, y todavía dudaban de la verdad de aquel hecho, viendo a Camila tendida en tierra y bañada en su sangre. Acudió Lotario con mucha presteza, despavorido y sin aliento, a sacar la daga, y, en ver la pequeña herida, salió del temor que hasta entonces tenía, y de nuevo se admiró de la sagacidad, prudencia y mucha discreción de la hermosa Camila; y, por acudir con lo que a él le tocaba, comenzó a hacer una larga y triste lamentación sobre el cuerpo de Camila, como si estuviera difunta, echándose muchas maldiciones, no sólo a él, sino al que había sido causa de habelle puesto en aquel término. Y, como sabía que le escuchaba su amigo Anselmo, decía cosas que el que le oyera le tuviera mucha más lástima que a Camila, aunque por muerta la juzgara. »Leonela la tomó en brazos y la puso en el lecho, suplicando a Lotario fuese a buscar quien secretamente a Camila curase; pedíale asimismo consejo y parecer de lo que dirían a Anselmo de aquella herida de su señora, si acaso viniese antes que estuviese sana. Él respondió que dijesen lo que quisiesen, que él no estaba para dar consejo que de provecho fuese; sólo le dijo que procurase tomarle la sangre, porque él se iba adonde gentes no le viesen. Y, con muestras de mucho dolor y sentimiento, se salió de casa; y, cuando se vio solo y en parte donde nadie le veía, no cesaba de hacerse cruces, maravillándose de la industria de Camila y de los ademanes tan proprios de Leonela. Consideraba cuán enterado había de quedar Anselmo de que tenía por mujer a una segunda Porcia, y deseaba verse con él para celebrar los dos la mentira y la verdad más disimulada que jamás pudiera imaginarse. »Leonela tomó, como se ha dicho, la sangre a su señora, que no era más de aquello que bastó para acreditar su embuste; y, lavando con un poco de vino la herida, se la ató lo mejor que supo, diciendo tales razones, en tanto que la curaba, que, aunque no hubieran precedido otras, bastaran a hacer creer a Anselmo que tenía en Camila un simulacro de la honestidad. »Juntáronse a las palabras de Leonela otras de Camila, llamándose cobarde y de poco ánimo, pues le había faltado al tiempo que fuera más necesario tenerle, para quitarse la vida, que tan aborrecida tenía. Pedía consejo a su doncella si daría, o no, todo aquel suceso a su querido esposo; la cual le dijo que no se lo dijese, porque le pondría en obligación de vengarse de Lotario, lo cual no podría ser sin mucho riesgo suyo, y que la buena mujer estaba obligada a no dar ocasión a su marido a que riñese, sino a quitalle todas aquellas que le fuese posible. »Respondió Camila que le parecía muy bien su parecer y que ella le seguiría; pero que en todo caso convenía buscar qué decir a Anselmo de la causa de aquella herida, que él no podría dejar de ver; a lo que Leonela respondía que ella, ni aun burlando, no sabía mentir. »-Pues yo, hermana -replicó Camila-, ¿qué tengo de saber, que no me atreveré a forjar ni sustentar una mentira, si me fuese en ello la vida? Y si es que no hemos de saber dar salida a esto, mejor será decirle la verdad desnuda, que no que nos alcance en mentirosa cuenta. »-No tengas pena, señora: de aquí a mañana -respondió Leonela- yo pensaré qué le digamos, y quizá que, por ser la herida donde es, la podrás encubrir sin que él la vea, y el cielo será servido de favorecer a nuestros tan justos y tan honrados pensamientos. Sosiégate, señora mía, y procura sosegar tu alteración, porque mi señor no te halle sobresaltada, y lo demás déjalo a mi cargo, y al de Dios, que siempre acude a los buenos deseos. »Atentísimo había estado Anselmo a escuchar y a ver representar la tragedia de la muerte de su honra; la cual con tan estraños y eficaces afectos la representaron los personajes della, que pareció que se habían transformado en la misma verdad de lo que fingían. Deseaba mucho la noche, y el tener lugar para salir de su casa, y ir a verse con su buen amigo Lotario, congratulándose con él de la margarita preciosa que había hallado en el desengaño de la bondad de su esposa. Tuvieron cuidado las dos de darle lugar y comodidad a que saliese, y él, sin perdella, salió y luego fue a buscar a Lotario, el cual hallado, no se puede buenamente contar los abrazos que le dio, las cosas que de su contento le dijo, las alabanzas que dio a Camila. Todo lo cual escuchó Lotario sin poder dar muestras de alguna alegría, porque se le representaba a la memoria cuán engañado estaba su amigo y cuán injustamente él le agraviaba. Y, aunque Anselmo veía que Lotario no se alegraba, creía ser la causa por haber dejado a Camila herida y haber él sido la causa; y así, entre otras razones, le dijo que no tuviese pena del suceso de Camila, porque, sin duda, la herida era ligera, pues quedaban de concierto de encubrírsela a él; y que, según esto, no había de qué temer, sino que de allí adelante se gozase y alegrase con él, pues por su industria y medio él se veía levantado a la más alta felicidad que acertara desearse, y quería que no fuesen otros sus entretenimientos que en hacer versos en alabanza de Camila, que la hiciesen eterna en la memoria de los siglos venideros. Lotario alabó su buena determinación y dijo que él, por su parte, ayudaría a levantar tan ilustre edificio. »Con esto quedó Anselmo el hombre más sabrosamente engañado que pudo haber en el mundo: él mismo llevó por la mano a su casa, creyendo que llevaba el instrumento de su gloria, toda la perdición de su fama. Recebíale Camila con rostro, al parecer, torcido, aunque con alma risueña. Duró este engaño algunos días, hasta que, al cabo de pocos meses, volvió Fortuna su rueda y salió a plaza la maldad con tanto artificio hasta allí cubierta, y a Anselmo le costó la vida su impertinente curiosidad.» Capítulo XXXV. Donde se da fin a la novela del Curioso impertinente Poco más quedaba por leer de la novela, cuando del caramanchón donde reposaba don Quijote salió Sancho Panza todo alborotado, diciendo a voces: -Acudid, señores, presto y socorred a mi señor, que anda envuelto en la más reñida y trabada batalla que mis ojos han visto. ¡Vive Dios, que ha dado una cuchillada al gigante enemigo de la señora princesa Micomicona, que le ha tajado la cabeza, cercen a cercen, como si fuera un nabo! -¿Qué dices, hermano? -dijo el cura, dejando de leer lo que de la novela quedaba-. ¿Estáis en vos, Sancho? ¿Cómo diablos puede ser eso que decís, estando el gigante dos mil leguas de aquí? En esto, oyeron un gran ruido en el aposento, y que don Quijote decía a voces: -¡Tente, ladrón, malandrín, follón, que aquí te tengo, y no te ha de valer tu cimitarra! Y parecía que daba grandes cuchilladas por las paredes. Y dijo Sancho: -No tienen que pararse a escuchar, sino entren a despartir la pelea, o a ayudar a mi amo; aunque ya no será menester, porque, sin duda alguna, el gigante está ya muerto, y dando cuenta a Dios de su pasada y mala vida, que yo vi correr la sangre por el suelo, y la cabeza cortada y caída a un lado, que es tamaña como un gran cuero de vino. -Que me maten -dijo a esta sazón el ventero- si don Quijote, o don diablo, no ha dado alguna cuchillada en alguno de los cueros de vino tinto que a su cabecera estaban llenos, y el vino derramado debe de ser lo que le parece sangre a este buen hombre. Y, con esto, entró en el aposento, y todos tras él, y hallaron a don Quijote en el más estraño traje del mundo: estaba en camisa, la cual no era tan cumplida que por delante le acabase de cubrir los muslos, y por detrás tenía seis dedos menos; las piernas eran muy largas y flacas, llenas de vello y no nada limpias; tenía en la cabeza un bonetillo colorado, grasiento, que era del ventero; en el brazo izquierdo tenía revuelta la manta de la cama, con quien tenía ojeriza Sancho, y él se sabía bien el porqué; y en la derecha, desenvainada la espada, con la cual daba cuchilladas a todas partes, diciendo palabras como si verdaderamente estuviera peleando con algún gigante. Y es lo bueno que no tenía los ojos abiertos, porque estaba durmiendo y soñando que estaba en batalla con el gigante; que fue tan intensa la imaginación de la aventura que iba a fenecer, que le hizo soñar que ya había llegado al reino de Micomicón, y que ya estaba en la pelea con su enemigo. Y había dado tantas cuchilladas en los cueros, creyendo que las daba en el gigante, que todo el aposento estaba lleno de vino; lo cual visto por el ventero, tomó tanto enojo que arremetió con don Quijote, y a puño cerrado le comenzó a dar tantos golpes que si Cardenio y el cura no se le quitaran, él acabara la guerra del gigante; y, con todo aquello, no despertaba el pobre caballero, hasta que el barbero trujo un gran caldero de agua fría del pozo y se le echó por todo el cuerpo de golpe, con lo cual despertó don Quijote; mas no con tanto acuerdo que echase de ver de la manera que estaba. Dorotea, que vio cuán corta y sotilmente estaba vestido, no quiso entrar a ver la batalla de su ayudador y de su contrario. Andaba Sancho buscando la cabeza del gigante por todo el suelo, y, como no la hallaba, dijo: -Ya yo sé que todo lo desta casa es encantamento; que la otra vez, en este mesmo lugar donde ahora me hallo, me dieron muchos mojicones y porrazos, sin saber quién me los daba, y nunca pude ver a nadie; y ahora no parece por aquí esta cabeza que vi cortar por mis mismísimos ojos, y la sangre corría del cuerpo como de una fuente. -¿Qué sangre ni qué fuente dices, enemigo de Dios y de sus santos? -dijo el ventero-. ¿No vees, ladrón, que la sangre y la fuente no es otra cosa que estos cueros que aquí están horadados y el vino tinto que nada en este aposento, que nadando vea yo el alma en los infiernos de quien los horadó? -No sé nada -respondió Sancho-; sólo sé que vendré a ser tan desdichado que, por no hallar esta cabeza, se me ha de deshacer mi condado como la sal en el agua. Y estaba peor Sancho despierto que su amo durmiendo: tal le tenían las promesas que su amo le había hecho. El ventero se desesperaba de ver la flema del escudero y el maleficio del señor, y juraba que no había de ser como la vez pasada, que se le fueron sin pagar; y que ahora no le habían de valer los previlegios de su caballería para dejar de pagar lo uno y lo otro, aun hasta lo que pudiesen costar las botanas que se habían de echar a los rotos cueros. Tenía el cura de las manos a don Quijote, el cual, creyendo que ya había acabado la aventura, y que se hallaba delante de la princesa Micomicona, se hincó de rodillas delante del cura, diciendo: -Bien puede la vuestra grandeza, alta y famosa señora, vivir, de hoy más, segura que le pueda hacer mal esta mal nacida criatura; y yo también, de hoy más, soy quito de la palabra que os di, pues, con el ayuda del alto Dios y con el favor de aquella por quien yo vivo y respiro, tan bien la he cumplido. -¿No lo dije yo? -dijo oyendo esto Sancho-. Sí que no estaba yo borracho: ¡mirad si tiene puesto ya en sal mi amo al gigante! ¡Ciertos son los toros: mi condado está de molde! ¿Quién no había de reír con los disparates de los dos, amo y mozo? Todos reían sino el ventero, que se daba a Satanás. Pero, en fin, tanto hicieron el barbero, Cardenio y el cura que, con no poco trabajo, dieron con don Quijote en la cama, el cual se quedó dormido, con muestras de grandísimo cansancio. Dejáronle dormir, y saliéronse al portal de la venta a consolar a Sancho Panza de no haber hallado la cabeza del gigante; aunque más tuvieron que hacer en aplacar al ventero, que estaba desesperado por la repentina muerte de sus cueros. Y la ventera decía en voz y en grito: -En mal punto y en hora menguada entró en mi casa este caballero andante, que nunca mis ojos le hubieran visto, que tan caro me cuesta. La vez pasada se fue con el costo de una noche, de cena, cama, paja y cebada, para él y para su escudero, y un rocín y un jumento, diciendo que era caballero aventurero (que mala ventura le dé Dios a él y a cuantos aventureros hay en el mundo) y que por esto no estaba obligado a pagar nada, que así estaba escrito en los aranceles de la caballería andantesca. Y ahora, por su respeto, vino estotro señor y me llevó mi cola, y hámela vuelto con más de dos cuartillos de daño, toda pelada, que no puede servir para lo que la quiere mi marido. Y, por fin y remate de todo, romperme mis cueros y derramarme mi vino; que derramada le vea yo su sangre. ¡Pues no se piense; que, por los huesos de mi padre y por el siglo de mi madre, si no me lo han de pagar un cuarto sobre otro, o no me llamaría yo como me llamo ni sería hija de quien soy! Estas y otras razones tales decía la ventera con grande enojo, y ayudábala su buena criada Maritornes. La hija callaba, y de cuando en cuando se sonreía. El cura lo sosegó todo, prometiendo de satisfacerles su pérdida lo mejor que pudiese, así de los cueros como del vino, y principalmente del menoscabo de la cola, de quien tanta cuenta hacían. Dorotea consoló a Sancho Panza diciéndole que cada y cuando que pareciese haber sido verdad que su amo hubiese descabezado al gigante, le prometía, en viéndose pacífica en su reino, de darle el mejor condado que en él hubiese. Consolóse con esto Sancho, y aseguró a la princesa que tuviese por cierto que él había visto la cabeza del gigante, y que, por más señas, tenía una barba que le llegaba a la cintura; y que si no parecía, era porque todo cuanto en aquella casa pasaba era por vía de encantamento, como él lo había probado otra vez que había posado en ella. Dorotea dijo que así lo creía, y que no tuviese pena, que todo se haría bien y sucedería a pedir de boca. Sosegados todos, el cura quiso acabar de leer la novela, porque vio que faltaba poco. Cardenio, Dorotea y todos los demás le rogaron la acabase. Él, que a todos quiso dar gusto, y por el que él tenía de leerla, prosiguió el cuento, que así decía: «Sucedió, pues, que, por la satisfación que Anselmo tenía de la bondad de Camila, vivía una vida contenta y descuidada, y Camila, de industria, hacía mal rostro a Lotario, porque Anselmo entendiese al revés de la voluntad que le tenía; y, para más confirmación de su hecho, pidió licencia Lotario para no venir a su casa, pues claramente se mostraba la pesadumbre que con su vista Camila recebía; mas el engañado Anselmo le dijo que en ninguna manera tal hiciese. Y, desta manera, por mil maneras era Anselmo el fabricador de su deshonra, creyendo que lo era de su gusto. »En esto, el que tenía Leonela de verse cualificada, no de con sus amores, llegó a tanto que, sin mirar a otra cosa, se iba tras él a suelta rienda, fiada en que su señora la encubría, y aun la advertía del modo que con poco recelo pudiese ponerle en ejecución. En fin, una noche sintió Anselmo pasos en el aposento de Leonela, y, queriendo entrar a ver quién los daba, sintió que le detenían la puerta, cosa que le puso más voluntad de abrirla; y tanta fuerza hizo, que la abrió, y entró dentro a tiempo que vio que un hombre saltaba por la ventana a la calle; y, acudiendo con presteza a alcanzarle o conocerle, no pudo conseguir lo uno ni lo otro, porque Leonela se abrazó con él, diciéndole: »-Sosiégate, señor mío, y no te alborotes, ni sigas al que de aquí saltó; es cosa mía, y tanto, que es mi esposo. »No lo quiso creer Anselmo; antes, ciego de enojo, sacó la daga y quiso herir a Leonela, diciéndole que le dijese la verdad, si no, que la mataría. Ella, con el miedo, sin saber lo que se decía, le dijo: »-No me mates, señor, que yo te diré cosas de más importancia de las que puedes imaginar. »-Dilas luego -dijo Anselmo-; si no, muerta eres. »-Por ahora será imposible -dijo Leonela-, según estoy de turbada; déjame hasta mañana, que entonces sabrás de mí lo que te ha de admirar; y está seguro que el que saltó por esta ventana es un mancebo desta ciudad, que me ha dado la mano de ser mi esposo. »Sosegóse con esto Anselmo y quiso aguardar el término que se le pedía, porque no pensaba oír cosa que contra Camila fuese, por estar de su bondad tan satisfecho y seguro; y así, se salió del aposento y dejó encerrada en él a Leonela, diciéndole que de allí no saldría hasta que le dijese lo que tenía que decirle. »Fue luego a ver a Camila y a decirle, como le dijo, todo aquello que con su doncella le había pasado, y la palabra que le había dado de decirle grandes cosas y de importancia. Si se turbó Camila o no, no hay para qué decirlo, porque fue tanto el temor que cobró, creyendo verdaderamente -y era de creer- que Leonela había de decir a Anselmo todo lo que sabía de su poca fe, que no tuvo ánimo para esperar si su sospecha salía falsa o no. Y aquella mesma noche, cuando le pareció que Anselmo dormía, juntó las mejores joyas que tenía y algunos dineros, y, sin ser de nadie sentida, salió de casa y se fue a la de Lotario, a quien contó lo que pasaba, y le pidió que la pusiese en cobro, o que se ausentasen los dos donde de Anselmo pudiesen estar seguros. La confusión en que Camila puso a Lotario fue tal, que no le sabía responder palabra, ni menos sabía resolverse en lo que haría. »En fin, acordó de llevar a Camila a un monesterio, en quien era priora una su hermana. Consintió Camila en ello, y, con la presteza que el caso pedía, la llevó Lotario y la dejó en el monesterio, y él, ansimesmo, se ausentó luego de la ciudad, sin dar parte a nadie de su ausencia. »Cuando amaneció, sin echar de ver Anselmo que Camila faltaba de su lado, con el deseo que tenía de saber lo que Leonela quería decirle, se levantó y fue adonde la había dejado encerrada. Abrió y entró en el aposento, pero no halló en él a Leonela: sólo halló puestas unas sábanas añudadas a la ventana, indicio y señal que por allí se había descolgado e ido. Volvió luego muy triste a decírselo a Camila, y, no hallándola en la cama ni en toda la casa, quedó asombrado.Preguntó a los criados de casa por ella, pero nadie le supo dar razón de lo que pedía. »Acertó acaso, andando a buscar a Camila, que vio sus cofres abiertos y que dellos faltaban las más de sus joyas, y con esto acabó de caer en la cuenta de su desgracia, y en que no era Leonela la causa de su desventura. Y, ansí como estaba, sin acabarse de vestir, triste y pensativo, fue a dar cuenta de su desdicha a su amigo Lotario. Mas, cuando no le halló, y sus criados le dijeron que aquella noche había faltado de casa y había llevado consigo todos los dineros que tenía, pensó perder el juicio. Y, para acabar de concluir con todo, volviéndose a su casa, no halló en ella ninguno de cuantos criados ni criadas tenía, sino la casa desierta y sola. »No sabía qué pensar, qué decir, ni qué hacer, y poco a poco se le iba volviendo el juicio. Contemplábase y mirábase en un instante sin mujer, sin amigo y sin criados; desamparado, a su parecer, del cielo que le cubría, y sobre todo sin honra, porque en la falta de Camila vio su perdición. »Resolvióse, en fin, a cabo de una gran pieza, de irse a la aldea de su amigo, donde había estado cuando dio lugar a que se maquinase toda aquella desventura. Cerró las puertas de su casa, subió a caballo, y con desmayado aliento se puso en camino; y, apenas hubo andado la mitad, cuando, acosado de sus pensamientos, le fue forzoso apearse y arrendar su caballo a un árbol, a cuyo tronco se dejó caer, dando tiernos y dolorosos suspiros, y allí se estuvo hasta casi que anochecía; y aquella hora vio que venía un hombre a caballo de la ciudad, y, después de haberle saludado, le preguntó qué nuevas había en Florencia. El ciudadano respondió: »-Las más estrañas que muchos días ha se han oído en ella; porque se dice públicamente que Lotario, aquel grande amigo de Anselmo el rico, que vivía a San Juan, se llevó esta noche a Camila, mujer de Anselmo, el cual tampoco parece. Todo esto ha dicho una criada de Camila, que anoche la halló el gobernador descolgándose con una sábana por las ventanas de la casa de Anselmo. En efeto, no sé puntualmente cómo pasó el negocio; sólo sé que toda la ciudad está admirada deste suceso, porque no se podía esperar tal hecho de la mucha y familiar amistad de los dos, que dicen que era tanta, que los llamaban los dos amigos. »-¿Sábese, por ventura -dijo Anselmo-, el camino que llevan Lotario y Camila? »-Ni por pienso -dijo el ciudadano-, puesto que el gobernador ha usado de mucha diligencia en buscarlos »-A Dios vais, señor -dijo Anselmo. »-Con Él quedéis -respondió el ciudadano, y fuese. »Con tan desdichadas nuevas, casi casi llegó a términos Anselmo, no sólo de perder el juicio, sino de acabar la vida. Levantóse como pudo y llegó a casa de su amigo, que aún no sabía su desgracia; mas, como le vio llegar amarillo, consumido y seco, entendió que de algún grave mal venía fatigado. Pidió luego Anselmo que le acostasen, y que le diesen aderezo de escribir. Hízose así, y dejáronle acostado y solo, porque él así lo quiso, y aun que le cerrasen la puerta. Viéndose, pues, solo, comenzó a cargar tanto la imaginación de su desventura, que claramente conoció que se le iba acabando la vida; y así, ordenó de dejar noticia de la causa de su estraña muerte; y, comenzando a escribir, antes que acabase de poner todo lo que quería, le faltó el aliento y dejó la vida en las manos del dolor que le causó su curiosidad impertinente. »Viendo el señor de casa que era ya tarde y que Anselmo no llamaba, acordó de entrar a saber si pasaba adelante su indisposición, y hallóle tendido boca abajo, la mitad del cuerpo en la cama y la otra mitad sobre el bufete, sobre el cual estaba con el papel escrito y abierto, y él tenía aún la pluma en la mano. Llegóse el huésped a él, habiéndole llamado primero; y, trabándole por la mano, viendo que no le respondía y hallándole frío, vio que estaba muerto. Admiróse y congojóse en gran manera, y llamó a la gente de casa para que viesen la desgracia a Anselmo sucedida; y, finalmente, leyó el papel, que conoció que de su mesma mano estaba escrito, el cual contenía estas razones: Un necio e impertinente deseo me quitó la vida. Si las nuevas de mi muerte llegaren a los oídos de Camila, sepa que yo la perdono, porque no estaba ella obligada a hacer milagros, ni yo tenía necesidad de querer que ella los hiciese; y, pues yo fui el fabricador de mi deshonra, no hay para qué... »Hasta aquí escribió Anselmo, por donde se echó de ver que en aquel punto, sin poder acabar la razón, se le acabó la vida. Otro día dio aviso su amigo a los parientes de Anselmo de su muerte, los cuales ya sabían su desgracia, y el monesterio donde Camila estaba, casi en el término de acompañar a su esposo en aquel forzoso viaje, no por las nuevas del muerto esposo, mas por las que supo del ausente amigo. Dícese que, aunque se vio viuda, no quiso salir del monesterio, ni, menos, hacer profesión de monja, hasta que, no de allí a muchos días, le vinieron nuevas que Lotario había muerto en una batalla que en aquel tiempo dio monsiur de Lautrec al Gran Capitán Gonzalo Fernández de Córdoba en el reino de Nápoles, donde había ido a parar el tarde arrepentido amigo; lo cual sabido por Camila, hizo profesión, y acabó en breves días la vida a las rigurosas manos de tristezas y melancolías. Éste fue el fin que tuvieron todos, nacido de un tan desatinado principio.» -Bien -dijo el cura- me parece esta novela, pero no me puedo persuadir que esto sea verdad; y si es fingido, fingió mal el autor, porque no se puede imaginar que haya marido tan necio que quiera hacer tan costosa experiencia como Anselmo. Si este caso se pusiera entre un galán y una dama, pudiérase llevar, pero entre marido y mujer, algo tiene del imposible; y, en lo que toca al modo de contarle, no me descontenta. Capítulo XXXVI. Que trata de la brava y descomunal batalla que don Quijote tuvo con unos cueros de vino tinto, con otros raros sucesos que en la venta le sucedieron Estando en esto, el ventero, que estaba a la puerta de la venta, dijo: -Esta que viene es una hermosa tropa de huéspedes: si ellos paran aquí, gaudeamus tenemos. -¿Qué gente es? -dijo Cardenio. -Cuatro hombres -respondió el ventero- vienen a caballo, a la jineta, con lanzas y adargas, y todos con antifaces negros; y junto con ellos viene una mujer vestida de blanco, en un sillón, ansimesmo cubierto el rostro, y otros dos mozos de a pie. -¿Vienen muy cerca? -preguntó el cura. -Tan cerca -respondió el ventero-, que ya llegan. Oyendo esto Dorotea, se cubrió el rostro, y Cardenio se entró en el aposento de don Quijote; y casi no habían tenido lugar para esto, cuando entraron en la venta todos los que el ventero había dicho; y, apeándose los cuatro de a caballo, que de muy gentil talle y disposición eran, fueron a apear a la mujer que en el sillón venía; y, tomándola uno dellos en sus brazos, la sentó en una silla que estaba a la entrada del aposento donde Cardenio se había escondido. En todo este tiempo, ni ella ni ellos se habían quitado los antifaces, ni hablado palabra alguna; sólo que, al sentarse la mujer en la silla, dio un profundo suspiro y dejó caer los brazos, como persona enferma y desmayada. Los mozos de a pie llevaron los caballos a la caballeriza. Viendo esto el cura, deseoso de saber qué gente era aquella que con tal traje y tal silencio estaba, se fue donde estaban los mozos, y a uno dellos le preguntó lo que ya deseaba; el cual le respondió: -Pardiez, señor, yo no sabré deciros qué gente sea ésta; sólo sé que muestra ser muy principal, especialmente aquel que llegó a tomar en sus brazos a aquella señora que habéis visto; y esto dígolo porque todos los demás le tienen respeto, y no se hace otra cosa más de la que él ordena y manda. -Y la señora, ¿quién es? -preguntó el cura. -Tampoco sabré decir eso -respondió el mozo-, porque en todo el camino no la he visto el rostro; suspirar sí la he oído muchas veces, y dar unos gemidos que parece que con cada uno dellos quiere dar el alma. Y no es de maravillar que no sepamos más de lo que habemos dicho, porque mi compañero y yo no ha más de dos días que los acompañamos; porque, habiéndolos encontrado en el camino, nos rogaron y persuadieron que viniésemos con ellos hasta el Andalucía, ofreciéndose a pagárnoslo muy bien. -¿Y habéis oído nombrar a alguno dellos? -preguntó el cura. -No, por cierto -respondió el mozo-, porque todos caminan con tanto silencio que es maravilla, porque no se oye entre ellos otra cosa que los suspiros y sollozos de la pobre señora, que nos mueven a lástima; y sin duda tenemos creído que ella va forzada dondequiera que va, y, según se puede colegir por su hábito, ella es monja, o va a serlo, que es lo más cierto, y quizá porque no le debe de nacer de voluntad el monjío, va triste, como parece. -Todo podría ser -dijo el cura. Y, dejándolos, se volvió adonde estaba Dorotea, la cual, como había oído suspirar a la embozada, movida de natural compasión, se llegó a ella y le dijo: -¿Qué mal sentís, señora mía? Mirad si es alguno de quien las mujeres suelen tener uso y experiencia de curarle, que de mi parte os ofrezco una buena voluntad de serviros. A todo esto callaba la lastimada señora; y, aunque Dorotea tornó con mayores ofrecimientos, todavía se estaba en su silencio, hasta que llegó el caballero embozado que dijo el mozo que los demás obedecían, y dijo a Dorotea: -No os canséis, señora, en ofrecer nada a esa mujer, porque tiene por costumbre de no agradecer cosa que por ella se hace, ni procuréis que os responda, si no queréis oír alguna mentira de su boca. -Jamás la dije -dijo a esta sazón la que hasta allí había estado callando-; antes, por ser tan verdadera y tan sin trazas mentirosas, me veo ahora en tanta desventura; y desto vos mesmo quiero que seáis el testigo, pues mi pura verdad os hace a vos ser falso y mentiroso. Oyó estas razones Cardenio bien clara y distintamente, como quien estaba tan junto de quien las decía que sola la puerta del aposento de don Quijote estaba en medio; y, así como las oyó, dando una gran voz dijo: -¡Válgame Dios! ¿Qué es esto que oigo? ¿Qué voz es esta que ha llegado a mis oídos? Volvió la cabeza a estos gritos aquella señora, toda sobresaltada, y, no viendo quién las daba, se levantó en pie y fuese a entrar en el aposento; lo cual visto por el caballero, la detuvo, sin dejarla mover un paso. A ella, con la turbación y desasosiego, se le cayó el tafetán con que traía cubierto el rostro, y descubrió una hermosura incomparable y un rostro milagroso, aunque descolorido y asombrado, porque con los ojos andaba rodeando todos los lugares donde alcanzaba con la vista, con tanto ahínco, que parecía persona fuera de juicio; cuyas señales, sin saber por qué las hacía, pusieron gran lástima en Dorotea y en cuantos la miraban. Teníala el caballero fuertemente asida por las espaldas, y, por estar tan ocupado en tenerla, no pudo acudir a alzarse el embozo, que se le caía, como, en efeto, se le cayó del todo; y, alzando los ojos Dorotea, que abrazada con la señora estaba, vio que el que abrazada ansimesmo la tenía era su esposo don Fernando; y, apenas le hubo conocido, cuando, arrojando de lo íntimo de sus entrañas un luengo y tristísimo ''¡ay!'', se dejó caer de espaldas desmayada; y, a no hallarse allí junto el barbero, que la recogió en los brazos, ella diera consigo en el suelo. Acudió luego el cura a quitarle el embozo, para echarle agua en el rostro, y así como la descubrió la conoció don Fernando, que era el que estaba abrazado con la otra, y quedó como muerto en verla; pero no porque dejase, con todo esto, de tener a Luscinda, que era la que procuraba soltarse de sus brazos; la cual había conocido en el suspiro a Cardenio, y él la había conocido a ella. Oyó asimesmo Cardenio el ¡ay! que dio Dorotea cuando se cayó desmayada, y, creyendo que era su Luscinda, salió del aposento despavorido, y lo primero que vio fue a don Fernando, que tenía abrazada a Luscinda. También don Fernando conoció luego a Cardenio; y todos tres, Luscinda, Cardenio y Dorotea, quedaron mudos y suspensos, casi sin saber lo que les había acontecido. Callaban todos y mirábanse todos: Dorotea a don Fernando, don Fernando a Cardenio, Cardenio a Luscinda y Luscinda a Cardenio. Mas quien primero rompió el silencio fue Luscinda, hablando a don Fernando desta manera: -Dejadme, señor don Fernando, por lo que debéis a ser quien sois, ya que por otro respeto no lo hagáis; dejadme llegar al muro de quien yo soy yedra, al arrimo de quien no me han podido apartar vuestras importunaciones, vuestras amenazas, vuestras promesas ni vuestras dádivas. Notad cómo el cielo, por desusados y a nosotros encubiertos caminos, me ha puesto a mi verdadero esposo delante. Y bien sabéis por mil costosas experiencias que sola la muerte fuera bastante para borrarle de mi memoria. Sean, pues, parte tan claros desengaños para que volváis, ya que no podáis hacer otra cosa, el amor en rabia, la voluntad en despecho, y acabadme con él la vida; que, como yo la rinda delante de mi buen esposo, la daré por bien empleada: quizá con mi muerte quedará satisfecho de la fe que le mantuve hasta el último trance de la vida. Había en este entretanto vuelto Dorotea en sí, y había estado escuchando todas las razones que Luscinda dijo, por las cuales vino en conocimiento de quién ella era; que, viendo que don Fernando aún no la dejaba de los brazos, ni respondía a sus razones, esforzándose lo más que pudo, se levantó y se fue a hincar de rodillas a sus pies; y, derramando mucha cantidad de hermosas y lastimeras lágrimas, así le comenzó a decir: -Si ya no es, señor mío, que los rayos deste sol que en tus brazos eclipsado tienes te quitan y ofuscan los de tus ojos, ya habrás echado de ver que la que a tus pies está arrodillada es la sin ventura, hasta que tú quieras, y la desdichada Dorotea. Yo soy aquella labradora humilde a quien tú, por tu bondad o por tu gusto, quisiste levantar a la alteza de poder llamarse tuya. Soy la que, encerrada en los límites de la honestidad, vivió vida contenta hasta que, a las voces de tus importunidades, y, al parecer, justos y amorosos sentimientos, abrió las puertas de su recato y te entregó las llaves de su libertad: dádiva de ti tan mal agradecida, cual lo muestra bien claro haber sido forzoso hallarme en el lugar donde me hallas, y verte yo a ti de la manera que te veo. Pero, con todo esto, no querría que cayese en tu imaginación pensar que he venido aquí con pasos de mi deshonra, habiéndome traído sólo los del dolor y sentimiento de verme de ti olvidada. Tú quisiste que yo fuese tuya, y quisístelo de manera que, aunque ahora quieras que no lo sea, no será posible que tú dejes de ser mío. Mira, señor mío, que puede ser recompensa a la hermosura y nobleza por quien me dejas la incomparable voluntad que te tengo. Tú no puedes ser de la hermosa Luscinda, porque eres mío, ni ella puede ser tuya, porque es de Cardenio; y más fácil te será, si en ello miras, reducir tu voluntad a querer a quien te adora, que no encaminar la que te aborrece a que bien te quiera. Tú solicitaste mi descuido, tú rogaste a mi entereza, tú no ignoraste mi calidad, tú sabes bien de la manera que me entregué a toda tu voluntad: no te queda lugar ni acogida de llamarte a engaño. Y si esto es así, como lo es, y tú eres tan cristiano como caballero, ¿por qué por tantos rodeos dilatas de hacerme venturosa en los fines, como me heciste en los principios? Y si no me quieres por la que soy, que soy tu verdadera y legítima esposa, quiéreme, a lo menos, y admíteme por tu esclava; que, como yo esté en tu poder, me tendré por dichosa y bien afortunada. No permitas, con dejarme y desampararme, que se hagan y junten corrillos en mi deshonra; no des tan mala vejez a mis padres, pues no lo merecen los leales servicios que, como buenos vasallos, a los tuyos siempre han hecho. Y si te parece que has de aniquilar tu sangre por mezclarla con la mía, considera que pocas o ninguna nobleza hay en el mundo que no haya corrido por este camino, y que la que se toma de las mujeres no es la que hace al caso en las ilustres decendencias; cuanto más, que la verdadera nobleza consiste en la virtud, y si ésta a ti te falta, negándome lo que tan justamente me debes, yo quedaré con más ventajas de noble que las que tú tienes. En fin, señor, lo que últimamente te digo es que, quieras o no quieras, yo soy tu esposa: testigos son tus palabras, que no han ni deben ser mentirosas, si ya es que te precias de aquello por que me desprecias; testigo será la firma que hiciste, y testigo el cielo, a quien tú llamaste por testigo de lo que me prometías. Y, cuando todo esto falte, tu misma conciencia no ha de faltar de dar voces callando en mitad de tus alegrías, volviendo por esta verdad que te he dicho y turbando tus mejores gustos y contentos. Estas y otras razones dijo la lastimada Dorotea, con tanto sentimiento y lágrimas, que los mismos que acompañaban a don Fernando, y cuantos presentes estaban, la acompañaron en ellas. Escuchóla don Fernando sin replicalle palabra, hasta que ella dio fin a las suyas y principio a tantos sollozos y suspiros, que bien había de ser corazón de bronce el que con muestras de tanto dolor no se enterneciera. Mirándola estaba Luscinda, no menos lastimada de su sentimiento que admirada de su mucha discreción y hermosura; y, aunque quisiera llegarse a ella y decirle algunas palabras de consuelo, no la dejaban los brazos de don Fernando, que apretada la tenían. El cual, lleno de confusión y espanto, al cabo de un buen espacio que atentamente estuvo mirando a Dorotea, abrió los brazos y, dejando libre a Luscinda, dijo: -Venciste, hermosa Dorotea, venciste; porque no es posible tener ánimo para negar tantas verdades juntas. Con el desmayo que Luscinda había tenido, así como la dejó don Fernando, iba a caer en el suelo; mas, hallándose Cardenio allí junto, que a las espaldas de don Fernando se había puesto porque no le conociese, prosupuesto todo temor y aventurando a todo riesgo, acudió a sostener a Luscinda, y, cogiéndola entre sus brazos, le dijo: -Si el piadoso cielo gusta y quiere que ya tengas algún descanso, leal, firme y hermosa señora mía, en ninguna parte creo yo que le tendrás más seguro que en estos brazos que ahora te reciben, y otro tiempo te recibieron, cuando la fortuna quiso que pudiese llamarte mía. A estas razones, puso Luscinda en Cardenio los ojos, y, habiendo comenzado a conocerle, primero por la voz, y asegurándose que él era con la vista, casi fuera de sentido y sin tener cuenta a ningún honesto respeto, le echó los brazos al cuello, y, juntando su rostro con el de Cardenio, le dijo: -Vos sí, señor mío, sois el verdadero dueño desta vuestra captiva, aunque más lo impida la contraria suerte, y, aunque más amenazas le hagan a esta vida que en la vuestra se sustenta. Estraño espectáculo fue éste para don Fernando y para todos los circunstantes, admirándose de tan no visto suceso. Parecióle a Dorotea que don Fernando había perdido la color del rostro y que hacía ademán de querer vengarse de Cardenio, porque le vio encaminar la mano a ponella en la espada; y, así como lo pensó, con no vista presteza se abrazó con él por las rodillas, besándoselas y teniéndole apretado, que no le dejaba mover, y, sin cesar un punto de sus lágrimas, le decía: -¿Qué es lo que piensas hacer, único refugio mío, en este tan impensado trance? Tú tienes a tus pies a tu esposa, y la que quieres que lo sea está en los brazos de su marido. Mira si te estará bien o te será posible deshacer lo que el cielo ha hecho, o si te convendrá querer levantar a igualar a ti mismo a la que, pospuesto todo inconveniente, confirmada en su verdad y firmeza, delante de tus ojos tiene los suyos, bañados de licor amoroso el rostro y pecho de su verdadero esposo. Por quien Dios es te ruego, y por quien tú eres te suplico, que este tan notorio desengaño no sólo no acreciente tu ira, sino que la mengüe en tal manera, que con quietud y sosiego permitas que estos dos amantes le tengan, sin impedimiento tuyo, todo el tiempo que el cielo quisiere concedérsele; y en esto mostrarás la generosidad de tu ilustre y noble pecho, y verá el mundo que tiene contigo más fuerza la razón que el apetito. En tanto que esto decía Dorotea, aunque Cardenio tenía abrazada a Luscinda, no quitaba los ojos de don Fernando, con determinación de que, si le viese hacer algún movimiento en su perjuicio, procurar defenderse y ofender como mejor pudiese a todos aquellos que en su daño se mostrasen, aunque le costase la vida. Pero a esta sazón acudieron los amigos de don Fernando, y el cura y el barbero, que a todo habían estado presentes, sin que faltase el bueno de Sancho Panza, y todos rodeaban a don Fernando, suplicándole tuviese por bien de mirar las lágrimas de Dorotea; y que, siendo verdad, como sin duda ellos creían que lo era, lo que en sus razones había dicho, que no permitiese quedase defraudada de sus tan justas esperanzas. Que considerase que, no acaso, como parecía, sino con particular providencia del cielo, se habían todos juntado en lugar donde menos ninguno pensaba; y que advirtiese -dijo el cura- que sola la muerte podía apartar a Luscinda de Cardenio; y, aunque los dividiesen filos de alguna espada, ellos tendrían por felicísima su muerte; y que en los lazos inremediables era suma cordura, forzándose y venciéndose a sí mismo, mostrar un generoso pecho, permitiendo que por sola su voluntad los dos gozasen el bien que el cielo ya les había concedido; que pusiese los ojos ansimesmo en la beldad de Dorotea, y vería que pocas o ninguna se le podían igualar, cuanto más hacerle ventaja, y que juntase a su hermosura su humildad y el estremo del amor que le tenía; y, sobre todo, advirtiese que si se preciaba de caballero y de cristiano, que no podía hacer otra cosa que cumplille la palabra dada, y que, cumpliéndosela, cumpliría con Dios y satisfaría a las gentes discretas, las cuales saben y conocen que es prerrogativa de la hermosura, aunque esté en sujeto humilde, como se acompañe con la honestidad, poder levantarse e igualarse a cualquiera alteza, sin nota de menoscabo del que la levanta e iguala a sí mismo; y, cuando se cumplen las fuertes leyes del gusto, como en ello no intervenga pecado, no debe de ser culpado el que las sigue. En efeto, a estas razones añadieron todos otras, tales y tantas, que el valeroso pecho de don Fernando (en fin, como alimentado con ilustre sangre) se ablandó y se dejó vencer de la verdad, que él no pudiera negar aunque quisiera; y la señal que dio de haberse rendido y entregado al buen parecer que se le había propuesto fue abajarse y abrazar a Dorotea, diciéndole: -Levantaos, señora mía, que no es justo que esté arrodillada a mis pies la que yo tengo en mi alma; y si hasta aquí no he dado muestras de lo que digo, quizá ha sido por orden del cielo, para que, viendo yo en vos la fe con que me amáis, os sepa estimar en lo que merecéis. Lo que os ruego es que no me reprehendáis mi mal término y mi mucho descuido, pues la misma ocasión y fuerza que me movió para acetaros por mía, esa misma me impelió para procurar no ser vuestro. Y que esto sea verdad, volved y mirad los ojos de la ya contenta Luscinda, y en ellos hallaréis disculpa de todos mis yerros; y, pues ella halló y alcanzó lo que deseaba, y yo he hallado en vos lo que me cumple, viva ella segura y contenta luengos y felices años con su Cardenio, que yo rogaré al cielo que me los deje vivir con mi Dorotea. Y, diciendo esto, la tornó a abrazar y a juntar su rostro con el suyo, con tan tierno sentimiento, que le fue necesario tener gran cuenta con que las lágrimas no acabasen de dar indubitables señas de su amor y arrepentimiento. No lo hicieron así las de Luscinda y Cardenio, y aun las de casi todos los que allí presentes estaban, porque comenzaron a derramar tantas, los unos de contento proprio y los otros del ajeno, que no parecía sino que algún grave y mal caso a todos había sucedido. Hasta Sancho Panza lloraba, aunque después dijo que no lloraba él sino por ver que Dorotea no era, como él pensaba, la reina Micomicona, de quien él tantas mercedes esperaba. Duró algún espacio, junto con el llanto, la admiración en todos, y luego Cardenio y Luscinda se fueron a poner de rodillas ante don Fernando, dándole gracias de la merced que les había hecho con tan corteses razones, que don Fernando no sabía qué responderles; y así, los levantó y abrazó con muestras de mucho amor y de mucha cortesía. Preguntó luego a Dorotea le dijese cómo había venido a aquel lugar tan lejos del suyo. Ella, con breves y discretas razones, contó todo lo que antes había contado a Cardenio, de lo cual gustó tanto don Fernando y los que con él venían, que quisieran que durara el cuento más tiempo: tanta era la gracia con que Dorotea contaba sus desventuras. Y, así como hubo acabado, dijo don Fernando lo que en la ciudad le había acontecido después que halló el papel en el seno de Luscinda, donde declaraba ser esposa de Cardenio y no poderlo ser suya. Dijo que la quiso matar, y lo hiciera si de sus padres no fuera impedido; y que así, se salió de su casa, despechado y corrido, con determinación de vengarse con más comodidad; y que otro día supo como Luscinda había faltado de casa de sus padres, sin que nadie supiese decir dónde se había ido, y que, en resolución, al cabo de algunos meses vino a saber como estaba en un monesterio, con voluntad de quedarse en él toda la vida, si no la pudiese pasar con Cardenio; y que, así como lo supo, escogiendo para su compañía aquellos tres caballeros, vino al lugar donde estaba, a la cual no había querido hablar, temeroso que, en sabiendo que él estaba allí, había de haber más guarda en el monesterio; y así, aguardando un día a que la portería estuviese abierta, dejó a los dos a la guarda de la puerta, y él, con otro, habían entrado en el monesterio buscando a Luscinda, la cual hallaron en el claustro hablando con una monja; y, arrebatándola, sin darle lugar a otra cosa, se habían venido con ella a un lugar donde se acomodaron de aquello que hubieron menester para traella. Todo lo cual habían podido hacer bien a su salvo, por estar el monesterio en el campo, buen trecho fuera del pueblo. Dijo que, así como Luscinda se vio en su poder, perdió todos los sentidos; y que, después de vuelta en sí, no había hecho otra cosa sino llorar y suspirar, sin hablar palabra alguna; y que así, acompañados de silencio y de lágrimas, habían llegado a aquella venta, que para él era haber llegado al cielo, donde se rematan y tienen fin todas las desventuras de la tierra. Capítulo XXXVII. Que prosigue la historia de la famosa infanta Micomicona, con otras graciosas aventuras Todo esto escuchaba Sancho, no con poco dolor de su ánima, viendo que se le desparecían e iban en humo las esperanzas de su ditado, y que la linda princesa Micomicona se le había vuelto en Dorotea, y el gigante en don Fernando, y su amo se estaba durmiendo a sueño suelto, bien descuidado de todo lo sucedido. No se podía asegurar Dorotea si era soñado el bien que poseía. Cardenio estaba en el mismo pensamiento, y el de Luscinda corría por la misma cuenta. Don Fernando daba gracias al cielo por la merced recebida y haberle sacado de aquel intricado laberinto, donde se hallaba tan a pique de perder el crédito y el alma; y, finalmente, cuantos en la venta estaban, estaban contentos y gozosos del buen suceso que habían tenido tan trabados y desesperados negocios. Todo lo ponía en su punto el cura, como discreto, y a cada uno daba el parabién del bien alcanzado; pero quien más jubilaba y se contentaba era la ventera, por la promesa que Cardenio y el cura le habían hecho de pagalle todos los daños e intereses que por cuenta de don Quijote le hubiesen venido. Sólo Sancho, como ya se ha dicho, era el afligido, el desventurado y el triste; y así, con malencónico semblante, entró a su amo, el cual acababa de despertar, a quien dijo: -Bien puede vuestra merced, señor Triste Figura, dormir todo lo que quisiere, sin cuidado de matar a ningún gigante, ni de volver a la princesa su reino: que ya todo está hecho y concluido. -Eso creo yo bien -respondió don Quijote-, porque he tenido con el gigante la más descomunal y desaforada batalla que pienso tener en todos los días de mi vida; y de un revés, ¡zas!, le derribé la cabeza en el suelo, y fue tanta la sangre que le salió, que los arroyos corrían por la tierra como si fueran de agua. -Como si fueran de vino tinto, pudiera vuestra merced decir mejor -respondió Sancho-, porque quiero que sepa vuestra merced, si es que no lo sabe, que el gigante muerto es un cuero horadado, y la sangre, seis arrobas de vino tinto que encerraba en su vientre; y la cabeza cortada es la puta que me parió, y llévelo todo Satanás. -Y ¿qué es lo que dices, loco? -replicó don Quijote-. ¿Estás en tu seso? -Levántese vuestra merced -dijo Sancho-, y verá el buen recado que ha hecho, y lo que tenemos que pagar; y verá a la reina convertida en una dama particular, llamada Dorotea, con otros sucesos que, si cae en ellos, le han de admirar. -No me maravillaría de nada deso -replicó don Quijote-, porque, si bien te acuerdas, la otra vez que aquí estuvimos te dije yo que todo cuanto aquí sucedía eran cosas de encantamento, y no sería mucho que ahora fuese lo mesmo. -Todo lo creyera yo -respondió Sancho-, si también mi manteamiento fuera cosa dese jaez, mas no lo fue, sino real y verdaderamente; y vi yo que el ventero que aquí está hoy día tenía del un cabo de la manta, y me empujaba hacia el cielo con mucho donaire y brío, y con tanta risa como fuerza; y donde interviene conocerse las personas, tengo para mí, aunque simple y pecador, que no hay encantamento alguno, sino mucho molimiento y mucha mala ventura. -Ahora bien, Dios lo remediará -dijo don Quijote-. Dame de vestir y déjame salir allá fuera, que quiero ver los sucesos y transformaciones que dices. Diole de vestir Sancho, y, en el entretanto que se vestía, contó el cura a don Fernando y a los demás las locuras de don Quijote, y del artificio que habían usado para sacarle de la Peña Pobre, donde él se imaginaba estar por desdenes de su señora. Contóles asimismo casi todas las aventuras que Sancho había contado, de que no poco se admiraron y rieron, por parecerles lo que a todos parecía: ser el más estraño género de locura que podía caber en pensamiento desparatado. Dijo más el cura: que, pues ya el buen suceso de la señora Dorotea impidía pasar con su disignio adelante, que era menester inventar y hallar otro para poderle llevar a su tierra. Ofrecióse Cardenio de proseguir lo comenzado, y que Luscinda haría y representaría la persona de Dorotea. -No -dijo don Fernando-, no ha de ser así: que yo quiero que Dorotea prosiga su invención; que, como no sea muy lejos de aquí el lugar deste buen caballero, yo holgaré de que se procure su remedio. -No está más de dos jornadas de aquí. -Pues, aunque estuviera más, gustara yo de caminallas, a trueco de hacer tan buena obra. Salió, en esto, don Quijote, armado de todos sus pertrechos, con el yelmo, aunque abollado, de Mambrino en la cabeza, embrazado de su rodela y arrimado a su tronco o lanzón. Suspendió a don Fernando y a los demás la estraña presencia de don Quijote, viendo su rostro de media legua de andadura, seco y amarillo, la desigualdad de sus armas y su mesurado continente, y estuvieron callando hasta ver lo que él decía, el cual, con mucha gravedad y reposo, puestos los ojos en la hermosa Dorotea, dijo: -Estoy informado, hermosa señora, deste mi escudero que la vuestra grandeza se ha aniquilado, y vuestro ser se ha deshecho, porque de reina y gran señora que solíades ser os habéis vuelto en una particular doncella. Si esto ha sido por orden del rey nigromante de vuestro padre, temeroso que yo no os diese la necesaria y debida ayuda, digo que no supo ni sabe de la misa la media, y que fue poco versado en las historias caballerescas, porque si él las hubiera leído y pasado tan atentamente y con tanto espacio como yo las pasé y leí, hallara a cada paso cómo otros caballeros de menor fama que la mía habían acabado cosas más dificultosas, no siéndolo mucho matar a un gigantillo, por arrogante que sea; porque no ha muchas horas que yo me vi con él, y... quiero callar, porque no me digan que miento; pero el tiempo, descubridor de todas las cosas, lo dirá cuando menos lo pensemos. -Vístesos vos con dos cueros, que no con un gigante -dijo a esta sazón el ventero. Al cual mandó don Fernando que callase y no interrumpiese la plática de don Quijote en ninguna manera; y don Quijote prosiguió diciendo: -Digo, en fin, alta y desheredada señora, que si por la causa que he dicho vuestro padre ha hecho este metamorfóseos en vuestra persona, que no le deis crédito alguno, porque no hay ningún peligro en la tierra por quien no se abra camino mi espada, con la cual, poniendo la cabeza de vuestro enemigo en tierra, os pondré a vos la corona de la vuestra en la cabeza en breves días. No dijo más don Quijote, y esperó a que la princesa le respondiese, la cual, como ya sabía la determinación de don Fernando de que se prosiguiese adelante en el engaño hasta llevar a su tierra a don Quijote, con mucho donaire y gravedad, le respondió: -Quienquiera que os dijo, valeroso caballero de la Triste Figura, que yo me había mudado y trocado de mi ser, no os dijo lo cierto, porque la misma que ayer fui me soy hoy. Verdad es que alguna mudanza han hecho en mí ciertos acaecimientos de buena ventura, que me la han dado la mejor que yo pudiera desearme, pero no por eso he dejado de ser la que antes y de tener los mesmos pensamientos de valerme del valor de vuestro valeroso e invenerable brazo que siempre he tenido. Así que, señor mío, vuestra bondad vuelva la honra al padre que me engendró, y téngale por hombre advertido y prudente, pues con su ciencia halló camino tan fácil y tan verdadero para remediar mi desgracia; que yo creo que si por vos, señor, no fuera, jamás acertara a tener la ventura que tengo; y en esto digo tanta verdad como son buenos testigos della los más destos señores que están presentes. Lo que resta es que mañana nos pongamos en camino, porque ya hoy se podrá hacer poca jornada, y en lo demás del buen suceso que espero, lo dejaré a Dios y al valor de vuestro pecho. Esto dijo la discreta Dorotea, y, en oyéndolo don Quijote, se volvió a Sancho, y, con muestras de mucho enojo, le dijo: -Ahora te digo, Sanchuelo, que eres el mayor bellacuelo que hay en España. Dime, ladrón vagamundo, ¿no me acabaste de decir ahora que esta princesa se había vuelto en una doncella que se llamaba Dorotea, y que la cabeza que entiendo que corté a un gigante era la puta que te parió, con otros disparates que me pusieron en la mayor confusión que jamás he estado en todos los días de mi vida? ¡Voto... -y miró al cielo y apretó los dientes- que estoy por hacer un estrago en ti, que ponga sal en la mollera a todos cuantos mentirosos escuderos hubiere de caballeros andantes, de aquí adelante, en el mundo! -Vuestra merced se sosiegue, señor mío -respondió Sancho-, que bien podría ser que yo me hubiese engañado en lo que toca a la mutación de la señora princesa Micomicona; pero, en lo que toca a la cabeza del gigante, o, a lo menos, a la horadación de los cueros y a lo de ser vino tinto la sangre, no me engaño, ¡vive Dios!, porque los cueros allí están heridos, a la cabecera del lecho de vuestra merced, y el vino tinto tiene hecho un lago el aposento; y si no, al freír de los huevos lo verá; quiero decir que lo verá cuando aquí su merced del señor ventero le pida el menoscabo de todo. De lo demás, de que la señora reina se esté como se estaba, me regocijo en el alma, porque me va mi parte, como a cada hijo de vecino. -Ahora yo te digo, Sancho -dijo don Quijote-, que eres un mentecato; y perdóname, y basta. -Basta -dijo don Fernando-, y no se hable más en esto; y, pues la señora princesa dice que se camine mañana, porque ya hoy es tarde, hágase así, y esta noche la podremos pasar en buena conversación hasta el venidero día, donde todos acompañaremos al señor don Quijote, porque queremos ser testigos de las valerosas e inauditas hazañas que ha de hacer en el discurso desta grande empresa que a su cargo lleva. -Yo soy el que tengo de serviros y acompañaros -respondió don Quijote-, y agradezco mucho la merced que se me hace y la buena opinión que de mí se tiene, la cual procuraré que salga verdadera, o me costará la vida, y aun más, si más costarme puede. Muchas palabras de comedimiento y muchos ofrecimientos pasaron entre don Quijote y don Fernando; pero a todo puso silencio un pasajero que en aquella sazón entró en la venta, el cual en su traje mostraba ser cristiano recién venido de tierra de moros, porque venía vestido con una casaca de paño azul, corta de faldas, con medias mangas y sin cuello; los calzones eran asimismo de lienzo azul, con bonete de la misma color; traía unos borceguíes datilados y un alfanje morisco, puesto en un tahelí que le atravesaba el pecho. Entró luego tras él, encima de un jumento, una mujer a la morisca vestida, cubierto el rostro con una toca en la cabeza; traía un bonetillo de brocado, y vestida una almalafa, que desde los hombros a los pies la cubría. Era el hombre de robusto y agraciado talle, de edad de poco más de cuarenta años, algo moreno de rostro, largo de bigotes y la barba muy bien puesta. En resolución, él mostraba en su apostura que si estuviera bien vestido, le juzgaran por persona de calidad y bien nacida. Pidió, en entrando, un aposento, y, como le dijeron que en la venta no le había, mostró recebir pesadumbre; y, llegándose a la que en el traje parecía mora, la apeó en sus brazos. Luscinda, Dorotea, la ventera, su hija y Maritornes, llevadas del nuevo y para ellas nunca visto traje, rodearon a la mora, y Dorotea, que siempre fue agraciada, comedida y discreta, pareciéndole que así ella como el que la traía se congojaban por la falta del aposento, le dijo: -No os dé mucha pena, señora mía, la incomodidad de regalo que aquí falta, pues es proprio de ventas no hallarse en ellas; pero, con todo esto, si gustáredes de pasar con nosotras -señalando a Luscinda-, quizá en el discurso de este camino habréis hallado otros no tan buenos acogimientos. No respondió nada a esto la embozada, ni hizo otra cosa que levantarse de donde sentado se había, y, puestas entrambas manos cruzadas sobre el pecho, inclinada la cabeza, dobló el cuerpo en señal de que lo agradecía. Por su silencio imaginaron que, sin duda alguna, debía de ser mora, y que no sabía hablar cristiano. Llegó, en esto, el cautivo, que entendiendo en otra cosa hasta entonces había estado, y, viendo que todas tenían cercada a la que con él venía, y que ella a cuanto le decían callaba, dijo: -Señoras mías, esta doncella apenas entiende mi lengua, ni sabe hablar otra ninguna sino conforme a su tierra, y por esto no debe de haber respondido, ni responde, a lo que se le ha preguntado. -No se le pregunta otra cosa ninguna -respondió Luscinda- sino ofrecelle por esta noche nuestra compañía y parte del lugar donde nos acomodáremos, donde se le hará el regalo que la comodidad ofreciere, con la voluntad que obliga a servir a todos los estranjeros que dello tuvieren necesidad, especialmente siendo mujer a quien se sirve. -Por ella y por mí -respondió el captivo- os beso, señora mía, las manos, y estimo mucho y en lo que es razón la merced ofrecida; que en tal ocasión, y de tales personas como vuestro parecer muestra, bien se echa de ver que ha de ser muy grande. -Decidme, señor -dijo Dorotea-: ¿esta señora es cristiana o mora? Porque el traje y el silencio nos hace pensar que es lo que no querríamos que fuese. -Mora es en el traje y en el cuerpo, pero en el alma es muy grande cristiana, porque tiene grandísimos deseos de serlo. -Luego, ¿no es baptizada? -replicó Luscinda. -No ha habido lugar para ello -respondió el captivo- después que salió de Argel, su patria y tierra, y hasta agora no se ha visto en peligro de muerte tan cercana que obligase a baptizalla sin que supiese primero todas las ceremonias que nuestra Madre la Santa Iglesia manda; pero Dios será servido que presto se bautice con la decencia que la calidad de su persona merece, que es más de lo que muestra su hábito y el mío. Con estas razones puso gana en todos los que escuchándole estaban de saber quién fuese la mora y el captivo, pero nadie se lo quiso preguntar por entonces, por ver que aquella sazón era más para procurarles descanso que para preguntarles sus vidas. Dorotea la tomó por la mano y la llevó a sentar junto a sí, y le rogó que se quitase el embozo. Ella miró al cautivo, como si le preguntara le dijese lo que decían y lo que ella haría. Él, en lengua arábiga, le dijo que le pedían se quitase el embozo, y que lo hiciese; y así, se lo quitó, y descubrió un rostro tan hermoso que Dorotea la tuvo por más hermosa que a Luscinda, y Luscinda por más hermosa que a Dorotea, y todos los circustantes conocieron que si alguno se podría igualar al de las dos, era el de la mora, y aun hubo algunos que le aventajaron en alguna cosa. Y, como la hermosura tenga prerrogativa y gracia de reconciliar los ánimos y atraer las voluntades, luego se rindieron todos al deseo de servir y acariciar a la hermosa mora. Preguntó don Fernando al captivo cómo se llamaba la mora, el cual respondió que lela Zoraida; y, así como esto oyó, ella entendió lo que le habían preguntado al cristiano, y dijo con mucha priesa, llena de congoja y donaire: -¡No, no Zoraida: María, María! -dando a entender que se llamaba María y no Zoraida. Estas palabras, el grande afecto con que la mora las dijo, hicieron derramar más de una lágrima a algunos de los que la escucharon, especialmente a las mujeres, que de su naturaleza son tiernas y compasivas. Abrazóla Luscinda con mucho amor, diciéndole: -Sí, sí: María, María. A lo cual respondió la mora: -¡Sí, sí: María; Zoraida macange! -que quiere decir no. Ya en esto llegaba la noche, y, por orden de los que venían con don Fernando, había el ventero puesto diligencia y cuidado en aderezarles de cenar lo mejor que a él le fue posible. Llegada, pues, la hora, sentáronse todos a una larga mesa, como de tinelo, porque no la había redonda ni cuadrada en la venta, y dieron la cabecera y principal asiento, puesto que él lo rehusaba, a don Quijote, el cual quiso que estuviese a su lado la señora Micomicona, pues él era su aguardador. Luego se sentaron Luscinda y Zoraida, y frontero dellas don Fernando y Cardenio, y luego el cautivo y los demás caballeros, y, al lado de las señoras, el cura y el barbero. Y así, cenaron con mucho contento, y acrecentóseles más viendo que, dejando de comer don Quijote, movido de otro semejante espíritu que el que le movió a hablar tanto como habló cuando cenó con los cabreros, comenzó a decir: -Verdaderamente, si bien se considera, señores míos, grandes e inauditas cosas ven los que profesan la orden de la andante caballería. Si no, ¿cuál de los vivientes habrá en el mundo que ahora por la puerta deste castillo entrara, y de la suerte que estamos nos viere, que juzgue y crea que nosotros somos quien somos? ¿Quién podrá decir que esta señora que está a mi lado es la gran reina que todos sabemos, y que yo soy aquel Caballero de la Triste Figura que anda por ahí en boca de la fama? Ahora no hay que dudar, sino que esta arte y ejercicio excede a todas aquellas y aquellos que los hombres inventaron, y tanto más se ha de tener en estima cuanto a más peligros está sujeto. Quítenseme delante los que dijeren que las letras hacen ventaja a las armas, que les diré, y sean quien se fueren, que no saben lo que dicen. Porque la razón que los tales suelen decir, y a lo que ellos más se atienen, es que los trabajos del espíritu exceden a los del cuerpo, y que las armas sólo con el cuerpo se ejercitan, como si fuese su ejercicio oficio de ganapanes, para el cual no es menester más de buenas fuerzas; o como si en esto que llamamos armas los que las profesamos no se encerrasen los actos de la fortaleza, los cuales piden para ejecutallos mucho entendimiento; o como si no trabajase el ánimo del guerrero que tiene a su cargo un ejército, o la defensa de una ciudad sitiada, así con el espíritu como con el cuerpo. Si no, véase si se alcanza con las fuerzas corporales a saber y conjeturar el intento del enemigo, los disignios, las estratagemas, las dificultades, el prevenir los daños que se temen; que todas estas cosas son acciones del entendimiento, en quien no tiene parte alguna el cuerpo. Siendo pues ansí, que las armas requieren espíritu, como las letras, veamos ahora cuál de los dos espíritus, el del letrado o el del guerrero, trabaja más. Y esto se vendrá a conocer por el fin y paradero a que cada uno se encamina, porque aquella intención se ha de estimar en más que tiene por objeto más noble fin. Es el fin y paradero de las letras..., y no hablo ahora de las divinas, que tienen por blanco llevar y encaminar las almas al cielo, que a un fin tan sin fin como éste ninguno otro se le puede igualar; hablo de las letras humanas, que es su fin poner en su punto la justicia distributiva y dar a cada uno lo que es suyo, entender y hacer que las buenas leyes se guarden. Fin, por cierto, generoso y alto y digno de grande alabanza, pero no de tanta como merece aquel a que las armas atienden, las cuales tienen por objeto y fin la paz, que es el mayor bien que los hombres pueden desear en esta vida. Y así, las primeras buenas nuevas que tuvo el mundo y tuvieron los hombres fueron las que dieron los ángeles la noche que fue nuestro día, cuando cantaron en los aires: ''Gloria sea en las alturas, y paz en la tierra, a los hombres de buena voluntad''; y a la salutación que el mejor maestro de la tierra y del cielo enseñó a sus allegados y favoridos, fue decirles que cuando entrasen en alguna casa, dijesen: ''Paz sea en esta casa''; y otras muchas veces les dijo: ''Mi paz os doy, mi paz os dejo: paz sea con vosotros'', bien como joya y prenda dada y dejada de tal mano; joya que sin ella, en la tierra ni en el cielo puede haber bien alguno. Esta paz es el verdadero fin de la guerra, que lo mesmo es decir armas que guerra. Prosupuesta, pues, esta verdad, que el fin de la guerra es la paz, y que en esto hace ventaja al fin de las letras, vengamos ahora a los trabajos del cuerpo del letrado y a los del profesor de las armas, y véase cuáles son mayores. De tal manera, y por tan buenos términos, iba prosiguiendo en su plática don Quijote que obligó a que, por entonces, ninguno de los que escuchándole estaban le tuviese por loco; antes, como todos los más eran caballeros, a quien son anejas las armas, le escuchaban de muy buena gana; y él prosiguió diciendo: -Digo, pues, que los trabajos del estudiante son éstos: principalmente pobreza (no porque todos sean pobres, sino por poner este caso en todo el estremo que pueda ser); y, en haber dicho que padece pobreza, me parece que no había que decir más de su mala ventura, porque quien es pobre no tiene cosa buena. Esta pobreza la padece por sus partes, ya en hambre, ya en frío, ya en desnudez, ya en todo junto; pero, con todo eso, no es tanta que no coma, aunque sea un poco más tarde de lo que se usa, aunque sea de las sobras de los ricos; que es la mayor miseria del estudiante éste que entre ellos llaman andar a la sopa; y no les falta algún ajeno brasero o chimenea, que, si no callenta, a lo menos entibie su frío, y, en fin, la noche duermen debajo de cubierta. No quiero llegar a otras menudencias, conviene a saber, de la falta de camisas y no sobra de zapatos, la raridad y poco pelo del vestido, ni aquel ahitarse con tanto gusto, cuando la buena suerte les depara algún banquete. Por este camino que he pintado, áspero y dificultoso, tropezando aquí, cayendo allí, levantándose acullá, tornando a caer acá, llegan al grado que desean; el cual alcanzado, a muchos hemos visto que, habiendo pasado por estas Sirtes y por estas Scilas y Caribdis, como llevados en vuelo de la favorable fortuna, digo que los hemos visto mandar y gobernar el mundo desde una silla, trocada su hambre en hartura, su frío en refrigerio, su desnudez en galas, y su dormir en una estera en reposar en holandas y damascos: premio justamente merecido de su virtud. Pero, contrapuestos y comparados sus trabajos con los del mílite guerrero, se quedan muy atrás en todo, como ahora diré. Capítulo XXXVIII. Que trata del curioso discurso que hizo don Quijote de las armas y las letras Prosiguiendo don Quijote, dijo: -Pues comenzamos en el estudiante por la pobreza y sus partes, veamos si es más rico el soldado. Y veremos que no hay ninguno más pobre en la misma pobreza, porque está atenido a la miseria de su paga, que viene o tarde o nunca, o a lo que garbeare por sus manos, con notable peligro de su vida y de su conciencia. Y a veces suele ser su desnudez tanta, que un coleto acuchillado le sirve de gala y de camisa, y en la mitad del invierno se suele reparar de las inclemencias del cielo, estando en la campaña rasa, con sólo el aliento de su boca, que, como sale de lugar vacío, tengo por averiguado que debe de salir frío, contra toda naturaleza. Pues esperad que espere que llegue la noche, para restaurarse de todas estas incomodidades, en la cama que le aguarda, la cual, si no es por su culpa, jamás pecará de estrecha; que bien puede medir en la tierra los pies que quisiere, y revolverse en ella a su sabor, sin temor que se le encojan las sábanas. Lléguese, pues, a todo esto, el día y la hora de recebir el grado de su ejercicio; lléguese un día de batalla, que allí le pondrán la borla en la cabeza, hecha de hilas, para curarle algún balazo, que quizá le habrá pasado las sienes, o le dejará estropeado de brazo o pierna. Y, cuando esto no suceda, sino que el cielo piadoso le guarde y conserve sano y vivo, podrá ser que se quede en la mesma pobreza que antes estaba, y que sea menester que suceda uno y otro rencuentro, una y otra batalla, y que de todas salga vencedor, para medrar en algo; pero estos milagros vense raras veces. Pero, decidme, señores, si habéis mirado en ello: ¿cuán menos son los premiados por la guerra que los que han perecido en ella? Sin duda, habéis de responder que no tienen comparación, ni se pueden reducir a cuenta los muertos, y que se podrán contar los premiados vivos con tres letras de guarismo. Todo esto es al revés en los letrados; porque, de faldas, que no quiero decir de mangas, todos tienen en qué entretenerse. Así que, aunque es mayor el trabajo del soldado, es mucho menor el premio. Pero a esto se puede responder que es más fácil premiar a dos mil letrados que a treinta mil soldados, porque a aquéllos se premian con darles oficios, que por fuerza se han de dar a los de su profesión, y a éstos no se pueden premiar sino con la mesma hacienda del señor a quien sirven; y esta imposibilidad fortifica más la razón que tengo. Pero dejemos esto aparte, que es laberinto de muy dificultosa salida, sino volvamos a la preeminencia de las armas contra las letras, materia que hasta ahora está por averiguar, según son las razones que cada una de su parte alega. Y, entre las que he dicho, dicen las letras que sin ellas no se podrían sustentar las armas, porque la guerra también tiene sus leyes y está sujeta a ellas, y que las leyes caen debajo de lo que son letras y letrados. A esto responden las armas que las leyes no se podrán sustentar sin ellas, porque con las armas se defienden las repúblicas, se conservan los reinos, se guardan las ciudades, se aseguran los caminos, se despejan los mares de cosarios; y, finalmente, si por ellas no fuese, las repúblicas, los reinos, las monarquías, las ciudades, los caminos de mar y tierra estarían sujetos al rigor y a la confusión que trae consigo la guerra el tiempo que dura y tiene licencia de usar de sus previlegios y de sus fuerzas. Y es razón averiguada que aquello que más cuesta se estima y debe de estimar en más. Alcanzar alguno a ser eminente en letras le cuesta tiempo, vigilias, hambre, desnudez, váguidos de cabeza, indigestiones de estómago, y otras cosas a éstas adherentes, que, en parte, ya las tengo referidas; mas llegar uno por sus términos a ser buen soldado le cuesta todo lo que a el estudiante, en tanto mayor grado que no tiene comparación, porque a cada paso está a pique de perder la vida. Y ¿qué temor de necesidad y pobreza puede llegar ni fatigar al estudiante, que llegue al que tiene un soldado, que, hallándose cercado en alguna fuerza, y estando de posta, o guarda, en algún revellín o caballero, siente que los enemigos están minando hacia la parte donde él está, y no puede apartarse de allí por ningún caso, ni huir el peligro que de tan cerca le amenaza? Sólo lo que puede hacer es dar noticia a su capitán de lo que pasa, para que lo remedie con alguna contramina, y él estarse quedo, temiendo y esperando cuándo improvisamente ha de subir a las nubes sin alas y bajar al profundo sin su voluntad. Y si éste parece pequeño peligro, veamos si le iguala o hace ventajas el de embestirse dos galeras por las proas en mitad del mar espacioso, las cuales enclavijadas y trabadas, no le queda al soldado más espacio del que concede dos pies de tabla del espolón; y, con todo esto, viendo que tiene delante de sí tantos ministros de la muerte que le amenazan cuantos cañones de artillería se asestan de la parte contraria, que no distan de su cuerpo una lanza, y viendo que al primer descuido de los pies iría a visitar los profundos senos de Neptuno; y, con todo esto, con intrépido corazón, llevado de la honra que le incita, se pone a ser blanco de tanta arcabucería, y procura pasar por tan estrecho paso al bajel contrario. Y lo que más es de admirar: que apenas uno ha caído donde no se podrá levantar hasta la fin del mundo, cuando otro ocupa su mesmo lugar; y si éste también cae en el mar, que como a enemigo le aguarda, otro y otro le sucede, sin dar tiempo al tiempo de sus muertes: valentía y atrevimiento el mayor que se puede hallar en todos los trances de la guerra. Bien hayan aquellos benditos siglos que carecieron de la espantable furia de aquestos endemoniados instrumentos de la artillería, a cuyo inventor tengo para mí que en el infierno se le está dando el premio de su diabólica invención, con la cual dio causa que un infame y cobarde brazo quite la vida a un valeroso caballero, y que, sin saber cómo o por dónde, en la mitad del coraje y brío que enciende y anima a los valientes pechos, llega una desmandada bala, disparada de quien quizá huyó y se espantó del resplandor que hizo el fuego al disparar de la maldita máquina, y corta y acaba en un instante los pensamientos y vida de quien la merecía gozar luengos siglos. Y así, considerando esto, estoy por decir que en el alma me pesa de haber tomado este ejercicio de caballero andante en edad tan detestable como es esta en que ahora vivimos; porque, aunque a mí ningún peligro me pone miedo, todavía me pone recelo pensar si la pólvora y el estaño me han de quitar la ocasión de hacerme famoso y conocido por el valor de mi brazo y filos de mi espada, por todo lo descubierto de la tierra. Pero haga el cielo lo que fuere servido, que tanto seré más estimado, si salgo con lo que pretendo, cuanto a mayores peligros me he puesto que se pusieron los caballeros andantes de los pasados siglos. Todo este largo preámbulo dijo don Quijote, en tanto que los demás cenaban, olvidándose de llevar bocado a la boca, puesto que algunas veces le había dicho Sancho Panza que cenase, que después habría lugar para decir todo lo que quisiese. En los que escuchado le habían sobrevino nueva lástima de ver que hombre que, al parecer, tenía buen entendimiento y buen discurso en todas las cosas que trataba, le hubiese perdido tan rematadamente, en tratándole de su negra y pizmienta caballería. El cura le dijo que tenía mucha razón en todo cuanto había dicho en favor de las armas, y que él, aunque letrado y graduado, estaba de su mesmo parecer. Acabaron de cenar, levantaron los manteles, y, en tanto que la ventera, su hija y Maritornes aderezaban el camaranchón de don Quijote de la Mancha, donde habían determinado que aquella noche las mujeres solas en él se recogiesen, don Fernando rogó al cautivo les contase el discurso de su vida, porque no podría ser sino que fuese peregrino y gustoso, según las muestras que había comenzado a dar, viniendo en compañía de Zoraida. A lo cual respondió el cautivo que de muy buena gana haría lo que se le mandaba, y que sólo temía que el cuento no había de ser tal, que les diese el gusto que él deseaba; pero que, con todo eso, por no faltar en obedecelle, le contaría. El cura y todos los demás se lo agradecieron, y de nuevo se lo rogaron; y él, viéndose rogar de tantos, dijo que no eran menester ruegos adonde el mandar tenía tanta fuerza. -Y así, estén vuestras mercedes atentos, y oirán un discurso verdadero, a quien podría ser que no llegasen los mentirosos que con curioso y pensado artificio suelen componerse. Con esto que dijo, hizo que todos se acomodasen y le prestasen un grande silencio; y él, viendo que ya callaban y esperaban lo que decir quisiese, con voz agradable y reposada, comenzó a decir desta manera: Capítulo XXXIX. Donde el cautivo cuenta su vida y sucesos -«En un lugar de las Montañas de León tuvo principio mi linaje, con quien fue más agradecida y liberal la naturaleza que la fortuna, aunque, en la estrecheza de aquellos pueblos, todavía alcanzaba mi padre fama de rico, y verdaderamente lo fuera si así se diera maña a conservar su hacienda como se la daba en gastalla. Y la condición que tenía de ser liberal y gastador le procedió de haber sido soldado los años de su joventud, que es escuela la soldadesca donde el mezquino se hace franco, y el franco, pródigo; y si algunos soldados se hallan miserables, son como monstruos, que se ven raras veces. Pasaba mi padre los términos de la liberalidad, y rayaba en los de ser pródigo: cosa que no le es de ningún provecho al hombre casado, y que tiene hijos que le han de suceder en el nombre y en el ser. Los que mi padre tenía eran tres, todos varones y todos de edad de poder elegir estado. Viendo, pues, mi padre que, según él decía, no podía irse a la mano contra su condición, quiso privarse del instrumento y causa que le hacía gastador y dadivoso, que fue privarse de la hacienda, sin la cual el mismo Alejandro pareciera estrecho. »Y así, llamándonos un día a todos tres a solas en un aposento, nos dijo unas razones semejantes a las que ahora diré: ''Hijos, para deciros que os quiero bien, basta saber y decir que sois mis hijos; y, para entender que os quiero mal, basta saber que no me voy a la mano en lo que toca a conservar vuestra hacienda. Pues, para que entendáis desde aquí adelante que os quiero como padre, y que no os quiero destruir como padrastro, quiero hacer una cosa con vosotros que ha muchos días que la tengo pensada y con madura consideración dispuesta. Vosotros estáis ya en edad de tomar estado, o, a lo menos, de elegir ejercicio, tal que, cuando mayores, os honre y aproveche. Y lo que he pensado es hacer de mi hacienda cuatro partes: las tres os daré a vosotros, a cada uno lo que le tocare, sin exceder en cosa alguna, y con la otra me quedaré yo para vivir y sustentarme los días que el cielo fuere servido de darme de vida. Pero querría que, después que cada uno tuviese en su poder la parte que le toca de su hacienda, siguiese uno de los caminos que le diré. Hay un refrán en nuestra España, a mi parecer muy verdadero, como todos lo son, por ser sentencias breves sacadas de la luenga y discreta experiencia; y el que yo digo dice: "Iglesia, o mar, o casa real", como si más claramente dijera: "Quien quisiere valer y ser rico, siga o la Iglesia, o navegue, ejercitando el arte de la mercancía, o entre a servir a los reyes en sus casas"; porque dicen: "Más vale migaja de rey que merced de señor". Digo esto porque querría, y es mi voluntad, que uno de vosotros siguiese las letras, el otro la mercancía, y el otro sirviese al rey en la guerra, pues es dificultoso entrar a servirle en su casa; que, ya que la guerra no dé muchas riquezas, suele dar mucho valor y mucha fama. Dentro de ocho días, os daré toda vuestra parte en dineros, sin defraudaros en un ardite, como lo veréis por la obra. Decidme ahora si queréis seguir mi parecer y consejo en lo que os he propuesto''. Y, mandándome a mí, por ser el mayor, que respondiese, después de haberle dicho que no se deshiciese de la hacienda, sino que gastase todo lo que fuese su voluntad, que nosotros éramos mozos para saber ganarla, vine a concluir en que cumpliría su gusto, y que el mío era seguir el ejercicio de las armas, sirviendo en él a Dios y a mi rey. El segundo hermano hizo los mesmos ofrecimientos, y escogió el irse a las Indias, llevando empleada la hacienda que le cupiese. El menor, y, a lo que yo creo, el más discreto, dijo que quería seguir la Iglesia, o irse a acabar sus comenzados estudios a Salamanca. Así como acabamos de concordarnos y escoger nuestros ejercicios, mi padre nos abrazó a todos, y, con la brevedad que dijo, puso por obra cuanto nos había prometido; y, dando a cada uno su parte, que, a lo que se me acuerda, fueron cada tres mil ducados, en dineros (porque un nuestro tío compró toda la hacienda y la pagó de contado, porque no saliese del tronco de la casa), en un mesmo día nos despedimos todos tres de nuestro buen padre; y, en aquel mesmo, pareciéndome a mí ser inhumanidad que mi padre quedase viejo y con tan poca hacienda, hice con él que de mis tres mil tomase los dos mil ducados, porque a mí me bastaba el resto para acomodarme de lo que había menester un soldado. Mis dos hermanos, movidos de mi ejemplo, cada uno le dio mil ducados: de modo que a mi padre le quedaron cuatro mil en dineros, y más tres mil, que, a lo que parece, valía la hacienda que le cupo, que no quiso vender, sino quedarse con ella en raíces. Digo, en fin, que nos despedimos dél y de aquel nuestro tío que he dicho, no sin mucho sentimiento y lágrimas de todos, encargándonos que les hiciésemos saber, todas las veces que hubiese comodidad para ello, de nuestros sucesos, prósperos o adversos. Prometímosselo, y, abrazándonos y echándonos su bendición, el uno tomó el viaje de Salamanca, el otro de Sevilla y yo el de Alicante, adonde tuve nuevas que había una nave ginovesa que cargaba allí lana para Génova. ȃste hará veinte y dos años que salí de casa de mi padre, y en todos ellos, puesto que he escrito algunas cartas, no he sabido dél ni de mis hermanos nueva alguna. Y lo que en este discurso de tiempo he pasado lo diré brevemente. Embarquéme en Alicante, llegué con próspero viaje a Génova, fui desde allí a Milán, donde me acomodé de armas y de algunas galas de soldado, de donde quise ir a asentar mi plaza al Piamonte; y, estando ya de camino para Alejandría de la Palla, tuve nuevas que el gran duque de Alba pasaba a Flandes. Mudé propósito, fuime con él, servíle en las jornadas que hizo, halléme en la muerte de los condes de Eguemón y de Hornos, alcancé a ser alférez de un famoso capitán de Guadalajara, llamado Diego de Urbina; y, a cabo de algún tiempo que llegué a Flandes, se tuvo nuevas de la liga que la Santidad del Papa Pío Quinto, de felice recordación, había hecho con Venecia y con España, contra el enemigo común, que es el Turco; el cual, en aquel mesmo tiempo, había ganado con su armada la famosa isla de Chipre, que estaba debajo del dominio del veneciano: y pérdida lamentable y desdichada. Súpose cierto que venía por general desta liga el serenísimo don Juan de Austria, hermano natural de nuestro buen rey don Felipe. Divulgóse el grandísimo aparato de guerra que se hacía. Todo lo cual me incitó y conmovió el ánimo y el deseo de verme en la jornada que se esperaba; y, aunque tenía barruntos, y casi promesas ciertas, de que en la primera ocasión que se ofreciese sería promovido a capitán, lo quise dejar todo y venirme, como me vine, a Italia. Y quiso mi buena suerte que el señor don Juan de Austria acababa de llegar a Génova, que pasaba a Nápoles a juntarse con la armada de Venecia, como después lo hizo en Mecina. »Digo, en fin, que yo me hallé en aquella felicísima jornada, ya hecho capitán de infantería, a cuyo honroso cargo me subió mi buena suerte, más que mis merecimientos. Y aquel día, que fue para la cristiandad tan dichoso, porque en él se desengañó el mundo y todas las naciones del error en que estaban, creyendo que los turcos eran invencibles por la mar: en aquel día, digo, donde quedó el orgullo y soberbia otomana quebrantada, entre tantos venturosos como allí hubo (porque más ventura tuvieron los cristianos que allí murieron que los que vivos y vencedores quedaron), yo solo fui el desdichado, pues, en cambio de que pudiera esperar, si fuera en los romanos siglos, alguna naval corona, me vi aquella noche que siguió a tan famoso día con cadenas a los pies y esposas a las manos. »Y fue desta suerte: que, habiendo el Uchalí, rey de Argel, atrevido y venturoso cosario, embestido y rendido la capitana de Malta, que solos tres caballeros quedaron vivos en ella, y éstos malheridos, acudió la capitana de Juan Andrea a socorrella, en la cual yo iba con mi compañía; y, haciendo lo que debía en ocasión semejante, salté en la galera contraria, la cual, desviándose de la que la había embestido, estorbó que mis soldados me siguiesen, y así, me hallé solo entre mis enemigos, a quien no pude resistir, por ser tantos; en fin, me rindieron lleno de heridas. Y, como ya habréis, señores, oído decir que el Uchalí se salvó con toda su escuadra, vine yo a quedar cautivo en su poder, y solo fui el triste entre tantos alegres y el cautivo entre tantos libres; porque fueron quince mil cristianos los que aquel día alcanzaron la deseada libertad, que todos venían al remo en la turquesca armada. »Lleváronme a Costantinopla, donde el Gran Turco Selim hizo general de la mar a mi amo, porque había hecho su deber en la batalla, habiendo llevado por muestra de su valor el estandarte de la religión de Malta. Halléme el segundo año, que fue el de setenta y dos, en Navarino, bogando en la capitana de los tres fanales. Vi y noté la ocasión que allí se perdió de no coger en el puerto toda el armada turquesca, porque todos los leventes y jenízaros que en ella venían tuvieron por cierto que les habían de embestir dentro del mesmo puerto, y tenían a punto su ropa y pasamaques, que son sus zapatos, para huirse luego por tierra, sin esperar ser combatidos: tanto era el miedo que habían cobrado a nuestra armada. Pero el cielo lo ordenó de otra manera, no por culpa ni descuido del general que a los nuestros regía, sino por los pecados de la cristiandad, y porque quiere y permite Dios que tengamos siempre verdugos que nos castiguen. »En efeto, el Uchalí se recogió a Modón, que es una isla que está junto a Navarino, y, echando la gente en tierra, fortificó la boca del puerto, y estúvose quedo hasta que el señor don Juan se volvió. En este viaje se tomó la galera que se llamaba La Presa, de quien era capitán un hijo de aquel famoso cosario Barbarroja. Tomóla la capitana de Nápoles, llamada La Loba, regida por aquel rayo de la guerra, por el padre de los soldados, por aquel venturoso y jamás vencido capitán don Ãlvaro de Bazán, marqués de Santa Cruz. Y no quiero dejar de decir lo que sucedió en la presa de La Presa. Era tan cruel el hijo de Barbarroja, y trataba tan mal a sus cautivos, que, así como los que venían al remo vieron que la galera Loba les iba entrando y que los alcanzaba, soltaron todos a un tiempo los remos, y asieron de su capitán, que estaba sobre el estanterol gritando que bogasen apriesa, y pasándole de banco en banco, de popa a proa, le dieron bocados, que a poco más que pasó del árbol ya había pasado su ánima al infierno: tal era, como he dicho, la crueldad con que los trataba y el odio que ellos le tenían. »Volvimos a Constantinopla, y el año siguiente, que fue el de setenta y tres, se supo en ella cómo el señor don Juan había ganado a Túnez, y quitado aquel reino a los turcos y puesto en posesión dél a Muley Hamet, cortando las esperanzas que de volver a reinar en él tenía Muley Hamida, el moro más cruel y más valiente que tuvo el mundo. Sintió mucho esta pérdida el Gran Turco, y, usando de la sagacidad que todos los de su casa tienen, hizo paz con venecianos, que mucho más que él la deseaban; y el año siguiente de setenta y cuatro acometió a la Goleta y al fuerte que junto a Túnez había dejado medio levantado el señor don Juan. En todos estos trances andaba yo al remo, sin esperanza de libertad alguna; a lo menos, no esperaba tenerla por rescate, porque tenía determinado de no escribir las nuevas de mi desgracia a mi padre. »Perdióse, en fin, la Goleta; perdióse el fuerte, sobre las cuales plazas hubo de soldados turcos, pagados, setenta y cinco mil, y de moros, y alárabes de toda la Africa, más de cuatrocientos mil, acompañado este tan gran número de gente con tantas municiones y pertrechos de guerra, y con tantos gastadores, que con las manos y a puñados de tierra pudieran cubrir la Goleta y el fuerte. Perdióse primero la Goleta, tenida hasta entonces por inexpugnable; y no se perdió por culpa de sus defensores, los cuales hicieron en su defensa todo aquello que debían y podían, sino porque la experiencia mostró la facilidad con que se podían levantar trincheas en aquella desierta arena, porque a dos palmos se hallaba agua, y los turcos no la hallaron a dos varas; y así, con muchos sacos de arena levantaron las trincheas tan altas que sobrepujaban las murallas de la fuerza; y, tirándoles a caballero, ninguno podía parar, ni asistir a la defensa. Fue común opinión que no se habían de encerrar los nuestros en la Goleta, sino esperar en campaña al desembarcadero; y los que esto dicen hablan de lejos y con poca experiencia de casos semejantes, porque si en la Goleta y en el fuerte apenas había siete mil soldados, ¿cómo podía tan poco número, aunque más esforzados fuesen, salir a la campaña y quedar en las fuerzas, contra tanto como era el de los enemigos?; y ¿cómo es posible dejar de perderse fuerza que no es socorrida, y más cuando la cercan enemigos muchos y porfiados, y en su mesma tierra? Pero a muchos les pareció, y así me pareció a mí, que fue particular gracia y merced que el cielo hizo a España en permitir que se asolase aquella oficina y capa de maldades, y aquella gomia o esponja y polilla de la infinidad de dineros que allí sin provecho se gastaban, sin servir de otra cosa que de conservar la memoria de haberla ganado la felicísima del invictísimo Carlos Quinto; como si fuera menester para hacerla eterna, como lo es y será, que aquellas piedras la sustentaran. »Perdióse también el fuerte; pero fuéronle ganando los turcos palmo a palmo, porque los soldados que lo defendían pelearon tan valerosa y fuertemente, que pasaron de veinte y cinco mil enemigos los que mataron en veinte y dos asaltos generales que les dieron. Ninguno cautivaron sano de trecientos que quedaron vivos, señal cierta y clara de su esfuerzo y valor, y de lo bien que se habían defendido y guardado sus plazas. Rindióse a partido un pequeño fuerte o torre que estaba en mitad del estaño, a cargo de don Juan Zanoguera, caballero valenciano y famoso soldado. Cautivaron a don Pedro Puertocarrero, general de la Goleta, el cual hizo cuanto fue posible por defender su fuerza; y sintió tanto el haberla perdido que de pesar murió en el camino de Constantinopla, donde le llevaban cautivo. Cautivaron ansimesmo al general del fuerte, que se llamaba Gabrio Cervellón, caballero milanés, grande ingeniero y valentísimo soldado. Murieron en estas dos fuerzas muchas personas de cuenta, de las cuales fue una Pagán de Oria, caballero del hábito de San Juan, de condición generoso, como lo mostró la summa liberalidad que usó con su hermano, el famoso Juan de Andrea de Oria; y lo que más hizo lastimosa su muerte fue haber muerto a manos de unos alárabes de quien se fió, viendo ya perdido el fuerte, que se ofrecieron de llevarle en hábito de moro a Tabarca, que es un portezuelo o casa que en aquellas riberas tienen los ginoveses que se ejercitan en la pesquería del coral; los cuales alárabes le cortaron la cabeza y se la trujeron al general de la armada turquesca, el cual cumplió con ellos nuestro refrán castellano: "Que aunque la traición aplace, el traidor se aborrece"; y así, se dice que mandó el general ahorcar a los que le trujeron el presente, porque no se le habían traído vivo. »Entre los cristianos que en el fuerte se perdieron, fue uno llamado don Pedro de Aguilar, natural no sé de qué lugar del Andalucía, el cual había sido alférez en el fuerte, soldado de mucha cuenta y de raro entendimiento: especialmente tenía particular gracia en lo que llaman poesía. Dígolo porque su suerte le trujo a mi galera y a mi banco, y a ser esclavo de mi mesmo patrón; y, antes que nos partiésemos de aquel puerto, hizo este caballero dos sonetos, a manera de epitafios, el uno a la Goleta y el otro al fuerte. Y en verdad que los tengo de decir, porque los sé de memoria y creo que antes causarán gusto que pesadumbre.» En el punto que el cautivo nombró a don Pedro de Aguilar, don Fernando miró a sus camaradas, y todos tres se sonrieron; y, cuando llegó a decir de los sonetos, dijo el uno: -Antes que vuestra merced pase adelante, le suplico me diga qué se hizo ese don Pedro de Aguilar que ha dicho. -Lo que sé es -respondió el cautivo- que, al cabo de dos años que estuvo en Constantinopla, se huyó en traje de arnaúte con un griego espía, y no sé si vino en libertad, puesto que creo que sí, porque de allí a un año vi yo al griego en Constantinopla, y no le pude preguntar el suceso de aquel viaje. -Pues lo fue -respondió el caballero-, porque ese don Pedro es mi hermano, y está ahora en nuestro lugar, bueno y rico, casado y con tres hijos. -Gracias sean dadas a Dios -dijo el cautivo- por tantas mercedes como le hizo; porque no hay en la tierra, conforme mi parecer, contento que se iguale a alcanzar la libertad perdida. -Y más -replicó el caballero-, que yo sé los sonetos que mi hermano hizo. -Dígalos, pues, vuestra merced -dijo el cautivo-, que los sabrá decir mejor que yo. -Que me place -respondió el caballero-; y el de la Goleta decía así: Capítulo XL. Donde se prosigue la historia del cautivo Soneto Almas dichosas que del mortal velo libres y esentas, por el bien que obrastes, desde la baja tierra os levantastes a lo más alto y lo mejor del cielo, y, ardiendo en ira y en honroso celo, de los cuerpos la fuerza ejercitastes, que en propia y sangre ajena colorastes el mar vecino y arenoso suelo; primero que el valor faltó la vida en los cansados brazos, que, muriendo, con ser vencidos, llevan la vitoria. Y esta vuestra mortal, triste caída entre el muro y el hierro, os va adquiriendo fama que el mundo os da, y el cielo gloria. -Desa mesma manera le sé yo -dijo el cautivo. -Pues el del fuerte, si mal no me acuerdo -dijo el caballero-, dice así: Soneto De entre esta tierra estéril, derribada, destos terrones por el suelo echados, las almas santas de tres mil soldados subieron vivas a mejor morada, siendo primero, en vano, ejercitada la fuerza de sus brazos esforzados, hasta que, al fin, de pocos y cansados, dieron la vida al filo de la espada. Y éste es el suelo que continuo ha sido de mil memorias lamentables lleno en los pasados siglos y presentes. Mas no más justas de su duro seno habrán al claro cielo almas subido, ni aun él sostuvo cuerpos tan valientes. No parecieron mal los sonetos, y el cautivo se alegró con las nuevas que de su camarada le dieron; y, prosiguiendo su cuento, dijo: -«Rendidos, pues, la Goleta y el fuerte, los turcos dieron orden en desmantelar la Goleta, porque el fuerte quedó tal, que no hubo qué poner por tierra, y para hacerlo con más brevedad y menos trabajo, la minaron por tres partes; pero con ninguna se pudo volar lo que parecía menos fuerte, que eran las murallas viejas; y todo aquello que había quedado en pie de la fortificación nueva que había hecho el Fratín, con mucha facilidad vino a tierra. En resolución, la armada volvió a Constantinopla, triunfante y vencedora: y de allí a pocos meses murió mi amo el Uchalí, al cual llamaban Uchalí Fartax, que quiere decir, en lengua turquesca, el renegado tiñoso, porque lo era; y es costumbre entre los turcos ponerse nombres de alguna falta que tengan, o de alguna virtud que en ellos haya. Y esto es porque no hay entre ellos sino cuatro apellidos de linajes, que decienden de la casa Otomana, y los demás, como tengo dicho, toman nombre y apellido ya de las tachas del cuerpo y ya de las virtudes del ánimo. Y este Tiñoso bogó el remo, siendo esclavo del Gran Señor, catorce años, y a más de los treinta y cuatro de sus edad renegó, de despecho de que un turco, estando al remo, le dio un bofetón, y por poderse vengar dejó su fe; y fue tanto su valor que, sin subir por los torpes medios y caminos que los más privados del Gran Turco suben, vino a ser rey de Argel, y después, a ser general de la mar, que es el tercero cargo que hay en aquel señorío. Era calabrés de nación, y moralmente fue un hombre de bien, y trataba con mucha humanidad a sus cautivos, que llegó a tener tres mil, los cuales, después de su muerte, se repartieron, como él lo dejó en su testamento, entre el Gran Señor (que también es hijo heredero de cuantos mueren, y entra a la parte con los más hijos que deja el difunto) y entre sus renegados; y yo cupe a un renegado veneciano que, siendo grumete de una nave, le cautivó el Uchalí, y le quiso tanto, que fue uno de los más regalados garzones suyos, y él vino a ser el más cruel renegado que jamás se ha visto. Llamábase Azán Agá, y llegó a ser muy rico, y a ser rey de Argel; con el cual yo vine de Constantinopla, algo contento, por estar tan cerca de España, no porque pensase escribir a nadie el desdichado suceso mío, sino por ver si me era más favorable la suerte en Argel que en Constantinopla, donde ya había probado mil maneras de huirme, y ninguna tuvo sazón ni ventura; y pensaba en Argel buscar otros medios de alcanzar lo que tanto deseaba, porque jamás me desamparó la esperanza de tener libertad; y cuando en lo que fabricaba, pensaba y ponía por obra no correspondía el suceso a la intención, luego, sin abandonarme, fingía y buscaba otra esperanza que me sustentase, aunque fuese débil y flaca. »Con esto entretenía la vida, encerrado en una prisión o casa que los turcos llaman baño, donde encierran los cautivos cristianos, así los que son del rey como de algunos particulares; y los que llaman del almacén, que es como decir cautivos del concejo, que sirven a la ciudad en las obras públicas que hace y en otros oficios, y estos tales cautivos tienen muy dificultosa su libertad, que, como son del común y no tienen amo particular, no hay con quien tratar su rescate, aunque le tengan. En estos baños, como tengo dicho, suelen llevar a sus cautivos algunos particulares del pueblo, principalmente cuando son de rescate, porque allí los tienen holgados y seguros hasta que venga su rescate. También los cautivos del rey que son de rescate no salen al trabajo con la demás chusma, si no es cuando se tarda su rescate; que entonces, por hacerles que escriban por él con más ahínco, les hacen trabajar y ir por leña con los demás, que es un no pequeño trabajo. »Yo, pues, era uno de los de rescate; que, como se supo que era capitán, puesto que dije mi poca posibilidad y falta de hacienda, no aprovechó nada para que no me pusiesen en el número de los caballeros y gente de rescate. Pusiéronme una cadena, más por señal de rescate que por guardarme con ella; y así, pasaba la vida en aquel baño, con otros muchos caballeros y gente principal, señalados y tenidos por de rescate. Y, aunque la hambre y desnudez pudiera fatigarnos a veces, y aun casi siempre, ninguna cosa nos fatigaba tanto como oír y ver, a cada paso, las jamás vistas ni oídas crueldades que mi amo usaba con los cristianos. Cada día ahorcaba el suyo, empalaba a éste, desorejaba aquél; y esto, por tan poca ocasión, y tan sin ella, que los turcos conocían que lo hacía no más de por hacerlo, y por ser natural condición suya ser homicida de todo el género humano. Sólo libró bien con él un soldado español, llamado tal de Saavedra, el cual, con haber hecho cosas que quedarán en la memoria de aquellas gentes por muchos años, y todas por alcanzar libertad, jamás le dio palo, ni se lo mandó dar, ni le dijo mala palabra; y, por la menor cosa de muchas que hizo, temíamos todos que había de ser empalado, y así lo temió él más de una vez; y si no fuera porque el tiempo no da lugar, yo dijera ahora algo de lo que este soldado hizo, que fuera parte para entreteneros y admiraros harto mejor que con el cuento de mi historia. »Digo, pues, que encima del patio de nuestra prisión caían las ventanas de la casa de un moro rico y principal, las cuales, como de ordinario son las de los moros, más eran agujeros que ventanas, y aun éstas se cubrían con celosías muy espesas y apretadas. Acaeció, pues, que un día, estando en un terrado de nuestra prisión con otros tres compañeros, haciendo pruebas de saltar con las cadenas, por entretener el tiempo, estando solos, porque todos los demás cristianos habían salido a trabajar, alcé acaso los ojos y vi que por aquellas cerradas ventanillas que he dicho parecía una caña, y al remate della puesto un lienzo atado, y la caña se estaba blandeando y moviéndose, casi como si hiciera señas que llegásemos a tomarla. Miramos en ello, y uno de los que conmigo estaban fue a ponerse debajo de la caña, por ver si la soltaban, o lo que hacían; pero, así como llegó, alzaron la caña y la movieron a los dos lados, como si dijeran no con la cabeza. Volvióse el cristiano, y tornáronla a bajar y hacer los mesmos movimientos que primero. Fue otro de mis compañeros, y sucedióle lo mesmo que al primero. Finalmente, fue el tercero y avínole lo que al primero y al segundo. Viendo yo esto, no quise dejar de probar la suerte, y, así como llegué a ponerme debajo de la caña, la dejaron caer, y dio a mis pies dentro del baño. Acudí luego a desatar el lienzo, en el cual vi un nudo, y dentro dél venían diez cianíis, que son unas monedas de oro bajo que usan los moros, que cada una vale diez reales de los nuestros. Si me holgué con el hallazgo, no hay para qué decirlo, pues fue tanto el contento como la admiración de pensar de donde podía venirnos aquel bien, especialmente a mí, pues las muestras de no haber querido soltar la caña sino a mí claro decían que a mí se hacía la merced. Tomé mi buen dinero, quebré la caña, volvíme al terradillo, miré la ventana, y vi que por ella salía una muy blanca mano, que la abrían y cerraban muy apriesa. Con esto entendimos, o imaginamos, que alguna mujer que en aquella casa vivía nos debía de haber hecho aquel beneficio; y, en señal de que lo agradecíamos, hecimos zalemas a uso de moros, inclinando la cabeza, doblando el cuerpo y poniendo los brazos sobre el pecho. De allí a poco sacaron por la mesma ventana una pequeña cruz hecha de cañas, y luego la volvieron a entrar. Esta señal nos confirmó en que alguna cristiana debía de estar cautiva en aquella casa, y era la que el bien nos hacía; pero la blancura de la mano, y las ajorcas que en ella vimos, nos deshizo este pensamiento, puesto que imaginamos que debía de ser cristiana renegada, a quien de ordinario suelen tomar por legítimas mujeres sus mesmos amos, y aun lo tienen a ventura, porque las estiman en más que las de su nación. »En todos nuestros discursos dimos muy lejos de la verdad del caso; y así, todo nuestro entretenimiento desde allí adelante era mirar y tener por norte a la ventana donde nos había aparecido la estrella de la caña; pero bien se pasaron quince días en que no la vimos, ni la mano tampoco, ni otra señal alguna. Y, aunque en este tiempo procuramos con toda solicitud saber quién en aquella casa vivía, y si había en ella alguna cristiana renegada, jamás hubo quien nos dijese otra cosa, sino que allí vivía un moro principal y rico, llamado Agi Morato, alcaide que había sido de La Pata, que es oficio entre ellos de mucha calidad. Mas, cuando más descuidados estábamos de que por allí habían de llover más cianíis, vimos a deshora parecer la caña, y otro lienzo en ella, con otro nudo más crecido; y esto fue a tiempo que estaba el baño, como la vez pasada, solo y sin gente. Hecimos la acostumbrada prueba, yendo cada uno primero que yo, de los mismos tres que estábamos, pero a ninguno se rindió la caña sino a mí, porque, en llegando yo, la dejaron caer. Desaté el nudo, y hallé cuarenta escudos de oro españoles y un papel escrito en arábigo, y al cabo de lo escrito hecha una grande cruz. Besé la cruz, tomé los escudos, volvíme al terrado, hecimos todos nuestras zalemas, tornó a parecer la mano, hice señas que leería el papel, cerraron la ventana. Quedamos todos confusos y alegres con lo sucedido; y, como ninguno de nosotros no entendía el arábigo, era grande el deseo que teníamos de entender lo que el papel contenía, y mayor la dificultad de buscar quien lo leyese. »En fin, yo me determiné de fiarme de un renegado, natural de Murcia, que se había dado por grande amigo mío, y puesto prendas entre los dos, que le obligaban a guardar el secreto que le encargase; porque suelen algunos renegados, cuando tienen intención de volverse a tierra de cristianos, traer consigo algunas firmas de cautivos principales, en que dan fe, en la forma que pueden, como el tal renegado es hombre de bien, y que siempre ha hecho bien a cristianos, y que lleva deseo de huirse en la primera ocasión que se le ofrezca. Algunos hay que procuran estas fees con buena intención, otros se sirven dellas acaso y de industria: que, viniendo a robar a tierra de cristianos, si a dicha se pierden o los cautivan, sacan sus firmas y dicen que por aquellos papeles se verá el propósito con que venían, el cual era de quedarse en tierra de cristianos, y que por eso venían en corso con los demás turcos. Con esto se escapan de aquel primer ímpetu, y se reconcilian con la Iglesia, sin que se les haga daño; y, cuando veen la suya, se vuelven a Berbería a ser lo que antes eran. Otros hay que usan destos papeles, y los procuran, con buen intento, y se quedan en tierra de cristianos. »Pues uno de los renegados que he dicho era este mi amigo, el cual tenía firmas de todas nuestras camaradas, donde le acreditábamos cuanto era posible; y si los moros le hallaran estos papeles, le quemaran vivo. Supe que sabía muy bien arábigo, y no solamente hablarlo, sino escribirlo; pero, antes que del todo me declarase con él, le dije que me leyese aquel papel, que acaso me había hallado en un agujero de mi rancho. Abrióle, y estuvo un buen espacio mirándole y construyéndole, murmurando entre los dientes. Preguntéle si lo entendía; díjome que muy bien, y, que si quería que me lo declarase palabra por palabra, que le diese tinta y pluma, porque mejor lo hiciese. Dímosle luego lo que pedía, y él poco a poco lo fue traduciendo; y, en acabando, dijo: ''Todo lo que va aquí en romance, sin faltar letra, es lo que contiene este papel morisco; y hase de advertir que adonde dice Lela Marién quiere decir Nuestra Señora la Virgen María''. »Leímos el papel, y decía así: Cuando yo era niña, tenía mi padre una esclava, la cual en mi lengua me mostró la zalá cristianesca, y me dijo muchas cosas de Lela Marién. La cristiana murió, y yo sé que no fue al fuego, sino con Alá, porque después la vi dos veces, y me dijo que me fuese a tierra de cristianos a ver a Lela Marién, que me quería mucho. No sé yo cómo vaya: muchos cristianos he visto por esta ventana, y ninguno me ha parecido caballero sino tú. Yo soy muy hermosa y muchacha, y tengo muchos dineros que llevar conmigo: mira tú si puedes hacer cómo nos vamos, y serás allá mi marido, si quisieres, y si no quisieres, no se me dará nada, que Lela Marién me dará con quien me case. Yo escribí esto; mira a quién lo das a leer: no te fíes de ningún moro, porque son todos marfuces. Desto tengo mucha pena: que quisiera que no te descubrieras a nadie, porque si mi padre lo sabe, me echará luego en un pozo, y me cubrirá de piedras. En la caña pondré un hilo: ata allí la respuesta; y si no tienes quien te escriba arábigo, dímelo por señas, que Lela Marién hará que te entienda. Ella y Alá te guarden, y esa cruz que yo beso muchas veces; que así me lo mandó la cautiva. »Mirad, señores, si era razón que las razones deste papel nos admirasen y alegrasen. Y así, lo uno y lo otro fue de manera que el renegado entendió que no acaso se había hallado aquel papel, sino que realmente a alguno de nosotros se había escrito; y así, nos rogó que si era verdad lo que sospechaba, que nos fiásemos dél y se lo dijésemos, que él aventuraría su vida por nuestra libertad. Y, diciendo esto, sacó del pecho un crucifijo de metal, y con muchas lágrimas juró por el Dios que aquella imagen representaba, en quien él, aunque pecador y malo, bien y fielmente creía, de guardarnos lealtad y secreto en todo cuanto quisiésemos descubrirle, porque le parecía, y casi adevinaba que, por medio de aquella que aquel papel había escrito, había él y todos nosotros de tener libertad, y verse él en lo que tanto deseaba, que era reducirse al gremio de la Santa Iglesia, su madre, de quien como miembro podrido estaba dividido y apartado por su ignorancia y pecado. »Con tantas lágrimas y con muestras de tanto arrepentimiento dijo esto el renegado, que todos de un mesmo parecer consentimos, y venimos en declararle la verdad del caso; y así, le dimos cuenta de todo, sin encubrirle nada. Mostrámosle la ventanilla por donde parecía la caña, y él marcó desde allí la casa, y quedó de tener especial y gran cuidado de informarse quién en ella vivía. Acordamos, ansimesmo, que sería bien responder al billete de la mora; y, como teníamos quien lo supiese hacer, luego al momento el renegado escribió las razones que yo le fui notando, que puntualmente fueron las que diré, porque de todos los puntos sustanciales que en este suceso me acontecieron, ninguno se me ha ido de la memoria, ni aun se me irá en tanto que tuviere vida. »En efeto, lo que a la mora se le respondió fue esto: El verdadero Alá te guarde, señora mía, y aquella bendita Marién, que es la verdadera madre de Dios y es la que te ha puesto en corazón que te vayas a tierra de cristianos, porque te quiere bien. Ruégale tú que se sirva de darte a entender cómo podrás poner por obra lo que te manda, que ella es tan buena que sí hará. De mi parte y de la de todos estos cristianos que están conmigo, te ofrezco de hacer por ti todo lo que pudiéremos, hasta morir. No dejes de escribirme y avisarme lo que pensares hacer, que yo te responderé siempre; que el grande Alá nos ha dado un cristiano cautivo que sabe hablar y escribir tu lengua tan bien como lo verás por este papel. Así que, sin tener miedo, nos puedes avisar de todo lo que quisieres. A lo que dices que si fueres a tierra de cristianos, que has de ser mi mujer, yo te lo prometo como buen cristiano; y sabe que los cristianos cumplen lo que prometen mejor que los moros. Alá y Marién, su madre, sean en tu guarda, señora mía. »Escrito y cerrado este papel, aguardé dos días a que estuviese el baño solo, como solía, y luego salí al paso acostumbrado del terradillo, por ver si la caña parecía, que no tardó mucho en asomar. Así como la vi, aunque no podía ver quién la ponía, mostré el papel, como dando a entender que pusiesen el hilo, pero ya venía puesto en la caña, al cual até el papel, y de allí a poco tornó a parecer nuestra estrella, con la blanca bandera de paz del atadillo. Dejáronla caer, y alcé yo, y hallé en el paño, en toda suerte de moneda de plata y de oro, más de cincuenta escudos, los cuales cincuenta veces más doblaron nuestro contento y confirmaron la esperanza de tener libertad. »Aquella misma noche volvió nuestro renegado, y nos dijo que había sabido que en aquella casa vivía el mesmo moro que a nosotros nos habían dicho que se llamaba Agi Morato, riquísimo por todo estremo, el cual tenía una sola hija, heredera de toda su hacienda, y que era común opinión en toda la ciudad ser la más hermosa mujer de la Berbería; y que muchos de los virreyes que allí venían la habían pedido por mujer, y que ella nunca se había querido casar; y que también supo que tuvo una cristiana cautiva, que ya se había muerto; todo lo cual concertaba con lo que venía en el papel. Entramos luego en consejo con el renegado, en qué orden se tendría para sacar a la mora y venirnos todos a tierra de cristianos, y, en fin, se acordó por entonces que esperásemos el aviso segundo de Zoraida, que así se llamaba la que ahora quiere llamarse María; porque bien vimos que ella, y no otra alguna era la que había de dar medio a todas aquellas dificultades. Después que quedamos en esto, dijo el renegado que no tuviésemos pena, que él perdería la vida o nos pondría en libertad. »Cuatro días estuvo el baño con gente, que fue ocasión que cuatro días tardase en parecer la caña; al cabo de los cuales, en la acostumbrada soledad del baño, pareció con el lienzo tan preñado, que un felicísimo parto prometía. Inclinóse a mí la caña y el lienzo, hallé en él otro papel y cien escudos de oro, sin otra moneda alguna. Estaba allí el renegado, dímosle a leer el papel dentro de nuestro rancho, el cual dijo que así decía: Yo no sé, mi señor, cómo dar orden que nos vamos a España, ni Lela Marién me lo ha dicho, aunque yo se lo he preguntado. Lo que se podrá hacer es que yo os daré por esta ventana muchísimos dineros de oro: rescataos vos con ellos y vuestros amigos, y vaya uno en tierra de cristianos, y compre allá una barca y vuelva por los demás; y a mí me hallarán en el jardín de mi padre, que está a la puerta de Babazón, junto a la marina, donde tengo de estar todo este verano con mi padre y con mis criados. De allí, de noche, me podréis sacar sin miedo y llevarme a la barca; y mira que has de ser mi marido, porque si no, yo pediré a Marién que te castigue. Si no te fías de nadie que vaya por la barca, rescátate tú y ve, que yo sé que volverás mejor que otro, pues eres caballero y cristiano. Procura saber el jardín, y cuando te pasees por ahí sabré que está solo el baño, y te daré mucho dinero. Alá te guarde, señor mío. »Esto decía y contenía el segundo papel. Lo cual visto por todos, cada uno se ofreció a querer ser el rescatado, y prometió de ir y volver con toda puntualidad, y también yo me ofrecí a lo mismo; a todo lo cual se opuso el renegado, diciendo que en ninguna manera consentiría que ninguno saliese de libertad hasta que fuesen todos juntos, porque la experiencia le había mostrado cuán mal cumplían los libres las palabras que daban en el cautiverio; porque muchas veces habían usado de aquel remedio algunos principales cautivos, rescatando a uno que fuese a Valencia, o Mallorca, con dineros para poder armar una barca y volver por los que le habían rescatado, y nunca habían vuelto; porque la libertad alcanzada y el temor de no volver a perderla les borraba de la memoria todas las obligaciones del mundo. Y, en confirmación de la verdad que nos decía, nos contó brevemente un caso que casi en aquella mesma sazón había acaecido a unos caballeros cristianos, el más estraño que jamás sucedió en aquellas partes, donde a cada paso suceden cosas de grande espanto y de admiración. »En efecto, él vino a decir que lo que se podía y debía hacer era que el dinero que se había de dar para rescatar al cristiano, que se le diese a él para comprar allí en Argel una barca, con achaque de hacerse mercader y tratante en Tetuán y en aquella costa; y que, siendo él señor de la barca, fácilmente se daría traza para sacarlos del baño y embarcarlos a todos. Cuanto más, que si la mora, como ella decía, daba dineros para rescatarlos a todos, que, estando libres, era facilísima cosa aun embarcarse en la mitad del día; y que la dificultad que se ofrecía mayor era que los moros no consienten que renegado alguno compre ni tenga barca, si no es bajel grande para ir en corso, porque se temen que el que compra barca, principalmente si es español, no la quiere sino para irse a tierra de cristianos; pero que él facilitaría este inconveniente con hacer que un moro tagarino fuese a la parte con él en la compañía de la barca y en la ganancia de las mercancías, y con esta sombra él vendría a ser señor de la barca, con que daba por acabado todo lo demás. »Y, puesto que a mí y a mis camaradas nos había parecido mejor lo de enviar por la barca a Mallorca, como la mora decía, no osamos contradecirle, temerosos que, si no hacíamos lo que él decía, nos había de descubrir y poner a peligro de perder las vidas, si descubriese el trato de Zoraida, por cuya vida diéramos todos las nuestras. Y así, determinamos de ponernos en las manos de Dios y en las del renegado, y en aquel mismo punto se le respondió a Zoraida, diciéndole que haríamos todo cuanto nos aconsejaba, porque lo había advertido tan bien como si Lela Marién se lo hubiera dicho, y que en ella sola estaba dilatar aquel negocio, o ponello luego por obra. Ofrecímele de nuevo de ser su esposo, y, con esto, otro día que acaeció a estar solo el baño, en diversas veces, con la caña y el paño, nos dio dos mil escudos de oro, y un papel donde decía que el primer jumá, que es el viernes, se iba al jardín de su padre, y que antes que se fuese nos daría más dinero, y que si aquello no bastase, que se lo avisásemos, que nos daría cuanto le pidiésemos: que su padre tenía tantos, que no lo echaría menos, cuanto más, que ella tenía la llaves de todo. »Dimos luego quinientos escudos al renegado para comprar la barca; con ochocientos me rescaté yo, dando el dinero a un mercader valenciano que a la sazón se hallaba en Argel, el cual me rescató del rey, tomándome sobre su palabra, dándola de que con el primer bajel que viniese de Valencia pagaría mi rescate; porque si luego diera el dinero, fuera dar sospechas al rey que había muchos días que mi rescate estaba en Argel, y que el mercader, por sus granjerías, lo había callado. Finalmente, mi amo era tan caviloso que en ninguna manera me atreví a que luego se desembolsase el dinero. El jueves antes del viernes que la hermosa Zoraida se había de ir al jardín, nos dio otros mil escudos y nos avisó de su partida, rogándome que, si me rescatase, supiese luego el jardín de su padre, y que en todo caso buscase ocasión de ir allá y verla. Respondíle en breves palabras que así lo haría, y que tuviese cuidado de encomendarnos a Lela Marién, con todas aquellas oraciones que la cautiva le había enseñado. »Hecho esto, dieron orden en que los tres compañeros nuestros se rescatasen, por facilitar la salida del baño, y porque, viéndome a mí rescatado, y a ellos no, pues había dinero, no se alborotasen y les persuadiese el diablo que hiciesen alguna cosa en perjuicio de Zoraida; que, puesto que el ser ellos quien eran me podía asegurar deste temor, con todo eso, no quise poner el negocio en aventura, y así, los hice rescatar por la misma orden que yo me rescaté, entregando todo el dinero al mercader, para que, con certeza y seguridad, pudiese hacer la fianza; al cual nunca descubrimos nuestro trato y secreto, por el peligro que había. Capítulo XLI. Donde todavía prosigue el cautivo su suceso »No se pasaron quince días, cuando ya nuestro renegado tenía comprada una muy buena barca, capaz de más de treinta personas: y, para asegurar su hecho y dalle color, quiso hacer, como hizo, un viaje a un lugar que se llamaba Sargel, que está treinta leguas de Argel hacia la parte de Orán, en el cual hay mucha contratación de higos pasos. Dos o tres veces hizo este viaje, en compañía del tagarino que había dicho. Tagarinos llaman en Berbería a los moros de Aragón, y a los de Granada, mudéjares; y en el reino de Fez llaman a los mudéjares elches, los cuales son la gente de quien aquel rey más se sirve en la guerra. »Digo, pues, que cada vez que pasaba con su barca daba fondo en una caleta que estaba no dos tiros de ballesta del jardín donde Zoraida esperaba; y allí, muy de propósito, se ponía el renegado con los morillos que bogaban el remo, o ya a hacer la zalá, o a como por ensayarse de burlas a lo que pensaba hacer de veras; y así, se iba al jardín de Zoraida y le pedía fruta, y su padre se la daba sin conocelle; y, aunque él quisiera hablar a Zoraida, como él después me dijo, y decille que él era el que por orden mía le había de llevar a tierra de cristianos, que estuviese contenta y segura, nunca le fue posible, porque las moras no se dejan ver de ningún moro ni turco, si no es que su marido o su padre se lo manden. De cristianos cautivos se dejan tratar y comunicar, aun más de aquello que sería razonable; y a mí me hubiera pesado que él la hubiera hablado, que quizá la alborotara, viendo que su negocio andaba en boca de renegados. Pero Dios, que lo ordenaba de otra manera, no dio lugar al buen deseo que nuestro renegado tenía; el cual, viendo cuán seguramente iba y venía a Sargel, y que daba fondo cuando y como y adonde quería, y que el tagarino, su compañero, no tenía más voluntad de lo que la suya ordenaba, y que yo estaba ya rescatado, y que sólo faltaba buscar algunos cristianos que bogasen el remo, me dijo que mirase yo cuáles quería traer conmigo, fuera de los rescatados, y que los tuviese hablados para el primer viernes, donde tenía determinado que fuese nuestra partida. Viendo esto, hablé a doce españoles, todos valientes hombres del remo, y de aquellos que más libremente podían salir de la ciudad; y no fue poco hallar tantos en aquella coyuntura, porque estaban veinte bajeles en corso, y se habían llevado toda la gente de remo, y éstos no se hallaran, si no fuera que su amo se quedó aquel verano sin ir en corso, a acabar una galeota que tenía en astillero. A los cuales no les dije otra cosa, sino que el primer viernes en la tarde se saliesen uno a uno, disimuladamente, y se fuesen la vuelta del jardín de Agi Morato, y que allí me aguardasen hasta que yo fuese. A cada uno di este aviso de por sí, con orden que, aunque allí viesen a otros cristianos, no les dijesen sino que yo les había mandado esperar en aquel lugar. »Hecha esta diligencia, me faltaba hacer otra, que era la que más me convenía: y era la de avisar a Zoraida en el punto que estaban los negocios, para que estuviese apercebida y sobre aviso, que no se sobresaltase si de improviso la asaltásemos antes del tiempo que ella podía imaginar que la barca de cristianos podía volver. Y así, determiné de ir al jardín y ver si podría hablarla; y, con ocasión de coger algunas yerbas, un día, antes de mi partida, fui allá, y la primera persona con quién encontré fue con su padre, el cual me dijo, en lengua que en toda la Berbería, y aun en Costantinopla, se halla entre cautivos y moros, que ni es morisca, ni castellana, ni de otra nación alguna, sino una mezcla de todas las lenguas con la cual todos nos entendemos; digo, pues, que en esta manera de lenguaje me preguntó que qué buscaba en aquel su jardín, y de quién era. Respondíle que era esclavo de Arnaúte Mamí (y esto, porque sabía yo por muy cierto que era un grandísimo amigo suyo), y que buscaba de todas yerbas, para hacer ensalada. Preguntóme, por el consiguiente, si era hombre de rescate o no, y que cuánto pedía mi amo por mí. Estando en todas estas preguntas y respuestas, salió de la casa del jardín la bella Zoraida, la cual ya había mucho que me había visto; y, como las moras en ninguna manera hacen melindre de mostrarse a los cristianos, ni tampoco se esquivan, como ya he dicho, no se le dio nada de venir adonde su padre conmigo estaba; antes, luego cuando su padre vio que venía, y de espacio, la llamó y mandó que llegase. »Demasiada cosa sería decir yo agora la mucha hermosura, la gentileza, el gallardo y rico adorno con que mi querida Zoraida se mostró a mis ojos: sólo diré que más perlas pendían de su hermosísimo cuello, orejas y cabellos, que cabellos tenía en la cabeza. En las gargantas de los sus pies, que descubiertas, a su usanza, traía, traía dos carcajes (que así se llamaban las manillas o ajorcas de los pies en morisco) de purísimo oro, con tantos diamantes engastados, que ella me dijo después que su padre los estimaba en diez mil doblas, y las que traía en las muñecas de las manos valían otro tanto. Las perlas eran en gran cantidad y muy buenas, porque la mayor gala y bizarría de las moras es adornarse de ricas perlas y aljófar, y así, hay más perlas y aljófar entre moros que entre todas las demás naciones; y el padre de Zoraida tenía fama de tener muchas y de las mejores que en Argel había, y de tener asimismo más de docientos mil escudos españoles, de todo lo cual era señora esta que ahora lo es mía. Si con todo este adorno podía venir entonces hermosa, o no, por las reliquias que le han quedado en tantos trabajos se podrá conjeturar cuál debía de ser en las prosperidades. Porque ya se sabe que la hermosura de algunas mujeres tiene días y sazones, y requiere accidentes para diminuirse o acrecentarse; y es natural cosa que las pasiones del ánimo la levanten o abajen, puesto que las más veces la destruyen. »Digo, en fin, que entonces llegó en todo estremo aderezada y en todo estremo hermosa, o, a lo menos, a mí me pareció serlo la más que hasta entonces había visto; y con esto, viendo las obligaciones en que me había puesto, me parecía que tenía delante de mí una deidad del cielo, venida a la tierra para mi gusto y para mi remedio. Así como ella llegó, le dijo su padre en su lengua como yo era cautivo de su amigo Arnaúte Mamí, y que venía a buscar ensalada. Ella tomó la mano, y en aquella mezcla de lenguas que tengo dicho me preguntó si era caballero y qué era la causa que no me rescataba. Yo le respondí que ya estaba rescatado, y que en el precio podía echar de ver en lo que mi amo me estimaba, pues había dado por mí mil y quinientos zoltanís. A lo cual ella respondió: ''En verdad que si tú fueras de mi padre, que yo hiciera que no te diera él por otros dos tantos, porque vosotros, cristianos, siempre mentís en cuanto decís, y os hacéis pobres por engañar a los moros''. ''Bien podría ser eso, señora -le respondí-, mas en verdad que yo la he tratado con mi amo, y la trato y la trataré con cuantas personas hay en el mundo''. ''Y ¿cuándo te vas?'', dijo Zoraida. ''Mañana, creo yo -dije-, porque está aquí un bajel de Francia que se hace mañana a la vela, y pienso irme en él''. ''¿No es mejor -replicó Zoraida-, esperar a que vengan bajeles de España, y irte con ellos, que no con los de Francia, que no son vuestros amigos?'' ''No -respondí yo-, aunque si como hay nuevas que viene ya un bajel de España, es verdad, todavía yo le aguardaré, puesto que es más cierto el partirme mañana; porque el deseo que tengo de verme en mi tierra, y con las personas que bien quiero, es tanto que no me dejará esperar otra comodidad, si se tarda, por mejor que sea''. ''Debes de ser, sin duda, casado en tu tierra -dijo Zoraida-, y por eso deseas ir a verte con tu mujer''. ''No soy -respondí yo- casado, mas tengo dada la palabra de casarme en llegando allá''. ''Y ¿es hermosa la dama a quien se la diste?'', dijo Zoraida. ''Tan hermosa es -respondí yo- que para encarecella y decirte la verdad, te parece a ti mucho''. Desto se riyó muy de veras su padre, y dijo: ''Gualá, cristiano, que debe de ser muy hermosa si se parece a mi hija, que es la más hermosa de todo este reino. Si no, mírala bien, y verás cómo te digo verdad''. Servíanos de intérprete a las más de estas palabras y razones el padre de Zoraida, como más ladino; que, aunque ella hablaba la bastarda lengua que, como he dicho, allí se usa, más declaraba su intención por señas que por palabras. »Estando en estas y otras muchas razones, llegó un moro corriendo, y dijo, a grandes voces, que por las bardas o paredes del jardín habían saltado cuatro turcos, y andaban cogiendo la fruta, aunque no estaba madura. Sobresaltóse el viejo, y lo mesmo hizo Zoraida, porque es común y casi natural el miedo que los moros a los turcos tienen, especialmente a los soldados, los cuales son tan insolentes y tienen tanto imperio sobre los moros que a ellos están sujetos, que los tratan peor que si fuesen esclavos suyos. Digo, pues, que dijo su padre a Zoraida: ''Hija, retírate a la casa y enciérrate, en tanto que yo voy a hablar a estos canes; y tú, cristiano, busca tus yerbas, y vete en buen hora, y llévete Alá con bien a tu tierra''. Yo me incliné, y él se fue a buscar los turcos, dejándome solo con Zoraida, que comenzó a dar muestras de irse donde su padre la había mandado. Pero, apenas él se encubrió con los árboles del jardín, cuando ella, volviéndose a mí, llenos los ojos de lágrimas, me dijo: ''Ãmexi, cristiano, ámexi''; que quiere decir: "¿Vaste, cristiano, vaste?" Yo la respondí: ''Señora, sí, pero no en ninguna manera sin ti: el primero jumá me aguarda, y no te sobresaltes cuando nos veas; que sin duda alguna iremos a tierra de cristianos''. »Yo le dije esto de manera que ella me entendió muy bien a todas las razones que entrambos pasamos; y, echándome un brazo al cuello, con desmayados pasos comenzó a caminar hacia la casa; y quiso la suerte, que pudiera ser muy mala si el cielo no lo ordenara de otra manera, que, yendo los dos de la manera y postura que os he contado, con un brazo al cuello, su padre, que ya volvía de hacer ir a los turcos, nos vio de la suerte y manera que íbamos, y nosotros vimos que él nos había visto; pero Zoraida, advertida y discreta, no quiso quitar el brazo de mi cuello, antes se llegó más a mí y puso su cabeza sobre mi pecho, doblando un poco las rodillas, dando claras señales y muestras que se desmayaba, y yo, ansimismo, di a entender que la sostenía contra mi voluntad. Su padre llegó corriendo adonde estábamos, y, viendo a su hija de aquella manera, le preguntó que qué tenía; pero, como ella no le respondiese, dijo su padre: ''Sin duda alguna que con el sobresalto de la entrada de estos canes se ha desmayado''. Y, quitándola del mío, la arrimó a su pecho; y ella, dando un suspiro y aún no enjutos los ojos de lágrimas, volvió a decir: ''Ãmexi, cristiano, ámexi'': "Vete, cristiano, vete". A lo que su padre respondió: ''No importa, hija, que el cristiano se vaya, que ningún mal te ha hecho, y los turcos ya son idos. No te sobresalte cosa alguna, pues ninguna hay que pueda darte pesadumbre, pues, como ya te he dicho, los turcos, a mi ruego, se volvieron por donde entraron''. ''Ellos, señor, la sobresaltaron, como has dicho -dije yo a su padre-; mas, pues ella dice que yo me vaya, no la quiero dar pesadumbre: quédate en paz, y, con tu licencia, volveré, si fuere menester, por yerbas a este jardín; que, según dice mi amo, en ninguno las hay mejores para ensalada que en él''. ''Todas las que quisieres podrás volver -respondió Agi Morato-, que mi hija no dice esto porque tú ni ninguno de los cristianos la enojaban, sino que, por decir que los turcos se fuesen, dijo que tú te fueses, o porque ya era hora que buscases tus yerbas''. »Con esto, me despedí al punto de entrambos; y ella, arrancándosele el alma, al parecer, se fue con su padre; y yo, con achaque de buscar las yerbas, rodeé muy bien y a mi placer todo el jardín: miré bien las entradas y salidas, y la fortaleza de la casa, y la comodidad que se podía ofrecer para facilitar todo nuestro negocio. Hecho esto, me vine y di cuenta de cuanto había pasado al renegado y a mis compañeros; y ya no veía la hora de verme gozar sin sobresalto del bien que en la hermosa y bella Zoraida la suerte me ofrecía. »En fin, el tiempo se pasó, y se llegó el día y plazo de nosotros tan deseado; y, siguiendo todos el orden y parecer que, con discreta consideración y largo discurso, muchas veces habíamos dado, tuvimos el buen suceso que deseábamos; porque el viernes que se siguió al día que yo con Zoraida hablé en el jardín, nuestro renegado, al anochecer, dio fondo con la barca casi frontero de donde la hermosísima Zoraida estaba. Ya los cristianos que habían de bogar el remo estaban prevenidos y escondidos por diversas partes de todos aquellos alrededores. Todos estaban suspensos y alborozados, aguardándome, deseosos ya de embestir con el bajel que a los ojos tenían; porque ellos no sabían el concierto del renegado, sino que pensaban que a fuerza de brazos habían de haber y ganar la libertad, quitando la vida a los moros que dentro de la barca estaban. »Sucedió, pues, que, así como yo me mostré y mis compañeros, todos los demás escondidos que nos vieron se vinieron llegando a nosotros. Esto era ya a tiempo que la ciudad estaba ya cerrada, y por toda aquella campaña ninguna persona parecía. Como estuvimos juntos, dudamos si sería mejor ir primero por Zoraida, o rendir primero a los moros bagarinos que bogaban el remo en la barca. Y, estando en esta duda, llegó a nosotros nuestro renegado diciéndonos que en qué nos deteníamos, que ya era hora, y que todos sus moros estaban descuidados, y los más dellos durmiendo. Dijímosle en lo que reparábamos, y él dijo que lo que más importaba era rendir primero el bajel, que se podía hacer con grandísima facilidad y sin peligro alguno, y que luego podíamos ir por Zoraida. Pareciónos bien a todos lo que decía, y así, sin detenernos más, haciendo él la guía, llegamos al bajel, y, saltando él dentro primero, metió mano a un alfanje, y dijo en morisco: ''Ninguno de vosotros se mueva de aquí, si no quiere que le cueste la vida''. Ya, a este tiempo, habían entrado dentro casi todos los cristianos. Los moros, que eran de poco ánimo, viendo hablar de aquella manera a su arráez, quedáronse espantados, y sin ninguno de todos ellos echar mano a las armas, que pocas o casi ningunas tenían, se dejaron, sin hablar alguna palabra, maniatar de los cristianos, los cuales con mucha presteza lo hicieron, amenazando a los moros que si alzaban por alguna vía o manera la voz, que luego al punto los pasarían todos a cuchillo. »Hecho ya esto, quedándose en guardia dellos la mitad de los nuestros, los que quedábamos, haciéndonos asimismo el renegado la guía, fuimos al jardín de Agi Morato, y quiso la buena suerte que, llegando a abrir la puerta, se abrió con tanta facilidad como si cerrada no estuviera; y así, con gran quietud y silencio, llegamos a la casa sin ser sentidos de nadie. Estaba la bellísima Zoraida aguardándonos a una ventana, y, así como sintió gente, preguntó con voz baja si éramos nizarani, como si dijera o preguntara si éramos cristianos. Yo le respondí que sí, y que bajase. Cuando ella me conoció, no se detuvo un punto, porque, sin responderme palabra, bajó en un instante, abrió la puerta y mostróse a todos tan hermosa y ricamente vestida que no lo acierto a encarecer. Luego que yo la vi, le tomé una mano y la comencé a besar, y el renegado hizo lo mismo, y mis dos camaradas; y los demás, que el caso no sabían, hicieron lo que vieron que nosotros hacíamos, que no parecía sino que le dábamos las gracias y la reconocíamos por señora de nuestra libertad. El renegado le dijo en lengua morisca si estaba su padre en el jardín. Ella respondió que sí y que dormía. ''Pues será menester despertalle -replicó el renegado-, y llevárnosle con nosotros, y todo aquello que tiene de valor este hermoso jardín.'' ''No -dijo ella-, a mi padre no se ha de tocar en ningún modo, y en esta casa no hay otra cosa que lo que yo llevo, que es tanto, que bien habrá para que todos quedéis ricos y contentos; y esperaros un poco y lo veréis''. Y, diciendo esto, se volvió a entrar, diciendo que muy presto volvería; que nos estuviésemos quedos, sin hacer ningún ruido. Preguntéle al renegado lo que con ella había pasado, el cual me lo contó, a quien yo dije que en ninguna cosa se había de hacer más de lo que Zoraida quisiese; la cual ya que volvía cargada con un cofrecillo lleno de escudos de oro, tantos, que apenas lo podía sustentar, quiso la mala suerte que su padre despertase en el ínterin y sintiese el ruido que andaba en el jardín; y, asomándose a la ventana, luego conoció que todos los que en él estaban eran cristianos; y, dando muchas, grandes y desaforadas voces, comenzó a decir en arábigo: ''¡Cristianos, cristianos! ¡Ladrones, ladrones!''; por los cuales gritos nos vimos todos puestos en grandísima y temerosa confusión. Pero el renegado, viendo el peligro en que estábamos, y lo mucho que le importaba salir con aquella empresa antes de ser sentido, con grandísima presteza, subió donde Agi Morato estaba, y juntamente con él fueron algunos de nosotros; que yo no osé desamparar a la Zoraida, que como desmayada se había dejado caer en mis brazos. En resolución, los que subieron se dieron tan buena maña que en un momento bajaron con Agi Morato, trayéndole atadas las manos y puesto un pañizuelo en la boca, que no le dejaba hablar palabra, amenazándole que el hablarla le había de costar la vida. Cuando su hija le vio, se cubrió los ojos por no verle, y su padre quedó espantado, ignorando cuán de su voluntad se había puesto en nuestras manos. Mas, entonces siendo más necesarios los pies, con diligencia y presteza nos pusimos en la barca; que ya los que en ella habían quedado nos esperaban, temerosos de algún mal suceso nuestro. »Apenas serían dos horas pasadas de la noche, cuando ya estábamos todos en la barca, en la cual se le quitó al padre de Zoraida la atadura de las manos y el paño de la boca; pero tornóle a decir el renegado que no hablase palabra, que le quitarían la vida. Él, como vio allí a su hija, comenzó a suspirar ternísimamente, y más cuando vio que yo estrechamente la tenía abrazada, y que ella sin defender, quejarse ni esquivarse, se estaba queda; pero, con todo esto, callaba, porque no pusiesen en efeto las muchas amenazas que el renegado le hacía. Viéndose, pues, Zoraida ya en la barca, y que queríamos dar los remos al agua, y viendo allí a su padre y a los demás moros que atados estaban, le dijo al renegado que me dijese le hiciese merced de soltar a aquellos moros y de dar libertad a su padre, porque antes se arrojaría en la mar que ver delante de sus ojos y por causa suya llevar cautivo a un padre que tanto la había querido. El renegado me lo dijo; y yo respondí que era muy contento; pero él respondió que no convenía, a causa que, si allí los dejaban apellidarían luego la tierra y alborotarían la ciudad, y serían causa que saliesen a buscallos con algunas fragatas ligeras, y les tomasen la tierra y la mar, de manera que no pudiésemos escaparnos; que lo que se podría hacer era darles libertad en llegando a la primera tierra de cristianos. En este parecer venimos todos, y Zoraida, a quien se le dio cuenta, con las causas que nos movían a no hacer luego lo que quería, también se satisfizo; y luego, con regocijado silencio y alegre diligencia, cada uno de nuestros valientes remeros tomó su remo, y comenzamos, encomendándonos a Dios de todo corazón, a navegar la vuelta de las islas de Mallorca, que es la tierra de cristianos más cerca. »Pero, a causa de soplar un poco el viento tramontana y estar la mar algo picada, no fue posible seguir la derrota de Mallorca, y fuenos forzoso dejarnos ir tierra a tierra la vuelta de Orán, no sin mucha pesadumbre nuestra, por no ser descubiertos del lugar de Sargel, que en aquella costa cae sesenta millas de Argel. Y, asimismo, temíamos encontrar por aquel paraje alguna galeota de las que de ordinario vienen con mercancía de Tetuán, aunque cada uno por sí, y todos juntos, presumíamos de que, si se encontraba galeota de mercancía, como no fuese de las que andan en corso, que no sólo no nos perderíamos, mas que tomaríamos bajel donde con más seguridad pudiésemos acabar nuestro viaje. Iba Zoraida, en tanto que se navegaba, puesta la cabeza entre mis manos, por no ver a su padre, y sentía yo que iba llamando a Lela Marién que nos ayudase. »Bien habríamos navegado treinta millas, cuando nos amaneció, como tres tiros de arcabuz desviados de tierra, toda la cual vimos desierta y sin nadie que nos descubriese; pero, con todo eso, nos fuimos a fuerza de brazos entrando un poco en la mar, que ya estaba algo más sosegada; y, habiendo entrado casi dos leguas, diose orden que se bogase a cuarteles en tanto que comíamos algo, que iba bien proveída la barca, puesto que los que bogaban dijeron que no era aquél tiempo de tomar reposo alguno, que les diesen de comer los que no bogaban, que ellos no querían soltar los remos de las manos en manera alguna. Hízose ansí, y en esto comenzó a soplar un viento largo, que nos obligó a hacer luego vela y a dejar el remo, y enderezar a Orán, por no ser posible poder hacer otro viaje. Todo se hizo con muchísima presteza; y así, a la vela, navegamos por más de ocho millas por hora, sin llevar otro temor alguno sino el de encontrar con bajel que de corso fuese. »Dimos de comer a los moros bagarinos, y el renegado les consoló diciéndoles como no iban cautivos, que en la primera ocasión les darían libertad. Lo mismo se le dijo al padre de Zoraida, el cual respondió: ''Cualquiera otra cosa pudiera yo esperar y creer de vuestra liberalidad y buen término, ¡oh cristianos!, mas el darme libertad, no me tengáis por tan simple que lo imagine; que nunca os pusistes vosotros al peligro de quitármela para volverla tan liberalmente, especialmente sabiendo quién soy yo, y el interese que se os puede seguir de dármela; el cual interese, si le queréis poner nombre, desde aquí os ofrezco todo aquello que quisiéredes por mí y por esa desdichada hija mía, o si no, por ella sola, que es la mayor y la mejor parte de mi alma''. En diciendo esto, comenzó a llorar tan amargamente que a todos nos movió a compasión, y forzó a Zoraida que le mirase; la cual, viéndole llorar, así se enterneció que se levantó de mis pies y fue a abrazar a su padre, y, juntando su rostro con el suyo, comenzaron los dos tan tierno llanto que muchos de los que allí íbamos le acompañamos en él. Pero, cuando su padre la vio adornada de fiesta y con tantas joyas sobre sí, le dijo en su lengua: ''¿Qué es esto, hija, que ayer al anochecer, antes que nos sucediese esta terrible desgracia en que nos vemos, te vi con tus ordinarios y caseros vestidos, y agora, sin que hayas tenido tiempo de vestirte y sin haberte dado alguna nueva alegre de solenizalle con adornarte y pulirte, te veo compuesta con los mejores vestidos que yo supe y pude darte cuando nos fue la ventura más favorable? Respóndeme a esto, que me tiene más suspenso y admirado que la misma desgracia en que me hallo''. »Todo lo que el moro decía a su hija nos lo declaraba el renegado, y ella no le respondía palabra. Pero, cuando él vio a un lado de la barca el cofrecillo donde ella solía tener sus joyas, el cual sabía él bien que le había dejado en Argel, y no traídole al jardín, quedó más confuso, y preguntóle que cómo aquel cofre había venido a nuestras manos, y qué era lo que venía dentro. A lo cual el renegado, sin aguardar que Zoraida le respondiese, le respondió: ''No te canses, señor, en preguntar a Zoraida, tu hija, tantas cosas, porque con una que yo te responda te satisfaré a todas; y así, quiero que sepas que ella es cristiana, y es la que ha sido la lima de nuestras cadenas y la libertad de nuestro cautiverio; ella va aquí de su voluntad, tan contenta, a lo que yo imagino, de verse en este estado, como el que sale de las tinieblas a la luz, de la muerte a la vida y de la pena a la gloria''. ''¿Es verdad lo que éste dice, hija?'', dijo el moro. ''Así es'', respondió Zoraida. ''¿Que, en efeto -replicó el viejo-, tú eres cristiana, y la que ha puesto a su padre en poder de sus enemigos?'' A lo cual respondió Zoraida: ''La que es cristiana yo soy, pero no la que te ha puesto en este punto, porque nunca mi deseo se estendió a dejarte ni a hacerte mal, sino a hacerme a mí bien''. ''Y ¿qué bien es el que te has hecho, hija?'' ''Eso -respondió ella- pregúntaselo tú a Lela Marién, que ella te lo sabrá decir mejor que no yo''. »Apenas hubo oído esto el moro, cuando, con una increíble presteza, se arrojó de cabeza en la mar, donde sin ninguna duda se ahogara, si el vestido largo y embarazoso que traía no le entretuviera un poco sobre el agua. Dio voces Zoraida que le sacasen, y así, acudimos luego todos, y, asiéndole de la almalafa, le sacamos medio ahogado y sin sentido, de que recibió tanta pena Zoraida que, como si fuera ya muerto, hacía sobre él un tierno y doloroso llanto. Volvímosle boca abajo, volvió mucha agua, tornó en sí al cabo de dos horas, en las cuales, habiéndose trocado el viento, nos convino volver hacia tierra, y hacer fuerza de remos, por no embestir en ella; mas quiso nuestra buena suerte que llegamos a una cala que se hace al lado de un pequeño promontorio o cabo que de los moros es llamado el de La Cava Rumía, que en nuestra lengua quiere decir La mala mujer cristiana; y es tradición entre los moros que en aquel lugar está enterrada la Cava, por quien se perdió España, porque cava en su lengua quiere decir mujer mala, y rumía, cristiana; y aun tienen por mal agüero llegar allí a dar fondo cuando la necesidad les fuerza a ello, porque nunca le dan sin ella; puesto que para nosotros no fue abrigo de mala mujer, sino puerto seguro de nuestro remedio, según andaba alterada la mar. »Pusimos nuestras centinelas en tierra, y no dejamos jamás los remos de la mano; comimos de lo que el renegado había proveído, y rogamos a Dios y a Nuestra Señora, de todo nuestro corazón, que nos ayudase y favoreciese para que felicemente diésemos fin a tan dichoso principio. Diose orden, a suplicación de Zoraida, como echásemos en tierra a su padre y a todos los demás moros que allí atados venían, porque no le bastaba el ánimo, ni lo podían sufrir sus blandas entrañas, ver delante de sus ojos atado a su padre y aquellos de su tierra presos. Prometímosle de hacerlo así al tiempo de la partida, pues no corría peligro el dejallos en aquel lugar, que era despoblado. No fueron tan vanas nuestras oraciones que no fuesen oídas del cielo; que, en nuestro favor, luego volvió el viento, tranquilo el mar, convidándonos a que tornásemos alegres a proseguir nuestro comenzado viaje. »Viendo esto, desatamos a los moros, y uno a uno los pusimos en tierra, de lo que ellos se quedaron admirados; pero, llegando a desembarcar al padre de Zoraida, que ya estaba en todo su acuerdo, dijo: ''¿Por qué pensáis, cristianos, que esta mala hembra huelga de que me deis libertad? ¿Pensáis que es por piedad que de mí tiene? No, por cierto, sino que lo hace por el estorbo que le dará mi presencia cuando quiera poner en ejecución sus malos deseos; ni penséis que la ha movido a mudar religión entender ella que la vuestra a la nuestra se aventaja, sino el saber que en vuestra tierra se usa la deshonestidad más libremente que en la nuestra''. Y, volviéndose a Zoraida, teniéndole yo y otro cristiano de entrambos brazos asido, porque algún desatino no hiciese, le dijo: ''¡Oh infame moza y mal aconsejada muchacha! ¿Adónde vas, ciega y desatinada, en poder destos perros, naturales enemigos nuestros? ¡Maldita sea la hora en que yo te engendré, y malditos sean los regalos y deleites en que te he criado!'' Pero, viendo yo que llevaba término de no acabar tan presto, di priesa a ponelle en tierra, y desde allí, a voces, prosiguió en sus maldiciones y lamentos, rogando a Mahoma rogase a Alá que nos destruyese, confundiese y acabase; y cuando, por habernos hecho a la vela, no podimos oír sus palabras, vimos sus obras, que eran arrancarse las barbas, mesarse los cabellos y arrastrarse por el suelo; mas una vez esforzó la voz de tal manera que podimos entender que decía: ''¡Vuelve, amada hija, vuelve a tierra, que todo te lo perdono; entrega a esos hombres ese dinero, que ya es suyo, y vuelve a consolar a este triste padre tuyo, que en esta desierta arena dejará la vida, si tú le dejas!'' Todo lo cual escuchaba Zoraida, y todo lo sentía y lloraba, y no supo decirle ni respondelle palabra, sino: ''Plega a Alá, padre mío, que Lela Marién, que ha sido la causa de que yo sea cristiana, ella te consuele en tu tristeza. Alá sabe bien que no pude hacer otra cosa de la que he hecho, y que estos cristianos no deben nada a mi voluntad, pues, aunque quisiera no venir con ellos y quedarme en mi casa, me fuera imposible, según la priesa que me daba mi alma a poner por obra ésta que a mí me parece tan buena como tú, padre amado, la juzgas por mala''. Esto dijo, a tiempo que ni su padre la oía, ni nosotros ya le veíamos; y así, consolando yo a Zoraida, atendimos todos a nuestro viaje, el cual nos le facilitaba el proprio viento, de tal manera que bien tuvimos por cierto de vernos otro día al amanecer en las riberas de España. »Mas, como pocas veces, o nunca, viene el bien puro y sencillo, sin ser acompañado o seguido de algún mal que le turbe o sobresalte, quiso nuestra ventura, o quizá las maldiciones que el moro a su hija había echado, que siempre se han de temer de cualquier padre que sean; quiso, digo, que estando ya engolfados y siendo ya casi pasadas tres horas de la noche, yendo con la vela tendida de alto baja, frenillados los remos, porque el próspero viento nos quitaba del trabajo de haberlos menester, con la luz de la luna, que claramente resplandecía, vimos cerca de nosotros un bajel redondo, que, con todas las velas tendidas, llevando un poco a orza el timón, delante de nosotros atravesaba; y esto tan cerca, que nos fue forzoso amainar por no embestirle, y ellos, asimesmo, hicieron fuerza de timón para darnos lugar que pasásemos. »Habíanse puesto a bordo del bajel a preguntarnos quién éramos, y adónde navegábamos, y de dónde veníamos; pero, por preguntarnos esto en lengua francesa, dijo nuestro renegado: ''Ninguno responda; porque éstos, sin duda, son cosarios franceses, que hacen a toda ropa''. Por este advertimiento, ninguno respondió palabra; y, habiendo pasado un poco delante, que ya el bajel quedaba sotavento, de improviso soltaron dos piezas de artillería, y, a lo que parecía, ambas venían con cadenas, porque con una cortaron nuestro árbol por medio, y dieron con él y con la vela en la mar; y al momento, disparando otra pieza, vino a dar la bala en mitad de nuestra barca, de modo que la abrió toda, sin hacer otro mal alguno; pero, como nosotros nos vimos ir a fondo, comenzamos todos a grandes voces a pedir socorro y a rogar a los del bajel que nos acogiesen, porque nos anegábamos. Amainaron entonces, y, echando el esquife o barca a la mar, entraron en él hasta doce franceses bien armados, con sus arcabuces y cuerdas encendidas, y así llegaron junto al nuestro; y, viendo cuán pocos éramos y cómo el bajel se hundía, nos recogieron, diciendo que, por haber usado de la descortesía de no respondelles, nos había sucedido aquello. Nuestro renegado tomó el cofre de las riquezas de Zoraida, y dio con él en la mar, sin que ninguno echase de ver en lo que hacía. En resolución, todos pasamos con los franceses, los cuales, después de haberse informado de todo aquello que de nosotros saber quisieron, como si fueran nuestros capitales enemigos, nos despojaron de todo cuanto teníamos, y a Zoraida le quitaron hasta los carcajes que traía en los pies. Pero no me daba a mí tanta pesadumbre la que a Zoraida daban, como me la daba el temor que tenía de que habían de pasar del quitar de las riquísimas y preciosísimas joyas al quitar de la joya que más valía y ella más estimaba. Pero los deseos de aquella gente no se estienden a más que al dinero, y desto jamás se vee harta su codicia; lo cual entonces llegó a tanto, que aun hasta los vestidos de cautivos nos quitaran si de algún provecho les fueran. Y hubo parecer entre ellos de que a todos nos arrojasen a la mar envueltos en una vela, porque tenían intención de tratar en algunos puertos de España con nombre de que eran bretones, y si nos llevaban vivos, serían castigados, siendo descubierto su hurto. Mas el capitán, que era el que había despojado a mi querida Zoraida, dijo que él se contentaba con la presa que tenía, y que no quería tocar en ningún puerto de España, sino pasar el estrecho de Gibraltar de noche, o como pudiese, y irse a la Rochela, de donde había salido; y así, tomaron por acuerdo de darnos el esquife de su navío, y todo lo necesario para la corta navegación que nos quedaba, como lo hicieron otra día, ya a vista de tierra de España, con la cual vista, todas nuestras pesadumbres y pobrezas se nos olvidaron de todo punto, como si no hubieran pasado por nosotros: tanto es el gusto de alcanzar la libertad perdida. »Cerca de mediodía podría ser cuando nos echaron en la barca, dándonos dos barriles de agua y algún bizcocho; y el capitán, movido no sé de qué misericordia, al embarcarse la hermosísima Zoraida, le dio hasta cuarenta escudos de oro, y no consintió que le quitasen sus soldados estos mesmos vestidos que ahora tiene puestos. Entramos en el bajel; dímosles las gracias por el bien que nos hacían, mostrándonos más agradecidos que quejosos; ellos se hicieron a lo largo, siguiendo la derrota del estrecho; nosotros, sin mirar a otro norte que a la tierra que se nos mostraba delante, nos dimos tanta priesa a bogar que al poner del sol estábamos tan cerca que bien pudiéramos, a nuestro parecer, llegar antes que fuera muy noche; pero, por no parecer en aquella noche la luna y el cielo mostrarse escuro, y por ignorar el paraje en que estábamos, no nos pareció cosa segura embestir en tierra, como a muchos de nosotros les parecía, diciendo que diésemos en ella, aunque fuese en unas peñas y lejos de poblado, porque así aseguraríamos el temor que de razón se debía tener que por allí anduviesen bajeles de cosarios de Tetuán, los cuales anochecen en Berbería y amanecen en las costas de España, y hacen de ordinario presa, y se vuelven a dormir a sus casas. Pero, de los contrarios pareceres, el que se tomó fue que nos llegásemos poco a poco, y que si el sosiego del mar lo concediese, desembarcásemos donde pudiésemos. »Hízose así, y poco antes de la media noche sería cuando llegamos al pie de una disformísima y alta montaña, no tan junto al mar que no concediese un poco de espacio para poder desembarcar cómodamente. Embestimos en la arena, salimos a tierra, besamos el suelo, y, con lágrimas de muy alegrísimo contento, dimos todos gracias a Dios, Señor Nuestro, por el bien tan incomparable que nos había hecho. Sacamos de la barca los bastimentos que tenía, tirámosla en tierra, y subímonos un grandísimo trecho en la montaña, porque aún allí estábamos, y aún no podíamos asegurar el pecho, ni acabábamos de creer que era tierra de cristianos la que ya nos sostenía. Amaneció más tarde, a mi parecer, de lo que quisiéramos. Acabamos de subir toda la montaña, por ver si desde allí algún poblado se descubría, o algunas cabañas de pastores; pero, aunque más tendimos la vista, ni poblado, ni persona, ni senda, ni camino descubrimos. Con todo esto, determinamos de entrarnos la tierra adentro, pues no podría ser menos sino que presto descubriésemos quien nos diese noticia della. Pero lo que a mí más me fatigaba era el ver ir a pie a Zoraida por aquellas asperezas, que, puesto que alguna vez la puse sobre mis hombros, más le cansaba a ella mi cansancio que la reposaba su reposo; y así, nunca más quiso que yo aquel trabajo tomase; y, con mucha paciencia y muestras de alegría, llevándola yo siempre de la mano, poco menos de un cuarto de legua debíamos de haber andado, cuando llegó a nuestros oídos el son de una pequeña esquila, señal clara que por allí cerca había ganado; y, mirando todos con atención si alguno se parecía, vimos al pie de un alcornoque un pastor mozo, que con grande reposo y descuido estaba labrando un palo con un cuchillo. Dimos voces, y él, alzando la cabeza, se puso ligeramente en pie, y, a lo que después supimos, los primeros que a la vista se le ofrecieron fueron el renegado y Zoraida, y, como él los vio en hábito de moros, pensó que todos los de la Berbería estaban sobre él; y, metiéndose con estraña ligereza por el bosque adelante, comenzó a dar los mayores gritos del mundo diciendo: ''¡Moros, moros hay en la tierra! ¡Moros, moros! ¡Arma, arma!'' »Con estas voces quedamos todos confusos, y no sabíamos qué hacernos; pero, considerando que las voces del pastor habían de alborotar la tierra, y que la caballería de la costa había de venir luego a ver lo que era, acordamos que el renegado se desnudase las ropas del turco y se vistiese un gilecuelco o casaca de cautivo que uno de nosotros le dio luego, aunque se quedó en camisa; y así, encomendándonos a Dios, fuimos por el mismo camino que vimos que el pastor llevaba, esperando siempre cuándo había de dar sobre nosotros la caballería de la costa. Y no nos engañó nuestro pensamiento, porque, aún no habrían pasado dos horas cuando, habiendo ya salido de aquellas malezas a un llano, descubrimos hasta cincuenta caballeros, que con gran ligereza, corriendo a media rienda, a nosotros se venían, y así como los vimos, nos estuvimos quedos aguardándolos; pero, como ellos llegaron y vieron, en lugar de los moros que buscaban, tanto pobre cristiano, quedaron confusos, y uno dellos nos preguntó si éramos nosotros acaso la ocasión por que un pastor había apellidado al arma. ''Sí'', dije yo; y, queriendo comenzar a decirle mi suceso, y de dónde veníamos y quién éramos, uno de los cristianos que con nosotros venían conoció al jinete que nos había hecho la pregunta, y dijo, sin dejarme a mí decir más palabra: ''¡Gracias sean dadas a Dios, señores, que a tan buena parte nos ha conducido!, porque, si yo no me engaño, la tierra que pisamos es la de Vélez Málaga, si ya los años de mi cautiverio no me han quitado de la memoria el acordarme que vos, señor, que nos preguntáis quién somos, sois Pedro de Bustamante, tío mío''. Apenas hubo dicho esto el cristiano cautivo, cuando el jinete se arrojó del caballo y vino a abrazar al mozo, diciéndole: ''Sobrino de mi alma y de mi vida, ya te conozco, y ya te he llorado por muerto yo, y mi hermana, tu madre, y todos los tuyos, que aún viven; y Dios ha sido servido de darles vida para que gocen el placer de verte: ya sabíamos que estabas en Argel, y por las señales y muestras de tus vestidos, y la de todos los desta compañía, comprehendo que habéis tenido milagrosa libertad''. ''Así es -respondió el mozo-, y tiempo nos quedará para contároslo todo''. »Luego que los jinetes entendieron que éramos cristianos cautivos, se apearon de sus caballos, y cada uno nos convidaba con el suyo para llevarnos a la ciudad de Vélez Málaga, que legua y media de allí estaba. Algunos dellos volvieron a llevar la barca a la ciudad, diciéndoles dónde la habíamos dejado; otros nos subieron a las ancas, y Zoraida fue en las del caballo del tío del cristiano. Saliónos a recebir todo el pueblo, que ya de alguno que se había adelantado sabían la nueva de nuestra venida. No se admiraban de ver cautivos libres, ni moros cautivos, porque toda la gente de aquella costa está hecha a ver a los unos y a los otros; pero admirábanse de la hermosura de Zoraida, la cual en aquel instante y sazón estaba en su punto, ansí con el cansancio del camino como con la alegría de verse ya en tierra de cristianos, sin sobresalto de perderse; y esto le había sacado al rostro tales colores que, si no es que la afición entonces me engañaba, osaré decir que más hermosa criatura no había en el mundo; a lo menos, que yo la hubiese visto. »Fuimos derechos a la iglesia, a dar gracias a Dios por la merced recebida; y, así como en ella entró Zoraida, dijo que allí había rostros que se parecían a los de Lela Marién. Dijímosle que eran imágines suyas, y como mejor se pudo le dio el renegado a entender lo que significaban, para que ella las adorase como si verdaderamente fueran cada una dellas la misma Lela Marién que la había hablado. Ella, que tiene buen entendimiento y un natural fácil y claro, entendió luego cuanto acerca de las imágenes se le dijo. Desde allí nos llevaron y repartieron a todos en diferentes casas del pueblo; pero al renegado, Zoraida y a mí nos llevó el cristiano que vino con nosotros, y en casa de sus padres, que medianamente eran acomodados de los bienes de fortuna, y nos regalaron con tanto amor como a su mismo hijo. »Seis días estuvimos en Vélez, al cabo de los cuales el renegado, hecha su información de cuanto le convenía, se fue a la ciudad de Granada, a reducirse por medio de la Santa Inquisición al gremio santísimo de la Iglesia; los demás cristianos libertados se fueron cada uno donde mejor le pareció; solos quedamos Zoraida y yo, con solos los escudos que la cortesía del francés le dio a Zoraida, de los cuales compré este animal en que ella viene; y, sirviéndola yo hasta agora de padre y escudero, y no de esposo, vamos con intención de ver si mi padre es vivo, o si alguno de mis hermanos ha tenido más próspera ventura que la mía, puesto que, por haberme hecho el cielo compañero de Zoraida, me parece que ninguna otra suerte me pudiera venir, por buena que fuera, que más la estimara. La paciencia con que Zoraida lleva las incomodidades que la pobreza trae consigo, y el deseo que muestra tener de verse ya cristiana es tanto y tal, que me admira y me mueve a servirla todo el tiempo de mi vida, puesto que el gusto que tengo de verme suyo y de que ella sea mía me lo turba y deshace no saber si hallaré en mi tierra algún rincón donde recogella, y si habrán hecho el tiempo y la muerte tal mudanza en la hacienda y vida de mi padre y hermanos que apenas halle quien me conozca, si ellos faltan.» No tengo más, señores, que deciros de mi historia; la cual, si es agradable y peregrina, júzguenlo vuestros buenos entendimientos; que de mí sé decir que quisiera habérosla contado más brevemente, puesto que el temor de enfadaros más de cuatro circustancias me ha quitado de la lengua. Capítulo XLII. Que trata de lo que más sucedió en la venta y de otras muchas cosas dignas de saberse Calló, en diciendo esto, el cautivo, a quien don Fernando dijo: -Por cierto, señor capitán, el modo con que habéis contado este estraño suceso ha sido tal, que iguala a la novedad y estrañeza del mesmo caso. Todo es peregrino y raro, y lleno de accidentes que maravillan y suspenden a quien los oye; y es de tal manera el gusto que hemos recebido en escuchalle, que, aunque nos hallara el día de mañana entretenidos en el mesmo cuento, holgáramos que de nuevo se comenzara. Y, en diciendo esto, don Fernando y todos los demás se le ofrecieron, con todo lo a ellos posible para servirle, con palabras y razones tan amorosas y tan verdaderas que el capitán se tuvo por bien satisfecho de sus voluntades. Especialmente, le ofreció don Fernando que si quería volverse con él, que él haría que el marqués, su hermano, fuese padrino del bautismo de Zoraida, y que él, por su parte, le acomodaría de manera que pudiese entrar en su tierra con el autoridad y cómodo que a su persona se debía. Todo lo agradeció cortesísimamente el cautivo, pero no quiso acetar ninguno de sus liberales ofrecimientos. En esto, llegaba ya la noche, y, al cerrar della, llegó a la venta un coche, con algunos hombres de a caballo. Pidieron posada; a quien la ventera respondió que no había en toda la venta un palmo desocupado. -Pues, aunque eso sea -dijo uno de los de a caballo que habían entrado-, no ha de faltar para el señor oidor que aquí viene. A este nombre se turbó la güéspeda, y dijo: -Señor, lo que en ello hay es que no tengo camas: si es que su merced del señor oidor la trae, que sí debe de traer, entre en buen hora, que yo y mi marido nos saldremos de nuestro aposento por acomodar a su merced. -Sea en buen hora -dijo el escudero. Pero, a este tiempo, ya había salido del coche un hombre, que en el traje mostró luego el oficio y cargo que tenía, porque la ropa luenga, con las mangas arrocadas, que vestía, mostraron ser oidor, como su criado había dicho. Traía de la mano a una doncella, al parecer de hasta diez y seis años, vestida de camino, tan bizarra, tan hermosa y tan gallarda que a todos puso en admiración su vista; de suerte que, a no haber visto a Dorotea y a Luscinda y Zoraida, que en la venta estaban, creyeran que otra tal hermosura como la desta doncella difícilmente pudiera hallarse. Hallóse don Quijote al entrar del oidor y de la doncella, y, así como le vio, dijo: -Seguramente puede vuestra merced entrar y espaciarse en este castillo, que, aunque es estrecho y mal acomodado, no hay estrecheza ni incomodidad en el mundo que no dé lugar a las armas y a las letras, y más si las armas y letras traen por guía y adalid a la fermosura, como la traen las letras de vuestra merced en esta fermosa doncella, a quien deben no sólo abrirse y manifestarse los castillos, sino apartarse los riscos, y devidirse y abajarse las montañas, para dalle acogida. Entre vuestra merced, digo, en este paraíso, que aquí hallará estrellas y soles que acompañen el cielo que vuestra merced trae consigo; aquí hallará las armas en su punto y la hermosura en su estremo. Admirado quedó el oidor del razonamiento de don Quijote, a quien se puso a mirar muy de propósito, y no menos le admiraba su talle que sus palabras; y, sin hallar ningunas con que respondelle, se tornó a admirar de nuevo cuando vio delante de sí a Luscinda, Dorotea y a Zoraida, que, a las nuevas de los nuevos güéspedes y a las que la ventera les había dado de la hermosura de la doncella, habían venido a verla y a recebirla. Pero don Fernando, Cardenio y el cura le hicieron más llanos y más cortesanos ofrecimientos. En efecto, el señor oidor entró confuso, así de lo que veía como de lo que escuchaba, y las hermosas de la venta dieron la bienllegada a la hermosa doncella. En resolución, bien echó de ver el oidor que era gente principal toda la que allí estaba; pero el talle, visaje y la apostura de don Quijote le desatinaba; y, habiendo pasado entre todos corteses ofrecimientos y tanteado la comodidad de la venta, se ordenó lo que antes estaba ordenado: que todas las mujeres se entrasen en el camaranchón ya referido, y que los hombres se quedasen fuera, como en su guarda. Y así, fue contento el oidor que su hija, que era la doncella, se fuese con aquellas señoras, lo que ella hizo de muy buena gana. Y con parte de la estrecha cama del ventero, y con la mitad de la que el oidor traía, se acomodaron aquella noche mejor de lo que pensaban. El cautivo, que, desde el punto que vio al oidor, le dio saltos el corazón y barruntos de que aquél era su hermano, preguntó a uno de los criados que con él venían que cómo se llamaba y si sabía de qué tierra era. El criado le respondió que se llamaba el licenciado Juan Pérez de Viedma, y que había oído decir que era de un lugar de las montañas de León. Con esta relación y con lo que él había visto se acabó de confirmar de que aquél era su hermano, que había seguido las letras por consejo de su padre; y, alborotado y contento, llamando aparte a don Fernando, a Cardenio y al cura, les contó lo que pasaba, certificándoles que aquel oidor era su hermano. Habíale dicho también el criado como iba proveído por oidor a las Indias, en la Audiencia de Méjico. Supo también como aquella doncella era su hija, de cuyo parto había muerto su madre, y que él había quedado muy rico con el dote que con la hija se le quedó en casa. Pidióles consejo qué modo tendría para descubrirse, o para conocer primero si, después de descubierto, su hermano, por verle pobre, se afrentaba o le recebía con buenas entrañas. -Déjeseme a mí el hacer esa experiencia -dijo el cura-; cuanto más, que no hay pensar sino que vos, señor capitán, seréis muy bien recebido; porque el valor y prudencia que en su buen parecer descubre vuestro hermano no da indicios de ser arrogante ni desconocido, ni que no ha de saber poner los casos de la fortuna en su punto. -Con todo eso -dijo el capitán- yo querría, no de improviso, sino por rodeos, dármele a conocer. -Ya os digo -respondió el cura- que yo lo trazaré de modo que todos quedemos satisfechos. Ya, en esto, estaba aderezada la cena, y todos se sentaron a la mesa, eceto el cautivo y las señoras, que cenaron de por sí en su aposento. En la mitad de la cena dijo el cura: -Del mesmo nombre de vuestra merced, señor oidor, tuve yo una camarada en Costantinopla, donde estuve cautivo algunos años; la cual camarada era uno de los valientes soldados y capitanes que había en toda la infantería española, pero tanto cuanto tenía de esforzado y valeroso lo tenía de desdichado. -Y ¿cómo se llamaba ese capitán, señor mío? -preguntó el oidor. -Llamábase -respondió el cura- Ruy Pérez de Viedma, y era natural de un lugar de las montañas de León, el cual me contó un caso que a su padre con sus hermanos le había sucedido, que, a no contármelo un hombre tan verdadero como él, lo tuviera por conseja de aquellas que las viejas cuentan el invierno al fuego. Porque me dijo que su padre había dividido su hacienda entre tres hijos que tenía, y les había dado ciertos consejos, mejores que los de Catón. Y sé yo decir que el que él escogió de venir a la guerra le había sucedido tan bien que en pocos años, por su valor y esfuerzo, sin otro brazo que el de su mucha virtud, subió a ser capitán de infantería, y a verse en camino y predicamento de ser presto maestre de campo. Pero fuele la fortuna contraria, pues donde la pudiera esperar y tener buena, allí la perdió, con perder la libertad en la felicísima jornada donde tantos la cobraron, que fue en la batalla de Lepanto. Yo la perdí en la Goleta, y después, por diferentes sucesos, nos hallamos camaradas en Costantinopla. Desde allí vino a Argel, donde sé que le sucedió uno de los más estraños casos que en el mundo han sucedido. De aquí fue prosiguiendo el cura, y, con brevedad sucinta, contó lo que con Zoraida a su hermano había sucedido; a todo lo cual estaba tan atento el oidor, que ninguna vez había sido tan oidor como entonces. Sólo llegó el cura al punto de cuando los franceses despojaron a los cristianos que en la barca venían, y la pobreza y necesidad en que su camarada y la hermosa mora habían quedado; de los cuales no había sabido en qué habían parado, ni si habían llegado a España, o llevádolos los franceses a Francia. Todo lo que el cura decía estaba escuchando, algo de allí desviado, el capitán, y notaba todos los movimientos que su hermano hacía; el cual, viendo que ya el cura había llegado al fin de su cuento, dando un grande suspiro y llenándosele los ojos de agua, dijo: -¡Oh, señor, si supiésedes las nuevas que me habéis contado, y cómo me tocan tan en parte que me es forzoso dar muestras dello con estas lágrimas que, contra toda mi discreción y recato, me salen por los ojos! Ese capitán tan valeroso que decís es mi mayor hermano, el cual, como más fuerte y de más altos pensamientos que yo ni otro hermano menor mío, escogió el honroso y digno ejercicio de la guerra, que fue uno de los tres caminos que nuestro padre nos propuso, según os dijo vuestra camarada en la conseja que, a vuestro parecer, le oístes. Yo seguí el de las letras, en las cuales Dios y mi diligencia me han puesto en el grado que me veis. Mi menor hermano está en el Pirú, tan rico que con lo que ha enviado a mi padre y a mí ha satisfecho bien la parte que él se llevó, y aun dado a las manos de mi padre con que poder hartar su liberalidad natural; y yo, ansimesmo, he podido con más decencia y autoridad tratarme en mis estudios y llegar al puesto en que me veo. Vive aún mi padre, muriendo con el deseo de saber de su hijo mayor, y pide a Dios con continuas oraciones no cierre la muerte sus ojos hasta que él vea con vida a los de su hijo; del cual me maravillo, siendo tan discreto, cómo en tantos trabajos y afliciones, o prósperos sucesos, se haya descuidado de dar noticia de sí a su padre; que si él lo supiera, o alguno de nosotros, no tuviera necesidad de aguardar al milagro de la caña para alcanzar su rescate. Pero de lo que yo agora me temo es de pensar si aquellos franceses le habrán dado libertad, o le habrán muerto por encubrir su hurto. Esto todo será que yo prosiga mi viaje, no con aquel contento con que le comencé, sino con toda melancolía y tristeza. ¡Oh buen hermano mío, y quién supiera agora dónde estabas; que yo te fuera a buscar y a librar de tus trabajos, aunque fuera a costa de los míos! ¡Oh, quién llevara nuevas a nuestro viejo padre de que tenías vida, aunque estuvieras en las mazmorras más escondidas de Berbería; que de allí te sacaran sus riquezas, las de mi hermano y las mías! ¡Oh Zoraida hermosa y liberal, quién pudiera pagar el bien que a un hermano hiciste!; ¡quién pudiera hallarse al renacer de tu alma, y a las bodas, que tanto gusto a todos nos dieran! Estas y otras semejantes palabras decía el oidor, lleno de tanta compasión con las nuevas que de su hermano le habían dado, que todos los que le oían le acompañaban en dar muestras del sentimiento que tenían de su lástima. Viendo, pues, el cura que tan bien había salido con su intención y con lo que deseaba el capitán, no quiso tenerlos a todos más tiempo tristes, y así, se levantó de la mesa, y, entrando donde estaba Zoraida, la tomó por la mano, y tras ella se vinieron Luscinda, Dorotea y la hija del oidor. Estaba esperando el capitán a ver lo que el cura quería hacer, que fue que, tomándole a él asimesmo de la otra mano, con entrambos a dos se fue donde el oidor y los demás caballeros estaban, y dijo: -Cesen, señor oidor, vuestras lágrimas, y cólmese vuestro deseo de todo el bien que acertare a desearse, pues tenéis delante a vuestro buen hermano y a vuestra buena cuñada. Éste que aquí veis es el capitán Viedma, y ésta, la hermosa mora que tanto bien le hizo. Los franceses que os dije los pusieron en la estrecheza que veis, para que vos mostréis la liberalidad de vuestro buen pecho. Acudió el capitán a abrazar a su hermano, y él le puso ambas manos en los pechos por mirarle algo más apartado; mas, cuando le acabó de conocer, le abrazó tan estrechamente, derramando tan tiernas lágrimas de contento,que los más de los que presentes estaban le hubieron de acompañar en ellas. Las palabras que entrambos hermanos se dijeron, los sentimientos que mostraron, apenas creo que pueden pensarse, cuanto más escribirse. Allí, en breves razones, se dieron cuenta de sus sucesos; allí mostraron puesta en su punto la buena amistad de dos hermanos; allí abrazó el oidor a Zoraida; allí la ofreció su hacienda; allí hizo que la abrazase su hija; allí la cristiana hermosa y la mora hermosísima renovaron las lágrimas de todos. Allí don Quijote estaba atento, sin hablar palabra, considerando estos tan estraños sucesos, atribuyéndolos todos a quimeras de la andante caballería. Allí concertaron que el capitán y Zoraida se volviesen con su hermano a Sevilla y avisasen a su padre de su hallazgo y libertad, para que, como pudiese, viniese a hallarse en las bodas y bautismo de Zoraida, por no le ser al oidor posible dejar el camino que llevaba, a causa de tener nuevas que de allí a un mes partía la flota de Sevilla a la Nueva España, y fuérale de grande incomodidad perder el viaje. En resolución, todos quedaron contentos y alegres del buen suceso del cautivo; y, como ya la noche iba casi en las dos partes de su jornada, acordaron de recogerse y reposar lo que de ella les quedaba. Don Quijote se ofreció a hacer la guardia del castillo, porque de algún gigante o otro mal andante follón no fuesen acometidos, codiciosos del gran tesoro de hermosura que en aquel castillo se encerraba. Agradeciéronselo los que le conocían, y dieron al oidor cuenta del humor estraño de don Quijote, de que no poco gusto recibió. Sólo Sancho Panza se desesperaba con la tardanza del recogimiento, y sólo él se acomodó mejor que todos, echándose sobre los aparejos de su jumento, que le costaron tan caros como adelante se dirá. Recogidas, pues, las damas en su estancia, y los demás acomodádose como menos mal pudieron, don Quijote se salió fuera de la venta a hacer la centinela del castillo, como lo había prometido. Sucedió, pues, que faltando poco por venir el alba, llegó a los oídos de las damas una voz tan entonada y tan buena, que les obligó a que todas le prestasen atento oído, especialmente Dorotea, que despierta estaba, a cuyo lado dormía doña Clara de Viedma, que ansí se llamaba la hija del oidor. Nadie podía imaginar quién era la persona que tan bien cantaba, y era una voz sola, sin que la acompañase instrumento alguno. Unas veces les parecía que cantaban en el patio; otras, que en la caballeriza; y, estando en esta confusión muy atentas, llegó a la puerta del aposento Cardenio y dijo: -Quien no duerme, escuche; que oirán una voz de un mozo de mulas, que de tal manera canta que encanta. -Ya lo oímos, señor -respondió Dorotea. Y, con esto, se fue Cardenio; y Dorotea, poniendo toda la atención posible, entendió que lo que se cantaba era esto: Capítulo XLIII. Donde se cuenta la agradable historia del mozo de mulas, con otros estraños acaecimientos en la venta sucedidos] -Marinero soy de amor, y en su piélago profundo navego sin esperanza de llegar a puerto alguno. Siguiendo voy a una estrella que desde lejos descubro, más bella y resplandeciente que cuantas vio Palinuro. Yo no sé adónde me guía, y así, navego confuso, el alma a mirarla atenta, cuidadosa y con descuido. Recatos impertinentes, honestidad contra el uso, son nubes que me la encubren cuando más verla procuro. ¡Oh clara y luciente estrella, en cuya lumbre me apuro!; al punto que te me encubras, será de mi muerte el punto. Llegando el que cantaba a este punto, le pareció a Dorotea que no sería bien que dejase Clara de oír una tan buena voz; y así, moviéndola a una y a otra parte, la despertó diciéndole: -Perdóname, niña, que te despierto, pues lo hago porque gustes de oír la mejor voz que quizá habrás oído en toda tu vida. Clara despertó toda soñolienta, y de la primera vez no entendió lo que Dorotea le decía; y, volviéndoselo a preguntar, ella se lo volvió a decir, por lo cual estuvo atenta Clara. Pero, apenas hubo oído dos versos que el que cantaba iba prosiguiendo, cuando le tomó un temblor tan estraño como si de algún grave accidente de cuartana estuviera enferma, y, abrazándose estrechamente con Teodora, le dijo: -¡Ay señora de mi alma y de mi vida!, ¿para qué me despertastes?; que el mayor bien que la fortuna me podía hacer por ahora era tenerme cerrados los ojos y los oídos, para no ver ni oír a ese desdichado músico. -¿Qué es lo que dices, niña?; mira que dicen que el que canta es un mozo de mulas. -No es sino señor de lugares -respondió Clara-, y el que le tiene en mi alma con tanta seguridad que si él no quiere dejalle, no le será quitado eternamente. Admirada quedó Dorotea de las sentidas razones de la muchacha, pareciéndole que se aventajaban en mucho a la discreción que sus pocos años prometían; y así, le dijo: -Habláis de modo, señora Clara, que no puedo entenderos: declaraos más y decidme qué es lo que decís de alma y de lugares, y deste músico, cuya voz tan inquieta os tiene. Pero no me digáis nada por ahora, que no quiero perder, por acudir a vuestro sobresalto, el gusto que recibo de oír al que canta; que me parece que con nuevos versos y nuevo tono torna a su canto. -Sea en buen hora -respondió Clara. Y, por no oílle, se tapó con las manos entrambos oídos, de lo que también se admiró Dorotea; la cual, estando atenta a lo que se cantaba, vio que proseguían en esta manera: -Dulce esperanza mía, que, rompiendo imposibles y malezas, sigues firme la vía que tú mesma te finges y aderezas: no te desmaye el verte a cada paso junto al de tu muerte. No alcanzan perezosos honrados triunfos ni vitoria alguna, ni pueden ser dichosos los que, no contrastando a la fortuna, entregan, desvalidos, al ocio blando todos los sentidos. Que amor sus glorias venda caras, es gran razón, y es trato justo, pues no hay más rica prenda que la que se quilata por su gusto; y es cosa manifiesta que no es de estima lo que poco cuesta. Amorosas porfías tal vez alcanzan imposibles cosas; y ansí, aunque con las mías sigo de amor las más dificultosas, no por eso recelo de no alcanzar desde la tierra el cielo. Aquí dio fin la voz, y principio a nuevos sollozos Clara. Todo lo cual encendía el deseo de Dorotea, que deseaba saber la causa de tan suave canto y de tan triste lloro. Y así, le volvió a preguntar qué era lo que le quería decir denantes. Entonces Clara, temerosa de que Luscinda no la oyese, abrazando estrechamente a Dorotea, puso su boca tan junto del oído de Dorotea, que seguramente podía hablar sin ser de otro sentida, y así le dijo: -Este que canta, señora mía, es un hijo de un caballero natural del reino de Aragón, señor de dos lugares, el cual vivía frontero de la casa de mi padre en la Corte; y, aunque mi padre tenía las ventanas de su casa con lienzos en el invierno y celosías en el verano, yo no sé lo que fue, ni lo que no, que este caballero, que andaba al estudio, me vio, ni sé si en la iglesia o en otra parte. Finalmente, él se enamoró de mí, y me lo dio a entender desde las ventanas de su casa con tantas señas y con tantas lágrimas, que yo le hube de creer, y aun querer, sin saber lo que me quería. Entre las señas que me hacía, era una de juntarse la una mano con la otra, dándome a entender que se casaría conmigo; y, aunque yo me holgaría mucho de que ansí fuera, como sola y sin madre, no sabía con quién comunicallo, y así, lo dejé estar sin dalle otro favor si no era, cuando estaba mi padre fuera de casa y el suyo también, alzar un poco el lienzo o la celosía y dejarme ver toda, de lo que él hacía tanta fiesta, que daba señales de volverse loco. Llegóse en esto el tiempo de la partida de mi padre, la cual él supo, y no de mí, pues nunca pude decírselo. Cayó malo, a lo que yo entiendo, de pesadumbre; y así, el día que nos partimos nunca pude verle para despedirme dél, siquiera con los ojos. Pero, a cabo de dos días que caminábamos, al entrar de una posada, en un lugar una jornada de aquí, le vi a la puerta del mesón, puesto en hábito de mozo de mulas, tan al natural que si yo no le trujera tan retratado en mi alma fuera imposible conocelle. Conocíle, admiréme y alegréme; él me miró a hurto de mi padre, de quien él siempre se esconde cuando atraviesa por delante de mí en los caminos y en las posadas do llegamos; y, como yo sé quién es, y considero que por amor de mí viene a pie y con tanto trabajo, muérome de pesadumbre, y adonde él pone los pies pongo yo los ojos. No sé con qué intención viene, ni cómo ha podido escaparse de su padre, que le quiere estraordinariamente, porque no tiene otro heredero, y porque él lo merece, como lo verá vuestra merced cuando le vea. Y más le sé decir: que todo aquello que canta lo saca de su cabeza; que he oído decir que es muy gran estudiante y poeta. Y hay más: que cada vez que le veo o le oigo cantar, tiemblo toda y me sobresalto, temerosa de que mi padre le conozca y venga en conocimiento de nuestros deseos. En mi vida le he hablado palabra, y, con todo eso, le quiero de manera que no he de poder vivir sin él. Esto es, señora mía, todo lo que os puedo decir deste músico, cuya voz tanto os ha contentado; que en sola ella echaréis bien de ver que no es mozo de mulas, como decís, sino señor de almas y lugares, como yo os he dicho. -No digáis más, señora doña Clara -dijo a esta sazón Dorotea, y esto, besándola mil veces-; no digáis más, digo, y esperad que venga el nuevo día, que yo espero en Dios de encaminar de manera vuestros negocios, que tengan el felice fin que tan honestos principios merecen. -¡Ay señora! -dijo doña Clara-, ¿qué fin se puede esperar, si su padre es tan principal y tan rico que le parecerá que aun yo no puedo ser criada de su hijo, cuanto más esposa? Pues casarme yo a hurto de mi padre, no lo haré por cuanto hay en el mundo. No querría sino que este mozo se volviese y me dejase; quizá con no velle y con la gran distancia del camino que llevamos se me aliviaría la pena que ahora llevo, aunque sé decir que este remedio que me imagino me ha de aprovechar bien poco. No sé qué diablos ha sido esto, ni por dónde se ha entrado este amor que le tengo, siendo yo tan muchacha y él tan muchacho, que en verdad que creo que somos de una edad mesma, y que yo no tengo cumplidos diez y seis años; que para el día de San Miguel que vendrá dice mi padre que los cumplo. No pudo dejar de reírse Dorotea, oyendo cuán como niña hablaba doña Clara, a quien dijo: -Reposemos, señora, lo poco que creo queda de la noche, y amanecerá Dios y medraremos, o mal me andarán las manos. Sosegáronse con esto, y en toda la venta se guardaba un grande silencio; solamente no dormían la hija de la ventera y Maritornes, su criada, las cuales, como ya sabían el humor de que pecaba don Quijote, y que estaba fuera de la venta armado y a caballo haciendo la guarda, determinaron las dos de hacelle alguna burla, o, a lo menos, de pasar un poco el tiempo oyéndole sus disparates. Es, pues, el caso que en toda la venta no había ventana que saliese al campo, sino un agujero de un pajar, por donde echaban la paja por defuera. A este agujero se pusieron las dos semidoncellas, y vieron que don Quijote estaba a caballo, recostado sobre su lanzón, dando de cuando en cuando tan dolientes y profundos suspiros que parecía, que con cada uno se le arrancaba el alma. Y asimesmo oyeron que decía con voz blanda, regalada y amorosa: -¡Oh mi señora Dulcinea del Toboso, estremo de toda hermosura, fin y remate de la discreción, archivo del mejor donaire, depósito de la honestidad, y, ultimadamente, idea de todo lo provechoso, honesto y deleitable que hay en el mundo! Y ¿qué fará agora la tu merced? ¿Si tendrás por ventura las mientes en tu cautivo caballero, que a tantos peligros, por sólo servirte, de su voluntad ha querido ponerse? Dame tú nuevas della, ¡oh luminaria de las tres caras! Quizá con envidia de la suya la estás ahora mirando; que, o paseándose por alguna galería de sus suntuosos palacios, o ya puesta de pechos sobre algún balcón, está considerando cómo, salva su honestidad y grandeza, ha de amansar la tormenta que por ella este mi cuitado corazón padece, qué gloria ha de dar a mis penas, qué sosiego a mi cuidado y, finalmente, qué vida a mi muerte y qué premio a mis servicios. Y tú, sol, que ya debes de estar apriesa ensillando tus caballos, por madrugar y salir a ver a mi señora, así como la veas, suplícote que de mi parte la saludes; pero guárdate que al verla y saludarla no le des paz en el rostro, que tendré más celos de ti que tú los tuviste de aquella ligera ingrata que tanto te hizo sudar y correr por los llanos de Tesalia, o por las riberas de Peneo, que no me acuerdo bien por dónde corriste entonces celoso y enamorado. A este punto llegaba entonces don Quijote en su tan lastimero razonamiento, cuando la hija de la ventera le comenzó a cecear y a decirle: -Señor mío, lléguese acá la vuestra merced si es servido. A cuyas señas y voz volvió don Quijote la cabeza, y vio, a la luz de la luna, que entonces estaba en toda su claridad, cómo le llamaban del agujero que a él le pareció ventana, y aun con rejas doradas, como conviene que las tengan tan ricos castillos como él se imaginaba que era aquella venta; y luego en el instante se le representó en su loca imaginación que otra vez, como la pasada, la doncella fermosa, hija de la señora de aquel castillo, vencida de su amor, tornaba a solicitarle; y con este pensamiento, por no mostrarse descortés y desagradecido, volvió las riendas a Rocinante y se llegó al agujero, y, así como vio a las dos mozas, dijo: -Lástima os tengo, fermosa señora, de que hayades puesto vuestras amorosas mientes en parte donde no es posible corresponderos conforme merece vuestro gran valor y gentileza; de lo que no debéis dar culpa a este miserable andante caballero, a quien tiene amor imposibilitado de poder entregar su voluntad a otra que aquella que, en el punto que sus ojos la vieron, la hizo señora absoluta de su alma. Perdonadme, buena señora, y recogeos en vuestro aposento, y no queráis, con significarme más vuestros deseos, que yo me muestre más desagradecido; y si del amor que me tenéis halláis en mí otra cosa con que satisfaceros, que el mismo amor no sea, pedídmela; que yo os juro, por aquella ausente enemiga dulce mía, de dárosla en continente, si bien me pidiésedes una guedeja de los cabellos de Medusa, que eran todos culebras, o ya los mesmos rayos del sol encerrados en una redoma. -No ha menester nada deso mi señora, señor caballero -dijo a este punto Maritornes. -Pues, ¿qué ha menester, discreta dueña, vuestra señora? -respondió don Quijote. -Sola una de vuestras hermosas manos -dijo Maritornes-, por poder deshogar con ella el gran deseo que a este agujero la ha traído, tan a peligro de su honor que si su señor padre la hubiera sentido, la menor tajada della fuera la oreja. -¡Ya quisiera yo ver eso! -respondió don Quijote-; pero él se guardará bien deso, si ya no quiere hacer el más desastrado fin que padre hizo en el mundo, por haber puesto las manos en los delicados miembros de su enamorada hija. Parecióle a Maritornes que sin duda don Quijote daría la mano que le habían pedido, y, proponiendo en su pensamiento lo que había de hacer, se bajó del agujero y se fue a la caballeriza, donde tomó el cabestro del jumento de Sancho Panza, y con mucha presteza se volvió a su agujero, a tiempo que don Quijote se había puesto de pies sobre la silla de Rocinante, por alcanzar a la ventana enrejada, donde se imaginaba estar la ferida doncella; y, al darle la mano, dijo: -Tomad, señora, esa mano, o, por mejor decir, ese verdugo de los malhechores del mundo; tomad esa mano, digo, a quien no ha tocado otra de mujer alguna, ni aun la de aquella que tiene entera posesión de todo mi cuerpo. No os la doy para que la beséis, sino para que miréis la contestura de sus nervios, la trabazón de sus músculos, la anchura y espaciosidad de sus venas; de donde sacaréis qué tal debe de ser la fuerza del brazo que tal mano tiene. -Ahora lo veremos -dijo Maritornes. Y, haciendo una lazada corrediza al cabestro, se la echó a la muñeca, y, bajándose del agujero, ató lo que quedaba al cerrojo de la puerta del pajar muy fuertemente. Don Quijote, que sintió la aspereza del cordel en su muñeca, dijo: -Más parece que vuestra merced me ralla que no que me regala la mano; no la tratéis tan mal, pues ella no tiene la culpa del mal que mi voluntad os hace, ni es bien que en tan poca parte venguéis el todo de vuestro enojo. Mirad que quien quiere bien no se venga tan mal. Pero todas estas razones de don Quijote ya no las escuchaba nadie, porque, así como Maritornes le ató, ella y la otra se fueron, muertas de risa, y le dejaron asido de manera que fue imposible soltarse. Estaba, pues, como se ha dicho, de pies sobre Rocinante, metido todo el brazo por el agujero y atado de la muñeca, y al cerrojo de la puerta, con grandísimo temor y cuidado, que si Rocinante se desviaba a un cabo o a otro, había de quedar colgado del brazo; y así, no osaba hacer movimiento alguno, puesto que de la paciencia y quietud de Rocinante bien se podía esperar que estaría sin moverse un siglo entero. En resolución, viéndose don Quijote atado, y que ya las damas se habían ido, se dio a imaginar que todo aquello se hacía por vía de encantamento, como la vez pasada, cuando en aquel mesmo castillo le molió aquel moro encantado del arriero; y maldecía entre sí su poca discreción y discurso, pues, habiendo salido tan mal la vez primera de aquel castillo, se había aventurado a entrar en él la segunda, siendo advertimiento de caballeros andantes que, cuando han probado una aventura y no salido bien con ella, es señal que no está para ellos guardada, sino para otros; y así, no tienen necesidad de probarla segunda vez. Con todo esto, tiraba de su brazo, por ver si podía soltarse; mas él estaba tan bien asido, que todas sus pruebas fueron en vano. Bien es verdad que tiraba con tiento, porque Rocinante no se moviese; y, aunque él quisiera sentarse y ponerse en la silla, no podía sino estar en pie, o arrancarse la mano. Allí fue el desear de la espada de Amadís, contra quien no tenía fuerza de encantamento alguno; allí fue el maldecir de su fortuna; allí fue el exagerar la falta que haría en el mundo su presencia el tiempo que allí estuviese encantado, que sin duda alguna se había creído que lo estaba; allí el acordarse de nuevo de su querida Dulcinea del Toboso; allí fue el llamar a su buen escudero Sancho Panza, que, sepultado en sueño y tendido sobre el albarda de su jumento, no se acordaba en aquel instante de la madre que lo había parido; allí llamó a los sabios Lirgandeo y Alquife, que le ayudasen; allí invocó a su buena amiga Urganda, que le socorriese, y, finalmente, allí le tomó la mañana, tan desesperado y confuso que bramaba como un toro; porque no esperaba él que con el día se remediara su cuita, porque la tenía por eterna, teniéndose por encantado. Y hacíale creer esto ver que Rocinante poco ni mucho se movía, y creía que de aquella suerte, sin comer ni beber ni dormir, habían de estar él y su caballo, hasta que aquel mal influjo de las estrellas se pasase, o hasta que otro más sabio encantador le desencantase. Pero engañóse mucho en su creencia, porque, apenas comenzó a amanecer, cuando llegaron a la venta cuatro hombres de a caballo, muy bien puestos y aderezados, con sus escopetas sobre los arzones. Llamaron a la puerta de la venta, que aún estaba cerrada, con grandes golpes; lo cual, visto por don Quijote desde donde aún no dejaba de hacer la centinela, con voz arrogante y alta dijo: -Caballeros, o escuderos, o quienquiera que seáis: no tenéis para qué llamar a las puertas deste castillo; que asaz de claro está que a tales horas, o los que están dentro duermen, o no tienen por costumbre de abrirse las fortalezas hasta que el sol esté tendido por todo el suelo. Desviaos afuera, y esperad que aclare el día, y entonces veremos si será justo o no que os abran. -¿Qué diablos de fortaleza o castillo es éste -dijo uno-, para obligarnos a guardar esas ceremonias? Si sois el ventero, mandad que nos abran, que somos caminantes que no queremos más de dar cebada a nuestras cabalgaduras y pasar adelante, porque vamos de priesa. -¿Paréceos, caballeros, que tengo yo talle de ventero? -respondió don Quijote. -No sé de qué tenéis talle -respondió el otro-, pero sé que decís disparates en llamar castillo a esta venta. -Castillo es -replicó don Quijote-, y aun de los mejores de toda esta provincia; y gente tiene dentro que ha tenido cetro en la mano y corona en la cabeza. -Mejor fuera al revés -dijo el caminante-: el cetro en la cabeza y la corona en la mano. Y será, si a mano viene, que debe de estar dentro alguna compañía de representantes, de los cuales es tener a menudo esas coronas y cetros que decís, porque en una venta tan pequeña, y adonde se guarda tanto silencio como ésta, no creo yo que se alojan personas dignas de corona y cetro. -Sabéis poco del mundo -replicó don Quijote-, pues ignoráis los casos que suelen acontecer en la caballería andante. Cansábanse los compañeros que con el preguntante venían del coloquio que con don Quijote pasaba, y así, tornaron a llamar con grande furia; y fue de modo que el ventero despertó, y aun todos cuantos en la venta estaban; y así, se levantó a preguntar quién llamaba. Sucedió en este tiempo que una de las cabalgaduras en que venían los cuatro que llamaban se llegó a oler a Rocinante, que, melancólico y triste, con las orejas caídas, sostenía sin moverse a su estirado señor; y como, en fin, era de carne, aunque parecía de leño, no pudo dejar de resentirse y tornar a oler a quien le llegaba a hacer caricias; y así, no se hubo movido tanto cuanto, cuando se desviaron los juntos pies de don Quijote, y, resbalando de la silla, dieran con él en el suelo, a no quedar colgado del brazo: cosa que le causó tanto dolor que creyó o que la muñeca le cortaban, o que el brazo se le arrancaba; porque él quedó tan cerca del suelo que con los estremos de las puntas de los pies besaba la tierra, que era en su perjuicio, porque, como sentía lo poco que le faltaba para poner las plantas en la tierra, fatigábase y estirábase cuanto podía por alcanzar al suelo: bien así como los que están en el tormento de la garrucha, puestos a toca, no toca, que ellos mesmos son causa de acrecentar su dolor, con el ahínco que ponen en estirarse, engañados de la esperanza que se les representa, que con poco más que se estiren llegarán al suelo. Capítulo XLIV. Donde se prosiguen los inauditos sucesos de la venta En efeto, fueron tantas las voces que don Quijote dio, que, abriendo de presto las puertas de la venta, salió el ventero, despavorido, a ver quién tales gritos daba, y los que estaban fuera hicieron lo mesmo. Maritornes, que ya había despertado a las mismas voces, imaginando lo que podía ser, se fue al pajar y desató, sin que nadie lo viese, el cabestro que a don Quijote sostenía, y él dio luego en el suelo, a vista del ventero y de los caminantes, que, llegándose a él, le preguntaron qué tenía, que tales voces daba. Él, sin responder palabra, se quitó el cordel de la muñeca, y, levantándose en pie, subió sobre Rocinante, embrazó su adarga, enristró su lanzón, y, tomando buena parte del campo, volvió a medio galope, diciendo: -Cualquiera que dijere que yo he sido con justo título encantado, como mi señora la princesa Micomicona me dé licencia para ello, yo le desmiento, le rieto y desafío a singular batalla. Admirados se quedaron los nuevos caminantes de las palabras de don Quijote, pero el ventero les quitó de aquella admiración, diciéndoles que era don Quijote, y que no había que hacer caso dél, porque estaba fuera de juicio. Preguntáronle al ventero si acaso había llegado a aquella venta un muchacho de hasta edad de quince años, que venía vestido como mozo de mulas, de tales y tales señas, dando las mesmas que traía el amante de doña Clara. El ventero respondió que había tanta gente en la venta, que no había echado de ver en el que preguntaban. Pero, habiendo visto uno dellos el coche donde había venido el oidor, dijo: -Aquí debe de estar sin duda, porque éste es el coche que él dicen que sigue; quédese uno de nosotros a la puerta y entren los demás a buscarle; y aun sería bien que uno de nosotros rodease toda la venta, porque no se fuese por las bardas de los corrales. -Así se hará -respondió uno dellos. Y, entrándose los dos dentro, uno se quedó a la puerta y el otro se fue a rodear la venta; todo lo cual veía el ventero, y no sabía atinar para qué se hacían aquellas diligencias, puesto que bien creyó que buscaban aquel mozo cuyas señas le habían dado. Ya a esta sazón aclaraba el día; y, así por esto como por el ruido que don Quijote había hecho, estaban todos despiertos y se levantaban, especialmente doña Clara y Dorotea, que la una con sobresalto de tener tan cerca a su amante, y la otra con el deseo de verle, habían podido dormir bien mal aquella noche. Don Quijote, que vio que ninguno de los cuatro caminantes hacía caso dél, ni le respondían a su demanda, moría y rabiaba de despecho y saña; y si él hallara en las ordenanzas de su caballería que lícitamente podía el caballero andante tomar y emprender otra empresa, habiendo dado su palabra y fe de no ponerse en ninguna hasta acabar la que había prometido, él embistiera con todos, y les hiciera responder mal de su grado. Pero, por parecerle no convenirle ni estarle bien comenzar nueva empresa hasta poner a Micomicona en su reino, hubo de callar y estarse quedo, esperando a ver en qué paraban las diligencias de aquellos caminantes; uno de los cuales halló al mancebo que buscaba, durmiendo al lado de un mozo de mulas, bien descuidado de que nadie ni le buscase, ni menos de que le hallase. El hombre le trabó del brazo y le dijo: -Por cierto, señor don Luis, que responde bien a quien vos sois el hábito que tenéis, y que dice bien la cama en que os hallo al regalo con que vuestra madre os crió. Limpióse el mozo los soñolientos ojos y miró de espacio al que le tenía asido, y luego conoció que era criado de su padre, de que recibió tal sobresalto, que no acertó o no pudo hablarle palabra por un buen espacio. Y el criado prosiguió diciendo: -Aquí no hay que hacer otra cosa, señor don Luis, sino prestar paciencia y dar la vuelta a casa, si ya vuestra merced no gusta que su padre y mi señor la dé al otro mundo, porque no se puede esperar otra cosa de la pena con que queda por vuestra ausencia. -Pues, ¿cómo supo mi padre -dijo don Luis- que yo venía este camino y en este traje? -Un estudiante -respondió el criado- a quien distes cuenta de vuestros pensamientos fue el que lo descubrió, movido a lástima de las que vio que hacía vuestro padre al punto que os echó de menos; y así, despachó a cuatro de sus criados en vuestra busca, y todos estamos aquí a vuestro servicio, más contentos de lo que imaginar se puede, por el buen despacho con que tornaremos, llevándoos a los ojos que tanto os quieren. -Eso será como yo quisiere, o como el cielo lo ordenare -respondió don Luis. -¿Qué habéis de querer, o qué ha de ordenar el cielo, fuera de consentir en volveros?; porque no ha de ser posible otra cosa. Todas estas razones que entre los dos pasaban oyó el mozo de mulas junto a quien don Luis estaba; y, levantándose de allí, fue a decir lo que pasaba a don Fernando y a Cardenio, y a los demás, que ya vestido se habían; a los cuales dijo cómo aquel hombre llamaba de don a aquel muchacho, y las razones que pasaban, y cómo le quería volver a casa de su padre, y el mozo no quería. Y con esto, y con lo que dél sabían de la buena voz que el cielo le había dado, vinieron todos en gran deseo de saber más particularmente quién era, y aun de ayudarle si alguna fuerza le quisiesen hacer; y así, se fueron hacia la parte donde aún estaba hablando y porfiando con su criado. Salía en esto Dorotea de su aposento, y tras ella doña Clara, toda turbada; y, llamando Dorotea a Cardenio aparte, le contó en breves razones la historia del músico y de doña Clara, a quien él también dijo lo que pasaba de la venida a buscarle los criados de su padre, y no se lo dijo tan callando que lo dejase de oír Clara; de lo que quedó tan fuera de sí que, si Dorotea no llegara a tenerla, diera consigo en el suelo. Cardenio dijo a Dorotea que se volviesen al aposento, que él procuraría poner remedio en todo, y ellas lo hicieron. Ya estaban todos los cuatro que venían a buscar a don Luis dentro de la venta y rodeados dél, persuadiéndole que luego, sin detenerse un punto, volviese a consolar a su padre. Él respondió que en ninguna manera lo podía hacer hasta dar fin a un negocio en que le iba la vida, la honra y el alma. Apretáronle entonces los criados, diciéndole que en ningún modo volverían sin él, y que le llevarían, quisiese o no quisiese. -Eso no haréis vosotros -replicó don Luis-, si no es llevándome muerto; aunque, de cualquiera manera que me llevéis, será llevarme sin vida. Ya a esta sazón habían acudido a la porfía todos los más que en la venta estaban, especialmente Cardenio, don Fernando, sus camaradas, el oidor, el cura, el barbero y don Quijote, que ya le pareció que no había necesidad de guardar más el castillo. Cardenio, como ya sabía la historia del mozo, preguntó a los que llevarle querían que qué les movía a querer llevar contra su voluntad aquel muchacho. -Muévenos -respondió uno de los cuatro- dar la vida a su padre, que por la ausencia deste caballero queda a peligro de perderla. A esto dijo don Luis: -No hay para qué se dé cuenta aquí de mis cosas: yo soy libre, y volveré si me diere gusto, y si no, ninguno de vosotros me ha de hacer fuerza. -Harásela a vuestra merced la razón -respondió el hombre-; y, cuando ella no bastare con vuestra merced, bastará con nosotros para hacer a lo que venimos y lo que somos obligados. -Sepamos qué es esto de raíz -dijo a este tiempo el oidor. Pero el hombre, que lo conoció, como vecino de su casa, respondió: -¿No conoce vuestra merced, señor oidor, a este caballero, que es el hijo de su vecino, el cual se ha ausentado de casa de su padre en el hábito tan indecente a su calidad como vuestra merced puede ver? Miróle entonces el oidor más atentamente y conocióle; y, abrazándole, dijo: -¿Qué niñerías son éstas, señor don Luis, o qué causas tan poderosas, que os hayan movido a venir desta manera, y en este traje, que dice tan mal con la calidad vuestra? Al mozo se le vinieron las lágrimas a los ojos, y no pudo responder palabra. El oidor dijo a los cuatro que se sosegasen, que todo se haría bien; y, tomando por la mano a don Luis, le apartó a una parte y le preguntó qué venida había sido aquélla. Y, en tanto que le hacía esta y otras preguntas, oyeron grandes voces a la puerta de la venta, y era la causa dellas que dos huéspedes que aquella noche habían alojado en ella, viendo a toda la gente ocupada en saber lo que los cuatro buscaban, habían intentado a irse sin pagar lo que debían; mas el ventero, que atendía más a su negocio que a los ajenos, les asió al salir de la puerta y pidió su paga, y les afeó su mala intención con tales palabras, que les movió a que le respondiesen con los puños; y así, le comenzaron a dar tal mano, que el pobre ventero tuvo necesidad de dar voces y pedir socorro. La ventera y su hija no vieron a otro más desocupado para poder socorrerle que a don Quijote, a quien la hija de la ventera dijo: -Socorra vuestra merced, señor caballero, por la virtud que Dios le dio, a mi pobre padre, que dos malos hombres le están moliendo como a cibera. A lo cual respondió don Quijote, muy de espacio y con mucha flema: -Fermosa doncella, no ha lugar por ahora vuestra petición, porque estoy impedido de entremeterme en otra aventura en tanto que no diere cima a una en que mi palabra me ha puesto. Mas lo que yo podré hacer por serviros es lo que ahora diré: corred y decid a vuestro padre que se entretenga en esa batalla lo mejor que pudiere, y que no se deje vencer en ningún modo, en tanto que yo pido licencia a la princesa Micomicona para poder socorrerle en su cuita; que si ella me la da, tened por cierto que yo le sacaré della. -¡Pecadora de mí! -dijo a esto Maritornes, que estaba delante-: primero que vuestra merced alcance esa licencia que dice, estará ya mi señor en el otro mundo. -Dadme vos, señora, que yo alcance la licencia que digo -respondió don Quijote-; que, como yo la tenga, poco hará al caso que él esté en el otro mundo; que de allí le sacaré a pesar del mismo mundo que lo contradiga; o, por lo menos, os daré tal venganza de los que allá le hubieren enviado, que quedéis más que medianamente satisfechas. Y sin decir más se fue a poner de hinojos ante Dorotea, pidiéndole con palabras caballerescas y andantescas que la su grandeza fuese servida de darle licencia de acorrer y socorrer al castellano de aquel castillo, que estaba puesto en una grave mengua. La princesa se la dio de buen talante, y él luego, embrazando su adarga y poniendo mano a su espada, acudió a la puerta de la venta, adonde aún todavía traían los dos huéspedes a mal traer al ventero; pero, así como llegó, embazó y se estuvo quedo, aunque Maritornes y la ventera le decían que en qué se detenía, que socorriese a su señor y marido. -Deténgome -dijo don Quijote- porque no me es lícito poner mano a la espada contra gente escuderil; pero llamadme aquí a mi escudero Sancho, que a él toca y atañe esta defensa y venganza. Esto pasaba en la puerta de la venta, y en ella andaban las puñadas y mojicones muy en su punto, todo en daño del ventero y en rabia de Maritornes, la ventera y su hija, que se desesperaban de ver la cobardía de don Quijote, y de lo mal que lo pasaba su marido, señor y padre. Pero dejémosle aquí, que no faltará quien le socorra, o si no, sufra y calle el que se atreve a más de a lo que sus fuerzas le prometen, y volvámonos atrás cincuenta pasos, a ver qué fue lo que don Luis respondió al oidor, que le dejamos aparte, preguntándole la causa de su venida a pie y de tan vil traje vestido. A lo cual el mozo, asiéndole fuertemente de las manos, como en señal de que algún gran dolor le apretaba el corazón, y derramando lágrimas en grande abundancia, le dijo: -Señor mío, yo no sé deciros otra cosa sino que desde el punto que quiso el cielo y facilitó nuestra vecindad que yo viese a mi señora doña Clara, hija vuestra y señora mía, desde aquel instante la hice dueño de mi voluntad; y si la vuestra, verdadero señor y padre mío, no lo impide, en este mesmo día ha de ser mi esposa. Por ella dejé la casa de mi padre, y por ella me puse en este traje, para seguirla dondequiera que fuese, como la saeta al blanco, o como el marinero al norte. Ella no sabe de mis deseos más de lo que ha podido entender de algunas veces que desde lejos ha visto llorar mis ojos. Ya, señor, sabéis la riqueza y la nobleza de mis padres, y como yo soy su único heredero: si os parece que éstas son partes para que os aventuréis a hacerme en todo venturoso, recebidme luego por vuestro hijo; que si mi padre, llevado de otros disignios suyos, no gustare deste bien que yo supe buscarme, más fuerza tiene el tiempo para deshacer y mudar las cosas que las humanas voluntades. Calló, en diciendo esto, el enamorado mancebo, y el oidor quedó en oírle suspenso, confuso y admirado, así de haber oído el modo y la discreción con que don Luis le había descubierto su pensamiento, como de verse en punto que no sabía el que poder tomar en tan repentino y no esperado negocio; y así, no respondió otra cosa sino que se sosegase por entonces, y entretuviese a sus criados, que por aquel día no le volviesen, porque se tuviese tiempo para considerar lo que mejor a todos estuviese. Besóle las manos por fuerza don Luis, y aun se las bañó con lágrimas, cosa que pudiera enternecer un corazón de mármol, no sólo el del oidor, que, como discreto, ya había conocido cuán bien le estaba a su hija aquel matrimonio; puesto que, si fuera posible, lo quisiera efetuar con voluntad del padre de don Luis, del cual sabía que pretendía hacer de título a su hijo. Ya a esta sazón estaban en paz los huéspedes con el ventero, pues, por persuasión y buenas razones de don Quijote, más que por amenazas, le habían pagado todo lo que él quiso, y los criados de don Luis aguardaban el fin de la plática del oidor y la resolución de su amo, cuando el demonio, que no duerme, ordenó que en aquel mesmo punto entró en la venta el barbero a quien don Quijote quitó el yelmo de Mambrino y Sancho Panza los aparejos del asno, que trocó con los del suyo; el cual barbero, llevando su jumento a la caballeriza, vio a Sancho Panza que estaba aderezando no sé qué de la albarda, y así como la vio la conoció, y se atrevió a arremeter a Sancho, diciendo: -¡Ah don ladrón, que aquí os tengo! ¡Venga mi bacía y mi albarda, con todos mis aparejos que me robastes! Sancho, que se vio acometer tan de improviso y oyó los vituperios que le decían, con la una mano asió de la albarda, y con la otra dio un mojicón al barbero que le bañó los dientes en sangre; pero no por esto dejó el barbero la presa que tenía hecha en el albarda; antes, alzó la voz de tal manera que todos los de la venta acudieron al ruido y pendencia, y decía: -¡Aquí del rey y de la justicia, que, sobre cobrar mi hacienda, me quiere matar este ladrón salteador de caminos! -Mentís -respondió Sancho-, que yo no soy salteador de caminos; que en buena guerra ganó mi señor don Quijote estos despojos. Ya estaba don Quijote delante, con mucho contento de ver cuán bien se defendía y ofendía su escudero, y túvole desde allí adelante por hombre de pro, y propuso en su corazón de armalle caballero en la primera ocasión que se le ofreciese, por parecerle que sería en él bien empleada la orden de la caballería. Entre otras cosas que el barbero decía en el discurso de la pendencia, vino a decir: -Señores, así esta albarda es mía como la muerte que debo a Dios, y así la conozco como si la hubiera parido; y ahí está mi asno en el establo, que no me dejará mentir; si no, pruébensela, y si no le viniere pintiparada, yo quedaré por infame. Y hay más: que el mismo día que ella se me quitó, me quitaron también una bacía de azófar nueva, que no se había estrenado, que era señora de un escudo. Aquí no se pudo contener don Quijote sin responder: y, poniéndose entre los dos y apartándoles, depositando la albarda en el suelo, que la tuviese de manifiesto hasta que la verdad se aclarase, dijo: -¡Porque vean vuestras mercedes clara y manifiestamente el error en que está este buen escudero, pues llama bacía a lo que fue, es y será yelmo de Mambrino, el cual se lo quité yo en buena guerra, y me hice señor dél con ligítima y lícita posesión! En lo del albarda no me entremeto, que lo que en ello sabré decir es que mi escudero Sancho me pidió licencia para quitar los jaeces del caballo deste vencido cobarde, y con ellos adornar el suyo; yo se la di, y él los tomó, y, de haberse convertido de jaez en albarda, no sabré dar otra razón si no es la ordinaria: que como esas transformaciones se ven en los sucesos de la caballería; para confirmación de lo cual, corre, Sancho hijo, y saca aquí el yelmo que este buen hombre dice ser bacía. -¡Pardiez, señor -dijo Sancho-, si no tenemos otra prueba de nuestra intención que la que vuestra merced dice, tan bacía es el yelmo de Malino como el jaez deste buen hombre albarda! -Haz lo que te mando -replicó don Quijote-, que no todas las cosas deste castillo han de ser guiadas por encantamento. Sancho fue a do estaba la bacía y la trujo; y, así como don Quijote la vio, la tomó en las manos y dijo: -Miren vuestras mercedes con qué cara podía decir este escudero que ésta es bacía, y no el yelmo que yo he dicho; y juro por la orden de caballería que profeso que este yelmo fue el mismo que yo le quité, sin haber añadido en él ni quitado cosa alguna. -En eso no hay duda -dijo a esta sazón Sancho-, porque desde que mi señor le ganó hasta agora no ha hecho con él más de una batalla, cuando libró a los sin ventura encadenados; y si no fuera por este baciyelmo, no lo pasara entonces muy bien, porque hubo asaz de pedradas en aquel trance. Capítulo XLV. Donde se acaba de averiguar la duda del yelmo de Mambrino y de la albarda, y otras aventuras sucedidas, con toda verdad -¿Qué les parece a vuestras mercedes, señores -dijo el barbero-, de lo que afirman estos gentiles hombres, pues aún porfían que ésta no es bacía, sino yelmo? -Y quien lo contrario dijere -dijo don Quijote-, le haré yo conocer que miente, si fuere caballero, y si escudero, que remiente mil veces. Nuestro barbero, que a todo estaba presente, como tenía tan bien conocido el humor de don Quijote, quiso esforzar su desatino y llevar adelante la burla para que todos riesen, y dijo, hablando con el otro barbero: -Señor barbero, o quien sois, sabed que yo también soy de vuestro oficio, y tengo más ha de veinte años carta de examen, y conozco muy bien de todos los instrumentos de la barbería, sin que le falte uno; y ni más ni menos fui un tiempo en mi mocedad soldado, y sé también qué es yelmo, y qué es morrión, y celada de encaje, y otras cosas tocantes a la milicia, digo, a los géneros de armas de los soldados; y digo, salvo mejor parecer, remitiéndome siempre al mejor entendimiento, que esta pieza que está aquí delante y que este buen señor tiene en las manos, no sólo no es bacía de barbero, pero está tan lejos de serlo como está lejos lo blanco de lo negro y la verdad de la mentira; también digo que éste, aunque es yelmo, no es yelmo entero. -No, por cierto -dijo don Quijote-, porque le falta la mitad, que es la babera. -Así es -dijo el cura, que ya había entendido la intención de su amigo el barbero. Y lo mismo confirmó Cardenio, don Fernando y sus camaradas; y aun el oidor, si no estuviera tan pensativo con el negocio de don Luis, ayudara, por su parte, a la burla; pero las veras de lo que pensaba le tenían tan suspenso, que poco o nada atendía a aquellos donaires. -¡Válame Dios! -dijo a esta sazón el barbero burlado-; ¿que es posible que tanta gente honrada diga que ésta no es bacía, sino yelmo? Cosa parece ésta que puede poner en admiración a toda una Universidad, por discreta que sea. Basta: si es que esta bacía es yelmo, también debe de ser esta albarda jaez de caballo, como este señor ha dicho. -A mí albarda me parece -dijo don Quijote-, pero ya he dicho que en eso no me entremeto. -De que sea albarda o jaez -dijo el cura- no está en más de decirlo el señor don Quijote; que en estas cosas de la caballería todos estos señores y yo le damos la ventaja. -Por Dios, señores míos -dijo don Quijote-, que son tantas y tan estrañas las cosas que en este castillo, en dos veces que en él he alojado, me han sucedido, que no me atreva a decir afirmativamente ninguna cosa de lo que acerca de lo que en él se contiene se preguntare, porque imagino que cuanto en él se trata va por vía de encantamento. La primera vez me fatigó mucho un moro encantado que en él hay, y a Sancho no le fue muy bien con otros sus secuaces; y anoche estuve colgado deste brazo casi dos horas, sin saber cómo ni cómo no vine a caer en aquella desgracia. Así que, ponerme yo agora en cosa de tanta confusión a dar mi parecer, será caer en juicio temerario. En lo que toca a lo que dicen que ésta es bacía, y no yelmo, ya yo tengo respondido; pero, en lo de declarar si ésa es albarda o jaez, no me atrevo a dar sentencia difinitiva: sólo lo dejo al buen parecer de vuestras mercedes. Quizá por no ser armados caballeros, como yo lo soy, no tendrán que ver con vuestras mercedes los encantamentos deste lugar, y tendrán los entendimientos libres, y podrán juzgar de las cosas deste castillo como ellas son real y verdaderamente, y no como a mí me parecían. -No hay duda -respondió a esto don Fernando-, sino que el señor don Quijote ha dicho muy bien hoy que a nosotros toca la difinición deste caso; y, porque vaya con más fundamento, yo tomaré en secreto los votos destos señores, y de lo que resultare daré entera y clara noticia. Para aquellos que la tenían del humor de don Quijote, era todo esto materia de grandísima risa; pero, para los que le ignoraban, les parecía el mayor disparate del mundo, especialmente a los cuatro criados de don Luis, y a don Luis ni más ni menos, y a otros tres pasajeros que acaso habían llegado a la venta, que tenían parecer de ser cuadrilleros, como, en efeto, lo eran. Pero el que más se desesperaba era el barbero, cuya bacía, allí delante de sus ojos, se le había vuelto en yelmo de Mambrino, y cuya albarda pensaba sin duda alguna que se le había de volver en jaez rico de caballo; y los unos y los otros se reían de ver cómo andaba don Fernando tomando los votos de unos en otros, hablándolos al oído para que en secreto declarasen si era albarda o jaez aquella joya sobre quien tanto se había peleado. Y, después que hubo tomado los votos de aquellos que a don Quijote conocían, dijo en alta voz: -El caso es, buen hombre, que ya yo estoy cansado de tomar tantos pareceres, porque veo que a ninguno pregunto lo que deseo saber que no me diga que es disparate el decir que ésta sea albarda de jumento, sino jaez de caballo, y aun de caballo castizo; y así, habréis de tener paciencia, porque, a vuestro pesar y al de vuestro asno, éste es jaez y no albarda, y vos habéis alegado y probado muy mal de vuestra parte. -No la tenga yo en el cielo -dijo el sobrebarbero- si todos vuestras mercedes no se engañan, y que así parezca mi ánima ante Dios como ella me parece a mí albarda, y no jaez; pero allá van leyes..., etcétera; y no digo más; y en verdad que no estoy borracho: que no me he desayunado, si de pecar no. No menos causaban risa las necedades que decía el barbero que los disparates de don Quijote, el cual a esta sazón dijo: -Aquí no hay más que hacer, sino que cada uno tome lo que es suyo, y a quien Dios se la dio, San Pedro se la bendiga. Uno de los cuatro dijo: -Si ya no es que esto sea burla pesada, no me puedo persuadir que hombres de tan buen entendimiento como son, o parecen, todos los que aquí están, se atrevan a decir y afirmar que ésta no es bacía, ni aquélla albarda; mas, como veo que lo afirman y lo dicen, me doy a entender que no carece de misterio el porfiar una cosa tan contraria de lo que nos muestra la misma verdad y la misma experiencia; porque, ¡voto a tal! -y arrojóle redondo-, que no me den a mí a entender cuantos hoy viven en el mundo al revés de que ésta no sea bacía de barbero y ésta albarda de asno. -Bien podría ser de borrica -dijo el cura. -Tanto monta -dijo el criado-, que el caso no consiste en eso, sino en si es o no es albarda, como vuestras mercedes dicen. Oyendo esto uno de los cuadrilleros que habían entrado, que había oído la pendencia y quistión, lleno de cólera y de enfado, dijo: -Tan albarda es como mi padre; y el que otra cosa ha dicho o dijere debe de estar hecho uva. -Mentís como bellaco villano -respondió don Quijote. Y, alzando el lanzón, que nunca le dejaba de las manos, le iba a descargar tal golpe sobre la cabeza, que, a no desviarse el cuadrillero, se le dejara allí tendido. El lanzón se hizo pedazos en el suelo, y los demás cuadrilleros, que vieron tratar mal a su compañero, alzaron la voz pidiendo favor a la Santa Hermandad. El ventero, que era de la cuadrilla, entró al punto por su varilla y por su espada, y se puso al lado de sus compañeros; los criados de don Luis rodearon a don Luis, porque con el alboroto no se les fuese; el barbero, viendo la casa revuelta, tornó a asir de su albarda, y lo mismo hizo Sancho; don Quijote puso mano a su espada y arremetió a los cuadrilleros. Don Luis daba voces a sus criados que le dejasen a él y acorriesen a don Quijote, y a Cardenio, y a don Fernando, que todos favorecían a don Quijote. El cura daba voces, la ventera gritaba, su hija se afligía, Maritornes lloraba, Dorotea estaba confusa, Luscinda suspensa y doña Clara desmayada. El barbero aporreaba a Sancho, Sancho molía al barbero; don Luis, a quien un criado suyo se atrevió a asirle del brazo porque no se fuese, le dio una puñada que le bañó los dientes en sangre; el oidor le defendía, don Fernando tenía debajo de sus pies a un cuadrillero, midiéndole el cuerpo con ellos muy a su sabor. El ventero tornó a reforzar la voz, pidiendo favor a la Santa Hermandad: de modo que toda la venta era llantos, voces, gritos, confusiones, temores, sobresaltos, desgracias, cuchilladas, mojicones, palos, coces y efusión de sangre. Y, en la mitad deste caos, máquina y laberinto de cosas, se le representó en la memoria de don Quijote que se veía metido de hoz y de coz en la discordia del campo de Agramante; y así dijo, con voz que atronaba la venta: -¡Ténganse todos; todos envainen; todos se sosieguen; óiganme todos, si todos quieren quedar con vida! A cuya gran voz, todos se pararon, y él prosiguió diciendo: -¿No os dije yo, señores, que este castillo era encantado, y que alguna región de demonios debe de habitar en él? En confirmación de lo cual, quiero que veáis por vuestros ojos cómo se ha pasado aquí y trasladado entre nosotros la discordia del campo de Agramante. Mirad cómo allí se pelea por la espada, aquí por el caballo, acullá por el águila, acá por el yelmo, y todos peleamos, y todos no nos entendemos. Venga, pues, vuestra merced, señor oidor, y vuestra merced, señor cura, y el uno sirva de rey Agramante, y el otro de rey Sobrino, y pónganos en paz; porque por Dios Todopoderoso que es gran bellaquería que tanta gente principal como aquí estamos se mate por causas tan livianas. Los cuadrilleros, que no entendían el frasis de don Quijote, y se veían malparados de don Fernando, Cardenio y sus camaradas, no querían sosegarse; el barbero sí, porque en la pendencia tenía deshechas las barbas y el albarda; Sancho, a la más mínima voz de su amo, obedeció como buen criado; los cuatro criados de don Luis también se estuvieron quedos, viendo cuán poco les iba en no estarlo. Sólo el ventero porfiaba que se habían de castigar las insolencias de aquel loco, que a cada paso le alborotaba la venta. Finalmente, el rumor se apaciguó por entonces, la albarda se quedó por jaez hasta el día del juicio, y la bacía por yelmo y la venta por castillo en la imaginación de don Quijote. Puestos, pues, ya en sosiego, y hechos amigos todos a persuasión del oidor y del cura, volvieron los criados de don Luis a porfiarle que al momento se viniese con ellos; y, en tanto que él con ellos se avenía, el oidor comunicó con don Fernando, Cardenio y el cura qué debía hacer en aquel caso, contándoseles con las razones que don Luis le había dicho. En fin, fue acordado que don Fernando dijese a los criados de don Luis quién él era y cómo era su gusto que don Luis se fuese con él al Andalucía, donde de su hermano el marqués sería estimado como el valor de don Luis merecía; porque desta manera se sabía de la intención de don Luis que no volvería por aquella vez a los ojos de su padre, si le hiciesen pedazos. Entendida, pues, de los cuatro la calidad de don Fernando y la intención de don Luis, determinaron entre ellos que los tres se volviesen a contar lo que pasaba a su padre, y el otro se quedase a servir a don Luis, y a no dejalle hasta que ellos volviesen por él, o viese lo que su padre les ordenaba. Desta manera se apaciguó aquella máquina de pendencias, por la autoridad de Agramante y prudencia del rey Sobrino; pero, viéndose el enemigo de la concordia y el émulo de la paz menospreciado y burlado, y el poco fruto que había granjeado de haberlos puesto a todos en tan confuso laberinto, acordó de probar otra vez la mano, resucitando nuevas pendencias y desasosiegos. Es, pues, el caso que los cuadrilleros se sosegaron, por haber entreoído la calidad de los que con ellos se habían combatido, y se retiraron de la pendencia, por parecerles que, de cualquiera manera que sucediese, habían de llevar lo peor de la batalla; pero uno dellos, que fue el que fue molido y pateado por don Fernando, le vino a la memoria que, entre algunos mandamientos que traía para prender a algunos delincuentes, traía uno contra don Quijote, a quien la Santa Hermandad había mandado prender, por la libertad que dio a los galeotes, y como Sancho, con mucha razón, había temido. Imaginando, pues, esto, quiso certificarse si las señas que de don Quijote traía venían bien, y, sacando del seno un pergamino, topó con el que buscaba; y, poniéndosele a leer de espacio, porque no era buen lector, a cada palabra que leía ponía los ojos en don Quijote, y iba cotejando las señas del mandamiento con el rostro de don Quijote, y halló que, sin duda alguna, era el que el mandamiento rezaba. Y, apenas se hubo certificado, cuando, recogiendo su pergamino, en la izquierda tomó el mandamiento, y con la derecha asió a don Quijote del cuello fuertemente, que no le dejaba alentar, y a grandes voces decía: -¡Favor a la Santa Hermandad! Y, para que se vea que lo pido de veras, léase este mandamiento, donde se contiene que se prenda a este salteador de caminos. Tomó el mandamiento el cura, y vio como era verdad cuanto el cuadrillero decía, y cómo convenía con las señas con don Quijote; el cual, viéndose tratar mal de aquel villano malandrín, puesta la cólera en su punto y crujiéndole los huesos de su cuerpo, como mejor pudo él, asió al cuadrillero con entrambas manos de la garganta, que, a no ser socorrido de sus compañeros, allí dejara la vida antes que don Quijote la presa. El ventero, que por fuerza había de favorecer a los de su oficio, acudió luego a dalle favor. La ventera, que vio de nuevo a su marido en pendencias, de nuevo alzó la voz, cuyo tenor le llevaron luego Maritornes y su hija, pidiendo favor al cielo y a los que allí estaban. Sancho dijo, viendo lo que pasaba: -¡Vive el Señor, que es verdad cuanto mi amo dice de los encantos deste castillo, pues no es posible vivir una hora con quietud en él! Don Fernando despartió al cuadrillero y a don Quijote, y, con gusto de entrambos, les desenclavijó las manos, que el uno en el collar del sayo del uno, y el otro en la garganta del otro, bien asidas tenían; pero no por esto cesaban los cuadrilleros de pedir su preso, y que les ayudasen a dársele atado y entregado a toda su voluntad, porque así convenía al servicio del rey y de la Santa Hermandad, de cuya parte de nuevo les pedían socorro y favor para hacer aquella prisión de aquel robador y salteador de sendas y de carreras. Reíase de oír decir estas razones don Quijote; y, con mucho sosiego, dijo: -Venid acá, gente soez y malnacida: ¿saltear de caminos llamáis al dar libertad a los encadenados, soltar los presos, acorrer a los miserables, alzar los caídos, remediar los menesterosos? ¡Ah gente infame, digna por vuestro bajo y vil entendimiento que el cielo no os comunique el valor que se encierra en la caballería andante, ni os dé a entender el pecado e ignorancia en que estáis en no reverenciar la sombra, cuanto más la asistencia, de cualquier caballero andante! Venid acá, ladrones en cuadrilla, que no cuadrilleros, salteadores de caminos con licencia de la Santa Hermandad; decidme: ¿quién fue el ignorante que firmó mandamiento de prisión contra un tal caballero como yo soy? ¿Quién el que ignoró que son esentos de todo judicial fuero los caballeros andantes, y que su ley es su espada; sus fueros, sus bríos; sus premáticas, su voluntad? ¿Quién fue el mentecato, vuelvo a decir, que no sabe que no hay secutoria de hidalgo con tantas preeminencias, ni esenciones, como la que adquiere un caballero andante el día que se arma caballero y se entrega al duro ejercicio de la caballería? ¿Qué caballero andante pagó pecho, alcabala, chapín de la reina, moneda forera, portazgo ni barca? ¿Qué sastre le llevó hechura de vestido que le hiciese? ¿Qué castellano le acogió en su castillo que le hiciese pagar el escote? ¿Qué rey no le asentó a su mesa? ¿Qué doncella no se le aficionó y se le entregó rendida, a todo su talante y voluntad? Y, finalmente, ¿qué caballero andante ha habido, hay ni habrá en el mundo, que no tenga bríos para dar él solo cuatrocientos palos a cuatrocientos cuadrilleros que se le pongan delante? Capítulo XLVI. De la notable aventura de los cuadrilleros, y la gran ferocidad de nuestro buen caballero don Quijote En tanto que don Quijote esto decía, estaba persuadiendo el cura a los cuadrilleros como don Quijote era falto de juicio, como lo veían por sus obras y por sus palabras, y que no tenían para qué llevar aquel negocio adelante, pues, aunque le prendiesen y llevasen, luego le habían de dejar por loco; a lo que respondió el del mandamiento que a él no tocaba juzgar de la locura de don Quijote, sino hacer lo que por su mayor le era mandado, y que una vez preso, siquiera le soltasen trecientas. -Con todo eso -dijo el cura-, por esta vez no le habéis de llevar, ni aun él dejará llevarse, a lo que yo entiendo. En efeto, tanto les supo el cura decir, y tantas locuras supo don Quijote hacer, que más locos fueran que no él los cuadrilleros si no conocieran la falta de don Quijote; y así, tuvieron por bien de apaciguarse, y aun de ser medianeros de hacer las paces entre el barbero y Sancho Panza, que todavía asistían con gran rancor a su pendencia. Finalmente, ellos, como miembros de justicia, mediaron la causa y fueron árbitros della, de tal modo que ambas partes quedaron, si no del todo contentas, a lo menos en algo satisfechas, porque se trocaron las albardas, y no las cinchas y jáquimas; y en lo que tocaba a lo del yelmo de Mambrino, el cura, a socapa y sin que don Quijote lo entendiese, le dio por la bacía ocho reales, y el barbero le hizo una cédula del recibo y de no llamarse a engaño por entonces, ni por siempre jamás amén. Sosegadas, pues, estas dos pendencias, que eran las más principales y de más tomo, restaba que los criados de don Luis se contentasen de volver los tres, y que el uno quedase para acompañarle donde don Fernando le quería llevar; y, como ya la buena suerte y mejor fortuna había comenzado a romper lanzas y a facilitar dificultades en favor de los amantes de la venta y de los valientes della, quiso llevarlo al cabo y dar a todo felice suceso, porque los criados se contentaron de cuanto don Luis quería; de que recibió tanto contento doña Clara, que ninguno en aquella sazón la mirara al rostro que no conociera el regocijo de su alma. Zoraida, aunque no entendía bien todos los sucesos que había visto, se entristecía y alegraba a bulto, conforme veía y notaba los semblantes a cada uno, especialmente de su español, en quien tenía siempre puestos los ojos y traía colgada el alma. El ventero, a quien no se le pasó por alto la dádiva y recompensa que el cura había hecho al barbero, pidió el escote de don Quijote, con el menoscabo de sus cueros y falta de vino, jurando que no saldría de la venta Rocinante, ni el jumento de Sancho, sin que se le pagase primero hasta el último ardite. Todo lo apaciguó el cura, y lo pagó don Fernando, puesto que el oidor, de muy buena voluntad, había también ofrecido la paga; y de tal manera quedaron todos en paz y sosiego, que ya no parecía la venta la discordia del campo de Agramante, como don Quijote había dicho, sino la misma paz y quietud del tiempo de Otaviano; de todo lo cual fue común opinión que se debían dar las gracias a la buena intención y mucha elocuencia del señor cura y a la incomparable liberalidad de don Fernando. Viéndose, pues, don Quijote libre y desembarazado de tantas pendencias, así de su escudero como suyas, le pareció que sería bien seguir su comenzado viaje y dar fin a aquella grande aventura para que había sido llamado y escogido; y así, con resoluta determinación se fue a poner de hinojos ante Dorotea, la cual no le consintió que hablase palabra hasta que se levantase; y él, por obedecella, se puso en pie y le dijo: -Es común proverbio, fermosa señora, que la diligencia es madre de la buena ventura, y en muchas y graves cosas ha mostrado la experiencia que la solicitud del negociante trae a buen fin el pleito dudoso; pero en ningunas cosas se muestra más esta verdad que en las de la guerra, adonde la celeridad y presteza previene los discursos del enemigo, y alcanza la vitoria antes que el contrario se ponga en defensa. Todo esto digo, alta y preciosa señora, porque me parece que la estada nuestra en este castillo ya es sin provecho, y podría sernos de tanto daño que lo echásemos de ver algún día; porque, ¿quién sabe si por ocultas espías y diligentes habrá sabido ya vuestro enemigo el gigante de que yo voy a destruille?; y, dándole lugar el tiempo, se fortificase en algún inexpugnable castillo o fortaleza contra quien valiesen poco mis diligencias y la fuerza de mi incansable brazo. Así que, señora mía, prevengamos, como tengo dicho, con nuestra diligencia sus designios, y partámonos luego a la buena ventura; que no está más de tenerla vuestra grandeza como desea, de cuanto yo tarde de verme con vuestro contrario. Calló y no dijo más don Quijote, y esperó con mucho sosiego la respuesta de la fermosa infanta; la cual, con ademán señoril y acomodado al estilo de don Quijote, le respondió desta manera: -Yo os agradezco, señor caballero, el deseo que mostráis tener de favorecerme en mi gran cuita, bien así como caballero, a quien es anejo y concerniente favorecer los huérfanos y menesterosos; y quiera el cielo que el vuestro y mi deseo se cumplan, para que veáis que hay agradecidas mujeres en el mundo. Y en lo de mi partida, sea luego; que yo no tengo más voluntad que la vuestra: disponed vos de mí a toda vuestra guisa y talante; que la que una vez os entregó la defensa de su persona y puso en vuestras manos la restauración de sus señoríos no ha de querer ir contra lo que la vuestra prudencia ordenare. -A la mano de Dios -dijo don Quijote-; pues así es que una señora se me humilla, no quiero yo perder la ocasión de levantalla y ponella en su heredado trono. La partida sea luego, porque me va poniendo espuelas al deseo y al camino lo que suele decirse que en la tardanza está el peligro. Y, pues no ha criado el cielo, ni visto el infierno, ninguno que me espante ni acobarde, ensilla, Sancho, a Rocinante, y apareja tu jumento y el palafrén de la reina, y despidámonos del castellano y destos señores, y vamos de aquí luego al punto. Sancho, que a todo estaba presente, dijo, meneando la cabeza a una parte y a otra: -¡Ay señor, señor, y cómo hay más mal en el aldegüela que se suena, con perdón sea dicho de las tocadas honradas! -¿Qué mal puede haber en ninguna aldea, ni en todas las ciudades del mundo, que pueda sonarse en menoscabo mío, villano? -Si vuestra merced se enoja -respondió Sancho-, yo callaré, y dejaré de decir lo que soy obligado como buen escudero, y como debe un buen criado decir a su señor. -Di lo que quisieres -replicó don Quijote-, como tus palabras no se encaminen a ponerme miedo; que si tú le tienes, haces como quien eres, y si yo no le tengo, hago como quien soy. -No es eso, ¡pecador fui yo a Dios! -respondió Sancho-, sino que yo tengo por cierto y por averiguado que esta señora que se dice ser reina del gran reino Micomicón no lo es más que mi madre; porque, a ser lo que ella dice, no se anduviera hocicando con alguno de los que están en la rueda, a vuelta de cabeza y a cada traspuesta. Paróse colorada con las razones de Sancho Dorotea, porque era verdad que su esposo don Fernando, alguna vez, a hurto de otros ojos, había cogido con los labios parte del premio que merecían sus deseos (lo cual había visto Sancho, y pareciéndole que aquella desenvoltura más era de dama cortesana que de reina de tan gran reino), y no pudo ni quiso responder palabra a Sancho, sino dejóle proseguir en su plática, y él fue diciendo: -Esto digo, señor, porque, si al cabo de haber andado caminos y carreras, y pasado malas noches y peores días, ha de venir a coger el fruto de nuestros trabajos el que se está holgando en esta venta, no hay para qué darme priesa a que ensille a Rocinante, albarde el jumento y aderece al palafrén, pues será mejor que nos estemos quedos, y cada puta hile, y comamos. ¡Oh, válame Dios, y cuán grande que fue el enojo que recibió don Quijote, oyendo las descompuestas palabras de su escudero! Digo que fue tanto, que, con voz atropellada y tartamuda lengua, lanzando vivo fuego por los ojos, dijo: -¡Oh bellaco villano, mal mirado, descompuesto, ignorante, infacundo, deslenguado, atrevido, murmurador y maldiciente! ¿Tales palabras has osado decir en mi presencia y en la destas ínclitas señoras, y tales deshonestidades y atrevimientos osaste poner en tu confusa imaginación? ¡Vete de mi presencia, monstruo de naturaleza, depositario de mentiras, almario de embustes, silo de bellaquerías, inventor de maldades, publicador de sandeces, enemigo del decoro que se debe a las reales personas! ¡Vete; no parezcas delante de mí, so pena de mi ira! Y, diciendo esto, enarcó las cejas, hinchó los carrillos, miró a todas partes, y dio con el pie derecho una gran patada en el suelo, señales todas de la ira que encerraba en sus entrañas. A cuyas palabras y furibundos ademanes quedó Sancho tan encogido y medroso, que se holgara que en aquel instante se abriera debajo de sus pies la tierra y le tragara. Y no supo qué hacerse, sino volver las espaldas y quitarse de la enojada presencia de su señor. Pero la discreta Dorotea, que tan entendido tenía ya el humor de don Quijote, dijo, para templarle la ira: -No os despechéis, señor Caballero de la Triste Figura, de las sandeces que vuestro buen escudero ha dicho, porque quizá no las debe de decir sin ocasión, ni de su buen entendimiento y cristiana conciencia se puede sospechar que levante testimonio a nadie; y así, se ha de creer, sin poner duda en ello, que, como en este castillo, según vos, señor caballero, decís, todas las cosas van y suceden por modo de encantamento, podría ser, digo, que Sancho hubiese visto por esta diabólica vía lo que él dice que vio, tan en ofensa de mi honestidad. -Por el omnipotente Dios juro -dijo a esta sazón don Quijote-, que la vuestra grandeza ha dado en el punto, y que alguna mala visión se le puso delante a este pecador de Sancho, que le hizo ver lo que fuera imposible verse de otro modo que por el de encantos no fuera; que sé yo bien de la bondad e inocencia deste desdichado, que no sabe levantar testimonios a nadie. -Ansí es y ansí será -dijo don Fernando-; por lo cual debe vuestra merced, señor don Quijote, perdonalle y reducille al gremio de su gracia, sicut erat in principio, antes que las tales visiones le sacasen de juicio. Don Quijote respondió que él le perdonaba, y el cura fue por Sancho, el cual vino muy humilde, y, hincándose de rodillas, pidió la mano a su amo; y él se la dio, y, después de habérsela dejado besar, le echó la bendición, diciendo: -Agora acabarás de conocer, Sancho hijo, ser verdad lo que yo otras muchas veces te he dicho de que todas las cosas deste castillo son hechas por vía de encantamento. -Así lo creo yo -dijo Sancho-, excepto aquello de la manta, que realmente sucedió por vía ordinaria. -No lo creas -respondió don Quijote-; que si así fuera, yo te vengara entonces, y aun agora; pero ni entonces ni agora pude ni vi en quién tomar venganza de tu agravio. Desearon saber todos qué era aquello de la manta, y el ventero lo contó, punto por punto: la volatería de Sancho Panza, de que no poco se rieron todos; y de que no menos se corriera Sancho, si de nuevo no le asegurara su amo que era encantamento; puesto que jamás llegó la sandez de Sancho a tanto, que creyese no ser verdad pura y averiguada, sin mezcla de engaño alguno, lo de haber sido manteado por personas de carne y hueso, y no por fantasmas soñadas ni imaginadas, como su señor lo creía y lo afirmaba. Dos días eran ya pasados los que había que toda aquella ilustre compañía estaba en la venta; y, pareciéndoles que ya era tiempo de partirse, dieron orden para que, sin ponerse al trabajo de volver Dorotea y don Fernando con don Quijote a su aldea, con la invención de la libertad de la reina Micomicona, pudiesen el cura y el barbero llevársele, como deseaban, y procurar la cura de su locura en su tierra. Y lo que ordenaron fue que se concertaron con un carretero de bueyes que acaso acertó a pasar por allí, para que lo llevase en esta forma: hicieron una como jaula de palos enrejados, capaz que pudiese en ella caber holgadamente don Quijote; y luego don Fernando y sus camaradas, con los criados de don Luis y los cuadrilleros, juntamente con el ventero, todos por orden y parecer del cura, se cubrieron los rostros y se disfrazaron, quién de una manera y quién de otra, de modo que a don Quijote le pareciese ser otra gente de la que en aquel castillo había visto. Hecho esto, con grandísimo silencio se entraron adonde él estaba durmiendo y descansando de las pasadas refriegas. Llegáronse a él, que libre y seguro de tal acontecimiento dormía, y, asiéndole fuertemente, le ataron muy bien las manos y los pies, de modo que, cuando él despertó con sobresalto, no pudo menearse, ni hacer otra cosa más que admirarse y suspenderse de ver delante de sí tan estraños visajes; y luego dio en la cuenta de lo que su continua y desvariada imaginación le representaba, y se creyó que todas aquellas figuras eran fantasmas de aquel encantado castillo, y que, sin duda alguna, ya estaba encantado, pues no se podía menear ni defender: todo a punto como había pensado que sucedería el cura, trazador desta máquina. Sólo Sancho, de todos los presentes, estaba en su mesmo juicio y en su mesma figura; el cual, aunque le faltaba bien poco para tener la mesma enfermedad de su amo, no dejó de conocer quién eran todas aquellas contrahechas figuras; mas no osó descoser su boca, hasta ver en qué paraba aquel asalto y prisión de su amo, el cual tampoco hablaba palabra, atendiendo a ver el paradero de su desgracia; que fue que, trayendo allí la jaula, le encerraron dentro, y le clavaron los maderos tan fuertemente que no se pudieran romper a dos tirones. Tomáronle luego en hombros, y, al salir del aposento, se oyó una voz temerosa, todo cuanto la supo formar el barbero, no el del albarda, sino el otro, que decía: -¡Oh Caballero de la Triste Figura!, no te dé afincamiento la prisión en que vas, porque así conviene para acabar más presto la aventura en que tu gran esfuerzo te puso; la cual se acabará cuando el furibundo león manchado con la blanca paloma tobosina yoguieren en uno, ya después de humilladas las altas cervices al blando yugo matrimoñesco; de cuyo inaudito consorcio saldrán a la luz del orbe los bravos cachorros, que imitarán las rumpantes garras del valeroso padre. Y esto será antes que el seguidor de la fugitiva ninfa faga dos vegadas la visita de las lucientes imágines con su rápido y natural curso. Y tú, ¡oh, el más noble y obediente escudero que tuvo espada en cinta, barbas en rostro y olfato en las narices!, no te desmaye ni descontente ver llevar ansí delante de tus ojos mesmos a la flor de la caballería andante; que presto, si al plasmador del mundo le place, te verás tan alto y tan sublimado que no te conozcas, y no saldrán defraudadas las promesas que te ha fecho tu buen señor. Y asegúrote, de parte de la sabia Mentironiana, que tu salario te sea pagado, como lo verás por la obra; y sigue las pisadas del valeroso y encantado caballero, que conviene que vayas donde paréis entrambos. Y, porque no me es lícito decir otra cosa, a Dios quedad, que yo me vuelvo adonde yo me sé. Y, al acabar de la profecía, alzó la voz de punto, y diminuyóla después, con tan tierno acento, que aun los sabidores de la burla estuvieron por creer que era verdad lo que oían. Quedó don Quijote consolado con la escuchada profecía, porque luego coligió de todo en todo la significación de ella; y vio que le prometían el verse ayuntados en santo y debido matrimonio con su querida Dulcinea del Toboso, de cuyo felice vientre saldrían los cachorros, que eran sus hijos, para gloria perpetua de la Mancha. Y, creyendo esto bien y firmemente, alzó la voz, y, dando un gran suspiro, dijo: -¡Oh tú, quienquiera que seas, que tanto bien me has pronosticado!, ruégote que pidas de mi parte al sabio encantador que mis cosas tiene a cargo, que no me deje perecer en esta prisión donde agora me llevan, hasta ver cumplidas tan alegres e incomparables promesas como son las que aquí se me han hecho; que, como esto sea, tendré por gloria las penas de mi cárcel, y por alivio estas cadenas que me ciñen, y no por duro campo de batalla este lecho en que me acuestan, sino por cama blanda y tálamo dichoso. Y, en lo que toca a la consolación de Sancho Panza, mi escudero, yo confío de su bondad y buen proceder que no me dejará en buena ni en mala suerte; porque, cuando no suceda, por la suya o por mi corta ventura, el poderle yo dar la ínsula, o otra cosa equivalente que le tengo prometida, por lo menos su salario no podrá perderse; que en mi testamento, que ya está hecho, dejo declarado lo que se le ha de dar, no conforme a sus muchos y buenos servicios, sino a la posibilidad mía. Sancho Panza se le inclinó con mucho comedimiento, y le besó entrambas las manos, porque la una no pudiera, por estar atadas entrambas. Luego tomaron la jaula en hombros aquellas visiones, y la acomodaron en el carro de los bueyes. Capítulo XLVII. Del estraño modo con que fue encantado don Quijote de la Mancha, con otros famosos sucesos Cuando don Quijote se vio de aquella manera enjaulado y encima del carro, dijo: -Muchas y muy graves historias he yo leído de caballeros andantes, pero jamás he leído, ni visto, ni oído, que a los caballeros encantados los lleven desta manera y con el espacio que prometen estos perezosos y tardíos animales; porque siempre los suelen llevar por los aires, con estraña ligereza, encerrados en alguna parda y escura nube, o en algún carro de fuego, o ya sobre algún hipogrifo o otra bestia semejante; pero que me lleven a mí agora sobre un carro de bueyes, ¡vive Dios que me pone en confusión! Pero quizá la caballería y los encantos destos nuestros tiempos deben de seguir otro camino que siguieron los antiguos. Y también podría ser que, como yo soy nuevo caballero en el mundo, y el primero que ha resucitado el ya olvidado ejercicio de la caballería aventurera, también nuevamente se hayan inventado otros géneros de encantamentos y otros modos de llevar a los encantados. ¿Qué te parece desto, Sancho hijo? -No sé yo lo que me parece -respondió Sancho-, por no ser tan leído como vuestra merced en las escrituras andantes; pero, con todo eso, osaría afirmar y jurar que estas visiones que por aquí andan, que no son del todo católicas. -¿Católicas? ¡Mi padre! -respondió don Quijote-. ¿Cómo han de ser católicas si son todos demonios que han tomado cuerpos fantásticos para venir a hacer esto y a ponerme en este estado? Y si quieres ver esta verdad, tócalos y pálpalos, y verás como no tienen cuerpo sino de aire, y como no consiste más de en la apariencia. -Par Dios, señor -replicó Sancho-, ya yo los he tocado; y este diablo que aquí anda tan solícito es rollizo de carnes, y tiene otra propiedad muy diferente de la que yo he oído decir que tienen los demonios; porque, según se dice, todos huelen a piedra azufre y a otros malos olores; pero éste huele a ámbar de media legua. Decía esto Sancho por don Fernando, que, como tan señor, debía de oler a lo que Sancho decía. -No te maravilles deso, Sancho amigo -respondió don Quijote-, porque te hago saber que los diablos saben mucho, y, puesto que traigan olores consigo, ellos no huelen nada, porque son espíritus, y si huelen, no pueden oler cosas buenas, sino malas y hidiondas. Y la razón es que como ellos, dondequiera que están, traen el infierno consigo, y no pueden recebir género de alivio alguno en sus tormentos, y el buen olor sea cosa que deleita y contenta, no es posible que ellos huelan cosa buena. Y si a ti te parece que ese demonio que dices huele a ámbar, o tú te engañas, o él quiere engañarte con hacer que no le tengas por demonio. Todos estos coloquios pasaron entre amo y criado; y, temiendo don Fernando y Cardenio que Sancho no viniese a caer del todo en la cuenta de su invención, a quien andaba ya muy en los alcances, determinaron de abreviar con la partida; y, llamando aparte al ventero, le ordenaron que ensillase a Rocinante y enalbardase el jumento de Sancho; el cual lo hizo con mucha presteza. Ya en esto, el cura se había concertado con los cuadrilleros que le acompañasen hasta su lugar, dándoles un tanto cada día. Colgó Cardenio del arzón de la silla de Rocinante, del un cabo la adarga y del otro la bacía, y por señas mandó a Sancho que subiese en su asno y tomase de las riendas a Rocinante, y puso a los dos lados del carro a los dos cuadrilleros con sus escopetas. Pero, antes que se moviese el carro, salió la ventera, su hija y Maritornes a despedirse de don Quijote, fingiendo que lloraban de dolor de su desgracia; a quien don Quijote dijo: -No lloréis, mis buenas señoras, que todas estas desdichas son anexas a los que profesan lo que yo profeso; y si estas calamidades no me acontecieran, no me tuviera yo por famoso caballero andante; porque a los caballeros de poco nombre y fama nunca les suceden semejantes casos, porque no hay en el mundo quien se acuerde dellos. A los valerosos sí, que tienen envidiosos de su virtud y valentía a muchos príncipes y a muchos otros caballeros, que procuran por malas vías destruir a los buenos. Pero, con todo eso, la virtud es tan poderosa que, por sí sola, a pesar de toda la nigromancia que supo su primer inventor, Zoroastes, saldrá vencedora de todo trance, y dará de sí luz en el mundo, como la da el sol en el cielo. Perdonadme, fermosas damas, si algún desaguisado, por descuido mío, os he fecho, que, de voluntad y a sabiendas, jamás le di a nadie; y rogad a Dios me saque destas prisiones, donde algún mal intencionado encantador me ha puesto; que si de ellas me veo libre, no se me caerá de la memoria las mercedes que en este castillo me habedes fecho, para gratificallas, servillas y recompensallas como ellas merecen. En tanto que las damas del castillo esto pasaban con don Quijote, el cura y el barbero se despidieron de don Fernando y sus camaradas, y del capitán y de su hermano y todas aquellas contentas señoras, especialmente de Dorotea y Luscinda. Todos se abrazaron y quedaron de darse noticia de sus sucesos, diciendo don Fernando al cura dónde había de escribirle para avisarle en lo que paraba don Quijote, asegurándole que no habría cosa que más gusto le diese que saberlo; y que él, asimesmo, le avisaría de todo aquello que él viese que podría darle gusto, así de su casamiento como del bautismo de Zoraida, y suceso de don Luis, y vuelta de Luscinda a su casa. El cura ofreció de hacer cuanto se le mandaba, con toda puntualidad. Tornaron a abrazarse otra vez, y otra vez tornaron a nuevos ofrecimientos. El ventero se llegó al cura y le dio unos papeles, diciéndole que los había hallado en un aforro de la maleta donde se halló la Novela del curioso impertinente, y que, pues su dueño no había vuelto más por allí, que se los llevase todos; que, pues él no sabía leer, no los quería. El cura se lo agradeció, y, abriéndolos luego, vio que al principio de lo escrito decía: Novela de Rinconete y Cortadillo, por donde entendió ser alguna novela y coligió que, pues la del Curioso impertinente había sido buena, que también lo sería aquélla, pues podría ser fuesen todas de un mesmo autor; y así, la guardó, con prosupuesto de leerla cuando tuviese comodidad. Subió a caballo, y también su amigo el barbero, con sus antifaces, porque no fuesen luego conocidos de don Quijote, y pusiéronse a caminar tras el carro. Y la orden que llevaban era ésta: iba primero el carro, guiándole su dueño; a los dos lados iban los cuadrilleros, como se ha dicho, con sus escopetas; seguía luego Sancho Panza sobre su asno, llevando de rienda a Rocinante. Detrás de todo esto iban el cura y el barbero sobre sus poderosas mulas, cubiertos los rostros, como se ha dicho, con grave y reposado continente, no caminando más de lo que permitía el paso tardo de los bueyes. Don Quijote iba sentado en la jaula, las manos atadas, tendidos los pies, y arrimado a las verjas, con tanto silencio y tanta paciencia como si no fuera hombre de carne, sino estatua de piedra. Y así, con aquel espacio y silencio caminaron hasta dos leguas, que llegaron a un valle, donde le pareció al boyero ser lugar acomodado para reposar y dar pasto a los bueyes; y, comunicándolo con el cura, fue de parecer el barbero que caminasen un poco más, porque él sabía, detrás de un recuesto que cerca de allí se mostraba, había un valle de más yerba y mucho mejor que aquel donde parar querían. Tomóse el parecer del barbero, y así, tornaron a proseguir su camino. En esto, volvió el cura el rostro, y vio que a sus espaldas venían hasta seis o siete hombres de a caballo, bien puestos y aderezados, de los cuales fueron presto alcanzados, porque caminaban no con la flema y reposo de los bueyes, sino como quien iba sobre mulas de canónigos y con deseo de llegar presto a sestear a la venta, que menos de una legua de allí se parecía. Llegaron los diligentes a los perezosos y saludáronse cortésmente; y uno de los que venían, que, en resolución, era canónigo de Toledo y señor de los demás que le acompañaban, viendo la concertada procesión del carro, cuadrilleros, Sancho, Rocinante, cura y barbero, y más a don Quijote, enjaulado y aprisionado, no pudo dejar de preguntar qué significaba llevar aquel hombre de aquella manera; aunque ya se había dado a entender, viendo las insignias de los cuadrilleros, que debía de ser algún facinoroso salteador, o otro delincuente cuyo castigo tocase a la Santa Hermandad. Uno de los cuadrilleros, a quien fue hecha la pregunta, respondió ansí: -Señor, lo que significa ir este caballero desta manera, dígalo él, porque nosotros no lo sabemos. Oyó don Quijote la plática, y dijo: -¿Por dicha vuestras mercedes, señores caballeros, son versados y perictos en esto de la caballería andante? Porque si lo son, comunicaré con ellos mis desgracias, y si no, no hay para qué me canse en decillas. Y, a este tiempo, habían ya llegado el cura y el barbero, viendo que los caminantes estaban en pláticas con don Quijote de la Mancha, para responder de modo que no fuese descubierto su artificio. El canónigo, a lo que don Quijote dijo, respondió: -En verdad, hermano, que sé más de libros de caballerías que de las Súmulas de Villalpando. Ansí que, si no está más que en esto, seguramente podéis comunicar conmigo lo que quisiéredes. -A la mano de Dios -replicó don Quijote-. Pues así es, quiero, señor caballero, que sepades que yo voy encantado en esta jaula, por envidia y fraude de malos encantadores; que la virtud más es perseguida de los malos que amada de los buenos. Caballero andante soy, y no de aquellos de cuyos nombres jamás la Fama se acordó para eternizarlos en su memoria, sino de aquellos que, a despecho y pesar de la mesma envidia, y de cuantos magos crió Persia, bracmanes la India, ginosofistas la Etiopía, ha de poner su nombre en el templo de la inmortalidad para que sirva de ejemplo y dechado en los venideros siglos, donde los caballeros andantes vean los pasos que han de seguir, si quisieren llegar a la cumbre y alteza honrosa de las armas. -Dice verdad el señor don Quijote de la Mancha -dijo a esta sazón el cura-; que él va encantado en esta carreta, no por sus culpas y pecados, sino por la mala intención de aquellos a quien la virtud enfada y la valentía enoja. Éste es, señor, el Caballero de la Triste Figura, si ya le oístes nombrar en algún tiempo, cuyas valerosas hazañas y grandes hechos serán escritas en bronces duros y en eternos mármoles, por más que se canse la envidia en escurecerlos y la malicia en ocultarlos. Cuando el canónigo oyó hablar al preso y al libre en semejante estilo, estuvo por hacerse la cruz, de admirado, y no podía saber lo que le había acontencido; y en la mesma admiración cayeron todos los que con él venían. En esto, Sancho Panza, que se había acercado a oír la plática, para adobarlo todo, dijo: -Ahora, señores, quiéranme bien o quiéranme mal por lo que dijere, el caso de ello es que así va encantado mi señor don Quijote como mi madre; él tiene su entero juicio, él come y bebe y hace sus necesidades como los demás hombres, y como las hacía ayer, antes que le enjaulasen. Siendo esto ansí, ¿cómo quieren hacerme a mí entender que va encantado? Pues yo he oído decir a muchas personas que los encantados ni comen, ni duermen, ni hablan, y mi amo, si no le van a la mano, hablará más que treinta procuradores. Y, volviéndose a mirar al cura, prosiguió diciendo: -¡Ah señor cura, señor cura! ¿Pensaba vuestra merced que no le conozco, y pensará que yo no calo y adivino adónde se encaminan estos nuevos encantamentos? Pues sepa que le conozco, por más que se encubra el rostro, y sepa que le entiendo, por más que disimule sus embustes. En fin, donde reina la envidia no puede vivir la virtud, ni adonde hay escaseza la liberalidad. !Mal haya el diablo!; que, si por su reverencia no fuera, ésta fuera ya la hora que mi señor estuviera casado con la infanta Micomicona, y yo fuera conde, por lo menos, pues no se podía esperar otra cosa, así de la bondad de mi señor el de la Triste Figura como de la grandeza de mis servicios. Pero ya veo que es verdad lo que se dice por ahí: que la rueda de la Fortuna anda más lista que una rueda de molino, y que los que ayer estaban en pinganitos hoy están por el suelo. De mis hijos y de mi mujer me pesa, pues cuando podían y debían esperar ver entrar a su padre por sus puertas hecho gobernador o visorrey de alguna ínsula o reino, le verán entrar hecho mozo de caballos. Todo esto que he dicho, señor cura, no es más de por encarecer a su paternidad haga conciencia del mal tratamiento que a mi señor se le hace, y mire bien no le pida Dios en la otra vida esta prisión de mi amo, y se le haga cargo de todos aquellos socorros y bienes que mi señor don Quijote deja de hacer en este tiempo que está preso. -¡Adóbame esos candiles! -dijo a este punto el barbero-. ¿También vos, Sancho, sois de la cofradía de vuestro amo? ¡Vive el Señor, que voy viendo que le habéis de tener compañía en la jaula, y que habéis de quedar tan encantado como él, por lo que os toca de su humor y de su caballería! En mal punto os empreñastes de sus promesas, y en mal hora se os entró en los cascos la ínsula que tanto deseáis. -Yo no estoy preñado de nadie -respondió Sancho-, ni soy hombre que me dejaría empreñar, del rey que fuese; y, aunque pobre, soy cristiano viejo, y no debo nada a nadie; y si ínsulas deseo, otros desean otras cosas peores; y cada uno es hijo de sus obras; y, debajo de ser hombre, puedo venir a ser papa, cuanto más gobernador de una ínsula, y más pudiendo ganar tantas mi señor que le falte a quien dallas. Vuestra merced mire cómo habla, señor barbero; que no es todo hacer barbas, y algo va de Pedro a Pedro. Dígolo porque todos nos conocemos, y a mí no se me ha de echar dado falso. Y en esto del encanto de mi amo, Dios sabe la verdad; y quédese aquí, porque es peor meneallo. No quiso responder el barbero a Sancho, porque no descubriese con sus simplicidades lo que él y el cura tanto procuraban encubrir; y, por este mesmo temor, había el cura dicho al canónigo que caminasen un poco delante: que él le diría el misterio del enjaulado, con otras cosas que le diesen gusto. Hízolo así el canónigo, y adelantóse con sus criados y con él: estuvo atento a todo aquello que decirle quiso de la condición, vida, locura y costumbres de don Quijote, contándole brevemente el principio y causa de su desvarío, y todo el progreso de sus sucesos, hasta haberlo puesto en aquella jaula, y el disignio que llevaban de llevarle a su tierra, para ver si por algún medio hallaban remedio a su locura. Admiráronse de nuevo los criados y el canónigo de oír la peregrina historia de don Quijote, y, en acabándola de oír, dijo: -Verdaderamente, señor cura, yo hallo por mi cuenta que son perjudiciales en la república estos que llaman libros de caballerías; y, aunque he leído, llevado de un ocioso y falso gusto, casi el principio de todos los más que hay impresos, jamás me he podido acomodar a leer ninguno del principio al cabo, porque me parece que, cuál más, cuál menos, todos ellos son una mesma cosa, y no tiene más éste que aquél, ni estotro que el otro. Y, según a mí me parece, este género de escritura y composición cae debajo de aquel de las fábulas que llaman milesias, que son cuentos disparatados, que atienden solamente a deleitar, y no a enseñar: al contrario de lo que hacen las fábulas apólogas, que deleitan y enseñan juntamente. Y, puesto que el principal intento de semejantes libros sea el deleitar, no sé yo cómo puedan conseguirle, yendo llenos de tantos y tan desaforados disparates; que el deleite que en el alma se concibe ha de ser de la hermosura y concordancia que vee o contempla en las cosas que la vista o la imaginación le ponen delante; y toda cosa que tiene en sí fealdad y descompostura no nos puede causar contento alguno. Pues, ¿qué hermosura puede haber, o qué proporción de partes con el todo y del todo con las partes, en un libro o fábula donde un mozo de diez y seis años da una cuchillada a un gigante como una torre, y le divide en dos mitades, como si fuera de alfeñique; y que, cuando nos quieren pintar una batalla, después de haber dicho que hay de la parte de los enemigos un millón de competientes, como sea contra ellos el señor del libro, forzosamente, mal que nos pese, habemos de entender que el tal caballero alcanzó la vitoria por solo el valor de su fuerte brazo? Pues, ¿qué diremos de la facilidad con que una reina o emperatriz heredera se conduce en los brazos de un andante y no conocido caballero? ¿Qué ingenio, si no es del todo bárbaro e inculto, podrá contentarse leyendo que una gran torre llena de caballeros va por la mar adelante, como nave con próspero viento, y hoy anochece en Lombardía, y mañana amanezca en tierras del Preste Juan de las Indias, o en otras que ni las descubrió Tolomeo ni las vio Marco Polo? Y, si a esto se me respondiese que los que tales libros componen los escriben como cosas de mentira, y que así, no están obligados a mirar en delicadezas ni verdades, responderles hía yo que tanto la mentira es mejor cuanto más parece verdadera, y tanto más agrada cuanto tiene más de lo dudoso y posible. Hanse de casar las fábulas mentirosas con el entendimiento de los que las leyeren, escribiéndose de suerte que, facilitando los imposibles, allanando las grandezas, suspendiendo los ánimos, admiren, suspendan, alborocen y entretengan, de modo que anden a un mismo paso la admiración y la alegría juntas; y todas estas cosas no podrá hacer el que huyere de la verisimilitud y de la imitación, en quien consiste la perfeción de lo que se escribe. No he visto ningún libro de caballerías que haga un cuerpo de fábula entero con todos sus miembros, de manera que el medio corresponda al principio, y el fin al principio y al medio; sino que los componen con tantos miembros, que más parece que llevan intención a formar una quimera o un monstruo que a hacer una figura proporcionada. Fuera desto, son en el estilo duros; en las hazañas, increíbles; en los amores, lascivos; en las cortesías, mal mirados; largos en las batallas, necios en las razones, disparatados en los viajes, y, finalmente, ajenos de todo discreto artificio, y por esto dignos de ser desterrados de la república cristiana, como a gente inútil. El cura le estuvo escuchando con grande atención, y parecióle hombre de buen entendimiento, y que tenía razón en cuanto decía; y así, le dijo que, por ser él de su mesma opinión y tener ojeriza a los libros de caballerías, había quemado todos los de don Quijote, que eran muchos. Y contóle el escrutinio que dellos había hecho, y los que había condenado al fuego y dejado con vida, de que no poco se rió el canónigo, y dijo que, con todo cuanto mal había dicho de tales libros, hallaba en ellos una cosa buena: que era el sujeto que ofrecían para que un buen entendimiento pudiese mostrarse en ellos, porque daban largo y espacioso campo por donde sin empacho alguno pudiese correr la pluma, descubriendo naufragios, tormentas, rencuentros y batallas; pintando un capitán valeroso con todas las partes que para ser tal se requieren, mostrándose prudente previniendo las astucias de sus enemigos, y elocuente orador persuadiendo o disuadiendo a sus soldados, maduro en el consejo, presto en lo determinado, tan valiente en el esperar como en el acometer; pintando ora un lamentable y trágico suceso, ahora un alegre y no pensado acontecimiento; allí una hermosísima dama, honesta, discreta y recatada; aquí un caballero cristiano, valiente y comedido; acullá un desaforado bárbaro fanfarrón; acá un príncipe cortés, valeroso y bien mirado; representando bondad y lealtad de vasallos, grandezas y mercedes de señores. Ya puede mostrarse astrólogo, ya cosmógrafo excelente, ya músico, ya inteligente en las materias de estado, y tal vez le vendrá ocasión de mostrarse nigromante, si quisiere. Puede mostrar las astucias de Ulixes, la piedad de Eneas, la valentía de Aquiles, las desgracias de Héctor, las traiciones de Sinón, la amistad de Eurialio, la liberalidad de Alejandro, el valor de César, la clemencia y verdad de Trajano, la fidelidad de Zopiro, la prudencia de Catón; y, finalmente, todas aquellas acciones que pueden hacer perfecto a un varón ilustre, ahora poniéndolas en uno solo, ahora dividiéndolas en muchos. -Y, siendo esto hecho con apacibilidad de estilo y con ingeniosa invención, que tire lo más que fuere posible a la verdad, sin duda compondrá una tela de varios y hermosos lazos tejida, que, después de acabada, tal perfeción y hermosura muestre, que consiga el fin mejor que se pretende en los escritos, que es enseñar y deleitar juntamente, como ya tengo dicho. Porque la escritura desatada destos libros da lugar a que el autor pueda mostrarse épico, lírico, trágico, cómico, con todas aquellas partes que encierran en sí las dulcísimas y agradables ciencias de la poesía y de la oratoria; que la épica también puede escrebirse en prosa como en verso. Capítulo XLVIII. Donde prosigue el canónigo la materia de los libros de caballerías, con otras cosas dignas de su ingenio -Así es como vuestra merced dice, señor canónigo -dijo el cura-, y por esta causa son más dignos de reprehensión los que hasta aquí han compuesto semejantes libros sin tener advertencia a ningún buen discurso, ni al arte y reglas por donde pudieran guiarse y hacerse famosos en prosa, como lo son en verso los dos príncipes de la poesía griega y latina. -Yo, a lo menos -replicó el canónigo-, he tenido cierta tentación de hacer un libro de caballerías, guardando en él todos los puntos que he significado; y si he de confesar la verdad, tengo escritas más de cien hojas. Y para hacer la experiencia de si correspondían a mi estimación, las he comunicado con hombres apasionados desta leyenda, dotos y discretos, y con otros ignorantes, que sólo atienden al gusto de oír disparates, y de todos he hallado una agradable aprobación; pero, con todo esto, no he proseguido adelante, así por parecerme que hago cosa ajena de mi profesión, como por ver que es más el número de los simples que de los prudentes; y que, puesto que es mejor ser loado de los pocos sabios que burlado de los muchos necios, no quiero sujetarme al confuso juicio del desvanecido vulgo, a quien por la mayor parte toca leer semejantes libros. Pero lo que más me le quitó de las manos, y aun del pensamiento, de acabarle, fue un argumento que hice conmigo mesmo, sacado de las comedias que ahora se representa, diciendo: ''Si estas que ahora se usan, así las imaginadas como las de historia, todas o las más son conocidos disparates y cosas que no llevan pies ni cabeza, y, con todo eso, el vulgo las oye con gusto, y las tiene y las aprueba por buenas, estando tan lejos de serlo, y los autores que las componen y los actores que las representan dicen que así han de ser, porque así las quiere el vulgo, y no de otra manera; y que las que llevan traza y siguen la fábula como el arte pide, no sirven sino para cuatro discretos que las entienden, y todos los demás se quedan ayunos de entender su artificio, y que a ellos les está mejor ganar de comer con los muchos, que no opinión con los pocos, deste modo vendrá a ser un libro, al cabo de haberme quemado las cejas por guardar los preceptos referidos, y vendré a ser el sastre del cantillo''. Y, aunque algunas veces he procurado persuadir a los actores que se engañan en tener la opinión que tienen, y que más gente atraerán y más fama cobrarán representando comedias que hagan el arte que no con las disparatadas, y están tan asidos y encorporados en su parecer, que no hay razón ni evidencia que dél los saque. Acuérdome que un día dije a uno destos pertinaces: ''Decidme, ¿no os acordáis que ha pocos años que se representaron en España tres tragedias que compuso un famoso poeta destos reinos, las cuales fueron tales, que admiraron, alegraron y suspendieron a todos cuantos las oyeron, así simples como prudentes, así del vulgo como de los escogidos, y dieron más dineros a los representantes ellas tres solas que treinta de las mejores que después acá se han hecho?'' ''Sin duda -respondió el autor que digo-, que debe de decir vuestra merced por La Isabela, La Filis y La Alejandra''. ''Por ésas digo -le repliqué yo-; y mirad si guardaban bien los preceptos del arte, y si por guardarlos dejaron de parecer lo que eran y de agradar a todo el mundo. Así que no está la falta en el vulgo, que pide disparates, sino en aquellos que no saben representar otra cosa. Sí, que no fue disparate La ingratitud vengada, ni le tuvo La Numancia, ni se le halló en la del Mercader amante, ni menos en La enemiga favorable, ni en otras algunas que de algunos entendidos poetas han sido compuestas, para fama y renombre suyo, y para ganancia de los que las han representado''. Y otras cosas añadí a éstas, con que, a mi parecer, le dejé algo confuso, pero no satisfecho ni convencido para sacarle de su errado pensamiento. -En materia ha tocado vuestra merced, señor canónigo -dijo a esta sazón el cura-, que ha despertado en mí un antiguo rancor que tengo con las comedias que agora se usan, tal, que iguala al que tengo con los libros de caballerías; porque, habiendo de ser la comedia, según le parece a Tulio, espejo de la vida humana, ejemplo de las costumbres y imagen de la verdad, las que ahora se representan son espejos de disparates, ejemplos de necedades e imágenes de lascivia. Porque, ¿qué mayor disparate puede ser en el sujeto que tratamos que salir un niño en mantillas en la primera cena del primer acto, y en la segunda salir ya hecho hombre barbado? Y ¿qué mayor que pintarnos un viejo valiente y un mozo cobarde, un lacayo rectórico, un paje consejero, un rey ganapán y una princesa fregona? ¿Qué diré, pues, de la observancia que guardan en los tiempos en que pueden o podían suceder las acciones que representan, sino que he visto comedia que la primera jornada comenzó en Europa, la segunda en Asia, la tercera se acabó en Africa, y ansí fuera de cuatro jornadas, la cuarta acababa en América, y así se hubiera hecho en todas las cuatro partes del mundo? Y si es que la imitación es lo principal que ha de tener la comedia, ¿cómo es posible que satisfaga a ningún mediano entendimiento que, fingiendo una acción que pasa en tiempo del rey Pepino y Carlomagno, el mismo que en ella hace la persona principal le atribuyan que fue el emperador Heraclio, que entró con la Cruz en Jerusalén, y el que ganó la Casa Santa, como Godofre de Bullón, habiendo infinitos años de lo uno a lo otro; y fundándose la comedia sobre cosa fingida, atribuirle verdades de historia, y mezclarle pedazos de otras sucedidas a diferentes personas y tiempos, y esto, no con trazas verisímiles, sino con patentes errores de todo punto inexcusables? Y es lo malo que hay ignorantes que digan que esto es lo perfecto, y que lo demás es buscar gullurías. Pues, ¿qué si venimos a las comedias divinas?: ¡qué de milagros falsos fingen en ellas, qué de cosas apócrifas y mal entendidas, atribuyendo a un santo los milagros de otro! Y aun en las humanas se atreven a hacer milagros, sin más respeto ni consideración que parecerles que allí estará bien el tal milagro y apariencia, como ellos llaman, para que gente ignorante se admire y venga a la comedia; que todo esto es en perjuicio de la verdad y en menoscabo de las historias, y aun en oprobrio de los ingenios españoles; porque los estranjeros, que con mucha puntualidad guardan las leyes de la comedia, nos tienen por bárbaros e ignorantes, viendo los absurdos y disparates de las que hacemos. Y no sería bastante disculpa desto decir que el principal intento que las repúblicas bien ordenadas tienen, permitiendo que se hagan públicas comedias, es para entretener la comunidad con alguna honesta recreación, y divertirla a veces de los malos humores que suele engendrar la ociosidad; y que, pues éste se consigue con cualquier comedia, buena o mala, no hay para qué poner leyes, ni estrechar a los que las componen y representan a que las hagan como debían hacerse, pues, como he dicho, con cualquiera se consigue lo que con ellas se pretende. A lo cual respondería yo que este fin se conseguiría mucho mejor, sin comparación alguna, con las comedias buenas que con las no tales; porque, de haber oído la comedia artificiosa y bien ordenada, saldría el oyente alegre con las burlas, enseñado con las veras, admirado de los sucesos, discreto con las razones, advertido con los embustes, sagaz con los ejemplos, airado contra el vicio y enamorado de la virtud; que todos estos afectos ha de despertar la buena comedia en el ánimo del que la escuchare, por rústico y torpe que sea; y de toda imposibilidad es imposible dejar de alegrar y entretener, satisfacer y contentar, la comedia que todas estas partes tuviere mucho más que aquella que careciere dellas, como por la mayor parte carecen estas que de ordinario agora se representan. Y no tienen la culpa desto los poetas que las componen, porque algunos hay dellos que conocen muy bien en lo que yerran, y saben estremadamente lo que deben hacer; pero, como las comedias se han hecho mercadería vendible, dicen, y dicen verdad, que los representantes no se las comprarían si no fuesen de aquel jaez; y así, el poeta procura acomodarse con lo que el representante que le ha de pagar su obra le pide. Y que esto sea verdad véase por muchas e infinitas comedias que ha compuesto un felicísimo ingenio destos reinos, con tanta gala, con tanto donaire, con tan elegante verso, con tan buenas razones, con tan graves sentencias y, finalmente, tan llenas de elocución y alteza de estilo, que tiene lleno el mundo de su fama. Y, por querer acomodarse al gusto de los representantes, no han llegado todas, como han llegado algunas, al punto de la perfección que requieren. Otros las componen tan sin mirar lo que hacen, que después de representadas tienen necesidad los recitantes de huirse y ausentarse, temerosos de ser castigados, como lo han sido muchas veces, por haber representado cosas en perjuicio de algunos reyes y en deshonra de algunos linajes. Y todos estos inconvinientes cesarían, y aun otros muchos más que no digo, con que hubiese en la Corte una persona inteligente y discreta que examinase todas las comedias antes que se representasen (no sólo aquellas que se hiciesen en la Corte, sino todas las que se quisiesen representar en España), sin la cual aprobación, sello y firma, ninguna justicia en su lugar dejase representar comedia alguna; y, desta manera, los comediantes tendrían cuidado de enviar las comedias a la Corte, y con seguridad podrían representallas, y aquellos que las componen mirarían con más cuidado y estudio lo que hacían, temorosos de haber de pasar sus obras por el riguroso examen de quien lo entiende; y desta manera se harían buenas comedias y se conseguiría felicísimamente lo que en ellas se pretende: así el entretenimiento del pueblo, como la opinión de los ingenios de España, el interés y seguridad de los recitantes y el ahorro del cuidado de castigallos. Y si diese cargo a otro, o a este mismo, que examinase los libros de caballerías que de nuevo se compusiesen, sin duda podrían salir algunos con la perfección que vuestra merced ha dicho, enriqueciendo nuestra lengua del agradable y precioso tesoro de la elocuencia, dando ocasión que los libros viejos se escureciesen a la luz de los nuevos que saliesen, para honesto pasatiempo, no solamente de los ociosos, sino de los más ocupados; pues no es posible que esté continuo el arco armado, ni la condición y flaqueza humana se pueda sustentar sin alguna lícita recreación. A este punto de su coloquio llegaban el canónigo y el cura, cuando, adelantándose el barbero, llegó a ellos, y dijo al cura: -Aquí, señor licenciado, es el lugar que yo dije que era bueno para que, sesteando nosotros, tuviesen los bueyes fresco y abundoso pasto. -Así me lo parece a mí -respondió el cura. Y, diciéndole al canónigo lo que pensaba hacer, él también quiso quedarse con ellos, convidado del sitio de un hermoso valle que a la vista se les ofrecía. Y, así por gozar dél como de la conversación del cura, de quien ya iba aficionado, y por saber más por menudo las hazañas de don Quijote, mandó a algunos de sus criados que se fuesen a la venta, que no lejos de allí estaba, y trujesen della lo que hubiese de comer, para todos, porque él determinaba de sestear en aquel lugar aquella tarde; a lo cual uno de sus criados respondió que el acémila del repuesto, que ya debía de estar en la venta, traía recado bastante para no obligar a no tomar de la venta más que cebada. -Pues así es -dijo el canónigo-, llévense allá todas las cabalgaduras, y haced volver la acémila. En tanto que esto pasaba, viendo Sancho que podía hablar a su amo sin la continua asistencia del cura y el barbero, que tenía por sospechosos, se llegó a la jaula donde iba su amo, y le dijo: -Señor, para descargo de mi conciencia, le quiero decir lo que pasa cerca de su encantamento; y es que aquestos dos que vienen aquí cubiertos los rostros son el cura de nuestro lugar y el barbero; y imagino han dado esta traza de llevalle desta manera, de pura envidia que tienen como vuestra merced se les adelanta en hacer famosos hechos. Presupuesta, pues, esta verdad, síguese que no va encantado, sino embaído y tonto. Para prueba de lo cual le quiero preguntar una cosa; y si me responde como creo que me ha de responder, tocará con la mano este engaño y verá como no va encantado, sino trastornado el juicio. -Pregunta lo que quisieres, hijo Sancho -respondió don Quijote-, que yo te satisfaré y responderé a toda tu voluntad. Y en lo que dices que aquellos que allí van y vienen con nosotros son el cura y el barbero, nuestros compatriotos y conocidos, bien podrá ser que parezca que son ellos mesmos; pero que lo sean realmente y en efeto, eso no lo creas en ninguna manera. Lo que has de creer y entender es que si ellos se les parecen, como dices, debe de ser que los que me han encantado habrán tomado esa apariencia y semejanza; porque es fácil a los encantadores tomar la figura que se les antoja, y habrán tomado las destos nuestros amigos, para darte a ti ocasión de que pienses lo que piensas, y ponerte en un laberinto de imaginaciones, que no aciertes a salir dél, aunque tuvieses la soga de Teseo. Y también lo habrán hecho para que yo vacile en mi entendimiento, y no sepa atinar de dónde me viene este daño; porque si, por una parte, tú me dices que me acompañan el barbero y el cura de nuestro pueblo, y, por otra, yo me veo enjaulado, y sé de mí que fuerzas humanas, como no fueran sobrenaturales, no fueran bastantes para enjaularme, ¿qué quieres que diga o piense sino que la manera de mi encantamento excede a cuantas yo he leído en todas las historias que tratan de caballeros andantes que han sido encantados? Ansí que, bien puedes darte paz y sosiego en esto de creer que son los que dices, porque así son ellos como yo soy turco. Y, en lo que toca a querer preguntarme algo, di, que yo te responderé, aunque me preguntes de aquí a mañana. -¡Válame Nuestra Señora! -respondió Sancho, dando una gran voz-. Y ¿es posible que sea vuestra merced tan duro de celebro, y tan falto de meollo, que no eche de ver que es pura verdad la que le digo, y que en esta su prisión y desgracia tiene más parte la malicia que el encanto? Pero, pues así es, yo le quiero probar evidentemente como no va encantado. Si no, dígame, así Dios le saque desta tormenta, y así se vea en los brazos de mi señora Dulcinea cuando menos se piense... -Acaba de conjurarme -dijo don Quijote-, y pregunta lo que quisieres; que ya te he dicho que te responderé con toda puntualidad. -Eso pido -replicó Sancho-; y lo que quiero saber es que me diga, sin añadir ni quitar cosa ninguna, sino con toda verdad, como se espera que la han de decir y la dicen todos aquellos que profesan las armas, como vuestra merced las profesa, debajo de título de caballeros andantes... -Digo que no mentiré en cosa alguna -respondió don Quijote-. Acaba ya de preguntar, que en verdad que me cansas con tantas salvas, plegarias y prevenciones, Sancho. -Digo que yo estoy seguro de la bondad y verdad de mi amo; y así, porque hace al caso a nuestro cuento, pregunto, hablando con acatamiento, si acaso después que vuestra merced va enjaulado y, a su parecer, encantado en esta jaula, le ha venido gana y voluntad de hacer aguas mayores o menores, como suele decirse. -No entiendo eso de hacer aguas, Sancho; aclárate más, si quieres que te responda derechamente. -¿Es posible que no entiende vuestra merced de hacer aguas menores o mayores? Pues en la escuela destetan a los muchachos con ello. Pues sepa que quiero decir si le ha venido gana de hacer lo que no se escusa. -¡Ya, ya te entiendo, Sancho! Y muchas veces; y aun agora la tengo. ¡Sácame deste peligro, que no anda todo limpio! Capítulo XLIX. Donde se trata del discreto coloquio que Sancho Panza tuvo con su señor don Quijote -¡Ah -dijo Sancho-; cogido le tengo! Esto es lo que yo deseaba saber, como al alma y como a la vida. Venga acá, señor: ¿podría negar lo que comúnmente suele decirse por ahí cuando una persona está de mala voluntad: "No sé qué tiene fulano, que ni come, ni bebe, ni duerme, ni responde a propósito a lo que le preguntan, que no parece sino que está encantado"? De donde se viene a sacar que los que no comen, ni beben, ni duermen, ni hacen las obras naturales que yo digo, estos tales están encantados; pero no aquellos que tienen la gana que vuestra merced tiene y que bebe cuando se lo dan, y come cuando lo tiene, y responde a todo aquello que le preguntan. -Verdad dices, Sancho -respondió don Quijote-, pero ya te he dicho que hay muchas maneras de encantamentos, y podría ser que con el tiempo se hubiesen mudado de unos en otros, y que agora se use que los encantados hagan todo lo que yo hago, aunque antes no lo hacían. De manera que contra el uso de los tiempos no hay que argüir ni de qué hacer consecuencias. Yo sé y tengo para mí que voy encantado, y esto me basta para la seguridad de mi conciencia; que la formaría muy grande si yo pensase que no estaba encantado y me dejase estar en esta jaula, perezoso y cobarde, defraudando el socorro que podría dar a muchos menesterosos y necesitados que de mi ayuda y amparo deben tener a la hora de ahora precisa y estrema necesidad. -Pues, con todo eso -replicó Sancho-, digo que, para mayor abundancia y satisfación, sería bien que vuestra merced probase a salir desta cárcel, que yo me obligo con todo mi poder a facilitarlo, y aun a sacarle della, y probase de nuevo a subir sobre su buen Rocinante, que también parece que va encantado, según va de malencólico y triste; y, hecho esto, probásemos otra vez la suerte de buscar más aventuras; y si no nos sucediese bien, tiempo nos queda para volvernos a la jaula, en la cual prometo, a ley de buen y leal escudero, de encerrarme juntamente con vuestra merced, si acaso fuere vuestra merced tan desdichado, o yo tan simple, que no acierte a salir con lo que digo. -Yo soy contento de hacer lo que dices, Sancho hermano -replicó don Quijote-; y cuando tú veas coyuntura de poner en obra mi libertad, yo te obedeceré en todo y por todo; pero tú, Sancho, verás como te engañas en el conocimiento de mi desgracia. En estas pláticas se entretuvieron el caballero andante y el mal andante escudero, hasta que llegaron donde, ya apeados, los aguardaban el cura, el canónigo y el barbero. Desunció luego los bueyes de la carreta el boyero, y dejólos andar a sus anchuras por aquel verde y apacible sitio, cuya frescura convidaba a quererla gozar, no a las personas tan encantadas como don Quijote, sino a los tan advertidos y discretos como su escudero; el cual rogó al cura que permitiese que su señor saliese por un rato de la jaula, porque si no le dejaban salir, no iría tan limpia aquella prisión como requiría la decencia de un tal caballero como su amo. Entendióle el cura, y dijo que de muy buena gana haría lo que le pedía si no temiera que, en viéndose su señor en libertad, había de hacer de las suyas, y irse donde jamás gentes le viesen. -Yo le fío de la fuga -respondió Sancho. -Y yo y todo -dijo el canónigo-; y más si él me da la palabra, como caballero, de no apartarse de nosotros hasta que sea nuestra voluntad. -Sí doy -respondió don Quijote, que todo lo estaba escuchando-; cuanto más, que el que está encantado, como yo, no tiene libertad para hacer de su persona lo que quisiere, porque el que le encantó le puede hacer que no se mueva de un lugar en tres siglos; y si hubiere huido, le hará volver en volandas. -Y que, pues esto era así, bien podían soltalle, y más, siendo tan en provecho de todos; y del no soltalle les protestaba que no podía dejar de fatigalles el olfato, si de allí no se desviaban. Tomóle la mano el canónigo, aunque las tenía atadas, y, debajo de su buena fe y palabra, le desenjaularon, de que él se alegró infinito y en grande manera de verse fuera de la jaula. Y lo primero que hizo fue estirarse todo el cuerpo, y luego se fue donde estaba Rocinante, y, dándole dos palmadas en las ancas, dijo: -Aún espero en Dios y en su bendita Madre, flor y espejo de los caballos, que presto nos hemos de ver los dos cual deseamos; tú, con tu señor a cuestas; y yo, encima de ti, ejercitando el oficio para que Dios me echó al mundo. Y, diciendo esto, don Quijote se apartó con Sancho en remota parte, de donde vino más aliviado y con más deseos de poner en obra lo que su escudero ordenase. Mirábalo el canónigo, y admirábase de ver la estrañeza de su grande locura, y de que, en cuanto hablaba y respondía, mostraba tener bonísimo entendimiento: solamente venía a perder los estribos, como otras veces se ha dicho, en tratándole de caballería. Y así, movido de compasión, después de haberse sentado todos en la verde yerba, para esperar el repuesto del canónigo, le dijo: -¿Es posible, señor hidalgo, que haya podido tanto con vuestra merced la amarga y ociosa letura de los libros de caballerías, que le hayan vuelto el juicio de modo que venga a creer que va encantado, con otras cosas deste jaez, tan lejos de ser verdaderas como lo está la mesma mentira de la verdad? Y ¿cómo es posible que haya entendimiento humano que se dé a entender que ha habido en el mundo aquella infinidad de Amadises, y aquella turbamulta de tanto famoso caballero, tanto emperador de Trapisonda, tanto Felixmarte de Hircania, tanto palafrén, tanta doncella andante, tantas sierpes, tantos endriagos, tantos gigantes, tantas inauditas aventuras, tanto género de encantamentos, tantas batallas, tantos desaforados encuentros, tanta bizarría de trajes, tantas princesas enamoradas, tantos escuderos condes, tantos enanos graciosos, tanto billete, tanto requiebro, tantas mujeres valientes; y, finalmente, tantos y tan disparatados casos como los libros de caballerías contienen? De mí sé decir que, cuando los leo, en tanto que no pongo la imaginación en pensar que son todos mentira y liviandad, me dan algún contento; pero, cuando caigo en la cuenta de lo que son, doy con el mejor dellos en la pared, y aun diera con él en el fuego si cerca o presente le tuviera, bien como a merecedores de tal pena, por ser falsos y embusteros, y fuera del trato que pide la común naturaleza, y como a inventores de nuevas sectas y de nuevo modo de vida, y como a quien da ocasión que el vulgo ignorante venga a creer y a tener por verdaderas tantas necedades como contienen. Y aun tienen tanto atrevimiento, que se atreven a turbar los ingenios de los discretos y bien nacidos hidalgos, como se echa bien de ver por lo que con vuestra merced han hecho, pues le han traído a términos que sea forzoso encerrarle en una jaula, y traerle sobre un carro de bueyes, como quien trae o lleva algún león o algún tigre, de lugar en lugar, para ganar con él dejando que le vean. ¡Ea, señor don Quijote, duélase de sí mismo, y redúzgase al gremio de la discreción, y sepa usar de la mucha que el cielo fue servido de darle, empleando el felicísimo talento de su ingenio en otra letura que redunde en aprovechamiento de su conciencia y en aumento de su honra! Y si todavía, llevado de su natural inclinación, quisiere leer libros de hazañas y de caballerías, lea en la Sacra Escritura el de los Jueces; que allí hallará verdades grandiosas y hechos tan verdaderos como valientes. Un Viriato tuvo Lusitania; un César, Roma; un Anibal, Cartago; un Alejandro, Grecia; un conde Fernán González, Castilla; un Cid, Valencia; un Gonzalo Fernández, Andalucía; un Diego García de Paredes, Estremadura; un Garci Pérez de Vargas, Jerez; un Garcilaso, Toledo; un don Manuel de León, Sevilla, cuya leción de sus valerosos hechos puede entretener, enseñar, deleitar y admirar a los más altos ingenios que los leyeren. Ésta sí será letura digna del buen entendimiento de vuestra merced, señor don Quijote mío, de la cual saldrá erudito en la historia, enamorado de la virtud, enseñado en la bondad, mejorado en las costumbres, valiente sin temeridad, osado sin cobardía, y todo esto, para honra de Dios, provecho suyo y fama de la Mancha; do, según he sabido, trae vuestra merced su principio y origen. Atentísimamente estuvo don Quijote escuchando las razones del canónigo; y, cuando vio que ya había puesto fin a ellas, después de haberle estado un buen espacio mirando, le dijo: -Paréceme, señor hidalgo, que la plática de vuestra merced se ha encaminado a querer darme a entender que no ha habido caballeros andantes en el mundo, y que todos los libros de caballerías son falsos, mentirosos, dañadores e inútiles para la república; y que yo he hecho mal en leerlos, y peor en creerlos, y más mal en imitarlos, habiéndome puesto a seguir la durísima profesión de la caballería andante, que ellos enseñan, negándome que no ha habido en el mundo Amadises, ni de Gaula ni de Grecia, ni todos los otros caballeros de que las escrituras están llenas. -Todo es al pie de la letra como vuestra merced lo va relatando -dijo a está sazón el canónigo. A lo cual respondió don Quijote: -Añadió también vuestra merced, diciendo que me habían hecho mucho daño tales libros, pues me habían vuelto el juicio y puéstome en una jaula, y que me sería mejor hacer la enmienda y mudar de letura, leyendo otros más verdaderos y que mejor deleitan y enseñan. -Así es -dijo el canónigo. -Pues yo -replicó don Quijote- hallo por mi cuenta que el sin juicio y el encantado es vuestra merced, pues se ha puesto a decir tantas blasfemias contra una cosa tan recebida en el mundo, y tenida por tan verdadera, que el que la negase, como vuestra merced la niega, merecía la mesma pena que vuestra merced dice que da a los libros cuando los lee y le enfadan. Porque querer dar a entender a nadie que Amadís no fue en el mundo, ni todos los otros caballeros aventureros de que están colmadas las historias, será querer persuadir que el sol no alumbra, ni el yelo enfría, ni la tierra sustenta; porque, ¿qué ingenio puede haber en el mundo que pueda persuadir a otro que no fue verdad lo de la infanta Floripes y Guy de Borgoña, y lo de Fierabrás con la puente de Mantible, que sucedió en el tiempo de Carlomagno; que voto a tal que es tanta verdad como es ahora de día? Y si es mentira, también lo debe de ser que no hubo Héctor, ni Aquiles, ni la guerra de Troya, ni los Doce Pares de Francia, ni el rey Artús de Ingalaterra, que anda hasta ahora convertido en cuervo y le esperan en su reino por momentos. Y también se atreverán a decir que es mentirosa la historia de Guarino Mezquino, y la de la demanda del Santo Grial, y que son apócrifos los amores de don Tristán y la reina Iseo, como los de Ginebra y Lanzarote, habiendo personas que casi se acuerdan de haber visto a la dueña Quintañona, que fue la mejor escanciadora de vino que tuvo la Gran Bretaña. Y es esto tan ansí, que me acuerdo yo que me decía una mi agüela de partes de mi padre, cuando veía alguna dueña con tocas reverendas: ''Aquélla, nieto, se parece a la dueña Quintañona''; de donde arguyo yo que la debió de conocer ella o, por lo menos, debió de alcanzar a ver algún retrato suyo. Pues, ¿quién podrá negar no ser verdadera la historia de Pierres y la linda Magalona, pues aun hasta hoy día se vee en la armería de los reyes la clavija con que volvía al caballo de madera, sobre quien iba el valiente Pierres por los aires, que es un poco mayor que un timón de carreta? Y junto a la clavija está la silla de Babieca, y en Roncesvalles está el cuerno de Roldán, tamaño como una grande viga: de donde se infiere que hubo Doce Pares, que hubo Pierres, que hubo Cides, y otros caballeros semejantes, déstos que dicen las gentes que a sus aventuras van. Si no, díganme también que no es verdad que fue caballero andante el valiente lusitano Juan de Merlo, que fue a Borgoña y se combatió en la ciudad de Ras con el famoso señor de Charní, llamado mosén Pierres, y después, en la ciudad de Basilea, con mosén Enrique de Remestán, saliendo de entrambas empresas vencedor y lleno de honrosa fama; y las aventuras y desafíos que también acabaron en Borgoña los valientes españoles Pedro Barba y Gutierre Quijada (de cuya alcurnia yo deciendo por línea recta de varón), venciendo a los hijos del conde de San Polo. Niéguenme, asimesmo, que no fue a buscar las aventuras a Alemania don Fernando de Guevara, donde se combatió con micer Jorge, caballero de la casa del duque de Austria; digan que fueron burla las justas de Suero de Quiñones, del Paso; las empresas de mosén Luis de Falces contra don Gonzalo de Guzmán, caballero castellano, con otras muchas hazañas hechas por caballeros cristianos, déstos y de los reinos estranjeros, tan auténticas y verdaderas, que torno a decir que el que las negase carecería de toda razón y buen discurso. Admirado quedó el canónigo de oír la mezcla que don Quijote hacía de verdades y mentiras, y de ver la noticia que tenía de todas aquellas cosas tocantes y concernientes a los hechos de su andante caballería; y así, le respondió: -No puedo yo negar, señor don Quijote, que no sea verdad algo de lo que vuestra merced ha dicho, especialmente en lo que toca a los caballeros andantes españoles; y, asimesmo, quiero conceder que hubo Doce Pares de Francia, pero no quiero creer que hicieron todas aquellas cosas que el arzobispo Turpín dellos escribe; porque la verdad dello es que fueron caballeros escogidos por los reyes de Francia, a quien llamaron pares por ser todos iguales en valor, en calidad y en valentía; a lo menos, si no lo eran, era razón que lo fuesen y era como una religión de las que ahora se usan de Santiago o de Calatrava, que se presupone que los que la profesan han de ser, o deben ser, caballeros valerosos, valientes y bien nacidos; y, como ahora dicen caballero de San Juan, o de Alcántara, decían en aquel tiempo caballero de los Doce Pares, porque no fueron doce iguales los que para esta religión militar se escogieron. En lo de que hubo Cid no hay duda, ni menos Bernardo del Carpio, pero de que hicieron las hazañas que dicen, creo que la hay muy grande. En lo otro de la clavija que vuestra merced dice del conde Pierres, y que está junto a la silla de Babieca en la armería de los reyes, confieso mi pecado; que soy tan ignorante, o tan corto de vista, que, aunque he visto la silla, no he echado de ver la clavija, y más siendo tan grande como vuestra merced ha dicho. -Pues allí está, sin duda alguna -replicó don Quijote-; y, por más señas, dicen que está metida en una funda de vaqueta, porque no se tome de moho. -Todo puede ser -respondió el canónigo-; pero, por las órdenes que recebí, que no me acuerdo haberla visto. Mas, puesto que conceda que está allí, no por eso me obligo a creer las historias de tantos Amadises, ni las de tanta turbamulta de caballeros como por ahí nos cuentan; ni es razón que un hombre como vuestra merced, tan honrado y de tan buenas partes, y dotado de tan buen entendimiento, se dé a entender que son verdaderas tantas y tan estrañas locuras como las que están escritas en los disparatados libros de caballerías. Capítulo L. De las discretas altercaciones que don Quijote y el canónigo tuvieron, con otros sucesos -¡Bueno está eso! -respondió don Quijote-. Los libros que están impresos con licencia de los reyes y con aprobación de aquellos a quien se remitieron, y que con gusto general son leídos y celebrados de los grandes y de los chicos, de los pobres y de los ricos, de los letrados e ignorantes, de los plebeyos y caballeros, finalmente, de todo género de personas, de cualquier estado y condición que sean, ¿habían de ser mentira?; y más llevando tanta apariencia de verdad, pues nos cuentan el padre, la madre, la patria, los parientes, la edad, el lugar y las hazañas, punto por punto y día por día, que el tal caballero hizo, o caballeros hicieron. Calle vuestra merced, no diga tal blasfemia (y créame que le aconsejo en esto lo que debe de hacer como discreto), sino léalos, y verá el gusto que recibe de su leyenda. Si no, dígame: ¿hay mayor contento que ver, como si dijésemos: aquí ahora se muestra delante de nosotros un gran lago de pez hirviendo a borbollones, y que andan nadando y cruzando por él muchas serpientes, culebras y lagartos, y otros muchos géneros de animales feroces y espantables, y que del medio del lago sale una voz tristísima que dice: ''Tú, caballero, quienquiera que seas, que el temeroso lago estás mirando, si quieres alcanzar el bien que debajo destas negras aguas se encubre, muestra el valor de tu fuerte pecho y arrójate en mitad de su negro y encendido licor; porque si así no lo haces, no serás digno de ver las altas maravillas que en sí encierran y contienen los siete castillos de las siete fadas que debajo desta negregura yacen?'' ¿Y que, apenas el caballero no ha acabado de oír la voz temerosa, cuando, sin entrar más en cuentas consigo, sin ponerse a considerar el peligro a que se pone, y aun sin despojarse de la pesadumbre de sus fuertes armas, encomendándose a Dios y a su señora, se arroja en mitad del bullente lago, y, cuando no se cata ni sabe dónde ha de parar, se halla entre unos floridos campos, con quien los Elíseos no tienen que ver en ninguna cosa? Allí le parece que el cielo es más transparente, y que el sol luce con claridad más nueva; ofrécesele a los ojos una apacible floresta de tan verdes y frondosos árboles compuesta, que alegra a la vista su verdura, y entretiene los oídos el dulce y no aprendido canto de los pequeños, infinitos y pintados pajarillos que por los intricados ramos van cruzando. Aquí descubre un arroyuelo, cuyas frescas aguas, que líquidos cristales parecen, corren sobre menudas arenas y blancas pedrezuelas, que oro cernido y puras perlas semejan; acullá vee una artificiosa fuente de jaspe variado y de liso mármol compuesta; acá vee otra a lo brutesco adornada, adonde las menudas conchas de las almejas, con las torcidas casas blancas y amarillas del caracol, puestas con orden desordenada, mezclados entre ellas pedazos de cristal luciente y de contrahechas esmeraldas, hacen una variada labor, de manera que el arte, imitando a la naturaleza, parece que allí la vence. Acullá de improviso se le descubre un fuerte castillo o vistoso alcázar, cuyas murallas son de macizo oro, las almenas de diamantes, las puertas de jacintos; finalmente, él es de tan admirable compostura que, con ser la materia de que está formado no menos que de diamantes, de carbuncos, de rubíes, de perlas, de oro y de esmeraldas, es de más estimación su hechura. Y ¿hay más que ver, después de haber visto esto, que ver salir por la puerta del castillo un buen número de doncellas, cuyos galanos y vistosos trajes, si yo me pusiese ahora a decirlos como las historias nos los cuentan, sería nunca acabar; y tomar luego la que parecía principal de todas por la mano al atrevido caballero que se arrojó en el ferviente lago, y llevarle, sin hablarle palabra, dentro del rico alcázar o castillo, y hacerle desnudar como su madre le parió, y bañarle con templadas aguas, y luego untarle todo con olorosos ungüentos, y vestirle una camisa de cendal delgadísimo, toda olorosa y perfumada, y acudir otra doncella y echarle un mantón sobre los hombros, que, por lo menos menos, dicen que suele valer una ciudad, y aun más? ¿Qué es ver, pues, cuando nos cuentan que, tras todo esto, le llevan a otra sala, donde halla puestas las mesas, con tanto concierto, que queda suspenso y admirado?; ¿qué, el verle echar agua a manos, toda de ámbar y de olorosas flores distilada?; ¿qué, el hacerle sentar sobre una silla de marfil?; ¿qué, verle servir todas las doncellas, guardando un maravilloso silencio?; ¿qué, el traerle tanta diferencia de manjares, tan sabrosamente guisados, que no sabe el apetito a cuál deba de alargar la mano? ¿Cuál será oír la música que en tanto que come suena, sin saberse quién la canta ni adónde suena? ¿Y, después de la comida acabada y las mesas alzadas, quedarse el caballero recostado sobre la silla, y quizá mondándose los dientes, como es costumbre, entrar a deshora por la puerta de la sala otra mucho más hermosa doncella que ninguna de las primeras, y sentarse al lado del caballero, y comenzar a darle cuenta de qué castillo es aquél, y de cómo ella está encantada en él, con otras cosas que suspenden al caballero y admiran a los leyentes que van leyendo su historia? No quiero alargarme más en esto, pues dello se puede colegir que cualquiera parte que se lea, de cualquiera historia de caballero andante, ha de causar gusto y maravilla a cualquiera que la leyere. Y vuestra merced créame, y, como otra vez le he dicho, lea estos libros, y verá cómo le destierran la melancolía que tuviere, y le mejoran la condición, si acaso la tiene mala. De mí sé decir que, después que soy caballero andante, soy valiente, comedido, liberal, bien criado, generoso, cortés, atrevido, blando, paciente, sufridor de trabajos, de prisiones, de encantos; y, aunque ha tan poco que me vi encerrado en una jaula, como loco, pienso, por el valor de mi brazo, favoreciéndome el cielo y no me siendo contraria la fortuna, en pocos días verme rey de algún reino, adonde pueda mostrar el agradecimiento y liberalidad que mi pecho encierra. Que, mía fe, señor, el pobre está inhabilitado de poder mostrar la virtud de liberalidad con ninguno, aunque en sumo grado la posea; y el agradecimiento que sólo consiste en el deseo es cosa muerta, como es muerta la fe sin obras. Por esto querría que la fortuna me ofreciese presto alguna ocasión donde me hiciese emperador, por mostrar mi pecho haciendo bien a mis amigos, especialmente a este pobre de Sancho Panza, mi escudero, que es el mejor hombre del mundo, y querría darle un condado que le tengo muchos días ha prometido, sino que temo que no ha de tener habilidad para gobernar su estado. Casi estas últimas palabras oyó Sancho a su amo, a quien dijo: -Trabaje vuestra merced, señor don Quijote, en darme ese condado, tan prometido de vuestra merced como de mí esperado, que yo le prometo que no me falte a mí habilidad para gobernarle; y, cuando me faltare, yo he oído decir que hay hombres en el mundo que toman en arrendamiento los estados de los señores, y les dan un tanto cada año, y ellos se tienen cuidado del gobierno, y el señor se está a pierna tendida, gozando de la renta que le dan, sin curarse de otra cosa; y así haré yo, y no repararé en tanto más cuanto, sino que luego me desistiré de todo, y me gozaré mi renta como un duque, y allá se lo hayan. -Eso, hermano Sancho -dijo el canónigo-, entiéndese en cuanto al gozar la renta; empero, al administrar justicia, ha de atender el señor del estado, y aquí entra la habilidad y buen juicio, y principalmente la buena intención de acertar; que si ésta falta en los principios, siempre irán errados los medios y los fines; y así suele Dios ayudar al buen deseo del simple como desfavorecer al malo del discreto. -No sé esas filosofías -respondió Sancho Panza-; mas sólo sé que tan presto tuviese yo el condado como sabría regirle; que tanta alma tengo yo como otro, y tanto cuerpo como el que más, y tan rey sería yo de mi estado como cada uno del suyo; y, siéndolo, haría lo que quisiese; y, haciendo lo que quisiese, haría mi gusto; y, haciendo mi gusto, estaría contento; y, en estando uno contento, no tiene más que desear; y, no teniendo más que desear, acabóse; y el estado venga, y a Dios y veámonos, como dijo un ciego a otro. -No son malas filosofías ésas, como tú dices, Sancho; pero, con todo eso, hay mucho que decir sobre esta materia de condados. A lo cual replicó don Quijote: -Yo no sé que haya más que decir; sólo me guío por el ejemplo que me da el grande Amadís de Gaula, que hizo a su escudero conde de la Ãnsula Firme; y así, puedo yo, sin escrúpulo de conciencia, hacer conde a Sancho Panza, que es uno de los mejores escuderos que caballero andante ha tenido. Admirado quedó el canónigo de los concertados disparates que don Quijote había dicho, del modo con que había pintado la aventura del Caballero del Lago, de la impresión que en él habían hecho las pensadas mentiras de los libros que había leído; y, finalmente, le admiraba la necedad de Sancho, que con tanto ahínco deseaba alcanzar el condado que su amo le había prometido. Ya en esto, volvían los criados del canónigo, que a la venta habían ido por la acémila del repuesto, y, haciendo mesa de una alhombra y de la verde yerba del prado, a la sombra de unos árboles se sentaron, y comieron allí, porque el boyero no perdiese la comodidad de aquel sitio, como queda dicho. Y, estando comiendo, a deshora oyeron un recio estruendo y un son de esquila, que por entre unas zarzas y espesas matas que allí junto estaban sonaba, y al mesmo instante vieron salir de entre aquellas malezas una hermosa cabra, toda la piel manchada de negro, blanco y pardo. Tras ella venía un cabrero dándole voces, y diciéndole palabras a su uso, para que se detuviese, o al rebaño volviese. La fugitiva cabra, temerosa y despavorida, se vino a la gente, como a favorecerse della, y allí se detuvo. Llegó el cabrero, y, asiéndola de los cuernos, como si fuera capaz de discurso y entendimiento, le dijo: -¡Ah cerrera, cerrera, Manchada, Manchada, y cómo andáis vos estos días de pie cojo! ¿Qué lobos os espantan, hija? ¿No me diréis qué es esto, hermosa? Mas ¡qué puede ser sino que sois hembra, y no podéis estar sosegada; que mal haya vuestra condición, y la de todas aquellas a quien imitáis! Volved, volved, amiga; que si no tan contenta, a lo menos, estaréis más segura en vuestro aprisco, o con vuestras compañeras; que si vos que las habéis de guardar y encaminar andáis tan sin guía y tan descaminada, ¿en qué podrán parar ellas? Contento dieron las palabras del cabrero a los que las oyeron, especialmente al canónigo, que le dijo: -Por vida vuestra, hermano, que os soseguéis un poco y no os acuciéis en volver tan presto esa cabra a su rebaño; que, pues ella es hembra, como vos decís, ha de seguir su natural distinto, por más que vos os pongáis a estorbarlo. Tomad este bocado y bebed una vez, con que templaréis la cólera, y en tanto, descansará la cabra. Y el decir esto y el darle con la punta del cuchillo los lomos de un conejo fiambre, todo fue uno. Tomólo y agradeciólo el cabrero; bebió y sosegóse, y luego dijo: -No querría que por haber yo hablado con esta alimaña tan en seso, me tuviesen vuestras mercedes por hombre simple; que en verdad que no carecen de misterio las palabras que le dije. Rústico soy, pero no tanto que no entienda cómo se ha de tratar con los hombres y con las bestias. -Eso creo yo muy bien -dijo el cura-, que ya yo sé de esperiencia que los montes crían letrados y las cabañas de los pastores encierran filósofos. -A lo menos, señor -replicó el cabrero-, acogen hombres escarmentados; y para que creáis esta verdad y la toquéis con la mano, aunque parezca que sin ser rogado me convido, si no os enfadáis dello y queréis, señores, un breve espacio prestarme oído atento, os contaré una verdad que acredite lo que ese señor (señalando al cura) ha dicho, y la mía. A esto respondió don Quijote: -Por ver que tiene este caso un no sé qué de sombra de aventura de caballería, yo, por mi parte, os oiré, hermano, de muy buena gana, y así lo harán todos estos señores, por lo mucho que tienen de discretos y de ser amigos de curiosas novedades que suspendan, alegren y entretengan los sentidos, como, sin duda, pienso que lo ha de hacer vuestro cuento. Comenzad, pues, amigo, que todos escucharemos. -Saco la mía -dijo Sancho-; que yo a aquel arroyo me voy con esta empanada, donde pienso hartarme por tres días; porque he oído decir a mi señor don Quijote que el escudero de caballero andante ha de comer, cuando se le ofreciere, hasta no poder más, a causa que se les suele ofrecer entrar acaso por una selva tan intricada que no aciertan a salir della en seis días; y si el hombre no va harto, o bien proveídas las alforjas, allí se podrá quedar, como muchas veces se queda, hecho carne momia. -Tú estás en lo cierto, Sancho -dijo don Quijote-: vete adonde quisieres, y come lo que pudieres; que yo ya estoy satisfecho, y sólo me falta dar al alma su refacción, como se la daré escuchando el cuento deste buen hombre. -Así las daremos todos a las nuestras -dijo el canónigo. Y luego, rogó al cabrero que diese principio a lo que prometido había. El cabrero dio dos palmadas sobre el lomo a la cabra, que por los cuernos tenía, diciéndole: -Recuéstate junto a mí, Manchada, que tiempo nos queda para volver a nuestro apero. Parece que lo entendió la cabra, porque, en sentándose su dueño, se tendió ella junto a él con mucho sosiego, y, mirándole al rostro, daba a entender que estaba atenta a lo que el cabrero iba diciendo, el cual comenzó su historia desta manera: Capítulo LI. Que trata de lo que contó el cabrero a todos los que llevaban a don Quijote -«Tres leguas deste valle está una aldea que, aunque pequeña, es de las más ricas que hay en todos estos contornos; en la cual había un labrador muy honrado, y tanto, que, aunque es anexo al ser rico el ser honrado, más lo era él por la virtud que tenía que por la riqueza que alcanzaba. Mas lo que le hacía más dichoso, según él decía, era tener una hija de tan estremada hermosura, rara discreción, donaire y virtud, que el que la conocía y la miraba se admiraba de ver las estremadas partes con que el cielo y la naturaleza la habían enriquecido. Siendo niña fue hermosa, y siempre fue creciendo en belleza, y en la edad de diez y seis años fue hermosísima. La fama de su belleza se comenzó a estender por todas las circunvecinas aldeas, ¿qué digo yo por las circunvecinas no más, si se estendió a las apartadas ciudades, y aun se entró por las salas de los reyes, y por los oídos de todo género de gente; que, como a cosa rara, o como a imagen de milagros, de todas partes a verla venían? Guardábala su padre, y guardábase ella; que no hay candados, guardas ni cerraduras que mejor guarden a una doncella que las del recato proprio. »La riqueza del padre y la belleza de la hija movieron a muchos, así del pueblo como forasteros, a que por mujer se la pidiesen; mas él, como a quien tocaba disponer de tan rica joya, andaba confuso, sin saber determinarse a quién la entregaría de los infinitos que le importunaban. Y, entre los muchos que tan buen deseo tenían, fui yo uno, a quien dieron muchas y grandes esperanzas de buen suceso conocer que el padre conocía quien yo era, el ser natural del mismo pueblo, limpio en sangre, en la edad floreciente, en la hacienda muy rico y en el ingenio no menos acabado. Con todas estas mismas partes la pidió también otro del mismo pueblo, que fue causa de suspender y poner en balanza la voluntad del padre, a quien parecía que con cualquiera de nosotros estaba su hija bien empleada; y, por salir desta confusión, determinó decírselo a Leandra, que así se llama la rica que en miseria me tiene puesto, advirtiendo que, pues los dos éramos iguales, era bien dejar a la voluntad de su querida hija el escoger a su gusto: cosa digna de imitar de todos los padres que a sus hijos quieren poner en estado: no digo yo que los dejen escoger en cosas ruines y malas, sino que se las propongan buenas, y de las buenas, que escojan a su gusto. No sé yo el que tuvo Leandra; sólo sé que el padre nos entretuvo a entrambos con la poca edad de su hija y con palabras generales, que ni le obligaban, ni nos desobligaba tampoco. Llámase mi competidor Anselmo, y yo Eugenio, porque vais con noticia de los nombres de las personas que en esta tragedia se contienen, cuyo fin aún está pendiente; pero bien se deja entender que será desastrado. »En esta sazón, vino a nuestro pueblo un Vicente de la Rosa, hijo de un pobre labrador del mismo lugar; el cual Vicente venía de las Italias, y de otras diversas partes, de ser soldado. Llevóle de nuestro lugar, siendo muchacho de hasta doce años, un capitán que con su compañía por allí acertó a pasar, y volvió el mozo de allí a otros doce, vestido a la soldadesca, pintado con mil colores, lleno de mil dijes de cristal y sutiles cadenas de acero. Hoy se ponía una gala y mañana otra; pero todas sutiles, pintadas, de poco peso y menos tomo. La gente labradora, que de suyo es maliciosa, y dándole el ocio lugar es la misma malicia, lo notó, y contó punto por punto sus galas y preseas, y halló que los vestidos eran tres, de diferentes colores, con sus ligas y medias; pero él hacía tantos guisados e invenciones dellas, que si no se los contaran, hubiera quien jurara que había hecho muestra de más de diez pares de vestidos y de más de veinte plumajes. Y no parezca impertinencia y demasía esto que de los vestidos voy contando, porque ellos hacen una buena parte en esta historia. »Sentábase en un poyo que debajo de un gran álamo está en nuestra plaza, y allí nos tenía a todos la boca abierta, pendientes de las hazañas que nos iba contando. No había tierra en todo el orbe que no hubiese visto, ni batalla donde no se hubiese hallado; había muerto más moros que tiene Marruecos y Túnez, y entrado en más singulares desafíos, según él decía, que Gante y Luna, Diego García de Paredes y otros mil que nombraba; y de todos había salido con vitoria, sin que le hubiesen derramado una sola gota de sangre. Por otra parte, mostraba señales de heridas que, aunque no se divisaban, nos hacía entender que eran arcabuzazos dados en diferentes rencuentros y faciones. Finalmente, con una no vista arrogancia, llamaba de vos a sus iguales y a los mismos que le conocían, y decía que su padre era su brazo, su linaje, sus obras, y que debajo de ser soldado, al mismo rey no debía nada. Añadiósele a estas arrogancias ser un poco músico y tocar una guitarra a lo rasgado, de manera que decían algunos que la hacía hablar; pero no pararon aquí sus gracias, que también la tenía de poeta, y así, de cada niñería que pasaba en el pueblo, componía un romance de legua y media de escritura. »Este soldado, pues, que aquí he pintado, este Vicente de la Rosa, este bravo, este galán, este músico, este poeta fue visto y mirado muchas veces de Leandra, desde una ventana de su casa que tenía la vista a la plaza. Enamoróla el oropel de sus vistosos trajes, encantáronla sus romances, que de cada uno que componía daba veinte traslados, llegaron a sus oídos las hazañas que él de sí mismo había referido, y, finalmente, que así el diablo lo debía de tener ordenado, ella se vino a enamorar dél, antes que en él naciese presunción de solicitalla. Y, como en los casos de amor no hay ninguno que con más facilidad se cumpla que aquel que tiene de su parte el deseo de la dama, con facilidad se concertaron Leandra y Vicente; y, primero que alguno de sus muchos pretendientes cayesen en la cuenta de su deseo, ya ella le tenía cumplido, habiendo dejado la casa de su querido y amado padre, que madre no la tiene, y ausentádose de la aldea con el soldado, que salió con más triunfo desta empresa que de todas las muchas que él se aplicaba. »Admiró el suceso a toda el aldea, y aun a todos los que dél noticia tuvieron; yo quedé suspenso, Anselmo, atónito, el padre triste, sus parientes afrentados, solícita la justicia, los cuadrilleros listos; tomáronse los caminos, escudriñáronse los bosques y cuanto había, y, al cabo de tres días, hallaron a la antojadiza Leandra en una cueva de un monte, desnuda en camisa, sin muchos dineros y preciosísimas joyas que de su casa había sacado. Volviéronla a la presencia del lastimado padre; preguntáronle su desgracia; confesó sin apremio que Vicente de la Roca la había engañado, y debajo de su palabra de ser su esposo la persuadió que dejase la casa de su padre; que él la llevaría a la más rica y más viciosa ciudad que había en todo el universo mundo, que era Nápoles; y que ella, mal advertida y peor engañada, le había creído; y, robando a su padre, se le entregó la misma noche que había faltado; y que él la llevó a un áspero monte, y la encerró en aquella cueva donde la habían hallado. Contó también como el soldado, sin quitalle su honor, le robó cuanto tenía, y la dejó en aquella cueva y se fue: suceso que de nuevo puso en admiración a todos. »Duro se nos hizo de creer la continencia del mozo, pero ella lo afirmó con tantas veras, que fueron parte para que el desconsolado padre se consolase, no haciendo cuenta de las riquezas que le llevaban, pues le habían dejado a su hija con la joya que, si una vez se pierde, no deja esperanza de que jamás se cobre. El mismo día que pareció Leandra la despareció su padre de nuestros ojos, y la llevó a encerrar en un monesterio de una villa que está aquí cerca, esperando que el tiempo gaste alguna parte de la mala opinión en que su hija se puso. Los pocos años de Leandra sirvieron de disculpa de su culpa, a lo menos con aquellos que no les iba algún interés en que ella fuese mala o buena; pero los que conocían su discreción y mucho entendimiento no atribuyeron a ignorancia su pecado, sino a su desenvoltura y a la natural inclinación de las mujeres, que, por la mayor parte, suele ser desatinada y mal compuesta. »Encerrada Leandra, quedaron los ojos de Anselmo ciegos, a lo menos sin tener cosa que mirar que contento le diese; los míos en tinieblas, sin luz que a ninguna cosa de gusto les encaminase; con la ausencia de Leandra, crecía nuestra tristeza, apocábase nuestra paciencia, maldecíamos las galas del soldado y abominábamos del poco recato del padre de Leandra. Finalmente, Anselmo y yo nos concertamos de dejar el aldea y venirnos a este valle, donde él, apacentando una gran cantidad de ovejas suyas proprias, y yo un numeroso rebaño de cabras, también mías, pasamos la vida entre los árboles, dando vado a nuestras pasiones, o cantando juntos alabanzas o vituperios de la hermosa Leandra, o suspirando solos y a solas comunicando con el cielo nuestras querellas. »A imitación nuestra, otros muchos de los pretendientes de Leandra se han venido a estos ásperos montes, usando el mismo ejercicio nuestro; y son tantos, que parece que este sitio se ha convertido en la pastoral Arcadia, según está colmo de pastores y de apriscos, y no hay parte en él donde no se oiga el nombre de la hermosa Leandra. Éste la maldice y la llama antojadiza, varia y deshonesta; aquél la condena por fácil y ligera; tal la absuelve y perdona, y tal la justicia y vitupera; uno celebra su hermosura, otro reniega de su condición, y, en fin, todos la deshonran, y todos la adoran, y de todos se estiende a tanto la locura, que hay quien se queje de desdén sin haberla jamás hablado, y aun quien se lamente y sienta la rabiosa enfermedad de los celos, que ella jamás dio a nadie; porque, como ya tengo dicho, antes se supo su pecado que su deseo. No hay hueco de peña, ni margen de arroyo, ni sombra de árbol que no esté ocupada de algún pastor que sus desventuras a los aires cuente; el eco repite el nombre de Leandra dondequiera que pueda formarse: Leandra resuenan los montes, Leandra murmuran los arroyos, y Leandra nos tiene a todos suspensos y encantados, esperando sin esperanza y temiendo sin saber de qué tememos. Entre estos disparatados, el que muestra que menos y más juicio tiene es mi competidor Anselmo, el cual, teniendo tantas otras cosas de que quejarse, sólo se queja de ausencia; y al son de un rabel, que admirablemente toca, con versos donde muestra su buen entendimiento, cantando se queja. Yo sigo otro camino más fácil, y a mi parecer el más acertado, que es decir mal de la ligereza de las mujeres, de su inconstancia, de su doble trato, de sus promesas muertas, de su fe rompida, y, finalmente, del poco discurso que tienen en saber colocar sus pensamientos e intenciones que tienen.» Y ésta fue la ocasión, señores, de las palabras y razones que dije a esta cabra cuando aquí llegué; que por ser hembra la tengo en poco, aunque es la mejor de todo mi apero. Ésta es la historia que prometí contaros; si he sido en el contarla prolijo, no seré en serviros corto: cerca de aquí tengo mi majada, y en ella tengo fresca leche y muy sabrosísimo queso, con otras varias y sazonadas frutas, no menos a la vista que al gusto agradables. Capítulo LII. De la pendencia que don Quijote tuvo con el cabrero, con la rara aventura de los deceplinantes, a quien dio felice fin a costa de su sudor General gusto causó el cuento del cabrero a todos los que escuchado le habían; especialmente le recibió el canónigo, que con estraña curiosidad notó la manera con que le había contado, tan lejos de parecer rústico cabrero cuan cerca de mostrarse discreto cortesano; y así, dijo que había dicho muy bien el cura en decir que los montes criaban letrados. Todos se ofrecieron a Eugenio; pero el que más se mostró liberal en esto fue don Quijote, que le dijo: -Por cierto, hermano cabrero, que si yo me hallara posibilitado de poder comenzar alguna aventura, que luego luego me pusiera en camino porque vos la tuviérades buena; que yo sacara del monesterio, donde, sin duda alguna, debe de estar contra su voluntad, a Leandra, a pesar de la abadesa y de cuantos quisieran estorbarlo, y os la pusiera en vuestras manos, para que hiciérades della a toda vuestra voluntad y talante, guardando, pero, las leyes de la caballería, que mandan que a ninguna doncella se le sea fecho desaguisado alguno; aunque yo espero en Dios Nuestro Señor que no ha de poder tanto la fuerza de un encantador malicioso, que no pueda más la de otro encantador mejor intencionado, y para entonces os prometo mi favor y ayuda, como me obliga mi profesión, que no es otra si no es favorecer a los desvalidos y menesterosos. Miróle el cabrero, y, como vio a don Quijote de tan mal pelaje y catadura, admiróse y preguntó al barbero, que cerca de sí tenía: -Señor, ¿quién es este hombre, que tal talle tiene y de tal manera habla? -¿Quién ha de ser -respondió el barbero- sino el famoso don Quijote de la Mancha, desfacedor de agravios, enderezador de tuertos, el amparo de las doncellas, el asombro de los gigantes y el vencedor de las batallas? -Eso me semeja -respondió el cabrero- a lo que se lee en los libros de caballeros andantes, que hacían todo eso que de este hombre vuestra merced dice; puesto que para mí tengo, o que vuestra merced se burla, o que este gentil hombre debe de tener vacíos los aposentos de la cabeza. -Sois un grandísimo bellaco -dijo a esta sazón don Quijote-; y vos sois el vacío y el menguado, que yo estoy más lleno que jamás lo estuvo la muy hideputa puta que os parió. Y, diciendo y haciendo, arrebató de un pan que junto a sí tenía, y dio con él al cabrero en todo el rostro, con tanta furia, que le remachó las narices; mas el cabrero, que no sabía de burlas, viendo con cuántas veras le maltrataban, sin tener respeto a la alhombra, ni a los manteles, ni a todos aquellos que comiendo estaban, saltó sobre don Quijote, y, asiéndole del cuello con entrambas manos, no dudara de ahogalle, si Sancho Panza no llegara en aquel punto, y le asiera por las espaldas y diera con él encima de la mesa, quebrando platos, rompiendo tazas y derramando y esparciendo cuanto en ella estaba. Don Quijote, que se vio libre, acudió a subirse sobre el cabrero; el cual, lleno de sangre el rostro, molido a coces de Sancho, andaba buscando a gatas algún cuchillo de la mesa para hacer alguna sanguinolenta venganza, pero estorbábanselo el canónigo y el cura; mas el barbero hizo de suerte que el cabrero cogió debajo de sí a don Quijote, sobre el cual llovió tanto número de mojicones, que del rostro del pobre caballero llovía tanta sangre como del suyo. Reventaban de risa el canónigo y el cura, saltaban los cuadrilleros de gozo, zuzaban los unos y los otros, como hacen a los perros cuando en pendencia están trabados; sólo Sancho Panza se desesperaba, porque no se podía desasir de un criado del canónigo, que le estorbaba que a su amo no ayudase. En resolución, estando todos en regocijo y fiesta, sino los dos aporreantes que se carpían, oyeron el son de una trompeta, tan triste que les hizo volver los rostros hacia donde les pareció que sonaba; pero el que más se alborotó de oírle fue don Quijote, el cual, aunque estaba debajo del cabrero, harto contra su voluntad y más que medianamente molido, le dijo: -Hermano demonio, que no es posible que dejes de serlo, pues has tenido valor y fuerzas para sujetar las mías, ruégote que hagamos treguas, no más de por una hora; porque el doloroso son de aquella trompeta que a nuestros oídos llega me parece que a alguna nueva aventura me llama. El cabrero, que ya estaba cansado de moler y ser molido, le dejó luego, y don Quijote se puso en pie, volviendo asimismo el rostro adonde el son se oía, y vio a deshora que por un recuesto bajaban muchos hombres vestidos de blanco, a modo de diciplinantes. Era el caso que aquel año habían las nubes negado su rocío a la tierra, y por todos los lugares de aquella comarca se hacían procesiones, rogativas y diciplinas, pidiendo a Dios abriese las manos de su misericordia y les lloviese; y para este efecto la gente de una aldea que allí junto estaba venía en procesión a una devota ermita que en un recuesto de aquel valle había. Don Quijote, que vio los estraños trajes de los diciplinantes, sin pasarle por la memoria las muchas veces que los había de haber visto, se imaginó que era cosa de aventura, y que a él solo tocaba, como a caballero andante, el acometerla; y confirmóle más esta imaginación pensar que una imagen que traían cubierta de luto fuese alguna principal señora que llevaban por fuerza aquellos follones y descomedidos malandrines; y, como esto le cayó en las mientes, con gran ligereza arremetió a Rocinante, que paciendo andaba, quitándole del arzón el freno y el adarga, y en un punto le enfrenó, y, pidiendo a Sancho su espada, subió sobre Rocinante y embrazó su adarga, y dijo en alta voz a todos los que presentes estaban: -Agora, valerosa compañía, veredes cuánto importa que haya en el mundo caballeros que profesen la orden de la andante caballería; agora digo que veredes, en la libertad de aquella buena señora que allí va cautiva, si se han de estimar los caballeros andantes. Y, en diciendo esto, apretó los muslos a Rocinante, porque espuelas no las tenía, y, a todo galope, porque carrera tirada no se lee en toda esta verdadera historia que jamás la diese Rocinante, se fue a encontrar con los diciplinantes, bien que fueran el cura y el canónigo y barbero a detenelle; mas no les fue posible, ni menos le detuvieron las voces que Sancho le daba, diciendo: -¿Adónde va, señor don Quijote? ¿Qué demonios lleva en el pecho, que le incitan a ir contra nuestra fe católica? Advierta, mal haya yo, que aquélla es procesión de diciplinantes, y que aquella señora que llevan sobre la peana es la imagen benditísima de la Virgen sin mancilla; mire, señor, lo que hace, que por esta vez se puede decir que no es lo que sabe. Fatigóse en vano Sancho, porque su amo iba tan puesto en llegar a los ensabanados y en librar a la señora enlutada, que no oyó palabra; y, aunque la oyera, no volviera, si el rey se lo mandara. Llegó, pues, a la procesión, y paró a Rocinante, que ya llevaba deseo de quietarse un poco, y, con turbada y ronca voz, dijo: -Vosotros, que, quizá por no ser buenos, os encubrís los rostros, atended y escuchad lo que deciros quiero. Los primeros que se detuvieron fueron los que la imagen llevaban; y uno de los cuatro clérigos que cantaban las ledanías, viendo la estraña catadura de don Quijote, la flaqueza de Rocinante y otras circunstancias de risa que notó y descubrió en don Quijote, le respondió diciendo: -Señor hermano, si nos quiere decir algo, dígalo presto, porque se van estos hermanos abriendo las carnes, y no podemos, ni es razón que nos detengamos a oír cosa alguna, si ya no es tan breve que en dos palabras se diga. -En una lo diré -replicó don Quijote-, y es ésta: que luego al punto dejéis libre a esa hermosa señora, cuyas lágrimas y triste semblante dan claras muestras que la lleváis contra su voluntad y que algún notorio desaguisado le habedes fecho; y yo, que nací en el mundo para desfacer semejantes agravios, no consentiré que un solo paso adelante pase sin darle la deseada libertad que merece. En estas razones, cayeron todos los que las oyeron que don Quijote debía de ser algún hombre loco, y tomáronse a reír muy de gana; cuya risa fue poner pólvora a la cólera de don Quijote, porque, sin decir más palabra, sacando la espada, arremetió a las andas. Uno de aquellos que las llevaban, dejando la carga a sus compañeros, salió al encuentro de don Quijote, enarbolando una horquilla o bastón con que sustentaba las andas en tanto que descansaba; y, recibiendo en ella una gran cuchillada que le tiró don Quijote, con que se la hizo dos partes, con el último tercio, que le quedó en la mano, dio tal golpe a don Quijote encima de un hombro, por el mismo lado de la espada, que no pudo cubrir el adarga contra villana fuerza, que el pobre don Quijote vino al suelo muy mal parado. Sancho Panza, que jadeando le iba a los alcances, viéndole caído, dio voces a su moledor que no le diese otro palo, porque era un pobre caballero encantado, que no había hecho mal a nadie en todos los días de su vida. Mas, lo que detuvo al villano no fueron las voces de Sancho, sino el ver que don Quijote no bullía pie ni mano; y así, creyendo que le había muerto, con priesa se alzó la túnica a la cinta, y dio a huir por la campaña como un gamo. Ya en esto llegaron todos los de la compañía de don Quijote adonde él estaba; y más los de la procesión, que los vieron venir corriendo, y con ellos los cuadrilleros con sus ballestas, temieron algún mal suceso, y hiciéronse todos un remolino alrededor de la imagen; y, alzados los capirotes, empuñando las diciplinas, y los clérigos los ciriales, esperaban el asalto con determinación de defenderse, y aun ofender, si pudiesen, a sus acometedores; pero la fortuna lo hizo mejor que se pensaba, porque Sancho no hizo otra cosa que arrojarse sobre el cuerpo de su señor, haciendo sobre él el más doloroso y risueño llanto del mundo, creyendo que estaba muerto. El cura fue conocido de otro cura que en la procesión venía, cuyo conocimiento puso en sosiego el concebido temor de los dos escuadrones. El primer cura dio al segundo, en dos razones, cuenta de quién era don Quijote, y así él como toda la turba de los diciplinantes fueron a ver si estaba muerto el pobre caballero, y oyeron que Sancho Panza, con lágrimas en los ojos, decía: -¡Oh flor de la caballería, que con solo un garrotazo acabaste la carrera de tus tan bien gastados años! ¡Oh honra de tu linaje, honor y gloria de toda la Mancha, y aun de todo el mundo, el cual, faltando tú en él, quedará lleno de malhechores, sin temor de ser castigados de sus malas fechorías! ¡Oh liberal sobre todos los Alejandros, pues por solos ocho meses de servicio me tenías dada la mejor ínsula que el mar ciñe y rodea! ¡Oh humilde con los soberbios y arrogante con los humildes, acometedor de peligros, sufridor de afrentas, enamorado sin causa, imitador de los buenos, azote de los malos, enemigo de los ruines, en fin, caballero andante, que es todo lo que decir se puede! Con las voces y gemidos de Sancho revivió don Quijote, y la primer palabra que dijo fue: -El que de vos vive ausente, dulcísima Dulcinea, a mayores miserias que éstas está sujeto. Ayúdame, Sancho amigo, a ponerme sobre el carro encantado, que ya no estoy para oprimir la silla de Rocinante, porque tengo todo este hombro hecho pedazos. -Eso haré yo de muy buena gana, señor mío -respondió Sancho-, y volvamos a mi aldea en compañía destos señores, que su bien desean, y allí daremos orden de hacer otra salida que nos sea de más provecho y fama. -Bien dices, Sancho -respondió don Quijote-, y será gran prudencia dejar pasar el mal influjo de las estrellas que agora corre. El canónigo y el cura y barbero le dijeron que haría muy bien en hacer lo que decía; y así, habiendo recebido grande gusto de las simplicidades de Sancho Panza, pusieron a don Quijote en el carro, como antes venía. La procesión volvió a ordenarse y a proseguir su camino; el cabrero se despidió de todos; los cuadrilleros no quisieron pasar adelante, y el cura les pagó lo que se les debía. El canónigo pidió al cura le avisase el suceso de don Quijote, si sanaba de su locura o si proseguía en ella, y con esto tomó licencia para seguir su viaje. En fin, todos se dividieron y apartaron, quedando solos el cura y barbero, don Quijote y Panza, y el bueno de Rocinante, que a todo lo que había visto estaba con tanta paciencia como su amo. El boyero unció sus bueyes y acomodó a don Quijote sobre un haz de heno, y con su acostumbrada flema siguió el camino que el cura quiso, y a cabo de seis días llegaron a la aldea de don Quijote, adonde entraron en la mitad del día, que acertó a ser domingo, y la gente estaba toda en la plaza, por mitad de la cual atravesó el carro de don Quijote. Acudieron todos a ver lo que en el carro venía, y, cuando conocieron a su compatrioto, quedaron maravillados, y un muchacho acudió corriendo a dar las nuevas a su ama y a su sobrina de que su tío y su señor venía flaco y amarillo, y tendido sobre un montón de heno y sobre un carro de bueyes. Cosa de lástima fue oír los gritos que las dos buenas señoras alzaron, las bofetadas que se dieron, las maldiciones que de nuevo echaron a los malditos libros de caballerías; todo lo cual se renovó cuando vieron entrar a don Quijote por sus puertas. A las nuevas desta venida de don Quijote, acudió la mujer de Sancho Panza, que ya había sabido que había ido con él sirviéndole de escudero, y, así como vio a Sancho, lo primero que le preguntó fue que si venía bueno el asno. Sancho respondió que venía mejor que su amo. -Gracias sean dadas a Dios -replicó ella-, que tanto bien me ha hecho; pero contadme agora, amigo: ¿qué bien habéis sacado de vuestras escuderías?, ¿qué saboyana me traes a mí?, ¿qué zapaticos a vuestros hijos? -No traigo nada deso -dijo Sancho-, mujer mía, aunque traigo otras cosas de más momento y consideración. -Deso recibo yo mucho gusto -respondió la mujer-; mostradme esas cosas de más consideración y más momento, amigo mío, que las quiero ver, para que se me alegre este corazón, que tan triste y descontento ha estado en todos los siglos de vuestra ausencia. -En casa os las mostraré, mujer -dijo Panza-, y por agora estad contenta, que, siendo Dios servido de que otra vez salgamos en viaje a buscar aventuras, vos me veréis presto conde o gobernador de una ínsula, y no de las de por ahí, sino la mejor que pueda hallarse. -Quiéralo así el cielo, marido mío; que bien lo habemos menester. Mas, decidme: ¿qué es eso de ínsulas, que no lo entiendo? -No es la miel para la boca del asno -respondió Sancho-; a su tiempo lo verás, mujer, y aun te admirarás de oírte llamar Señoría de todos tus vasallos. -¿Qué es lo que decís, Sancho, de señorías, ínsulas y vasallos? -respondió Juana Panza, que así se llamaba la mujer de Sancho, aunque no eran parientes, sino porque se usa en la Mancha tomar las mujeres el apellido de sus maridos. -No te acucies, Juana, por saber todo esto tan apriesa; basta que te digo verdad, y cose la boca. Sólo te sabré decir, así de paso, que no hay cosa más gustosa en el mundo que ser un hombre honrado escudero de un caballero andante buscador de aventuras. Bien es verdad que las más que se hallan no salen tan a gusto como el hombre querría, porque de ciento que se encuentran, las noventa y nueve suelen salir aviesas y torcidas. Sélo yo de expiriencia, porque de algunas he salido manteado, y de otras molido; pero, con todo eso, es linda cosa esperar los sucesos atravesando montes, escudriñando selvas, pisando peñas, visitando castillos, alojando en ventas a toda discreción, sin pagar, ofrecido sea al diablo, el maravedí. Todas estas pláticas pasaron entre Sancho Panza y Juana Panza, su mujer, en tanto que el ama y sobrina de don Quijote le recibieron, y le desnudaron, y le tendieron en su antiguo lecho. Mirábalas él con ojos atravesados, y no acababa de entender en qué parte estaba. El cura encargó a la sobrina tuviese gran cuenta con regalar a su tío, y que estuviesen alerta de que otra vez no se les escapase, contando lo que había sido menester para traelle a su casa. Aquí alzaron las dos de nuevo los gritos al cielo; allí se renovaron las maldiciones de los libros de caballerías, allí pidieron al cielo que confundiese en el centro del abismo a los autores de tantas mentiras y disparates. Finalmente, ellas quedaron confusas y temerosas de que se habían de ver sin su amo y tío en el mesmo punto que tuviese alguna mejoría; y sí fue como ellas se lo imaginaron. Pero el autor desta historia, puesto que con curiosidad y diligencia ha buscado los hechos que don Quijote hizo en su tercera salida, no ha podido hallar noticia de ellas, a lo menos por escrituras auténticas; sólo la fama ha guardado, en las memorias de la Mancha, que don Quijote, la tercera vez que salió de su casa, fue a Zaragoza, donde se halló en unas famosas justas que en aquella ciudad hicieron, y allí le pasaron cosas dignas de su valor y buen entendimiento. Ni de su fin y acabamiento pudo alcanzar cosa alguna, ni la alcanzara ni supiera si la buena suerte no le deparara un antiguo médico que tenía en su poder una caja de plomo, que, según él dijo, se había hallado en los cimientos derribados de una antigua ermita que se renovaba; en la cual caja se habían hallado unos pergaminos escritos con letras góticas, pero en versos castellanos, que contenían muchas de sus hazañas y daban noticia de la hermosura de Dulcinea del Toboso, de la figura de Rocinante, de la fidelidad de Sancho Panza y de la sepultura del mesmo don Quijote, con diferentes epitafios y elogios de su vida y costumbres. Y los que se pudieron leer y sacar en limpio fueron los que aquí pone el fidedigno autor desta nueva y jamás vista historia. El cual autor no pide a los que la leyeren, en premio del inmenso trabajo que le costó inquerir y buscar todos los archivos manchegos, por sacarla a luz, sino que le den el mesmo crédito que suelen dar los discretos a los libros de caballerías, que tan validos andan en el mundo; que con esto se tendrá por bien pagado y satisfecho, y se animará a sacar y buscar otras, si no tan verdaderas, a lo menos de tanta invención y pasatiempo. Las palabras primeras que estaban escritas en el pergamino que se halló en la caja de plomo eran éstas: LOS ACADÉMICOS DE LA ARGAMASILLA, LUGAR DE LA MANCHA, EN VIDA Y MUERTE DEL VALEROSO DON QUIJOTE DE LA MANCHA, HOC SCRIPSERUNT: EL MONICONGO, ACADÉMICO DE LA ARGAMASILLA, A LA SEPULTURA DE DON QUIJOTE Epitafio El calvatrueno que adornó a la Mancha de más despojos que Jasón decreta; el jüicio que tuvo la veleta aguda donde fuera mejor ancha, el brazo que su fuerza tanto ensancha, que llegó del Catay hasta Gaeta, la musa más horrenda y más discreta que grabó versos en la broncínea plancha, el que a cola dejó los Amadises, y en muy poquito a Galaores tuvo, estribando en su amor y bizarría, el que hizo callar los Belianises, aquel que en Rocinante errando anduvo, yace debajo desta losa fría. DEL PANIAGUADO, ACADÉMICO DE LA ARGAMASILLA, In laudem Dulcineae del Toboso Soneto Esta que veis de rostro amondongado, alta de pechos y ademán brioso, es Dulcinea, reina del Toboso, de quien fue el gran Quijote aficionado. Pisó por ella el uno y otro lado de la gran Sierra Negra, y el famoso campo de Montïel, hasta el herboso llano de Aranjüez, a pie y cansado. Culpa de Rocinante, ¡oh dura estrella!, que esta manchega dama, y este invito andante caballero, en tiernos años, ella dejó, muriendo, de ser bella; y él, aunque queda en mármores escrito, no pudo huir de amor, iras y engaños. DEL CAPRICHOSO, DISCRETÃSIMO ACADÉMICO DE LA ARGAMASILLA, EN LOOR DE ROCINANTE, CABALLO DE DON QUIJOTE DE LA MANCHA Soneto En el soberbio trono diamantino que con sangrientas plantas huella Marte, frenético, el Manchego su estandarte tremola con esfuerzo peregrino. Cuelga las armas y el acero fino con que destroza, asuela, raja y parte: ¡nuevas proezas!, pero inventa el arte un nuevo estilo al nuevo paladino. Y si de su Amadís se precia Gaula, por cuyos bravos descendientes Grecia triunfó mil veces y su fama ensancha, hoy a Quijote le corona el aula do Belona preside, y dél se precia, más que Grecia ni Gaula, la alta Mancha. Nunca sus glorias el olvido mancha, pues hasta Rocinante, en ser gallardo, excede a Brilladoro y a Bayardo. DEL BURLADOR, ACADÉMICO ARGAMASILLESCO, A SANCHO PANZA Soneto DEL CACHIDIABLO, ACADÉMICO DE LA ARGAMASILLA, EN LA SEPULTURA DE DON QUIJOTE Epitafio Aquí yace el caballero, bien molido y mal andante, a quien llevó Rocinante por uno y otro sendero. Sancho Panza el majadero yace también junto a él, escudero el más fïel que vio el trato de escudero. DEL TIQUITOC, ACADÉMICO DE LA ARGAMASILLA, EN LA SEPULTURA DE DULCINEA DEL TOBOSO Epitafio Reposa aquí Dulcinea; y, aunque de carnes rolliza, la volvió en polvo y ceniza la muerte espantable y fea. Fue de castiza ralea, y tuvo asomos de dama; del gran Quijote fue llama, y fue gloria de su aldea. Éstos fueron los versos que se pudieron leer; los demás, por estar carcomida la letra, se entregaron a un académico para que por conjeturas los declarase. Tiénese noticia que lo ha hecho, a costa de muchas vigilias y mucho trabajo, y que tiene intención de sacallos a luz, con esperanza de la tercera salida de don Quijote. Forsi altro canterà con miglior plectio. Finis Segunda parte del ingenioso caballero don Quijote de la Mancha TASA Yo, Hernando de Vallejo, escribano de Cámara del Rey nuestro señor, de los que residen en su Consejo, doy fe que, habiéndose visto por los señores dél un libro que compuso Miguel de Cervantes Saavedra, intitulado Don Quijote de la Mancha, Segunda parte, que con licencia de Su Majestad fue impreso, le tasaron a cuatro maravedís cada pliego en papel, el cual tiene setenta y tres pliegos, que al dicho respeto suma y monta docientos y noventa y dos maravedís, y mandaron que esta tasa se ponga al principio de cada volumen del dicho libro, para que se sepa y entienda lo que por él se ha de pedir y llevar, sin que se exceda en ello en manera alguna, como consta y parece por el auto y decreto original sobre ello dado, y que queda en mi poder, a que me refiero; y de mandamiento de los dichos señores del Consejo y de pedimiento de la parte del dicho Miguel de Cervantes, di esta fee en Madrid, a veinte y uno días del mes de otubre del mil y seiscientos y quince años. Hernando de Vallejo. FEE DE ERRATAS Vi este libro intitulado Segunda parte de don Quijote de la Mancha, compuesto por Miguel de Cervantes Saavedra, y no hay en él cosa digna de notar que no corresponda a su original. Dada en Madrid, a veinte y uno de otubre, mil y seiscientos y quince. El licenciado Francisco Murcia de la Llana. APROBACIONES APROBACIÓN Por comisión y mandado de los señores del Consejo, he hecho ver el libro contenido en este memorial: no contiene cosa contra la fe ni buenas costumbres, antes es libro de mucho entretenimiento lícito, mezclado de mucha filosofía moral; puédesele dar licencia para imprimirle. En Madrid, a cinco de noviembre de mil seiscientos y quince. Doctor Gutierre de Cetina. APROBACIÓN Por comisión y mandado de los señores del Consejo, he visto la Segunda parte de don Quijote de la Mancha, por Miguel de Cervantes Saavedra: no contiene cosa contra nuestra santa fe católica, ni buenas costumbres, antes, muchas de honesta recreación y apacible divertimiento, que los antiguos juzgaron convenientes a sus repúblicas, pues aun en la severa de los lacedemonios levantaron estatua a la risa, y los de Tesalia la dedicaron fiestas, como lo dice Pausanias, referido de Bosio, libro II De signis Ecclesiae, cap. 10, alentando ánimos marchitos y espíritus melancólicos, de que se acordó Tulio en el primero De legibus, y el poeta diciendo: Interpone tuis interdum gaudia curis, lo cual hace el autor mezclando las veras a las burlas, lo dulce a lo provechoso y lo moral a lo faceto, disimulando en el cebo del donaire el anzuelo de la reprehensión, y cumpliendo con el acertado asunto en que pretende la expulsión de los libros de caballerías, pues con su buena diligencia mañosamente alimpiando de su contagiosa dolencia a estos reinos, es obra muy digna de su grande ingenio, honra y lustre de nuestra nación, admiración y invidia de las estrañas. Éste es mi parecer, salvo etc. En Madrid, a 17 de marzo de 1615. El maestro Josef de Valdivielso. APROBACIÓN Por comisión del señor doctor Gutierre de Cetina, vicario general desta villa de Madrid, corte de Su Majestad, he visto este libro de la Segunda parte del ingenioso caballero don Quijote de la Mancha, por Miguel de Cervantes Saavedra, y no hallo en él cosa indigna de un cristiano celo, ni que disuene de la decencia debida a buen ejemplo, ni virtudes morales; antes, mucha erudición y aprovechamiento, así en la continencia de su bien seguido asunto para extirpar los vanos y mentirosos libros de caballerías, cuyo contagio había cundido más de lo que fuera justo, como en la lisura del lenguaje castellano, no adulterado con enfadosa y estudiada afectación, vicio con razón aborrecido de hombres cuerdos; y en la correción de vicios que generalmente toca, ocasionado de sus agudos discursos, guarda con tanta cordura las leyes de reprehensión cristiana, que aquel que fuere tocado de la enfermedad que pretende curar, en lo dulce y sabroso de sus medicinas gustosamente habrá bebido, cuando menos lo imagine, sin empacho ni asco alguno, lo provechoso de la detestación de su vicio, con que se hallará, que es lo más difícil de conseguirse, gustoso y reprehendido. Ha habido muchos que, por no haber sabido templar ni mezclar a propósito lo útil con lo dulce, han dado con todo su molesto trabajo en tierra, pues no pudiendo imitar a Diógenes en lo filósofo y docto, atrevida, por no decir licenciosa y desalumbradamente, le pretenden imitar en lo cínico, entregándose a maldicientes, inventando casos que no pasaron, para hacer capaz al vicio que tocan de su áspera reprehensión, y por ventura descubren caminos para seguirle, hasta entonces ignorados, con que vienen a quedar, si no reprehensores, a lo menos maestros dél. Hácense odiosos a los bien entendidos, con el pueblo pierden el crédito, si alguno tuvieron, para admitir sus escritos y los vicios que arrojada e imprudentemente quisieren corregir en muy peor estado que antes, que no todas las postemas a un mismo tiempo están dispuestas para admitir las recetas o cauterios; antes, algunos mucho mejor reciben las blandas y suaves medicinas, con cuya aplicación, el atentado y docto médico consigue el fin de resolverlas, término que muchas veces es mejor que no el que se alcanza con el rigor del hierro. Bien diferente han sentido de los escritos de Miguel de Cervantes, así nuestra nación como las estrañas, pues como a milagro desean ver el autor de libros que con general aplauso, así por su decoro y decencia como por la suavidad y blandura de sus discursos, han recebido España, Francia, Italia, Alemania y Flandes. Certifico con verdad que en veinte y cinco de febrero deste año de seiscientos y quince, habiendo ido el ilustrísimo señor don Bernardo de Sandoval y Rojas, cardenal arzobispo de Toledo, mi señor, a pagar la visita que a Su Ilustrísima hizo el embajador de Francia, que vino a tratar cosas tocantes a los casamientos de sus príncipes y los de España, muchos caballeros franceses, de los que vinieron acompañando al embajador, tan corteses como entendidos y amigos de buenas letras, se llegaron a mí y a otros capellanes del cardenal mi señor, deseosos de saber qué libros de ingenio andaban más validos; y, tocando acaso en éste que yo estaba censurando, apenas oyeron el nombre de Miguel de Cervantes, cuando se comenzaron a hacer lenguas, encareciendo la estimación en que, así en Francia como en los reinos sus confinantes, se tenían sus obras: la Galatea, que alguno dellos tiene casi de memoria la primera parte désta, y las Novelas. Fueron tantos sus encarecimientos, que me ofrecí llevarles que viesen el autor dellas, que estimaron con mil demostraciones de vivos deseos. Preguntáronme muy por menor su edad, su profesión, calidad y cantidad. Halléme obligado a decir que era viejo, soldado, hidalgo y pobre, a que uno respondió estas formales palabras: ''Pues, ¿a tal hombre no le tiene España muy rico y sustentado del erario público?'' Acudió otro de aquellos caballeros con este pensamiento y con mucha agudeza, y dijo: ''Si necesidad le ha de obligar a escribir, plega a Dios que nunca tenga abundancia, para que con sus obras, siendo él pobre, haga rico a todo el mundo''. Bien creo que está, para censura, un poco larga; alguno dirá que toca los límites de lisonjero elogio; mas la verdad de lo que cortamente digo deshace en el crítico la sospecha y en mí el cuidado; además que el día de hoy no se lisonjea a quien no tiene con qué cebar el pico del adulador, que, aunque afectuosa y falsamente dice de burlas, pretende ser remunerado de veras. En Madrid, a veinte y siete de febrero de mil y seiscientos y quince. El licenciado Márquez Torres. PRIVILEGIO Por cuanto por parte de vos, Miguel de Cervantes Saavedra, nos fue fecha relación que habíades compuesto la Segunda parte de don Quijote de la Mancha, de la cual hacíades presentación, y, por ser libro de historia agradable y honesta, y haberos costado mucho trabajo y estudio, nos suplicastes os mandásemos dar licencia para le poder imprimir y privilegio por veinte años, o como la nuestra merced fuese; lo cual visto por los del nuestro Consejo, por cuanto en el dicho libro se hizo la diligencia que la premática por nos sobre ello fecha dispone, fue acordado que debíamos mandar dar esta nuestra cédula en la dicha razón, y nos tuvímoslo por bien. Por la cual vos damos licencia y facultad para que, por tiempo y espacio de diez años, cumplidos primeros siguientes, que corran y se cuenten desde el día de la fecha de esta nuestra cédula en adelante, vos, o la persona que para ello vuestro poder hobiere, y no otra alguna, podáis imprimir y vender el dicho libro que desuso se hace mención; y por la presente damos licencia y facultad a cualquier impresor de nuestros reinos que nombráredes para que durante el dicho tiempo le pueda imprimir por el original que en el nuestro Consejo se vio, que va rubricado y firmado al fin de Hernando de Vallejo, nuestro escribano de Cámara, y uno de los que en él residen, con que antes y primero que se venda lo traigáis ante ellos, juntamente con el dicho original, para que se vea si la dicha impresión está conforme a él, o traigáis fe en pública forma cómo, por corretor por nos nombrado, se vio y corrigió la dicha impresión por el dicho original, y más al dicho impresor que ansí imprimiere el dicho libro no imprima el principio y primer pliego dél, ni entregue más de un solo libro con el original al autor y persona a cuya costa lo imprimiere, ni a otra alguna, para efecto de la dicha correción y tasa, hasta que antes y primero el dicho libro esté corregido y tasado por los del nuestro Consejo, y estando hecho, y no de otra manera, pueda imprimir el dicho principio y primer pliego, en el cual imediatamente ponga esta nuestra licencia y la aprobación, tasa y erratas, ni lo podáis vender ni vendáis vos ni otra persona alguna, hasta que esté el dicho libro en la forma susodicha, so pena de caer e incurrir en las penas contenidas en la dicha premática y leyes de nuestros reinos que sobre ello disponen; y más, que durante el dicho tiempo persona alguna sin vuestra licencia no le pueda imprimir ni vender, so pena que el que lo imprimiere y vendiere haya perdido y pierda cualesquiera libros, moldes y aparejos que dél tuviere, y más incurra en pena de cincuenta mil maravedís por cada vez que lo contrario hiciere, de la cual dicha pena sea la tercia parte para nuestra Cámara, y la otra tercia parte para el juez que lo sentenciare, y la otra tercia parte par el que lo denunciare; y más a los del nuestro Consejo, presidentes, oidores de las nuestras Audiencias, alcaldes, alguaciles de la nuestra Casa y Corte y Chancillerías, y a otras cualesquiera justicias de todas las ciudades, villas y lugares de los nuestros reinos y señoríos, y a cada uno en su juridición, ansí a los que agora son como a los que serán de aquí adelante, que vos guarden y cumplan esta nuestra cédula y merced, que ansí vos hacemos, y contra ella no vayan ni pasen en manera alguna, so pena de la nuestra merced y de diez mil maravedís para la nuestra Cámara. Dada en Madrid, a treinta días del mes de marzo de mil y seiscientos y quince años. YO, EL REY. Por mandado del Rey nuestro señor: Pedro de Contreras. PRÓLOGO AL LECTOR ¡Válame Dios, y con cuánta gana debes de estar esperando ahora, lector ilustre, o quier plebeyo, este prólogo, creyendo hallar en él venganzas, riñas y vituperios del autor del segundo Don Quijote; digo de aquel que dicen que se engendró en Tordesillas y nació en Tarragona! Pues en verdad que no te he dar este contento; que, puesto que los agravios despiertan la cólera en los más humildes pechos, en el mío ha de padecer excepción esta regla. Quisieras tú que lo diera del asno, del mentecato y del atrevido, pero no me pasa por el pensamiento: castíguele su pecado, con su pan se lo coma y allá se lo haya. Lo que no he podido dejar de sentir es que me note de viejo y de manco, como si hubiera sido en mi mano haber detenido el tiempo, que no pasase por mí, o si mi manquedad hubiera nacido en alguna taberna, sino en la más alta ocasión que vieron los siglos pasados, los presentes, ni esperan ver los venideros. Si mis heridas no resplandecen en los ojos de quien las mira, son estimadas, a lo menos, en la estimación de los que saben dónde se cobraron; que el soldado más bien parece muerto en la batalla que libre en la fuga; y es esto en mí de manera, que si ahora me propusieran y facilitaran un imposible, quisiera antes haberme hallado en aquella facción prodigiosa que sano ahora de mis heridas sin haberme hallado en ella. Las que el soldado muestra en el rostro y en los pechos, estrellas son que guían a los demás al cielo de la honra, y al de desear la justa alabanza; y hase de advertir que no se escribe con las canas, sino con el entendimiento, el cual suele mejorarse con los años. He sentido también que me llame invidioso, y que, como a ignorante, me describa qué cosa sea la invidia; que, en realidad de verdad, de dos que hay, yo no conozco sino a la santa, a la noble y bien intencionada; y, siendo esto así, como lo es, no tengo yo de perseguir a ningún sacerdote, y más si tiene por añadidura ser familiar del Santo Oficio; y si él lo dijo por quien parece que lo dijo, engañóse de todo en todo: que del tal adoro el ingenio, admiro las obras y la ocupación continua y virtuosa. Pero, en efecto, le agradezco a este señor autor el decir que mis novelas son más satíricas que ejemplares, pero que son buenas; y no lo pudieran ser si no tuvieran de todo. Paréceme que me dices que ando muy limitado y que me contengo mucho en los términos de mi modestia, sabiendo que no se ha añadir aflición al afligido, y que la que debe de tener este señor sin duda es grande, pues no osa parecer a campo abierto y al cielo claro, encubriendo su nombre, fingiendo su patria, como si hubiera hecho alguna traición de lesa majestad. Si, por ventura, llegares a conocerle, dile de mi parte que no me tengo por agraviado: que bien sé lo que son tentaciones del demonio, y que una de las mayores es ponerle a un hombre en el entendimiento que puede componer y imprimir un libro, con que gane tanta fama como dineros, y tantos dineros cuanta fama; y, para confirmación desto, quiero que en tu buen donaire y gracia le cuentes este cuento: «Había en Sevilla un loco que dio en el más gracioso disparate y tema que dio loco en el mundo. Y fue que hizo un cañuto de caña puntiagudo en el fin, y, en cogiendo algún perro en la calle, o en cualquiera otra parte, con el un pie le cogía el suyo, y el otro le alzaba con la mano, y como mejor podía le acomodaba el cañuto en la parte que, soplándole, le ponía redondo como una pelota; y, en teniéndolo desta suerte, le daba dos palmaditas en la barriga, y le soltaba, diciendo a los circunstantes, que siempre eran muchos: ''¿Pensarán vuestras mercedes ahora que es poco trabajo hinchar un perro?''» ¿Pensará vuestra merced ahora que es poco trabajo hacer un libro? Y si este cuento no le cuadrare, dirásle, lector amigo, éste, que también es de loco y de perro: «Había en Córdoba otro loco, que tenía por costumbre de traer encima de la cabeza un pedazo de losa de mármol, o un canto no muy liviano, y, en topando algún perro descuidado, se le ponía junto, y a plomo dejaba caer sobre él el peso. Amohinábase el perro, y, dando ladridos y aullidos, no paraba en tres calles. Sucedió, pues, que, entre los perros que descargó la carga, fue uno un perro de un bonetero, a quien quería mucho su dueño. Bajó el canto, diole en la cabeza, alzó el grito el molido perro, violo y sintiólo su amo, asió de una vara de medir, y salió al loco y no le dejó hueso sano; y cada palo que le daba decía: ''Perro ladrón, ¿a mi podenco? ¿No viste, cruel, que era podenco mi perro?'' Y, repitiéndole el nombre de podenco muchas veces, envió al loco hecho una alheña. Escarmentó el loco y retiróse, y en más de un mes no salió a la plaza; al cabo del cual tiempo, volvió con su invención y con más carga. Llegábase donde estaba el perro, y, mirándole muy bien de hito en hito, y sin querer ni atreverse a descargar la piedra, decía: ''Este es podenco: ¡guarda!'' En efeto, todos cuantos perros topaba, aunque fuesen alanos, o gozques, decía que eran podencos; y así, no soltó más el canto.» Quizá de esta suerte le podrá acontecer a este historiador: que no se atreverá a soltar más la presa de su ingenio en libros que, en siendo malos, son más duros que las peñas. Dile también que de la amenaza que me hace, que me ha de quitar la ganancia con su libro, no se me da un ardite, que, acomodándome al entremés famoso de La Perendenga, le respondo que me viva el Veinte y cuatro, mi señor, y Cristo con todos. Viva el gran conde de Lemos, cuya cristiandad y liberalidad, bien conocida, contra todos los golpes de mi corta fortuna me tiene en pie, y vívame la suma caridad del ilustrísimo de Toledo, don Bernardo de Sandoval y Rojas, y siquiera no haya emprentas en el mundo, y siquiera se impriman contra mí más libros que tienen letras las Coplas de Mingo Revulgo. Estos dos príncipes, sin que los solicite adulación mía ni otro género de aplauso, por sola su bondad, han tomado a su cargo el hacerme merced y favorecerme; en lo que me tengo por más dichoso y más rico que si la fortuna por camino ordinario me hubiera puesto en su cumbre. La honra puédela tener el pobre, pero no el vicioso; la pobreza puede anublar a la nobleza, pero no escurecerla del todo; pero, como la virtud dé alguna luz de sí, aunque sea por los inconvenientes y resquicios de la estrecheza, viene a ser estimada de los altos y nobles espíritus, y, por el consiguiente, favorecida. Y no le digas más, ni yo quiero decirte más a ti, sino advertirte que consideres que esta segunda parte de Don Quijote que te ofrezco es cortada del mismo artífice y del mesmo paño que la primera, y que en ella te doy a don Quijote dilatado, y, finalmente, muerto y sepultado, porque ninguno se atreva a levantarle nuevos testimonios, pues bastan los pasados y basta también que un hombre honrado haya dado noticia destas discretas locuras, sin querer de nuevo entrarse en ellas: que la abundancia de las cosas, aunque sean buenas, hace que no se estimen, y la carestía, aun de las malas, se estima en algo. Olvídaseme de decirte que esperes el Persiles, que ya estoy acabando, y la segunda parte de Galatea. DEDICATORIA, AL CONDE DE LEMOS Enviando a Vuestra Excelencia los días pasados mis comedias, antes impresas que representadas, si bien me acuerdo, dije que don Quijote quedaba calzadas las espuelas para ir a besar las manos a Vuestra Excelencia; y ahora digo que se las ha calzado y se ha puesto en camino, y si él allá llega, me parece que habré hecho algún servicio a Vuestra Excelencia, porque es mucha la priesa que de infinitas partes me dan a que le envíe para quitar el hámago y la náusea que ha causado otro don Quijote, que, con nombre de segunda parte, se ha disfrazado y corrido por el orbe; y el que más ha mostrado desearle ha sido el grande emperador de la China, pues en lengua chinesca habrá un mes que me escribió una carta con un propio, pidiéndome, o, por mejor decir, suplicándome se le enviase, porque quería fundar un colegio donde se leyese la lengua castellana, y quería que el libro que se leyese fuese el de la historia de don Quijote. Juntamente con esto, me decía que fuese yo a ser el rector del tal colegio. Preguntéle al portador si Su Majestad le había dado para mí alguna ayuda de costa. Respondióme que ni por pensamiento. ''Pues, hermano -le respondí yo-, vos os podéis volver a vuestra China a las diez, o a las veinte, o a las que venís despachado, porque yo no estoy con salud para ponerme en tan largo viaje; además que, sobre estar enfermo, estoy muy sin dineros, y emperador por emperador, y monarca por monarca, en Nápoles tengo al grande conde de Lemos, que, sin tantos titulillos de colegios ni rectorías, me sustenta, me ampara y hace más merced que la que yo acierto a desear''. Con esto le despedí, y con esto me despido, ofreciendo a Vuestra Excelencia los Trabajos de Persiles y Sigismunda, libro a quien daré fin dentro de cuatro meses, Deo volente; el cual ha de ser o el más malo o el mejor que en nuestra lengua se haya compuesto, quiero decir de los de entretenimiento; y digo que me arrepiento de haber dicho el más malo, porque, según la opinión de mis amigos, ha de llegar al estremo de bondad posible. Venga Vuestra Excelencia con la salud que es deseado; que ya estará Persiles para besarle las manos, y yo los pies, como criado que soy de Vuestra Excelencia. De Madrid, último de otubre de mil seiscientos y quince. Criado de Vuestra Excelencia, Miguel de Cervantes Saavedra. Capítulo Primero. De lo que el cura y el barbero pasaron con don Quijote cerca de su enfermedad Cuenta Cide Hamete Benengeli, en la segunda parte desta historia y tercera salida de don Quijote, que el cura y el barbero se estuvieron casi un mes sin verle, por no renovarle y traerle a la memoria las cosas pasadas; pero no por esto dejaron de visitar a su sobrina y a su ama, encargándolas tuviesen cuenta con regalarle, dándole a comer cosas confortativas y apropiadas para el corazón y el celebro, de donde procedía, según buen discurso, toda su mala ventura. Las cuales dijeron que así lo hacían, y lo harían, con la voluntad y cuidado posible, porque echaban de ver que su señor por momentos iba dando muestras de estar en su entero juicio; de lo cual recibieron los dos gran contento, por parecerles que habían acertado en haberle traído encantado en el carro de los bueyes, como se contó en la primera parte desta tan grande como puntual historia, en su último capítulo. Y así, determinaron de visitarle y hacer esperiencia de su mejoría, aunque tenían casi por imposible que la tuviese, y acordaron de no tocarle en ningún punto de la andante caballería, por no ponerse a peligro de descoser los de la herida, que tan tiernos estaban. Visitáronle, en fin, y halláronle sentado en la cama, vestida una almilla de bayeta verde, con un bonete colorado toledano; y estaba tan seco y amojamado, que no parecía sino hecho de carne momia. Fueron dél muy bien recebidos, preguntáronle por su salud, y él dio cuenta de sí y de ella con mucho juicio y con muy elegantes palabras; y en el discurso de su plática vinieron a tratar en esto que llaman razón de estado y modos de gobierno, enmendando este abuso y condenando aquél, reformando una costumbre y desterrando otra, haciéndose cada uno de los tres un nuevo legislador, un Licurgo moderno o un Solón flamante; y de tal manera renovaron la república, que no pareció sino que la habían puesto en una fragua, y sacado otra de la que pusieron; y habló don Quijote con tanta discreción en todas las materias que se tocaron, que los dos esaminadores creyeron indubitadamente que estaba del todo bueno y en su entero juicio. Halláronse presentes a la plática la sobrina y ama, y no se hartaban de dar gracias a Dios de ver a su señor con tan buen entendimiento; pero el cura, mudando el propósito primero, que era de no tocarle en cosa de caballerías, quiso hacer de todo en todo esperiencia si la sanidad de don Quijote era falsa o verdadera, y así, de lance en lance, vino a contar algunas nuevas que habían venido de la corte; y, entre otras, dijo que se tenía por cierto que el Turco bajaba con una poderosa armada, y que no se sabía su designio, ni adónde había de descargar tan gran nublado; y, con este temor, con que casi cada año nos toca arma, estaba puesta en ella toda la cristiandad, y Su Majestad había hecho proveer las costas de Nápoles y Sicilia y la isla de Malta. A esto respondió don Quijote: -Su Majestad ha hecho como prudentísimo guerrero en proveer sus estados con tiempo, porque no le halle desapercebido el enemigo; pero si se tomara mi consejo, aconsejárale yo que usara de una prevención, de la cual Su Majestad la hora de agora debe estar muy ajeno de pensar en ella. Apenas oyó esto el cura, cuando dijo entre sí: -¡Dios te tenga de su mano, pobre don Quijote: que me parece que te despeñas de la alta cumbre de tu locura hasta el profundo abismo de tu simplicidad! Mas el barbero, que ya había dado en el mesmo pensamiento que el cura, preguntó a don Quijote cuál era la advertencia de la prevención que decía era bien se hiciese; quizá podría ser tal, que se pusiese en la lista de los muchos advertimientos impertinentes que se suelen dar a los príncipes. -El mío, señor rapador -dijo don Quijote-, no será impertinente, sino perteneciente. -No lo digo por tanto -replicó el barbero-, sino porque tiene mostrado la esperiencia que todos o los más arbitrios que se dan a Su Majestad, o son imposibles, o disparatados, o en daño del rey o del reino. -Pues el mío -respondió don Quijote- ni es imposible ni disparatado, sino el más fácil, el más justo y el más mañero y breve que puede caber en pensamiento de arbitrante alguno. -Ya tarda en decirle vuestra merced, señor don Quijote -dijo el cura. -No querría -dijo don Quijote- que le dijese yo aquí agora, y amaneciese mañana en los oídos de los señores consejeros, y se llevase otro las gracias y el premio de mi trabajo. -Por mí -dijo el barbero-, doy la palabra, para aquí y para delante de Dios, de no decir lo que vuestra merced dijere a rey ni a roque, ni a hombre terrenal, juramento que aprendí del romance del cura que en el prefacio avisó al rey del ladrón que le había robado las cien doblas y la su mula la andariega. -No sé historias -dijo don Quijote-, pero sé que es bueno ese juramento, en fee de que sé que es hombre de bien el señor barbero. -Cuando no lo fuera -dijo el cura-, yo le abono y salgo por él, que en este caso no hablará más que un mudo, so pena de pagar lo juzgado y sentenciado. -Y a vuestra merced, ¿quién le fía, señor cura? -dijo don Quijote. -Mi profesión -respondió el cura-, que es de guardar secreto. -¡Cuerpo de tal! -dijo a esta sazón don Quijote-. ¿Hay más, sino mandar Su Majestad por público pregón que se junten en la corte para un día señalado todos los caballeros andantes que vagan por España; que, aunque no viniesen sino media docena, tal podría venir entre ellos, que solo bastase a destruir toda la potestad del Turco? Esténme vuestras mercedes atentos, y vayan conmigo. ¿Por ventura es cosa nueva deshacer un solo caballero andante un ejército de docientos mil hombres, como si todos juntos tuvieran una sola garganta, o fueran hechos de alfenique? Si no, díganme: ¿cuántas historias están llenas destas maravillas? ¡Había, en hora mala para mí, que no quiero decir para otro, de vivir hoy el famoso don Belianís, o alguno de los del inumerable linaje de Amadís de Gaula; que si alguno déstos hoy viviera y con el Turco se afrontara, a fee que no le arrendara la ganancia! Pero Dios mirará por su pueblo, y deparará alguno que, si no tan bravo como los pasados andantes caballeros, a lo menos no les será inferior en el ánimo; y Dios me entiende, y no digo más. -¡Ay! -dijo a este punto la sobrina-; ¡que me maten si no quiere mi señor volver a ser caballero andante! A lo que dijo don Quijote: -Caballero andante he de morir, y baje o suba el Turco cuando él quisiere y cuan poderosamente pudiere; que otra vez digo que Dios me entiende. A esta sazón dijo el barbero: -Suplico a vuestras mercedes que se me dé licencia para contar un cuento breve que sucedió en Sevilla, que, por venir aquí como de molde, me da gana de contarle. Dio la licencia don Quijote, y el cura y los demás le prestaron atención, y él comenzó desta manera: -«En la casa de los locos de Sevilla estaba un hombre a quien sus parientes habían puesto allí por falto de juicio. Era graduado en cánones por Osuna, pero, aunque lo fuera por Salamanca, según opinión de muchos, no dejara de ser loco. Este tal graduado, al cabo de algunos años de recogimiento, se dio a entender que estaba cuerdo y en su entero juicio, y con esta imaginación escribió al arzobispo, suplicándole encarecidamente y con muy concertadas razones le mandase sacar de aquella miseria en que vivía, pues por la misericordia de Dios había ya cobrado el juicio perdido; pero que sus parientes, por gozar de la parte de su hacienda, le tenían allí, y, a pesar de la verdad, querían que fuese loco hasta la muerte. »El arzobispo, persuadido de muchos billetes concertados y discretos, mandó a un capellán suyo se informase del retor de la casa si era verdad lo que aquel licenciado le escribía, y que asimesmo hablase con el loco, y que si le pareciese que tenía juicio, le sacase y pusiese en libertad. Hízolo así el capellán, y el retor le dijo que aquel hombre aún se estaba loco: que, puesto que hablaba muchas veces como persona de grande entendimiento, al cabo disparaba con tantas necedades, que en muchas y en grandes igualaban a sus primeras discreciones, como se podía hacer la esperiencia hablándole. Quiso hacerla el capellán, y, poniéndole con el loco, habló con él una hora y más, y en todo aquel tiempo jamás el loco dijo razón torcida ni disparatada; antes, habló tan atentadamente, que el capellán fue forzado a creer que el loco estaba cuerdo; y entre otras cosas que el loco le dijo fue que el retor le tenía ojeriza, por no perder los regalos que sus parientes le hacían porque dijese que aún estaba loco, y con lúcidos intervalos; y que el mayor contrario que en su desgracia tenía era su mucha hacienda, pues, por gozar della sus enemigos, ponían dolo y dudaban de la merced que Nuestro Señor le había hecho en volverle de bestia en hombre. Finalmente, él habló de manera que hizo sospechoso al retor, codiciosos y desalmados a sus parientes, y a él tan discreto que el capellán se determinó a llevársele consigo a que el arzobispo le viese y tocase con la mano la verdad de aquel negocio. »Con esta buena fee, el buen capellán pidió al retor mandase dar los vestidos con que allí había entrado el licenciado; volvió a decir el retor que mirase lo que hacía, porque, sin duda alguna, el licenciado aún se estaba loco. No sirvieron de nada para con el capellán las prevenciones y advertimientos del retor para que dejase de llevarle; obedeció el retor, viendo ser orden del arzobispo; pusieron al licenciado sus vestidos, que eran nuevos y decentes, y, como él se vio vestido de cuerdo y desnudo de loco, suplicó al capellán que por caridad le diese licencia para ir a despedirse de sus compañeros los locos. El capellán dijo que él le quería acompañar y ver los locos que en la casa había. Subieron, en efeto, y con ellos algunos que se hallaron presentes; y, llegado el licenciado a una jaula adonde estaba un loco furioso, aunque entonces sosegado y quieto, le dijo: ''Hermano mío, mire si me manda algo, que me voy a mi casa; que ya Dios ha sido servido, por su infinita bondad y misericordia, sin yo merecerlo, de volverme mi juicio: ya estoy sano y cuerdo; que acerca del poder de Dios ninguna cosa es imposible. Tenga grande esperanza y confianza en Él, que, pues a mí me ha vuelto a mi primero estado, también le volverá a él si en Él confía. Yo tendré cuidado de enviarle algunos regalos que coma, y cómalos en todo caso, que le hago saber que imagino, como quien ha pasado por ello, que todas nuestras locuras proceden de tener los estómagos vacíos y los celebros llenos de aire. Esfuércese, esfuércese, que el descaecimiento en los infortunios apoca la salud y acarrea la muerte''. »Todas estas razones del licenciado escuchó otro loco que estaba en otra jaula, frontero de la del furioso, y, levantándose de una estera vieja donde estaba echado y desnudo en cueros, preguntó a grandes voces quién era el que se iba sano y cuerdo. El licenciado respondió: ''Yo soy, hermano, el que me voy; que ya no tengo necesidad de estar más aquí, por lo que doy infinitas gracias a los cielos, que tan grande merced me han hecho''. ''Mirad lo que decís, licenciado, no os engañe el diablo -replicó el loco-; sosegad el pie, y estaos quedito en vuestra casa, y ahorraréis la vuelta''. ''Yo sé que estoy bueno -replicó el licenciado-, y no habrá para qué tornar a andar estaciones''. ''¿Vos bueno? -dijo el loco-: agora bien, ello dirá; andad con Dios, pero yo os voto a Júpiter, cuya majestad yo represento en la tierra, que por solo este pecado que hoy comete Sevilla, en sacaros desta casa y en teneros por cuerdo, tengo de hacer un tal castigo en ella, que quede memoria dél por todos los siglos del los siglos, amén. ¿No sabes tú, licenciadillo menguado, que lo podré hacer, pues, como digo, soy Júpiter Tonante, que tengo en mis manos los rayos abrasadores con que puedo y suelo amenazar y destruir el mundo? Pero con sola una cosa quiero castigar a este ignorante pueblo, y es con no llover en él ni en todo su distrito y contorno por tres enteros años, que se han de contar desde el día y punto en que ha sido hecha esta amenaza en adelante. ¿Tú libre, tú sano, tú cuerdo, y yo loco, y yo enfermo, y yo atado...? Así pienso llover como pensar ahorcarme''. »A las voces y a las razones del loco estuvieron los circustantes atentos, pero nuestro licenciado, volviéndose a nuestro capellán y asiéndole de las manos, le dijo: ''No tenga vuestra merced pena, señor mío, ni haga caso de lo que este loco ha dicho, que si él es Júpiter y no quisiere llover, yo, que soy Neptuno, el padre y el dios de las aguas, lloveré todas las veces que se me antojare y fuere menester''. A lo que respondió el capellán: ''Con todo eso, señor Neptuno, no será bien enojar al señor Júpiter: vuestra merced se quede en su casa, que otro día, cuando haya más comodidad y más espacio, volveremos por vuestra merced''. Rióse el retor y los presentes, por cuya risa se medio corrió el capellán; desnudaron al licenciado, quedóse en casa y acabóse el cuento.» -Pues, ¿éste es el cuento, señor barbero -dijo don Quijote-, que, por venir aquí como de molde, no podía dejar de contarle? ¡Ah, señor rapista, señor rapista, y cuán ciego es aquel que no vee por tela de cedazo! Y ¿es posible que vuestra merced no sabe que las comparaciones que se hacen de ingenio a ingenio, de valor a valor, de hermosura a hermosura y de linaje a linaje son siempre odiosas y mal recebidas? Yo, señor barbero, no soy Neptuno, el dios de las aguas, ni procuro que nadie me tenga por discreto no lo siendo; sólo me fatigo por dar a entender al mundo en el error en que está en no renovar en sí el felicísimo tiempo donde campeaba la orden de la andante caballería. Pero no es merecedora la depravada edad nuestra de gozar tanto bien como el que gozaron las edades donde los andantes caballeros tomaron a su cargo y echaron sobre sus espaldas la defensa de los reinos, el amparo de las doncellas, el socorro de los huérfanos y pupilos, el castigo de los soberbios y el premio de los humildes. Los más de los caballeros que agora se usan, antes les crujen los damascos, los brocados y otras ricas telas de que se visten, que la malla con que se arman; ya no hay caballero que duerma en los campos, sujeto al rigor del cielo, armado de todas armas desde los pies a la cabeza; y ya no hay quien, sin sacar los pies de los estribos, arrimado a su lanza, sólo procure descabezar, como dicen, el sueño, como lo hacían los caballeros andantes. Ya no hay ninguno que, saliendo deste bosque, entre en aquella montaña, y de allí pise una estéril y desierta playa del mar, las más veces proceloso y alterado, y, hallando en ella y en su orilla un pequeño batel sin remos, vela, mástil ni jarcia alguna, con intrépido corazón se arroje en él, entregándose a las implacables olas del mar profundo, que ya le suben al cielo y ya le bajan al abismo; y él, puesto el pecho a la incontrastable borrasca, cuando menos se cata, se halla tres mil y más leguas distante del lugar donde se embarcó, y, saltando en tierra remota y no conocida, le suceden cosas dignas de estar escritas, no en pergaminos, sino en bronces. Mas agora, ya triunfa la pereza de la diligencia, la ociosidad del trabajo, el vicio de la virtud, la arrogancia de la valentía y la teórica de la práctica de las armas, que sólo vivieron y resplandecieron en las edades del oro y en los andantes caballeros. Si no, díganme: ¿quién más honesto y más valiente que el famoso Amadís de Gaula?; ¿quién más discreto que Palmerín de Inglaterra?; ¿quién más acomodado y manual que Tirante el Blanco?; ¿quién más galán que Lisuarte de Grecia?; ¿quién más acuchillado ni acuchillador que don Belianís?; ¿quién más intrépido que Perión de Gaula, o quién más acometedor de peligros que Felixmarte de Hircania, o quién más sincero que Esplandián?; ¿quién mas arrojado que don Cirongilio de Tracia?; ¿quién más bravo que Rodamonte?; ¿quién más prudente que el rey Sobrino?; ¿quién más atrevido que Reinaldos?; ¿quién más invencible que Roldán?; y ¿quién más gallardo y más cortés que Rugero, de quien decienden hoy los duques de Ferrara, según Turpín en su Cosmografía? Todos estos caballeros, y otros muchos que pudiera decir, señor cura, fueron caballeros andantes, luz y gloria de la caballería. Déstos, o tales como éstos, quisiera yo que fueran los de mi arbitrio, que, a serlo, Su Majestad se hallara bien servido y ahorrara de mucho gasto, y el Turco se quedara pelando las barbas, y con esto, no quiero quedar en mi casa, pues no me saca el capellán della; y si su Júpiter, como ha dicho el barbero, no lloviere, aquí estoy yo, que lloveré cuando se me antojare. Digo esto porque sepa el señor Bacía que le entiendo. -En verdad, señor don Quijote -dijo el barbero-, que no lo dije por tanto, y así me ayude Dios como fue buena mi intención, y que no debe vuestra merced sentirse. -Si puedo sentirme o no -respondió don Quijote-, yo me lo sé. A esto dijo el cura: -Aun bien que yo casi no he hablado palabra hasta ahora, y no quisiera quedar con un escrúpulo que me roe y escarba la conciencia, nacido de lo que aquí el señor don Quijote ha dicho. -Para otras cosas más -respondió don Quijote- tiene licencia el señor cura; y así, puede decir su escrúpulo, porque no es de gusto andar con la conciencia escrupulosa. -Pues con ese beneplácito -respondió el cura-, digo que mi escrúpulo es que no me puedo persuadir en ninguna manera a que toda la caterva de caballeros andantes que vuestra merced, señor don Quijote, ha referido, hayan sido real y verdaderamente personas de carne y hueso en el mundo; antes, imagino que todo es ficción, fábula y mentira, y sueños contados por hombres despiertos, o, por mejor decir, medio dormidos. -Ése es otro error -respondió don Quijote- en que han caído muchos, que no creen que haya habido tales caballeros en el mundo; y yo muchas veces, con diversas gentes y ocasiones, he procurado sacar a la luz de la verdad este casi común engaño; pero algunas veces no he salido con mi intención, y otras sí, sustentándola sobre los hombros de la verdad; la cual verdad es tan cierta, que estoy por decir que con mis propios ojos vi a Amadís de Gaula, que era un hombre alto de cuerpo, blanco de rostro, bien puesto de barba, aunque negra, de vista entre blanda y rigurosa, corto de razones, tardo en airarse y presto en deponer la ira; y del modo que he delineado a Amadís pudiera, a mi parecer, pintar y descubrir todos cuantos caballeros andantes andan en las historias en el orbe, que, por la aprehensión que tengo de que fueron como sus historias cuentan, y por las hazañas que hicieron y condiciones que tuvieron, se pueden sacar por buena filosofía sus faciones, sus colores y estaturas. -¿Que tan grande le parece a vuestra merced, mi señor don Quijote -preguntó el barbero-, debía de ser el gigante Morgante? -En esto de gigantes -respondió don Quijote- hay diferentes opiniones, si los ha habido o no en el mundo; pero la Santa Escritura, que no puede faltar un átomo en la verdad, nos muestra que los hubo, contándonos la historia de aquel filisteazo de Golías, que tenía siete codos y medio de altura, que es una desmesurada grandeza. También en la isla de Sicilia se han hallado canillas y espaldas tan grandes, que su grandeza manifiesta que fueron gigantes sus dueños, y tan grandes como grandes torres; que la geometría saca esta verdad de duda. Pero, con todo esto, no sabré decir con certidumbre qué tamaño tuviese Morgante, aunque imagino que no debió de ser muy alto; y muéveme a ser deste parecer hallar en la historia donde se hace mención particular de sus hazañas que muchas veces dormía debajo de techado; y, pues hallaba casa donde cupiese, claro está que no era desmesurada su grandeza. -Así es -dijo el cura. El cual, gustando de oírle decir tan grandes disparates, le preguntó que qué sentía acerca de los rostros de Reinaldos de Montalbán y de don Roldán, y de los demás Doce Pares de Francia, pues todos habían sido caballeros andantes. -De Reinaldos -respondió don Quijote- me atrevo a decir que era ancho de rostro, de color bermejo, los ojos bailadores y algo saltados, puntoso y colérico en demasía, amigo de ladrones y de gente perdida. De Roldán, o Rotolando, o Orlando, que con todos estos nombres le nombran las historias, soy de parecer y me afirmo que fue de mediana estatura, ancho de espaldas, algo estevado, moreno de rostro y barbitaheño, velloso en el cuerpo y de vista amenazadora; corto de razones, pero muy comedido y bien criado. -Si no fue Roldán más gentilhombre que vuestra merced ha dicho -replicó el cura-, no fue maravilla que la señora Angélica la Bella le desdeñase y dejase por la gala, brío y donaire que debía de tener el morillo barbiponiente a quien ella se entregó; y anduvo discreta de adamar antes la blandura de Medoro que la aspereza de Roldán. -Esa Angélica -respondió don Quijote-, señor cura, fue una doncella destraída, andariega y algo antojadiza, y tan lleno dejó el mundo de sus impertinencias como de la fama de su hermosura: despreció mil señores, mil valientes y mil discretos, y contentóse con un pajecillo barbilucio, sin otra hacienda ni nombre que el que le pudo dar de agradecido la amistad que guardó a su amigo. El gran cantor de su belleza, el famoso Ariosto, por no atreverse, o por no querer cantar lo que a esta señora le sucedió después de su ruin entrego, que no debieron ser cosas demasiadamente honestas, la dejó donde dijo: Y como del Catay recibió el cetro, quizá otro cantará con mejor plectro. Y, sin duda, que esto fue como profecía; que los poetas también se llaman vates, que quiere decir adivinos. Véese esta verdad clara, porque, después acá, un famoso poeta andaluz lloró y cantó sus lágrimas, y otro famoso y único poeta castellano cantó su hermosura. -Dígame, señor don Quijote -dijo a esta sazón el barbero-, ¿no ha habido algún poeta que haya hecho alguna sátira a esa señora Angélica, entre tantos como la han alabado? -Bien creo yo -respondió don Quijote- que si Sacripante o Roldán fueran poetas, que ya me hubieran jabonado a la doncella; porque es propio y natural de los poetas desdeñados y no admitidos de sus damas fingidas -o fingidas, en efeto, de aquéllos a quien ellos escogieron por señoras de sus pensamientos-, vengarse con sátiras y libelos (venganza, por cierto, indigna de pechos generosos), pero hasta agora no ha llegado a mi noticia ningún verso infamatorio contra la señora Angélica, que trujo revuelto el mundo. -¡Milagro! -dijo el cura. Y, en esto, oyeron que la ama y la sobrina, que ya habían dejado la conversación, daban grandes voces en el patio, y acudieron todos al ruido. Capítulo II. Que trata de la notable pendencia que Sancho Panza tuvo con la sobrina y ama de don Quijote, con otros sujetos graciosos Cuenta la historia que las voces que oyeron don Quijote, el cura y el barbero eran de la sobrina y ama, que las daban diciendo a Sancho Panza, que pugnaba por entrar a ver a don Quijote, y ellas le defendían la puerta: -¿Qué quiere este mostrenco en esta casa? Idos a la vuestra, hermano, que vos sois, y no otro, el que destrae y sonsaca a mi señor, y le lleva por esos andurriales. A lo que Sancho respondió: -Ama de Satanás, el sonsacado, y el destraído, y el llevado por esos andurriales soy yo, que no tu amo; él me llevó por esos mundos, y vosotras os engañáis en la mitad del justo precio: él me sacó de mi casa con engañifas, prometiéndome una ínsula, que hasta agora la espero. -Malas ínsulas te ahoguen -respondió la sobrina-, Sancho maldito. Y ¿qué son ínsulas? ¿Es alguna cosa de comer, golosazo, comilón, que tú eres? -No es de comer -replicó Sancho-, sino de gobernar y regir mejor que cuatro ciudades y que cuatro alcaldes de corte. -Con todo eso -dijo el ama-, no entraréis acá, saco de maldades y costal de malicias. Id a gobernar vuestra casa y a labrar vuestros pegujares, y dejaos de pretender ínsulas ni ínsulos. Grande gusto recebían el cura y el barbero de oír el coloquio de los tres; pero don Quijote, temeroso que Sancho se descosiese y desbuchase algún montón de maliciosas necedades, y tocase en puntos que no le estarían bien a su crédito, le llamó, y hizo a las dos que callasen y le dejasen entrar. Entró Sancho, y el cura y el barbero se despidieron de don Quijote, de cuya salud desesperaron, viendo cuán puesto estaba en sus desvariados pensamientos, y cuán embebido en la simplicidad de sus malandantes caballerías; y así, dijo el cura al barbero: -Vos veréis, compadre, cómo, cuando menos lo pensemos, nuestro hidalgo sale otra vez a volar la ribera. No pongo yo duda en eso -respondió el barbero-, pero no me maravillo tanto de la locura del caballero como de la simplicidad del escudero, que tan creído tiene aquello de la ínsula, que creo que no se lo sacarán del casco cuantos desengaños pueden imaginarse. -Dios los remedie -dijo el cura-, y estemos a la mira: veremos en lo que para esta máquina de disparates de tal caballero y de tal escudero, que parece que los forjaron a los dos en una mesma turquesa, y que las locuras del señor, sin las necedades del criado, no valían un ardite. -Así es -dijo el barbero-, y holgara mucho saber qué tratarán ahora los dos. -Yo seguro -respondió el cura- que la sobrina o el ama nos lo cuenta después, que no son de condición que dejarán de escucharlo. En tanto, don Quijote se encerró con Sancho en su aposento; y, estando solos, le dijo: -Mucho me pesa, Sancho, que hayas dicho y digas que yo fui el que te saqué de tus casillas, sabiendo que yo no me quedé en mis casas: juntos salimos, juntos fuimos y juntos peregrinamos; una misma fortuna y una misma suerte ha corrido por los dos: si a ti te mantearon una vez, a mí me han molido ciento, y esto es lo que te llevo de ventaja. -Eso estaba puesto en razón -respondió Sancho-, porque, según vuestra merced dice, más anejas son a los caballeros andantes las desgracias que a sus escuderos. -Engáñaste, Sancho -dijo don Quijote-; según aquello, quando caput dolet..., etcétera. -No entiendo otra lengua que la mía -respondió Sancho. -Quiero decir -dijo don Quijote- que, cuando la cabeza duele, todos los miembros duelen; y así, siendo yo tu amo y señor, soy tu cabeza, y tú mi parte, pues eres mi criado; y, por esta razón, el mal que a mí me toca, o tocare, a ti te ha de doler, y a mí el tuyo. -Así había de ser -dijo Sancho-, pero cuando a mí me manteaban como a miembro, se estaba mi cabeza detrás de las bardas, mirándome volar por los aires, sin sentir dolor alguno; y, pues los miembros están obligados a dolerse del mal de la cabeza, había de estar obligada ella a dolerse dellos. -¿Querrás tú decir agora, Sancho -respondió don Quijote-, que no me dolía yo cuando a ti te manteaban? Y si lo dices, no lo digas, ni lo pienses; pues más dolor sentía yo entonces en mi espíritu que tú en tu cuerpo. Pero dejemos esto aparte por agora, que tiempo habrá donde lo ponderemos y pongamos en su punto, y dime, Sancho amigo: ¿qué es lo que dicen de mí por ese lugar? ¿En qué opinión me tiene el vulgo, en qué los hidalgos y en qué los caballeros? ¿Qué dicen de mi valentía, qué de mis hazañas y qué de mi cortesía? ¿Qué se platica del asumpto que he tomado de resucitar y volver al mundo la ya olvidada orden caballeresca? Finalmente, quiero, Sancho, me digas lo que acerca desto ha llegado a tus oídos; y esto me has de decir sin añadir al bien ni quitar al mal cosa alguna, que de los vasallos leales es decir la verdad a sus señores en su ser y figura propia, sin que la adulación la acreciente o otro vano respeto la disminuya; y quiero que sepas, Sancho, que si a los oídos de los príncipes llegase la verdad desnuda, sin los vestidos de la lisonja, otros siglos correrían, otras edades serían tenidas por más de hierro que la nuestra, que entiendo que, de las que ahora se usan, es la dorada. Sírvate este advertimiento, Sancho, para que discreta y bienintencionadamente pongas en mis oídos la verdad de las cosas que supieres de lo que te he preguntado. -Eso haré yo de muy buena gana, señor mío -respondió Sancho-, con condición que vuestra merced no se ha de enojar de lo que dijere, pues quiere que lo diga en cueros, sin vestirlo de otras ropas de aquellas con que llegaron a mi noticia. -En ninguna manera me enojaré -respondió don Quijote-. Bien puedes, Sancho, hablar libremente y sin rodeo alguno. -Pues lo primero que digo -dijo-, es que el vulgo tiene a vuestra merced por grandísimo loco, y a mí por no menos mentecato. Los hidalgos dicen que, no conteniéndose vuestra merced en los límites de la hidalguía, se ha puesto don y se ha arremetido a caballero con cuatro cepas y dos yugadas de tierra y con un trapo atrás y otro adelante. Dicen los caballeros que no querrían que los hidalgos se opusiesen a ellos, especialmente aquellos hidalgos escuderiles que dan humo a los zapatos y toman los puntos de las medias negras con seda verde. -Eso -dijo don Quijote- no tiene que ver conmigo, pues ando siempre bien vestido, y jamás remendado; roto, bien podría ser; y el roto, más de las armas que del tiempo. -En lo que toca -prosiguió Sancho- a la valentía, cortesía, hazañas y asumpto de vuestra merced, hay diferentes opiniones; unos dicen: "loco, pero gracioso"; otros, "valiente, pero desgraciado"; otros, "cortés, pero impertinente"; y por aquí van discurriendo en tantas cosas, que ni a vuestra merced ni a mí nos dejan hueso sano. -Mira, Sancho -dijo don Quijote-: dondequiera que está la virtud en eminente grado, es perseguida. Pocos o ninguno de los famosos varones que pasaron dejó de ser calumniado de la malicia. Julio César, animosísimo, prudentísimo y valentísimo capitán, fue notado de ambicioso y algún tanto no limpio, ni en sus vestidos ni en sus costumbres. Alejandro, a quien sus hazañas le alcanzaron el renombre de Magno, dicen dél que tuvo sus ciertos puntos de borracho. De Hércules, el de los muchos trabajos, se cuenta que fue lascivo y muelle. De don Galaor, hermano de Amadís de Gaula, se murmura que fue más que demasiadamente rijoso; y de su hermano, que fue llorón. Así que, ¡oh Sancho!, entre las tantas calumnias de buenos, bien pueden pasar las mías, como no sean más de las que has dicho. -¡Ahí está el toque, cuerpo de mi padre! -replicó Sancho. -Pues, ¿hay más? -preguntó don Quijote. -Aún la cola falta por desollar -dijo Sancho-. Lo de hasta aquí son tortas y pan pintado; mas si vuestra merced quiere saber todo lo que hay acerca de las caloñas que le ponen, yo le traeré aquí luego al momento quien se las diga todas, sin que les falte una meaja; que anoche llegó el hijo de Bartolomé Carrasco, que viene de estudiar de Salamanca, hecho bachiller, y, yéndole yo a dar la bienvenida, me dijo que andaba ya en libros la historia de vuestra merced, con nombre del Ingenioso Hidalgo don Quijote de la Mancha; y dice que me mientan a mí en ella con mi mesmo nombre de Sancho Panza, y a la señora Dulcinea del Toboso, con otras cosas que pasamos nosotros a solas, que me hice cruces de espantado cómo las pudo saber el historiador que las escribió. -Yo te aseguro, Sancho -dijo don Quijote-, que debe de ser algún sabio encantador el autor de nuestra historia; que a los tales no se les encubre nada de lo que quieren escribir. -Y ¡cómo -dijo Sancho- si era sabio y encantador, pues (según dice el bachiller Sansón Carrasco, que así se llama el que dicho tengo) que el autor de la historia se llama Cide Hamete Berenjena! -Ese nombre es de moro -respondió don Quijote. -Así será -respondió Sancho-, porque por la mayor parte he oído decir que los moros son amigos de berenjenas. -Tú debes, Sancho -dijo don Quijote-, errarte en el sobrenombre de ese Cide, que en arábigo quiere decir señor. -Bien podría ser -replicó Sancho-, mas, si vuestra merced gusta que yo le haga venir aquí, iré por él en volandas. -Harásme mucho placer, amigo -dijo don Quijote-, que me tiene suspenso lo que me has dicho, y no comeré bocado que bien me sepa hasta ser informado de todo. -Pues yo voy por él -respondió Sancho. Y, dejando a su señor, se fue a buscar al bachiller, con el cual volvió de allí a poco espacio, y entre los tres pasaron un graciosísimo coloquio. Capítulo III. Del ridículo razonamiento que pasó entre don Quijote, Sancho Panza y el bachiller Sansón Carrasco Pensativo además quedó don Quijote, esperando al bachiller Carrasco, de quien esperaba oír las nuevas de sí mismo puestas en libro, como había dicho Sancho; y no se podía persuadir a que tal historia hubiese, pues aún no estaba enjuta en la cuchilla de su espada la sangre de los enemigos que había muerto, y ya querían que anduviesen en estampa sus altas caballerías. Con todo eso, imaginó que algún sabio, o ya amigo o enemigo, por arte de encantamento las habrá dado a la estampa: si amigo, para engrandecerlas y levantarlas sobre las más señaladas de caballero andante; si enemigo, para aniquilarlas y ponerlas debajo de las más viles que de algún vil escudero se hubiesen escrito, puesto -decía entre sí- que nunca hazañas de escuderos se escribieron; y cuando fuese verdad que la tal historia hubiese, siendo de caballero andante, por fuerza había de ser grandílocua, alta, insigne, magnífica y verdadera. Con esto se consoló algún tanto, pero desconsolóle pensar que su autor era moro, según aquel nombre de Cide; y de los moros no se podía esperar verdad alguna, porque todos son embelecadores, falsarios y quimeristas. Temíase no hubiese tratado sus amores con alguna indecencia, que redundase en menoscabo y perjuicio de la honestidad de su señora Dulcinea del Toboso; deseaba que hubiese declarado su fidelidad y el decoro que siempre la había guardado, menospreciando reinas, emperatrices y doncellas de todas calidades, teniendo a raya los ímpetus de los naturales movimientos; y así, envuelto y revuelto en estas y otras muchas imaginaciones, le hallaron Sancho y Carrasco, a quien don Quijote recibió con mucha cortesía. Era el bachiller, aunque se llamaba Sansón, no muy grande de cuerpo, aunque muy gran socarrón, de color macilenta, pero de muy buen entendimiento; tendría hasta veinte y cuatro años, carirredondo, de nariz chata y de boca grande, señales todas de ser de condición maliciosa y amigo de donaires y de burlas, como lo mostró en viendo a don Quijote, poniéndose delante dél de rodillas, diciéndole: -Déme vuestra grandeza las manos, señor don Quijote de la Mancha; que, por el hábito de San Pedro que visto, aunque no tengo otras órdenes que las cuatro primeras, que es vuestra merced uno de los más famosos caballeros andantes que ha habido, ni aun habrá, en toda la redondez de la tierra. Bien haya Cide Hamete Benengeli, que la historia de vuestras grandezas dejó escritas, y rebién haya el curioso que tuvo cuidado de hacerlas traducir de arábigo en nuestro vulgar castellano, para universal entretenimiento de las gentes. Hízole levantar don Quijote, y dijo: -Desa manera, ¿verdad es que hay historia mía, y que fue moro y sabio el que la compuso? -Es tan verdad, señor -dijo Sansón-, que tengo para mí que el día de hoy están impresos más de doce mil libros de la tal historia; si no, dígalo Portugal, Barcelona y Valencia, donde se han impreso; y aun hay fama que se está imprimiendo en Amberes, y a mí se me trasluce que no ha de haber nación ni lengua donde no se traduzga. -Una de las cosas -dijo a esta sazón don Quijote- que más debe de dar contento a un hombre virtuoso y eminente es verse, viviendo, andar con buen nombre por las lenguas de las gentes, impreso y en estampa. Dije con buen nombre porque, siendo al contrario, ninguna muerte se le igualará. -Si por buena fama y si por buen nombre va -dijo el bachiller-, solo vuestra merced lleva la palma a todos los caballeros andantes; porque el moro en su lengua y el cristiano en la suya tuvieron cuidado de pintarnos muy al vivo la gallardía de vuestra merced, el ánimo grande en acometer los peligros, la paciencia en las adversidades y el sufrimiento, así en las desgracias como en las heridas, la honestidad y continencia en los amores tan platónicos de vuestra merced y de mi señora doña Dulcinea del Toboso. -Nunca -dijo a este punto Sancho Panza- he oído llamar con don a mi señora Dulcinea, sino solamente la señora Dulcinea del Toboso, y ya en esto anda errada la historia. -No es objeción de importancia ésa -respondió Carrasco. -No, por cierto -respondió don Quijote-; pero dígame vuestra merced, señor bachiller: ¿qué hazañas mías son las que más se ponderan en esa historia? -En eso -respondió el bachiller-, hay diferentes opiniones, como hay diferentes gustos: unos se atienen a la aventura de los molinos de viento, que a vuestra merced le parecieron Briareos y gigantes; otros, a la de los batanes; éste, a la descripción de los dos ejércitos, que después parecieron ser dos manadas de carneros; aquél encarece la del muerto que llevaban a enterrar a Segovia; uno dice que a todas se aventaja la de la libertad de los galeotes; otro, que ninguna iguala a la de los dos gigantes benitos, con la pendencia del valeroso vizcaíno. -Dígame, señor bachiller -dijo a esta sazón Sancho-: ¿entra ahí la aventura de los yangüeses, cuando a nuestro buen Rocinante se le antojó pedir cotufas en el golfo? -No se le quedó nada -respondió Sansón- al sabio en el tintero: todo lo dice y todo lo apunta, hasta lo de las cabriolas que el buen Sancho hizo en la manta. -En la manta no hice yo cabriolas -respondió Sancho-; en el aire sí, y aun más de las que yo quisiera. -A lo que yo imagino -dijo don Quijote-, no hay historia humana en el mundo que no tenga sus altibajos, especialmente las que tratan de caballerías, las cuales nunca pueden estar llenas de prósperos sucesos. -Con todo eso -respondió el bachiller-, dicen algunos que han leído la historia que se holgaran se les hubiera olvidado a los autores della algunos de los infinitos palos que en diferentes encuentros dieron al señor don Quijote. -Ahí entra la verdad de la historia -dijo Sancho. -También pudieran callarlos por equidad -dijo don Quijote-, pues las acciones que ni mudan ni alteran la verdad de la historia no hay para qué escribirlas, si han de redundar en menosprecio del señor de la historia. A fee que no fue tan piadoso Eneas como Virgilio le pinta, ni tan prudente Ulises como le describe Homero. -Así es -replicó Sansón-, pero uno es escribir como poeta y otro como historiador: el poeta puede contar, o cantar las cosas, no como fueron, sino como debían ser; y el historiador las ha de escribir, no como debían ser, sino como fueron, sin añadir ni quitar a la verdad cosa alguna. -Pues si es que se anda a decir verdades ese señor moro -dijo Sancho-, a buen seguro que entre los palos de mi señor se hallen los míos; porque nunca a su merced le tomaron la medida de las espaldas que no me la tomasen a mí de todo el cuerpo; pero no hay de qué maravillarme, pues, como dice el mismo señor mío, del dolor de la cabeza han de participar los miembros. -Socarrón sois, Sancho -respondió don Quijote-. A fee que no os falta memoria cuando vos queréis tenerla. -Cuando yo quisiese olvidarme de los garrotazos que me han dado -dijo Sancho-, no lo consentirán los cardenales, que aún se están frescos en las costillas. -Callad, Sancho -dijo don Quijote-, y no interrumpáis al señor bachiller, a quien suplico pase adelante en decirme lo que se dice de mí en la referida historia. -Y de mí -dijo Sancho-, que también dicen que soy yo uno de los principales presonajes della. -Personajes que no presonajes, Sancho amigo -dijo Sansón. -¿Otro reprochador de voquibles tenemos? -dijo Sancho-. Pues ándense a eso, y no acabaremos en toda la vida. -Mala me la dé Dios, Sancho -respondió el bachiller-, si no sois vos la segunda persona de la historia; y que hay tal, que precia más oíros hablar a vos que al más pintado de toda ella, puesto que también hay quien diga que anduvistes demasiadamente de crédulo en creer que podía ser verdad el gobierno de aquella ínsula, ofrecida por el señor don Quijote, que está presente. -Aún hay sol en las bardas -dijo don Quijote-, y, mientras más fuere entrando en edad Sancho, con la esperiencia que dan los años, estará más idóneo y más hábil para ser gobernador que no está agora. -Por Dios, señor -dijo Sancho-, la isla que yo no gobernase con los años que tengo, no la gobernaré con los años de Matusalén. El daño está en que la dicha ínsula se entretiene, no sé dónde, y no en faltarme a mí el caletre para gobernarla. -Encomendadlo a Dios, Sancho -dijo don Quijote-, que todo se hará bien, y quizá mejor de lo que vos pensáis; que no se mueve la hoja en el árbol sin la voluntad de Dios. -Así es verdad -dijo Sansón-, que si Dios quiere, no le faltarán a Sancho mil islas que gobernar, cuanto más una. -Gobernador he visto por ahí -dijo Sancho- que, a mi parecer, no llegan a la suela de mi zapato, y, con todo eso, los llaman señoría, y se sirven con plata. -Ésos no son gobernadores de ínsulas -replicó Sansón-, sino de otros gobiernos más manuales; que los que gobiernan ínsulas, por lo menos han de saber gramática. -Con la grama bien me avendría yo -dijo Sancho-, pero con la tica, ni me tiro ni me pago, porque no la entiendo. Pero, dejando esto del gobierno en las manos de Dios, que me eche a las partes donde más de mí se sirva, digo, señor bachiller Sansón Carrasco, que infinitamente me ha dado gusto que el autor de la historia haya hablado de mí de manera que no enfadan las cosas que de mí se cuentan; que a fe de buen escudero que si hubiera dicho de mí cosas que no fueran muy de cristiano viejo, como soy, que nos habían de oír los sordos. -Eso fuera hacer milagros -respondió Sansón. -Milagros o no milagros -dijo Sancho-, cada uno mire cómo habla o cómo escribe de las presonas, y no ponga a troche moche lo primero que le viene al magín. -Una de las tachas que ponen a la tal historia -dijo el bachiller- es que su autor puso en ella una novela intitulada El curioso impertinente; no por mala ni por mal razonada, sino por no ser de aquel lugar, ni tiene que ver con la historia de su merced del señor don Quijote. -Yo apostaré -replicó Sancho- que ha mezclado el hideperro berzas con capachos. -Ahora digo -dijo don Quijote- que no ha sido sabio el autor de mi historia, sino algún ignorante hablador, que, a tiento y sin algún discurso, se puso a escribirla, salga lo que saliere, como hacía Orbaneja, el pintor de Úbeda, al cual preguntándole qué pintaba, respondió: ''Lo que saliere''. Tal vez pintaba un gallo, de tal suerte y tan mal parecido, que era menester que con letras góticas escribiese junto a él: "Éste es gallo". Y así debe de ser de mi historia, que tendrá necesidad de comento para entenderla. -Eso no -respondió Sansón-, porque es tan clara, que no hay cosa que dificultar en ella: los niños la manosean, los mozos la leen, los hombres la entienden y los viejos la celebran; y, finalmente, es tan trillada y tan leída y tan sabida de todo género de gentes, que, apenas han visto algún rocín flaco, cuando dicen: "allí va Rocinante". Y los que más se han dado a su letura son los pajes: no hay antecámara de señor donde no se halle un Don Quijote: unos le toman si otros le dejan; éstos le embisten y aquéllos le piden. Finalmente, la tal historia es del más gustoso y menos perjudicial entretenimiento que hasta agora se haya visto, porque en toda ella no se descubre, ni por semejas, una palabra deshonesta ni un pensamiento menos que católico. -A escribir de otra suerte -dijo don Quijote-, no fuera escribir verdades, sino mentiras; y los historiadores que de mentiras se valen habían de ser quemados, como los que hacen moneda falsa; y no sé yo qué le movió al autor a valerse de novelas y cuentos ajenos, habiendo tanto que escribir en los míos: sin duda se debió de atener al refrán: "De paja y de heno...", etcétera. Pues en verdad que en sólo manifestar mis pensamientos, mis sospiros, mis lágrimas, mis buenos deseos y mis acometimientos pudiera hacer un volumen mayor, o tan grande que el que pueden hacer todas las obras del Tostado. En efeto, lo que yo alcanzo, señor bachiller, es que para componer historias y libros, de cualquier suerte que sean, es menester un gran juicio y un maduro entendimiento. Decir gracias y escribir donaires es de grandes ingenios: la más discreta figura de la comedia es la del bobo, porque no lo ha de ser el que quiere dar a entender que es simple. La historia es como cosa sagrada; porque ha de ser verdadera, y donde está la verdad está Dios, en cuanto a verdad; pero, no obstante esto, hay algunos que así componen y arrojan libros de sí como si fuesen buñuelos. -No hay libro tan malo -dijo el bachiller- que no tenga algo bueno. -No hay duda en eso -replicó don Quijote-; pero muchas veces acontece que los que tenían méritamente granjeada y alcanzada gran fama por sus escritos, en dándolos a la estampa, la perdieron del todo, o la menoscabaron en algo. -La causa deso es -dijo Sansón- que, como las obras impresas se miran despacio, fácilmente se veen sus faltas, y tanto más se escudriñan cuanto es mayor la fama del que las compuso. Los hombres famosos por sus ingenios, los grandes poetas, los ilustres historiadores, siempre, o las más veces, son envidiados de aquellos que tienen por gusto y por particular entretenimiento juzgar los escritos ajenos, sin haber dado algunos propios a la luz del mundo. -Eso no es de maravillar -dijo don Quijote-, porque muchos teólogos hay que no son buenos para el púlpito, y son bonísimos para conocer las faltas o sobras de los que predican. -Todo eso es así, señor don Quijote -dijo Carrasco-, pero quisiera yo que los tales censuradores fueran más misericordiosos y menos escrupulosos, sin atenerse a los átomos del sol clarísimo de la obra de que murmuran; que si aliquando bonus dormitat Homerus, consideren lo mucho que estuvo despierto, por dar la luz de su obra con la menos sombra que pudiese; y quizá podría ser que lo que a ellos les parece mal fuesen lunares, que a las veces acrecientan la hermosura del rostro que los tiene; y así, digo que es grandísimo el riesgo a que se pone el que imprime un libro, siendo de toda imposibilidad imposible componerle tal, que satisfaga y contente a todos los que le leyeren. -El que de mí trata -dijo don Quijote-, a pocos habrá contentado. -Antes es al revés; que, como de stultorum infinitus est numerus, infinitos son los que han gustado de la tal historia; y algunos han puesto falta y dolo en la memoria del autor, pues se le olvida de contar quién fue el ladrón que hurtó el rucio a Sancho, que allí no se declara, y sólo se infiere de lo escrito que se le hurtaron, y de allí a poco le vemos a caballo sobre el mesmo jumento, sin haber parecido. También dicen que se le olvidó poner lo que Sancho hizo de aquellos cien escudos que halló en la maleta en Sierra Morena, que nunca más los nombra, y hay muchos que desean saber qué hizo dellos, o en qué los gastó, que es uno de los puntos sustanciales que faltan en la obra. -Sancho respondió: -Yo, señor Sansón, no estoy ahora para ponerme en cuentas ni cuentos; que me ha tomado un desmayo de estómago, que si no le reparo con dos tragos de lo añejo, me pondrá en la espina de Santa Lucía. En casa lo tengo, mi oíslo me aguarda; en acabando de comer, daré la vuelta, y satisfaré a vuestra merced y a todo el mundo de lo que preguntar quisieren, así de la pérdida del jumento como del gasto de los cien escudos. Y, sin esperar respuesta ni decir otra palabra, se fue a su casa. Don Quijote pidió y rogó al bachiller se quedase a hacer penitencia con él. Tuvo el bachiller el envite: quedóse, añadióse al ordinaro un par de pichones, tratóse en la mesa de caballerías, siguióle el humor Carrasco, acabóse el banquete, durmieron la siesta, volvió Sancho y renovóse la plática pasada. Capítulo IV. Donde Sancho Panza satisface al bachiller Sansón Carrasco de sus dudas y preguntas, con otros sucesos dignos de saberse y de contarse Volvió Sancho a casa de don Quijote, y, volviendo al pasado razonamiento, dijo: -A lo que el señor Sansón dijo que se deseaba saber quién, o cómo, o cuándo se me hurtó el jumento, respondiendo digo que la noche misma que, huyendo de la Santa Hermandad, nos entramos en Sierra Morena, después de la aventura sin ventura de los galeotes y de la del difunto que llevaban a Segovia, mi señor y yo nos metimos entre una espesura, adonde mi señor arrimado a su lanza, y yo sobre mi rucio, molidos y cansados de las pasadas refriegas, nos pusimos a dormir como si fuera sobre cuatro colchones de pluma; especialmente yo dormí con tan pesado sueño, que quienquiera que fue tuvo lugar de llegar y suspenderme sobre cuatro estacas que puso a los cuatro lados de la albarda, de manera que me dejó a caballo sobre ella, y me sacó debajo de mí al rucio, sin que yo lo sintiese. -Eso es cosa fácil, y no acontecimiento nuevo, que lo mesmo le sucedió a Sacripante cuando, estando en el cerco de Albraca, con esa misma invención le sacó el caballo de entre las piernas aquel famoso ladrón llamado Brunelo. -Amaneció -prosiguió Sancho-, y, apenas me hube estremecido, cuando, faltando las estacas, di conmigo en el suelo una gran caída; miré por el jumento, y no le vi; acudiéronme lágrimas a los ojos, y hice una lamentación, que si no la puso el autor de nuestra historia, puede hacer cuenta que no puso cosa buena. Al cabo de no sé cuántos días, viniendo con la señora princesa Micomicona, conocí mi asno, y que venía sobre él en hábito de gitano aquel Ginés de Pasamonte, aquel embustero y grandísimo maleador que quitamos mi señor y yo de la cadena. -No está en eso el yerro -replicó Sansón-, sino en que, antes de haber parecido el jumento, dice el autor que iba a caballo Sancho en el mesmo rucio. -A eso -dijo Sancho-, no sé qué responder, sino que el historiador se engañó, o ya sería descuido del impresor. -Así es, sin duda -dijo Sansón-; pero, ¿qué se hicieron los cien escudos?; ¿deshiciéronse? Respondió Sancho: -Yo los gasté en pro de mi persona y de la de mi mujer, y de mis hijos, y ellos han sido causa de que mi mujer lleve en paciencia los caminos y carreras que he andado sirviendo a mi señor don Quijote; que si, al cabo de tanto tiempo, volviera sin blanca y sin el jumento a mi casa, negra ventura me esperaba; y si hay más que saber de mí, aquí estoy, que responderé al mismo rey en presona, y nadie tiene para qué meterse en si truje o no truje, si gasté o no gasté; que si los palos que me dieron en estos viajes se hubieran de pagar a dinero, aunque no se tasaran sino a cuatro maravedís cada uno, en otros cien escudos no había para pagarme la mitad; y cada uno meta la mano en su pecho, y no se ponga a juzgar lo blanco por negro y lo negro por blanco; que cada uno es como Dios le hizo, y aun peor muchas veces. -Yo tendré cuidado -dijo Carrasco- de acusar al autor de la historia que si otra vez la imprimiere, no se le olvide esto que el buen Sancho ha dicho, que será realzarla un buen coto más de lo que ella se está. -¿Hay otra cosa que enmendar en esa leyenda, señor bachiller? -preguntó don Quijote. -Sí debe de haber -respondió él-, pero ninguna debe de ser de la importancia de las ya referidas. -Y por ventura -dijo don Quijote-, ¿promete el autor segunda parte? -Sí promete -respondió Sansón-, pero dice que no ha hallado ni sabe quién la tiene, y así, estamos en duda si saldrá o no; y así por esto como porque algunos dicen: "Nunca segundas partes fueron buenas", y otros: "De las cosas de don Quijote bastan las escritas", se duda que no ha de haber segunda parte; aunque algunos que son más joviales que saturninos dicen: "Vengan más quijotadas: embista don Quijote y hable Sancho Panza, y sea lo que fuere, que con eso nos contentamos". -Y ¿a qué se atiene el autor? -A que -respondió Sansón-, en hallando que halle la historia, que él va buscando con extraordinarias diligencias, la dará luego a la estampa, llevado más del interés que de darla se le sigue que de otra alabanza alguna. A lo que dijo Sancho: -¿Al dinero y al interés mira el autor? Maravilla será que acierte, porque no hará sino harbar, harbar, como sastre en vísperas de pascuas, y las obras que se hacen apriesa nunca se acaban con la perfeción que requieren. Atienda ese señor moro, o lo que es, a mirar lo que hace; que yo y mi señor le daremos tanto ripio a la mano en materia de aventuras y de sucesos diferentes, que pueda componer no sólo segunda parte, sino ciento. Debe de pensar el buen hombre, sin duda, que nos dormimos aquí en las pajas; pues ténganos el pie al herrar, y verá del que cosqueamos. Lo que yo sé decir es que si mi señor tomase mi consejo, ya habíamos de estar en esas campañas deshaciendo agravios y enderezando tuertos, como es uso y costumbre de los buenos andantes caballeros. No había bien acabado de decir estas razones Sancho, cuando llegaron a sus oídos relinchos de Rocinante; los cuales relinchos tomó don Quijote por felicísimo agüero, y determinó de hacer de allí a tres o cuatro días otra salida; y, declarando su intento al bachiller, le pidió consejo por qué parte comenzaría su jornada; el cual le respondió que era su parecer que fuese al reino de Aragón y a la ciudad de Zaragoza, adonde, de allí a pocos días, se habían de hacer unas solenísimas justas por la fiesta de San Jorge, en las cuales podría ganar fama sobre todos los caballeros aragoneses, que sería ganarla sobre todos los del mundo. Alabóle ser honradísima y valentísima su determinación, y advirtióle que anduviese más atentado en acometer los peligros, a causa que su vida no era suya, sino de todos aquellos que le habían de menester para que los amparase y socorriese en sus desventuras. -Deso es lo que yo reniego, señor Sansón -dijo a este punto Sancho-, que así acomete mi señor a cien hombres armados como un muchacho goloso a media docena de badeas. ¡Cuerpo del mundo, señor bachiller! Sí, que tiempos hay de acometer y tiempos de retirar; sí, no ha de ser todo "¡Santiago, y cierra, España!" Y más, que yo he oído decir, y creo que a mi señor mismo, si mal no me acuerdo, que en los estremos de cobarde y de temerario está el medio de la valentía; y si esto es así, no quiero que huya sin tener para qué, ni que acometa cuando la demasía pide otra cosa. Pero, sobre todo, aviso a mi señor que si me ha de llevar consigo, ha de ser con condición que él se lo ha de batallar todo, y que yo no he de estar obligado a otra cosa que a mirar por su persona en lo que tocare a su limpieza y a su regalo; que en esto yo le bailaré el agua delante; pero pensar que tengo de poner mano a la espada, aunque sea contra villanos malandrines de hacha y capellina, es pensar en lo escusado. Yo, señor Sansón, no pienso granjear fama de valiente, sino del mejor y más leal escudero que jamás sirvió a caballero andante; y si mi señor don Quijote, obligado de mis muchos y buenos servicios, quisiere darme alguna ínsula de las muchas que su merced dice que se ha de topar por ahí, recibiré mucha merced en ello; y cuando no me la diere, nacido soy, y no ha de vivir el hombre en hoto de otro sino de Dios; y más, que tan bien, y aun quizá mejor, me sabrá el pan desgobernado que siendo gobernador; y ¿sé yo por ventura si en esos gobiernos me tiene aparejada el diablo alguna zancadilla donde tropiece y caiga y me haga las muelas? Sancho nací, y Sancho pienso morir; pero si con todo esto, de buenas a buenas, sin mucha solicitud y sin mucho riesgo, me deparase el cielo alguna ínsula, o otra cosa semejante, no soy tan necio que la desechase; que también se dice: "Cuando te dieren la vaquilla, corre con la soguilla"; y "Cuando viene el bien, mételo en tu casa". -Vos, hermano Sancho -dijo Carrasco-, habéis hablado como un catedrático; pero, con todo eso, confiad en Dios y en el señor don Quijote, que os ha de dar un reino, no que una ínsula. -Tanto es lo de más como lo de menos -respondió Sancho-; aunque sé decir al señor Carrasco que no echara mi señor el reino que me diera en saco roto, que yo he tomado el pulso a mí mismo, y me hallo con salud para regir reinos y gobernar ínsulas, y esto ya otras veces lo he dicho a mi señor. -Mirad, Sancho -dijo Sansón-, que los oficios mudan las costumbres, y podría ser que viéndoos gobernador no conociésedes a la madre que os parió. -Eso allá se ha de entender -respondió Sancho- con los que nacieron en las malvas, y no con los que tienen sobre el alma cuatro dedos de enjundia de cristianos viejos, como yo los tengo. ¡No, sino llegaos a mi condición, que sabrá usar de desagradecimiento con alguno! -Dios lo haga -dijo don Quijote-, y ello dirá cuando el gobierno venga; que ya me parece que le trayo entre los ojos. Dicho esto, rogó al bachiller que, si era poeta, le hiciese merced de componerle unos versos que tratasen de la despedida que pensaba hacer de su señora Dulcinea del Toboso, y que advirtiese que en el principio de cada verso había de poner una letra de su nombre, de manera que al fin de los versos, juntando las primeras letras, se leyese: Dulcinea del Toboso. El bachiller respondió que, puesto que él no era de los famosos poetas que había en España, que decían que no eran sino tres y medio, que no dejaría de componer los tales metros, aunque hallaba una dificultad grande en su composición, a causa que las letras que contenían el nombre eran diez y siete; y que si hacía cuatro castellanas de a cuatro versos, sobrara una letra; y si de a cinco, a quien llaman décimas o redondillas, faltaban tres letras; pero, con todo eso, procuraría embeber una letra lo mejor que pudiese, de manera que en las cuatro castellanas se incluyese el nombre de Dulcinea del Toboso. -Ha de ser así en todo caso -dijo don Quijote-; que si allí no va el nombre patente y de manifiesto, no hay mujer que crea que para ella se hicieron los metros. Quedaron en esto y en que la partida sería de allí a ocho días. Encargó don Quijote al bachiller la tuviese secreta, especialmente al cura y a maese Nicolás, y a su sobrina y al ama, porque no estorbasen su honrada y valerosa determinación. Todo lo prometió Carrasco. Con esto se despidió, encargando a don Quijote que de todos sus buenos o malos sucesos le avisase, habiendo comodidad; y así, se despidieron, y Sancho fue a poner en orden lo necesario para su jornada. Capítulo V. De la discreta y graciosa plática que pasó entre Sancho Panza y su mujer Teresa Panza, y otros sucesos dignos de felice recordación (Llegando a escribir el traductor desta historia este quinto capítulo, dice que le tiene por apócrifo, porque en él habla Sancho Panza con otro estilo del que se podía prometer de su corto ingenio, y dice cosas tan sutiles, que no tiene por posible que él las supiese; pero que no quiso dejar de traducirlo, por cumplir con lo que a su oficio debía; y así, prosiguió diciendo:) Llegó Sancho a su casa tan regocijado y alegre, que su mujer conoció su alegría a tiro de ballesta; tanto, que la obligó a preguntarle: -¿Qué traés, Sancho amigo, que tan alegre venís? A lo que él respondió: -Mujer mía, si Dios quisiera, bien me holgara yo de no estar tan contento como muestro. -No os entiendo, marido -replicó ella-, y no sé qué queréis decir en eso de que os holgáredes, si Dios quisiera, de no estar contento; que, maguer tonta, no sé yo quién recibe gusto de no tenerle. -Mirad, Teresa -respondió Sancho-: yo estoy alegre porque tengo determinado de volver a servir a mi amo don Quijote, el cual quiere la vez tercera salir a buscar las aventuras; y yo vuelvo a salir con él, porque lo quiere así mi necesidad, junto con la esperanza, que me alegra, de pensar si podré hallar otros cien escudos como los ya gastados, puesto que me entristece el haberme de apartar de ti y de mis hijos; y si Dios quisiera darme de comer a pie enjuto y en mi casa, sin traerme por vericuetos y encrucijadas, pues lo podía hacer a poca costa y no más de quererlo, claro está que mi alegría fuera más firme y valedera, pues que la que tengo va mezclada con la tristeza del dejarte; así que, dije bien que holgara, si Dios quisiera, de no estar contento. -Mirad, Sancho -replicó Teresa-: después que os hicistes miembro de caballero andante habláis de tan rodeada manera, que no hay quien os entienda. -Basta que me entienda Dios, mujer -respondió Sancho-, que Él es el entendedor de todas las cosas, y quédese esto aquí; y advertid, hermana, que os conviene tener cuenta estos tres días con el rucio, de manera que esté para armas tomar: dobladle los piensos, requerid la albarda y las demás jarcias, porque no vamos a bodas, sino a rodear el mundo, y a tener dares y tomares con gigantes, con endriagos y con vestiglos, y a oír silbos, rugidos, bramidos y baladros; y aun todo esto fuera flores de cantueso si no tuviéramos que entender con yangüeses y con moros encantados. -Bien creo yo, marido -replicó Teresa-, que los escuderos andantes no comen el pan de balde; y así, quedaré rogando a Nuestro Señor os saque presto de tanta mala ventura. -Yo os digo, mujer -respondió Sancho-, que si no pensase antes de mucho tiempo verme gobernador de una ínsula, aquí me caería muerto. -Eso no, marido mío -dijo Teresa-: viva la gallina, aunque sea con su pepita; vivid vos, y llévese el diablo cuantos gobiernos hay en el mundo; sin gobierno salistes del vientre de vuestra madre, sin gobierno habéis vivido hasta ahora, y sin gobierno os iréis, o os llevarán, a la sepultura cuando Dios fuere servido. Como ésos hay en el mundo que viven sin gobierno, y no por eso dejan de vivir y de ser contados en el número de las gentes. La mejor salsa del mundo es la hambre; y como ésta no falta a los pobres, siempre comen con gusto. Pero mirad, Sancho: si por ventura os viéredes con algún gobierno, no os olvidéis de mí y de vuestros hijos. Advertid que Sanchico tiene ya quince años cabales, y es razón que vaya a la escuela, si es que su tío el abad le ha de dejar hecho de la Iglesia. Mirad también que Mari Sancha, vuestra hija, no se morirá si la casamos; que me va dando barruntos que desea tanto tener marido como vos deseáis veros con gobierno; y, en fin en fin, mejor parece la hija mal casada que bien abarraganada. -A buena fe -respondió Sancho- que si Dios me llega a tener algo qué de gobierno, que tengo de casar, mujer mía, a Mari Sancha tan altamente que no la alcancen sino con llamarla señora. -Eso no, Sancho -respondió Teresa-: casadla con su igual, que es lo más acertado; que si de los zuecos la sacáis a chapines, y de saya parda de catorceno a verdugado y saboyanas de seda, y de una Marica y un tú a una doña tal y señoría, no se ha de hallar la mochacha, y a cada paso ha de caer en mil faltas, descubriendo la hilaza de su tela basta y grosera. -Calla, boba -dijo Sancho-, que todo será usarlo dos o tres años; que después le vendrá el señorío y la gravedad como de molde; y cuando no, ¿qué importa? Séase ella señoría, y venga lo que viniere. -Medíos, Sancho, con vuestro estado -respondió Teresa-; no os queráis alzar a mayores, y advertid al refrán que dice: "Al hijo de tu vecino, límpiale las narices y métele en tu casa". ¡Por cierto, que sería gentil cosa casar a nuestra María con un condazo, o con caballerote que, cuando se le antojase, la pusiese como nueva, llamándola de villana, hija del destripaterrones y de la pelarruecas! ¡No en mis días, marido! ¡Para eso, por cierto, he criado yo a mi hija! Traed vos dineros, Sancho, y el casarla dejadlo a mi cargo; que ahí está Lope Tocho, el hijo de Juan Tocho, mozo rollizo y sano, y que le conocemos, y sé que no mira de mal ojo a la mochacha; y con éste, que es nuestro igual, estará bien casada, y le tendremos siempre a nuestros ojos, y seremos todos unos, padres y hijos, nietos y yernos, y andará la paz y la bendición de Dios entre todos nosotros; y no casármela vos ahora en esas cortes y en esos palacios grandes, adonde ni a ella la entiendan, ni ella se entienda. -Ven acá, bestia y mujer de Barrabás -replicó Sancho-: ¿por qué quieres tú ahora, sin qué ni para qué, estorbarme que no case a mi hija con quien me dé nietos que se llamen señoría? Mira, Teresa: siempre he oído decir a mis mayores que el que no sabe gozar de la ventura cuando le viene, que no se debe quejar si se le pasa. Y no sería bien que ahora, que está llamando a nuestra puerta, se la cerremos; dejémonos llevar deste viento favorable que nos sopla. (Por este modo de hablar, y por lo que más abajo dice Sancho, dijo el tradutor desta historia que tenía por apócrifo este capítulo.) -¿No te parece, animalia -prosiguió Sancho-, que será bien dar con mi cuerpo en algún gobierno provechoso que nos saque el pie del lodo? Y cásese a Mari Sancha con quien yo quisiere, y verás cómo te llaman a ti doña Teresa Panza, y te sientas en la iglesia sobre alcatifa, almohadas y arambeles, a pesar y despecho de las hidalgas del pueblo. ¡No, sino estaos siempre en un ser, sin crecer ni menguar, como figura de paramento! Y en esto no hablemos más, que Sanchica ha de ser condesa, aunque tú más me digas. -¿Veis cuanto decís, marido? -respondió Teresa-. Pues, con todo eso, temo que este condado de mi hija ha de ser su perdición. Vos haced lo que quisiéredes, ora la hagáis duquesa o princesa, pero séos decir que no será ello con voluntad ni consentimiento mío. Siempre, hermano, fui amiga de la igualdad, y no puedo ver entonos sin fundamentos. Teresa me pusieron en el bautismo, nombre mondo y escueto, sin añadiduras ni cortapisas, ni arrequives de dones ni donas; Cascajo se llamó mi padre, y a mí, por ser vuestra mujer, me llaman Teresa Panza, que a buena razón me habían de llamar Teresa Cascajo. Pero allá van reyes do quieren leyes, y con este nombre me contento, sin que me le pongan un don encima, que pese tanto que no le pueda llevar, y no quiero dar que decir a los que me vieren andar vestida a lo condesil o a lo de gobernadora, que luego dirán: ''¡Mirad qué entonada va la pazpuerca!; ayer no se hartaba de estirar de un copo de estopa, y iba a misa cubierta la cabeza con la falda de la saya, en lugar de manto, y ya hoy va con verdugado, con broches y con entono, como si no la conociésemos''. Si Dios me guarda mis siete, o mis cinco sentidos, o los que tengo, no pienso dar ocasión de verme en tal aprieto. Vos, hermano, idos a ser gobierno o ínsulo, y entonaos a vuestro gusto; que mi hija ni yo, por el siglo de mi madre, que no nos hemos de mudar un paso de nuestra aldea: la mujer honrada, la pierna quebrada, y en casa; y la doncella honesta, el hacer algo es su fiesta. Idos con vuestro don Quijote a vuestras aventuras, y dejadnos a nosotras con nuestras malas venturas, que Dios nos las mejorará como seamos buenas; y yo no sé, por cierto, quién le puso a él don, que no tuvieron sus padres ni sus agüelos. -Ahora digo -replicó Sancho- que tienes algún familiar en ese cuerpo. ¡Válate Dios, la mujer, y qué de cosas has ensartado unas en otras, sin tener pies ni cabeza! ¿Qué tiene que ver el Cascajo, los broches, los refranes y el entono con lo que yo digo? Ven acá, mentecata e ignorante (que así te puedo llamar, pues no entiendes mis razones y vas huyendo de la dicha): si yo dijera que mi hija se arrojara de una torre abajo, o que se fuera por esos mundos, como se quiso ir la infanta doña Urraca, tenías razón de no venir con mi gusto; pero si en dos paletas, y en menos de un abrir y cerrar de ojos, te la chanto un don y una señoría a cuestas, y te la saco de los rastrojos, y te la pongo en toldo y en peana, y en un estrado de más almohadas de velludo que tuvieron moros en su linaje los Almohadas de Marruecos, ¿por qué no has de consentir y querer lo que yo quiero? -¿Sabéis por qué, marido? -respondió Teresa-; por el refrán que dice: "¡Quien te cubre, te descubre!" Por el pobre todos pasan los ojos como de corrida, y en el rico los detienen; y si el tal rico fue un tiempo pobre, allí es el murmurar y el maldecir, y el peor perseverar de los maldicientes, que los hay por esas calles a montones, como enjambres de abejas. -Mira, Teresa -respondió Sancho-, y escucha lo que agora quiero decirte; quizá no lo habrás oído en todos los días de tu vida, y yo agora no hablo de mío; que todo lo que pienso decir son sentencias del padre predicador que la Cuaresma pasada predicó en este pueblo, el cual, si mal no me acuerdo, dijo que todas las cosas presentes que los ojos están mirando se presentan, están y asisten en nuestra memoria mucho mejor y con más vehemencia que las cosas pasadas. (Todas estas razones que aquí va diciendo Sancho son las segundas por quien dice el tradutor que tiene por apócrifo este capítulo, que exceden a la capacidad de Sancho. El cual prosiguió diciendo:) -De donde nace que, cuando vemos alguna persona bien aderezada, y con ricos vestidos compuesta, y con pompa de criados, parece que por fuerza nos mueve y convida a que la tengamos respeto, puesto que la memoria en aquel instante nos represente alguna bajeza en que vimos a la tal persona; la cual inominia, ahora sea de pobreza o de linaje, como ya pasó, no es, y sólo es lo que vemos presente. Y si éste a quien la fortuna sacó del borrador de su bajeza (que por estas mesmas razones lo dijo el padre) a la alteza de su prosperidad, fuere bien criado, liberal y cortés con todos, y no se pusiere en cuentos con aquellos que por antigüedad son nobles, ten por cierto, Teresa, que no habrá quien se acuerde de lo que fue, sino que reverencien lo que es, si no fueren los invidiosos, de quien ninguna próspera fortuna está segura. -Yo no os entiendo, marido -replicó Teresa-: haced lo que quisiéredes, y no me quebréis más la cabeza con vuestras arengas y retóricas. Y si estáis revuelto en hacer lo que decís... -Resuelto has de decir, mujer -dijo Sancho-, y no revuelto. -No os pongáis a disputar, marido, conmigo -respondió Teresa-. Yo hablo como Dios es servido, y no me meto en más dibujos; y digo que si estáis porfiando en tener gobierno, que llevéis con vos a vuestro hijo Sancho, para que desde agora le enseñéis a tener gobierno, que bien es que los hijos hereden y aprendan los oficios de sus padres. -En teniendo gobierno -dijo Sancho-, enviaré por él por la posta, y te enviaré dineros, que no me faltarán, pues nunca falta quien se los preste a los gobernadores cuando no los tienen; y vístele de modo que disimule lo que es y parezca lo que ha de ser. -Enviad vos dinero -dijo Teresa-, que yo os lo vistiré como un palmito. -En efecto, quedamos de acuerdo -dijo Sancho- de que ha de ser condesa nuestra hija. -El día que yo la viere condesa -respondió Teresa-, ése haré cuenta que la entierro, pero otra vez os digo que hagáis lo que os diere gusto, que con esta carga nacemos las mujeres, de estar obedientes a sus maridos, aunque sean unos porros. Y, en esto, comenzó a llorar tan de veras como si ya viera muerta y enterrada a Sanchica. Sancho la consoló diciéndole que, ya que la hubiese de hacer condesa, la haría todo lo más tarde que ser pudiese. Con esto se acabó su plática, y Sancho volvió a ver a don Quijote para dar orden en su partida. Capítulo VI. De lo que le pasó a Don Quijote con su sobrina y con su ama, y es uno de los importantes capítulos de toda la historia En tanto que Sancho Panza y su mujer Teresa Cascajo pasaron la impertinente referida plática, no estaban ociosas la sobrina y el ama de don Quijote, que por mil señales iban coligiendo que su tío y señor quería desgarrarse la vez tercera, y volver al ejercicio de su, para ellas, mal andante caballería: procuraban por todas las vías posibles apartarle de tan mal pensamiento, pero todo era predicar en desierto y majar en hierro frío. Con todo esto, entre otras muchas razones que con él pasaron, le dijo el ama: -En verdad, señor mío, que si vuesa merced no afirma el pie llano y se está quedo en su casa, y se deja de andar por los montes y por los valles como ánima en pena, buscando esas que dicen que se llaman aventuras, a quien yo llamo desdichas, que me tengo de quejar en voz y en grita a Dios y al rey, que pongan remedio en ello. A lo que respondió don Quijote: -Ama, lo que Dios responderá a tus quejas yo no lo sé, ni lo que ha de responder Su Majestad tampoco, y sólo sé que si yo fuera rey, me escusara de responder a tanta infinidad de memoriales impertinentes como cada día le dan; que uno de los mayores trabajos que los reyes tienen, entre otros muchos, es el estar obligados a escuchar a todos y a responder a todos; y así, no querría yo que cosas mías le diesen pesadumbre. A lo que dijo el ama: -Díganos, señor: en la corte de Su Majestad, ¿no hay caballeros? -Sí -respondió don Quijote-, y muchos; y es razón que los haya, para adorno de la grandeza de los príncipes y para ostentación de la majestad real. -Pues, ¿no sería vuesa merced -replicó ella- uno de los que a pie quedo sirviesen a su rey y señor, estándose en la corte? -Mira, amiga -respondió don Quijote-: no todos los caballeros pueden ser cortesanos, ni todos los cortesanos pueden ni deben ser caballeros andantes: de todos ha de haber en el mundo; y, aunque todos seamos caballeros, va mucha diferencia de los unos a los otros; porque los cortesanos, sin salir de sus aposentos ni de los umbrales de la corte, se pasean por todo el mundo, mirando un mapa, sin costarles blanca, ni padecer calor ni frío, hambre ni sed; pero nosotros, los caballeros andantes verdaderos, al sol, al frío, al aire, a las inclemencias del cielo, de noche y de día, a pie y a caballo, medimos toda la tierra con nuestros mismos pies; y no solamente conocemos los enemigos pintados, sino en su mismo ser, y en todo trance y en toda ocasión los acometemos, sin mirar en niñerías, ni en las leyes de los desafíos; si lleva, o no lleva, más corta la lanza, o la espada; si trae sobre sí reliquias, o algún engaño encubierto; si se ha de partir y hacer tajadas el sol, o no, con otras ceremonias deste jaez, que se usan en los desafíos particulares de persona a persona, que tú no sabes y yo sí. Y has de saber más: que el buen caballero andante, aunque vea diez gigantes que con las cabezas no sólo tocan, sino pasan las nubes, y que a cada uno le sirven de piernas dos grandísimas torres, y que los brazos semejan árboles de gruesos y poderosos navíos, y cada ojo como una gran rueda de molino y más ardiendo que un horno de vidrio, no le han de espantar en manera alguna; antes con gentil continente y con intrépido corazón los ha de acometer y embestir, y, si fuere posible, vencerlos y desbaratarlos en un pequeño instante, aunque viniesen armados de unas conchas de un cierto pescado que dicen que son más duras que si fuesen de diamantes, y en lugar de espadas trujesen cuchillos tajantes de damasquino acero, o porras ferradas con puntas asimismo de acero, como yo las he visto más de dos veces. Todo esto he dicho, ama mía, porque veas la diferencia que hay de unos caballeros a otros; y sería razón que no hubiese príncipe que no estimase en más esta segunda, o, por mejor decir, primera especie de caballeros andantes, que, según leemos en sus historias, tal ha habido entre ellos que ha sido la salud no sólo de un reino, sino de muchos. -¡Ah, señor mío! -dijo a esta sazón la sobrina-; advierta vuestra merced que todo eso que dice de los caballeros andantes es fábula y mentira, y sus historias, ya que no las quemasen, merecían que a cada una se le echase un sambenito, o alguna señal en que fuese conocida por infame y por gastadora de las buenas costumbres. -Por el Dios que me sustenta -dijo don Quijote-, que si no fueras mi sobrina derechamente, como hija de mi misma hermana, que había de hacer un tal castigo en ti, por la blasfemia que has dicho, que sonara por todo el mundo. ¿Cómo que es posible que una rapaza que apenas sabe menear doce palillos de randas se atreva a poner lengua y a censurar las historias de los caballeros andantes? ¿Qué dijera el señor Amadís si lo tal oyera? Pero a buen seguro que él te perdonara, porque fue el más humilde y cortés caballero de su tiempo, y, demás, grande amparador de las doncellas; mas, tal te pudiera haber oído que no te fuera bien dello, que no todos son corteses ni bien mirados: algunos hay follones y descomedidos. Ni todos los que se llaman caballeros lo son de todo en todo: que unos son de oro, otros de alquimia, y todos parecen caballeros, pero no todos pueden estar al toque de la piedra de la verdad. Hombres bajos hay que revientan por parecer caballeros, y caballeros altos hay que parece que aposta mueren por parecer hombres bajos; aquéllos se llevantan o con la ambición o con la virtud, éstos se abajan o con la flojedad o con el vicio; y es menester aprovecharnos del conocimiento discreto para distinguir estas dos maneras de caballeros, tan parecidos en los nombres y tan distantes en las acciones. -¡Válame Dios! -dijo la sobrina-. ¡Que sepa vuestra merced tanto, señor tío, que, si fuese menester en una necesidad, podría subir en un púlpito e irse a predicar por esas calles, y que, con todo esto, dé en una ceguera tan grande y en una sandez tan conocida, que se dé a entender que es valiente, siendo viejo, que tiene fuerzas, estando enfermo, y que endereza tuertos, estando por la edad agobiado, y, sobre todo, que es caballero, no lo siendo; porque, aunque lo puedan ser los hidalgos, no lo son los pobres! -Tienes mucha razón, sobrina, en lo que dices -respondió don Quijote-, y cosas te pudiera yo decir cerca de los linajes, que te admiraran; pero, por no mezclar lo divino con lo humano, no las digo. Mirad, amigas: a cuatro suertes de linajes, y estadme atentas, se pueden reducir todos los que hay en el mundo, que son éstas: unos, que tuvieron principios humildes, y se fueron estendiendo y dilatando hasta llegar a una suma grandeza; otros, que tuvieron principios grandes, y los fueron conservando y los conservan y mantienen en el ser que comenzaron; otros, que, aunque tuvieron principios grandes, acabaron en punta, como pirámide, habiendo diminuido y aniquilado su principio hasta parar en nonada, como lo es la punta de la pirámide, que respeto de su basa o asiento no es nada; otros hay, y éstos son los más, que ni tuvieron principio bueno ni razonable medio, y así tendrán el fin, sin nombre, como el linaje de la gente plebeya y ordinaria. De los primeros, que tuvieron principio humilde y subieron a la grandeza que agora conservan, te sirva de ejemplo la Casa Otomana, que, de un humilde y bajo pastor que le dio principio, está en la cumbre que le vemos. Del segundo linaje, que tuvo principio en grandeza y la conserva sin aumentarla, serán ejemplo muchos príncipes que por herencia lo son, y se conservan en ella, sin aumentarla ni diminuirla, conteniéndose en los límites de sus estados pacíficamente. De los que comenzaron grandes y acabaron en punta hay millares de ejemplos, porque todos los Faraones y Tolomeos de Egipto, los Césares de Roma, con toda la caterva, si es que se le puede dar este nombre, de infinitos príncipes, monarcas, señores, medos, asirios, persas, griegos y bárbaros, todos estos linajes y señoríos han acabado en punta y en nonada, así ellos como los que les dieron principio, pues no será posible hallar agora ninguno de sus decendientes, y si le hallásemos, sería en bajo y humilde estado. Del linaje plebeyo no tengo qué decir, sino que sirve sólo de acrecentar el número de los que viven, sin que merezcan otra fama ni otro elogio sus grandezas. De todo lo dicho quiero que infiráis, bobas mías, que es grande la confusión que hay entre los linajes, y que solos aquéllos parecen grandes y ilustres que lo muestran en la virtud, y en la riqueza y liberalidad de sus dueños. Dije virtudes, riquezas y liberalidades, porque el grande que fuere vicioso será vicioso grande, y el rico no liberal será un avaro mendigo; que al poseedor de las riquezas no le hace dichoso el tenerlas, sino el gastarlas, y no el gastarlas comoquiera, sino el saberlas bien gastar. Al caballero pobre no le queda otro camino para mostrar que es caballero sino el de la virtud, siendo afable, bien criado, cortés y comedido, y oficioso; no soberbio, no arrogante, no murmurador, y, sobre todo, caritativo; que con dos maravedís que con ánimo alegre dé al pobre se mostrará tan liberal como el que a campana herida da limosna, y no habrá quien le vea adornado de las referidas virtudes que, aunque no le conozca, deje de juzgarle y tenerle por de buena casta, y el no serlo sería milagro; y siempre la alabanza fue premio de la virtud, y los virtuosos no pueden dejar de ser alabados. Dos caminos hay, hijas, por donde pueden ir los hombres a llegar a ser ricos y honrados: el uno es el de las letras; otro, el de las armas. Yo tengo más armas que letras, y nací, según me inclino a las armas, debajo de la influencia del planeta Marte; así que, casi me es forzoso seguir por su camino, y por él tengo de ir a pesar de todo el mundo, y será en balde cansaros en persuadirme a que no quiera yo lo que los cielos quieren, la fortuna ordena y la razón pide, y, sobre todo, mi voluntad desea. Pues con saber, como sé, los innumerables trabajos que son anejos al andante caballería, sé también los infinitos bienes que se alcanzan con ella; y sé que la senda de la virtud es muy estrecha, y el camino del vicio, ancho y espacioso; y sé que sus fines y paraderos son diferentes, porque el del vicio, dilatado y espacioso, acaba en la muerte, y el de la virtud, angosto y trabajoso, acaba en vida, y no en vida que se acaba, sino en la que no tendrá fin; y sé, como dice el gran poeta castellano nuestro, que Por estas asperezas se camina de la inmortalidad al alto asiento, do nunca arriba quien de allí declina. -¡Ay, desdichada de mí -dijo la sobrina-, que también mi señor es poeta!. Todo lo sabe, todo lo alcanza: yo apostaré que si quisiera ser albañil, que supiera fabricar una casa como una jaula. Yo te prometo, sobrina -respondió don Quijote-, que si estos pensamientos caballerescos no me llevasen tras sí todos los sentidos, que no habría cosa que yo no hiciese, ni curiosidad que no saliese de mis manos, especialmente jaulas y palillos de dientes. A este tiempo, llamaron a la puerta, y, preguntando quién llamaba, respondió Sancho Panza que él era; y, apenas le hubo conocido el ama, cuando corrió a esconderse por no verle: tanto le aborrecía. Abrióle la sobrina, salió a recebirle con los brazos abiertos su señor don Quijote, y encerráronse los dos en su aposento, donde tuvieron otro coloquio, que no le hace ventaja el pasado. Capítulo VII. De lo que pasó don Quijote con su escudero, con otros sucesos famosísimos Apenas vio el ama que Sancho Panza se encerraba con su señor, cuando dio en la cuenta de sus tratos; y, imaginando que de aquella consulta había de salir la resolución de su tercera salida y tomando su manto, toda llena de congoja y pesadumbre, se fue a buscar al bachiller Sansón Carrasco, pareciéndole que, por ser bien hablado y amigo fresco de su señor, le podría persuadir a que dejase tan desvariado propósito. Hallóle paseándose por el patio de su casa, y, viéndole, se dejó caer ante sus pies, trasudando y congojosa. Cuando la vio Carrasco con muestras tan doloridas y sobresaltadas, le dijo: -¿Qué es esto, señora ama? ¿Qué le ha acontecido, que parece que se le quiere arrancar el alma? -No es nada, señor Sansón mío, sino que mi amo se sale; ¡sálese sin duda! -Y ¿por dónde se sale, señora? -preguntó Sansón-. ¿Hásele roto alguna parte de su cuerpo? -No se sale -respondió ella-, sino por la puerta de su locura. Quiero decir, señor bachiller de mi ánima, que quiere salir otra vez, que con ésta será la tercera, a buscar por ese mundo lo que él llama venturas, que yo no puedo entender cómo les da este nombre. La vez primera nos le volvieron atravesado sobre un jumento, molido a palos. La segunda vino en un carro de bueyes, metido y encerrado en una jaula, adonde él se daba a entender que estaba encantado; y venía tal el triste, que no le conociera la madre que le parió: flaco, amarillo, los ojos hundidos en los últimos camaranchones del celebro, que, para haberle de volver algún tanto en sí, gasté más de seiscientos huevos, como lo sabe Dios y todo el mundo, y mis gallinas, que no me dejaran mentir. -Eso creo yo muy bien -respondió el bachiller-; que ellas son tan buenas, tan gordas y tan bien criadas, que no dirán una cosa por otra, si reventasen. En efecto, señora ama: ¿no hay otra cosa, ni ha sucedido otro desmán alguno, sino el que se teme que quiere hacer el señor don Quijote? -No, señor -respondió ella. -Pues no tenga pena -respondió el bachiller-, sino váyase en hora buena a su casa, y téngame aderezado de almorzar alguna cosa caliente, y, de camino, vaya rezando la oración de Santa Apolonia si es que la sabe, que yo iré luego allá, y verá maravillas. -¡Cuitada de mí! -replicó el ama-; ¿la oración de Santa Apolonia dice vuestra merced que rece?: eso fuera si mi amo lo hubiera de las muelas, pero no lo ha sino de los cascos. -Yo sé lo que digo, señora ama: váyase y no se ponga a disputar conmigo, pues sabe que soy bachiller por Salamanca, que no hay más que bachillear -respondió Carrasco. Y con esto, se fue el ama, y el bachiller fue luego a buscar al cura, a comunicar con él lo que se dirá a su tiempo. En el que estuvieron encerrados don Quijote y Sancho, pasaron las razones que con mucha puntualidad y verdadera relación cuenta la historia. Dijo Sancho a su amo: -Señor, ya yo tengo relucida a mi mujer a que me deje ir con vuestra merced adonde quisiere llevarme. -Reducida has de decir, Sancho -dijo don Quijote-, que no relucida. -Una o dos veces -respondió Sancho-, si mal no me acuerdo, he suplicado a vuestra merced que no me emiende los vocablos, si es que entiende lo que quiero decir en ellos, y que, cuando no los entienda, diga: ''Sancho, o diablo, no te entiendo''; y si yo no me declarare, entonces podrá emendarme; que yo soy tan fócil... -No te entiendo, Sancho -dijo luego don Quijote-, pues no sé qué quiere decir soy tan fócil. -Tan fócil quiere decir -respondió Sancho- soy tan así. -Menos te entiendo agora -replicó don Quijote. -Pues si no me puede entender -respondió Sancho-, no sé cómo lo diga: no sé más, y Dios sea conmigo. -Ya, ya caigo -respondió don Quijote- en ello: tú quieres decir que eres tan dócil, blando y mañero que tomarás lo que yo te dijere, y pasarás por lo que te enseñare. -Apostaré yo -dijo Sancho- que desde el emprincipio me caló y me entendió, sino que quiso turbarme por oírme decir otras docientas patochadas. -Podrá ser -replicó don Quijote-. Y, en efecto, ¿qué dice Teresa? -Teresa dice -dijo Sancho- que ate bien mi dedo con vuestra merced, y que hablen cartas y callen barbas, porque quien destaja no baraja, pues más vale un toma que dos te daré. Y yo digo que el consejo de la mujer es poco, y el que no le toma es loco. -Y yo lo digo también -respondió don Quijote-. Decid, Sancho amigo; pasá adelante, que habláis hoy de perlas. -Es el caso -replicó Sancho- que, como vuestra merced mejor sabe, todos estamos sujetos a la muerte, y que hoy somos y mañana no, y que tan presto se va el cordero como el carnero, y que nadie puede prometerse en este mundo más horas de vida de las que Dios quisiere darle, porque la muerte es sorda, y, cuando llega a llamar a las puertas de nuestra vida, siempre va depriesa y no la harán detener ni ruegos, ni fuerzas, ni ceptros, ni mitras, según es pública voz y fama, y según nos lo dicen por esos púlpitos. -Todo eso es verdad -dijo don Quijote-, pero no sé dónde vas a parar. -Voy a parar -dijo Sancho- en que vuesa merced me señale salario conocido de lo que me ha de dar cada mes el tiempo que le sirviere, y que el tal salario se me pague de su hacienda; que no quiero estar a mercedes, que llegan tarde, o mal, o nunca; con lo mío me ayude Dios. En fin, yo quiero saber lo que gano, poco o mucho que sea, que sobre un huevo pone la gallina, y muchos pocos hacen un mucho, y mientras se gana algo no se pierde nada. Verdad sea que si sucediese, lo cual ni lo creo ni lo espero, que vuesa merced me diese la ínsula que me tiene prometida, no soy tan ingrato, ni llevo las cosas tan por los cabos, que no querré que se aprecie lo que montare la renta de la tal ínsula, y se descuente de mi salario gata por cantidad. -Sancho amigo -respondió don Quijote-, a las veces, tan buena suele ser una gata como una rata. -Ya entiendo -dijo Sancho-: yo apostaré que había de decir rata, y no gata; pero no importa nada, pues vuesa merced me ha entendido. -Y tan entendido -respondió don Quijote- que he penetrado lo último de tus pensamientos, y sé al blanco que tiras con las inumerables saetas de tus refranes. Mira, Sancho: yo bien te señalaría salario, si hubiera hallado en alguna de las historias de los caballeros andantes ejemplo que me descubriese y mostrase, por algún pequeño resquicio, qué es lo que solían ganar cada mes, o cada año; pero yo he leído todas o las más de sus historias, y no me acuerdo haber leído que ningún caballero andante haya señalado conocido salario a su escudero. Sólo sé que todos servían a merced, y que, cuando menos se lo pensaban, si a sus señores les había corrido bien la suerte, se hallaban premiados con una ínsula, o con otra cosa equivalente, y, por lo menos, quedaban con título y señoría. Si con estas esperanzas y aditamentos vos, Sancho, gustáis de volver a servirme, sea en buena hora: que pensar que yo he de sacar de sus términos y quicios la antigua usanza de la caballería andante es pensar en lo escusado. Así que, Sancho mío, volveos a vuestra casa, y declarad a vuestra Teresa mi intención; y si ella gustare y vos gustáredes de estar a merced conmigo, bene quidem; y si no, tan amigos como de antes; que si al palomar no le falta cebo, no le faltarán palomas. Y advertid, hijo, que vale más buena esperanza que ruin posesión, y buena queja que mala paga. Hablo de esta manera, Sancho, por daros a entender que también como vos sé yo arrojar refranes como llovidos. Y, finalmente, quiero decir, y os digo, que si no queréis venir a merced conmigo y correr la suerte que yo corriere, que Dios quede con vos y os haga un santo; que a mí no me faltarán escuderos más obedientes, más solícitos, y no tan empachados ni tan habladores como vos. Cuando Sancho oyó la firme resolución de su amo se le anubló el cielo y se le cayeron las alas del corazón, porque tenía creído que su señor no se iría sin él por todos los haberes del mundo; y así, estando suspenso y pensativo, entró Sansón Carrasco y la sobrina, deseosos de oír con qué razones persuadía a su señor que no tornarse a buscar las aventuras. Llegó Sansón, socarrón famoso, y, abrazándole como la vez primera y con voz levantada, le dijo: -¡Oh flor de la andante caballería; oh luz resplandeciente de las armas; oh honor y espejo de la nación española! Plega a Dios todopoderoso, donde más largamente se contiene, que la persona o personas que pusieren impedimento y estorbaren tu tercera salida, que no la hallen en el laberinto de sus deseos, ni jamás se les cumpla lo que mal desearen. Y, volviéndose al ama, le dijo: -Bien puede la señora ama no rezar más la oración de Santa Apolonia, que yo sé que es determinación precisa de las esferas que el señor don Quijote vuelva a ejecutar sus altos y nuevos pensamientos, y yo encargaría mucho mi conciencia si no intimase y persuadiese a este caballero que no tenga más tiempo encogida y detenida la fuerza de su valeroso brazo y la bondad de su ánimo valentísimo, porque defrauda con su tardanza el derecho de los tuertos, el amparo de los huérfanos, la honra de las doncellas, el favor de las viudas y el arrimo de las casadas, y otras cosas deste jaez, que tocan, atañen, dependen y son anejas a la orden de la caballería andante. ¡Ea, señor don Quijote mío, hermoso y bravo, antes hoy que mañana se ponga vuestra merced y su grandeza en camino; y si alguna cosa faltare para ponerle en ejecución, aquí estoy yo para suplirla con mi persona y hacienda; y si fuere necesidad servir a tu magnificencia de escudero, lo tendré a felicísima ventura! A esta sazón, dijo don Quijote, volviéndose a Sancho: -¿No te dije yo, Sancho, que me habían de sobrar escuderos? Mira quién se ofrece a serlo, sino el inaudito bachiller Sansón Carrasco, perpetuo trastulo y regocijador de los patios de las escuelas salmanticenses, sano de su persona, ágil de sus miembros, callado, sufridor así del calor como del frío, así de la hambre como de la sed, con todas aquellas partes que se requieren para ser escudero de un caballero andante. Pero no permita el cielo que, por seguir mi gusto, desjarrete y quiebre la coluna de las letras y el vaso de las ciencias, y tronque la palma eminente de las buenas y liberales artes. Quédese el nuevo Sansón en su patria, y, honrándola, honre juntamente las canas de sus ancianos padres; que yo con cualquier escudero estaré contento, ya que Sancho no se digna de venir conmigo. -Sí digno -respondió Sancho, enternecido y llenos de lágrimas los ojos; y prosiguió-: No se dirá por mí, señor mío: el pan comido y la compañía deshecha; sí, que no vengo yo de alguna alcurnia desagradecida, que ya sabe todo el mundo, y especialmente mi pueblo, quién fueron los Panzas, de quien yo deciendo, y más, que tengo conocido y calado por muchas buenas obras, y por más buenas palabras, el deseo que vuestra merced tiene de hacerme merced; y si me he puesto en cuentas de tanto más cuanto acerca de mi salario, ha sido por complacer a mi mujer; la cual, cuando toma la mano a persuadir una cosa, no hay mazo que tanto apriete los aros de una cuba como ella aprieta a que se haga lo que quiere; pero, en efeto, el hombre ha de ser hombre, y la mujer, mujer; y, pues yo soy hombre dondequiera, que no lo puedo negar, también lo quiero ser en mi casa, pese a quien pesare; y así, no hay más que hacer, sino que vuestra merced ordene su testamento con su codicilo, en modo que no se pueda revolcar, y pongámonos luego en camino, porque no padezca el alma del señor Sansón, que dice que su conciencia le lita que persuada a vuestra merced a salir vez tercera por ese mundo; y yo de nuevo me ofrezco a servir a vuestra merced fiel y legalmente, tan bien y mejor que cuantos escuderos han servido a caballeros andantes en los pasados y presentes tiempos. Admirado quedó el bachiller de oír el término y modo de hablar de Sancho Panza; que, puesto que había leído la primera historia de su señor, nunca creyó que era tan gracioso como allí le pintan; pero, oyéndole decir ahora testamento y codicilo que no se pueda revolcar, en lugar de testamento y codicilo que no se pueda revocar, creyó todo lo que dél había leído, y confirmólo por uno de los más solenes mentecatos de nuestros siglos; y dijo entre sí que tales dos locos como amo y mozo no se habrían visto en el mundo. Finalmente, don Quijote y Sancho se abrazaron y quedaron amigos, y con parecer y beneplácito del gran Carrasco, que por entonces era su oráculo, se ordenó que de allí a tres días fuese su partida; en los cuales habría lugar de aderezar lo necesario para el viaje, y de buscar una celada de encaje, que en todas maneras dijo don Quijote que la había de llevar. Ofreciósela Sansón, porque sabía no se la negaría un amigo suyo que la tenía, puesto que estaba más escura por el orín y el moho que clara y limpia por el terso acero. Las maldiciones que las dos, ama y sobrina, echaron al bachiller no tuvieron cuento: mesaron sus cabellos, arañaron sus rostros, y, al modo de las endechaderas que se usaban, lamentaban la partida como si fuera la muerte de su señor. El designo que tuvo Sansón, para persuadirle a que otra vez saliese, fue hacer lo que adelante cuenta la historia, todo por consejo del cura y del barbero, con quien él antes lo había comunicado. En resolución, en aquellos tres días don Quijote y Sancho se acomodaron de lo que les pareció convenirles; y, habiendo aplacado Sancho a su mujer, y don Quijote a su sobrina y a su ama, al anochecer, sin que nadie lo viese, sino el bachiller, que quiso acompañarles media legua del lugar, se pusieron en camino del Toboso: don Quijote sobre su buen Rocinante, y Sancho sobre su antiguo rucio, proveídas las alforjas de cosas tocantes a la bucólica, y la bolsa de dineros que le dio don Quijote para lo que se ofreciese. Abrazóle Sansón, y suplicóle le avisase de su buena o mala suerte, para alegrarse con ésta o entristecerse con aquélla, como las leyes de su amistad pedían. Prometióselo don Quijote, dio Sansón la vuelta a su lugar, y los dos tomaron la de la gran ciudad del Toboso. Capítulo VIII. Donde se cuenta lo que le sucedió a don Quijote, yendo a ver su señora Dulcinea del Toboso ''¡Bendito sea el poderoso Alá! -dice Hamete Benengeli al comienzo deste octavo capítulo-. ¡Bendito sea Alá!'', repite tres veces; y dice que da estas bendiciones por ver que tiene ya en campaña a don Quijote y a Sancho, y que los letores de su agradable historia pueden hacer cuenta que desde este punto comienzan las hazañas y donaires de don Quijote y de su escudero; persuádeles que se les olviden las pasadas caballerías del ingenioso hidalgo, y pongan los ojos en las que están por venir, que desde agora en el camino del Toboso comienzan, como las otras comenzaron en los campos de Montiel, y no es mucho lo que pide para tanto como él promete; y así prosigue diciendo: Solos quedaron don Quijote y Sancho, y, apenas se hubo apartado Sansón, cuando comenzó a relinchar Rocinante y a sospirar el rucio, que de entrambos, caballero y escudero, fue tenido a buena señal y por felicísimo agüero; aunque, si se ha de contar la verdad, más fueron los sospiros y rebuznos del rucio que los relinchos del rocín, de donde coligió Sancho que su ventura había de sobrepujar y ponerse encima de la de su señor, fundándose no sé si en astrología judiciaria que él se sabía, puesto que la historia no lo declara; sólo le oyeron decir que, cuando tropezaba o caía, se holgara no haber salido de casa, porque del tropezar o caer no se sacaba otra cosa sino el zapato roto o las costillas quebradas; y, aunque tonto, no andaba en esto muy fuera de camino. Díjole don Quijote: -Sancho amigo, la noche se nos va entrando a más andar, y con más escuridad de la que habíamos menester para alcanzar a ver con el día al Toboso, adonde tengo determinado de ir antes que en otra aventura me ponga, y allí tomaré la bendición y buena licencia de la sin par Dulcinea, con la cual licencia pienso y tengo por cierto de acabar y dar felice cima a toda peligrosa aventura, porque ninguna cosa desta vida hace más valientes a los caballeros andantes que verse favorecidos de sus damas. -Yo así lo creo -respondió Sancho-; pero tengo por dificultoso que vuestra merced pueda hablarla ni verse con ella, en parte, a lo menos, que pueda recebir su bendición, si ya no se la echa desde las bardas del corral, por donde yo la vi la vez primera, cuando le llevé la carta donde iban las nuevas de las sandeces y locuras que vuestra merced quedaba haciendo en el corazón de Sierra Morena. -¿Bardas de corral se te antojaron aquéllas, Sancho -dijo don Quijote-, adonde o por donde viste aquella jamás bastantemente alabada gentileza y hermosura? No debían de ser sino galerías o corredores, o lonjas, o como las llaman, de ricos y reales palacios. -Todo pudo ser -respondió Sancho-, pero a mí bardas me parecieron, si no es que soy falto de memoria. -Con todo eso, vamos allá, Sancho -replicó don Quijote-, que como yo la vea, eso se me da que sea por bardas que por ventanas, o por resquicios, o verjas de jardines; que cualquier rayo que del sol de su belleza llegue a mis ojos alumbrará mi entendimiento y fortalecerá mi corazón, de modo que quede único y sin igual en la discreción y en la valentía. -Pues en verdad, señor -respondió Sancho-, que cuando yo vi ese sol de la señora Dulcinea del Toboso, que no estaba tan claro, que pudiese echar de sí rayos algunos, y debió de ser que, como su merced estaba ahechando aquel trigo que dije, el mucho polvo que sacaba se le puso como nube ante el rostro y se le escureció. -¡Que todavía das, Sancho -dijo don Quijote-, en decir, en pensar, en creer y en porfiar que mi señora Dulcinea ahechaba trigo, siendo eso un menester y ejercicio que va desviado de todo lo que hacen y deben hacer las personas principales que están constituidas y guardadas para otros ejercicios y entretenimientos, que muestran a tiro de ballesta su principalidad...! Mal se te acuerdan a ti, ¡oh Sancho!, aquellos versos de nuestro poeta donde nos pinta las labores que hacían allá en sus moradas de cristal aquellas cuatro ninfas que del Tajo amado sacaron las cabezas, y se sentaron a labrar en el prado verde aquellas ricas telas que allí el ingenioso poeta nos describe, que todas eran de oro, sirgo y perlas contestas y tejidas. Y desta manera debía de ser el de mi señora cuando tú la viste; sino que la envidia que algún mal encantador debe de tener a mis cosas, todas las que me han de dar gusto trueca y vuelve en diferentes figuras que ellas tienen; y así, temo que, en aquella historia que dicen que anda impresa de mis hazañas, si por ventura ha sido su autor algún sabio mi enemigo, habrá puesto unas cosas por otras, mezclando con una verdad mil mentiras, divertiéndose a contar otras acciones fuera de lo que requiere la continuación de una verdadera historia. ¡Oh envidia, raíz de infinitos males y carcoma de las virtudes! Todos los vicios, Sancho, traen un no sé qué de deleite consigo, pero el de la envidia no trae sino disgustos, rancores y rabias. -Eso es lo que yo digo también -respondió Sancho-, y pienso que en esa leyenda o historia que nos dijo el bachiller Carrasco que de nosotros había visto debe de andar mi honra a coche acá, cinchado, y, como dicen, al estricote, aquí y allí, barriendo las calles. Pues, a fe de bueno, que no he dicho yo mal de ningún encantador, ni tengo tantos bienes que pueda ser envidiado; bien es verdad que soy algo malicioso, y que tengo mis ciertos asomos de bellaco, pero todo lo cubre y tapa la gran capa de la simpleza mía, siempre natural y nunca artificiosa. Y cuando otra cosa no tuviese sino el creer, como siempre creo, firme y verdaderamente en Dios y en todo aquello que tiene y cree la Santa Iglesia Católica Romana, y el ser enemigo mortal, como lo soy, de los judíos, debían los historiadores tener misericordia de mí y tratarme bien en sus escritos. Pero digan lo que quisieren; que desnudo nací, desnudo me hallo: ni pierdo ni gano; aunque, por verme puesto en libros y andar por ese mundo de mano en mano, no se me da un higo que digan de mí todo lo que quisieren. -Eso me parece, Sancho -dijo don Quijote-, a lo que sucedió a un famoso poeta destos tiempos, el cual, habiendo hecho una maliciosa sátira contra todas las damas cortesanas, no puso ni nombró en ella a una dama que se podía dudar si lo era o no; la cual, viendo que no estaba en la lista de las demás, se quejó al poeta, diciéndole que qué había visto en ella para no ponerla en el número de las otras, y que alargase la sátira, y la pusiese en el ensanche; si no, que mirase para lo que había nacido. Hízolo así el poeta, y púsola cual no digan dueñas, y ella quedó satisfecha, por verse con fama, aunque infame. También viene con esto lo que cuentan de aquel pastor que puso fuego y abrasó el templo famoso de Diana, contado por una de las siete maravillas del mundo, sólo porque quedase vivo su nombre en los siglos venideros; y, aunque se mandó que nadie le nombrase, ni hiciese por palabra o por escrito mención de su nombre, porque no consiguiese el fin de su deseo, todavía se supo que se llamaba Eróstrato. También alude a esto lo que sucedió al grande emperador Carlo Quinto con un caballero en Roma. Quiso ver el emperador aquel famoso templo de la Rotunda, que en la antigüedad se llamó el templo de todos los dioses, y ahora, con mejor vocación, se llama de todos los santos, y es el edificio que más entero ha quedado de los que alzó la gentilidad en Roma, y es el que más conserva la fama de la grandiosidad y magnificencia de sus fundadores: él es de hechura de una media naranja, grandísimo en estremo, y está muy claro, sin entrarle otra luz que la que le concede una ventana, o, por mejor decir, claraboya redonda que está en su cima, desde la cual mirando el emperador el edificio, estaba con él y a su lado un caballero romano, declarándole los primores y sutilezas de aquella gran máquina y memorable arquitetura; y, habiéndose quitado de la claraboya, dijo al emperador: ''Mil veces, Sacra Majestad, me vino deseo de abrazarme con vuestra Majestad y arrojarme de aquella claraboya abajo, por dejar de mí fama eterna en el mundo''. ''Yo os agradezco -respondió el emperador- el no haber puesto tan mal pensamiento en efeto, y de aquí adelante no os pondré yo en ocasión que volváis a hacer prueba de vuestra lealtad; y así, os mando que jamás me habléis, ni estéis donde yo estuviere''. Y, tras estas palabras, le hizo una gran merced. Quiero decir, Sancho, que el deseo de alcanzar fama es activo en gran manera. ¿Quién piensas tú que arrojó a Horacio del puente abajo, armado de todas armas, en la profundidad del Tibre? ¿Quién abrasó el brazo y la mano a Mucio? ¿Quién impelió a Curcio a lanzarse en la profunda sima ardiente que apareció en la mitad de Roma? ¿Quién, contra todos los agüeros que en contra se le habían mostrado, hizo pasar el Rubicón a César? Y, con ejemplos más modernos, ¿quién barrenó los navíos y dejó en seco y aislados los valerosos españoles guiados por el cortesísimo Cortés en el Nuevo Mundo? Todas estas y otras grandes y diferentes hazañas son, fueron y serán obras de la fama, que los mortales desean como premios y parte de la inmortalidad que sus famosos hechos merecen, puesto que los cristianos, católicos y andantes caballeros más habemos de atender a la gloria de los siglos venideros, que es eterna en las regiones etéreas y celestes, que a la vanidad de la fama que en este presente y acabable siglo se alcanza; la cual fama, por mucho que dure, en fin se ha de acabar con el mesmo mundo, que tiene su fin señalado. Así, ¡oh Sancho!, que nuestras obras no han de salir del límite que nos tiene puesto la religión cristiana, que profesamos. Hemos de matar en los gigantes a la soberbia; a la envidia, en la generosidad y buen pecho; a la ira, en el reposado continente y quietud del ánimo; a la gula y al sueño, en el poco comer que comemos y en el mucho velar que velamos; a la lujuria y lascivia, en la lealtad que guardamos a las que hemos hecho señoras de nuestros pensamientos; a la pereza, con andar por todas las partes del mundo, buscando las ocasiones que nos puedan hacer y hagan, sobre cristianos, famosos caballeros. Ves aquí, Sancho, los medios por donde se alcanzan los estremos de alabanzas que consigo trae la buena fama. -Todo lo que vuestra merced hasta aquí me ha dicho -dijo Sancho- lo he entendido muy bien, pero, con todo eso, querría que vuestra merced me sorbiese una duda que agora en este punto me ha venido a la memoria. -Asolviese quieres decir, Sancho -dijo don Quijote-. Di en buen hora, que yo responderé lo que supiere. -Dígame, señor -prosiguió Sancho-: esos Julios o Agostos, y todos esos caballeros hazañosos que ha dicho, que ya son muertos, ¿dónde están agora? -Los gentiles -respondió don Quijote- sin duda están en el infierno; los cristianos, si fueron buenos cristianos, o están en el purgatorio o en el cielo. -Está bien -dijo Sancho-, pero sepamos ahora: esas sepulturas donde están los cuerpos desos señorazos, ¿tienen delante de sí lámparas de plata, o están adornadas las paredes de sus capillas de muletas, de mortajas, de cabelleras, de piernas y de ojos de cera? Y si desto no, ¿de qué están adornadas? A lo que respondió don Quijote: -Los sepulcros de los gentiles fueron por la mayor parte suntuosos templos: las cenizas del cuerpo de Julio César se pusieron sobre una pirámide de piedra de desmesurada grandeza, a quien hoy llaman en Roma La aguja de San Pedro; al emperador Adriano le sirvió de sepultura un castillo tan grande como una buena aldea, a quien llamaron Moles Hadriani, que agora es el castillo de Santángel en Roma; la reina Artemisa sepultó a su marido Mausoleo en un sepulcro que se tuvo por una de las siete maravillas del mundo; pero ninguna destas sepulturas ni otras muchas que tuvieron los gentiles se adornaron con mortajas ni con otras ofrendas y señales que mostrasen ser santos los que en ellas estaban sepultados. -A eso voy -replicó Sancho-. Y dígame agora: ¿cuál es más: resucitar a un muerto, o matar a un gigante? -La respuesta está en la mano -respondió don Quijote-: más es resucitar a un muerto. -Cogido le tengo -dijo Sancho-: luego la fama del que resucita muertos, da vista a los ciegos, endereza los cojos y da salud a los enfermos, y delante de sus sepulturas arden lámparas, y están llenas sus capillas de gentes devotas que de rodillas adoran sus reliquias, mejor fama será, para este y para el otro siglo, que la que dejaron y dejaren cuantos emperadores gentiles y caballeros andantes ha habido en el mundo. -También confieso esa verdad -respondió don Quijote. -Pues esta fama, estas gracias, estas prerrogativas, como llaman a esto -respondió Sancho-, tienen los cuerpos y las reliquias de los santos que, con aprobación y licencia de nuestra santa madre Iglesia, tienen lámparas, velas, mortajas, muletas, pinturas, cabelleras, ojos, piernas, con que aumentan la devoción y engrandecen su cristiana fama. Los cuerpos de los santos o sus reliquias llevan los reyes sobre sus hombros, besan los pedazos de sus huesos, adornan y enriquecen con ellos sus oratorios y sus más preciados altares... -¿Qué quieres que infiera, Sancho, de todo lo que has dicho? -dijo don Quijote. -Quiero decir -dijo Sancho- que nos demos a ser santos, y alcanzaremos más brevemente la buena fama que pretendemos; y advierta, señor, que ayer o antes de ayer, que, según ha poco se puede decir desta manera, canonizaron o beatificaron dos frailecitos descalzos, cuyas cadenas de hierro con que ceñían y atormentaban sus cuerpos se tiene ahora a gran ventura el besarlas y tocarlas, y están en más veneración que está, según dije, la espada de Roldán en la armería del rey, nuestro señor, que Dios guarde. Así que, señor mío, más vale ser humilde frailecito, de cualquier orden que sea, que valiente y andante caballero; mas alcanzan con Dios dos docenas de diciplinas que dos mil lanzadas, ora las den a gigantes, ora a vestiglos o a endrigos. -Todo eso es así -respondió don Quijote-, pero no todos podemos ser frailes, y muchos son los caminos por donde lleva Dios a los suyos al cielo: religión es la caballería; caballeros santos hay en la gloria. -Sí -respondió Sancho-, pero yo he oído decir que hay más frailes en el cielo que caballeros andantes. -Eso es -respondió don Quijote- porque es mayor el número de los religiosos que el de los caballeros. -Muchos son los andantes -dijo Sancho. -Muchos -respondió don Quijote-, pero pocos los que merecen nombre de caballeros. En estas y otras semejantes pláticas se les pasó aquella noche y el día siguiente, sin acontecerles cosa que de contar fuese, de que no poco le pesó a don Quijote. En fin, otro día, al anochecer, descubrieron la gran ciudad del Toboso, con cuya vista se le alegraron los espíritus a don Quijote y se le entristecieron a Sancho, porque no sabía la casa de Dulcinea, ni en su vida la había visto, como no la había visto su señor; de modo que el uno por verla, y el otro por no haberla visto, estaban alborotados, y no imaginaba Sancho qué había de hacer cuando su dueño le enviase al Toboso. Finalmente, ordenó don Quijote entrar en la ciudad entrada la noche, y, en tanto que la hora se llegaba, se quedaron entre unas encinas que cerca del Toboso estaban, y, llegado el determinado punto, entraron en la ciudad, donde les sucedió cosas que a cosas llegan. Capítulo IX. Donde se cuenta lo que en él se verá Media noche era por filo, poco más a menos, cuando don Quijote y Sancho dejaron el monte y entraron en el Toboso. Estaba el pueblo en un sosegado silencio, porque todos sus vecinos dormían y reposaban a pierna tendida, como suele decirse. Era la noche entreclara, puesto que quisiera Sancho que fuera del todo escura, por hallar en su escuridad disculpa de su sandez. No se oía en todo el lugar sino ladridos de perros, que atronaban los oídos de don Quijote y turbaban el corazón de Sancho. De cuando en cuando, rebuznaba un jumento, gruñían puercos, mayaban gatos, cuyas voces, de diferentes sonidos, se aumentaban con el silencio de la noche, todo lo cual tuvo el enamorado caballero a mal agüero; pero, con todo esto, dijo a Sancho: -Sancho, hijo, guía al palacio de Dulcinea: quizá podrá ser que la hallemos despierta. -¿A qué palacio tengo de guiar, cuerpo del sol -respondió Sancho-, que en el que yo vi a su grandeza no era sino casa muy pequeña? -Debía de estar retirada, entonces -respondió don Quijote-, en algún pequeño apartamiento de su alcázar, solazándose a solas con sus doncellas, como es uso y costumbre de las altas señoras y princesas. -Señor -dijo Sancho-, ya que vuestra merced quiere, a pesar mío, que sea alcázar la casa de mi señora Dulcinea, ¿es hora ésta por ventura de hallar la puerta abierta? Y ¿será bien que demos aldabazos para que nos oyan y nos abran, metiendo en alboroto y rumor toda la gente? ¿Vamos por dicha a llamar a la casa de nuestras mancebas, como hacen los abarraganados, que llegan, y llaman, y entran a cualquier hora, por tarde que sea? -Hallemos primero una por una el alcázar -replicó don Quijote-, que entonces yo te diré, Sancho, lo que será bien que hagamos. Y advierte, Sancho, que yo veo poco, o que aquel bulto grande y sombra que desde aquí se descubre la debe de hacer el palacio de Dulcinea. -Pues guíe vuestra merced -respondió Sancho-: quizá será así; aunque yo lo veré con los ojos y lo tocaré con las manos, y así lo creeré yo como creer que es ahora de día. Guió don Quijote, y, habiendo andado como docientos pasos, dio con el bulto que hacía la sombra, y vio una gran torre, y luego conoció que el tal edificio no era alcázar, sino la iglesia principal del pueblo. Y dijo: -Con la iglesia hemos dado, Sancho. -Ya lo veo -respondió Sancho-; y plega a Dios que no demos con nuestra sepultura, que no es buena señal andar por los cimenterios a tales horas, y más, habiendo yo dicho a vuestra merced, si mal no me acuerdo, que la casa desta señora ha de estar en una callejuela sin salida. -¡Maldito seas de Dios, mentecato! -dijo don Quijote-. ¿Adónde has tú hallado que los alcázares y palacios reales estén edificados en callejuelas sin salida? -Señor -respondió Sancho-, en cada tierra su uso: quizá se usa aquí en el Toboso edificar en callejuelas los palacios y edificios grandes; y así, suplico a vuestra merced me deje buscar por estas calles o callejuelas que se me ofrecen: podría ser que en algún rincón topase con ese alcázar, que le vea yo comido de perros, que así nos trae corridos y asendereados. -Habla con respeto, Sancho, de las cosas de mi señora -dijo don Quijote-, y tengamos la fiesta en paz, y no arrojemos la soga tras el caldero. -Yo me reportaré -respondió Sancho-; pero, ¿con qué paciencia podré llevar que quiera vuestra merced que de sola una vez que vi la casa de nuestra ama, la haya de saber siempre y hallarla a media noche, no hallándola vuestra merced, que la debe de haber visto millares de veces? -Tú me harás desesperar, Sancho -dijo don Quijote-. Ven acá, hereje: ¿no te he dicho mil veces que en todos los días de mi vida no he visto a la sin par Dulcinea, ni jamás atravesé los umbrales de su palacio, y que sólo estoy enamorado de oídas y de la gran fama que tiene de hermosa y discreta? -Ahora lo oigo -respondió Sancho-; y digo que, pues vuestra merced no la ha visto, ni yo tampoco... -Eso no puede ser -replicó don Quijote-; que, por lo menos, ya me has dicho tú que la viste ahechando trigo, cuando me trujiste la respuesta de la carta que le envié contigo. -No se atenga a eso, señor -respondió Sancho-, porque le hago saber que también fue de oídas la vista y la respuesta que le truje; porque, así sé yo quién es la señora Dulcinea como dar un puño en el cielo. -Sancho, Sancho -respondió don Quijote-, tiempos hay de burlar, y tiempos donde caen y parecen mal las burlas. No porque yo diga que ni he visto ni hablado a la señora de mi alma has tú de decir también que ni la has hablado ni visto, siendo tan al revés como sabes. Estando los dos en estas pláticas, vieron que venía a pasar por donde estaban uno con dos mulas, que, por el ruido que hacía el arado, que arrastraba por el suelo, juzgaron que debía de ser labrador, que habría madrugado antes del día a ir a su labranza; y así fue la verdad. Venía el labrador cantando aquel romance que dicen: Mala la hubistes, franceses, en esa de Roncesvalles. -Que me maten, Sancho -dijo, en oyéndole, don Quijote-, si nos ha de suceder cosa buena esta noche. ¿No oyes lo que viene cantando ese villano? -Sí oigo -respondió Sancho-; pero, ¿qué hace a nuestro propósito la caza de Roncesvalles? Así pudiera cantar el romance de Calaínos, que todo fuera uno para sucedernos bien o mal en nuestro negocio. Llegó, en esto, el labrador, a quien don Quijote preguntó: -¿Sabréisme decir, buen amigo, que buena ventura os dé Dios, dónde son por aquí los palacios de la sin par princesa doña Dulcinea del Toboso? -Señor -respondió el mozo-, yo soy forastero y ha pocos días que estoy en este pueblo, sirviendo a un labrador rico en la labranza del campo; en esa casa frontera viven el cura y el sacristán del lugar; entrambos, o cualquier dellos, sabrá dar a vuestra merced razón desa señora princesa, porque tienen la lista de todos los vecinos del Toboso; aunque para mí tengo que en todo él no vive princesa alguna; muchas señoras, sí, principales, que cada una en su casa puede ser princesa. -Pues entre ésas -dijo don Quijote- debe de estar, amigo, ésta por quien te pregunto. -Podría ser -respondió el mozo-; y adiós, que ya viene el alba. Y, dando a sus mulas, no atendió a más preguntas. Sancho, que vio suspenso a su señor y asaz mal contento, le dijo: -Señor, ya se viene a más andar el día, y no será acertado dejar que nos halle el sol en la calle; mejor será que nos salgamos fuera de la ciudad, y que vuestra merced se embosque en alguna floresta aquí cercana, y yo volveré de día, y no dejaré ostugo en todo este lugar donde no busque la casa, alcázar o palacio de mi señora, y asaz sería de desdichado si no le hallase; y, hallándole, hablaré con su merced, y le diré dónde y cómo queda vuestra merced esperando que le dé orden y traza para verla, sin menoscabo de su honra y fama. -Has dicho, Sancho -dijo don Quijote-, mil sentencias encerradas en el círculo de breves palabras: el consejo que ahora me has dado le apetezco y recibo de bonísima gana. Ven, hijo, y vamos a buscar donde me embosque, que tú volverás, como dices, a buscar, a ver y hablar a mi señora, de cuya discreción y cortesía espero más que milagrosos favores. Rabiaba Sancho por sacar a su amo del pueblo, porque no averiguase la mentira de la respuesta que de parte de Dulcinea le había llevado a Sierra Morena; y así, dio priesa a la salida, que fue luego, y a dos millas del lugar hallaron una floresta o bosque, donde don Quijote se emboscó en tanto que Sancho volvía a la ciudad a hablar a Dulcinea; en cuya embajada le sucedieron cosas que piden nueva atención y nuevo crédito. Capítulo X. Donde se cuenta la industria que Sancho tuvo para encantar a la señora Dulcinea, y de otros sucesos tan ridículos como verdaderos Llegando el autor desta grande historia a contar lo que en este capítulo cuenta, dice que quisiera pasarle en silencio, temeroso de que no había de ser creído, porque las locuras de don Quijote llegaron aquí al término y raya de las mayores que pueden imaginarse, y aun pasaron dos tiros de ballesta más allá de las mayores. Finalmente, aunque con este miedo y recelo, las escribió de la misma manera que él las hizo, sin añadir ni quitar a la historia un átomo de la verdad, sin dársele nada por las objeciones que podían ponerle de mentiroso. Y tuvo razón, porque la verdad adelgaza y no quiebra, y siempre anda sobre la mentira como el aceite sobre el agua. Y así, prosiguiendo su historia, dice que, así como don Quijote se emboscó en la floresta, encinar o selva junto al gran Toboso, mandó a Sancho volver a la ciudad, y que no volviese a su presencia sin haber primero hablado de su parte a su señora, pidiéndola fuese servida de dejarse ver de su cautivo caballero, y se dignase de echarle su bendición, para que pudiese esperar por ella felicísimos sucesos de todos sus acometimientos y dificultosas empresas. Encargóse Sancho de hacerlo así como se le mandaba, y de traerle tan buena respuesta como le trujo la vez primera. -Anda, hijo -replicó don Quijote-, y no te turbes cuando te vieres ante la luz del sol de hermosura que vas a buscar. ¡Dichoso tú sobre todos los escuderos del mundo! Ten memoria, y no se te pase della cómo te recibe: si muda las colores el tiempo que la estuvieres dando mi embajada; si se desasosiega y turba oyendo mi nombre; si no cabe en la almohada, si acaso la hallas sentada en el estrado rico de su autoridad; y si está en pie, mírala si se pone ahora sobre el uno, ahora sobre el otro pie; si te repite la respuesta que te diere dos o tres veces; si la muda de blanda en áspera, de aceda en amorosa; si levanta la mano al cabello para componerle, aunque no esté desordenado; finalmente, hijo, mira todas sus acciones y movimientos; porque si tú me los relatares como ellos fueron, sacaré yo lo que ella tiene escondido en lo secreto de su corazón acerca de lo que al fecho de mis amores toca; que has de saber, Sancho, si no lo sabes, que entre los amantes, las acciones y movimientos exteriores que muestran, cuando de sus amores se trata, son certísimos correos que traen las nuevas de lo que allá en lo interior del alma pasa. Ve, amigo, y guíete otra mejor ventura que la mía, y vuélvate otro mejor suceso del que yo quedo temiendo y esperando en esta amarga soledad en que me dejas. -Yo iré y volveré presto -dijo Sancho-; y ensanche vuestra merced, señor mío, ese corazoncillo, que le debe de tener agora no mayor que una avellana, y considere que se suele decir que buen corazón quebranta mala ventura, y que donde no hay tocinos, no hay estacas; y también se dice: donde no piensa, salta la liebre. Dígolo porque si esta noche no hallamos los palacios o alcázares de mi señora, agora que es de día los pienso hallar, cuando menos los piense, y hallados, déjenme a mí con ella. -Por cierto, Sancho -dijo don Quijote-, que siempre traes tus refranes tan a pelo de lo que tratamos cuanto me dé Dios mejor ventura en lo que deseo. Esto dicho, volvió Sancho las espaldas y vareó su rucio, y don Quijote se quedó a caballo, descansando sobre los estribos y sobre el arrimo de su lanza, lleno de tristes y confusas imaginaciones, donde le dejaremos, yéndonos con Sancho Panza, que no menos confuso y pensativo se apartó de su señor que él quedaba; y tanto, que, apenas hubo salido del bosque, cuando, volviendo la cabeza y viendo que don Quijote no parecía, se apeó del jumento, y, sentándose al pie de un árbol, comenzó a hablar consigo mesmo y a decirse: -Sepamos agora, Sancho hermano, adónde va vuesa merced. ¿Va a buscar algún jumento que se le haya perdido? ''No, por cierto''. Pues, ¿qué va a buscar? ''Voy a buscar, como quien no dice nada, a una princesa, y en ella al sol de la hermosura y a todo el cielo junto''. Y ¿adónde pensáis hallar eso que decís, Sancho? ''¿Adónde? En la gran ciudad del Toboso''. Y bien: ¿y de parte de quién la vais a buscar? ''De parte del famoso caballero don Quijote de la Mancha, que desface los tuertos, y da de comer al que ha sed, y de beber al que ha hambre''. Todo eso está muy bien. Y ¿sabéis su casa, Sancho? ''Mi amo dice que han de ser unos reales palacios o unos soberbios alcázares''. Y ¿habéisla visto algún día por ventura? ''Ni yo ni mi amo la habemos visto jamás''. Y ¿paréceos que fuera acertado y bien hecho que si los del Toboso supiesen que estáis vos aquí con intención de ir a sonsacarles sus princesas y a desasosegarles sus damas, viniesen y os moliesen las costillas a puros palos, y no os dejasen hueso sano? ''En verdad que tendrían mucha razón, cuando no considerasen que soy mandado, y que mensajero sois, amigo, no merecéis culpa, non''. No os fiéis en eso, Sancho, porque la gente manchega es tan colérica como honrada, y no consiente cosquillas de nadie. Vive Dios que si os huele, que os mando mala ventura. ''¡Oxte, puto! ¡Allá darás, rayo! ¡No, sino ándeme yo buscando tres pies al gato por el gusto ajeno! Y más, que así será buscar a Dulcinea por el Toboso como a Marica por Rávena, o al bachiller en Salamanca. ¡El diablo, el diablo me ha metido a mí en esto, que otro no!'' Este soliloquio pasó consigo Sancho, y lo que sacó dél fue que volvió a decirse: -Ahora bien, todas las cosas tienen remedio, si no es la muerte, debajo de cuyo yugo hemos de pasar todos, mal que nos pese, al acabar de la vida. Este mi amo, por mil señales, he visto que es un loco de atar, y aun también yo no le quedo en zaga, pues soy más mentecato que él, pues le sigo y le sirvo, si es verdadero el refrán que dice: "Dime con quién andas, decirte he quién eres", y el otro de "No con quien naces, sino con quien paces". Siendo, pues, loco, como lo es, y de locura que las más veces toma unas cosas por otras, y juzga lo blanco por negro y lo negro por blanco, como se pareció cuando dijo que los molinos de viento eran gigantes, y las mulas de los religiosos dromedarios, y las manadas de carneros ejércitos de enemigos, y otras muchas cosas a este tono, no será muy difícil hacerle creer que una labradora, la primera que me topare por aquí, es la señora Dulcinea; y, cuando él no lo crea, juraré yo; y si él jurare, tornaré yo a jurar; y si porfiare, porfiaré yo más, y de manera que tengo de tener la mía siempre sobre el hito, venga lo que viniere. Quizá con esta porfía acabaré con él que no me envíe otra vez a semejantes mensajerías, viendo cuán mal recado le traigo dellas, o quizá pensará, como yo imagino, que algún mal encantador de estos que él dice que le quieren mal la habrá mudado la figura por hacerle mal y daño. Con esto que pensó Sancho Panza quedó sosegado su espíritu, y tuvo por bien acabado su negocio, y deteniéndose allí hasta la tarde, por dar lugar a que don Quijote pensase que le había tenido para ir y volver del Toboso; y sucedióle todo tan bien que, cuando se levantó para subir en el rucio, vio que del Toboso hacia donde él estaba venían tres labradoras sobre tres pollinos, o pollinas, que el autor no lo declara, aunque más se puede creer que eran borricas, por ser ordinaria caballería de las aldeanas; pero, como no va mucho en esto, no hay para qué detenernos en averiguarlo. En resolución: así como Sancho vio a las labradoras, a paso tirado volvió a buscar a su señor don Quijote, y hallóle suspirando y diciendo mil amorosas lamentaciones. Como don Quijote le vio, le dijo: -¿Qué hay, Sancho amigo? ¿Podré señalar este día con piedra blanca, o con negra? -Mejor será -respondió Sancho- que vuesa merced le señale con almagre, como rétulos de cátedras, porque le echen bien de ver los que le vieren. -De ese modo -replicó don Quijote-, buenas nuevas traes. -Tan buenas -respondió Sancho-, que no tiene más que hacer vuesa merced sino picar a Rocinante y salir a lo raso a ver a la señora Dulcinea del Toboso, que con otras dos doncellas suyas viene a ver a vuesa merced. -¡Santo Dios! ¿Qué es lo que dices, Sancho amigo? -dijo don Quijote-. Mira no me engañes, ni quieras con falsas alegrías alegrar mis verdaderas tristezas. -¿Qué sacaría yo de engañar a vuesa merced -respondió Sancho-, y más estando tan cerca de descubrir mi verdad? Pique, señor, y venga, y verá venir a la princesa, nuestra ama, vestida y adornada, en fin, como quien ella es. Sus doncellas y ella todas son una ascua de oro, todas mazorcas de perlas, todas son diamantes, todas rubíes, todas telas de brocado de más de diez altos; los cabellos, sueltos por las espaldas, que son otros tantos rayos del sol que andan jugando con el viento; y, sobre todo, vienen a caballo sobre tres cananeas remendadas, que no hay más que ver. -Hacaneas querrás decir, Sancho. -Poca diferencia hay -respondió Sancho- de cananeas a hacaneas; pero, vengan sobre lo que vinieren, ellas vienen las más galanas señoras que se puedan desear, especialmente la princesa Dulcinea, mi señora, que pasma los sentidos. -Vamos, Sancho hijo -respondió don Quijote-; y, en albricias destas no esperadas como buenas nuevas, te mando el mejor despojo que ganare en la primera aventura que tuviere, y si esto no te contenta, te mando las crías que este año me dieren las tres yeguas mías, que tú sabes que quedan para parir en el prado concejil de nuestro pueblo. -A las crías me atengo -respondió Sancho-, porque de ser buenos los despojos de la primera aventura no está muy cierto. Ya en esto salieron de la selva, y descubrieron cerca a las tres aldeanas. Tendió don Quijote los ojos por todo el camino del Toboso, y como no vio sino a las tres labradoras, turbóse todo, y preguntó a Sancho si las había dejado fuera de la ciudad. -¿Cómo fuera de la ciudad? -respondió-. ¿Por ventura tiene vuesa merced los ojos en el colodrillo, que no vee que son éstas, las que aquí vienen, resplandecientes como el mismo sol a mediodía? -Yo no veo, Sancho -dijo don Quijote-, sino a tres labradoras sobre tres borricos. -¡Agora me libre Dios del diablo! -respondió Sancho-. Y ¿es posible que tres hacaneas, o como se llaman, blancas como el ampo de la nieve, le parezcan a vuesa merced borricos? ¡Vive el Señor, que me pele estas barbas si tal fuese verdad! -Pues yo te digo, Sancho amigo -dijo don Quijote-, que es tan verdad que son borricos, o borricas, como yo soy don Quijote y tú Sancho Panza; a lo menos, a mí tales me parecen. -Calle, señor -dijo Sancho-, no diga la tal palabra, sino despabile esos ojos, y venga a hacer reverencia a la señora de sus pensamientos, que ya llega cerca. Y, diciendo esto, se adelantó a recebir a las tres aldeanas; y, apeándose del rucio, tuvo del cabestro al jumento de una de las tres labradoras, y, hincando ambas rodillas en el suelo, dijo: -Reina y princesa y duquesa de la hermosura, vuestra altivez y grandeza sea servida de recebir en su gracia y buen talente al cautivo caballero vuestro, que allí está hecho piedra mármol, todo turbado y sin pulsos de verse ante vuestra magnífica presencia. Yo soy Sancho Panza, su escudero, y él es el asendereado caballero don Quijote de la Mancha, llamado por otro nombre el Caballero de la Triste Figura. A esta sazón, ya se había puesto don Quijote de hinojos junto a Sancho, y miraba con ojos desencajados y vista turbada a la que Sancho llamaba reina y señora, y, como no descubría en ella sino una moza aldeana, y no de muy buen rostro, porque era carirredonda y chata, estaba suspenso y admirado, sin osar desplegar los labios. Las labradoras estaban asimismo atónitas, viendo aquellos dos hombres tan diferentes hincados de rodillas, que no dejaban pasar adelante a su compañera; pero, rompiendo el silencio la detenida, toda desgraciada y mohína, dijo: -Apártense nora en tal del camino, y déjenmos pasar, que vamos de priesa. A lo que respondió Sancho: -¡Oh princesa y señora universal del Toboso! ¿Cómo vuestro magnánimo corazón no se enternece viendo arrodillado ante vuestra sublimada presencia a la coluna y sustento de la andante caballería? Oyendo lo cual, otra de las dos dijo: -Mas, ¡jo, que te estrego, burra de mi suegro! ¡Mirad con qué se vienen los señoritos ahora a hacer burla de las aldeanas, como si aquí no supiésemos echar pullas como ellos! Vayan su camino, e déjenmos hacer el nueso, y serles ha sano. -Levántate, Sancho -dijo a este punto don Quijote-, que ya veo que la Fortuna, de mi mal no harta, tiene tomados los caminos todos por donde pueda venir algún contento a esta ánima mezquina que tengo en las carnes. Y tú, ¡oh estremo del valor que puede desearse, término de la humana gentileza, único remedio deste afligido corazón que te adora!, ya que el maligno encantador me persigue, y ha puesto nubes y cataratas en mis ojos, y para sólo ellos y no para otros ha mudado y transformado tu sin igual hermosura y rostro en el de una labradora pobre, si ya también el mío no le ha cambiado en el de algún vestiglo, para hacerle aborrecible a tus ojos, no dejes de mirarme blanda y amorosamente, echando de ver en esta sumisión y arrodillamiento que a tu contrahecha hermosura hago, la humildad con que mi alma te adora. -¡Tomá que mi agüelo! -respondió la aldeana-. ¡Amiguita soy yo de oír resquebrajos! Apártense y déjenmos ir, y agradecérselo hemos. Apartóse Sancho y dejóla ir, contentísimo de haber salido bien de su enredo. Apenas se vio libre la aldeana que había hecho la figura de Dulcinea, cuando, picando a su cananea con un aguijón que en un palo traía, dio a correr por el prado adelante. Y, como la borrica sentía la punta del aguijón, que le fatigaba más de lo ordinario, comenzó a dar corcovos, de manera que dio con la señora Dulcinea en tierra; lo cual visto por don Quijote, acudió a levantarla, y Sancho a componer y cinchar el albarda, que también vino a la barriga de la pollina. Acomodada, pues, la albarda, y quiriendo don Quijote levantar a su encantada señora en los brazos sobre la jumenta, la señora, levantándose del suelo, le quitó de aquel trabajo, porque, haciéndose algún tanto atrás, tomó una corridica, y, puestas ambas manos sobre las ancas de la pollina, dio con su cuerpo, más ligero que un halcón, sobre la albarda, y quedó a horcajadas, como si fuera hombre; y entonces dijo Sancho: -¡Vive Roque, que es la señora nuestra ama más ligera que un acotán, y que puede enseñar a subir a la jineta al más diestro cordobés o mejicano! El arzón trasero de la silla pasó de un salto, y sin espuelas hace correr la hacanea como una cebra. Y no le van en zaga sus doncellas; que todas corren como el viento. Y así era la verdad, porque, en viéndose a caballo Dulcinea, todas picaron tras ella y dispararon a correr, sin volver la cabeza atrás por espacio de más de media legua. Siguiólas don Quijote con la vista, y, cuando vio que no parecían, volviéndose a Sancho, le dijo: -Sancho, ¿qué te parece cuán malquisto soy de encantadores? Y mira hasta dónde se estiende su malicia y la ojeriza que me tienen, pues me han querido privar del contento que pudiera darme ver en su ser a mi señora. En efecto, yo nací para ejemplo de desdichados, y para ser blanco y terrero donde tomen la mira y asiesten las flechas de la mala fortuna. Y has también de advertir, Sancho, que no se contentaron estos traidores de haber vuelto y transformado a mi Dulcinea, sino que la transformaron y volvieron en una figura tan baja y tan fea como la de aquella aldeana, y juntamente le quitaron lo que es tan suyo de las principales señoras, que es el buen olor, por andar siempre entre ámbares y entre flores. Porque te hago saber, Sancho, que cuando llegé a subir a Dulcinea sobre su hacanea, según tú dices, que a mí me pareció borrica, me dio un olor de ajos crudos, que me encalabrinó y atosigó el alma. -¡Oh canalla! -gritó a esta sazón Sancho- ¡Oh encantadores aciagos y malintencionados, y quién os viera a todos ensartados por las agallas, como sardinas en lercha! Mucho sabéis, mucho podéis y mucho más hacéis. Bastaros debiera, bellacos, haber mudado las perlas de los ojos de mi señora en agallas alcornoqueñas, y sus cabellos de oro purísimo en cerdas de cola de buey bermejo, y, finalmente, todas sus faciones de buenas en malas, sin que le tocárades en el olor; que por él siquiera sacáramos lo que estaba encubierto debajo de aquella fea corteza; aunque, para decir verdad, nunca yo vi su fealdad, sino su hermosura, a la cual subía de punto y quilates un lunar que tenía sobre el labio derecho, a manera de bigote, con siete o ocho cabellos rubios como hebras de oro y largos de más de un palmo. -A ese lunar -dijo don Quijote-, según la correspondencia que tienen entre sí los del rostro con los del cuerpo, ha de tener otro Dulcinea en la tabla del muslo que corresponde al lado donde tiene el del rostro, pero muy luengos para lunares son pelos de la grandeza que has significado. -Pues yo sé decir a vuestra merced -respondió Sancho- que le parecían allí como nacidos. -Yo lo creo, amigo -replicó don Quijote-, porque ninguna cosa puso la naturaleza en Dulcinea que no fuese perfecta y bien acabada; y así, si tuviera cien lunares como el que dices, en ella no fueran lunares, sino lunas y estrellas resplandecientes. Pero dime, Sancho: aquella que a mí me pareció albarda, que tú aderezaste, ¿era silla rasa o sillón? -No era -respondió Sancho- sino silla a la jineta, con una cubierta de campo que vale la mitad de un reino, según es de rica. -¡Y que no viese yo todo eso, Sancho! -dijo don Quijote-. Ahora torno a decir, y diré mil veces, que soy el más desdichado de los hombres. Harto tenía que hacer el socarrón de Sancho en disimular la risa, oyendo las sandeces de su amo, tan delicadamente engañado. Finalmente, después de otras muchas razones que entre los dos pasaron, volvieron a subir en sus bestias, y siguieron el camino de Zaragoza, adonde pensaban llegar a tiempo que pudiesen hallarse en unas solenes fiestas que en aquella insigne ciudad cada año suelen hacerse. Pero, antes que allá llegasen, les sucedieron cosas que, por muchas, grandes y nuevas, merecen ser escritas y leídas, como se verá adelante. Capítulo XI. De la estraña aventura que le sucedió al valeroso don Quijote con el carro, o carreta, de Las Cortes de la Muerte Pensativo además iba don Quijote por su camino adelante, considerando la mala burla que le habían hecho los encantadores, volviendo a su señora Dulcinea en la mala figura de la aldeana, y no imaginaba qué remedio tendría para volverla a su ser primero; y estos pensamientos le llevaban tan fuera de sí, que, sin sentirlo, soltó las riendas a Rocinante, el cual, sintiendo la libertad que se le daba, a cada paso se detenía a pacer la verde yerba de que aquellos campos abundaban. De su embelesamiento le volvió Sancho Panza, diciéndole: -Señor, las tristezas no se hicieron para las bestias, sino para los hombres; pero si los hombres las sienten demasiado, se vuelven bestias: vuestra merced se reporte, y vuelva en sí, y coja las riendas a Rocinante, y avive y despierte, y muestre aquella gallardía que conviene que tengan los caballeros andantes. ¿Qué diablos es esto? ¿Qué descaecimiento es éste? ¿Estamos aquí, o en Francia? Mas que se lleve Satanás a cuantas Dulcineas hay en el mundo, pues vale más la salud de un solo caballero andante que todos los encantos y transformaciones de la tierra. -Calla, Sancho -respondió don Quijote con voz no muy desmayada-; calla, digo, y no digas blasfemias contra aquella encantada señora, que de su desgracia y desventura yo solo tengo la culpa: de la invidia que me tienen los malos ha nacido su mala andanza. -Así lo digo yo -respondió Sancho-: quien la vido y la vee ahora, ¿cuál es el corazón que no llora? -Eso puedes tú decir bien, Sancho -replicó don Quijote-, pues la viste en la entereza cabal de su hermosura, que el encanto no se estendió a turbarte la vista ni a encubrirte su belleza: contra mí solo y contra mis ojos se endereza la fuerza de su veneno. Mas, con todo esto, he caído, Sancho, en una cosa, y es que me pintaste mal su hermosura, porque, si mal no me acuerdo, dijiste que tenía los ojos de perlas, y los ojos que parecen de perlas antes son de besugo que de dama; y, a lo que yo creo, los de Dulcinea deben ser de verdes esmeraldas, rasgados, con dos celestiales arcos que les sirven de cejas; y esas perlas quítalas de los ojos y pásalas a los dientes, que sin duda te trocaste, Sancho, tomando los ojos por los dientes. -Todo puede ser -respondió Sancho-, porque también me turbó a mí su hermosura como a vuesa merced su fealdad. Pero encomendémoslo todo a Dios, que Él es el sabidor de las cosas que han de suceder en este valle de lágrimas, en este mal mundo que tenemos, donde apenas se halla cosa que esté sin mezcla de maldad, embuste y bellaquería. De una cosa me pesa, señor mío, más que de otras; que es pensar qué medio se ha de tener cuando vuesa merced venza a algún gigante o otro caballero, y le mande que se vaya a presentar ante la hermosura de la señora Dulcinea: ¿adónde la ha de hallar este pobre gigante, o este pobre y mísero caballero vencido? Paréceme que los veo andar por el Toboso hechos unos bausanes, buscando a mi señora Dulcinea, y, aunque la encuentren en mitad de la calle, no la conocerán más que a mi padre. -Quizá, Sancho -respondió don Quijote-, no se estenderá el encantamento a quitar el conocimiento de Dulcinea a los vencidos y presentados gigantes y caballeros; y, en uno o dos de los primeros que yo venza y le envíe, haremos la experiencia si la ven o no, mandándoles que vuelvan a darme relación de lo que acerca desto les hubiere sucedido. -Digo, señor -replicó Sancho-, que me ha parecido bien lo que vuesa merced ha dicho, y que con ese artificio vendremos en conocimiento de lo que deseamos; y si es que ella a solo vuesa merced se encubre, la desgracia más será de vuesa merced que suya; pero, como la señora Dulcinea tenga salud y contento, nosotros por acá nos avendremos y lo pasaremos lo mejor que pudiéremos, buscando nuestras aventuras y dejando al tiempo que haga de las suyas, que él es el mejor médico destas y de otras mayores enfermedades. Responder quería don Quijote a Sancho Panza, pero estorbóselo una carreta que salió al través del camino, cargada de los más diversos y estraños personajes y figuras que pudieron imaginarse. El que guiaba las mulas y servía de carretero era un feo demonio. Venía la carreta descubierta al cielo abierto, sin toldo ni zarzo. La primera figura que se ofreció a los ojos de don Quijote fue la de la misma Muerte, con rostro humano; junto a ella venía un ángel con unas grandes y pintadas alas; al un lado estaba un emperador con una corona, al parecer de oro, en la cabeza; a los pies de la Muerte estaba el dios que llaman Cupido, sin venda en los ojos, pero con su arco, carcaj y saetas. Venía también un caballero armado de punta en blanco, excepto que no traía morrión, ni celada, sino un sombrero lleno de plumas de diversas colores; con éstas venían otras personas de diferentes trajes y rostros. Todo lo cual visto de improviso, en alguna manera alborotó a don Quijote y puso miedo en el corazón de Sancho; mas luego se alegró don Quijote, creyendo que se le ofrecía alguna nueva y peligrosa aventura, y con este pensamiento, y con ánimo dispuesto de acometer cualquier peligro, se puso delante de la carreta, y, con voz alta y amenazadora, dijo: -Carretero, cochero, o diablo, o lo que eres, no tardes en decirme quién eres, a dó vas y quién es la gente que llevas en tu carricoche, que más parece la barca de Carón que carreta de las que se usan. A lo cual, mansamente, deteniendo el Diablo la carreta, respondió: -Señor, nosotros somos recitantes de la compañía de Angulo el Malo; hemos hecho en un lugar que está detrás de aquella loma, esta mañana, que es la octava del Corpus, el auto de Las Cortes de la Muerte, y hémosle de hacer esta tarde en aquel lugar que desde aquí se parece; y, por estar tan cerca y escusar el trabajo de desnudarnos y volvernos a vestir, nos vamos vestidos con los mesmos vestidos que representamos. Aquel mancebo va de Muerte; el otro, de Ãngel; aquella mujer, que es la del autor, va de Reina; el otro, de Soldado; aquél, de Emperador, y yo, de Demonio, y soy una de las principales figuras del auto, porque hago en esta compañía los primeros papeles. Si otra cosa vuestra merced desea saber de nosotros, pregúntemelo, que yo le sabré responder con toda puntualidad; que, como soy demonio, todo se me alcanza. -Por la fe de caballero andante -respondió don Quijote-, que, así como vi este carro, imaginé que alguna grande aventura se me ofrecía; y ahora digo que es menester tocar las apariencias con la mano para dar lugar al desengaño. Andad con Dios, buena gente, y haced vuestra fiesta, y mirad si mandáis algo en que pueda seros de provecho, que lo haré con buen ánimo y buen talante, porque desde mochacho fui aficionado a la carátula, y en mi mocedad se me iban los ojos tras la farándula. Estando en estas pláticas, quiso la suerte que llegase uno de la compañía, que venía vestido de bojiganga, con muchos cascabeles, y en la punta de un palo traía tres vejigas de vaca hinchadas; el cual moharracho, llegándose a don Quijote, comenzó a esgrimir el palo y a sacudir el suelo con las vejigas, y a dar grandes saltos, sonando los cascabeles, cuya mala visión así alborotó a Rocinante, que, sin ser poderoso a detenerle don Quijote, tomando el freno entre los dientes, dio a correr por el campo con más ligereza que jamás prometieron los huesos de su notomía. Sancho, que consideró el peligro en que iba su amo de ser derribado, saltó del rucio, y a toda priesa fue a valerle; pero, cuando a él llegó, ya estaba en tierra, y junto a él, Rocinante, que, con su amo, vino al suelo: ordinario fin y paradero de las lozanías de Rocinante y de sus atrevimientos. Mas, apenas hubo dejado su caballería Sancho por acudir a don Quijote, cuando el demonio bailador de las vejigas saltó sobre el rucio, y, sacudiéndole con ellas, el miedo y ruido, más que el dolor de los golpes, le hizo volar por la campaña hacia el lugar donde iban a hacer la fiesta. Miraba Sancho la carrera de su rucio y la caída de su amo, y no sabía a cuál de las dos necesidades acudiría primero; pero, en efecto, como buen escudero y como buen criado, pudo más con él el amor de su señor que el cariño de su jumento, puesto que cada vez que veía levantar las vejigas en el aire y caer sobre las ancas de su rucio eran para él tártagos y sustos de muerte, y antes quisiera que aquellos golpes se los dieran a él en las niñas de los ojos que en el más mínimo pelo de la cola de su asno. Con esta perpleja tribulación llegó donde estaba don Quijote, harto más maltrecho de lo que él quisiera, y, ayudándole a subir sobre Rocinante, le dijo: -Señor, el Diablo se ha llevado al rucio. -¿Qué diablo? -preguntó don Quijote. -El de las vejigas -respondió Sancho. -Pues yo le cobraré -replicó don Quijote-, si bien se encerrase con él en los más hondos y escuros calabozos del infierno. Sígueme, Sancho, que la carreta va despacio, y con las mulas della satisfaré la pérdida del rucio. -No hay para qué hacer esa diligencia, señor -respondió Sancho-: vuestra merced temple su cólera, que, según me parece, ya el Diablo ha dejado el rucio, y vuelve a la querencia. Y así era la verdad; porque, habiendo caído el Diablo con el rucio, por imitar a don Quijote y a Rocinante, el Diablo se fue a pie al pueblo, y el jumento se volvió a su amo. -Con todo eso -dijo don Quijote-, será bien castigar el descomedimiento de aquel demonio en alguno de los de la carreta, aunque sea el mesmo emperador. -Quítesele a vuestra merced eso de la imaginación -replicó Sancho-, y tome mi consejo, que es que nunca se tome con farsantes, que es gente favorecida. Recitante he visto yo estar preso por dos muertes y salir libre y sin costas. Sepa vuesa merced que, como son gentes alegres y de placer, todos los favorecen, todos los amparan, ayudan y estiman, y más siendo de aquellos de las compañías reales y de título, que todos, o los más, en sus trajes y compostura parecen unos príncipes. -Pues con todo -respondió don Quijote-, no se me ha de ir el demonio farsante alabando, aunque le favorezca todo el género humano. Y, diciendo esto, volvió a la carreta, que ya estaba bien cerca del pueblo. Iba dando voces, diciendo: -Deteneos, esperad, turba alegre y regocijada, que os quiero dar a entender cómo se han de tratar los jumentos y alimañas que sirven de caballería a los escuderos de los caballeros andantes. Tan altos eran los gritos de don Quijote, que los oyeron y entendieron los de la carreta; y, juzgando por las palabras la intención del que las decía, en un instante saltó la Muerte de la carreta, y tras ella, el Emperador, el Diablo carretero y el Ãngel, sin quedarse la Reina ni el dios Cupido; y todos se cargaron de piedras y se pusieron en ala, esperando recebir a don Quijote en las puntas de sus guijarros. Don Quijote, que los vio puestos en tan gallardo escuadrón, los brazos levantados con ademán de despedir poderosamente las piedras, detuvo las riendas a Rocinante y púsose a pensar de qué modo los acometería con menos peligro de su persona. En esto que se detuvo, llegó Sancho, y, viéndole en talle de acometer al bien formado escuadrón, le dijo: -Asaz de locura sería intentar tal empresa: considere vuesa merced, señor mío, que para sopa de arroyo y tente bonete, no hay arma defensiva en el mundo, si no es embutirse y encerrarse en una campana de bronce; y también se ha de considerar que es más temeridad que valentía acometer un hombre solo a un ejército donde está la Muerte, y pelean en persona emperadores, y a quien ayudan los buenos y los malos ángeles; y si esta consideración no le mueve a estarse quedo, muévale saber de cierto que, entre todos los que allí están, aunque parecen reyes, príncipes y emperadores, no hay ningún caballero andante. -Ahora sí -dijo don Quijote- has dado, Sancho, en el punto que puede y debe mudarme de mi ya determinado intento. Yo no puedo ni debo sacar la espada, como otras veces muchas te he dicho, contra quien no fuere armado caballero. A ti, Sancho, toca, si quieres tomar la venganza del agravio que a tu rucio se le ha hecho, que yo desde aquí te ayudaré con voces y advertimientos saludables. -No hay para qué, señor -respondió Sancho-, tomar venganza de nadie, pues no es de buenos cristianos tomarla de los agravios; cuanto más, que yo acabaré con mi asno que ponga su ofensa en las manos de mi voluntad, la cual es de vivir pacíficamente los días que los cielos me dieren de vida. -Pues ésa es tu determinación -replicó don Quijote-, Sancho bueno, Sancho discreto, Sancho cristiano y Sancho sincero, dejemos estas fantasmas y volvamos a buscar mejores y más calificadas aventuras; que yo veo esta tierra de talle, que no han de faltar en ella muchas y muy milagrosas. Volvió las riendas luego, Sancho fue a tomar su rucio, la Muerte con todo su escuadrón volante volvieron a su carreta y prosiguieron su viaje, y este felice fin tuvo la temerosa aventura de la carreta de la Muerte, gracias sean dadas al saludable consejo que Sancho Panza dio a su amo; al cual, el día siguiente, le sucedió otra con un enamorado y andante caballero, de no menos suspensión que la pasada. Capítulo XII. De la estraña aventura que le sucedió al valeroso don Quijote con el bravo Caballero de los Espejos La noche que siguió al día del rencuentro de la Muerte la pasaron don Quijote y su escudero debajo de unos altos y sombrosos árboles, habiendo, a persuasión de Sancho, comido don Quijote de lo que venía en el repuesto del rucio, y entre la cena dijo Sancho a su señor: -Señor, ¡qué tonto hubiera andado yo si hubiera escogido en albricias los despojos de la primera aventura que vuestra merced acabara, antes que las crías de las tres yeguas! En efecto, en efecto, más vale pájaro en mano que buitre volando. -Todavía -respondió don Quijote-, si tú, Sancho, me dejaras acometer, como yo quería, te hubieran cabido en despojos, por lo menos, la corona de oro de la Emperatriz y las pintadas alas de Cupido, que yo se las quitara al redropelo y te las pusiera en las manos. -Nunca los cetros y coronas de los emperadores farsantes -respondió Sancho Panza- fueron de oro puro, sino de oropel o hoja de lata. -Así es verdad -replicó don Quijote-, porque no fuera acertado que los atavíos de la comedia fueran finos, sino fingidos y aparentes, como lo es la mesma comedia, con la cual quiero, Sancho, que estés bien, teniéndola en tu gracia, y por el mismo consiguiente a los que las representan y a los que las componen, porque todos son instrumentos de hacer un gran bien a la república, poniéndonos un espejo a cada paso delante, donde se veen al vivo las acciones de la vida humana, y ninguna comparación hay que más al vivo nos represente lo que somos y lo que habemos de ser como la comedia y los comediantes. Si no, dime: ¿no has visto tú representar alguna comedia adonde se introducen reyes, emperadores y pontífices, caballeros, damas y otros diversos personajes? Uno hace el rufián, otro el embustero, éste el mercader, aquél el soldado, otro el simple discreto, otro el enamorado simple; y, acabada la comedia y desnudándose de los vestidos della, quedan todos los recitantes iguales. -Sí he visto -respondió Sancho. -Pues lo mesmo -dijo don Quijote- acontece en la comedia y trato deste mundo, donde unos hacen los emperadores, otros los pontífices, y, finalmente, todas cuantas figuras se pueden introducir en una comedia; pero, en llegando al fin, que es cuando se acaba la vida, a todos les quita la muerte las ropas que los diferenciaban, y quedan iguales en la sepultura. -¡Brava comparación! -dijo Sancho-, aunque no tan nueva que yo no la haya oído muchas y diversas veces, como aquella del juego del ajedrez, que, mientras dura el juego, cada pieza tiene su particular oficio; y, en acabándose el juego, todas se mezclan, juntan y barajan, y dan con ellas en una bolsa, que es como dar con la vida en la sepultura. -Cada día, Sancho -dijo don Quijote-, te vas haciendo menos simple y más discreto. -Sí, que algo se me ha de pegar de la discreción de vuestra merced -respondió Sancho-; que las tierras que de suyo son estériles y secas, estercolándolas y cultivándolas, vienen a dar buenos frutos: quiero decir que la conversación de vuestra merced ha sido el estiércol que sobre la estéril tierra de mi seco ingenio ha caído; la cultivación, el tiempo que ha que le sirvo y comunico; y con esto espero de dar frutos de mí que sean de bendición, tales, que no desdigan ni deslicen de los senderos de la buena crianza que vuesa merced ha hecho en el agostado entendimiento mío. Rióse don Quijote de las afectadas razones de Sancho, y parecióle ser verdad lo que decía de su emienda, porque de cuando en cuando hablaba de manera que le admiraba; puesto que todas o las más veces que Sancho quería hablar de oposición y a lo cortesano, acababa su razón con despeñarse del monte de su simplicidad al profundo de su ignorancia; y en lo que él se mostraba más elegante y memorioso era en traer refranes, viniesen o no viniesen a pelo de lo que trataba, como se habrá visto y se habrá notado en el discurso desta historia. En estas y en otras pláticas se les pasó gran parte de la noche, y a Sancho le vino en voluntad de dejar caer las compuertas de los ojos, como él decía cuando quería dormir, y, desaliñando al rucio, le dio pasto abundoso y libre. No quitó la silla a Rocinante, por ser expreso mandamiento de su señor que, en el tiempo que anduviesen en campaña, o no durmiesen debajo de techado, no desaliñase a Rocinante: antigua usanza establecida y guardada de los andantes caballeros, quitar el freno y colgarle del arzón de la silla; pero, ¿quitar la silla al caballo?, ¡guarda!; y así lo hizo Sancho, y le dio la misma libertad que al rucio, cuya amistad dél y de Rocinante fue tan única y tan trabada, que hay fama, por tradición de padres a hijos, que el autor desta verdadera historia hizo particulares capítulos della; mas que, por guardar la decencia y decoro que a tan heroica historia se debe, no los puso en ella, puesto que algunas veces se descuida deste su prosupuesto, y escribe que, así como las dos bestias se juntaban, acudían a rascarse el uno al otro, y que, después de cansados y satisfechos, cruzaba Rocinante el pescuezo sobre el cuello del rucio (que le sobraba de la otra parte más de media vara), y, mirando los dos atentamente al suelo, se solían estar de aquella manera tres días; a lo menos, todo el tiempo que les dejaban, o no les compelía la hambre a buscar sustento. Digo que dicen que dejó el autor escrito que los había comparado en la amistad a la que tuvieron Niso y Euríalo, y Pílades y Orestes; y si esto es así, se podía echar de ver, para universal admiración, cuán firme debió ser la amistad destos dos pacíficos animales, y para confusión de los hombres, que tan mal saben guardarse amistad los unos a los otros. Por esto se dijo: No hay amigo para amigo: las cañas se vuelven lanzas; y el otro que cantó: De amigo a amigo la chinche, etc. Y no le parezca a alguno que anduvo el autor algo fuera de camino en haber comparado la amistad destos animales a la de los hombres, que de las bestias han recebido muchos advertimientos los hombres y aprendido muchas cosas de importancia, como son: de las cigüeñas, el cristel; de los perros, el vómito y el agradecimiento; de las grullas, la vigilancia; de las hormigas, la providencia; de los elefantes, la honestidad, y la lealtad, del caballo. Finalmente, Sancho se quedó dormido al pie de un alcornoque, y don Quijote dormitando al de una robusta encina; pero, poco espacio de tiempo había pasado, cuando le despertó un ruido que sintió a sus espaldas, y, levantándose con sobresalto, se puso a mirar y a escuchar de dónde el ruido procedía, y vio que eran dos hombres a caballo, y que el uno, dejándose derribar de la silla, dijo al otro: -Apéate, amigo, y quita los frenos a los caballos, que, a mi parecer, este sitio abunda de yerba para ellos, y del silencio y soledad que han menester mis amorosos pensamientos. El decir esto y el tenderse en el suelo todo fue a un mesmo tiempo; y, al arrojarse, hicieron ruido las armas de que venía armado, manifiesta señal por donde conoció don Quijote que debía de ser caballero andante; y, llegándose a Sancho, que dormía, le trabó del brazo, y con no pequeño trabajo le volvió en su acuerdo, y con voz baja le dijo: -Hermano Sancho, aventura tenemos. -Dios nos la dé buena -respondió Sancho-; y ¿adónde está, señor mío, su merced de esa señora aventura? -¿Adónde, Sancho? -replicó don Quijote-; vuelve los ojos y mira, y verás allí tendido un andante caballero, que, a lo que a mí se me trasluce, no debe de estar demasiadamente alegre, porque le vi arrojar del caballo y tenderse en el suelo con algunas muestras de despecho, y al caer le crujieron las armas. -Pues ¿en qué halla vuesa merced -dijo Sancho- que ésta sea aventura? -No quiero yo decir -respondió don Quijote- que ésta sea aventura del todo, sino principio della; que por aquí se comienzan las aventuras. Pero escucha, que, a lo que parece, templando está un laúd o vigüela, y, según escupe y se desembaraza el pecho, debe de prepararse para cantar algo. -A buena fe que es así -respondió Sancho-, y que debe de ser caballero enamorado. -No hay ninguno de los andantes que no lo sea -dijo don Quijote-. Y escuchémosle, que por el hilo sacaremos el ovillo de sus pensamientos, si es que canta; que de la abundancia del corazón habla la lengua. Replicar quería Sancho a su amo, pero la voz del Caballero del Bosque, que no era muy mala mi muy buena, lo estorbó; y, estando los dos atónitos, oyeron que lo que cantó fue este soneto: -Dadme, señora, un término que siga, conforme a vuestra voluntad cortado; que será de la mía así estimado, que por jamás un punto dél desdiga. Si gustáis que callando mi fatiga muera, contadme ya por acabado: si queréis que os la cuente en desusado modo, haré que el mesmo amor la diga. A prueba de contrarios estoy hecho, de blanda cera y de diamante duro, y a las leyes de amor el ama ajusto. Blando cual es, o fuerte, ofrezco el pecho: entallad o imprimid lo que os dé gusto, que de guardarlo eternamente juro. Con un ¡ay!, arrancado, al parecer, de lo íntimo de su corazón, dio fin a su canto el Caballero del Bosque, y, de allí a un poco, con voz doliente y lastimada, dijo: -¡Oh la más hermosa y la más ingrata mujer del orbe! ¿Cómo que será posible, serenísima Casildea de Vandalia, que has de consentir que se consuma y acabe en continuas peregrinaciones y en ásperos y duros trabajos este tu cautivo caballero? ¿No basta ya que he hecho que te confiesen por la más hermosa del mundo todos los caballeros de Navarra, todos los leoneses, todos los tartesios, todos los castellanos, y, finalmente, todos los caballeros de la Mancha? -Eso no -dijo a esta sazón don Quijote-, que yo soy de la Mancha y nunca tal he confesado, ni podía ni debía confesar una cosa tan perjudicial a la belleza de mi señora; y este tal caballero ya vees tú, Sancho, que desvaría. Pero, escuchemos: quizá se declarará más. -Si hará -replicó Sancho-, que término lleva de quejarse un mes arreo. Pero no fue así, porque, habiendo entreoído el Caballero del Bosque que hablaban cerca dél, sin pasar adelante en su lamentación, se puso en pie, y dijo con voz sonora y comedida: -¿Quién va allá? ¿Qué gente? ¿Es por ventura de la del número de los contentos, o la del de los afligidos? -De los afligidos -respondió don Quijote. -Pues lléguese a mí -respondió el del Bosque-, y hará cuenta que se llega a la mesma tristeza y a la aflición mesma. Don Quijote, que se vio responder tan tierna y comedidamente, se llegó a él, y Sancho ni más ni menos. El caballero lamentador asió a don Quijote del brazo, diciendo: -Sentaos aquí, señor caballero, que para entender que lo sois, y de los que profesan la andante caballería, bástame el haberos hallado en este lugar, donde la soledad y el sereno os hacen compañía, naturales lechos y propias estancias de los caballeros andantes. A lo que respondió don Quijote: -Caballero soy, y de la profesión que decís; y, aunque en mi alma tienen su propio asiento las tristezas, las desgracias y las desventuras, no por eso se ha ahuyentado della la compasión que tengo de las ajenas desdichas. De lo que contaste poco ha, colegí que las vuestras son enamoradas, quiero decir, del amor que tenéis a aquella hermosa ingrata que en vuestras lamentaciones nombrastes. Ya cuando esto pasaban estaban sentados juntos sobre la dura tierra, en buena paz y compañía, como si al romper del día no se hubieran de romper las cabezas. -Por ventura, señor caballero -preguntó el del Bosque a don Quijote-, ¿sois enamorado? -Por desventura lo soy -respondió don Quijote-; aunque los daños que nacen de los bien colocados pensamientos, antes se deben tener por gracias que por desdichas. -Así es la verdad -replicó el del Bosque-, si no nos turbasen la razón y el entendimiento los desdenes, que, siendo muchos, parecen venganzas. -Nunca fui desdeñado de mi señora -respondió don Quijote. -No, por cierto -dijo Sancho, que allí junto estaba-, porque es mi señora como una borrega mansa: es más blanda que una manteca. -¿Es vuestro escudero éste? -preguntó el del Bosque. -Sí es -respondió don Quijote. -Nunca he visto yo escudero -replicó el del Bosque- que se atreva a hablar donde habla su señor; a lo menos, ahí está ese mío, que es tan grande como su padre, y no se probará que haya desplegado el labio donde yo hablo. -Pues a fe -dijo Sancho-, que he hablado yo, y puedo hablar delante de otro tan..., y aun quédese aquí, que es peor meneallo. El escudero del Bosque asió por el brazo a Sancho, diciéndole: -Vámonos los dos donde podamos hablar escuderilmente todo cuanto quisiéremos, y dejemos a estos señores amos nuestros que se den de las astas, contándose las historias de sus amores; que a buen seguro que les ha de coger el día en ellas y no las han de haber acabado. -Sea en buena hora -dijo Sancho-; y yo le diré a vuestra merced quién soy, para que vea si puedo entrar en docena con los más hablantes escuderos. Con esto se apartaron los dos escuderos, entre los cuales pasó un tan gracioso coloquio como fue grave el que pasó entre sus señores. Capítulo XIII. Donde se prosigue la aventura del Caballero del Bosque, con el discreto, nuevo y suave coloquio que pasó entre los dos escuderos Divididos estaban caballeros y escuderos: éstos contándose sus vidas, y aquéllos sus amores; pero la historia cuenta primero el razonamiento de los mozos y luego prosigue el de los amos; y así, dice que, apartándose un poco dellos, el del Bosque dijo a Sancho: -Trabajosa vida es la que pasamos y vivimos, señor mío, estos que somos escuderos de caballeros andantes: en verdad que comemos el pan en el sudor de nuestros rostros, que es una de las maldiciones que echó Dios a nuestros primeros padres. -También se puede decir -añadió Sancho- que lo comemos en el yelo de nuestros cuerpos; porque, ¿quién más calor y más frío que los miserables escuderos de la andante caballería? Y aun menos mal si comiéramos, pues los duelos, con pan son menos; pero tal vez hay que se nos pasa un día y dos sin desayunarnos, si no es del viento que sopla. -Todo eso se puede llevar y conllevar -dijo el del Bosque-, con la esperanza que tenemos del premio; porque si demasiadamente no es desgraciado el caballero andante a quien un escudero sirve, por lo menos, a pocos lances se verá premiado con un hermoso gobierno de cualque ínsula, o con un condado de buen parecer. Yo -replicó Sancho- ya he dicho a mi amo que me contento con el gobierno de alguna ínsula; y él es tan noble y tan liberal, que me le ha prometido muchas y diversas veces. Yo -dijo el del Bosque-, con un canonicato quedaré satisfecho de mis servicios, y ya me le tiene mandado mi amo, y ¡qué tal! -Debe de ser -dijo Sancho- su amo de vuesa merced caballero a lo eclesiástico, y podrá hacer esas mercedes a sus buenos escuderos; pero el mío es meramente lego, aunque yo me acuerdo cuando le querían aconsejar personas discretas, aunque, a mi parecer mal intencionadas, que procurase ser arzobispo; pero él no quiso sino ser emperador, y yo estaba entonces temblando si le venía en voluntad de ser de la Iglesia, por no hallarme suficiente de tener beneficios por ella; porque le hago saber a vuesa merced que, aunque parezco hombre, soy una bestia para ser de la Iglesia. -Pues en verdad que lo yerra vuesa merced -dijo el del Bosque-, a causa que los gobiernos insulanos no son todos de buena data. Algunos hay torcidos, algunos pobres, algunos malencónicos, y finalmente, el más erguido y bien dispuesto trae consigo una pesada carga de pensamientos y de incomodidades, que pone sobre sus hombros el desdichado que le cupo en suerte. Harto mejor sería que los que profesamos esta maldita servidumbre nos retirásemos a nuestras casas, y allí nos entretuviésemos en ejercicios más suaves, como si dijésemos, cazando o pescando; que, ¿qué escudero hay tan pobre en el mundo, a quien le falte un rocín, y un par de galgos, y una caña de pescar, con que entretenerse en su aldea? -A mí no me falta nada deso -respondió Sancho-: verdad es que no tengo rocín, pero tengo un asno que vale dos veces más que el caballo de mi amo. Mala pascua me dé Dios, y sea la primera que viniere, si le trocara por él, aunque me diesen cuatro fanegas de cebada encima. A burla tendrá vuesa merced el valor de mi rucio, que rucio es el color de mi jumento. Pues galgos no me habían de faltar, habiéndolos sobrados en mi pueblo; y más, que entonces es la caza más gustosa cuando se hace a costa ajena. -Real y verdaderamente -respondió el del Bosque-, señor escudero, que tengo propuesto y determinado de dejar estas borracherías destos caballeros, y retirarme a mi aldea, y criar mis hijitos, que tengo tres como tres orientales perlas. -Dos tengo yo -dijo Sancho-, que se pueden presentar al Papa en persona, especialmente una muchacha a quien crío para condesa, si Dios fuere servido, aunque a pesar de su madre. -Y ¿qué edad tiene esa señora que se cría para condesa? -preguntó el del Bosque. -Quince años, dos más a menos -respondió Sancho-, pero es tan grande como una lanza, y tan fresca como una mañana de abril, y tiene una fuerza de un ganapán. -Partes son ésas -respondió el del Bosque- no sólo para ser condesa, sino para ser ninfa del verde bosque. ¡Oh hideputa, puta, y qué rejo debe de tener la bellaca! A lo que respondió Sancho, algo mohíno: -Ni ella es puta, ni lo fue su madre, ni lo será ninguna de las dos, Dios quiriendo, mientras yo viviere. Y háblese más comedidamente, que, para haberse criado vuesa merced entre caballeros andantes, que son la mesma cortesía, no me parecen muy concertadas esas palabras. -¡Oh, qué mal se le entiende a vuesa merced -replicó el del Bosque- de achaque de alabanzas, señor escudero! ¿Cómo y no sabe que cuando algún caballero da una buena lanzada al toro en la plaza, o cuando alguna persona hace alguna cosa bien hecha, suele decir el vulgo: "¡Oh hideputa, puto, y qué bien que lo ha hecho!?" Y aquello que parece vituperio, en aquel término, es alabanza notable; y renegad vos, señor, de los hijos o hijas que no hacen obras que merezcan se les den a sus padres loores semejantes. -Sí reniego -respondió Sancho-, y dese modo y por esa misma razón podía echar vuestra merced a mí y hijos y a mi mujer toda una putería encima, porque todo cuanto hacen y dicen son estremos dignos de semejantes alabanzas, y para volverlos a ver ruego yo a Dios me saque de pecado mortal, que lo mesmo será si me saca deste peligroso oficio de escudero, en el cual he incurrido segunda vez, cebado y engañado de una bolsa con cien ducados que me hallé un día en el corazón de Sierra Morena, y el diablo me pone ante los ojos aquí, allí, acá no, sino acullá, un talego lleno de doblones, que me parece que a cada paso le toco con la mano, y me abrazo con él, y lo llevo a mi casa, y echo censos, y fundo rentas, y vivo como un príncipe; y el rato que en esto pienso se me hacen fáciles y llevaderos cuantos trabajos padezco con este mentecato de mi amo, de quien sé que tiene más de loco que de caballero. -Por eso -respondió el del Bosque- dicen que la codicia rompe el saco; y si va a tratar dellos, no hay otro mayor en el mundo que mi amo, porque es de aquellos que dicen: "Cuidados ajenos matan al asno"; pues, porque cobre otro caballero el juicio que ha perdido, se hace el loco, y anda buscando lo que no sé si después de hallado le ha de salir a los hocicos. -Y ¿es enamorado, por dicha? -Sí -dijo el del Bosque-: de una tal Casildea de Vandalia, la más cruda y la más asada señora que en todo el orbe puede hallarse; pero no cojea del pie de la crudeza, que otros mayores embustes le gruñen en las entrañas, y ello dirá antes de muchas horas. -No hay camino tan llano -replicó Sancho- que no tenga algún tropezón o barranco; en otras casas cuecen habas, y en la mía, a calderadas; más acompañados y paniaguados debe de tener la locura que la discreción. Mas si es verdad lo que comúnmente se dice, que el tener compañeros en los trabajos suele servir de alivio en ellos, con vuestra merced podré consolarme, pues sirve a otro amo tan tonto como el mío. -Tonto, pero valiente -respondió el del Bosque-, y más bellaco que tonto y que valiente. -Eso no es el mío -respondió Sancho-: digo, que no tiene nada de bellaco; antes tiene una alma como un cántaro: no sabe hacer mal a nadie, sino bien a todos, ni tiene malicia alguna: un niño le hará entender que es de noche en la mitad del día; y por esta sencillez le quiero como a las telas de mi corazón, y no me amaño a dejarle, por más disparates que haga. -Con todo eso, hermano y señor -dijo el del Bosque-, si el ciego guía al ciego, ambos van a peligro de caer en el hoyo. Mejor es retirarnos con buen compás de pies, y volvernos a nuestras querencias; que los que buscan aventuras no siempre las hallan buenas. Escupía Sancho a menudo, al parecer, un cierto género de saliva pegajosa y algo seca; lo cual visto y notado por el caritativo bosqueril escudero, dijo: -Paréceme que de lo que hemos hablado se nos pegan al paladar las lenguas; pero yo traigo un despegador pendiente del arzón de mi caballo, que es tal como bueno. Y, levantándose, volvió desde allí a un poco con una gran bota de vino y una empanada de media vara; y no es encarecimiento, porque era de un conejo albar, tan grande que Sancho, al tocarla, entendió ser de algún cabrón, no que de cabrito; lo cual visto por Sancho, dijo: -Y ¿esto trae vuestra merced consigo, señor? -Pues, ¿qué se pensaba? -respondió el otro-. ¿Soy yo por ventura algún escudero de agua y lana? Mejor repuesto traigo yo en las ancas de mi caballo que lleva consigo cuando va de camino un general. Comió Sancho sin hacerse de rogar, y tragaba a escuras bocados de nudos de suelta. Y dijo: -Vuestra merced sí que es escudero fiel y legal, moliente y corriente, magnífico y grande, como lo muestra este banquete, que si no ha venido aquí por arte de encantamento, parécelo, a lo menos; y no como yo, mezquino y malaventurado, que sólo traigo en mis alforjas un poco de queso, tan duro que pueden descalabrar con ello a un gigante, a quien hacen compañía cuatro docenas de algarrobas y otras tantas de avellanas y nueces, mercedes a la estrecheza de mi dueño, y a la opinión que tiene y orden que guarda de que los caballeros andantes no se han de mantener y sustentar sino con frutas secas y con las yerbas del campo. -Por mi fe, hermano -replicó el del Bosque-, que yo no tengo hecho el estómago a tagarninas, ni a piruétanos, ni a raíces de los montes. Allá se lo hayan con sus opiniones y leyes caballerescas nuestros amos, y coman lo que ellos mandaren. Fiambreras traigo, y esta bota colgando del arzón de la silla, por sí o por no; y es tan devota mía y quiérola tanto, que pocos ratos se pasan sin que la dé mil besos y mil abrazos. Y, diciendo esto, se la puso en las manos a Sancho, el cual, empinándola, puesta a la boca, estuvo mirando las estrellas un cuarto de hora, y, en acabando de beber, dejó caer la cabeza a un lado, y, dando un gran suspiro, dijo: -¡Oh hideputa bellaco, y cómo es católico! -¿Veis ahí -dijo el del Bosque, en oyendo el hideputa de Sancho-, cómo habéis alabado este vino llamándole hideputa? -Digo -respondió Sancho-, que confieso que conozco que no es deshonra llamar hijo de puta a nadie, cuando cae debajo del entendimiento de alabarle. Pero dígame, señor, por el siglo de lo que más quiere: ¿este vino es de Ciudad Real? -¡Bravo mojón! -respondió el del Bosque-. En verdad que no es de otra parte, y que tiene algunos años de ancianidad. -¡A mí con eso! -dijo Sancho-. No toméis menos, sino que se me fuera a mí por alto dar alcance a su conocimiento. ¿No será bueno, señor escudero, que tenga yo un instinto tan grande y tan natural, en esto de conocer vinos, que, en dándome a oler cualquiera, acierto la patria, el linaje, el sabor, y la dura, y las vueltas que ha de dar, con todas las circunstancias al vino atañederas? Pero no hay de qué maravillarse, si tuve en mi linaje por parte de mi padre los dos más excelentes mojones que en luengos años conoció la Mancha; para prueba de lo cual les sucedió lo que ahora diré: «Diéronles a los dos a probar del vino de una cuba, pidiéndoles su parecer del estado, cualidad, bondad o malicia del vino. El uno lo probó con la punta de la lengua, el otro no hizo más de llegarlo a las narices. El primero dijo que aquel vino sabía a hierro, el segundo dijo que más sabía a cordobán. El dueño dijo que la cuba estaba limpia, y que el tal vino no tenía adobo alguno por donde hubiese tomado sabor de hierro ni de cordobán. Con todo eso, los dos famosos mojones se afirmaron en lo que habían dicho. Anduvo el tiempo, vendióse el vino, y al limpiar de la cuba hallaron en ella una llave pequeña, pendiente de una correa de cordobán.» Porque vea vuestra merced si quien viene desta ralea podrá dar su parecer en semejantes causas. -Por eso digo -dijo el del Bosque- que nos dejemos de andar buscando aventuras; y, pues tenemos hogazas, no busquemos tortas, y volvámonos a nuestras chozas, que allí nos hallará Dios, si Él quiere. -Hasta que mi amo llegue a Zaragoza, le serviré; que después todos nos entenderemos. Finalmente, tanto hablaron y tanto bebieron los dos buenos escuderos, que tuvo necesidad el sueño de atarles las lenguas y templarles la sed, que quitársela fuera imposible; y así, asidos entrambos de la ya casi vacía bota, con los bocados a medio mascar en la boca, se quedaron dormidos, donde los dejaremos por ahora, por contar lo que el Caballero del Bosque pasó con el de la Triste Figura. Capítulo XIV. Donde se prosigue la aventura del Caballero del Bosque Entre muchas razones que pasaron don Quijote y el Caballero de la Selva, dice la historia que el del Bosque dijo a don Quijote: -Finalmente, señor caballero, quiero que sepáis que mi destino, o, por mejor decir, mi elección, me trujo a enamorar de la sin par Casildea de Vandalia. Llámola sin par porque no le tiene, así en la grandeza del cuerpo como en el estremo del estado y de la hermosura. Esta tal Casildea, pues, que voy contando, pagó mis buenos pensamientos y comedidos deseos con hacerme ocupar, como su madrina a Hércules, en muchos y diversos peligros, prometiéndome al fin de cada uno que en el fin del otro llegaría el de mi esperanza; pero así se han ido eslabonando mis trabajos, que no tienen cuento, ni yo sé cuál ha de ser el último que dé principio al cumplimiento de mis buenos deseos. Una vez me mandó que fuese a desafiar a aquella famosa giganta de Sevilla llamada la Giralda, que es tan valiente y fuerte como hecha de bronce, y, sin mudarse de un lugar, es la más movible y voltaria mujer del mundo. Llegué, vila, y vencíla, y hícela estar queda y a raya, porque en más de una semana no soplaron sino vientos nortes. Vez también hubo que me mandó fuese a tomar en peso las antiguas piedras de los valientes Toros de Guisando, empresa más para encomendarse a ganapanes que a caballeros. Otra vez me mandó que me precipitase y sumiese en la sima de Cabra, peligro inaudito y temeroso, y que le trujese particular relación de lo que en aquella escura profundidad se encierra. Detuve el movimiento a la Giralda, pesé los Toros de Guisando, despeñéme en la sima y saqué a luz lo escondido de su abismo, y mis esperanzas, muertas que muertas, y sus mandamientos y desdenes, vivos que vivos. En resolución, últimamente me ha mandado que discurra por todas las provincias de España y haga confesar a todos los andantes caballeros que por ellas vagaren que ella sola es la más aventajada en hermosura de cuantas hoy viven, y que yo soy el más valiente y el más bien enamorado caballero del orbe; en cuya demanda he andado ya la mayor parte de España, y en ella he vencido muchos caballeros que se han atrevido a contradecirme. Pero de lo que yo más me precio y ufano es de haber vencido, en singular batalla, a aquel tan famoso caballero don Quijote de la Mancha, y héchole confesar que es más hermosa mi Casildea que su Dulcinea; y en solo este vencimiento hago cuenta que he vencido todos los caballeros del mundo, porque el tal don Quijote que digo los ha vencido a todos; y, habiéndole yo vencido a él, su gloria, su fama y su honra se ha transferido y pasado a mi persona; y tanto el vencedor es más honrado, cuanto más el vencido es reputado; así que, ya corren por mi cuenta y son mías las inumerables hazañas del ya referido don Quijote. Admirado quedó don Quijote de oír al Caballero del Bosque, y estuvo mil veces por decirle que mentía, y ya tuvo el mentís en el pico de la lengua; pero reportóse lo mejor que pudo, por hacerle confesar por su propia boca su mentira; y así, sosegadamente le dijo: -De que vuesa merced, señor caballero, haya vencido a los más caballeros andantes de España, y aun de todo el mundo, no digo nada; pero de que haya vencido a don Quijote de la Mancha, póngolo en duda. Podría ser que fuese otro que le pareciese, aunque hay pocos que le parezcan. -¿Cómo no? -replicó el del Bosque-. Por el cielo que nos cubre, que peleé con don Quijote, y le vencí y rendí; y es un hombre alto de cuerpo, seco de rostro, estirado y avellanado de miembros, entrecano, la nariz aguileña y algo corva, de bigotes grandes, negros y caídos. Campea debajo del nombre del Caballero de la Triste Figura, y trae por escudero a un labrador llamado Sancho Panza; oprime el lomo y rige el freno de un famoso caballo llamado Rocinante, y, finalmente, tiene por señora de su voluntad a una tal Dulcinea del Toboso, llamada un tiempo Aldonza Lorenzo; como la mía, que, por llamarse Casilda y ser de la Andalucía, yo la llamo Casildea de Vandalia. Si todas estas señas no bastan para acreditar mi verdad, aquí está mi espada, que la hará dar crédito a la mesma incredulidad. -Sosegaos, señor caballero -dijo don Quijote-, y escuchad lo que decir os quiero. Habéis de saber que ese don Quijote que decís es el mayor amigo que en este mundo tengo, y tanto, que podré decir que le tengo en lugar de mi misma persona, y que por las señas que dél me habéis dado, tan puntuales y ciertas, no puedo pensar sino que sea el mismo que habéis vencido. Por otra parte, veo con los ojos y toco con las manos no ser posible ser el mesmo, si ya no fuese que como él tiene muchos enemigos encantadores, especialmente uno que de ordinario le persigue, no haya alguno dellos tomado su figura para dejarse vencer, por defraudarle de la fama que sus altas caballerías le tienen granjeada y adquirida por todo lo descubierto de la tierra. Y, para confirmación desto, quiero también que sepáis que los tales encantadores sus contrarios no ha más de dos días que transformaron la figura y persona de la hermosa Dulcinea del Toboso en una aldeana soez y baja, y desta manera habrán transformado a don Quijote; y si todo esto no basta para enteraros en esta verdad que digo, aquí está el mesmo don Quijote, que la sustentará con sus armas a pie, o a caballo, o de cualquiera suerte que os agradare. Y, diciendo esto, se levantó en pie y se empuñó en la espada, esperando qué resolución tomaría el Caballero del Bosque; el cual, con voz asimismo sosegada, respondió y dijo: -Al buen pagador no le duelen prendas: el que una vez, señor don Quijote, pudo venceros transformado, bien podrá tener esperanza de rendiros en vuestro propio ser. Mas, porque no es bien que los caballeros hagan sus fechos de armas ascuras, como los salteadores y rufianes, esperemos el día, para que el sol vea nuestras obras. Y ha de ser condición de nuestra batalla que el vencido ha de quedar a la voluntad del vencedor, para que haga dél todo lo que quisiere, con tal que sea decente a caballero lo que se le ordenare. -Soy más que contento desa condición y convenencia -respondió don Quijote. Y, en diciendo esto, se fueron donde estaban sus escuderos, y los hallaron roncando y en la misma forma que estaban cuando les salteó el sueño. Despertáronlos y mandáronles que tuviesen a punto los caballos, porque, en saliendo el sol, habían de hacer los dos una sangrienta, singular y desigual batalla; a cuyas nuevas quedó Sancho atónito y pasmado, temeroso de la salud de su amo, por las valentías que había oído decir del suyo al escudero del Bosque; pero, sin hablar palabra, se fueron los dos escuderos a buscar su ganado, que ya todos tres caballos y el rucio se habían olido, y estaban todos juntos. En el camino dijo el del Bosque a Sancho: -Ha de saber, hermano, que tienen por costumbre los peleantes de la Andalucía, cuando son padrinos de alguna pendencia, no estarse ociosos mano sobre mano en tanto que sus ahijados riñen. Dígolo porque esté advertido que mientras nuestros dueños riñeren, nosotros también hemos de pelear y hacernos astillas. -Esa costumbre, señor escudero -respondió Sancho-, allá puede correr y pasar con los rufianes y peleantes que dice, pero con los escuderos de los caballeros andantes, ni por pienso. A lo menos, yo no he oído decir a mi amo semejante costumbre, y sabe de memoria todas las ordenanzas de la andante caballería. Cuanto más, que yo quiero que sea verdad y ordenanza expresa el pelear los escuderos en tanto que sus señores pelean; pero yo no quiero cumplirla, sino pagar la pena que estuviere puesta a los tales pacíficos escuderos, que yo aseguro que no pase de dos libras de cera, y más quiero pagar las tales libras, que sé que me costarán menos que las hilas que podré gastar en curarme la cabeza, que ya me la cuento por partida y dividida en dos partes. Hay más: que me imposibilita el reñir el no tener espada, pues en mi vida me la puse. -Para eso sé yo un buen remedio -dijo el del Bosque-: yo traigo aquí dos talegas de lienzo, de un mesmo tamaño: tomaréis vos la una, y yo la otra, y riñiremos a talegazos, con armas iguales. -Desa manera, sea en buena hora -respondió Sancho-, porque antes servirá la tal pelea de despolvorearnos que de herirnos. -No ha de ser así -replicó el otro-, porque se han de echar dentro de las talegas, porque no se las lleve el aire, media docena de guijarros lindos y pelados, que pesen tanto los unos como los otros, y desta manera nos podremos atalegar sin hacernos mal ni daño. -¡Mirad, cuerpo de mi padre -respondió Sancho-, qué martas cebollinas, o qué copos de algodón cardado pone en las talegas, para no quedar molidos los cascos y hechos alheña los huesos! Pero, aunque se llenaran de capullos de seda, sepa, señor mío, que no he de pelear: peleen nuestros amos, y allá se lo hayan, y bebamos y vivamos nosotros, que el tiempo tiene cuidado de quitarnos las vidas, sin que andemos buscando apetites para que se acaben antes de llegar su sazón y término y que se cayan de maduras. -Con todo -replicó el del Bosque-, hemos de pelear siquiera media hora. -Eso no -respondió Sancho-: no seré yo tan descortés ni tan desagradecido, que con quien he comido y he bebido trabe cuestión alguna, por mínima que sea; cuanto más que, estando sin cólera y sin enojo, ¿quién diablos se ha de amañar a reñir a secas? -Para eso -dijo el del Bosque- yo daré un suficiente remedio: y es que, antes que comencemos la pelea, yo me llegaré bonitamente a vuestra merced y le daré tres o cuatro bofetadas, que dé con él a mis pies, con las cuales le haré despertar la cólera, aunque esté con más sueño que un lirón. -Contra ese corte sé yo otro -respondió Sancho-, que no le va en zaga: cogeré yo un garrote, y, antes que vuestra merced llegue a despertarme la cólera, haré yo dormir a garrotazos de tal suerte la suya, que no despierte si no fuere en el otro mundo, en el cual se sabe que no soy yo hombre que me dejo manosear el rostro de nadie; y cada uno mire por el virote, aunque lo más acertado sería dejar dormir su cólera a cada uno, que no sabe nadie el alma de nadie, y tal suele venir por lana que vuelve tresquilado; y Dios bendijo la paz y maldijo las riñas, porque si un gato acosado, encerrado y apretado se vuelve en león, yo, que soy hombre, Dios sabe en lo que podré volverme; y así, desde ahora intimo a vuestra merced, señor escudero, que corra por su cuenta todo el mal y daño que de nuestra pendencia resultare. -Está bien -replicó el del Bosque-. Amanecerá Dios y medraremos. En esto, ya comenzaban a gorjear en los árboles mil suertes de pintados pajarillos, y en sus diversos y alegres cantos parecía que daban la norabuena y saludaban a la fresca aurora, que ya por las puertas y balcones del oriente iba descubriendo la hermosura de su rostro, sacudiendo de sus cabellos un número infinito de líquidas perlas, en cuyo suave licor bañándose las yerbas, parecía asimesmo que ellas brotaban y llovían blanco y menudo aljófar; los sauces destilaban maná sabroso, reíanse las fuentes, murmuraban los arroyos, alegrábanse las selvas y enriquecíanse los prados con su venida. Mas, apenas dio lugar la claridad del día para ver y diferenciar las cosas, cuando la primera que se ofreció a los ojos de Sancho Panza fue la nariz del escudero del Bosque, que era tan grande que casi le hacía sombra a todo el cuerpo. Cuéntase, en efecto, que era de demasiada grandeza, corva en la mitad y toda llena de verrugas, de color amoratado, como de berenjena; bajábale dos dedos más abajo de la boca; cuya grandeza, color, verrugas y encorvamiento así le afeaban el rostro, que, en viéndole Sancho, comenzó a herir de pie y de mano, como niño con alferecía, y propuso en su corazón de dejarse dar docientas bofetadas antes que despertar la cólera para reñir con aquel vestiglo. Don Quijote miró a su contendor, y hallóle ya puesta y calada la celada, de modo que no le pudo ver el rostro, pero notó que era hombre membrudo, y no muy alto de cuerpo. Sobre las armas traía una sobrevista o casaca de una tela, al parecer, de oro finísimo, sembradas por ella muchas lunas pequeñas de resplandecientes espejos, que le hacían en grandísima manera galán y vistoso; volábanle sobre la celada grande cantidad de plumas verdes, amarillas y blancas; la lanza, que tenía arrimada a un árbol, era grandísima y gruesa, y de un hierro acerado de más de un palmo. Todo lo miró y todo lo notó don Quijote, y juzgó de lo visto y mirado que el ya dicho caballero debía de ser de grandes fuerzas; pero no por eso temió, como Sancho Panza; antes, con gentil denuedo, dijo al Caballero de los Espejos: -Si la mucha gana de pelear, señor caballero, no os gasta la cortesía, por ella os pido que alcéis la visera un poco, porque yo vea si la gallardía de vuestro rostro responde a la de vuestra disposición. -O vencido o vencedor que salgáis desta empresa, señor caballero -respondió el de los Espejos-, os quedará tiempo y espacio demasiado para verme; y si ahora no satisfago a vuestro deseo, es por parecerme que hago notable agravio a la hermosa Casildea de Vandalia en dilatar el tiempo que tardare en alzarme la visera, sin haceros confesar lo que ya sabéis que pretendo. -Pues, en tanto que subimos a caballo -dijo don Quijote-, bien podéis decirme si soy yo aquel don Quijote que dijistes haber vencido. -A eso vos respondemos -dijo el de los Espejos- que parecéis, como se parece un huevo a otro, al mismo caballero que yo vencí; pero, según vos decís que le persiguen encantadores, no osaré afirmar si sois el contenido o no. -Eso me basta a mí -respondió don Quijote- para que crea vuestro engaño; empero, para sacaros dél de todo punto, vengan nuestros caballos; que, en menos tiempo que el que tardárades en alzaros la visera, si Dios, si mi señora y mi brazo me valen, veré yo vuestro rostro, y vos veréis que no soy yo el vencido don Quijote que pensáis. Con esto, acortando razones, subieron a caballo, y don Quijote volvió las riendas a Rocinante para tomar lo que convenía del campo, para volver a encontrar a su contrario, y lo mesmo hizo el de los Espejos. Pero, no se había apartado don Quijote veinte pasos, cuando se oyó llamar del de los Espejos, y, partiendo los dos el camino, el de los Espejos le dijo: -Advertid, señor caballero, que la condición de nuestra batalla es que el vencido, como otra vez he dicho, ha de quedar a discreción del vencedor. -Ya la sé -respondió don Quijote-; con tal que lo que se le impusiere y mandare al vencido han de ser cosas que no salgan de los límites de la caballería. -Así se entiende -respondió el de los Espejos. Ofreciéronsele en esto a la vista de don Quijote las estrañas narices del escudero, y no se admiró menos de verlas que Sancho; tanto, que le juzgó por algún monstro, o por hombre nuevo y de aquellos que no se usan en el mundo. Sancho, que vio partir a su amo para tomar carrera, no quiso quedar solo con el narigudo, temiendo que con solo un pasagonzalo con aquellas narices en las suyas sería acabada la pendencia suya, quedando del golpe, o del miedo, tendido en el suelo, y fuese tras su amo, asido a una acción de Rocinante; y, cuando le pareció que ya era tiempo que volviese, le dijo: -Suplico a vuesa merced, señor mío, que antes que vuelva a encontrarse me ayude a subir sobre aquel alcornoque, de donde podré ver más a mi sabor, mejor que desde el suelo, el gallardo encuentro que vuesa merced ha de hacer con este caballero. -Antes creo, Sancho -dijo don Quijote-, que te quieres encaramar y subir en andamio por ver sin peligro los toros. -La verdad que diga -respondió Sancho-, las desaforadas narices de aquel escudero me tienen atónito y lleno de espanto, y no me atrevo a estar junto a él. -Ellas son tales -dijo don Quijote-, que, a no ser yo quien soy, también me asombraran; y así, ven: ayudarte he a subir donde dices. En lo que se detuvo don Quijote en que Sancho subiese en el alcornoque, tomó el de los Espejos del campo lo que le pareció necesario; y, creyendo que lo mismo habría hecho don Quijote, sin esperar son de trompeta ni otra señal que los avisase, volvió las riendas a su caballo -que no era más ligero ni de mejor parecer que Rocinante-, y, a todo su correr, que era un mediano trote, iba a encontrar a su enemigo; pero, viéndole ocupado en la subida de Sancho, detuvo las riendas y paróse en la mitad de la carrera, de lo que el caballo quedó agradecidísimo, a causa que ya no podía moverse. Don Quijote, que le pareció que ya su enemigo venía volando, arrimó reciamente las espuelas a las trasijadas ijadas de Rocinante, y le hizo aguijar de manera, que cuenta la historia que esta sola vez se conoció haber corrido algo, porque todas las demás siempre fueron trotes declarados; y con esta no vista furia llegó donde el de los Espejos estaba hincando a su caballo las espuelas hasta los botones, sin que le pudiese mover un solo dedo del lugar donde había hecho estanco de su carrera. En esta buena sazón y coyuntura halló don Quijote a su contrario embarazado con su caballo y ocupado con su lanza, que nunca, o no acertó, o no tuvo lugar de ponerla en ristre. Don Quijote, que no miraba en estos inconvenientes, a salvamano y sin peligro alguno, encontró al de los Espejos con tanta fuerza, que mal de su grado le hizo venir al suelo por las ancas del caballo, dando tal caída, que, sin mover pie ni mano, dio señales de que estaba muerto. Apenas le vio caído Sancho, cuando se deslizó del alcornoque y a toda priesa vino donde su señor estaba, el cual, apeándose de Rocinante, fue sobre el de los Espejos, y, quitándole las lazadas del yelmo para ver si era muerto y para que le diese el aire si acaso estaba vivo; y vio... ¿Quién podrá decir lo que vio, sin causar admiración, maravilla y espanto a los que lo oyeren? Vio, dice la historia, el rostro mesmo, la misma figura, el mesmo aspecto, la misma fisonomía, la mesma efigie, la pespetiva mesma del bachiller Sansón Carrasco; y, así como la vio, en altas voces dijo: -¡Acude, Sancho, y mira lo que has de ver y no lo has creer! ¡Aguija, hijo, y advierte lo que puede la magia, lo que pueden los hechiceros y los encantadores! Llegó Sancho, y, como vio el rostro del bachiller Carrasco, comenzó a hacerse mil cruces y a santiguarse otras tantas. En todo esto, no daba muestras de estar vivo el derribado caballero, y Sancho dijo a don Quijote: -Soy de parecer, señor mío, que, por sí o por no, vuesa merced hinque y meta la espada por la boca a este que parece el bachiller Sansón Carrasco; quizá matará en él a alguno de sus enemigos los encantadores. -No dices mal -dijo don Quijote-, porque de los enemigos, los menos. Y, sacando la espada para poner en efecto el aviso y consejo de Sancho, llegó el escudero del de los Espejos, ya sin las narices que tan feo le habían hecho, y a grandes voces dijo: -Mire vuesa merced lo que hace, señor don Quijote, que ese que tiene a los pies es el bachiller Sansón Carrasco, su amigo, y yo soy su escudero. Y, viéndole Sancho sin aquella fealdad primera, le dijo: -¿Y las narices? A lo que él respondió: -Aquí las tengo, en la faldriquera. Y, echando mano a la derecha, sacó unas narices de pasta y barniz, de máscara, de la manifatura que quedan delineadas. Y, mirándole más y más Sancho, con voz admirativa y grande, dijo: -¡Santa María, y valme! ¿Éste no es Tomé Cecial, mi vecino y mi compadre? -Y ¡cómo si lo soy! -respondió el ya desnarigado escudero-: Tomé Cecial soy, compadre y amigo Sancho Panza, y luego os diré los arcaduces, embustes y enredos por donde soy aquí venido; y en tanto, pedid y suplicad al señor vuestro amo que no toque, maltrate, hiera ni mate al caballero de los Espejos, que a sus pies tiene, porque sin duda alguna es el atrevido y mal aconsejado del bachiller Sansón Carrasco, nuestro compatrioto. En esto, volvió en sí el de los Espejos, lo cual visto por don Quijote, le puso la punta desnuda de su espada encima del rostro, y le dijo: -Muerto sois, caballero, si no confesáis que la sin par Dulcinea del Toboso se aventaja en belleza a vuestra Casildea de Vandalia; y demás de esto habéis de prometer, si de esta contienda y caída quedárades con vida, de ir a la ciudad del Toboso y presentaros en su presencia de mi parte, para que haga de vos lo que más en voluntad le viniere; y si os dejare en la vuestra, asimismo habéis de volver a buscarme, que el rastro de mis hazañas os servirá de guía que os traiga donde yo estuviere, y a decirme lo que con ella hubiéredes pasado; condiciones que, conforme a las que pusimos antes de nuestra batalla, no salen de los términos de la andante caballería. -Confieso -dijo el caído caballero- que vale más el zapato descosido y sucio de la señora Dulcinea del Toboso que las barbas mal peinadas, aunque limpias, de Casildea, y prometo de ir y volver de su presencia a la vuestra, y daros entera y particular cuenta de lo que me pedís. -También habéis de confesar y creer -añadió don Quijote- que aquel caballero que vencistes no fue ni pudo ser don Quijote de la Mancha, sino otro que se le parecía, como yo confieso y creo que vos, aunque parecéis el bachiller Sansón Carrasco, no lo sois, sino otro que le parece, y que en su figura aquí me le han puesto mis enemigos, para que detenga y temple el ímpetu de mi cólera, y para que use blandamente de la gloria del vencimiento. -Todo lo confieso, juzgo y siento como vos lo creéis, juzgáis y sentís -respondió el derrengado caballero-. Dejadme levantar, os ruego, si es que lo permite el golpe de mi caída, que asaz maltrecho me tiene. Ayudóle a levantar don Quijote y Tomé Cecial, su escudero, del cual no apartaba los ojos Sancho, preguntándole cosas cuyas respuestas le daban manifiestas señales de que verdaderamente era el Tomé Cecial que decía; mas la aprehensión que en Sancho había hecho lo que su amo dijo, de que los encantadores habían mudado la figura del Caballero de los Espejos en la del bachiller Carrasco, no le dejaba dar crédito a la verdad que con los ojos estaba mirando. Finalmente, se quedaron con este engaño amo y mozo, y el de los Espejos y su escudero, mohínos y malandantes, se apartaron de don Quijote y Sancho, con intención de buscar algún lugar donde bizmarle y entablarle las costillas. Don Quijote y Sancho volvieron a proseguir su camino de Zaragoza, donde los deja la historia, por dar cuenta de quién era el Caballero de los Espejos y su narigante escudero. Capítulo XV. Donde se cuenta y da noticia de quién era el Caballero de los Espejos y su escudero En estremo contento, ufano y vanaglorioso iba don Quijote por haber alcanzado vitoria de tan valiente caballero como él se imaginaba que era el de los Espejos, de cuya caballeresca palabra esperaba saber si el encantamento de su señora pasaba adelante, pues era forzoso que el tal vencido caballero volviese, so pena de no serlo, a darle razón de lo que con ella le hubiese sucedido. Pero uno pensaba don Quijote y otro el de los Espejos, puesto que por entonces no era otro su pensamiento sino buscar donde bizmarse, como se ha dicho. Dice, pues, la historia que cuando el bachiller Sansón Carrasco aconsejó a don Quijote que volviese a proseguir sus dejadas caballerías, fue por haber entrado primero en bureo con el cura y el barbero sobre qué medio se podría tomar para reducir a don Quijote a que se estuviese en su casa quieto y sosegado, sin que le alborotasen sus mal buscadas aventuras; de cuyo consejo salió, por voto común de todos y parecer particular de Carrasco, que dejasen salir a don Quijote, pues el detenerle parecía imposible, y que Sansón le saliese al camino como caballero andante, y trabase batalla con él, pues no faltaría sobre qué, y le venciese, teniéndolo por cosa fácil, y que fuese pacto y concierto que el vencido quedase a merced del vencedor; y así vencido don Quijote, le había de mandar el bachiller caballero se volviese a su pueblo y casa, y no saliese della en dos años, o hasta tanto que por él le fuese mandado otra cosa; lo cual era claro que don Quijote vencido cumpliría indubitablemente, por no contravenir y faltar a las leyes de la caballería, y podría ser que en el tiempo de su reclusión se le olvidasen sus vanidades, o se diese lugar de buscar a su locura algún conveniente remedio. Aceptólo Carrasco, y ofreciósele por escudero Tomé Cecial, compadre y vecino de Sancho Panza, hombre alegre y de lucios cascos. Armóse Sansón como queda referido y Tomé Cecial acomodó sobre sus naturales narices las falsas y de máscara ya dichas, porque no fuese conocido de su compadre cuando se viesen; y así, siguieron el mismo viaje que llevaba don Quijote, y llegaron casi a hallarse en la aventura del carro de la Muerte. Y, finalmente, dieron con ellos en el bosque, donde les sucedió todo lo que el prudente ha leído; y si no fuera por los pensamientos extraordinarios de don Quijote, que se dio a entender que el bachiller no era el bachiller, el señor bachiller quedara imposibilitado para siempre de graduarse de licenciado, por no haber hallado nidos donde pensó hallar pájaros. Tomé Cecial, que vio cuán mal había logrado sus deseos y el mal paradero que había tenido su camino, dijo al bachiller: -Por cierto, señor Sansón Carrasco, que tenemos nuestro merecido: con facilidad se piensa y se acomete una empresa, pero con dificultad las más veces se sale della. Don Quijote loco, nosotros cuerdos: él se va sano y riendo, vuesa merced queda molido y triste. Sepamos, pues, ahora, cuál es más loco: ¿el que lo es por no poder menos, o el que lo es por su voluntad? A lo que respondió Sansón: -La diferencia que hay entre esos dos locos es que el que lo es por fuerza lo será siempre, y el que lo es de grado lo dejará de ser cuando quisiere. -Pues así es -dijo Tomé Cecial-, yo fui por mi voluntad loco cuando quise hacerme escudero de vuestra merced, y por la misma quiero dejar de serlo y volverme a mi casa. -Eso os cumple -respondió Sansón-, porque pensar que yo he de volver a la mía, hasta haber molido a palos a don Quijote, es pensar en lo escusado; y no me llevará ahora a buscarle el deseo de que cobre su juicio, sino el de la venganza; que el dolor grande de mis costillas no me deja hacer más piadosos discursos. En esto fueron razonando los dos, hasta que llegaron a un pueblo donde fue ventura hallar un algebrista, con quien se curó el Sansón desgraciado. Tomé Cecial se volvió y le dejó, y él quedó imaginando su venganza; y la historia vuelve a hablar dél a su tiempo, por no dejar de regocijarse ahora con don Quijote. Capítulo XVI. De lo que sucedió a don Quijote con un discreto caballero de la Mancha Con la alegría, contento y ufanidad que se ha dicho, seguía don Quijote su jornada, imaginándose por la pasada vitoria ser el caballero andante más valiente que tenía en aquella edad el mundo; daba por acabadas y a felice fin conducidas cuantas aventuras pudiesen sucederle de allí adelante; tenía en poco a los encantos y a los encantadores; no se acordaba de los inumerables palos que en el discurso de sus caballerías le habían dado, ni de la pedrada que le derribó la mitad de los dientes, ni del desagradecimiento de los galeotes, ni del atrevimiento y lluvia de estacas de los yangüeses. Finalmente, decía entre sí que si él hallara arte, modo o manera como desencantar a su señora Dulcinea, no invidiara a la mayor ventura que alcanzó o pudo alcanzar el más venturoso caballero andante de los pasados siglos. En estas imaginaciones iba todo ocupado, cuando Sancho le dijo: -¿No es bueno, señor, que aun todavía traigo entre los ojos las desaforadas narices, y mayores de marca, de mi compadre Tomé Cecial? -Y ¿crees tú, Sancho, por ventura, que el Caballero de los Espejos era el bachiller Carrasco; y su escudero, Tomé Cecial, tu compadre? -No sé qué me diga a eso -respondió Sancho-; sólo sé que las señas que me dio de mi casa, mujer y hijos no me las podría dar otro que él mesmo; y la cara, quitadas las narices, era la misma de Tomé Cecial, como yo se la he visto muchas veces en mi pueblo y pared en medio de mi misma casa; y el tono de la habla era todo uno. -Estemos a razón, Sancho -replicó don Quijote-. Ven acá: ¿en qué consideración puede caber que el bachiller Sansón Carrasco viniese como caballero andante, armado de armas ofensivas y defensivas, a pelear conmigo? ¿He sido yo su enemigo por ventura? ¿Hele dado yo jamás ocasión para tenerme ojeriza? ¿Soy yo su rival, o hace él profesión de las armas, para tener invidia a la fama que yo por ellas he ganado? -Pues, ¿qué diremos, señor -respondió Sancho-, a esto de parecerse tanto aquel caballero, sea el que se fuere, al bachiller Carrasco, y su escudero a Tomé Cecial, mi compadre? Y si ello es encantamento, como vuestra merced ha dicho, ¿no había en el mundo otros dos a quien se parecieran? -Todo es artificio y traza -respondió don Quijote- de los malignos magos que me persiguen, los cuales, anteviendo que yo había de quedar vencedor en la contienda, se previnieron de que el caballero vencido mostrase el rostro de mi amigo el bachiller, porque la amistad que le tengo se pusiese entre los filos de mi espada y el rigor de mi brazo, y templase la justa ira de mi corazón, y desta manera quedase con vida el que con embelecos y falsías procuraba quitarme la mía. Para prueba de lo cual ya sabes, ¡oh Sancho!, por experiencia que no te dejará mentir ni engañar, cuán fácil sea a los encantadores mudar unos rostros en otros, haciendo de lo hermoso feo y de lo feo hermoso, pues no ha dos días que viste por tus mismos ojos la hermosura y gallardía de la sin par Dulcinea en toda su entereza y natural conformidad, y yo la vi en la fealdad y bajeza de una zafia labradora, con cataratas en los ojos y con mal olor en la boca; y más, que el perverso encantador que se atrevió a hacer una transformación tan mala no es mucho que haya hecho la de Sansón Carrasco y la de tu compadre, por quitarme la gloria del vencimiento de las manos. Pero, con todo esto, me consuelo; porque, en fin, en cualquiera figura que haya sido, he quedado vencedor de mi enemigo. -Dios sabe la verdad de todo -respondió Sancho. Y como él sabía que la transformación de Dulcinea había sido traza y embeleco suyo, no le satisfacían las quimeras de su amo; pero no le quiso replicar, por no decir alguna palabra que descubriese su embuste. En estas razones estaban cuando los alcanzó un hombre que detrás dellos por el mismo camino venía sobre una muy hermosa yegua tordilla, vestido un gabán de paño fino verde, jironado de terciopelo leonado, con una montera del mismo terciopelo; el aderezo de la yegua era de campo y de la jineta, asimismo de morado y verde. Traía un alfanje morisco pendiente de un ancho tahalí de verde y oro, y los borceguíes eran de la labor del tahalí; las espuelas no eran doradas, sino dadas con un barniz verde, tan tersas y bruñidas que, por hacer labor con todo el vestido, parecían mejor que si fuera de oro puro. Cuando llegó a ellos, el caminante los saludó cortésmente, y, picando a la yegua, se pasaba de largo; pero don Quijote le dijo: -Señor galán, si es que vuestra merced lleva el camino que nosotros y no importa el darse priesa, merced recibiría en que nos fuésemos juntos. -En verdad -respondió el de la yegua- que no me pasara tan de largo, si no fuera por temor que con la compañía de mi yegua no se alborotara ese caballo. -Bien puede, señor -respondió a esta sazón Sancho-, bien puede tener las riendas a su yegua, porque nuestro caballo es el más honesto y bien mirado del mundo: jamás en semejantes ocasiones ha hecho vileza alguna, y una vez que se desmandó a hacerla la lastamos mi señor y yo con las setenas. Digo otra vez que puede vuestra merced detenerse, si quisiere; que, aunque se la den entre dos platos, a buen seguro que el caballo no la arrostre. Detuvo la rienda el caminante, admirándose de la apostura y rostro de don Quijote, el cual iba sin celada, que la llevaba Sancho como maleta en el arzón delantero de la albarda del rucio; y si mucho miraba el de lo verde a don Quijote, mucho más miraba don Quijote al de lo verde, pareciéndole hombre de chapa. La edad mostraba ser de cincuenta años; las canas, pocas, y el rostro, aguileño; la vista, entre alegre y grave; finalmente, en el traje y apostura daba a entender ser hombre de buenas prendas. Lo que juzgó de don Quijote de la Mancha el de lo verde fue que semejante manera ni parecer de hombre no le había visto jamás: admiróle la longura de su caballo, la grandeza de su cuerpo, la flaqueza y amarillez de su rostro, sus armas, su ademán y compostura: figura y retrato no visto por luengos tiempos atrás en aquella tierra. Notó bien don Quijote la atención con que el caminante le miraba, y leyóle en la suspensión su deseo; y, como era tan cortés y tan amigo de dar gusto a todos, antes que le preguntase nada, le salió al camino, diciéndole: -Esta figura que vuesa merced en mí ha visto, por ser tan nueva y tan fuera de las que comúnmente se usan, no me maravillaría yo de que le hubiese maravillado; pero dejará vuesa merced de estarlo cuando le diga, como le digo, que soy caballero destos que dicen las gentes que a sus aventuras van. Salí de mi patria, empeñé mi hacienda, dejé mi regalo, y entreguéme en los brazos de la Fortuna, que me llevasen donde más fuese servida. Quise resucitar la ya muerta andante caballería, y ha muchos días que, tropezando aquí, cayendo allí, despeñándome acá y levantándome acullá, he cumplido gran parte de mi deseo, socorriendo viudas, amparando doncellas y favoreciendo casadas, huérfanos y pupilos, propio y natural oficio de caballeros andantes; y así, por mis valerosas, muchas y cristianas hazañas he merecido andar ya en estampa en casi todas o las más naciones del mundo. Treinta mil volúmenes se han impreso de mi historia, y lleva camino de imprimirse treinta mil veces de millares, si el cielo no lo remedia. Finalmente, por encerrarlo todo en breves palabras, o en una sola, digo que yo soy don Quijote de la Mancha, por otro nombre llamado el Caballero de la Triste Figura; y, puesto que las propias alabanzas envilecen, esme forzoso decir yo tal vez las mías, y esto se entiende cuando no se halla presente quien las diga; así que, señor gentilhombre, ni este caballo, esta lanza, ni este escudo, ni escudero, ni todas juntas estas armas, ni la amarillez de mi rostro, ni mi atenuada flaqueza, os podrá admirar de aquí adelante, habiendo ya sabido quién soy y la profesión que hago. Calló en diciendo esto don Quijote, y el de lo verde, según se tardaba en responderle, parecía que no acertaba a hacerlo; pero de allí a buen espacio le dijo: -Acertastes, señor caballero, a conocer por mi suspensión mi deseo; pero no habéis acertado a quitarme la maravilla que en mí causa el haberos visto; que, puesto que, como vos, señor, decís, que el saber ya quién sois me lo podría quitar, no ha sido así; antes, agora que lo sé, quedo más suspenso y maravillado. ¿Cómo y es posible que hay hoy caballeros andantes en el mundo, y que hay historias impresas de verdaderas caballerías? No me puedo persuadir que haya hoy en la tierra quien favorezca viudas, ampare doncellas, ni honre casadas, ni socorra huérfanos, y no lo creyera si en vuesa merced no lo hubiera visto con mis ojos. ¡Bendito sea el cielo!, que con esa historia, que vuesa merced dice que está impresa, de sus altas y verdaderas caballerías, se habrán puesto en olvido las innumerables de los fingidos caballeros andantes, de que estaba lleno el mundo, tan en daño de las buenas costumbres y tan en perjuicio y descrédito de las buenas historias. -Hay mucho que decir -respondió don Quijote- en razón de si son fingidas, o no, las historias de los andantes caballeros. -Pues, ¿hay quien dude -respondió el Verde- que no son falsas las tales historias? -Yo lo dudo -respondió don Quijote-, y quédese esto aquí; que si nuestra jornada dura, espero en Dios de dar a entender a vuesa merced que ha hecho mal en irse con la corriente de los que tienen por cierto que no son verdaderas. Desta última razón de don Quijote tomó barruntos el caminante de que don Quijote debía de ser algún mentecato, y aguardaba que con otras lo confirmase; pero, antes que se divertiesen en otros razonamientos, don Quijote le rogó le dijese quién era, pues él le había dado parte de su condición y de su vida. A lo que respondió el del Verde Gabán: -Yo, señor Caballero de la Triste Figura, soy un hidalgo natural de un lugar donde iremos a comer hoy, si Dios fuere servido. Soy más que medianamente rico y es mi nombre don Diego de Miranda; paso la vida con mi mujer, y con mis hijos, y con mis amigos; mis ejercicios son el de la caza y pesca, pero no mantengo ni halcón ni galgos, sino algún perdigón manso, o algún hurón atrevido. Tengo hasta seis docenas de libros, cuáles de romance y cuáles de latín, de historia algunos y de devoción otros; los de caballerías aún no han entrado por los umbrales de mis puertas. Hojeo más los que son profanos que los devotos, como sean de honesto entretenimiento, que deleiten con el lenguaje y admiren y suspendan con la invención, puesto que déstos hay muy pocos en España. Alguna vez como con mis vecinos y amigos, y muchas veces los convido; son mis convites limpios y aseados, y no nada escasos; ni gusto de murmurar, ni consiento que delante de mí se murmure; no escudriño las vidas ajenas, ni soy lince de los hechos de los otros; oigo misa cada día; reparto de mis bienes con los pobres, sin hacer alarde de las buenas obras, por no dar entrada en mi corazón a la hipocresía y vanagloria, enemigos que blandamente se apoderan del corazón más recatado; procuro poner en paz los que sé que están desavenidos; soy devoto de nuestra Señora, y confío siempre en la misericordia infinita de Dios nuestro Señor. Atentísimo estuvo Sancho a la relación de la vida y entretenimientos del hidalgo; y, pareciéndole buena y santa y que quien la hacía debía de hacer milagros, se arrojó del rucio, y con gran priesa le fue a asir del estribo derecho, y con devoto corazón y casi lágrimas le besó los pies una y muchas veces. Visto lo cual por el hidalgo, le preguntó: -¿Qué hacéis, hermano? ¿Qué besos son éstos? -Déjenme besar -respondió Sancho-, porque me parece vuesa merced el primer santo a la jineta que he visto en todos los días de mi vida. -No soy santo -respondió el hidalgo-, sino gran pecador; vos sí, hermano, que debéis de ser bueno, como vuestra simplicidad lo muestra. Volvió Sancho a cobrar la albarda, habiendo sacado a plaza la risa de la profunda malencolía de su amo y causado nueva admiración a don Diego. Preguntóle don Quijote que cuántos hijos tenía, y díjole que una de las cosas en que ponían el sumo bien los antiguos filósofos, que carecieron del verdadero conocimiento de Dios, fue en los bienes de la naturaleza, en los de la fortuna, en tener muchos amigos y en tener muchos y buenos hijos. -Yo, señor don Quijote -respondió el hidalgo-, tengo un hijo, que, a no tenerle, quizá me juzgara por más dichoso de lo que soy; y no porque él sea malo, sino porque no es tan bueno como yo quisiera. Será de edad de diez y ocho años: los seis ha estado en Salamanca, aprendiendo las lenguas latina y griega; y, cuando quise que pasase a estudiar otras ciencias, halléle tan embebido en la de la poesía, si es que se puede llamar ciencia, que no es posible hacerle arrostrar la de las leyes, que yo quisiera que estudiara, ni de la reina de todas, la teología. Quisiera yo que fuera corona de su linaje, pues vivimos en siglo donde nuestros reyes premian altamente las virtuosas y buenas letras; porque letras sin virtud son perlas en el muladar. Todo el día se le pasa en averiguar si dijo bien o mal Homero en tal verso de la Ilíada; si Marcial anduvo deshonesto, o no, en tal epigrama; si se han de entender de una manera o otra tales y tales versos de Virgilio. En fin, todas sus conversaciones son con los libros de los referidos poetas, y con los de Horacio, Persio, Juvenal y Tibulo; que de los modernos romancistas no hace mucha cuenta; y, con todo el mal cariño que muestra tener a la poesía de romance, le tiene agora desvanecidos los pensamientos el hacer una glosa a cuatro versos que le han enviado de Salamanca, y pienso que son de justa literaria. A todo lo cual respondió don Quijote: -Los hijos, señor, son pedazos de las entrañas de sus padres, y así, se han de querer, o buenos o malos que sean, como se quieren las almas que nos dan vida; a los padres toca el encaminarlos desde pequeños por los pasos de la virtud, de la buena crianza y de las buenas y cristianas costumbres, para que cuando grandes sean báculo de la vejez de sus padres y gloria de su posteridad; y en lo de forzarles que estudien esta o aquella ciencia no lo tengo por acertado, aunque el persuadirles no será dañoso; y cuando no se ha de estudiar para pane lucrando, siendo tan venturoso el estudiante que le dio el cielo padres que se lo dejen, sería yo de parecer que le dejen seguir aquella ciencia a que más le vieren inclinado; y, aunque la de la poesía es menos útil que deleitable, no es de aquellas que suelen deshonrar a quien las posee. La poesía, señor hidalgo, a mi parecer, es como una doncella tierna y de poca edad, y en todo estremo hermosa, a quien tienen cuidado de enriquecer, pulir y adornar otras muchas doncellas, que son todas las otras ciencias, y ella se ha de servir de todas, y todas se han de autorizar con ella; pero esta tal doncella no quiere ser manoseada, ni traída por las calles, ni publicada por las esquinas de las plazas ni por los rincones de los palacios. Ella es hecha de una alquimia de tal virtud, que quien la sabe tratar la volverá en oro purísimo de inestimable precio; hala de tener, el que la tuviere, a raya, no dejándola correr en torpes sátiras ni en desalmados sonetos; no ha de ser vendible en ninguna manera, si ya no fuere en poemas heroicos, en lamentables tragedias, o en comedias alegres y artificiosas; no se ha de dejar tratar de los truhanes, ni del ignorante vulgo, incapaz de conocer ni estimar los tesoros que en ella se encierran. Y no penséis, señor, que yo llamo aquí vulgo solamente a la gente plebeya y humilde; que todo aquel que no sabe, aunque sea señor y príncipe, puede y debe entrar en número de vulgo. Y así, el que con los requisitos que he dicho tratare y tuviere a la poesía, será famoso y estimado su nombre en todas las naciones políticas del mundo. Y a lo que decís, señor, que vuestro hijo no estima mucho la poesía de romance, doyme a entender que no anda muy acertado en ello, y la razón es ésta: el grande Homero no escribió en latín, porque era griego, ni Virgilio no escribió en griego, porque era latino. En resolución, todos los poetas antiguos escribieron en la lengua que mamaron en la leche, y no fueron a buscar las estranjeras para declarar la alteza de sus conceptos. Y, siendo esto así, razón sería se estendiese esta costumbre por todas las naciones, y que no se desestimase el poeta alemán porque escribe en su lengua, ni el castellano, ni aun el vizcaíno, que escribe en la suya. Pero vuestro hijo, a lo que yo, señor, imagino, no debe de estar mal con la poesía de romance, sino con los poetas que son meros romancistas, sin saber otras lenguas ni otras ciencias que adornen y despierten y ayuden a su natural impulso; y aun en esto puede haber yerro; porque, según es opinión verdadera, el poeta nace: quieren decir que del vientre de su madre el poeta natural sale poeta; y, con aquella inclinación que le dio el cielo, sin más estudio ni artificio, compone cosas, que hace verdadero al que dijo: est Deus in nobis..., etcétera. También digo que el natural poeta que se ayudare del arte será mucho mejor y se aventajará al poeta que sólo por saber el arte quisiere serlo; la razón es porque el arte no se aventaja a la naturaleza, sino perficiónala; así que, mezcladas la naturaleza y el arte, y el arte con la naturaleza, sacarán un perfetísimo poeta. Sea, pues, la conclusión de mi plática, señor hidalgo, que vuesa merced deje caminar a su hijo por donde su estrella le llama; que, siendo él tan buen estudiante como debe de ser, y habiendo ya subido felicemente el primer escalón de las esencias, que es el de las lenguas, con ellas por sí mesmo subirá a la cumbre de las letras humanas, las cuales tan bien parecen en un caballero de capa y espada, y así le adornan, honran y engrandecen, como las mitras a los obispos, o como las garnachas a los peritos jurisconsultos. Riña vuesa merced a su hijo si hiciere sátiras que perjudiquen las honras ajenas, y castíguele, y rómpaselas, pero si hiciere sermones al modo de Horacio, donde reprehenda los vicios en general, como tan elegantemente él lo hizo, alábele: porque lícito es al poeta escribir contra la invidia, y decir en sus versos mal de los invidiosos, y así de los otros vicios, con que no señale persona alguna; pero hay poetas que, a trueco de decir una malicia, se pondrán a peligro que los destierren a las islas de Ponto. Si el poeta fuere casto en sus costumbres, lo será también en sus versos; la pluma es lengua del alma: cuales fueren los conceptos que en ella se engendraren, tales serán sus escritos; y cuando los reyes y príncipes veen la milagrosa ciencia de la poesía en sujetos prudentes, virtuosos y graves, los honran, los estiman y los enriquecen, y aun los coronan con las hojas del árbol a quien no ofende el rayo, como en señal que no han de ser ofendidos de nadie los que con tales coronas veen honrados y adornadas sus sienes. Admirado quedó el del Verde Gabán del razonamiento de don Quijote, y tanto, que fue perdiendo de la opinión que con él tenía, de ser mentecato. Pero, a la mitad desta plática, Sancho, por no ser muy de su gusto, se había desviado del camino a pedir un poco de leche a unos pastores que allí junto estaban ordeñando unas ovejas; y, en esto, ya volvía a renovar la plática el hidalgo, satisfecho en estremo de la discreción y buen discurso de don Quijote, cuando, alzando don Quijote la cabeza, vio que por el camino por donde ellos iban venía un carro lleno de banderas reales; y, creyendo que debía de ser alguna nueva aventura, a grandes voces llamó a Sancho que viniese a darle la celada. El cual Sancho, oyéndose llamar, dejó a los pastores, y a toda priesa picó al rucio, y llegó donde su amo estaba, a quien sucedió una espantosa y desatinada aventura. Capítulo XVII. De donde se declaró el último punto y estremo adonde llegó y pudo llegar el inaudito ánimo de don Quijote, con la felicemente acabada aventura de los leones Cuenta la historia que cuando don Quijote daba voces a Sancho que le trujese el yelmo, estaba él comprando unos requesones que los pastores le vendían; y, acosado de la mucha priesa de su amo, no supo qué hacer dellos, ni en qué traerlos, y, por no perderlos, que ya los tenía pagados, acordó de echarlos en la celada de su señor, y con este buen recado volvió a ver lo que le quería; el cual, en llegando, le dijo: -Dame, amigo, esa celada; que yo sé poco de aventuras, o lo que allí descubro es alguna que me ha de necesitar, y me necesita, a tomar mis armas. El del Verde Gabán, que esto oyó, tendió la vista por todas partes, y no descubrió otra cosa que un carro que hacia ellos venía, con dos o tres banderas pequeñas, que le dieron a entender que el tal carro debía de traer moneda de Su Majestad, y así se lo dijo a don Quijote; pero él no le dio crédito, siempre creyendo y pensando que todo lo que le sucediese habían de ser aventuras y más aventuras, y así, respondió al hidalgo: -Hombre apercebido, medio combatido: no se pierde nada en que yo me aperciba, que sé por experiencia que tengo enemigos visibles e invisibles, y no sé cuándo, ni adónde, ni en qué tiempo, ni en qué figuras me han de acometer. Y, volviéndose a Sancho, le pidió la celada; el cual, como no tuvo lugar de sacar los requesones, le fue forzoso dársela como estaba. Tomóla don Quijote, y, sin que echase de ver lo que dentro venía, con toda priesa se la encajó en la cabeza; y, como los requesones se apretaron y exprimieron, comenzó a correr el suero por todo el rostro y barbas de don Quijote, de lo que recibió tal susto, que dijo a Sancho: -¿Qué será esto, Sancho, que parece que se me ablandan los cascos, o se me derriten los sesos, o que sudo de los pies a la cabeza? Y si es que sudo, en verdad que no es de miedo; sin duda creo que es terrible la aventura que agora quiere sucederme. Dame, si tienes, con que me limpie, que el copioso sudor me ciega los ojos. Calló Sancho y diole un paño, y dio con él gracias a Dios de que su señor no hubiese caído en el caso. Limpióse don Quijote y quitóse la celada por ver qué cosa era la que, a su parecer, le enfriaba la cabeza, y, viendo aquellas gachas blancas dentro de la celada, las llegó a las narices, y en oliéndolas dijo: -Por vida de mi señora Dulcinea del Toboso, que son requesones los que aquí me has puesto, traidor, bergante y mal mirado escudero. A lo que, con gran flema y disimulación, respondió Sancho: -Si son requesones, démelos vuesa merced, que yo me los comeré... Pero cómalos el diablo, que debió de ser el que ahí los puso. ¿Yo había de tener atrevimiento de ensuciar el yelmo de vuesa merced? ¡Hallado le habéis el atrevido! A la fe, señor, a lo que Dios me da a entender, también debo yo de tener encantadores que me persiguen como a hechura y miembro de vuesa merced, y habrán puesto ahí esa inmundicia para mover a cólera su paciencia y hacer que me muela, como suele, las costillas. Pues en verdad que esta vez han dado salto en vago, que yo confío en el buen discurso de mi señor, que habrá considerado que ni yo tengo requesones, ni leche, ni otra cosa que lo valga, y que si la tuviera, antes la pusiera en mi estómago que en la celada. -Todo puede ser -dijo don Quijote. Y todo lo miraba el hidalgo, y de todo se admiraba, especialmente cuando, después de haberse limpiado don Quijote cabeza, rostro y barbas y celada, se la encajó; y, afirmándose bien en los estribos, requiriendo la espada y asiendo la lanza, dijo: -Ahora, venga lo que veniere, que aquí estoy con ánimo de tomarme con el mesmo Satanás en persona. Llegó en esto el carro de las banderas, en el cual no venía otra gente que el carretero, en las mulas, y un hombre sentado en la delantera. Púsose don Quijote delante y dijo: -¿Adónde vais, hermanos? ¿Qué carro es éste, qué lleváis en él y qué banderas son aquéstas? A lo que respondió el carretero: -El carro es mío; lo que va en él son dos bravos leones enjaulados, que el general de Orán envía a la corte, presentados a Su Majestad; las banderas son del rey nuestro señor, en señal que aquí va cosa suya. -Y ¿son grandes los leones? -preguntó don Quijote. -Tan grandes -respondió el hombre que iba a la puerta del carro-, que no han pasado mayores, ni tan grandes, de Africa a España jamás; y yo soy el leonero, y he pasado otros, pero como éstos, ninguno. Son hembra y macho; el macho va en esta jaula primera, y la hembra en la de atrás; y ahora van hambrientos porque no han comido hoy; y así, vuesa merced se desvíe, que es menester llegar presto donde les demos de comer. A lo que dijo don Quijote, sonriéndose un poco: -¿Leoncitos a mí? ¿A mí leoncitos, y a tales horas? Pues, ¡por Dios que han de ver esos señores que acá los envían si soy yo hombre que se espanta de leones! Apeaos, buen hombre, y, pues sois el leonero, abrid esas jaulas y echadme esas bestias fuera, que en mitad desta campaña les daré a conocer quién es don Quijote de la Mancha, a despecho y pesar de los encantadores que a mí los envían. -¡Ta, ta! -dijo a esta sazón entre sí el hidalgo-, dado ha señal de quién es nuestro buen caballero: los requesones, sin duda, le han ablandado los cascos y madurado los sesos. Llegóse en esto a él Sancho y díjole: -Señor, por quien Dios es, que vuesa merced haga de manera que mi señor don Quijote no se tome con estos leones, que si se toma, aquí nos han de hacer pedazos a todos. -Pues, ¿tan loco es vuestro amo -respondió el hidalgo-, que teméis, y creéis que se ha de tomar con tan fieros animales? -No es loco -respondió Sancho-, sino atrevido. -Yo haré que no lo sea -replicó el hidalgo. Y, llegándose a don Quijote, que estaba dando priesa al leonero que abriese las jaulas, le dijo: -Señor caballero, los caballeros andantes han de acometer las aventuras que prometen esperanza de salir bien dellas, y no aquellas que de en todo la quitan; porque la valentía que se entra en la juridición de la temeridad, más tiene de locura que de fortaleza. Cuanto más, que estos leones no vienen contra vuesa merced, ni lo sueñan: van presentados a Su Majestad, y no será bien detenerlos ni impedirles su viaje. -Váyase vuesa merced, señor hidalgo -respondió don Quijote-, a entender con su perdigón manso y con su hurón atrevido, y deje a cada uno hacer su oficio. Éste es el mío, y yo sé si vienen a mí, o no, estos señores leones. Y, volviéndose al leonero, le dijo: -¡Voto a tal, don bellaco, que si no abrís luego luego las jaulas, que con esta lanza os he de coser con el carro! El carretero, que vio la determinación de aquella armada fantasía, le dijo: -Señor mío, vuestra merced sea servido, por caridad, dejarme desuncir las mulas y ponerme en salvo con ellas antes que se desenvainen los leones, porque si me las matan, quedaré rematado para toda mi vida; que no tengo otra hacienda sino este carro y estas mulas. -¡Oh hombre de poca fe! -respondió don Quijote-, apéate y desunce, y haz lo que quisieres, que presto verás que trabajaste en vano y que pudieras ahorrar desta diligencia. Apeóse el carretero y desunció a gran priesa, y el leonero dijo a grandes voces: -Séanme testigos cuantos aquí están cómo contra mi voluntad y forzado abro las jaulas y suelto los leones, y de que protesto a este señor que todo el mal y daño que estas bestias hicieren corra y vaya por su cuenta, con más mis salarios y derechos. Vuestras mercedes, señores, se pongan en cobro antes que abra, que yo seguro estoy que no me han de hacer daño. Otra vez le persuadió el hidalgo que no hiciese locura semejante, que era tentar a Dios acometer tal disparate. A lo que respondió don Quijote que él sabía lo que hacía. Respondióle el hidalgo que lo mirase bien, que él entendía que se engañaba. -Ahora, señor -replicó don Quijote-, si vuesa merced no quiere ser oyente desta que a su parecer ha de ser tragedia, pique la tordilla y póngase en salvo. Oído lo cual por Sancho, con lágrimas en los ojos le suplicó desistiese de tal empresa, en cuya comparación habían sido tortas y pan pintado la de los molinos de viento y la temerosa de los batanes, y, finalmente, todas las hazañas que había acometido en todo el discurso de su vida. -Mire, señor -decía Sancho-, que aquí no hay encanto ni cosa que lo valga; que yo he visto por entre las verjas y resquicios de la jaula una uña de león verdadero, y saco por ella que el tal león, cuya debe de ser la tal uña, es mayor que una montaña. -El miedo, a lo menos -respondió don Quijote-, te le hará parecer mayor que la mitad del mundo. Retírate, Sancho, y déjame; y si aquí muriere, ya sabes nuestro antiguo concierto: acudirás a Dulcinea, y no te digo más. A éstas añadió otras razones, con que quitó las esperanzas de que no había de dejar de proseguir su desvariado intento. Quisiera el del Verde Gabán oponérsele, pero viose desigual en las armas, y no le pareció cordura tomarse con un loco, que ya se lo había parecido de todo punto don Quijote; el cual, volviendo a dar priesa al leonero y a reiterar las amenazas, dio ocasión al hidalgo a que picase la yegua, y Sancho al rucio, y el carretero a sus mulas, procurando todos apartarse del carro lo más que pudiesen, antes que los leones se desembanastasen. Lloraba Sancho la muerte de su señor, que aquella vez sin duda creía que llegaba en las garras de los leones; maldecía su ventura, y llamaba menguada la hora en que le vino al pensamiento volver a servirle; pero no por llorar y lamentarse dejaba de aporrear al rucio para que se alejase del carro. Viendo, pues, el leonero que ya los que iban huyendo estaban bien desviados, tornó a requerir y a intimar a don Quijote lo que ya le había requerido e intimado, el cual respondió que lo oía, y que no se curase de más intimaciones y requirimientos, que todo sería de poco fruto, y que se diese priesa. En el espacio que tardó el leonero en abrir la jaula primera, estuvo considerando don Quijote si sería bien hacer la batalla antes a pie que a caballo; y, en fin, se determinó de hacerla a pie, temiendo que Rocinante se espantaría con la vista de los leones. Por esto saltó del caballo, arrojó la lanza y embrazó el escudo, y, desenvainando la espada, paso ante paso, con maravilloso denuedo y corazón valiente, se fue a poner delante del carro, encomendándose a Dios de todo corazón, y luego a su señora Dulcinea. Y es de saber que, llegando a este paso, el autor de esta verdadera historia exclama y dice: ''¡Oh fuerte y, sobre todo encarecimiento, animoso don Quijote de la Mancha, espejo donde se pueden mirar todos los valientes del mundo, segundo y nuevo don Manuel de León, que fue gloria y honra de los españoles caballeros! ¿Con qué palabras contaré esta tan espantosa hazaña, o con qué razones la haré creíble a los siglos venideros, o qué alabanzas habrá que no te convengan y cuadren, aunque sean hipérboles sobre todos los hipérboles? Tú a pie, tú solo, tú intrépido, tú magnánimo, con sola una espada, y no de las del perrillo cortadoras, con un escudo no de muy luciente y limpio acero, estás aguardando y atendiendo los dos más fieros leones que jamás criaron las africanas selvas. Tus mismos hechos sean los que te alaben, valeroso manchego, que yo los dejo aquí en su punto por faltarme palabras con que encarecerlos''. Aquí cesó la referida exclamación del autor, y pasó adelante, anudando el hilo de la historia, diciendo que, visto el leonero ya puesto en postura a don Quijote, y que no podía dejar de soltar al león macho, so pena de caer en la desgracia del indignado y atrevido caballero, abrió de par en par la primera jaula, donde estaba, como se ha dicho, el león, el cual pareció de grandeza extraordinaria y de espantable y fea catadura. Lo primero que hizo fue revolverse en la jaula, donde venía echado, y tender la garra, y desperezarse todo; abrió luego la boca y bostezó muy despacio, y, con casi dos palmos de lengua que sacó fuera, se despolvoreó los ojos y se lavó el rostro; hecho esto, sacó la cabeza fuera de la jaula y miró a todas partes con los ojos hechos brasas, vista y ademán para poner espanto a la misma temeridad. Sólo don Quijote lo miraba atentamente, deseando que saltase ya del carro y viniese con él a las manos, entre las cuales pensaba hacerle pedazos. Hasta aquí llegó el estremo de su jamás vista locura. Pero el generoso león, más comedido que arrogante, no haciendo caso de niñerías, ni de bravatas, después de haber mirado a una y otra parte, como se ha dicho, volvió las espaldas y enseñó sus traseras partes a don Quijote, y con gran flema y remanso se volvió a echar en la jaula. Viendo lo cual don Quijote, mandó al leonero que le diese de palos y le irritase para echarle fuera. -Eso no haré yo -respondió el leonero-, porque si yo le instigo, el primero a quien hará pedazos será a mí mismo. Vuesa merced, señor caballero, se contente con lo hecho, que es todo lo que puede decirse en género de valentía, y no quiera tentar segunda fortuna. El león tiene abierta la puerta: en su mano está salir, o no salir; pero, pues no ha salido hasta ahora, no saldrá en todo el día. La grandeza del corazón de vuesa merced ya está bien declarada: ningún bravo peleante, según a mí se me alcanza, está obligado a más que a desafiar a su enemigo y esperarle en campaña; y si el contrario no acude, en él se queda la infamia, y el esperante gana la corona del vencimiento. -Así es verdad -respondió don Quijote-: cierra, amigo, la puerta, y dame por testimonio, en la mejor forma que pudieres, lo que aquí me has visto hacer; conviene a saber: cómo tú abriste al león, yo le esperé, él no salió; volvíle a esperar, volvió a no salir y volvióse acostar. No debo más, y encantos afuera, y Dios ayude a la razón y a la verdad, y a la verdadera caballería; y cierra, como he dicho, en tanto que hago señas a los huidos y ausentes, para que sepan de tu boca esta hazaña. Hízolo así el leonero, y don Quijote, poniendo en la punta de la lanza el lienzo con que se había limpiado el rostro de la lluvia de los requesones, comenzó a llamar a los que no dejaban de huir ni de volver la cabeza a cada paso, todos en tropa y antecogidos del hidalgo; pero, alcanzando Sancho a ver la señal del blanco paño, dijo: -Que me maten si mi señor no ha vencido a las fieras bestias, pues nos llama. Detuviéronse todos, y conocieron que el que hacía las señas era don Quijote; y, perdiendo alguna parte del miedo, poco a poco se vinieron acercando hasta donde claramente oyeron las voces de don Quijote, que los llamaba. Finalmente, volvieron al carro, y, en llegando, dijo don Quijote al carretero: -Volved, hermano, a uncir vuestras mulas y a proseguir vuestro viaje; y tú, Sancho, dale dos escudos de oro, para él y para el leonero, en recompensa de lo que por mí se han detenido. -Ésos daré yo de muy buena gana -respondió Sancho-; pero, ¿qué se han hecho los leones? ¿Son muertos, o vivos? Entonces el leonero, menudamente y por sus pausas, contó el fin de la contienda, exagerando, como él mejor pudo y supo, el valor de don Quijote, de cuya vista el león, acobardado, no quiso ni osó salir de la jaula, puesto que había tenido un buen espacio abierta la puerta de la jaula; y que, por haber él dicho a aquel caballero que era tentar a Dios irritar al león para que por fuerza saliese, como él quería que se irritase, mal de su grado y contra toda su voluntad, había permitido que la puerta se cerrase. -¿Qué te parece desto, Sancho? -dijo don Quijote-. ¿Hay encantos que valgan contra la verdadera valentía? Bien podrán los encantadores quitarme la ventura, pero el esfuerzo y el ánimo, será imposible. Dio los escudos Sancho, unció el carretero, besó las manos el leonero a don Quijote por la merced recebida, y prometióle de contar aquella valerosa hazaña al mismo rey, cuando en la corte se viese. -Pues, si acaso Su Majestad preguntare quién la hizo, diréisle que el Caballero de los Leones, que de aquí adelante quiero que en éste se trueque, cambie, vuelva y mude el que hasta aquí he tenido del Caballero de la Triste Figura; y en esto sigo la antigua usanza de los andantes caballeros, que se mudaban los nombres cuando querían, o cuando les venía a cuento. Siguió su camino el carro, y don Quijote, Sancho y el del Verde Gabán prosiguieron el suyo. En todo este tiempo no había hablado palabra don Diego de Miranda, todo atento a mirar y a notar los hechos y palabras de don Quijote, pareciéndole que era un cuerdo loco y un loco que tiraba a cuerdo. No había aún llegado a su noticia la primera parte de su historia; que si la hubiera leído, cesara la admiración en que lo ponían sus hechos y sus palabras, pues ya supiera el género de su locura; pero, como no la sabía, ya le tenía por cuerdo y ya por loco, porque lo que hablaba era concertado, elegante y bien dicho, y lo que hacía, disparatado, temerario y tonto. Y decía entre sí: -¿Qué más locura puede ser que ponerse la celada llena de requesones y darse a entender que le ablandaban los cascos los encantadores? Y ¿qué mayor temeridad y disparate que querer pelear por fuerza con leones? Destas imaginaciones y deste soliloquio le sacó don Quijote, diciéndole: -¿Quién duda, señor don Diego de Miranda, que vuestra merced no me tenga en su opinión por un hombre disparatado y loco? Y no sería mucho que así fuese, porque mis obras no pueden dar testimonio de otra cosa. Pues, con todo esto, quiero que vuestra merced advierta que no soy tan loco ni tan menguado como debo de haberle parecido. Bien parece un gallardo caballero, a los ojos de su rey, en la mitad de una gran plaza, dar una lanzada con felice suceso a un bravo toro; bien parece un caballero, armado de resplandecientes armas, pasar la tela en alegres justas delante de las damas, y bien parecen todos aquellos caballeros que en ejercicios militares, o que lo parezcan, entretienen y alegran, y, si se puede decir, honran las cortes de sus príncipes; pero sobre todos éstos parece mejor un caballero andante, que por los desiertos, por las soledades, por las encrucijadas, por las selvas y por los montes anda buscando peligrosas aventuras, con intención de darles dichosa y bien afortunada cima, sólo por alcanzar gloriosa fama y duradera. Mejor parece, digo, un caballero andante, socorriendo a una viuda en algún despoblado, que un cortesano caballero, requebrando a una doncella en las ciudades. Todos los caballeros tienen sus particulares ejercicios: sirva a las damas el cortesano; autorice la corte de su rey con libreas; sustente los caballeros pobres con el espléndido plato de su mesa; concierte justas, mantenga torneos y muéstrese grande, liberal y magnífico, y buen cristiano, sobre todo, y desta manera cumplirá con sus precisas obligaciones. Pero el andante caballero busque los rincones del mundo; éntrese en los más intricados laberintos; acometa a cada paso lo imposible; resista en los páramos despoblados los ardientes rayos del sol en la mitad del verano, y en el invierno la dura inclemencia de los vientos y de los yelos; no le asombren leones, ni le espanten vestiglos, ni atemoricen endriagos; que buscar éstos, acometer aquéllos y vencerlos a todos son sus principales y verdaderos ejercicios. Yo, pues, como me cupo en suerte ser uno del número de la andante caballería, no puedo dejar de acometer todo aquello que a mí me pareciere que cae debajo de la juridición de mis ejercicios; y así, el acometer los leones que ahora acometí derechamente me tocaba, puesto que conocí ser temeridad esorbitante, porque bien sé lo que es valentía, que es una virtud que está puesta entre dos estremos viciosos, como son la cobardía y la temeridad; pero menos mal será que el que es valiente toque y suba al punto de temerario, que no que baje y toque en el punto de cobarde; que así como es más fácil venir el pródigo a ser liberal que al avaro, así es más fácil dar el temerario en verdadero valiente que no el cobarde subir a la verdadera valentía; y, en esto de acometer aventuras, créame vuesa merced, señor don Diego, que antes se ha de perder por carta de más que de menos, porque mejor suena en las orejas de los que lo oyen "el tal caballero es temerario y atrevido" que no "el tal caballero es tímido y cobarde". -Digo, señor don Quijote -respondió don Diego-, que todo lo que vuesa merced ha dicho y hecho va nivelado con el fiel de la misma razón, y que entiendo que si las ordenanzas y leyes de la caballería andante se perdiesen, se hallarían en el pecho de vuesa merced como en su mismo depósito y archivo. Y démonos priesa, que se hace tarde, y lleguemos a mi aldea y casa, donde descansará vuestra merced del pasado trabajo, que si no ha sido del cuerpo, ha sido del espíritu, que suele tal vez redundar en cansancio del cuerpo. -Tengo el ofrecimiento a gran favor y merced, señor don Diego- respondió don Quijote. Y, picando más de lo que hasta entonces, serían como las dos de la tarde cuando llegaron a la aldea y a la casa de don Diego, a quien don Quijote llamaba el Caballero del Verde Gabán. Capítulo XVIII. De lo que sucedió a don Quijote en el castillo o casa del Caballero del Verde Gabán, con otras cosas extravagantes Halló don Quijote ser la casa de don Diego de Miranda ancha como de aldea; las armas, empero, aunque de piedra tosca, encima de la puerta de la calle; la bodega, en el patio; la cueva, en el portal, y muchas tinajas a la redonda, que, por ser del Toboso, le renovaron las memorias de su encantada y transformada Dulcinea; y sospirando, y sin mirar lo que decía, ni delante de quién estaba, dijo: -¡Oh dulces prendas, por mi mal halladas, dulces y alegres cuando Dios quería! ¡Oh tobosescas tinajas, que me habéis traído a la memoria la dulce prenda de mi mayor amargura! Oyóle decir esto el estudiante poeta, hijo de don Diego, que con su madre había salido a recebirle, y madre y hijo quedaron suspensos de ver la estraña figura de don Quijote; el cual, apeándose de Rocinante, fue con mucha cortesía a pedirle las manos para besárselas, y don Diego dijo: -Recebid, señora, con vuestro sólito agrado al señor don Quijote de la Mancha, que es el que tenéis delante, andante caballero y el más valiente y el más discreto que tiene el mundo. La señora, que doña Cristina se llamaba, le recibió con muestras de mucho amor y de mucha cortesía, y don Quijote se le ofreció con asaz de discretas y comedidas razones. Casi los mismos comedimientos pasó con el estudiante, que, en oyéndole hablar don Quijote, le tuvo por discreto y agudo. Aquí pinta el autor todas las circunstancias de la casa de don Diego, pintándonos en ellas lo que contiene una casa de un caballero labrador y rico; pero al traductor desta historia le pareció pasar estas y otras semejantes menudencias en silencio, porque no venían bien con el propósito principal de la historia, la cual más tiene su fuerza en la verdad que en las frías digresiones. Entraron a don Quijote en una sala, desarmóle Sancho, quedó en valones y en jubón de camuza, todo bisunto con la mugre de las armas: el cuello era valona a lo estudiantil, sin almidón y sin randas; los borceguíes eran datilados, y encerados los zapatos. Ciñóse su buena espada, que pendía de un tahalí de lobos marinos; que es opinión que muchos años fue enfermo de los riñones; cubrióse un herreruelo de buen paño pardo; pero antes de todo, con cinco calderos, o seis, de agua, que en la cantidad de los calderos hay alguna diferencia, se lavó la cabeza y rostro, y todavía se quedó el agua de color de suero, merced a la golosina de Sancho y a la compra de sus negros requesones, que tan blanco pusieron a su amo. Con los referidos atavíos, y con gentil donaire y gallardía, salió don Quijote a otra sala, donde el estudiante le estaba esperando para entretenerle en tanto que las mesas se ponían; que, por la venida de tan noble huésped, quería la señora doña Cristina mostrar que sabía y podía regalar a los que a su casa llegasen. En tanto que don Quijote se estuvo desarmando, tuvo lugar don Lorenzo, que así se llamaba el hijo de don Diego, de decir a su padre: -¿Quién diremos, señor, que es este caballero que vuesa merced nos ha traído a casa? Que el nombre, la figura, y el decir que es caballero andante, a mí y a mi madre nos tiene suspensos. -No sé lo que te diga, hijo -respondió don Diego-; sólo te sabré decir que le he visto hacer cosas del mayor loco del mundo, y decir razones tan discretas que borran y deshacen sus hechos: háblale tú, y toma el pulso a lo que sabe, y, pues eres discreto, juzga de su discreción o tontería lo que más puesto en razón estuviere; aunque, para decir verdad, antes le tengo por loco que por cuerdo. Con esto, se fue don Lorenzo a entretener a don Quijote, como queda dicho, y, entre otras pláticas que los dos pasaron, dijo don Quijote a don Lorenzo: -El señor don Diego de Miranda, padre de vuesa merced, me ha dado noticia de la rara habilidad y sutil ingenio que vuestra merced tiene, y, sobre todo, que es vuesa merced un gran poeta. -Poeta, bien podrá ser -respondió don Lorenzo-, pero grande, ni por pensamiento. Verdad es que yo soy algún tanto aficionado a la poesía y a leer los buenos poetas, pero no de manera que se me pueda dar el nombre de grande que mi padre dice. -No me parece mal esa humildad -respondió don Quijote-, porque no hay poeta que no sea arrogante y piense de sí que es el mayor poeta del mundo. -No hay regla sin excepción -respondió don Lorenzo-, y alguno habrá que lo sea y no lo piense. -Pocos -respondió don Quijote-; pero dígame vuesa merced: ¿qué versos son los que agora trae entre manos, que me ha dicho el señor su padre que le traen algo inquieto y pensativo? Y si es alguna glosa, a mí se me entiende algo de achaque de glosas, y holgaría saberlos; y si es que son de justa literaria, procure vuestra merced llevar el segundo premio, que el primero siempre se lleva el favor o la gran calidad de la persona, el segundo se le lleva la mera justicia, y el tercero viene a ser segundo, y el primero, a esta cuenta, será el tercero, al modo de las licencias que se dan en las universidades; pero, con todo esto, gran personaje es el nombre de primero. -Hasta ahora -dijo entre sí don Lorenzo-, no os podré yo juzgar por loco; vamos adelante. Y díjole: -Paréceme que vuesa merced ha cursado las escuelas: ¿qué ciencias ha oído? -La de la caballería andante -respondió don Quijote-, que es tan buena como la de la poesía, y aun dos deditos más. -No sé qué ciencia sea ésa -replicó don Lorenzo-, y hasta ahora no ha llegado a mi noticia. -Es una ciencia -replicó don Quijote- que encierra en sí todas o las más ciencias del mundo, a causa que el que la profesa ha de ser jurisperito, y saber las leyes de la justicia distributiva y comutativa, para dar a cada uno lo que es suyo y lo que le conviene; ha de ser teólogo, para saber dar razón de la cristiana ley que profesa, clara y distintamente, adondequiera que le fuere pedido; ha de ser médico y principalmente herbolario, para conocer en mitad de los despoblados y desiertos las yerbas que tienen virtud de sanar las heridas, que no ha de andar el caballero andante a cada triquete buscando quien se las cure; ha de ser astrólogo, para conocer por las estrellas cuántas horas son pasadas de la noche, y en qué parte y en qué clima del mundo se halla; ha de saber las matemáticas, porque a cada paso se le ofrecerá tener necesidad dellas; y, dejando aparte que ha de estar adornado de todas las virtudes teologales y cardinales, decendiendo a otras menudencias, digo que ha de saber nadar como dicen que nadaba el peje Nicolás o Nicolao; ha de saber herrar un caballo y aderezar la silla y el freno; y, volviendo a lo de arriba, ha de guardar la fe a Dios y a su dama; ha de ser casto en los pensamientos, honesto en las palabras, liberal en las obras, valiente en los hechos, sufrido en los trabajos, caritativo con los menesterosos, y, finalmente, mantenedor de la verdad, aunque le cueste la vida el defenderla. De todas estas grandes y mínimas partes se compone un buen caballero andante; porque vea vuesa merced, señor don Lorenzo, si es ciencia mocosa lo que aprende el caballero que la estudia y la profesa, y si se puede igualar a las más estiradas que en los ginasios y escuelas se enseñan. -Si eso es así -replicó don Lorenzo-, yo digo que se aventaja esa ciencia a todas. -¿Cómo si es así? -respondió don Quijote. Lo que yo quiero decir -dijo don Lorenzo- es que dudo que haya habido, ni que los hay ahora, caballeros andantes y adornados de virtudes tantas. -Muchas veces he dicho lo que vuelvo a decir ahora -respondió don Quijote-: que la mayor parte de la gente del mundo está de parecer de que no ha habido en él caballeros andantes; y, por parecerme a mí que si el cielo milagrosamente no les da a entender la verdad de que los hubo y de que los hay, cualquier trabajo que se tome ha de ser en vano, como muchas veces me lo ha mostrado la experiencia, no quiero detenerme agora en sacar a vuesa merced del error que con los muchos tiene; lo que pienso hacer es el rogar al cielo le saque dél, y le dé a entender cuán provechosos y cuán necesarios fueron al mundo los caballeros andantes en los pasados siglos, y cuán útiles fueran en el presente si se usaran; pero triunfan ahora, por pecados de las gentes, la pereza, la ociosidad, la gula y el regalo. -Escapado se nos ha nuestro huésped -dijo a esta sazón entre sí don Lorenzo-, pero, con todo eso, él es loco bizarro, y yo sería mentecato flojo si así no lo creyese. Aquí dieron fin a su plática, porque los llamaron a comer. Preguntó don Diego a su hijo qué había sacado en limpio del ingenio del huésped. A lo que él respondió: -No le sacarán del borrador de su locura cuantos médicos y buenos escribanos tiene el mundo: él es un entreverado loco, lleno de lúcidos intervalos. Fuéronse a comer, y la comida fue tal como don Diego había dicho en el camino que la solía dar a sus convidados: limpia, abundante y sabrosa; pero de lo que más se contentó don Quijote fue del maravilloso silencio que en toda la casa había, que semejaba un monasterio de cartujos. Levantados, pues, los manteles, y dadas gracias a Dios y agua a las manos, don Quijote pidió ahincadamente a don Lorenzo dijese los versos de la justa literaria; a lo que él respondió que, por no parecer de aquellos poetas que cuando les ruegan digan sus versos los niegan y cuando no se los piden los vomitan,... -...yo diré mi glosa, de la cual no espero premio alguno, que sólo por ejercitar el ingenio la he hecho. -Un amigo y discreto -respondió don Quijote- era de parecer que no se había de cansar nadie en glosar versos; y la razón, decía él, era que jamás la glosa podía llegar al texto, y que muchas o las más veces iba la glosa fuera de la intención y propósito de lo que pedía lo que se glosaba; y más, que las leyes de la glosa eran demasiadamente estrechas: que no sufrían interrogantes, ni dijo, ni diré, ni hacer nombres de verbos, ni mudar el sentido, con otras ataduras y estrechezas con que van atados los que glosan, como vuestra merced debe de saber. -Verdaderamente, señor don Quijote -dijo don Lorenzo-, que deseo coger a vuestra merced en un mal latín continuado, y no puedo, porque se me desliza de entre las manos como anguila. -No entiendo -respondió don Quijote- lo que vuestra merced dice ni quiere decir en eso del deslizarme. -Yo me daré a entender -respondió don Lorenzo-; y por ahora esté vuesa merced atento a los versos glosados y a la glosa, que dicen desta manera: ¡Si mi fue tornase a es, sin esperar más será, o viniese el tiempo ya de lo que será después...! Glosa Al fin, como todo pasa, se pasó el bien que me dio Fortuna, un tiempo no escasa, y nunca me le volvió, ni abundante, ni por tasa. Siglos ha ya que me vees, Fortuna, puesto a tus pies; vuélveme a ser venturoso, que será mi ser dichoso si mi fue tornase a es. No quiero otro gusto o gloria, otra palma o vencimiento, otro triunfo, otra vitoria, sino volver al contento que es pesar en mi memoria. Si tú me vuelves allá, Fortuna, templado está todo el rigor de mi fuego, y más si este bien es luego, sin esperar más será. Cosas imposibles pido, pues volver el tiempo a ser después que una vez ha sido, no hay en la tierra poder que a tanto se haya estendido. Corre el tiempo, vuela y va ligero, y no volverá, y erraría el que pidiese, o que el tiempo ya se fuese, o volviese el tiempo ya. Vivo en perpleja vida, ya esperando, ya temiendo: es muerte muy conocida, y es mucho mejor muriendo buscar al dolor salida. A mí me fuera interés acabar, mas no lo es, pues, con discurso mejor, me da la vida el temor de lo que será después. En acabando de decir su glosa don Lorenzo, se levantó en pie don Quijote, y, en voz levantada, que parecía grito, asiendo con su mano la derecha de don Lorenzo, dijo: -¡Viven los cielos donde más altos están, mancebo generoso, que sois el mejor poeta del orbe, y que merecéis estar laureado, no por Chipre ni por Gaeta, como dijo un poeta, que Dios perdone, sino por las academias de Atenas, si hoy vivieran, y por las que hoy viven de París, Bolonia y Salamanca! Plega al cielo que los jueces que os quitaren el premio primero, Febo los asaetee y las Musas jamás atraviesen los umbrales de sus casas. Decidme, señor, si sois servido, algunos versos mayores, que quiero tomar de todo en todo el pulso a vuestro admirable ingenio. ¿No es bueno que dicen que se holgó don Lorenzo de verse alabar de don Quijote, aunque le tenía por loco? ¡Oh fuerza de la adulación, a cuánto te estiendes, y cuán dilatados límites son los de tu juridición agradable! Esta verdad acreditó don Lorenzo, pues concedió con la demanda y deseo de don Quijote, diciéndole este soneto a la fábula o historia de Píramo y Tisbe: Soneto El muro rompe la doncella hermosa que de Píramo abrió el gallardo pecho: parte el Amor de Chipre, y va derecho a ver la quiebra estrecha y prodigiosa. Habla el silencio allí, porque no osa la voz entrar por tan estrecho estrecho; las almas sí, que amor suele de hecho facilitar la más difícil cosa. Salió el deseo de compás, y el paso de la imprudente virgen solicita por su gusto su muerte; ved qué historia: que a entrambos en un punto, ¡oh estraño caso!, los mata, los encubre y resucita una espada, un sepulcro, una memoria. -¡Bendito sea Dios! -dijo don Quijote habiendo oído el soneto a don Lorenzo-, que entre los infinitos poetas consumidos que hay, he visto un consumado poeta, como lo es vuesa merced, señor mío; que así me lo da a entender el artificio deste soneto. Cuatro días estuvo don Quijote regaladísimo en la casa de don Diego, al cabo de los cuales le pidió licencia para irse, diciéndole que le agradecía la merced y buen tratamiento que en su casa había recebido; pero que, por no parecer bien que los caballeros andantes se den muchas horas a ocio y al regalo, se quería ir a cumplir con su oficio, buscando las aventuras, de quien tenía noticia que aquella tierra abundaba, donde esperaba entretener el tiempo hasta que llegase el día de las justas de Zaragoza, que era el de su derecha derrota; y que primero había de entrar en la cueva de Montesinos, de quien tantas y tan admirables cosas en aquellos contornos se contaban, sabiendo e inquiriendo asimismo el nacimiento y verdaderos manantiales de las siete lagunas llamadas comúnmente de Ruidera. Don Diego y su hijo le alabaron su honrosa determinación, y le dijeron que tomase de su casa y de su hacienda todo lo que en grado le viniese, que le servirían con la voluntad posible; que a ello les obligaba el valor de su persona y la honrosa profesión suya. Llegóse, en fin, el día de su partida, tan alegre para don Quijote como triste y aciago para Sancho Panza, que se hallaba muy bien con la abundancia de la casa de don Diego, y rehusaba de volver a la hambre que se usa en las florestas, despoblados, y a la estrecheza de sus mal proveídas alforjas. Con todo esto, las llenó y colmó de lo más necesario que le pareció; y al despedirse dijo don Quijote a don Lorenzo: -No sé si he dicho a vuesa merced otra vez, y si lo he dicho lo vuelvo a decir, que cuando vuesa merced quisiere ahorrar caminos y trabajos para llegar a la inacesible cumbre del templo de la Fama, no tiene que hacer otra cosa sino dejar a una parte la senda de la poesía, algo estrecha, y tomar la estrechísima de la andante caballería, bastante para hacerle emperador en daca las pajas. Con estas razones acabó don Quijote de cerrar el proceso de su locura, y más con las que añadió, diciendo: -Sabe Dios si quisiera llevar conmigo al señor don Lorenzo, para enseñarle cómo se han de perdonar los sujetos, y supeditar y acocear los soberbios, virtudes anejas a la profesión que yo profeso; pero, pues no lo pide su poca edad, ni lo querrán consentir sus loables ejercicios, sólo me contento con advertirle a vuesa merced que, siendo poeta, podrá ser famoso si se guía más por el parecer ajeno que por el propio, porque no hay padre ni madre a quien sus hijos le parezcan feos, y en los que lo son del entendimiento corre más este engaño. De nuevo se admiraron padre y hijo de las entremetidas razones de don Quijote, ya discretas y ya disparatadas, y del tema y tesón que llevaba de acudir de todo en todo a la busca de sus desventuradas aventuras, que las tenía por fin y blanco de sus deseos. Reiteráronse los ofrecimientos y comedimientos, y, con la buena licencia de la señora del castillo, don Quijote y Sancho, sobre Rocinante y el rucio, se partieron. Capítulo XIX. Donde se cuenta la aventura del pastor enamorado, con otros en verdad graciosos sucesos Poco trecho se había alongado don Quijote del lugar de don Diego, cuando encontró con dos como clérigos o como estudiantes y con dos labradores que sobre cuatro bestias asnales venían caballeros. El uno de los estudiantes traía, como en portamanteo, en un lienzo de bocací verde envuelto, al parecer, un poco de grana blanca y dos pares de medias de cordellate; el otro no traía otra cosa que dos espadas negras de esgrima, nuevas, y con sus zapatillas. Los labradores traían otras cosas, que daban indicio y señal que venían de alguna villa grande, donde las habían comprado, y las llevaban a su aldea; y así estudiantes como labradores cayeron en la misma admiración en que caían todos aquellos que la vez primera veían a don Quijote, y morían por saber qué hombre fuese aquél tan fuera del uso de los otros hombres. Saludóles don Quijote, y, después de saber el camino que llevaban, que era el mesmo que él hacía, les ofreció su compañía, y les pidió detuviesen el paso, porque caminaban más sus pollinas que su caballo; y, para obligarlos, en breves razones les dijo quién era, y su oficio y profesión, que era de caballero andante que iba a buscar las aventuras por todas las partes del mundo. Díjoles que se llamaba de nombre propio don Quijote de la Mancha, y por el apelativo, el Caballero de los Leones. Todo esto para los labradores era hablarles en griego o en jerigonza, pero no para los estudiantes, que luego entendieron la flaqueza del celebro de don Quijote; pero, con todo eso, le miraban con admiración y con respecto, y uno dellos le dijo: -Si vuestra merced, señor caballero, no lleva camino determinado, como no le suelen llevar los que buscan las aventuras, vuesa merced se venga con nosotros: verá una de las mejores bodas y más ricas que hasta el día de hoy se habrán celebrado en la Mancha, ni en otras muchas leguas a la redonda. Preguntóle don Quijote si eran de algún príncipe, que así las ponderaba. -No son -respondió el estudiante- sino de un labrador y una labradora: él, el más rico de toda esta tierra; y ella, la más hermosa que han visto los hombres. El aparato con que se han de hacer es estraordinario y nuevo, porque se han de celebrar en un prado que está junto al pueblo de la novia, a quien por excelencia llaman Quiteria la hermosa, y el desposado se llama Camacho el rico; ella de edad de diez y ocho años, y él de veinte y dos; ambos para en uno, aunque algunos curiosos que tienen de memoria los linajes de todo el mundo quieren decir que el de la hermosa Quiteria se aventaja al de Camacho; pero ya no se mira en esto, que las riquezas son poderosas de soldar muchas quiebras. En efecto, el tal Camacho es liberal y hásele antojado de enramar y cubrir todo el prado por arriba, de tal suerte que el sol se ha de ver en trabajo si quiere entrar a visitar las yerbas verdes de que está cubierto el suelo. Tiene asimesmo maheridas danzas, así de espadas como de cascabel menudo, que hay en su pueblo quien los repique y sacuda por estremo; de zapateadores no digo nada, que es un juicio los que tiene muñidos; pero ninguna de las cosas referidas ni otras muchas que he dejado de referir ha de hacer más memorables estas bodas, sino las que imagino que hará en ellas el despechado Basilio. Es este Basilio un zagal vecino del mesmo lugar de Quiteria, el cual tenía su casa pared y medio de la de los padres de Quiteria, de donde tomó ocasión el amor de renovar al mundo los ya olvidados amores de Píramo y Tisbe, porque Basilio se enamoró de Quiteria desde sus tiernos y primeros años, y ella fue correspondiendo a su deseo con mil honestos favores, tanto, que se contaban por entretenimiento en el pueblo los amores de los dos niños Basilio y Quiteria. Fue creciendo la edad, y acordó el padre de Quiteria de estorbar a Basilio la ordinaria entrada que en su casa tenía; y, por quitarse de andar receloso y lleno de sospechas, ordenó de casar a su hija con el rico Camacho, no pareciéndole ser bien casarla con Basilio, que no tenía tantos bienes de fortuna como de naturaleza; pues si va a decir las verdades sin invidia, él es el más ágil mancebo que conocemos: gran tirador de barra, luchador estremado y gran jugador de pelota; corre como un gamo, salta más que una cabra y birla a los bolos como por encantamento; canta como una calandria, y toca una guitarra, que la hace hablar, y, sobre todo, juega una espada como el más pintado. -Por esa sola gracia -dijo a esta sazón don Quijote-, merecía ese mancebo no sólo casarse con la hermosa Quiteria, sino con la mesma reina Ginebra, si fuera hoy viva, a pesar de Lanzarote y de todos aquellos que estorbarlo quisieran. -¡A mi mujer con eso! -dijo Sancho Panza, que hasta entonces había ido callando y escuchando-, la cual no quiere sino que cada uno case con su igual, ateniéndose al refrán que dicen "cada oveja con su pareja". Lo que yo quisiera es que ese buen Basilio, que ya me le voy aficionando, se casara con esa señora Quiteria; que buen siglo hayan y buen poso, iba a decir al revés, los que estorban que se casen los que bien se quieren. -Si todos los que bien se quieren se hubiesen de casar -dijo don Quijote-, quitaríase la eleción y juridición a los padres de casar sus hijos con quien y cuando deben; y si a la voluntad de las hijas quedase escoger los maridos, tal habría que escogiese al criado de su padre, y tal al que vio pasar por la calle, a su parecer, bizarro y entonado, aunque fuese un desbaratado espadachín; que el amor y la afición con facilidad ciegan los ojos del entendimiento, tan necesarios para escoger estado, y el del matrimonio está muy a peligro de errarse, y es menester gran tiento y particular favor del cielo para acertarle. Quiere hacer uno un viaje largo, y si es prudente, antes de ponerse en camino busca alguna compañía segura y apacible con quien acompañarse; pues, ¿por qué no hará lo mesmo el que ha de caminar toda la vida, hasta el paradero de la muerte, y más si la compañía le ha de acompañar en la cama, en la mesa y en todas partes, como es la de la mujer con su marido? La de la propia mujer no es mercaduría que una vez comprada se vuelve, o se trueca o cambia, porque es accidente inseparable, que dura lo que dura la vida: es un lazo que si una vez le echáis al cuello, se vuelve en el nudo gordiano, que si no le corta la guadaña de la muerte, no hay desatarle. Muchas más cosas pudiera decir en esta materia, si no lo estorbara el deseo que tengo de saber si le queda más que decir al señor licenciado acerca de la historia de Basilio. A lo que respondió el estudiante bachiller, o licenciado, como le llamó don Quijote, que: -De todo no me queda más que decir sino que desde el punto que Basilio supo que la hermosa Quiteria se casaba con Camacho el rico, nunca más le han visto reír ni hablar razón concertada, y siempre anda pensativo y triste, hablando entre sí mismo, con que da ciertas y claras señales de que se le ha vuelto el juicio: come poco y duerme poco, y lo que come son frutas, y en lo que duerme, si duerme, es en el campo, sobre la dura tierra, como animal bruto; mira de cuando en cuando al cielo, y otras veces clava los ojos en la tierra, con tal embelesamiento, que no parece sino estatua vestida que el aire le mueve la ropa. En fin, él da tales muestras de tener apasionado el corazón, que tememos todos los que le conocemos que el dar el sí mañana la hermosa Quiteria ha de ser la sentencia de su muerte. -Dios lo hará mejor -dijo Sancho-; que Dios, que da la llaga, da la medicina; nadie sabe lo que está por venir: de aquí a mañana muchas horas hay, y en una, y aun en un momento, se cae la casa; yo he visto llover y hacer sol, todo a un mesmo punto; tal se acuesta sano la noche, que no se puede mover otro día. Y díganme, ¿por ventura habrá quien se alabe que tiene echado un clavo a la rodaja de la Fortuna? No, por cierto; y entre el sí y el no de la mujer no me atrevería yo a poner una punta de alfiler, porque no cabría. Denme a mí que Quiteria quiera de buen corazón y de buena voluntad a Basilio, que yo le daré a él un saco de buena ventura: que el amor, según yo he oído decir, mira con unos antojos que hacen parecer oro al cobre, a la pobreza riqueza, y a las lagañas perlas. -¿Adónde vas a parar, Sancho, que seas maldito? -dijo don Quijote-; que cuando comienzas a ensartar refranes y cuentos, no te puede esperar sino el mesmo Judas, que te lleve. Dime, animal, ¿qué sabes tú de clavos, ni de rodajas, ni de otra cosa ninguna? -¡Oh! Pues si no me entienden -respondió Sancho-, no es maravilla que mis sentencias sean tenidas por disparates. Pero no importa: yo me entiendo, y sé que no he dicho muchas necedades en lo que he dicho; sino que vuesa merced, señor mío, siempre es friscal de mis dichos, y aun de mis hechos. -Fiscal has de decir -dijo don Quijote-, que no friscal, prevaricador del buen lenguaje, que Dios te confunda. -No se apunte vuestra merced conmigo -respondió Sancho-, pues sabe que no me he criado en la Corte, ni he estudiado en Salamanca, para saber si añado o quito alguna letra a mis vocablos. Sí, que, ¡válgame Dios!, no hay para qué obligar al sayagués a que hable como el toledano, y toledanos puede haber que no las corten en el aire en esto del hablar polido. -Así es -dijo el licenciado-, porque no pueden hablar tan bien los que se crían en las Tenerías y en Zocodover como los que se pasean casi todo el día por el claustro de la Iglesia Mayor, y todos son toledanos. El lenguaje puro, el propio, el elegante y claro, está en los discretos cortesanos, aunque hayan nacido en Majalahonda: dije discretos porque hay muchos que no lo son, y la discreción es la gramática del buen lenguaje, que se acompaña con el uso. Yo, señores, por mis pecados, he estudiado Cánones en Salamanca, y pícome algún tanto de decir mi razón con palabras claras, llanas y significantes. -Si no os picáredes más de saber más menear las negras que lleváis que la lengua -dijo el otro estudiante-, vos llevárades el primero en licencias, como llevastes cola. -Mirad, bachiller -respondió el licenciado-: vos estáis en la más errada opinión del mundo acerca de la destreza de la espada, teniéndola por vana. -Para mí no es opinión, sino verdad asentada -replicó Corchuelo-; y si queréis que os lo muestre con la experiencia, espadas traéis, comodidad hay, yo pulsos y fuerzas tengo, que acompañadas de mi ánimo, que no es poco, os harán confesar que yo no me engaño. Apeaos, y usad de vuestro compás de pies, de vuestros círculos y vuestros ángulos y ciencia; que yo espero de haceros ver estrellas a mediodía con mi destreza moderna y zafia, en quien espero, después de Dios, que está por nacer hombre que me haga volver las espaldas, y que no le hay en el mundo a quien yo no le haga perder tierra. -En eso de volver, o no, las espaldas no me meto -replico el diestro-; aunque podría ser que en la parte donde la vez primera clavásedes el pie, allí os abriesen la sepultura: quiero decir que allí quedásedes muerto por la despreciada destreza. -Ahora se verá -respondió Corchuelo. Y, apeándose con gran presteza de su jumento, tiró con furia de una de las espadas que llevaba el licenciado en el suyo. -No ha de ser así -dijo a este instante don Quijote-, que yo quiero ser el maestro desta esgrima, y el juez desta muchas veces no averiguada cuestión. Y, apeándose de Rocinante y asiendo de su lanza, se puso en la mitad del camino, a tiempo que ya el licenciado, con gentil donaire de cuerpo y compás de pies, se iba contra Corchuelo, que contra él se vino, lanzando, como decirse suele, fuego por los ojos. Los otros dos labradores del acompañamiento, sin apearse de sus pollinas, sirvieron de aspetatores en la mortal tragedia. Las cuchilladas, estocadas, altibajos, reveses y mandobles que tiraba Corchuelo eran sin número, más espesas que hígado y más menudas que granizo. Arremetía como un león irritado, pero salíale al encuentro un tapaboca de la zapatilla de la espada del licenciado, que en mitad de su furia le detenía, y se la hacía besar como si fuera reliquia, aunque no con tanta devoción como las reliquias deben y suelen besarse. Finalmente, el licenciado le contó a estocadas todos los botones de una media sotanilla que traía vestida, haciéndole tiras los faldamentos, como colas de pulpo; derribóle el sombrero dos veces, y cansóle de manera que de despecho, cólera y rabia asió la espada por la empuñadura, y arrojóla por el aire con tanta fuerza, que uno de los labradores asistentes, que era escribano, que fue por ella, dio después por testimonio que la alongó de sí casi tres cuartos de legua; el cual testimonio sirve y ha servido para que se conozca y vea con toda verdad cómo la fuerza es vencida del arte. Sentóse cansado Corchuelo, y llegándose a él Sancho, le dijo: -Mía fe, señor bachiller, si vuesa merced toma mi consejo, de aquí adelante no ha de desafiar a nadie a esgrimir, sino a luchar o a tirar la barra, pues tiene edad y fuerzas para ello; que destos a quien llaman diestros he oído decir que meten una punta de una espada por el ojo de una aguja. -Yo me contento -respondió Corchuelo- de haber caído de mi burra, y de que me haya mostrado la experiencia la verdad, de quien tan lejos estaba. Y, levantándose, abrazó al licenciado, y quedaron más amigos que de antes, y no queriendo esperar al escribano, que había ido por la espada, por parecerle que tardaría mucho; y así, determinaron seguir, por llegar temprano a la aldea de Quiteria, de donde todos eran. En lo que faltaba del camino, les fue contando el licenciado las excelencias de la espada, con tantas razones demostrativas y con tantas figuras y demostraciones matemáticas, que todos quedaron enterados de la bondad de la ciencia, y Corchuelo reducido de su pertinacia. Era anochecido, pero antes que llegasen les pareció a todos que estaba delante del pueblo un cielo lleno de inumerables y resplandecientes estrellas. Oyeron, asimismo, confusos y suaves sonidos de diversos instrumentos, como de flautas, tamborinos, salterios, albogues, panderos y sonajas; y cuando llegaron cerca vieron que los árboles de una enramada, que a mano habían puesto a la entrada del pueblo, estaban todos llenos de luminarias, a quien no ofendía el viento, que entonces no soplaba sino tan manso que no tenía fuerza para mover las hojas de los árboles. Los músicos eran los regocijadores de la boda, que en diversas cuadrillas por aquel agradable sitio andaban, unos bailando, y otros cantando, y otros tocando la diversidad de los referidos instrumentos. En efecto, no parecía sino que por todo aquel prado andaba corriendo la alegría y saltando el contento. Otros muchos andaban ocupados en levantar andamios, de donde con comodidad pudiesen ver otro día las representaciones y danzas que se habían de hacer en aquel lugar dedicado para solenizar las bodas del rico Camacho y las exequias de Basilio. No quiso entrar en el lugar don Quijote, aunque se lo pidieron así el labrador como el bachiller; pero él dio por disculpa, bastantísima a su parecer, ser costumbre de los caballeros andantes dormir por los campos y florestas antes que en los poblados, aunque fuese debajo de dorados techos; y con esto, se desvió un poco del camino, bien contra la voluntad de Sancho, viniéndosele a la memoria el buen alojamiento que había tenido en el castillo o casa de don Diego. Capítulo XX. Donde se cuentan las bodas de Camacho el rico, con el suceso de Basilio el pobre Apenas la blanca aurora había dado lugar a que el luciente Febo, con el ardor de sus calientes rayos, las líquidas perlas de sus cabellos de oro enjugase, cuando don Quijote, sacudiendo la pereza de sus miembros, se puso en pie y llamó a su escudero Sancho, que aún todavía roncaba; lo cual visto por don Quijote, antes que le despertase, le dijo: -¡Oh tú, bienaventurado sobre cuantos viven sobre la haz de la tierra, pues sin tener invidia ni ser invidiado, duermes con sosegado espíritu, ni te persiguen encantadores, ni sobresaltan encantamentos! Duerme, digo otra vez, y lo diré otras ciento, sin que te tengan en contina vigilia celos de tu dama, ni te desvelen pensamientos de pagar deudas que debas, ni de lo que has de hacer para comer otro día tú y tu pequeña y angustiada familia. Ni la ambición te inquieta, ni la pompa vana del mundo te fatiga, pues los límites de tus deseos no se estienden a más que a pensar tu jumento; que el de tu persona sobre mis hombros le tienes puesto: contrapeso y carga que puso la naturaleza y la costumbre a los señores. Duerme el criado, y está velando el señor, pensando cómo le ha de sustentar, mejorar y hacer mercedes. La congoja de ver que el cielo se hace de bronce sin acudir a la tierra con el conveniente rocío no aflige al criado, sino al señor, que ha de sustentar en la esterilidad y hambre al que le sirvió en la fertilidad y abundancia. A todo esto no respondió Sancho, porque dormía, ni despertara tan presto si don Quijote con el cuento de la lanza no le hiciere volver en sí. Despertó, en fin, soñoliento y perezoso, y, volviendo el rostro a todas partes, dijo: -De la parte desta enramada, si no me engaño, sale un tufo y olor harto más de torreznos asados que de juncos y tomillos: bodas que por tales olores comienzan, para mi santiguada que deben de ser abundantes y generosas. -Acaba, glotón -dijo don Quijote-; ven, iremos a ver estos desposorios, por ver lo que hace el desdeñado Basilio. -Mas que haga lo que quisiere -respondió Sancho-: no fuera él pobre y casárase con Quiteria. ¿No hay más sino tener un cuarto y querer alzarse por las nubes? A la fe, señor, yo soy de parecer que el pobre debe de contentarse con lo que hallare, y no pedir cotufas en el golfo. Yo apostaré un brazo que puede Camacho envolver en reales a Basilio; y si esto es así, como debe de ser, bien boba fuera Quiteria en desechar las galas y las joyas que le debe de haber dado, y le puede dar Camacho, por escoger el tirar de la barra y el jugar de la negra de Basilio. Sobre un buen tiro de barra o sobre una gentil treta de espada no dan un cuartillo de vino en la taberna. Habilidades y gracias que no son vendibles, mas que las tenga el conde Dirlos; pero, cuando las tales gracias caen sobre quien tiene buen dinero, tal sea mi vida como ellas parecen. Sobre un buen cimiento se puede levantar un buen edificio, y el mejor cimiento y zanja del mundo es el dinero. -Por quien Dios es, Sancho -dijo a esta sazón don Quijote-, que concluyas con tu arenga; que tengo para mí que si te dejasen seguir en las que a cada paso comienzas, no te quedaría tiempo para comer ni para dormir, que todo le gastarías en hablar. -Si vuestra merced tuviera buena memoria -replicó Sancho-, debiérase acordar de los capítulos de nuestro concierto antes que esta última vez saliésemos de casa: uno dellos fue que me había de dejar hablar todo aquello que quisiese, con que no fuese contra el prójimo ni contra la autoridad de vuesa merced; y hasta agora me parece que no he contravenido contra el tal capítulo. -Yo no me acuerdo, Sancho -respondió don Quijote-, del tal capítulo; y, puesto que sea así, quiero que calles y vengas, que ya los instrumentos que anoche oímos vuelven a alegrar los valles, y sin duda los desposorios se celebrarán en el frescor de la mañana, y no en el calor de la tarde. Hizo Sancho lo que su señor le mandaba, y, poniendo la silla a Rocinante y la albarda al rucio, subieron los dos, y paso ante paso se fueron entrando por la enramada. Lo primero que se le ofreció a la vista de Sancho fue, espetado en un asador de un olmo entero, un entero novillo; y en el fuego donde se había de asar ardía un mediano monte de leña, y seis ollas que alrededor de la hoguera estaban no se habían hecho en la común turquesa de las demás ollas, porque eran seis medias tinajas, que cada una cabía un rastro de carne: así embebían y encerraban en sí carneros enteros, sin echarse de ver, como si fueran palominos; las liebres ya sin pellejo y las gallinas sin pluma que estaban colgadas por los árboles para sepultarlas en las ollas no tenían número; los pájaros y caza de diversos géneros eran infinitos, colgados de los árboles para que el aire los enfriase. Contó Sancho más de sesenta zaques de más de a dos arrobas cada uno, y todos llenos, según después pareció, de generosos vinos; así había rimeros de pan blanquísimo, como los suele haber de montones de trigo en las eras; los quesos, puestos como ladrillos enrejados, formaban una muralla, y dos calderas de aceite, mayores que las de un tinte, servían de freír cosas de masa, que con dos valientes palas las sacaban fritas y las zabullían en otra caldera de preparada miel que allí junto estaba. Los cocineros y cocineras pasaban de cincuenta: todos limpios, todos diligentes y todos contentos. En el dilatado vientre del novillo estaban doce tiernos y pequeños lechones, que, cosidos por encima, servían de darle sabor y enternecerle. Las especias de diversas suertes no parecía haberlas comprado por libras, sino por arrobas, y todas estaban de manifiesto en una grande arca. Finalmente, el aparato de la boda era rústico, pero tan abundante que podía sustentar a un ejército. Todo lo miraba Sancho Panza, y todo lo contemplaba, y de todo se aficionaba: primero le cautivaron y rindieron el deseo las ollas, de quién él tomara de bonísima gana un mediano puchero; luego le aficionaron la voluntad los zaques; y, últimamente, las frutas de sartén, si es que se podían llamar sartenes las tan orondas calderas; y así, sin poderlo sufrir ni ser en su mano hacer otra cosa, se llegó a uno de los solícitos cocineros, y, con corteses y hambrientas razones, le rogó le dejase mojar un mendrugo de pan en una de aquellas ollas. A lo que el cocinero respondió: -Hermano, este día no es de aquellos sobre quien tiene juridición la hambre, merced al rico Camacho. Apeaos y mirad si hay por ahí un cucharón, y espumad una gallina o dos, y buen provecho os hagan. -No veo ninguno -respondió Sancho. -Esperad -dijo el cocinero-. ¡Pecador de mí, y qué melindroso y para poco debéis de ser! Y, diciendo esto, asió de un caldero, y, encajándole en una de las medias tinajas, sacó en él tres gallinas y dos gansos, y dijo a Sancho: -Comed, amigo, y desayunaos con esta espuma, en tanto que se llega la hora del yantar. -No tengo en qué echarla -respondió Sancho. -Pues llevaos -dijo el cocinero- la cuchara y todo, que la riqueza y el contento de Camacho todo lo suple. En tanto, pues, que esto pasaba Sancho, estaba don Quijote mirando cómo, por una parte de la enramada, entraban hasta doce labradores sobre doce hermosísimas yeguas, con ricos y vistosos jaeces de campo y con muchos cascabeles en los petrales, y todos vestidos de regocijo y fiestas; los cuales, en concertado tropel, corrieron no una, sino muchas carreras por el prado, con regocijada algazara y grita, diciendo: -¡Vivan Camacho y Quiteria: él tan rico como ella hermosa, y ella la más hermosa del mundo! Oyendo lo cual don Quijote, dijo entre sí: -Bien parece que éstos no han visto a mi Dulcinea del Toboso, que si la hubieran visto, ellos se fueran a la mano en las alabanzas desta su Quiteria. De allí a poco comenzaron a entrar por diversas partes de la enramada muchas y diferentes danzas, entre las cuales venía una de espadas, de hasta veinte y cuatro zagales de gallardo parecer y brío, todos vestidos de delgado y blanquísimo lienzo, con sus paños de tocar, labrados de varias colores de fina seda; y al que los guiaba, que era un ligero mancebo, preguntó uno de los de las yeguas si se había herido alguno de los danzantes. -Por ahora, bendito sea Dios, no se ha herido nadie: todos vamos sanos. Y luego comenzó a enredarse con los demás compañeros, con tantas vueltas y con tanta destreza que, aunque don Quijote estaba hecho a ver semejantes danzas, ninguna le había parecido tan bien como aquélla. También le pareció bien otra que entró de doncellas hermosísimas, tan mozas que, al parecer, ninguna bajaba de catorce ni llegaba a diez y ocho años, vestidas todas de palmilla verde, los cabellos parte tranzados y parte sueltos, pero todos tan rubios, que con los del sol podían tener competencia, sobre los cuales traían guirnaldas de jazmines, rosas, amaranto y madreselva compuestas. Guiábalas un venerable viejo y una anciana matrona, pero más ligeros y sueltos que sus años prometían. Hacíales el son una gaita zamorana, y ellas, llevando en los rostros y en los ojos a la honestidad y en los pies a la ligereza, se mostraban las mejores bailadoras del mundo. Tras ésta entró otra danza de artificio y de las que llaman habladas. Era de ocho ninfas, repartidas en dos hileras: de la una hilera era guía el dios Cupido, y de la otra, el Interés; aquél, adornado de alas, arco, aljaba y saetas; éste, vestido de ricas y diversas colores de oro y seda. Las ninfas que al Amor seguían traían a las espaldas, en pargamino blanco y letras grandes, escritos sus nombres: poesía era el título de la primera, el de la segunda discreción, el de la tercera buen linaje, el de la cuarta valentía; del modo mesmo venían señaladas las que al Interés seguían: decía liberalidad el título de la primera, dádiva el de la segunda, tesoro el de la tercera y el de la cuarta posesión pacífica. Delante de todos venía un castillo de madera, a quien tiraban cuatro salvajes, todos vestidos de yedra y de cáñamo teñido de verde, tan al natural, que por poco espantaran a Sancho. En la frontera del castillo y en todas cuatro partes de sus cuadros traía escrito: castillo del buen recato. Hacíanles el son cuatro diestros tañedores de tamboril y flauta. Comenzaba la danza Cupido, y, habiendo hecho dos mudanzas, alzaba los ojos y flechaba el arco contra una doncella que se ponía entre las almenas del castillo, a la cual desta suerte dijo: -Yo soy el dios poderoso en el aire y en la tierra y en el ancho mar undoso, y en cuanto el abismo encierra en su báratro espantoso. Nunca conocí qué es miedo; todo cuanto quiero puedo, aunque quiera lo imposible, y en todo lo que es posible mando, quito, pongo y vedo. Acabó la copla, disparó una flecha por lo alto del castillo y retiróse a su puesto. Salió luego el Interés, y hizo otras dos mudanzas; callaron los tamborinos, y él dijo: -Soy quien puede más que Amor, y es Amor el que me guía; soy de la estirpe mejor que el cielo en la tierra cría, más conocida y mayor. Soy el Interés, en quien pocos suelen obrar bien, y obrar sin mí es gran milagro; y cual soy te me consagro, por siempre jamás, amén. Retiróse el Interés, y hízose adelante la Poesía; la cual, después de haber hecho sus mudanzas como los demás, puestos los ojos en la doncella del castillo, dijo: -En dulcísimos conceptos, la dulcísima Poesía, altos, graves y discretos, señora, el alma te envía envuelta entre mil sonetos. Si acaso no te importuna mi porfía, tu fortuna, de otras muchas invidiada, será por mí levantada sobre el cerco de la luna. Desvióse la Poesía, y de la parte del Interés salió la Liberalidad, y, después de hechas sus mudanzas, dijo: -Llaman Liberalidad al dar que el estremo huye de la prodigalidad, y del contrario, que arguye tibia y floja voluntad. Mas yo, por te engrandecer, de hoy más, pródiga he de ser; que, aunque es vicio, es vicio honrado y de pecho enamorado, que en el dar se echa de ver. Deste modo salieron y se retiraron todas las dos figuras de las dos escuadras, y cada uno hizo sus mudanzas y dijo sus versos, algunos elegantes y algunos ridículos, y sólo tomó de memoria don Quijote -que la tenía grande- los ya referidos; y luego se mezclaron todos, haciendo y deshaciendo lazos con gentil donaire y desenvoltura; y cuando pasaba el Amor por delante del castillo, disparaba por alto sus flechas, pero el Interés quebraba en él alcancías doradas. Finalmente, después de haber bailado un buen espacio, el Interés sacó un bolsón, que le formaba el pellejo de un gran gato romano, que parecía estar lleno de dineros, y, arrojándole al castillo, con el golpe se desencajaron las tablas y se cayeron, dejando a la doncella descubierta y sin defensa alguna. Llegó el Interés con las figuras de su valía, y, echándola una gran cadena de oro al cuello, mostraron prenderla, rendirla y cautivarla; lo cual visto por el Amor y sus valedores, hicieron ademán de quitársela; y todas las demostraciones que hacían eran al son de los tamborinos, bailando y danzando concertadamente. Pusiéronlos en paz los salvajes, los cuales con mucha presteza volvieron a armar y a encajar las tablas del castillo, y la doncella se encerró en él como de nuevo, y con esto se acabó la danza con gran contento de los que la miraban. Preguntó don Quijote a una de las ninfas que quién la había compuesto y ordenado. Respondióle que un beneficiado de aquel pueblo, que tenía gentil caletre para semejantes invenciones. -Yo apostaré -dijo don Quijote- que debe de ser más amigo de Camacho que de Basilio el tal bachiller o beneficiado, y que debe de tener más de satírico que de vísperas: ¡bien ha encajado en la danza las habilidades de Basilio y las riquezas de Camacho! Sancho Panza, que lo escuchaba todo, dijo: -El rey es mi gallo: a Camacho me atengo. -En fin -dijo don Quijote-, bien se parece, Sancho, que eres villano y de aquéllos que dicen: "¡Viva quien vence!" -No sé de los que soy -respondió Sancho-, pero bien sé que nunca de ollas de Basilio sacaré yo tan elegante espuma como es esta que he sacado de las de Camacho. Y enseñóle el caldero lleno de gansos y de gallinas, y, asiendo de una, comenzó a comer con mucho donaire y gana, y dijo: -¡A la barba de las habilidades de Basilio!, que tanto vales cuanto tienes, y tanto tienes cuanto vales. Dos linajes solos hay en el mundo, como decía una agüela mía, que son el tener y el no tener, aunque ella al del tener se atenía; y el día de hoy, mi señor don Quijote, antes se toma el pulso al haber que al saber: un asno cubierto de oro parece mejor que un caballo enalbardado. Así que vuelvo a decir que a Camacho me atengo, de cuyas ollas son abundantes espumas gansos y gallinas, liebres y conejos; y de las de Basilio serán, si viene a mano, y aunque no venga sino al pie, aguachirle. -¿Has acabado tu arenga, Sancho? -dijo don Quijote. -Habréla acabado -respondió Sancho-, porque veo que vuestra merced recibe pesadumbre con ella; que si esto no se pusiera de por medio, obra había cortada para tres días. -Plega a Dios, Sancho -replicó don Quijote-, que yo te vea mudo antes que me muera. -Al paso que llevamos -respondió Sancho-, antes que vuestra merced se muera estaré yo mascando barro, y entonces podrá ser que esté tan mudo que no hable palabra hasta la fin del mundo, o, por lo menos, hasta el día del Juicio. -Aunque eso así suceda, ¡oh Sancho! -respondió don Quijote-, nunca llegará tu silencio a do ha llegado lo que has hablado, hablas y tienes de hablar en tu vida; y más, que está muy puesto en razón natural que primero llegue el día de mi muerte que el de la tuya; y así, jamás pienso verte mudo, ni aun cuando estés bebiendo o durmiendo, que es lo que puedo encarecer. -A buena fe, señor -respondió Sancho-, que no hay que fiar en la descarnada, digo, en la muerte, la cual también come cordero como carnero; y a nuestro cura he oído decir que con igual pie pisaba las altas torres de los reyes como las humildes chozas de los pobres. Tiene esta señora más de poder que de melindre: no es nada asquerosa, de todo come y a todo hace, y de toda suerte de gentes, edades y preeminencias hinche sus alforjas. No es segador que duerme las siestas, que a todas horas siega, y corta así la seca como la verde yerba; y no parece que masca, sino que engulle y traga cuanto se le pone delante, porque tiene hambre canina, que nunca se harta; y, aunque no tiene barriga, da a entender que está hidrópica y sedienta de beber solas las vidas de cuantos viven, como quien se bebe un jarro de agua fría. -No más, Sancho -dijo a este punto don Quijote-. Tente en buenas, y no te dejes caer; que en verdad que lo que has dicho de la muerte por tus rústicos términos es lo que pudiera decir un buen predicador. Dígote, Sancho que si como tienes buen natural y discreción, pudieras tomar un púlpito en la mano y irte por ese mundo predicando lindezas... -Bien predica quien bien vive -respondió Sancho-, y yo no sé otras tologías. -Ni las has menester -dijo don Quijote-; pero yo no acabo de entender ni alcanzar cómo, siendo el principio de la sabiduría el temor de Dios, tú, que temes más a un lagarto que a Él, sabes tanto. -Juzgue vuesa merced, señor, de sus caballerías -respondió Sancho-, y no se meta en juzgar de los temores o valentías ajenas, que tan gentil temeroso soy yo de Dios como cada hijo de vecino; y déjeme vuestra merced despabilar esta espuma, que lo demás todas son palabras ociosas, de que nos han de pedir cuenta en la otra vida. Y, diciendo esto, comenzó de nuevo a dar asalto a su caldero, con tan buenos alientos que despertó los de don Quijote, y sin duda le ayudara, si no lo impidiera lo que es fuerza se diga adelante. Capítulo XXI. Donde se prosiguen las bodas de Camacho, con otros gustosos sucesos Cuando estaban don Quijote y Sancho en las razones referidas en el capítulo antecedente, se oyeron grandes voces y gran ruido, y dábanlas y causábanle los de las yeguas, que con larga carrera y grita iban a recebir a los novios, que, rodeados de mil géneros de instrumentos y de invenciones, venían acompañados del cura, y de la parentela de entrambos, y de toda la gente más lucida de los lugares circunvecinos, todos vestidos de fiesta. Y como Sancho vio a la novia, dijo: -A buena fe que no viene vestida de labradora, sino de garrida palaciega. ¡Pardiez, que según diviso, que las patenas que había de traer son ricos corales, y la palmilla verde de Cuenca es terciopelo de treinta pelos! ¡Y montas que la guarnición es de tiras de lienzo, blanca!, ¡voto a mí que es de raso!; pues, ¡tomadme las manos, adornadas con sortijas de azabache!: no medre yo si no son anillos de oro, y muy de oro, y empedrados con pelras blancas como una cuajada, que cada una debe de valer un ojo de la cara. ¡Oh hideputa, y qué cabellos; que, si no son postizos, no los he visto mas luengos ni más rubios en toda mi vida! ¡No, sino ponedla tacha en el brío y en el talle, y no la comparéis a una palma que se mueve cargada de racimos de dátiles, que lo mesmo parecen los dijes que trae pendientes de los cabellos y de la garganta! Juro en mi ánima que ella es una chapada moza, y que puede pasar por los bancos de Flandes. Rióse don Quijote de las rústicas alabanzas de Sancho Panza; parecióle que, fuera de su señora Dulcinea del Toboso, no había visto mujer más hermosa jamás. Venía la hermosa Quiteria algo descolorida, y debía de ser de la mala noche que siempre pasan las novias en componerse para el día venidero de sus bodas. Ãbanse acercando a un teatro que a un lado del prado estaba, adornado de alfombras y ramos, adonde se habían de hacer los desposorios, y de donde habían de mirar las danzas y las invenciones; y, a la sazón que llegaban al puesto, oyeron a sus espaldas grandes voces, y una que decía: -Esperaos un poco, gente tan inconsiderada como presurosa. A cuyas voces y palabras todos volvieron la cabeza, y vieron que las daba un hombre vestido, al parecer, de un sayo negro, jironado de carmesí a llamas. Venía coronado -como se vio luego- con una corona de funesto ciprés; en las manos traía un bastón grande. En llegando más cerca, fue conocido de todos por el gallardo Basilio, y todos estuvieron suspensos, esperando en qué habían de parar sus voces y sus palabras, temiendo algún mal suceso de su venida en sazón semejante. Llegó, en fin, cansado y sin aliento, y, puesto delante de los desposados, hincando el bastón en el suelo, que tenía el cuento de una punta de acero, mudada la color, puestos los ojos en Quiteria, con voz tremente y ronca, estas razones dijo: -Bien sabes, desconocida Quiteria, que conforme a la santa ley que profesamos, que viviendo yo, tú no puedes tomar esposo; y juntamente no ignoras que, por esperar yo que el tiempo y mi diligencia mejorasen los bienes de mi fortuna, no he querido dejar de guardar el decoro que a tu honra convenía; pero tú, echando a las espaldas todas las obligaciones que debes a mi buen deseo, quieres hacer señor de lo que es mío a otro, cuyas riquezas le sirven no sólo de buena fortuna, sino de bonísima ventura. Y para que la tenga colmada, y no como yo pienso que la merece, sino como se la quieren dar los cielos, yo, por mis manos, desharé el imposible o el inconveniente que puede estorbársela, quitándome a mí de por medio. ¡Viva, viva el rico Camacho con la ingrata Quiteria largos y felices siglos, y muera, muera el pobre Basilio, cuya pobreza cortó las alas de su dicha y le puso en la sepultura! Y, diciendo esto, asió del bastón que tenía hincado en el suelo, y, quedándose la mitad dél en la tierra, mostró que servía de vaina a un mediano estoque que en él se ocultaba; y, puesta la que se podía llamar empuñadura en el suelo, con ligero desenfado y determinado propósito se arrojó sobre él, y en un punto mostró la punta sangrienta a las espaldas, con la mitad del acerada cuchilla, quedando el triste bañado en su sangre y tendido en el suelo, de sus mismas armas traspasado. Acudieron luego sus amigos a favorecerle, condolidos de su miseria y lastimosa desgracia; y, dejando don Quijote a Rocinante, acudió a favorecerle y le tomó en sus brazos, y halló que aún no había espirado. Quisiéronle sacar el estoque, pero el cura, que estaba presente, fue de parecer que no se le sacasen antes de confesarle, porque el sacársele y el espirar sería todo a un tiempo. Pero, volviendo un poco en sí Basilio, con voz doliente y desmayada dijo: -Si quisieses, cruel Quiteria, darme en este último y forzoso trance la mano de esposa, aún pensaría que mi temeridad tendría desculpa, pues en ella alcancé el bien de ser tuyo. El cura, oyendo lo cual, le dijo que atendiese a la salud del alma antes que a los gustos del cuerpo, y que pidiese muy de veras a Dios perdón de sus pecados y de su desesperada determinación. A lo cual replicó Basilio que en ninguna manera se confesaría si primero Quiteria no le daba la mano de ser su esposa: que aquel contento le adobaría la voluntad y le daría aliento para confesarse. En oyendo don Quijote la petición del herido, en altas voces dijo que Basilio pedía una cosa muy justa y puesta en razón, y además, muy hacedera, y que el señor Camacho quedaría tan honrado recibiendo a la señora Quiteria viuda del valeroso Basilio como si la recibiera del lado de su padre: -Aquí no ha de haber más de un sí, que no tenga otro efecto que el pronunciarle, pues el tálamo de estas bodas ha de ser la sepultura. Todo lo oía Camacho, y todo le tenía suspenso y confuso, sin saber qué hacer ni qué decir; pero las voces de los amigos de Basilio fueron tantas, pidiéndole que consintiese que Quiteria le diese la mano de esposa, porque su alma no se perdiese, partiendo desesperado desta vida, que le movieron, y aun forzaron, a decir que si Quiteria quería dársela, que él se contentaba, pues todo era dilatar por un momento el cumplimiento de sus deseos. Luego acudieron todos a Quiteria, y unos con ruegos, y otros con lágrimas, y otros con eficaces razones, la persuadían que diese la mano al pobre Basilio; y ella, más dura que un mármol y más sesga que una estatua, mostraba que ni sabía ni podía, ni quería responder palabra; ni la respondiera si el cura no la dijera que se determinase presto en lo que había de hacer, porque tenía Basilio ya el alma en los dientes, y no daba lugar a esperar inresolutas determinaciones. Entonces la hermosa Quiteria, sin responder palabra alguna, turbada, al parecer triste y pesarosa, llegó donde Basilio estaba, ya los ojos vueltos, el aliento corto y apresurado, murmurando entre los dientes el nombre de Quiteria, dando muestras de morir como gentil, y no como cristiano. Llegó, en fin, Quiteria, y, puesta de rodillas, le pidió la mano por señas, y no por palabras. Desencajó los ojos Basilio, y, mirándola atentamente, le dijo: -¡Oh Quiteria, que has venido a ser piadosa a tiempo cuando tu piedad ha de servir de cuchillo que me acabe de quitar la vida, pues ya no tengo fuerzas para llevar la gloria que me das en escogerme por tuyo, ni para suspender el dolor que tan apriesa me va cubriendo los ojos con la espantosa sombra de la muerte! Lo que te suplico es, ¡oh fatal estrella mía!, que la mano que me pides y quieres darme no sea por cumplimiento, ni para engañarme de nuevo, sino que confieses y digas que, sin hacer fuerza a tu voluntad, me la entregas y me la das como a tu legítimo esposo; pues no es razón que en un trance como éste me engañes, ni uses de fingimientos con quien tantas verdades ha tratado contigo. Entre estas razones, se desmayaba, de modo que todos los presentes pensaban que cada desmayo se había de llevar el alma consigo. Quiteria, toda honesta y toda vergonzosa, asiendo con su derecha mano la de Basilio, le dijo: -Ninguna fuerza fuera bastante a torcer mi voluntad; y así, con la más libre que tengo te doy la mano de legítima esposa, y recibo la tuya, si es que me la das de tu libre albedrío, sin que la turbe ni contraste la calamidad en que tu discurso acelerado te ha puesto. -Sí doy -respondió Basilio-, no turbado ni confuso, sino con el claro entendimiento que el cielo quiso darme; y así, me doy y me entrego por tu esposo. -Y yo por tu esposa -respondió Quiteria-, ahora vivas largos años, ahora te lleven de mis brazos a la sepultura. -Para estar tan herido este mancebo -dijo a este punto Sancho Panza-, mucho habla; háganle que se deje de requiebros y que atienda a su alma, que, a mi parecer, más la tiene en la lengua que en los dientes. Estando, pues, asidos de las manos Basilio y Quiteria, el cura, tierno y lloroso, los echó la bendición y pidió al cielo diese buen poso al alma del nuevo desposado; el cual, así como recibió la bendición, con presta ligereza se levantó en pie, y con no vista desenvoltura se sacó el estoque, a quien servía de vaina su cuerpo. Quedaron todos los circunstantes admirados, y algunos dellos, más simples que curiosos, en altas voces, comenzaron a decir: -¡Milagro, milagro! Pero Basilio replicó: -¡No "milagro, milagro", sino industria, industria! El cura, desatentado y atónito, acudió con ambas manos a tentar la herida, y halló que la cuchilla había pasado, no por la carne y costillas de Basilio, sino por un cañón hueco de hierro que, lleno de sangre, en aquel lugar bien acomodado tenía; preparada la sangre, según después se supo, de modo que no se helase. Finalmente, el cura y Camacho, con todos los más circunstantes, se tuvieron por burlados y escarnidos. La esposa no dio muestras de pesarle de la burla; antes, oyendo decir que aquel casamiento, por haber sido engañoso, no había de ser valedero, dijo que ella le confirmaba de nuevo; de lo cual coligieron todos que de consentimiento y sabiduría de los dos se había trazado aquel caso, de lo que quedó Camacho y sus valedores tan corridos que remitieron su venganza a las manos, y, desenvainando muchas espadas, arremetieron a Basilio, en cuyo favor en un instante se desenvainaron casi otras tantas. Y, tomando la delantera a caballo don Quijote, con la lanza sobre el brazo y bien cubierto de su escudo, se hacía dar lugar de todos. Sancho, a quien jamás pluguieron ni solazaron semejantes fechurías, se acogió a las tinajas, donde había sacado su agradable espuma, pareciéndole aquel lugar como sagrado, que había de ser tenido en respeto. Don Quijote, a grandes voces, decía: -Teneos, señores, teneos, que no es razón toméis venganza de los agravios que el amor nos hace; y advertid que el amor y la guerra son una misma cosa, y así como en la guerra es cosa lícita y acostumbrada usar de ardides y estratagemas para vencer al enemigo, así en las contiendas y competencias amorosas se tienen por buenos los embustes y marañas que se hacen para conseguir el fin que se desea, como no sean en menoscabo y deshonra de la cosa amada. Quiteria era de Basilio, y Basilio de Quiteria, por justa y favorable disposición de los cielos. Camacho es rico, y podrá comprar su gusto cuando, donde y como quisiere. Basilio no tiene más desta oveja, y no se la ha de quitar alguno, por poderoso que sea; que a los dos que Dios junta no podrá separar el hombre; y el que lo intentare, primero ha de pasar por la punta desta lanza. Y, en esto, la blandió tan fuerte y tan diestramente, que puso pavor en todos los que no le conocían, y tan intensamente se fijó en la imaginación de Camacho el desdén de Quiteria, que se la borró de la memoria en un instante; y así, tuvieron lugar con él las persuasiones del cura, que era varón prudente y bien intencionado, con las cuales quedó Camacho y los de su parcialidad pacíficos y sosegados; en señal de lo cual volvieron las espadas a sus lugares, culpando más a la facilidad de Quiteria que a la industria de Basilio; haciendo discurso Camacho que si Quiteria quería bien a Basilio doncella, también le quisiera casada, y que debía de dar gracias al cielo, más por habérsela quitado que por habérsela dado. Consolado, pues, y pacífico Camacho y los de su mesnada, todos los de la de Basilio se sosegaron, y el rico Camacho, por mostrar que no sentía la burla, ni la estimaba en nada, quiso que las fiestas pasasen adelante como si realmente se desposara; pero no quisieron asistir a ellas Basilio ni su esposa ni secuaces; y así, se fueron a la aldea de Basilio, que también los pobres virtuosos y discretos tienen quien los siga, honre y ampare, como los ricos tienen quien los lisonjee y acompañe. Llevarónse consigo a don Quijote, estimándole por hombre de valor y de pelo en pecho. A sólo Sancho se le escureció el alma, por verse imposibilitado de aguardar la espléndida comida y fiestas de Camacho, que duraron hasta la noche; y así, asenderado y triste, siguió a su señor, que con la cuadrilla de Basilio iba, y así se dejó atrás las ollas de Egipto, aunque las llevaba en el alma, cuya ya casi consumida y acabada espuma, que en el caldero llevaba, le representaba la gloria y la abundancia del bien que perdía; y así, congojado y pensativo, aunque sin hambre, sin apearse del rucio, siguió las huellas de Rocinante. Capítulo XXII. Donde se da cuenta de la grande aventura de la cueva de Montesinos, que está en el corazón de la Mancha, a quien dio felice cima el valeroso don Quijote de la Mancha Grandes fueron y muchos los regalos que los desposados hicieron a don Quijote, obligados de las muestras que había dado defendiendo su causa, y al par de la valentía le graduaron la discreción, teniéndole por un Cid en las armas y por un Cicerón en la elocuencia. El buen Sancho se refociló tres días a costa de los novios, de los cuales se supo que no fue traza comunicada con la hermosa Quiteria el herirse fingidamente, sino industria de Basilio, esperando della el mesmo suceso que se había visto; bien es verdad que confesó que había dado parte de su pensamiento a algunos de sus amigos, para que al tiempo necesario favoreciesen su intención y abonasen su engaño. -No se pueden ni deben llamar engaños -dijo don Quijote- los que ponen la mira en virtuosos fines. Y que el de casarse los enamorados era el fin de más excelencia, advirtiendo que el mayor contrario que el amor tiene es la hambre y la continua necesidad, porque el amor es todo alegría, regocijo y contento, y más cuando el amante está en posesión de la cosa amada, contra quien son enemigos opuestos y declarados la necesidad y la pobreza; y que todo esto decía con intención de que se dejase el señor Basilio de ejercitar las habilidades que sabe, que, aunque le daban fama, no le daban dineros, y que atendiese a granjear hacienda por medios lícitos e industriosos, que nunca faltan a los prudentes y aplicados. -El pobre honrado, si es que puede ser honrado el pobre, tiene prenda en tener mujer hermosa, que, cuando se la quitan, le quitan la honra y se la matan. La mujer hermosa y honrada, cuyo marido es pobre, merece ser coronada con laureles y palmas de vencimiento y triunfo. La hermosura, por sí sola, atrae las voluntades de cuantos la miran y conocen, y como a señuelo gustoso se le abaten las águilas reales y los pájaros altaneros; pero si a la tal hermosura se le junta la necesidad y la estrecheza, también la embisten los cuervos, los milanos y las otras aves de rapiña; y la que está a tantos encuentros firme bien merece llamarse corona de su marido. Mirad, discreto Basilio -añadió don Quijote-: opinión fue de no sé qué sabio que no había en todo el mundo sino una sola mujer buena, y daba por consejo que cada uno pensase y creyese que aquella sola buena era la suya, y así viviría contento. Yo no soy casado, ni hasta agora me ha venido en pensamiento serlo; y, con todo esto, me atrevería a dar consejo al que me lo pidiese del modo que había de buscar la mujer con quien se quisiese casar. Lo primero, le aconsejaría que mirase más a la fama que a la hacienda, porque la buena mujer no alcanza la buena fama solamente con ser buena, sino con parecerlo; que mucho más dañan a las honras de las mujeres las desenvolturas y libertades públicas que las maldades secretas. Si traes buena mujer a tu casa, fácil cosa sería conservarla, y aun mejorarla, en aquella bondad; pero si la traes mala, en trabajo te pondrá el enmendarla: que no es muy hacedero pasar de un estremo a otro. Yo no digo que sea imposible, pero téngolo por dificultoso. Oía todo esto Sancho, y dijo entre sí: -Este mi amo, cuando yo hablo cosas de meollo y de sustancia suele decir que podría yo tomar un púlpito en las manos y irme por ese mundo adelante predicando lindezas; y yo digo dél que cuando comienza a enhilar sentencias y a dar consejos, no sólo puede tomar púlpito en las manos, sino dos en cada dedo, y andarse por esas plazas a ¿qué quieres boca? ¡Válate el diablo por caballero andante, que tantas cosas sabes! Yo pensaba en mi ánima que sólo podía saber aquello que tocaba a sus caballerías, pero no hay cosa donde no pique y deje de meter su cucharada. Murmuraba esto algo Sancho, y entreoyóle su señor, y preguntóle: -¿Qué murmuras, Sancho? -No digo nada, ni murmuro de nada -respondió Sancho-; sólo estaba diciendo entre mí que quisiera haber oído lo que vuesa merced aquí ha dicho antes que me casara, que quizá dijera yo agora: "El buey suelto bien se lame". -¿Tan mala es tu Teresa, Sancho? -dijo don Quijote. -No es muy mala -respondió Sancho-, pero no es muy buena; a lo menos, no es tan buena como yo quisiera. -Mal haces, Sancho -dijo don Quijote-, en decir mal de tu mujer, que, en efecto, es madre de tus hijos. -No nos debemos nada -respondió Sancho-, que también ella dice mal de mí cuando se le antoja, especialmente cuando está celosa, que entonces súfrala el mesmo Satanás. Finalmente, tres días estuvieron con los novios, donde fueron regalados y servidos como cuerpos de rey. Pidió don Quijote al diestro licenciado le diese una guía que le encaminase a la cueva de Montesinos, porque tenía gran deseo de entrar en ella y ver a ojos vistas si eran verdaderas las maravillas que de ella se decían por todos aquellos contornos. El licenciado le dijo que le daría a un primo suyo, famoso estudiante y muy aficionado a leer libros de caballerías, el cual con mucha voluntad le pondría a la boca de la mesma cueva, y le enseñaría las lagunas de Ruidera, famosas ansimismo en toda la Mancha, y aun en toda España; y díjole que llevaría con él gustoso entretenimiento, a causa que era mozo que sabía hacer libros para imprimir y para dirigirlos a príncipes. Finalmente, el primo vino con una pollina preñada, cuya albarda cubría un gayado tapete o arpillera. Ensilló Sancho a Rocinante y aderezó al rucio, proveyó sus alforjas, a las cuales acompañaron las del primo, asimismo bien proveídas, y, encomendándose a Dios y despediéndose de todos, se pusieron en camino, tomando la derrota de la famosa cueva de Montesinos. En el camino preguntó don Quijote al primo de qué género y calidad eran sus ejercicios, su profesión y estudios; a lo que él respondió que su profesión era ser humanista; sus ejercicios y estudios, componer libros para dar a la estampa, todos de gran provecho y no menos entretenimiento para la república; que el uno se intitulaba el de las libreas, donde pinta setecientas y tres libreas, con sus colores, motes y cifras, de donde podían sacar y tomar las que quisiesen en tiempo de fiestas y regocijos los caballeros cortesanos, sin andarlas mendigando de nadie, ni lambicando, como dicen, el cerbelo, por sacarlas conformes a sus deseos e intenciones. -Porque doy al celoso, al desdeñado, al olvidado y al ausente las que les convienen, que les vendrán más justas que pecadoras. Otro libro tengo también, a quien he de llamar Metamorfóseos, o Ovidio español, de invención nueva y rara; porque en él, imitando a Ovidio a lo burlesco, pinto quién fue la Giralda de Sevilla y el Ãngel de la Madalena, quién el Caño de Vecinguerra, de Córdoba, quiénes los Toros de Guisando, la Sierra Morena, las fuentes de Leganitos y Lavapiés, en Madrid, no olvidándome de la del Piojo, de la del Caño Dorado y de la Priora; y esto, con sus alegorías, metáforas y translaciones, de modo que alegran, suspenden y enseñan a un mismo punto. Otro libro tengo, que le llamo Suplemento a Virgilio Polidoro, que trata de la invención de las cosas, que es de grande erudición y estudio, a causa que las cosas que se dejó de decir Polidoro de gran sustancia, las averiguo yo, y las declaro por gentil estilo. Olvidósele a Virgilio de declararnos quién fue el primero que tuvo catarro en el mundo, y el primero que tomó las unciones para curarse del morbo gálico, y yo lo declaro al pie de la letra, y lo autorizo con más de veinte y cinco autores: porque vea vuesa merced si he trabajado bien y si ha de ser útil el tal libro a todo el mundo. Sancho, que había estado muy atento a la narración del primo, le dijo: -Dígame, señor, así Dios le dé buena manderecha en la impresión de sus libros: ¿sabríame decir, que sí sabrá, pues todo lo sabe, quién fue el primero que se rascó en la cabeza, que yo para mí tengo que debió de ser nuestro padre Adán? -Sí sería -respondió el primo-, porque Adán no hay duda sino que tuvo cabeza y cabellos; y, siendo esto así, y siendo el primer hombre del mundo, alguna vez se rascaría. -Así lo creo yo -respondió Sancho-; pero dígame ahora: ¿quién fue el primer volteador del mundo? -En verdad, hermano -respondió el primo-, que no me sabré determinar por ahora, hasta que lo estudie. Yo lo estudiaré, en volviendo adonde tengo mis libros, y yo os satisfaré cuando otra vez nos veamos, que no ha de ser ésta la postrera. -Pues mire, señor -replicó Sancho-, no tome trabajo en esto, que ahora he caído en la cuenta de lo que le he preguntado. Sepa que el primer volteador del mundo fue Lucifer, cuando le echaron o arrojaron del cielo, que vino volteando hasta los abismos. -Tienes razón, amigo -dijo el primo. Y dijo don Quijote: -Esa pregunta y respuesta no es tuya, Sancho: a alguno las has oído decir. -Calle, señor -replicó Sancho-, que a buena fe que si me doy a preguntar y a responder, que no acabe de aquí a mañana. Sí, que para preguntar necedades y responder disparates no he menester yo andar buscando ayuda de vecinos. -Más has dicho, Sancho, de lo que sabes -dijo don Quijote-; que hay algunos que se cansan en saber y averiguar cosas que, después de sabidas y averiguadas, no importan un ardite al entendimiento ni a la memoria. En estas y otras gustosas pláticas se les pasó aquel día, y a la noche se albergaron en una pequeña aldea, adonde el primo dijo a don Quijote que desde allí a la cueva de Montesinos no había más de dos leguas, y que si llevaba determinado de entrar en ella, era menester proverse de sogas, para atarse y descolgarse en su profundidad. Don Quijote dijo que, aunque llegase al abismo, había de ver dónde paraba; y así, compraron casi cien brazas de soga, y otro día, a las dos de la tarde, llegaron a la cueva, cuya boca es espaciosa y ancha, pero llena de cambroneras y cabrahígos, de zarzas y malezas, tan espesas y intricadas, que de todo en todo la ciegan y encubren. En viéndola, se apearon el primo, Sancho y don Quijote, al cual los dos le ataron luego fortísimamente con las sogas; y, en tanto que le fajaban y ceñían, le dijo Sancho: -Mire vuestra merced, señor mío, lo que hace: no se quiera sepultar en vida, ni se ponga adonde parezca frasco que le ponen a enfriar en algún pozo. Sí, que a vuestra merced no le toca ni atañe ser el escudriñador desta que debe de ser peor que mazmorra. -Ata y calla -respondió don Quijote-, que tal empresa como aquésta, Sancho amigo, para mí estaba guardada. Y entonces dijo la guía: -Suplico a vuesa merced, señor don Quijote, que mire bien y especule con cien ojos lo que hay allá dentro: quizá habrá cosas que las ponga yo en el libro de mis Transformaciones. -En manos está el pandero que le sabrá bien tañer -respondió Sancho Panza. Dicho esto y acabada la ligadura de don Quijote -que no fue sobre el arnés, sino sobre el jubón de armar-, dijo don Quijote: -Inadvertidos hemos andado en no habernos proveído de algún esquilón pequeño, que fuera atado junto a mí en esta mesma soga, con cuyo sonido se entendiera que todavía bajaba y estaba vivo; pero, pues ya no es posible, a la mano de Dios, que me guíe. Y luego se hincó de rodillas y hizo una oración en voz baja al cielo, pidiendo a Dios le ayudase y le diese buen suceso en aquella, al parecer, peligrosa y nueva aventura, y en voz alta dijo luego: -¡Oh señora de mis acciones y movimientos, clarísima y sin par Dulcinea del Toboso! Si es posible que lleguen a tus oídos las plegarias y rogaciones deste tu venturoso amante, por tu inaudita belleza te ruego las escuches, que no son otras que rogarte no me niegues tu favor y amparo, ahora que tanto le he menester. Yo voy a despeñarme, a empozarme y a hundirme en el abismo que aquí se me representa, sólo porque conozca el mundo que si tú me favoreces, no habrá imposible a quien yo no acometa y acabe. Y, en diciendo esto, se acercó a la sima; vio no ser posible descolgarse, ni hacer lugar a la entrada, si no era a fuerza de brazos, o a cuchilladas, y así, poniendo mano a la espada, comenzó a derribar y a cortar de aquellas malezas que a la boca de la cueva estaban, por cuyo ruido y estruendo salieron por ella una infinidad de grandísimos cuervos y grajos, tan espesos y con tanta priesa, que dieron con don Quijote en el suelo; y si él fuera tan agorero como católico cristiano, lo tuviera a mala señal y escusara de encerrarse en lugar semejante. Finalmente se levantó, y, viendo que no salían más cuervos ni otras aves noturnas, como fueron murciélagos, que asimismo entre los cuervos salieron, dándole soga el primo y Sancho, se dejó calar al fondo de la caverna espantosa; y, al entrar, echándole Sancho su bendición y haciendo sobre él mil cruces, dijo: -¡Dios te guíe y la Peña de Francia, junto con la Trinidad de Gaeta, flor, nata y espuma de los caballeros andantes! ¡Allá vas, valentón del mundo, corazón de acero, brazos de bronce! ¡Dios te guíe, otra vez, y te vuelva libre, sano y sin cautela a la luz desta vida, que dejas por enterrarte en esta escuridad que buscas! Casi las mismas plegarias y deprecaciones hizo el primo. Iba don Quijote dando voces que le diesen soga y más soga, y ellos se la daban poco a poco; y cuando las voces, que acanaladas por la cueva salían, dejaron de oírse, ya ellos tenían descolgadas las cien brazas de soga, y fueron de parecer de volver a subir a don Quijote, pues no le podían dar más cuerda. Con todo eso, se detuvieron como media hora, al cabo del cual espacio volvieron a recoger la soga con mucha facilidad y sin peso alguno, señal que les hizo imaginar que don Quijote se quedaba dentro; y, creyéndolo así, Sancho lloraba amargamente y tiraba con mucha priesa por desengañarse, pero, llegando, a su parecer, a poco más de las ochenta brazas, sintieron peso, de que en estremo se alegraron. Finalmente, a las diez vieron distintamente a don Quijote, a quien dio voces Sancho, diciéndole: -Sea vuestra merced muy bien vuelto, señor mío, que ya pensábamos que se quedaba allá para casta. Pero no respondía palabra don Quijote; y, sacándole del todo, vieron que traía cerrados los ojos, con muestras de estar dormido. Tendiéronle en el suelo y desliáronle, y con todo esto no despertaba; pero tanto le volvieron y revolvieron, sacudieron y menearon, que al cabo de un buen espacio volvió en sí, desperezándose, bien como si de algún grave y profundo sueño despertara; y, mirando a una y otra parte, como espantado, dijo: -Dios os lo perdone, amigos; que me habéis quitado de la más sabrosa y agradable vida y vista que ningún humano ha visto ni pasado. En efecto, ahora acabo de conocer que todos los contentos desta vida pasan como sombra y sueño, o se marchitan como la flor del campo. ¡Oh desdichado Montesinos! ¡Oh mal ferido Durandarte! ¡Oh sin ventura Belerma! ¡Oh lloroso Guadiana, y vosotras sin dicha ijas de Ruidera, que mostráis en vuestras aguas las que lloraron vuestros hermosos ojos! Escuchaban el primo y Sancho las palabras de don Quijote, que las decía como si con dolor inmenso las sacara de las entrañas. Suplicáronle les diese a entender lo que decía, y les dijese lo que en aquel infierno había visto. -¿Infierno le llamáis? -dijo don Quijote-; pues no le llaméis ansí, porque no lo merece, como luego veréis. Pidió que le diesen algo de comer, que traía grandísima hambre. Tendieron la arpillera del primo sobre la verde yerba, acudieron a la despensa de sus alforjas, y, sentados todos tres en buen amor y compaña, merendaron y cenaron, todo junto. Levantada la arpillera, dijo don Quijote de la Mancha: -No se levante nadie, y estadme, hijos, todos atentos. Capítulo XXIII. De las admirables cosas que el estremado don Quijote contó que había visto en la profunda cueva de Montesinos, cuya imposibilidad y grandeza hace que se tenga esta aventura por apócrifa Las cuatro de la tarde serían cuando el sol, entre nubes cubierto, con luz escasa y templados rayos, dio lugar a don Quijote para que, sin calor y pesadumbre, contase a sus dos clarísimos oyentes lo que en la cueva de Montesinos había visto. Y comenzó en el modo siguiente: -A obra de doce o catorce estados de la profundidad desta mazmorra, a la derecha mano, se hace una concavidad y espacio capaz de poder caber en ella un gran carro con sus mulas. Éntrale una pequeña luz por unos resquicios o agujeros, que lejos le responden, abiertos en la superficie de la tierra. Esta concavidad y espacio vi yo a tiempo cuando ya iba cansado y mohíno de verme, pendiente y colgado de la soga, caminar por aquella escura región abajo, sin llevar cierto ni determinado camino; y así, determiné entrarme en ella y descansar un poco. Di voces, pidiéndoos que no descolgásedes más soga hasta que yo os lo dijese, pero no debistes de oírme. Fui recogiendo la soga que enviábades, y, haciendo della una rosca o rimero, me senté sobre él, pensativo además, considerando lo que hacer debía para calar al fondo, no teniendo quién me sustentase; y, estando en este pensamiento y confusión, de repente y sin procurarlo, me salteó un sueño profundísimo; y, cuando menos lo pensaba, sin saber cómo ni cómo no, desperté dél y me hallé en la mitad del más bello, ameno y deleitoso prado que puede criar la naturaleza ni imaginar la más discreta imaginación humana. Despabilé los ojos, limpiémelos, y vi que no dormía, sino que realmente estaba despierto; con todo esto, me tenté la cabeza y los pechos, por certificarme si era yo mismo el que allí estaba, o alguna fantasma vana y contrahecha; pero el tacto, el sentimiento, los discursos concertados que entre mí hacía, me certificaron que yo era allí entonces el que soy aquí ahora. Ofrecióseme luego a la vista un real y suntuoso palacio o alcázar, cuyos muros y paredes parecían de transparente y claro cristal fabricados; del cual abriéndose dos grandes puertas, vi que por ellas salía y hacía mí se venía un venerable anciano, vestido con un capuz de bayeta morada, que por el suelo le arrastraba: ceñíale los hombros y los pechos una beca de colegial, de raso verde; cubríale la cabeza una gorra milanesa negra, y la barba, canísima, le pasaba de la cintura; no traía arma ninguna, sino un rosario de cuentas en la mano, mayores que medianas nueces, y los dieces asimismo como huevos medianos de avestruz; el continente, el paso, la gravedad y la anchísima presencia, cada cosa de por sí y todas juntas, me suspendieron y admiraron. Llegóse a mí, y lo primero que hizo fue abrazarme estrechamente, y luego decirme: ''Luengos tiempos ha, valeroso caballero don Quijote de la Mancha, que los que estamos en estas soledades encantados esperamos verte, para que des noticia al mundo de lo que encierra y cubre la profunda cueva por donde has entrado, llamada la cueva de Montesinos: hazaña sólo guardada para ser acometida de tu invencible corazón y de tu ánimo stupendo. Ven conmigo, señor clarísimo, que te quiero mostrar las maravillas que este transparente alcázar solapa, de quien yo soy alcaide y guarda mayor perpetua, porque soy el mismo Montesinos, de quien la cueva toma nombre''. Apenas me dijo que era Montesinos, cuando le pregunté si fue verdad lo que en el mundo de acá arriba se contaba: que él había sacado de la mitad del pecho, con una pequeña daga, el corazón de su grande amigo Durandarte y llevádole a la Señora Belerma, como él se lo mandó al punto de su muerte. Respondióme que en todo decían verdad, sino en la daga, porque no fue daga, ni pequeña, sino un puñal buido, más agudo que una lezna. -Debía de ser -dijo a este punto Sancho- el tal puñal de Ramón de Hoces, el sevillano. -No sé -prosiguió don Quijote-, pero no sería dese puñalero, porque Ramón de Hoces fue ayer, y lo de Roncesvalles, donde aconteció esta desgracia, ha muchos años; y esta averiguación no es de importancia, ni turba ni altera la verdad y contesto de la historia. -Así es -respondió el primo-; prosiga vuestra merced, señor don Quijote, que le escucho con el mayor gusto del mundo. -No con menor lo cuento yo -respondió don Quijote-; y así, digo que el venerable Montesinos me metió en el cristalino palacio, donde en una sala baja, fresquísima sobremodo y toda de alabastro, estaba un sepulcro de mármol, con gran maestría fabricado, sobre el cual vi a un caballero tendido de largo a largo, no de bronce, ni de mármol, ni de jaspe hecho, como los suele haber en otros sepulcros, sino de pura carne y de puros huesos. Tenía la mano derecha (que, a mi parecer, es algo peluda y nervosa, señal de tener muchas fuerzas su dueño) puesta sobre el lado del corazón, y, antes que preguntase nada a Montesinos, viéndome suspenso mirando al del sepulcro, me dijo: ''Éste es mi amigo Durandarte, flor y espejo de los caballeros enamorados y valientes de su tiempo; tiénele aquí encantado, como me tiene a mí y a otros muchos y muchas, Merlín, aquel francés encantador que dicen que fue hijo del diablo; y lo que yo creo es que no fue hijo del diablo, sino que supo, como dicen, un punto más que el diablo. El cómo o para qué nos encantó nadie lo sabe, y ello dirá andando los tiempos, que no están muy lejos, según imagino. Lo que a mí me admira es que sé, tan cierto como ahora es de día, que Durandarte acabó los de su vida en mis brazos, y que después de muerto le saqué el corazón con mis propias manos; y en verdad que debía de pesar dos libras, porque, según los naturales, el que tiene mayor corazón es dotado de mayor valentía del que le tiene pequeño. Pues siendo esto así, y que realmente murió este caballero, ¿cómo ahora se queja y sospira de cuando en cuando, como si estuviese vivo?'' Esto dicho, el mísero Durandarte, dando una gran voz, dijo: ''¡Oh, mi primo Montesinos! Lo postrero que os rogaba, que cuando yo fuere muerto, y mi ánima arrancada, que llevéis mi corazón adonde Belerma estaba, sacándomele del pecho, ya con puñal, ya con daga.'' Oyendo lo cual el venerable Montesinos, se puso de rodillas ante el lastimado caballero, y, con lágrimas en los ojos, le dijo: ''Ya, señor Durandarte, carísimo primo mío, ya hice lo que me mandastes en el aciago día de nuestra pérdida: yo os saqué el corazón lo mejor que pude, sin que os dejase una mínima parte en el pecho; yo le limpié con un pañizuelo de puntas; yo partí con él de carrera para Francia, habiéndoos primero puesto en el seno de la tierra, con tantas lágrimas, que fueron bastantes a lavarme las manos y limpiarme con ellas la sangre que tenían, de haberos andado en las entrañas; y, por más señas, primo de mi alma, en el primero lugar que topé, saliendo de Roncesvalles, eché un poco de sal en vuestro corazón, porque no oliese mal, y fuese, si no fresco, a lo menos amojamado, a la presencia de la señora Belerma; la cual, con vos, y conmigo, y con Guadiana, vuestro escudero, y con la dueña Ruidera y sus siete hijas y dos sobrinas, y con otros muchos de vuestros conocidos y amigos, nos tiene aquí encantados el sabio Merlín ha muchos años; y, aunque pasan de quinientos, no se ha muerto ninguno de nosotros: solamente faltan Ruidera y sus hijas y sobrinas, las cuales llorando, por compasión que debió de tener Merlín dellas, las convirtió en otras tantas lagunas, que ahora, en el mundo de los vivos y en la provincia de la Mancha, las llaman las lagunas de Ruidera; las siete son de los reyes de España, y las dos sobrinas, de los caballeros de una orden santísima, que llaman de San Juan. Guadiana, vuestro escudero, plañendo asimesmo vuestra desgracia, fue convertido en un río llamado de su mesmo nombre; el cual, cuando llegó a la superficie de la tierra y vio el sol del otro cielo, fue tanto el pesar que sintió de ver que os dejaba, que se sumergió en las entrañas de la tierra; pero, como no es posible dejar de acudir a su natural corriente, de cuando en cuando sale y se muestra donde el sol y las gentes le vean. Vanle administrando de sus aguas las referidas lagunas, con las cuales y con otras muchas que se llegan, entra pomposo y grande en Portugal. Pero, con todo esto, por dondequiera que va muestra su tristeza y melancolía, y no se precia de criar en sus aguas peces regalados y de estima, sino burdos y desabridos, bien diferentes de los del Tajo dorado; y esto que agora os digo, ¡oh primo mío!, os lo he dicho muchas veces; y, como no me respondéis, imagino que no me dais crédito, o no me oís, de lo que yo recibo tanta pena cual Dios lo sabe. Unas nuevas os quiero dar ahora, las cuales, ya que no sirvan de alivio a vuestro dolor, no os le aumentarán en ninguna manera. Sabed que tenéis aquí en vuestra presencia, y abrid los ojos y veréislo, aquel gran caballero de quien tantas cosas tiene profetizadas el sabio Merlín, aquel don Quijote de la Mancha, digo, que de nuevo y con mayores ventajas que en los pasados siglos ha resucitado en los presentes la ya olvidada andante caballería, por cuyo medio y favor podría ser que nosotros fuésemos desencantados; que las grandes hazañas para los grandes hombres están guardadas''. ''Y cuando así no sea -respondió el lastimado Durandarte con voz desmayada y baja-, cuando así no sea, ¡oh primo!, digo, paciencia y barajar''. Y, volviéndose de lado, tornó a su acostumbrado silencio, sin hablar más palabra. Oyéronse en esto grandes alaridos y llantos, acompañados de profundos gemidos y angustiados sollozos; volví la cabeza, y vi por las paredes de cristal que por otra sala pasaba una procesión de dos hileras de hermosísimas doncellas, todas vestidas de luto, con turbantes blancos sobre las cabezas, al modo turquesco. Al cabo y fin de las hileras venía una señora, que en la gravedad lo parecía, asimismo vestida de negro, con tocas blancas tan tendidas y largas, que besaban la tierra. Su turbante era mayor dos veces que el mayor de alguna de las otras; era cejijunta y la nariz algo chata; la boca grande, pero colorados los labios; los dientes, que tal vez los descubría, mostraban ser ralos y no bien puestos, aunque eran blancos como unas peladas almendras; traía en las manos un lienzo delgado, y entre él, a lo que pude divisar, un corazón de carne momia, según venía seco y amojamado. Díjome Montesinos como toda aquella gente de la procesión eran sirvientes de Durandarte y de Belerma, que allí con sus dos señores estaban encantados, y que la última, que traía el corazón entre el lienzo y en las manos, era la señora Belerma, la cual con sus doncellas cuatro días en la semana hacían aquella procesión y cantaban, o, por mejor decir, lloraban endechas sobre el cuerpo y sobre el lastimado corazón de su primo; y que si me había parecido algo fea, o no tan hermosa como tenía la fama, era la causa las malas noches y peores días que en aquel encantamento pasaba, como lo podía ver en sus grandes ojeras y en su color quebradiza. ''Y no toma ocasión su amarillez y sus ojeras de estar con el mal mensil, ordinario en las mujeres, porque ha muchos meses, y aun años, que no le tiene ni asoma por sus puertas, sino del dolor que siente su corazón por el que de contino tiene en las manos, que le renueva y trae a la memoria la desgracia de su mal logrado amante; que si esto no fuera, apenas la igualara en hermosura, donaire y brío la gran Dulcinea del Toboso, tan celebrada en todos estos contornos, y aun en todo el mundo''. ''¡Cepos quedos! -dije yo entonces-, señor don Montesinos: cuente vuesa merced su historia como debe, que ya sabe que toda comparación es odiosa, y así, no hay para qué comparar a nadie con nadie. La sin par Dulcinea del Toboso es quien es, y la señora doña Belerma es quien es, y quien ha sido, y quédese aquí''. A lo que él me respondió: ''Señor don Quijote, perdóneme vuesa merced, que yo confieso que anduve mal, y no dije bien en decir que apenas igualara la señora Dulcinea a la señora Belerma, pues me bastaba a mí haber entendido, por no sé qué barruntos, que vuesa merced es su caballero, para que me mordiera la lengua antes de compararla sino con el mismo cielo''. Con esta satisfación que me dio el gran Montesinos se quietó mi corazón del sobresalto que recebí en oír que a mi señora la comparaban con Belerma. -Y aun me maravillo yo -dijo Sancho- de cómo vuestra merced no se subió sobre el vejote, y le molió a coces todos los huesos, y le peló las barbas, sin dejarle pelo en ellas. -No, Sancho amigo -respondió don Quijote-, no me estaba a mí bien hacer eso, porque estamos todos obligados a tener respeto a los ancianos, aunque no sean caballeros, y principalmente a los que lo son y están encantados; yo sé bien que no nos quedamos a deber nada en otras muchas demandas y respuestas que entre los dos pasamos. A esta sazón dijo el primo: -Yo no sé, señor don Quijote, cómo vuestra merced en tan poco espacio de tiempo como ha que está allá bajo, haya visto tantas cosas y hablado y respondido tanto. -¿Cuánto ha que bajé? -preguntó don Quijote. -Poco más de una hora -respondió Sancho. -Eso no puede ser -replicó don Quijote-, porque allá me anocheció y amaneció, y tornó a anochecer y amanecer tres veces; de modo que, a mi cuenta, tres días he estado en aquellas partes remotas y escondidas a la vista nuestra. -Verdad debe de decir mi señor -dijo Sancho-, que, como todas las cosas que le han sucedido son por encantamento, quizá lo que a nosotros nos parece un hora, debe de parecer allá tres días con sus noches. -Así será -respondió don Quijote. -Y ¿ha comido vuestra merced en todo este tiempo, señor mío? -preguntó el primo. -No me he desayunado de bocado -respondió don Quijote-, ni aun he tenido hambre, ni por pensamiento. -Y los encantados, ¿comen? -dijo el primo. -No comen -respondió don Quijote-, ni tienen escrementos mayores; aunque es opinión que les crecen las uñas, las barbas y los cabellos. -¿Y duermen, por ventura, los encantados, señor? -preguntó Sancho. -No, por cierto -respondió don Quijote-; a lo menos, en estos tres días que yo he estado con ellos, ninguno ha pegado el ojo, ni yo tampoco. -Aquí encaja bien el refrán -dijo Sancho- de dime con quién andas, decirte he quién eres: ándase vuestra merced con encantados ayunos y vigilantes, mirad si es mucho que ni coma ni duerma mientras con ellos anduviere. Pero perdóneme vuestra merced, señor mío, si le digo que de todo cuanto aquí ha dicho, lléveme Dios, que iba a decir el diablo, si le creo cosa alguna. -¿Cómo no? -dijo el primo-, pues ¿había de mentir el señor don Quijote, que, aunque quisiera, no ha tenido lugar para componer e imaginar tanto millón de mentiras? -Yo no creo que mi señor miente -respondió Sancho. -Si no, ¿qué crees? -le preguntó don Quijote. -Creo -respondió Sancho- que aquel Merlín, o aquellos encantadores que encantaron a toda la chusma que vuestra merced dice que ha visto y comunicado allá bajo, le encajaron en el magín o la memoria toda esa máquina que nos ha contado, y todo aquello que por contar le queda. -Todo eso pudiera ser, Sancho -replicó don Quijote-, pero no es así, porque lo que he contado lo vi por mis propios ojos y lo toqué con mis mismas manos. Pero, ¿qué dirás cuando te diga yo ahora cómo, entre otras infinitas cosas y maravillas que me mostró Montesinos, las cuales despacio y a sus tiempos te las iré contando en el discurso de nuestro viaje, por no ser todas deste lugar, me mostró tres labradoras que por aquellos amenísimos campos iban saltando y brincando como cabras; y, apenas las hube visto, cuando conocí ser la una la sin par Dulcinea del Toboso, y las otras dos aquellas mismas labradoras que venían con ella, que hablamos a la salida del Toboso? Pregunté a Montesinos si las conocía, respondióme que no, pero que él imaginaba que debían de ser algunas señoras principales encantadas, que pocos días había que en aquellos prados habían parecido; y que no me maravillase desto, porque allí estaban otras muchas señoras de los pasados y presentes siglos, encantadas en diferentes y estrañas figuras, entre las cuales conocía él a la reina Ginebra y su dueña Quintañona, escanciando el vino a Lanzarote, cuando de Bretaña vino. Cuando Sancho Panza oyó decir esto a su amo, pensó perder el juicio, o morirse de risa; que, como él sabía la verdad del fingido encanto de Dulcinea, de quien él había sido el encantador y el levantador de tal testimonio, acabó de conocer indubitablemente que su señor estaba fuera de juicio y loco de todo punto; y así, le dijo: -En mala coyuntura y en peor sazón y en aciago día bajó vuestra merced, caro patrón mío, al otro mundo, y en mal punto se encontró con el señor Montesinos, que tal nos le ha vuelto. Bien se estaba vuestra merced acá arriba con su entero juicio, tal cual Dios se le había dado, hablando sentencias y dando consejos a cada paso, y no agora, contando los mayores disparates que pueden imaginarse. -Como te conozco, Sancho -respondió don Quijote-, no hago caso de tus palabras. -Ni yo tampoco de las de vuestra merced -replicó Sancho-, siquiera me hiera, siquiera me mate por las que le he dicho, o por las que le pienso decir si en las suyas no se corrige y enmienda. Pero dígame vuestra merced, ahora que estamos en paz: ¿cómo o en qué conoció a la señora nuestra ama? Y si la habló, ¿qué dijo, y qué le respondió? -Conocíla -respondió don Quijote- en que trae los mesmos vestidos que traía cuando tú me le mostraste. Habléla, pero no me respondió palabra; antes, me volvió las espaldas, y se fue huyendo con tanta priesa, que no la alcanzara una jara. Quise seguirla, y lo hiciera, si no me aconsejara Montesinos que no me cansase en ello, porque sería en balde, y más porque se llegaba la hora donde me convenía volver a salir de la sima. Díjome asimesmo que, andando el tiempo, se me daría aviso cómo habían de ser desencantados él, y Belerma y Durandarte, con todos los que allí estaban; pero lo que más pena me dio, de las que allí vi y noté, fue que, estándome diciendo Montesinos estas razones, se llegó a mí por un lado, sin que yo la viese venir, una de las dos compañeras de la sin ventura Dulcinea, y, llenos los ojos de lágrimas, con turbada y baja voz, me dijo: ''Mi señora Dulcinea del Toboso besa a vuestra merced las manos, y suplica a vuestra merced se la haga de hacerla saber cómo está; y que, por estar en una gran necesidad, asimismo suplica a vuestra merced, cuan encarecidamente puede, sea servido de prestarle sobre este faldellín que aquí traigo, de cotonía, nuevo, media docena de reales, o los que vuestra merced tuviere, que ella da su palabra de volvérselos con mucha brevedad''. Suspendióme y admiróme el tal recado, y, volviéndome al señor Montesinos, le pregunté: ''¿Es posible, señor Montesinos, que los encantados principales padecen necesidad?'' A lo que él me respondió: ''Créame vuestra merced, señor don Quijote de la Mancha, que ésta que llaman necesidad adondequiera se usa, y por todo se estiende, y a todos alcanza, y aun hasta los encantados no perdona; y, pues la señora Dulcinea del Toboso envía a pedir esos seis reales, y la prenda es buena, según parece, no hay sino dárselos; que, sin duda, debe de estar puesta en algún grande aprieto''. ''Prenda, no la tomaré yo -le respondí-, ni menos le daré lo que pide, porque no tengo sino solos cuatro reales''; los cuales le di (que fueron los que tú, Sancho, me diste el otro día para dar limosna a los pobres que topase por los caminos), y le dije: ''Decid, amiga mía, a vuesa señora que a mí me pesa en el alma de sus trabajos, y que quisiera ser un Fúcar para remediarlos; y que le hago saber que yo no puedo ni debo tener salud careciendo de su agradable vista y discreta conversación, y que le suplico, cuan encarecidamente puedo, sea servida su merced de dejarse ver y tratar deste su cautivo servidor y asendereado caballero. Diréisle también que, cuando menos se lo piense, oirá decir como yo he hecho un juramento y voto, a modo de aquel que hizo el marqués de Mantua, de vengar a su sobrino Baldovinos, cuando le halló para espirar en mitad de la montiña, que fue de no comer pan a manteles, con las otras zarandajas que allí añadió, hasta vengarle; y así le haré yo de no sosegar, y de andar las siete partidas del mundo, con más puntualidad que las anduvo el infante don Pedro de Portugal, hasta desencantarla''. ''Todo eso, y más, debe vuestra merced a mi señora'', me respondió la doncella. Y, tomando los cuatro reales, en lugar de hacerme una reverencia, hizo una cabriola, que se levantó dos varas de medir en el aire. -¡Oh santo Dios! -dijo a este tiempo dando una gran voz Sancho-. ¿Es posible que tal hay en el mundo, y que tengan en él tanta fuerza los encantadores y encantamentos, que hayan trocado el buen juicio de mi señor en una tan disparatada locura? ¡Oh señor, señor, por quien Dios es, que vuestra merced mire por sí y vuelva por su honra, y no dé crédito a esas vaciedades que le tienen menguado y descabalado el sentido! -Como me quieres bien, Sancho, hablas desa manera -dijo don Quijote-; y, como no estás experimentado en las cosas del mundo, todas las cosas que tienen algo de dificultad te parecen imposibles; pero andará el tiempo, como otra vez he dicho, y yo te contaré algunas de las que allá abajo he visto, que te harán creer las que aquí he contado, cuya verdad ni admite réplica ni disputa. Capítulo XXIV. Donde se cuentan mil zarandajas tan impertinentes como necesarias al verdadero entendimiento desta grande historia Dice el que tradujo esta grande historia del original, de la que escribió su primer autor Cide Hamete Benengeli, que, llegando al capítulo de la aventura de la cueva de Montesinos, en el margen dél estaban escritas, de mano del mesmo Hamete, estas mismas razones: ''No me puedo dar a entender, ni me puedo persuadir, que al valeroso don Quijote le pasase puntualmente todo lo que en el antecedente capítulo queda escrito: la razón es que todas las aventuras hasta aquí sucedidas han sido contingibles y verisímiles, pero ésta desta cueva no le hallo entrada alguna para tenerla por verdadera, por ir tan fuera de los términos razonables. Pues pensar yo que don Quijote mintiese, siendo el más verdadero hidalgo y el más noble caballero de sus tiempos, no es posible; que no dijera él una mentira si le asaetearan. Por otra parte, considero que él la contó y la dijo con todas las circunstancias dichas, y que no pudo fabricar en tan breve espacio tan gran máquina de disparates; y si esta aventura parece apócrifa, yo no tengo la culpa; y así, sin afirmarla por falsa o verdadera, la escribo. Tú, letor, pues eres prudente, juzga lo que te pareciere, que yo no debo ni puedo más; puesto que se tiene por cierto que al tiempo de su fin y muerte dicen que se retrató della, y dijo que él la había inventado, por parecerle que convenía y cuadraba bien con las aventuras que había leído en sus historias''. Y luego prosigue, diciendo: Espantóse el primo, así del atrevimiento de Sancho Panza como de la paciencia de su amo, y juzgó que del contento que tenía de haber visto a su señora Dulcinea del Toboso, aunque encantada, le nacía aquella condición blanda que entonces mostraba; porque, si así no fuera, palabras y razones le dijo Sancho, que merecían molerle a palos; porque realmente le pareció que había andado atrevidillo con su señor, a quien le dijo: -Yo, señor don Quijote de la Mancha, doy por bien empleadísima la jornada que con vuestra merced he hecho, porque en ella he granjeado cuatro cosas. La primera, haber conocido a vuestra merced, que lo tengo a gran felicidad. La segunda, haber sabido lo que se encierra en esta cueva de Montesinos, con las mutaciones de Guadiana y de las lagunas de Ruidera, que me servirán para el Ovidio español que traigo entre manos. La tercera, entender la antigüedad de los naipes, que, por lo menos, ya se usaban en tiempo del emperador Carlomagno, según puede colegirse de las palabras que vuesa merced dice que dijo Durandarte, cuando, al cabo de aquel grande espacio que estuvo hablando con él Montesinos, él despertó diciendo: ''Paciencia y barajar''; y esta razón y modo de hablar no la pudo aprender encantado, sino cuando no lo estaba, en Francia y en tiempo del referido emperador Carlomagno. Y esta averiguación me viene pintiparada para el otro libro que voy componiendo , que es Suplemento de Virgilio Polidoro, en la invención de las antigüedades; y creo que en el suyo no se acordó de poner la de los naipes, como la pondré yo ahora, que será de mucha importancia, y más alegando autor tan grave y tan verdadero como es el señor Durandarte. La cuarta es haber sabido con certidumbre el nacimiento del río Guadiana, hasta ahora ignorado de las gentes. -Vuestra merced tiene razón -dijo don Quijote-, pero querría yo saber, ya que Dios le haga merced de que se le dé licencia para imprimir esos sus libros, que lo dudo, a quién piensa dirigirlos. -Señores y grandes hay en España a quien puedan dirigirse -dijo el primo. -No muchos -respondió don Quijote-; y no porque no lo merezcan, sino que no quieren admitirlos, por no obligarse a la satisfación que parece se debe al trabajo y cortesía de sus autores. Un príncipe conozco yo que puede suplir la falta de los demás, con tantas ventajas que, si me atreviere a decirlas, quizá despertara la invidia en más de cuatro generosos pechos; pero quédese esto aquí para otro tiempo más cómodo, y vamos a buscar adonde recogernos esta noche. -No lejos de aquí -respondió el primo- está una ermita, donde hace su habitación un ermitaño, que dicen ha sido soldado, y está en opinión de ser un buen cristiano, y muy discreto y caritativo además. Junto con la ermita tiene una pequeña casa, que él ha labrado a su costa; pero, con todo, aunque chica, es capaz de recibir huéspedes. -¿Tiene por ventura gallinas el tal ermitaño? -preguntó Sancho. -Pocos ermitaños están sin ellas -respondió don Quijote-, porque no son los que agora se usan como aquellos de los desiertos de Egipto, que se vestían de hojas de palma y comían raíces de la tierra. Y no se entienda que por decir bien de aquéllos no lo digo de aquéstos, sino que quiero decir que al rigor y estrecheza de entonces no llegan las penitencias de los de agora; pero no por esto dejan de ser todos buenos; a lo menos, yo por buenos los juzgo; y, cuando todo corra turbio, menos mal hace el hipócrita que se finge bueno que el público pecador. Estando en esto, vieron que hacia donde ellos estaban venía un hombre a pie, caminando apriesa, y dando varazos a un macho que venía cargado de lanzas y de alabardas. Cuando llegó a ellos, los saludó y pasó de largo. Don Quijote le dijo: -Buen hombre, deteneos, que parece que vais con más diligencia que ese macho ha menester. -No me puedo detener, señor -respondió el hombre-, porque las armas que veis que aquí llevo han de servir mañana; y así, me es forzoso el no detenerme, y a Dios. Pero si quisiéredes saber para qué las llevo, en la venta que está más arriba de la ermita pienso alojar esta noche; y si es que hacéis este mesmo camino, allí me hallaréis, donde os contaré maravillas. Y a Dios otra vez. Y de tal manera aguijó el macho, que no tuvo lugar don Quijote de preguntarle qué maravillas eran las que pensaba decirles; y, como él era algo curioso y siempre le fatigaban deseos de saber cosas nuevas, ordenó que al momento se partiesen y fuesen a pasar la noche en la venta, sin tocar en la ermita, donde quisiera el primo que se quedaran. Hízose así, subieron a caballo, y siguieron todos tres el derecho camino de la venta, a la cual llegaron un poco antes de anochecer. Dijo el primo a don Quijote que llegasen a ella a beber un trago. Apenas oyó esto Sancho Panza, cuando encaminó el rucio a la ermita, y lo mismo hicieron don Quijote y el primo; pero la mala suerte de Sancho parece que ordenó que el ermitaño no estuviese en casa; que así se lo dijo una sotaermitaño que en la ermita hallaron. Pidiéronle de lo caro; respondió que su señor no lo tenía, pero que si querían agua barata, que se la daría de muy buena gana. -Si yo la tuviera de agua -respondió Sancho-, pozos hay en el camino, donde la hubiera satisfecho. ¡Ah bodas de Camacho y abundancia de la casa de don Diego, y cuántas veces os tengo de echar menos! Con esto, dejaron la ermita y picaron hacia la venta; y a poco trecho toparon un mancebito, que delante dellos iba caminando no con mucha priesa; y así, le alcanzaron. Llevaba la espada sobre el hombro, y en ella puesto un bulto o envoltorio, al parecer de sus vestidos; que, al parecer, debían de ser los calzones o greguescos, y herreruelo, y alguna camisa, porque traía puesta una ropilla de terciopelo con algunas vislumbres de raso, y la camisa, de fuera; las medias eran de seda, y los zapatos cuadrados, a uso de corte; la edad llegaría a diez y ocho o diez y nueve años; alegre de rostro, y, al parecer, ágil de su persona. Iba cantando seguidillas, para entretener el trabajo del camino. Cuando llegaron a él, acababa de cantar una, que el primo tomó de memoria, que dicen que decía: A la guerra me lleva mi necesidad; si tuviera dineros, no fuera, en verdad. El primero que le habló fue don Quijote, diciéndole: -Muy a la ligera camina vuesa merced, señor galán. Y ¿adónde bueno? Sepamos, si es que gusta decirlo. A lo que el mozo respondió: -El caminar tan a la ligera lo causa el calor y la pobreza, y el adónde voy es a la guerra. -¿Cómo la pobreza? -preguntó don Quijote-; que por el calor bien puede ser. -Señor -replicó el mancebo-, yo llevo en este envoltorio unos greguescos de terciopelo, compañeros desta ropilla; si los gasto en el camino, no me podré honrar con ellos en la ciudad, y no tengo con qué comprar otros; y, así por esto como por orearme, voy desta manera, hasta alcanzar unas compañías de infantería que no están doce leguas de aquí, donde asentaré mi plaza, y no faltarán bagajes en que caminar de allí adelante hasta el embarcadero, que dicen ha de ser en Cartagena. Y más quiero tener por amo y por señor al rey, y servirle en la guerra, que no a un pelón en la corte. -Y ¿lleva vuesa merced alguna ventaja por ventura? -preguntó el primo. -Si yo hubiera servido a algún grande de España, o algún principal personaje -respondió el mozo-, a buen seguro que yo la llevara, que eso tiene el servir a los buenos: que del tinelo suelen salir a ser alférez o capitanes, o con algún buen entretenimiento; pero yo, desventurado, serví siempre a catarriberas y a gente advenediza, de ración y quitación tan mísera y atenuada, que en pagar el almidonar un cuello se consumía la mitad della; y sería tenido a milagro que un paje aventurero alcanzase alguna siquiera razonable ventura. -Y dígame, por su vida, amigo -preguntó don Quijote-: ¿es posible que en los años que sirvió no ha podido alcanzar alguna librea? -Dos me han dado -respondió el paje-; pero, así como el que se sale de alguna religión antes de profesar le quitan el hábito y le vuelven sus vestidos, así me volvían a mí los míos mis amos, que, acabados los negocios a que venían a la corte, se volvían a sus casas y recogían las libreas que por sola ostentación habían dado. -Notable espilorchería, como dice el italiano -dijo don Quijote-; pero, con todo eso, tenga a felice ventura el haber salido de la corte con tan buena intención como lleva; porque no hay otra cosa en la tierra más honrada ni de más provecho que servir a Dios, primeramente, y luego, a su rey y señor natural, especialmente en el ejercicio de las armas, por las cuales se alcanzan, si no más riquezas, a lo menos, más honra que por las letras, como yo tengo dicho muchas veces; que, puesto que han fundado más mayorazgos las letras que las armas, todavía llevan un no sé qué los de las armas a los de las letras, con un sí sé qué de esplendor que se halla en ellos, que los aventaja a todos. Y esto que ahora le quiero decir llévelo en la memoria, que le será de mucho provecho y alivio en sus trabajos; y es que, aparte la imaginación de los sucesos adversos que le podrán venir, que el peor de todos es la muerte, y como ésta sea buena, el mejor de todos es el morir. Preguntáronle a Julio César, aquel valeroso emperador romano, cuál era la mejor muerte; respondió que la impensada, la de repente y no prevista; y, aunque respondió como gentil y ajeno del conocimiento del verdadero Dios, con todo eso, dijo bien, para ahorrarse del sentimiento humano; que, puesto caso que os maten en la primera facción y refriega, o ya de un tiro de artillería, o volado de una mina, ¿qué importa? Todo es morir, y acabóse la obra; y, según Terencio, más bien parece el soldado muerto en la batalla que vivo y salvo en la huida; y tanto alcanza de fama el buen soldado cuanto tiene de obediencia a sus capitanes y a los que mandarle pueden. Y advertid, hijo, que al soldado mejor le está el oler a pólvora que algalia, y que si la vejez os coge en este honroso ejercicio, aunque sea lleno de heridas y estropeado o cojo, a lo menos no os podrá coger sin honra, y tal, que no os la podrá menoscabar la pobreza; cuanto más, que ya se va dando orden cómo se entretengan y remedien los soldados viejos y estropeados, porque no es bien que se haga con ellos lo que suelen hacer los que ahorran y dan libertad a sus negros cuando ya son viejos y no pueden servir, y, echándolos de casa con título de libres, los hacen esclavos de la hambre, de quien no piensan ahorrarse sino con la muerte. Y por ahora no os quiero decir más, sino que subáis a las ancas deste mi caballo hasta la venta, y allí cenaréis conmigo, y por la mañana seguiréis el camino, que os le dé Dios tan bueno como vuestros deseos merecen. El paje no aceptó el convite de las ancas, aunque sí el de cenar con él en la venta; y, a esta sazón, dicen que dijo Sancho entre sí: -¡Válate Dios por señor! Y ¿es posible que hombre que sabe decir tales, tantas y tan buenas cosas como aquí ha dicho, diga que ha visto los disparates imposibles que cuenta de la cueva de Montesinos? Ahora bien, ello dirá. Y en esto, llegaron a la venta, a tiempo que anochecía, y no sin gusto de Sancho, por ver que su señor la juzgó por verdadera venta, y no por castillo, como solía. No hubieron bien entrado, cuando don Quijote preguntó al ventero por el hombre de las lanzas y alabardas; el cual le respondió que en la caballeriza estaba acomodando el macho. Lo mismo hicieron de sus jumentos el primo y Sancho, dando a Rocinante el mejor pesebre y el mejor lugar de la caballeriza. Capítulo XXV. Donde se apunta la aventura del rebuzno y la graciosa del titerero, con las memorables adivinanzas del mono adivino No se le cocía el pan a don Quijote, como suele decirse, hasta oír y saber las maravillas prometidas del hombre condutor de las armas. Fuele a buscar donde el ventero le había dicho que estaba, y hallóle, y díjole que en todo caso le dijese luego lo que le había de decir después, acerca de lo que le había preguntado en el camino. El hombre le respondió: -Más despacio, y no en pie, se ha de tomar el cuento de mis maravillas: déjeme vuestra merced, señor bueno, acabar de dar recado a mi bestia, que yo le diré cosas que le admiren. -No quede por eso -respondió don Quijote-, que yo os ayudaré a todo. Y así lo hizo, ahechándole la cebada y limpiando el pesebre, humildad que obligó al hombre a contarle con buena voluntad lo que le pedía; y, sentándose en un poyo y don Quijote junto a él, teniendo por senado y auditorio al primo, al paje, a Sancho Panza y al ventero, comenzó a decir desta manera: -«Sabrán vuesas mercedes que en un lugar que está cuatro leguas y media desta venta sucedió que a un regidor dél, por industria y engaño de una muchacha criada suya, y esto es largo de contar, le faltó un asno, y, aunque el tal regidor hizo las diligencias posibles por hallarle, no fue posible. Quince días serían pasados, según es pública voz y fama,- que el asno faltaba, cuando, estando en la plaza el regidor perdidoso, otro regidor del mismo pueblo le dijo: ''Dadme albricias, compadre, que vuestro jumento ha parecido''. ''Yo os las mando y buenas, compadre -respondió el otro-, pero sepamos dónde ha parecido''. ''En el monte -respondió el hallador-, le vi esta mañana, sin albarda y sin aparejo alguno, y tan flaco que era una compasión miralle. Quísele antecoger delante de mí y traérosle, pero está ya tan montaraz y tan huraño, que, cuando llegé a él, se fue huyendo y se entró en lo más escondido del monte. Si queréis que volvamos los dos a buscarle, dejadme poner esta borrica en mi casa, que luego vuelvo''. ''Mucho placer me haréis -dijo el del jumento-, e yo procuraré pagároslo en la mesma moneda''. Con estas circunstancias todas, y de la mesma manera que yo lo voy contando, lo cuentan todos aquellos que están enterados en la verdad deste caso. En resolución, los dos regidores, a pie y mano a mano, se fueron al monte, y, llegando al lugar y sitio donde pensaron hallar el asno, no le hallaron, ni pareció por todos aquellos contornos, aunque más le buscaron. Viendo, pues, que no parecía, dijo el regidor que le había visto al otro: ''Mirad, compadre: una traza me ha venido al pensamiento, con la cual sin duda alguna podremos descubrir este animal, aunque esté metido en las entrañas de la tierra, no que del monte; y es que yo sé rebuznar maravillosamente; y si vos sabéis algún tanto, dad el hecho por concluido''. ''¿Algún tanto decís, compadre? -dijo el otro-; por Dios, que no dé la ventaja a nadie, ni aun a los mesmos asnos''. ''Ahora lo veremos -respondió el regidor segundo-, porque tengo determinado que os vais vos por una parte del monte y yo por otra, de modo que le rodeemos y andemos todo, y de trecho en trecho rebuznaréis vos y rebuznaré yo, y no podrá ser menos sino que el asno nos oya y nos responda, si es que está en el monte''. A lo que respondió el dueño del jumento: ''Digo, compadre, que la traza es excelente y digna de vuestro gran ingenio''. Y, dividiéndose los dos según el acuerdo, sucedió que casi a un mesmo tiempo rebuznaron, y cada uno engañado del rebuzno del otro, acudieron a buscarse, pensando que ya el jumento había parecido; y, en viéndose, dijo el perdidoso: ''¿Es posible, compadre, que no fue mi asno el que rebuznó?'' ''No fue, sino yo'', respondió el otro. ''Ahora digo -dijo el dueño-, que de vos a un asno, compadre, no hay alguna diferencia, en cuanto toca al rebuznar, porque en mi vida he visto ni oído cosa más propia''. ''Esas alabanzas y encarecimiento -respondió el de la traza-, mejor os atañen y tocan a vos que a mí, compadre; que por el Dios que me crió que podéis dar dos rebuznos de ventaja al mayor y más perito rebuznador del mundo; porque el sonido que tenéis es alto; lo sostenido de la voz, a su tiempo y compás; los dejos, muchos y apresurados, y, en resolución, yo me doy por vencido y os rindo la palma y doy la bandera desta rara habilidad''. ''Ahora digo -respondió el dueño-, que me tendré y estimaré en más de aquí adelante, y pensaré que sé alguna cosa, pues tengo alguna gracia; que, puesto que pensara que rebuznaba bien, nunca entendí que llegaba el estremo que decís''. ''También diré yo ahora -respondió el segundo- que hay raras habilidades perdidas en el mundo, y que son mal empleadas en aquellos que no saben aprovecharse dellas''. ''Las nuestras -respondió el dueño-, si no es en casos semejantes como el que traemos entre manos, no nos pueden servir en otros, y aun en éste plega a Dios que nos sean de provecho''. Esto dicho, se tornaron a dividir y a volver a sus rebuznos, y a cada paso se engañaban y volvían a juntarse, hasta que se dieron por contraseño que, para entender que eran ellos, y no el asno, rebuznasen dos veces, una tras otra. Con esto, doblando a cada paso los rebuznos, rodearon todo el monte sin que el perdido jumento respondiese, ni aun por señas. Mas, ¿cómo había de responder el pobre y mal logrado, si le hallaron en lo más escondido del bosque, comido de lobos? Y, en viéndole, dijo su dueño: ''Ya me maravillaba yo de que él no respondía, pues a no estar muerto, él rebuznara si nos oyera, o no fuera asno; pero, a trueco de haberos oído rebuznar con tanta gracia, compadre, doy por bien empleado el trabajo que he tenido en buscarle, aunque le he hallado muerto''. ''En buena mano está, compadre -respondió el otro-, pues si bien canta el abad, no le va en zaga el monacillo''. Con esto, desconsolados y roncos, se volvieron a su aldea, adonde contaron a sus amigos, vecinos y conocidos cuanto les había acontecido en la busca del asno, exagerando el uno la gracia del otro en el rebuznar; todo lo cual se supo y se estendió por los lugares circunvecinos. Y el diablo, que no duerme, como es amigo de sembrar y derramar rencillas y discordia por doquiera, levantando caramillos en el viento y grandes quimeras de nonada, ordenó e hizo que las gentes de los otros pueblos, en viendo a alguno de nuestra aldea, rebuznase, como dándoles en rostro con el rebuzno de nuestros regidores. Dieron en ello los muchachos, que fue dar en manos y en bocas de todos los demonios del infierno, y fue cundiendo el rebuzno de en uno en otro pueblo, de manera que son conocidos los naturales del pueblo del rebuzno, como son conocidos y diferenciados los negros de los blancos; y ha llegado a tanto la desgracia desta burla, que muchas veces con mano armada y formado escuadrón han salido contra los burladores los burlados a darse la batalla, sin poderlo remediar rey ni roque, ni temor ni vergüenza. Yo creo que mañana o esotro día han de salir en campaña los de mi pueblo, que son los del rebuzno, contra otro lugar que está a dos leguas del nuestro, que es uno de los que más nos persiguen: y, por salir bien apercebidos, llevo compradas estas lanzas y alabardas que habéis visto.» Y éstas son las maravillas que dije que os había de contar, y si no os lo han parecido, no sé otras. Y con esto dio fin a su plática el buen hombre; y, en esto, entró por la puerta de la venta un hombre todo vestido de camuza, medias, greguescos y jubón, y con voz levantada dijo: -Señor huésped, ¿hay posada? Que viene aquí el mono adivino y el retablo de la libertad de Melisendra. -¡Cuerpo de tal -dijo el ventero-, que aquí está el señor mase Pedro! Buena noche se nos apareja. Olvidábaseme de decir como el tal mase Pedro traía cubierto el ojo izquierdo, y casi medio carrillo, con un parche de tafetán verde, señal que todo aquel lado debía de estar enfermo; y el ventero prosiguió, diciendo: -Sea bien venido vuestra merced, señor mase Pedro. ¿Adónde está el mono y el retablo, que no los veo? -Ya llegan cerca -respondió el todo camuza-, sino que yo me he adelantado, a saber si hay posada. -Al mismo duque de Alba se la quitara para dársela al señor mase Pedro -respondió el ventero-; llegue el mono y el retablo, que gente hay esta noche en la venta que pagará el verle y las habilidades del mono. -Sea en buen hora -respondió el del parche-, que yo moderaré el precio, y con sola la costa me daré por bien pagado; y yo vuelvo a hacer que camine la carreta donde viene el mono y el retablo. Y luego se volvió a salir de la venta. Preguntó luego don Quijote al ventero qué mase Pedro era aquél, y qué retablo y qué mono traía. A lo que respondió el ventero: -Éste es un famoso titerero, que ha muchos días que anda por esta Mancha de Aragón enseñando un retablo de Melisendra, libertada por el famoso don Gaiferos, que es una de las mejores y más bien representadas historias que de muchos años a esta parte en este reino se han visto. Trae asimismo consigo un mono de la más rara habilidad que se vio entre monos, ni se imaginó entre hombres, porque si le preguntan algo, está atento a lo que le preguntan y luego salta sobre los hombros de su amo, y, llegándosele al oído, le dice la respuesta de lo que le preguntan, y maese Pedro la declara luego; y de las cosas pasadas dice mucho más que de las que están por venir; y, aunque no todas veces acierta en todas, en las más no yerra, de modo que nos hace creer que tiene el diablo en el cuerpo. Dos reales lleva por cada pregunta, si es que el mono responde; quiero decir, si responde el amo por él, después de haberle hablado al oído; y así, se cree que el tal maese Pedro esta riquísimo; y es hombre galante, como dicen en Italia y bon compaño, y dase la mejor vida del mundo; habla más que seis y bebe más que doce, todo a costa de su lengua y de su mono y de su retablo. En esto, volvió maese Pedro, y en una carreta venía el retablo, y el mono, grande y sin cola, con las posaderas de fieltro, pero no de mala cara; y, apenas le vio don Quijote, cuando le preguntó: -Dígame vuestra merced, señor adivino: ¿qué peje pillamo? ¿Qué ha de ser de nosotros?. Y vea aquí mis dos reales. Y mandó a Sancho que se los diese a maese Pedro, el cual respondió por el mono, y dijo: -Señor, este animal no responde ni da noticia de las cosas que están por venir; de las pasadas sabe algo, y de las presentes, algún tanto. -¡Voto a Rus -dijo Sancho-, no dé yo un ardite porque me digan lo que por mí ha pasado!; porque, ¿quién lo puede saber mejor que yo mesmo? Y pagar yo porque me digan lo que sé, sería una gran necedad; pero, pues sabe las cosas presentes, he aquí mis dos reales, y dígame el señor monísimo qué hace ahora mi mujer Teresa Panza, y en qué se entretiene. No quiso tomar maese Pedro el dinero, diciendo: -No quiero recebir adelantados los premios, sin que hayan precedido los servicios. Y, dando con la mano derecha dos golpes sobre el hombro izquierdo, en un brinco se le puso el mono en él, y, llegando la boca al oído, daba diente con diente muy apriesa; y, habiendo hecho este ademán por espacio de un credo, de otro brinco se puso en el suelo, y al punto, con grandísima priesa, se fue maese Pedro a poner de rodillas ante don Quijote, y, abrazándole las piernas, dijo: -Estas piernas abrazo, bien así como si abrazara las dos colunas de Hércules, ¡oh resucitador insigne de la ya puesta en olvido andante caballería!; ¡oh no jamás como se debe alabado caballero don Quijote de la Mancha, ánimo de los desmayados, arrimo de los que van a caer, brazo de los caídos, báculo y consuelo de todos los desdichados! Quedó pasmado don Quijote, absorto Sancho, suspenso el primo, atónito el paje, abobado el del rebuzno, confuso el ventero, y, finalmente, espantados todos los que oyeron las razones del titerero, el cual prosiguió diciendo: -Y tú, ¡oh buen Sancho Panza!, el mejor escudero y del mejor caballero del mundo, alégrate, que tu buena mujer Teresa está buena, y ésta es la hora en que ella está rastrillando una libra de lino, y, por más señas, tiene a su lado izquierdo un jarro desbocado que cabe un buen porqué de vino, con que se entretiene en su trabajo. -Eso creo yo muy bien -respondió Sancho-, porque es ella una bienaventurada, y, a no ser celosa, no la trocara yo por la giganta Andandona, que, según mi señor, fue una mujer muy cabal y muy de pro; y es mi Teresa de aquellas que no se dejan mal pasar, aunque sea a costa de sus herederos. -Ahora digo -dijo a esta sazón don Quijote-, que el que lee mucho y anda mucho, vee mucho y sabe mucho. Digo esto porque, ¿qué persuasión fuera bastante para persuadirme que hay monos en el mundo que adivinen, como lo he visto ahora por mis propios ojos? Porque yo soy el mesmo don Quijote de la Mancha que este buen animal ha dicho, puesto que se ha estendido algún tanto en mis alabanzas; pero comoquiera que yo me sea, doy gracias al cielo, que me dotó de un ánimo blando y compasivo, inclinado siempre a hacer bien a todos, y mal a ninguno. -Si yo tuviera dineros -dijo el paje-, preguntara al señor mono qué me ha de suceder en la peregrinación que llevo. A lo que respondió maese Pedro, que ya se había levantado de los pies de don Quijote: -Ya he dicho que esta bestezuela no responde a lo por venir; que si respondiera, no importara no haber dineros; que, por servicio del señor don Quijote, que está presente, dejara yo todos los intereses del mundo. Y agora, porque se lo debo, y por darle gusto, quiero armar mi retablo y dar placer a cuantos están en la venta, sin paga alguna. Oyendo lo cual el ventero, alegre sobremanera, señaló el lugar donde se podía poner el retablo, que en un punto fue hecho. Don Quijote no estaba muy contento con las adivinanzas del mono, por parecerle no ser a propósito que un mono adivinase, ni las de por venir, ni las pasadas cosas; y así, en tanto que maese Pedro acomodaba el retablo, se retiró don Quijote con Sancho a un rincón de la caballeriza, donde, sin ser oídos de nadie, le dijo: -Mira, Sancho, yo he considerado bien la estraña habilidad deste mono, y hallo por mi cuenta que sin duda este maese Pedro, su amo, debe de tener hecho pacto, tácito o espreso, con el demonio. -Si el patio es espeso y del demonio -dijo Sancho-, sin duda debe de ser muy sucio patio; pero, ¿de qué provecho le es al tal maese Pedro tener esos patios? -No me entiendes, Sancho: no quiero decir sino que debe de tener hecho algún concierto con el demonio de que infunda esa habilidad en el mono, con que gane de comer, y después que esté rico le dará su alma, que es lo que este universal enemigo pretende. Y háceme creer esto el ver que el mono no responde sino a las cosas pasadas o presentes, y la sabiduría del diablo no se puede estender a más, que las por venir no las sabe si no es por conjeturas, y no todas veces; que a solo Dios está reservado conocer los tiempos y los momentos, y para Él no hay pasado ni porvenir, que todo es presente. Y, siendo esto así, como lo es, está claro que este mono habla con el estilo del diablo; y estoy maravillado cómo no le han acusado al Santo Oficio, y examinádole y sacádole de cuajo en virtud de quién adivina; porque cierto está que este mono no es astrólogo, ni su amo ni él alzan, ni saben alzar, estas figuras que llaman judiciarias, que tanto ahora se usan en España, que no hay mujercilla, ni paje, ni zapatero de viejo que no presuma de alzar una figura, como si fuera una sota de naipes del suelo, echando a perder con sus mentiras e ignorancias la verdad maravillosa de la ciencia. De una señora sé yo que preguntó a uno destos figureros que si una perrilla de falda pequeña, que tenía, si se empreñaría y pariría, y cuántos y de qué color serían los perros que pariese. A lo que el señor judiciario, después de haber alzado la figura, respondió que la perrica se empreñaría, y pariría tres perricos, el uno verde, el otro encarnado y el otro de mezcla, con tal condición que la tal perra se cubriese entre las once y doce del día, o de la noche, y que fuese en lunes o en sábado; y lo que sucedió fue que de allí a dos días se moría la perra de ahíta, y el señor levantador quedó acreditado en el lugar por acertadísimo judiciario, como lo quedan todos o los más levantadores. -Con todo eso, querría -dijo Sancho- que vuestra merced dijese a maese Pedro preguntase a su mono si es verdad lo que a vuestra merced le pasó en la cueva de Montesinos; que yo para mí tengo, con perdón de vuestra merced, que todo fue embeleco y mentira, o por lo menos, cosas soñadas. -Todo podría ser -respondió don Quijote-, pero yo haré lo que me aconsejas, puesto que me ha de quedar un no sé qué de escrúpulo. Estando en esto, llegó maese Pedro a buscar a don Quijote y decirle que ya estaba en orden el retablo; que su merced viniese a verle, porque lo merecía. Don Quijote le comunicó su pensamiento, y le rogó preguntase luego a su mono le dijese si ciertas cosas que había pasado en la cueva de Montesinos habían sido soñadas o verdaderas; porque a él le parecía que tenían de todo. A lo que maese Pedro, sin responder palabra, volvió a traer el mono, y, puesto delante de don Quijote y de Sancho, dijo: -Mirad, señor mono, que este caballero quiere saber si ciertas cosas que le pasaron en una cueva llamada de Montesinos, si fueron falsas o verdaderas. Y, haciéndole la acostumbrada señal, el mono se le subió en el hombro izquierdo, y, hablándole, al parecer, en el oído, dijo luego maese Pedro: -El mono dice que parte de las cosas que vuesa merced vio, o pasó, en la dicha cueva son falsas, y parte verisímiles; y que esto es lo que sabe, y no otra cosa, en cuanto a esta pregunta; y que si vuesa merced quisiere saber más, que el viernes venidero responderá a todo lo que se le preguntare, que por ahora se le ha acabado la virtud, que no le vendrá hasta el viernes, como dicho tiene. -¿No lo decía yo -dijo Sancho-, que no se me podía asentar que todo lo que vuesa merced, señor mío, ha dicho de los acontecimientos de la cueva era verdad, ni aun la mitad? -Los sucesos lo dirán, Sancho -respondió don Quijote-; que el tiempo, descubridor de todas las cosas, no se deja ninguna que no las saque a la luz del sol, aunque esté escondida en los senos de la tierra. Y, por hora, baste esto, y vámonos a ver el retablo del buen maese Pedro, que para mí tengo que debe de tener alguna novedad. -¿Cómo alguna? -respondió maese Pedro-: sesenta mil encierra en sí este mi retablo; dígole a vuesa merced, mi señor don Quijote, que es una de las cosas más de ver que hoy tiene el mundo, y operibus credite, et non verbis; y manos a labor, que se hace tarde y tenemos mucho que hacer y que decir y que mostrar. Obedeciéronle don Quijote y Sancho, y vinieron donde ya estaba el retablo puesto y descubierto, lleno por todas partes de candelillas de cera encendidas, que le hacían vistoso y resplandeciente. En llegando, se metió maese Pedro dentro dél, que era el que había de manejar las figuras del artificio, y fuera se puso un muchacho, criado del maese Pedro, para servir de intérprete y declarador de los misterios del tal retablo: tenía una varilla en la mano, con que señalaba las figuras que salían. Puestos, pues, todos cuantos había en la venta, y algunos en pie, frontero del retablo, y acomodados don Quijote, Sancho, el paje y el primo en los mejores lugares, el trujamán comenzó a decir lo que oirá y verá el que le oyere o viere el capítulo siguiente. Capítulo XXVI. Donde se prosigue la graciosa aventura del titerero, con otras cosas en verdad harto buenas Callaron todos, tirios y troyanos; quiero decir, pendientes estaban todos los que el retablo miraban de la boca del declarador de sus maravillas, cuando se oyeron sonar en el retablo cantidad de atabales y trompetas, y dispararse mucha artillería, cuyo rumor pasó en tiempo breve, y luego alzó la voz el muchacho, y dijo: -Esta verdadera historia que aquí a vuesas mercedes se representa es sacada al pie de la letra de las corónicas francesas y de los romances españoles que andan en boca de las gentes, y de los muchachos, por esas calles. Trata de la libertad que dio el señor don Gaiferos a su esposa Melisendra, que estaba cautiva en España, en poder de moros, en la ciudad de Sansueña, que así se llamaba entonces la que hoy se llama Zaragoza; y vean vuesas mercedes allí cómo está jugando a las tablas don Gaiferos, según aquello que se canta: Jugando está a las tablas don Gaiferos, que ya de Melisendra está olvidado. Y aquel personaje que allí asoma, con corona en la cabeza y ceptro en las manos, es el emperador Carlomagno, padre putativo de la tal Melisendra, el cual, mohíno de ver el ocio y descuido de su yerno, le sale a reñir; y adviertan con la vehemencia y ahínco que le riñe, que no parece sino que le quiere dar con el ceptro media docena de coscorrones, y aun hay autores que dicen que se los dio, y muy bien dados; y, después de haberle dicho muchas cosas acerca del peligro que corría su honra en no procurar la libertad de su esposa, dicen que le dijo: "Harto os he dicho: miradlo". Miren vuestras mercedes también cómo el emperador vuelve las espaldas y deja despechado a don Gaiferos, el cual ya ven como arroja, impaciente de la cólera, lejos de sí el tablero y las tablas, y pide apriesa las armas, y a don Roldán, su primo, pide prestada su espada Durindana, y cómo don Roldán no se la quiere prestar, ofreciéndole su compañía en la difícil empresa en que se pone; pero el valeroso enojado no lo quiere aceptar; antes, dice que él solo es bastante para sacar a su esposa, si bien estuviese metida en el más hondo centro de la tierra; y, con esto, se entra a armar, para ponerse luego en camino. Vuelvan vuestras mercedes los ojos a aquella torre que allí parece, que se presupone que es una de las torres del alcázar de Zaragoza, que ahora llaman la Aljafería; y aquella dama que en aquel balcón parece, vestida a lo moro, es la sin par Melisendra, que desde allí muchas veces se ponía a mirar el camino de Francia, y, puesta la imaginación en París y en su esposo, se consolaba en su cautiverio. Miren también un nuevo caso que ahora sucede, quizá no visto jamás. ¿No veen aquel moro que callandico y pasito a paso, puesto el dedo en la boca, se llega por las espaldas de Melisendra? Pues miren cómo la da un beso en mitad de los labios, y la priesa que ella se da a escupir, y a limpiárselos con la blanca manga de su camisa, y cómo se lamenta, y se arranca de pesar sus hermosos cabellos, como si ellos tuvieran la culpa del maleficio. Miren también cómo aquel grave moro que está en aquellos corredores es el rey Marsilio de Sansueña; el cual, por haber visto la insolencia del moro, puesto que era un pariente y gran privado suyo, le mandó luego prender, y que le den docientos azotes, llevándole por las calles acostumbradas de la ciudad, con chilladores delante y envaramiento detrás; y veis aquí donde salen a ejecutar la sentencia, aun bien apenas no habiendo sido puesta en ejecución la culpa; porque entre moros no hay "traslado a la parte", ni "a prueba y estése", como entre nosotros. -Niño, niño -dijo con voz alta a esta sazón don Quijote-, seguid vuestra historia línea recta, y no os metáis en las curvas o transversales; que, para sacar una verdad en limpio, menester son muchas pruebas y repruebas. También dijo maese Pedro desde dentro: -Muchacho, no te metas en dibujos, sino haz lo que ese señor te manda, que será lo más acertado; sigue tu canto llano, y no te metas en contrapuntos, que se suelen quebrar de sotiles. -Yo lo haré así -respondió el muchacho; y prosiguió, diciendo-: Esta figura que aquí parece a caballo, cubierta con una capa gascona, es la mesma de don Gaiferos, a quien su esposa, ya vengada del atrevimiento del enamorado moro, con mejor y más sosegado semblante, se ha puesto a los miradores de la torre, y habla con su esposo, creyendo que es algún pasajero, con quien pasó todas aquellas razones y coloquios de aquel romance que dicen: Caballero, si a Francia ides, por Gaiferos preguntad; las cuales no digo yo ahora, porque de la prolijidad se suele engendrar el fastidio; basta ver cómo don Gaiferos se descubre, y que por los ademanes alegres que Melisendra hace se nos da a entender que ella le ha conocido, y más ahora que veemos se descuelga del balcón, para ponerse en las ancas del caballo de su buen esposo. Mas, ¡ay, sin ventura!, que se le ha asido una punta del faldellín de uno de los hierros del balcón, y está pendiente en el aire, sin poder llegar al suelo. Pero veis cómo el piadoso cielo socorre en las mayores necesidades, pues llega don Gaiferos, y, sin mirar si se rasgará o no el rico faldellín, ase della, y mal su grado la hace bajar al suelo, y luego, de un brinco, la pone sobre las ancas de su caballo, a horcajadas como hombre, y la manda que se tenga fuertemente y le eche los brazos por las espaldas, de modo que los cruce en el pecho, porque no se caiga, a causa que no estaba la señora Melisendra acostumbrada a semejantes caballerías. Veis también cómo los relinchos del caballo dan señales que va contento con la valiente y hermosa carga que lleva en su señor y en su señora. Veis cómo vuelven las espaldas y salen de la ciudad, y alegres y regocijados toman de París la vía. ¡Vais en paz, oh par sin par de verdaderos amantes! ¡Lleguéis a salvamento a vuestra deseada patria, sin que la fortuna ponga estorbo en vuestro felice viaje! ¡Los ojos de vuestros amigos y parientes os vean gozar en paz tranquila los días, que los de Néstor sean, que os quedan de la vida! Aquí alzó otra vez la voz maese Pedro, y dijo: -Llaneza, muchacho; no te encumbres, que toda afectación es mala. No respondió nada el intérprete; antes, prosiguió, diciendo: -No faltaron algunos ociosos ojos, que lo suelen ver todo, que no viesen la bajada y la subida de Melisendra, de quien dieron noticia al rey Marsilio, el cual mandó luego tocar al arma; y miren con qué priesa, que ya la ciudad se hunde con el son de las campanas que en todas las torres de las mezquitas suenan. -¡Eso no! -dijo a esta sazón don Quijote-: en esto de las campanas anda muy impropio maese Pedro, porque entre moros no se usan campanas, sino atabales, y un género de dulzainas que parecen nuestras chirimías; y esto de sonar campanas en Sansueña sin duda que es un gran disparate. Lo cual oído por maese Pedro, cesó el tocar y dijo: -No mire vuesa merced en niñerías, señor don Quijote, ni quiera llevar las cosas tan por el cabo que no se le halle. ¿No se representan por ahí, casi de ordinario, mil comedias llenas de mil impropiedades y disparates, y, con todo eso, corren felicísimamente su carrera, y se escuchan no sólo con aplauso, sino con admiración y todo? Prosigue, muchacho, y deja decir; que, como yo llene mi talego, si quiere represente más impropiedades que tiene átomos el sol. -Así es la verdad -replicó don Quijote. Y el muchacho dijo: -Miren cuánta y cuán lucida caballería sale de la ciudad en siguimiento de los dos católicos amantes, cuántas trompetas que suenan, cuántas dulzainas que tocan y cuántos atabales y atambores que retumban. Témome que los han de alcanzar, y los han de volver atados a la cola de su mismo caballo, que sería un horrendo espetáculo. Viendo y oyendo, pues, tanta morisma y tanto estruendo don Quijote, parecióle ser bien dar ayuda a los que huían; y, levantándose en pie, en voz alta, dijo: -No consentiré yo en mis días y en mi presencia se le haga superchería a tan famoso caballero y a tan atrevido enamorado como don Gaiferos. ¡Deteneos, mal nacida canalla; no le sigáis ni persigáis; si no, conmigo sois en la batalla! Y, diciendo y haciendo, desenvainó la espada, y de un brinco se puso junto al retablo, y, con acelerada y nunca vista furia, comenzó a llover cuchilladas sobre la titerera morisma, derribando a unos, descabezando a otros, estropeando a éste, destrozando a aquél, y, entre otros muchos, tiró un altibajo tal, que si maese Pedro no se abaja, se encoge y agazapa, le cercenara la cabeza con más facilidad que si fuera hecha de masa de mazapán. Daba voces maese Pedro, diciendo: -Deténgase vuesa merced, señor don Quijote, y advierta que estos que derriba, destroza y mata no son verdaderos moros, sino unas figurillas de pasta. ¡Mire, pecador de mí, que me destruye y echa a perder toda mi hacienda! Mas no por esto dejaba de menudear don Quijote cuchilladas, mandobles, tajos y reveses como llovidos. Finalmente, en menos de dos credos dio con todo el retablo en el suelo, hechas pedazos y desmenuzadas todas sus jarcias y figuras: el rey Marsilio, mal herido, y el emperador Carlomagno, partida la corona y la cabeza en dos partes. Alborotóse el senado de los oyentes, huyóse el mono por los tejados de la ventana, temió el primo, acobardóse el paje, y hasta el mesmo Sancho Panza tuvo pavor grandísimo, porque, como él juró después de pasada la borrasca, jamás había visto a su señor con tan desatinada cólera. Hecho, pues, el general destrozo del retablo, sosegóse un poco don Quijote y dijo: -Quisiera yo tener aquí delante en este punto todos aquellos que no creen, ni quieren creer, de cuánto provecho sean en el mundo los caballeros andantes: miren, si no me hallara yo aquí presente, qué fuera del buen don Gaiferos y de la hermosa Melisendra; a buen seguro que ésta fuera ya la hora que los hubieran alcanzado estos canes, y les hubieran hecho algún desaguisado. En resolución, ¡viva la andante caballería sobre cuantas cosas hoy viven en la tierra! -¡Vivan en hora buena -dijo a esta sazón con voz enfermiza maese Pedro-, y muera yo, pues soy tan desdichado que puedo decir con el rey don Rodrigo: Ayer fui señor de España... y hoy no tengo una almena que pueda decir que es mía! No ha media hora, ni aun un mediano momento, que me vi señor de reyes y de emperadores, llenas mis caballerizas y mis cofres y sacos de infinitos caballos y de innumerables galas, y agora me veo desolado y abatido, pobre y mendigo, y, sobre todo, sin mi mono, que a fe que primero que le vuelva a mi poder me han de sudar los dientes; y todo por la furia mal considerada deste señor caballero, de quien se dice que ampara pupilos, y endereza tuertos, y hace otras obras caritativas; y en mí solo ha venido a faltar su intención generosa, que sean benditos y alabados los cielos, allá donde tienen más levantados sus asientos. En fin, el Caballero de la Triste Figura había de ser aquel que había de desfigurar las mías. Enternecióse Sancho Panza con las razones de maese Pedro, y díjole: -No llores, maese Pedro, ni te lamentes, que me quiebras el corazón; porque te hago saber que es mi señor don Quijote tan católico y escrupuloso cristiano, que si él cae en la cuenta de que te ha hecho algún agravio, te lo sabrá y te lo querrá pagar y satisfacer con muchas ventajas. -Con que me pagase el señor don Quijote alguna parte de las hechuras que me ha deshecho, quedaría contento, y su merced aseguraría su conciencia, porque no se puede salvar quien tiene lo ajeno contra la voluntad de su dueño y no lo restituye. -Así es -dijo don Quijote-, pero hasta ahora yo no sé que tenga nada vuestro, maese Pedro. -¿Cómo no? -respondió maese Pedro-; y estas reliquias que están por este duro y estéril suelo, ¿quién las esparció y aniquiló, sino la fuerza invencible dese poderoso brazo?, y ¿cúyos eran sus cuerpos sino míos?, y ¿con quién me sustentaba yo sino con ellos? -Ahora acabo de creer -dijo a este punto don Quijote- lo que otras muchas veces he creído: que estos encantadores que me persiguen no hacen sino ponerme las figuras como ellas son delante de los ojos, y luego me las mudan y truecan en las que ellos quieren. Real y verdaderamente os digo, señores que me oís, que a mí me pareció todo lo que aquí ha pasado que pasaba al pie de la letra: que Melisendra era Melisendra, don Gaiferos don Gaiferos, Marsilio Marsilio, y Carlomagno Carlomagno: por eso se me alteró la cólera, y, por cumplir con mi profesión de caballero andante, quise dar ayuda y favor a los que huían, y con este buen propósito hice lo que habéis visto; si me ha salido al revés, no es culpa mía, sino de los malos que me persiguen; y, con todo esto, deste mi yerro, aunque no ha procedido de malicia, quiero yo mismo condenarme en costas: vea maese Pedro lo que quiere por las figuras deshechas, que yo me ofrezco a pagárselo luego, en buena y corriente moneda castellana. Inclinósele maese Pedro, diciéndole: -No esperaba yo menos de la inaudita cristiandad del valeroso don Quijote de la Mancha, verdadero socorredor y amparo de todos los necesitados y menesterosos vagamundos; y aquí el señor ventero y el gran Sancho serán medianeros y apreciadores, entre vuesa merced y mí, de lo que valen o podían valer las ya deshechas figuras. El ventero y Sancho dijeron que así lo harían, y luego maese Pedro alzó del suelo, con la cabeza menos, al rey Marsilio de Zaragoza, y dijo: -Ya se vee cuán imposible es volver a este rey a su ser primero; y así, me parece, salvo mejor juicio, que se me dé por su muerte, fin y acabamiento cuatro reales y medio. -¡Adelante! -dijo don Quijote. -Pues por esta abertura de arriba abajo -prosiguió maese Pedro, tomando en las manos al partido emperador Carlomagno-, no sería mucho que pidiese yo cinco reales y un cuartillo. -No es poco -dijo Sancho. -Ni mucho -replicó el ventero-; médiese la partida y señálensele cinco reales. -Dénsele todos cinco y cuartillo -dijo don Quijote-, que no está en un cuartillo más a menos la monta desta notable desgracia; y acabe presto maese Pedro, que se hace hora de cenar, y yo tengo ciertos barruntos de hambre. -Por esta figura -dijo maese Pedro- que está sin narices y un ojo menos, que es de la hermosa Melisendra, quiero, y me pongo en lo justo, dos reales y doce maravedís. -Aun ahí sería el diablo -dijo don Quijote-, si ya no estuviese Melisendra con su esposo, por lo menos, en la raya de Francia; porque el caballo en que iban, a mí me pareció que antes volaba que corría; y así, no hay para qué venderme a mí el gato por liebre, presentándome aquí a Melisendra desnarigada, estando la otra, si viene a mano, ahora holgándose en Francia con su esposo a pierna tendida. Ayude Dios con lo suyo a cada uno, señor maese Pedro, y caminemos todos con pie llano y con intención sana. Y prosiga. Maese Pedro, que vio que don Quijote izquierdeaba y que volvía a su primer tema, no quiso que se le escapase; y así, le dijo: -Ésta no debe de ser Melisendra, sino alguna de las doncellas que la servían; y así, con sesenta maravedís que me den por ella quedaré contento y bien pagado. Desta manera fue poniendo precio a otras muchas destrozadas figuras, que después los moderaron los dos jueces árbitros, con satisfación de las partes, que llegaron a cuarenta reales y tres cuartillos; y, además desto, que luego lo desembolsó Sancho, pidió maese Pedro dos reales por el trabajo de tomar el mono. -Dáselos, Sancho -dijo don Quijote-, no para tomar el mono, sino la mona; y docientos diera yo ahora en albricias a quien me dijera con certidumbre que la señora doña Melisendra y el señor don Gaiferos estaban ya en Francia y entre los suyos. -Ninguno nos lo podrá decir mejor que mi mono -dijo maese Pedro-, pero no habrá diablo que ahora le tome; aunque imagino que el cariño y la hambre le han de forzar a que me busque esta noche, y amanecerá Dios y verémonos. En resolución, la borrasca del retablo se acabó y todos cenaron en paz y en buena compañía, a costa de don Quijote, que era liberal en todo estremo. Antes que amaneciese, se fue el que llevaba las lanzas y las alabardas, y ya después de amanecido, se vinieron a despedir de don Quijote el primo y el paje: el uno, para volverse a su tierra; y el otro, a proseguir su camino, para ayuda del cual le dio don Quijote una docena de reales. Maese Pedro no quiso volver a entrar en más dimes ni diretes con don Quijote, a quien él conocía muy bien, y así, madrugó antes que el sol, y, cogiendo las reliquias de su retablo y a su mono, se fue también a buscar sus aventuras. El ventero, que no conocía a don Quijote, tan admirado le tenían sus locuras como su liberalidad. Finalmente, Sancho le pagó muy bien, por orden de su señor, y, despidiéndose dél, casi a las ocho del día dejaron la venta y se pusieron en camino, donde los dejaremos ir; que así conviene para dar lugar a contar otras cosas pertenecientes a la declaración desta famosa historia. Capítulo XXVII. Donde se da cuenta quiénes eran maese Pedro y su mono, con el mal suceso que don Quijote tuvo en la aventura del rebuzno, que no la acabó como él quisiera y como lo tenía pensado Entra Cide Hamete, coronista desta grande historia, con estas palabras en este capítulo: ''Juro como católico cristiano...''; a lo que su traductor dice que el jurar Cide Hamete como católico cristiano, siendo él moro, como sin duda lo era, no quiso decir otra cosa sino que, así como el católico cristiano cuando jura, jura, o debe jurar, verdad, y decirla en lo que dijere, así él la decía, como si jurara como cristiano católico, en lo que quería escribir de don Quijote, especialmente en decir quién era maese Pedro, y quién el mono adivino que traía admirados todos aquellos pueblos con sus adivinanzas. Dice, pues, que bien se acordará, el que hubiere leído la primera parte desta historia, de aquel Ginés de Pasamonte, a quien, entre otros galeotes, dio libertad don Quijote en Sierra Morena, beneficio que después le fue mal agradecido y peor pagado de aquella gente maligna y mal acostumbrada. Este Ginés de Pasamonte, a quien don Quijote llamaba Ginesillo de Parapilla, fue el que hurtó a Sancho Panza el rucio; que, por no haberse puesto el cómo ni el cuándo en la primera parte, por culpa de los impresores, ha dado en qué entender a muchos, que atribuían a poca memoria del autor la falta de emprenta. Pero, en resolución, Ginés le hurtó, estando sobre él durmiendo Sancho Panza, usando de la traza y modo que usó Brunelo cuando, estando Sacripante sobre Albraca, le sacó el caballo de entre las piernas, y después le cobró Sancho, como se ha contado. Este Ginés, pues, temeroso de no ser hallado de la justicia, que le buscaba para castigarle de sus infinitas bellaquerías y delitos, que fueron tantos y tales, que él mismo compuso un gran volumen contándolos, determinó pasarse al reino de Aragón y cubrirse el ojo izquierdo, acomodándose al oficio de titerero; que esto y el jugar de manos lo sabía hacer por estremo. Sucedió, pues, que de unos cristianos ya libres que venían de Berbería compró aquel mono, a quien enseñó que, en haciéndole cierta señal, se le subiese en el hombro y le murmurase, o lo pareciese, al oído. Hecho esto, antes que entrase en el lugar donde entraba con su retablo y mono, se informaba en el lugar más cercano, o de quien él mejor podía, qué cosas particulares hubiesen sucedido en el tal lugar, y a qué personas; y, llevándolas bien en la memoria, lo primero que hacía era mostrar su retablo, el cual unas veces era de una historia, y otras de otra; pero todas alegres y regocijadas y conocidas. Acabada la muestra, proponía las habilidades de su mono, diciendo al pueblo que adivinaba todo lo pasado y lo presente; pero que en lo de por venir no se daba maña. Por la respuesta de cada pregunta pedía dos reales, y de algunas hacía barato, según tomaba el pulso a los preguntantes; y como tal vez llegaba a las casas de quien él sabía los sucesos de los que en ella moraban, aunque no le preguntasen nada por no pagarle, él hacía la seña al mono, y luego decía que le había dicho tal y tal cosa, que venía de molde con lo sucedido. Con esto cobraba crédito inefable, y andábanse todos tras él. Otras veces, como era tan discreto, respondía de manera que las respuestas venían bien con las preguntas; y, como nadie le apuraba ni apretaba a que dijese cómo adevinaba su mono, a todos hacía monas, y llenaba sus esqueros. Así como entró en la venta, conoció a don Quijote y a Sancho, por cuyo conocimiento le fue fácil poner en admiración a don Quijote y a Sancho Panza, y a todos los que en ella estaban; pero hubiérale de costar caro si don Quijote bajara un poco más la mano cuando cortó la cabeza al rey Marsilio y destruyó toda su caballería, como queda dicho en el antecedente capítulo. Esto es lo que hay que decir de maese Pedro y de su mono. Y, volviendo a don Quijote de la Mancha, digo que, después de haber salido de la venta, determinó de ver primero las riberas del río Ebro y todos aquellos contornos, antes de entrar en la ciudad de Zaragoza, pues le daba tiempo para todo el mucho que faltaba desde allí a las justas. Con esta intención siguió su camino, por el cual anduvo dos días sin acontecerle cosa digna de ponerse en escritura, hasta que al tercero, al subir de una loma, oyó un gran rumor de atambores, de trompetas y arcabuces. Al principio pensó que algún tercio de soldados pasaba por aquella parte, y por verlos picó a Rocinante y subió la loma arriba; y cuando estuvo en la cumbre, vio al pie della, a su parecer, más de docientos hombres armados de diferentes suertes de armas, como si dijésemos lanzones, ballestas, partesanas, alabardas y picas, y algunos arcabuces, y muchas rodelas. Bajó del recuesto y acercóse al escuadrón, tanto, que distintamente vio las banderas, juzgó de las colores y notó las empresas que en ellas traían, especialmente una que en un estandarte o jirón de raso blanco venía, en el cual estaba pintado muy al vivo un asno como un pequeño sardesco, la cabeza levantada, la boca abierta y la lengua de fuera, en acto y postura como si estuviera rebuznando; alrededor dél estaban escritos de letras grandes estos dos versos: No rebuznaron en balde el uno y el otro alcalde. Por esta insignia sacó don Quijote que aquella gente debía de ser del pueblo del rebuzno, y así se lo dijo a Sancho, declarándole lo que en el estandarte venía escrito. Díjole también que el que les había dado noticia de aquel caso se había errado en decir que dos regidores habían sido los que rebuznaron; pero que, según los versos del estandarte, no habían sido sino alcaldes. A lo que respondió Sancho Panza: -Señor, en eso no hay que reparar, que bien puede ser que los regidores que entonces rebuznaron viniesen con el tiempo a ser alcaldes de su pueblo, y así, se pueden llamar con entrambos títulos; cuanto más, que no hace al caso a la verdad de la historia ser los rebuznadores alcaldes o regidores, como ellos una por una hayan rebuznado; porque tan a pique está de rebuznar un alcalde como un regidor. Finalmente, conocieron y supieron como el pueblo corrido salía a pelear con otro que le corría más de lo justo y de lo que se debía a la buena vecindad. Fuese llegando a ellos don Quijote, no con poca pesadumbre de Sancho, que nunca fue amigo de hallarse en semejantes jornadas. Los del escuadrón le recogieron en medio, creyendo que era alguno de los de su parcialidad. Don Quijote, alzando la visera, con gentil brío y continente, llegó hasta el estandarte del asno, y allí se le pusieron alrededor todos los más principales del ejército, por verle, admirados con la admiración acostumbrada en que caían todos aquellos que la vez primera le miraban. Don Quijote, que los vio tan atentos a mirarle, sin que ninguno le hablase ni le preguntase nada, quiso aprovecharse de aquel silencio, y, rompiendo el suyo, alzó la voz y dijo: -Buenos señores, cuan encarecidamente puedo, os suplico que no interrumpáis un razonamiento que quiero haceros, hasta que veáis que os disgusta y enfada; que si esto sucede, con la más mínima señal que me hagáis pondré un sello en mi boca y echaré una mordaza a mi lengua. Todos le dijeron que dijese lo que quisiese, que de buena gana le escucharían. Don Quijote, con esta licencia, prosiguió diciendo: Yo, señores míos, soy caballero andante, cuyo ejercicio es el de las armas, y cuya profesión la de favorecer a los necesitados de favor y acudir a los menesterosos. Días ha que he sabido vuestra desgracia y la causa que os mueve a tomar las armas a cada paso, para vengaros de vuestros enemigos; y, habiendo discurrido una y muchas veces en mi entendimiento sobre vuestro negocio, hallo, según las leyes del duelo, que estáis engañados en teneros por afrentados, porque ningún particular puede afrentar a un pueblo entero, si no es retándole de traidor por junto, porque no sabe en particular quién cometió la traición por que le reta. Ejemplo desto tenemos en don Diego Ordóñez de Lara, que retó a todo el pueblo zamorano, porque ignoraba que solo Vellido Dolfos había cometido la traición de matar a su rey; y así, retó a todos, y a todos tocaba la venganza y la respuesta; aunque bien es verdad que el señor don Diego anduvo algo demasiado, y aun pasó muy adelante de los límites del reto, porque no tenía para qué retar a los muertos, a las aguas, ni a los panes, ni a los que estaban por nacer, ni a las otras menudencias que allí se declaran; pero, ¡vaya!, pues cuando la cólera sale de madre, no tiene la lengua padre, ayo ni freno que la corrija. Siendo, pues, esto así, que uno solo no puede afrentar a reino, provincia, ciudad, república ni pueblo entero, queda en limpio que no hay para qué salir a la venganza del reto de la tal afrenta, pues no lo es; porque, ¡bueno sería que se matasen a cada paso los del pueblo de la Reloja con quien se lo llama, ni los cazoleros, berenjeneros, ballenatos, jaboneros, ni los de otros nombres y apellidos que andan por ahí en boca de los muchachos y de gente de poco más a menos! ¡Bueno sería, por cierto, que todos estos insignes pueblos se corriesen y vengasen, y anduviesen contino hechas las espadas sacabuches a cualquier pendencia, por pequeña que fuese! No, no, ni Dios lo permita o quiera. Los varones prudentes, las repúblicas bien concertadas, por cuatro cosas han de tomar las armas y desenvainar las espadas, y poner a riesgo sus personas, vidas y haciendas: la primera, por defender la fe católica; la segunda, por defender su vida, que es de ley natural y divina; la tercera, en defensa de su honra, de su familia y hacienda; la cuarta, en servicio de su rey, en la guerra justa; y si le quisiéremos añadir la quinta, que se puede contar por segunda, es en defensa de su patria. A estas cinco causas, como capitales, se pueden agregar algunas otras que sean justas y razonables, y que obliguen a tomar las armas; pero tomarlas por niñerías y por cosas que antes son de risa y pasatiempo que de afrenta, parece que quien las toma carece de todo razonable discurso; cuanto más, que el tomar venganza injusta, que justa no puede haber alguna que lo sea, va derechamente contra la santa ley que profesamos, en la cual se nos manda que hagamos bien a nuestros enemigos y que amemos a los que nos aborrecen; mandamiento que, aunque parece algo dificultoso de cumplir, no lo es sino para aquellos que tienen menos de Dios que del mundo, y más de carne que de espíritu; porque Jesucristo, Dios y hombre verdadero, que nunca mintió, ni pudo ni puede mentir, siendo legislador nuestro, dijo que su yugo era suave y su carga liviana; y así, no nos había de mandar cosa que fuese imposible el cumplirla. Así que, mis señores, vuesas mercedes están obligados por leyes divinas y humanas a sosegarse. -El diablo me lleve -dijo a esta sazón Sancho entre sí- si este mi amo no es tólogo; y si no lo es, que lo parece como un güevo a otro. Tomó un poco de aliento don Quijote, y, viendo que todavía le prestaban silencio, quiso pasar adelante en su plática, como pasara ni no se pusiere en medio la agudeza de Sancho, el cual, viendo que su amo se detenía, tomó la mano por él, diciendo: -Mi señor don Quijote de la Mancha, que un tiempo se llamó el Caballero de la Triste Figura y ahora se llama el Caballero de los Leones, es un hidalgo muy atentado, que sabe latín y romance como un bachiller, y en todo cuanto trata y aconseja procede como muy buen soldado, y tiene todas las leyes y ordenanzas de lo que llaman el duelo en la uña; y así, no hay más que hacer sino dejarse llevar por lo que él dijere, y sobre mí si lo erraren; cuanto más, que ello se está dicho que es necedad correrse por sólo oír un rebuzno, que yo me acuerdo, cuando muchacho, que rebuznaba cada y cuando que se me antojaba, sin que nadie me fuese a la mano, y con tanta gracia y propiedad que, en rebuznando yo, rebuznaban todos los asnos del pueblo, y no por eso dejaba de ser hijo de mis padres, que eran honradísimos; y, aunque por esta habilidad era invidiado de más de cuatro de los estirados de mi pueblo, no se me daba dos ardites. Y, porque se vea que digo verdad, esperen y escuchen, que esta ciencia es como la del nadar: que, una vez aprendida, nunca se olvida. Y luego, puesta la mano en las narices, comenzó a rebuznar tan reciamente, que todos los cercanos valles retumbaron. Pero uno de los que estaban junto a él, creyendo que hacía burla dellos, alzó un varapalo que en la mano tenía, y diole tal golpe con él, que, sin ser poderoso a otra cosa, dio con Sancho Panza en el suelo. Don Quijote, que vio tan malparado a Sancho, arremetió al que le había dado, con la lanza sobre mano, pero fueron tantos los que se pusieron en medio, que no fue posible vengarle; antes, viendo que llovía sobre él un nublado de piedras, y que le amenazaban mil encaradas ballestas y no menos cantidad de arcabuces, volvió las riendas a Rocinante, y a todo lo que su galope pudo, se salió de entre ellos, encomendándose de todo corazón a Dios, que de aquel peligro le librase, temiendo a cada paso no le entrase alguna bala por las espaldas y le saliese al pecho; y a cada punto recogía el aliento, por ver si le faltaba. Pero los del escuadrón se contentaron con verle huir, sin tirarle. A Sancho le pusieron sobre su jumento, apenas vuelto en sí, y le dejaron ir tras su amo, no porque él tuviese sentido para regirle; pero el rucio siguió las huellas de Rocinante, sin el cual no se hallaba un punto. Alongado, pues, don Quijote buen trecho, volvió la cabeza y vio que Sancho venía, y atendióle, viendo que ninguno le seguía. Los del escuadrón se estuvieron allí hasta la noche, y, por no haber salido a la batalla sus contrarios, se volvieron a su pueblo, regocijados y alegres; y si ellos supieran la costumbre antigua de los griegos, levantaran en aquel lugar y sitio un trofeo. Capítulo XXVIII. De cosas que dice Benengeli que las sabrá quien le leyere, si las lee con atención Cuando el valiente huye, la superchería está descubierta, y es de varones prudentes guardarse para mejor ocasión. Esta verdad se verificó en don Quijote, el cual, dando lugar a la furia del pueblo y a las malas intenciones de aquel indignado escuadrón, puso pies en polvorosa, y, sin acordarse de Sancho ni del peligro en que le dejaba, se apartó tanto cuanto le pareció que bastaba para estar seguro. Seguíale Sancho, atravesado en su jumento, como queda referido. Llegó, en fin, ya vuelto en su acuerdo, y al llegar, se dejó caer del rucio a los pies de Rocinante, todo ansioso, todo molido y todo apaleado. Apeóse don Quijote para catarle las feridas; pero, como le hallase sano de los pies a la cabeza, con asaz cólera le dijo: -¡Tan en hora mala supistes vos rebuznar, Sancho! Y ¿dónde hallastes vos ser bueno el nombrar la soga en casa del ahorcado? A música de rebuznos, ¿qué contrapunto se había de llevar sino de varapalos? Y dad gracias a Dios, Sancho, que ya que os santiguaron con un palo, no os hicieron el per signum crucis con un alfanje. -No estoy para responder -respondió Sancho-, porque me parece que hablo por las espaldas. Subamos y apartémonos de aquí, que yo pondré silencio en mis rebuznos, pero no en dejar de decir que los caballeros andantes huyen, y dejan a sus buenos escuderos molidos como alheña, o como cibera, en poder de sus enemigos. -No huye el que se retira -respondió don Quijote-, porque has de saber, Sancho, que la valentía que no se funda sobre la basa de la prudencia se llama temeridad, y las hazañas del temerario más se atribuyen a la buena fortuna que a su ánimo. Y así, yo confieso que me he retirado, pero no huido; y en esto he imitado a muchos valientes, que se han guardado para tiempos mejores, y desto están las historias llenas, las cuales, por no serte a ti de provecho ni a mí de gusto, no te las refiero ahora. En esto, ya estaba a caballo Sancho, ayudado de don Quijote, el cual asimismo subió en Rocinante, y poco a poco se fueron a emboscar en una alameda que hasta un cuarto de legua de allí se parecía. De cuando en cuando daba Sancho unos ayes profundísimos y unos gemidos dolorosos; y, preguntándole don Quijote la causa de tan amargo sentimiento, respondió que, desde la punta del espinazo hasta la nuca del celebro, le dolía de manera que le sacaba de sentido. -La causa dese dolor debe de ser, sin duda -dijo don Quijote-, que, como era el palo con que te dieron largo y tendido, te cogió todas las espaldas, donde entran todas esas partes que te duelen; y si más te cogiera, más te doliera. -¡Por Dios -dijo Sancho-, que vuesa merced me ha sacado de una gran duda, y que me la ha declarado por lindos términos! ¡Cuerpo de mí! ¿Tan encubierta estaba la causa de mi dolor que ha sido menester decirme que me duele todo todo aquello que alcanzó el palo? Si me dolieran los tobillos, aún pudiera ser que se anduviera adivinando el porqué me dolían, pero dolerme lo que me molieron no es mucho adivinar. A la fe, señor nuestro amo, el mal ajeno de pelo cuelga, y cada día voy descubriendo tierra de lo poco que puedo esperar de la compañía que con vuestra merced tengo; porque si esta vez me ha dejado apalear, otra y otras ciento volveremos a los manteamientos de marras y a otras muchacherías, que si ahora me han salido a las espaldas, después me saldrán a los ojos. Harto mejor haría yo, sino que soy un bárbaro, y no haré nada que bueno sea en toda mi vida; harto mejor haría yo, vuelvo a decir, en volverme a mi casa, y a mi mujer, y a mis hijos, y sustentarla y criarlos con lo que Dios fue servido de darme, y no andarme tras vuesa merced por caminos sin camino y por sendas y carreras que no las tienen, bebiendo mal y comiendo peor. Pues, ¡tomadme el dormir! Contad, hermano escudero, siete pies de tierra, y si quisiéredes más, tomad otros tantos, que en vuestra mano está escudillar, y tendeos a todo vuestro buen talante; que quemado vea yo y hecho polvos al primero que dio puntada en la andante caballería, o, a lo menos, al primero que quiso ser escudero de tales tontos como debieron ser todos los caballeros andantes pasados. De los presentes no digo nada, que, por ser vuestra merced uno dellos, los tengo respeto, y porque sé que sabe vuesa merced un punto más que el diablo en cuanto habla y en cuanto piensa. -Haría yo una buena apuesta con vos, Sancho -dijo don Quijote-: que ahora que vais hablando sin que nadie os vaya a la mano, que no os duele nada en todo vuestro cuerpo. Hablad, hijo mío, todo aquello que os viniere al pensamiento y a la boca; que, a trueco de que a vos no os duela nada, tendré yo por gusto el enfado que me dan vuestras impertinencias. Y si tanto deseáis volveros a vuestra casa con vuestra mujer y hijos, no permita Dios que yo os lo impida; dineros tenéis míos: mirad cuánto ha que esta tercera vez salimos de nuestro pueblo, y mirad lo que podéis y debéis ganar cada mes, y pagaos de vuestra mano. -Cuando yo servía -respondió Sancho- a Tomé Carrasco, el padre del bachiller Sansón Carrasco, que vuestra merced bien conoce, dos ducados ganaba cada mes, amén de la comida; con vuestra merced no sé lo que puedo ganar, puesto que sé que tiene más trabajo el escudero del caballero andante que el que sirve a un labrador; que, en resolución, los que servimos a labradores, por mucho que trabajemos de día, por mal que suceda, a la noche cenamos olla y dormimos en cama, en la cual no he dormido después que ha que sirvo a vuestra merced. Si no ha sido el tiempo breve que estuvimos en casa de don Diego de Miranda, y la jira que tuve con la espuma que saqué de las ollas de Camacho, y lo que comí y bebí y dormí en casa de Basilio, todo el otro tiempo he dormido en la dura tierra, al cielo abierto, sujeto a lo que dicen inclemencias del cielo, sustentándome con rajas de queso y mendrugos de pan, y bebiendo aguas, ya de arroyos, ya de fuentes, de las que encontramos por esos andurriales donde andamos. -Confieso -dijo don Quijote- que todo lo que dices, Sancho, sea verdad. ¿Cuánto parece que os debo dar más de lo que os daba Tomé Carrasco? -A mi parecer -dijo Sancho-, con dos reales más que vuestra merced añadiese cada mes me tendría por bien pagado. Esto es cuanto al salario de mi trabajo; pero, en cuanto a satisfacerme a la palabra y promesa que vuestra merced me tiene hecha de darme el gobierno de una ínsula, sería justo que se me añadiesen otros seis reales, que por todos serían treinta. -Está muy bien -replicó don Quijote-; y, conforme al salario que vos os habéis señalado, 23 días ha que salimos de nuestro pueblo: contad, Sancho, rata por cantidad, y mirad lo que os debo, y pagaos, como os tengo dicho, de vuestra mano. -¡Oh, cuerpo de mí! -dijo Sancho-, que va vuestra merced muy errado en esta cuenta, porque en lo de la promesa de la ínsula se ha de contar desde el día que vuestra merced me la prometió hasta la presente hora en que estamos. -Pues, ¿qué tanto ha, Sancho, que os la prometí? -dijo don Quijote. -Si yo mal no me acuerdo -respondió Sancho-, debe de haber más de veinte años, tres días más a menos. Diose don Quijote una gran palmada en la frente, y comenzó a reír muy de gana, y dijo: -Pues no anduve yo en Sierra Morena, ni en todo el discurso de nuestras salidas, sino dos meses apenas, y ¿dices, Sancho, que ha veinte años que te prometí la ínsula? Ahora digo que quieres que se consuman en tus salarios el dinero que tienes mío; y si esto es así, y tú gustas dello, desde aquí te lo doy, y buen provecho te haga; que, a trueco de verme sin tan mal escudero, holgaréme de quedarme pobre y sin blanca. Pero dime, prevaricador de las ordenanzas escuderiles de la andante caballería, ¿dónde has visto tú, o leído, que ningún escudero de caballero andante se haya puesto con su señor en tanto más cuánto me habéis de dar cada mes porque os sirva? Éntrate, éntrate, malandrín, follón y vestiglo, que todo lo pareces; éntrate, digo, por el mare magnum de sus historias, y si hallares que algún escudero haya dicho, ni pensado, lo que aquí has dicho, quiero que me le claves en la frente, y, por añadidura, me hagas cuatro mamonas selladas en mi rostro. Vuelve las riendas, o el cabestro, al rucio, y vuélvete a tu casa, porque un solo paso desde aquí no has de pasar más adelante conmigo. ¡Oh pan mal conocido! ¡Oh promesas mal colocadas! ¡Oh hombre que tiene más de bestia que de persona! ¿Ahora, cuando yo pensaba ponerte en estado, y tal, que a pesar de tu mujer te llamaran señoría, te despides? ¿Ahora te vas, cuando yo venía con intención firme y valedera de hacerte señor de la mejor ínsula del mundo? En fin, como tú has dicho otras veces, no es la miel... etc. Asno eres, y asno has de ser, y en asno has de parar cuando se te acabe el curso de la vida; que para mí tengo que antes llegará ella a su último término que tú caigas y des en la cuenta de que eres bestia. Miraba Sancho a don Quijote de en hito en hito, en tanto que los tales vituperios le decía, y compungióse de manera que le vinieron las lágrimas a los ojos, y con voz dolorida y enferma le dijo: -Señor mío, yo confieso que para ser del todo asno no me falta más de la cola; si vuestra merced quiere ponérmela, yo la daré por bien puesta, y le serviré como jumento todos los días que me quedan de mi vida. Vuestra merced me perdone y se duela de mi mocedad, y advierta que sé poco, y que si hablo mucho, más procede de enfermedad que de malicia; mas, quien yerra y se enmienda, a Dios se encomienda. -Maravillárame yo, Sancho, si no mezclaras algún refrancico en tu coloquio. Ahora bien, yo te perdono, con que te emiendes, y con que no te muestres de aquí adelante tan amigo de tu interés, sino que procures ensanchar el corazón, y te alientes y animes a esperar el cumplimiento de mis promesas, que, aunque se tarda, no se imposibilita. Sancho respondió que sí haría, aunque sacase fuerzas de flaqueza. Con esto, se metieron en la alameda, y don Quijote se acomodó al pie de un olmo, y Sancho al de una haya; que estos tales árboles y otros sus semejantes siempre tienen pies, y no manos. Sancho pasó la noche penosamente, porque el varapalo se hacía más sentir con el sereno. Don Quijote la pasó en sus continuas memorias; pero, con todo eso, dieron los ojos al sueño, y al salir del alba siguieron su camino buscando las riberas del famoso Ebro, donde les sucedió lo que se contará en el capítulo venidero. Capítulo XXIX. De la famosa aventura del barco encantado Por sus pasos contados y por contar, dos días después que salieron de la alameda, llegaron don Quijote y Sancho al río Ebro, y el verle fue de gran gusto a don Quijote, porque contempló y miró en él la amenidad de sus riberas, la claridad de sus aguas, el sosiego de su curso y la abundancia de sus líquidos cristales, cuya alegre vista renovó en su memoria mil amorosos pensamientos. Especialmente fue y vino en lo que había visto en la cueva de Montesinos; que, puesto que el mono de maese Pedro le había dicho que parte de aquellas cosas eran verdad y parte mentira, él se atenía más a las verdaderas que a las mentirosas, bien al revés de Sancho, que todas las tenía por la mesma mentira. Yendo, pues, desta manera, se le ofreció a la vista un pequeño barco sin remos ni otras jarcias algunas, que estaba atado en la orilla a un tronco de un árbol que en la ribera estaba. Miró don Quijote a todas partes, y no vio persona alguna; y luego, sin más ni más, se apeó de Rocinante y mandó a Sancho que lo mesmo hiciese del rucio, y que a entrambas bestias las atase muy bien, juntas, al tronco de un álamo o sauce que allí estaba. Preguntóle Sancho la causa de aquel súbito apeamiento y de aquel ligamiento. Respondió don Quijote: -Has de saber, Sancho, que este barco que aquí está, derechamente y sin poder ser otra cosa en contrario, me está llamando y convidando a que entre en él, y vaya en él a dar socorro a algún caballero, o a otra necesitada y principal persona, que debe de estar puesta en alguna grande cuita, porque éste es estilo de los libros de las historias caballerescas y de los encantadores que en ellas se entremeten y platican: cuando algún caballero está puesto en algún trabajo, que no puede ser librado dél sino por la mano de otro caballero, puesto que estén distantes el uno del otro dos o tres mil leguas, y aun más, o le arrebatan en una nube o le deparan un barco donde se entre, y en menos de un abrir y cerrar de ojos le llevan, o por los aires, o por la mar, donde quieren y adonde es menester su ayuda; así que, ¡oh Sancho!, este barco está puesto aquí para el mesmo efecto; y esto es tan verdad como es ahora de día; y antes que éste se pase, ata juntos al rucio y a Rocinante, y a la mano de Dios, que nos guíe, que no dejaré de embarcarme si me lo pidiesen frailes descalzos. -Pues así es -respondió Sancho-, y vuestra merced quiere dar a cada paso en estos que no sé si los llame disparates, no hay sino obedecer y bajar la cabeza, atendiendo al refrán "haz lo que tu amo te manda, y siéntate con él a la mesa"; pero, con todo esto, por lo que toca al descargo de mi conciencia, quiero advertir a vuestra merced que a mí me parece que este tal barco no es de los encantados, sino de algunos pescadores deste río, porque en él se pescan las mejores sabogas del mundo. Esto decía, mientras ataba las bestias, Sancho, dejándolas a la proteción y amparo de los encantadores, con harto dolor de su ánima. Don Quijote le dijo que no tuviese pena del desamparo de aquellos animales, que el que los llevaría a ellos por tan longincuos caminos y regiones tendría cuenta de sustentarlos. -No entiendo eso de logicuos -dijo Sancho-, ni he oído tal vocablo en todos los días de mi vida. -Longincuos -respondió don Quijote- quiere decir apartados; y no es maravilla que no lo entiendas, que no estás tú obligado a saber latín, como algunos que presumen que lo saben, y lo ignoran. -Ya están atados -replicó Sancho-. ¿Qué hemos de hacer ahora? -¿Qué? -respondió don Quijote-. Santiguarnos y levar ferro; quiero decir, embarcarnos y cortar la amarra con que este barco está atado. Y, dando un salto en él, siguiéndole Sancho, cortó el cordel, y el barco se fue apartando poco a poco de la ribera; y cuando Sancho se vio obra de dos varas dentro del río, comenzó a temblar, temiendo su perdición; pero ninguna cosa le dio más pena que el oír roznar al rucio y el ver que Rocinante pugnaba por desatarse, y díjole a su señor: -El rucio rebuzna, condolido de nuestra ausencia, y Rocinante procura ponerse en libertad para arrojarse tras nosotros. ¡Oh carísimos amigos, quedaos en paz, y la locura que nos aparta de vosotros, convertida en desengaño, nos vuelva a vuestra presencia! Y, en esto, comenzó a llorar tan amargamente que don Quijote, mohíno y colérico, le dijo: -¿De qué temes, cobarde criatura? ¿De qué lloras, corazón de mantequillas? ¿Quién te persigue, o quién te acosa, ánimo de ratón casero, o qué te falta, menesteroso en la mitad de las entrañas de la abundancia? ¿Por dicha vas caminando a pie y descalzo por las montañas rifeas, sino sentado en una tabla, como un archiduque, por el sesgo curso deste agradable río, de donde en breve espacio saldremos al mar dilatado? Pero ya habemos de haber salido, y caminado, por lo menos, setecientas o ochocientas leguas; y si yo tuviera aquí un astrolabio con que tomar la altura del polo, yo te dijera las que hemos caminado; aunque, o yo sé poco, o ya hemos pasado, o pasaremos presto, por la línea equinocial, que divide y corta los dos contrapuestos polos en igual distancia. -Y cuando lleguemos a esa leña que vuestra merced dice -preguntó Sancho-, ¿cuánto habremos caminado? -Mucho -replicó don Quijote-, porque de trecientos y sesenta grados que contiene el globo, del agua y de la tierra, según el cómputo de Ptolomeo, que fue el mayor cosmógrafo que se sabe, la mitad habremos caminado, llegando a la línea que he dicho. -Por Dios -dijo Sancho-, que vuesa merced me trae por testigo de lo que dice a una gentil persona, puto y gafo, con la añadidura de meón, o meo, o no sé cómo. Rióse don Quijote de la interpretación que Sancho había dado al nombre y al cómputo y cuenta del cosmógrafo Ptolomeo, y díjole: -Sabrás, Sancho, que los españoles y los que se embarcan en Cádiz para ir a las Indias Orientales, una de las señales que tienen para entender que han pasado la línea equinocial que te he dicho es que a todos los que van en el navío se les mueren los piojos, sin que les quede ninguno, ni en todo el bajel le hallarán, si le pesan a oro; y así, puedes, Sancho, pasear una mano por un muslo, y si topares cosa viva, saldremos desta duda; y si no, pasado habemos. -Yo no creo nada deso -respondió Sancho-, pero, con todo, haré lo que vuesa merced me manda, aunque no sé para qué hay necesidad de hacer esas experiencias, pues yo veo con mis mismos ojos que no nos habemos apartado de la ribera cinco varas, ni hemos decantado de donde están las alemañas dos varas, porque allí están Rocinante y el rucio en el propio lugar do los dejamos; y tomada la mira, como yo la tomo ahora, voto a tal que no nos movemos ni andamos al paso de una hormiga. -Haz, Sancho, la averiguación que te he dicho, y no te cures de otra, que tú no sabes qué cosa sean coluros, líneas, paralelos, zodíacos, clíticas, polos, solsticios, equinocios, planetas, signos, puntos, medidas, de que se compone la esfera celeste y terrestre; que si todas estas cosas supieras, o parte dellas, vieras claramente qué de paralelos hemos cortado, qué de signos visto y qué de imágines hemos dejado atrás y vamos dejando ahora. Y tórnote a decir que te tientes y pesques, que yo para mí tengo que estás más limpio que un pliego de papel liso y blanco. Tentóse Sancho, y, llegando con la mano bonitamente y con tiento hacia la corva izquierda, alzó la cabeza y miró a su amo, y dijo: -O la experiencia es falsa, o no hemos llegado adonde vuesa merced dice, ni con muchas leguas. -Pues ¿qué? -preguntó don Quijote-, ¿has topado algo? -¡Y aun algos! -respondió Sancho. Y, sacudiéndose los dedos, se lavó toda la mano en el río, por el cual sosegadamente se deslizaba el barco por mitad de la corriente, sin que le moviese alguna inteligencia secreta, ni algún encantador escondido, sino el mismo curso del agua, blando entonces y suave. En esto, descubrieron unas grandes aceñas que en la mitad del río estaban; y apenas las hubo visto don Quijote, cuando con voz alta dijo a Sancho: -¿Vees? Allí, ¡oh amigo!, se descubre la ciudad, castillo o fortaleza donde debe de estar algún caballero oprimido, o alguna reina, infanta o princesa malparada, para cuyo socorro soy aquí traído. -¿Qué diablos de ciudad, fortaleza o castillo dice vuesa merced, señor? -dijo Sancho-. ¿No echa de ver que aquéllas son aceñas que están en el río, donde se muele el trigo? -Calla, Sancho -dijo don Quijote-; que, aunque parecen aceñas, no lo son; y ya te he dicho que todas las cosas trastruecan y mudan de su ser natural los encantos. No quiero decir que las mudan de en uno en otro ser realmente, sino que lo parece, como lo mostró la experiencia en la transformación de Dulcinea, único refugio de mis esperanzas. En esto, el barco, entrado en la mitad de la corriente del río, comenzó a caminar no tan lentamente como hasta allí. Los molineros de las aceñas, que vieron venir aquel barco por el río, y que se iba a embocar por el raudal de las ruedas, salieron con presteza muchos dellos con varas largas a detenerle, y, como salían enharinados, y cubiertos los rostros y los vestidos del polvo de la harina, representaban una mala vista. Daban voces grandes, diciendo: -¡Demonios de hombres! ¿Dónde vais? ¿Venís desesperados? ¿Qué queréis, ahogaros y haceros pedazos en estas ruedas? -¿No te dije yo, Sancho -dijo a esta sazón don Quijote-, que habíamos llegado donde he de mostrar a dó llega el valor de mi brazo? Mira qué de malandrines y follones me salen al encuentro, mira cuántos vestiglos se me oponen, mira cuántas feas cataduras nos hacen cocos... Pues ¡ahora lo veréis, bellacos! Y, puesto en pie en el barco, con grandes voces comenzó a amenazar a los molineros, diciéndoles: -Canalla malvada y peor aconsejada, dejad en su libertad y libre albedrío a la persona que en esa vuestra fortaleza o prisión tenéis oprimida, alta o baja, de cualquiera suerte o calidad que sea, que yo soy don Quijote de la Mancha, llamado el Caballero de los Leones por otro nombre, a quien está reservada por orden de los altos cielos el dar fin felice a esta aventura. Y, diciendo esto, echó mano a su espada y comenzó a esgrimirla en el aire contra los molineros; los cuales, oyendo y no entendiendo aquellas sandeces, se pusieron con sus varas a detener el barco, que ya iba entrando en el raudal y canal de las ruedas. Púsose Sancho de rodillas, pidiendo devotamente al cielo le librase de tan manifiesto peligro, como lo hizo, por la industria y presteza de los molineros, que, oponiéndose con sus palos al barco, le detuvieron, pero no de manera que dejasen de trastornar el barco y dar con don Quijote y con Sancho al través en el agua; pero vínole bien a don Quijote, que sabía nadar como un ganso, aunque el peso de las armas le llevó al fondo dos veces; y si no fuera por los molineros, que se arrojaron al agua y los sacaron como en peso a entrambos, allí había sido Troya para los dos. Puestos, pues, en tierra, más mojados que muertos de sed, Sancho, puesto de rodillas, las manos juntas y los ojos clavados al cielo, pidió a Dios con una larga y devota plegaria le librase de allí adelante de los atrevidos deseos y acometimientos de su señor. Llegaron en esto los pescadores dueños del barco, a quien habían hecho pedazos las ruedas de las aceñas; y, viéndole roto, acometieron a desnudar a Sancho, y a pedir a don Quijote se lo pagase; el cual, con gran sosiego, como si no hubiera pasado nada por él, dijo a los molineros y pescadores que él pagaría el barco de bonísima gana, con condición que le diesen libre y sin cautela a la persona o personas que en aquel su castillo estaban oprimidas. -¿Qué personas o qué castillo dice -respondió uno de los molineros-, hombre sin juicio? ¿Quiéreste llevar por ventura las que vienen a moler trigo a estas aceñas? -¡Basta! -dijo entre sí don Quijote-. Aquí será predicar en desierto querer reducir a esta canalla a que por ruegos haga virtud alguna. Y en esta aventura se deben de haber encontrado dos valientes encantadores, y el uno estorba lo que el otro intenta: el uno me deparó el barco, y el otro dio conmigo al través. Dios lo remedie, que todo este mundo es máquinas y trazas, contrarias unas de otras. Yo no puedo más. Y, alzando la voz, prosiguió diciendo, y mirando a las aceñas: -Amigos, cualesquiera que seáis, que en esa prisión quedáis encerrados, perdonadme; que, por mi desgracia y por la vuestra, yo no os puedo sacar de vuestra cuita. Para otro caballero debe de estar guardada y reservada esta aventura. En diciendo esto, se concertó con los pescadores, y pagó por el barco cincuenta reales, que los dio Sancho de muy mala gana, diciendo: -A dos barcadas como éstas, daremos con todo el caudal al fondo. Los pescadores y molineros estaban admirados, mirando aquellas dos figuras tan fuera del uso, al parecer, de los otros hombres, y no acababan de entender a dó se encaminaban las razones y preguntas que don Quijote les decía; y, teniéndolos por locos, les dejaron y se recogieron a sus aceñas, y los pescadores a sus ranchos. Volvieron a sus bestias, y a ser bestias, don Quijote y Sancho, y este fin tuvo la aventura del encantado barco. Capítulo XXX. De lo que le avino a don Quijote con una bella cazadora Asaz melancólicos y de mal talante llegaron a sus animales caballero y escudero, especialmente Sancho, a quien llegaba al alma llegar al caudal del dinero, pareciéndole que todo lo que dél se quitaba era quitárselo a él de las niñas de sus ojos. Finalmente, sin hablarse palabra, se pusieron a caballo y se apartaron del famoso río, don Quijote sepultado en los pensamientos de sus amores, y Sancho en los de su acrecentamiento, que por entonces le parecía que estaba bien lejos de tenerle; porque, maguer era tonto, bien se le alcanzaba que las acciones de su amo, todas o las más, eran disparates, y buscaba ocasión de que, sin entrar en cuentas ni en despedimientos con su señor, un día se desgarrase y se fuese a su casa. Pero la fortuna ordenó las cosas muy al revés de lo que él temía. Sucedió, pues, que otro día, al poner del sol y al salir de una selva, tendió don Quijote la vista por un verde prado, y en lo último dél vio gente, y, llegándose cerca, conoció que eran cazadores de altanería. Llegóse más, y entre ellos vio una gallarda señora sobre un palafrén o hacanea blanquísima, adornada de guarniciones verdes y con un sillón de plata. Venía la señora asimismo vestida de verde, tan bizarra y ricamente que la misma bizarría venía transformada en ella. En la mano izquierda traía un azor, señal que dio a entender a don Quijote ser aquélla alguna gran señora, que debía serlo de todos aquellos cazadores, como era la verdad; y así, dijo a Sancho: -Corre, hijo Sancho, y di a aquella señora del palafrén y del azor que yo, el Caballero de los Leones, besa las manos a su gran fermosura, y que si su grandeza me da licencia, se las iré a besar, y a servirla en cuanto mis fuerzas pudieren y su alteza me mandare. Y mira, Sancho, cómo hablas, y ten cuenta de no encajar algún refrán de los tuyos en tu embajada. -¡Hallado os le habéis el encajador! -respondió Sancho-. ¡A mí con eso! ¡Sí, que no es ésta la vez primera que he llevado embajadas a altas y crecidas señoras en esta vida! -Si no fue la que llevaste a la señora Dulcinea -replicó don Quijote-, yo no sé que hayas llevado otra, a lo menos en mi poder. -Así es verdad -respondió Sancho-, pero al buen pagador no le duelen prendas, y en casa llena presto se guisa la cena; quiero decir que a mí no hay que decirme ni advertirme de nada, que para todo tengo y de todo se me alcanza un poco. -Yo lo creo, Sancho -dijo don Quijote-; ve en buena hora, y Dios te guíe. Partió Sancho de carrera, sacando de su paso al rucio, y llegó donde la bella cazadora estaba, y, apeándose, puesto ante ella de hinojos, le dijo: -Hermosa señora, aquel caballero que allí se parece, llamado el Caballero de los Leones, es mi amo, y yo soy un escudero suyo, a quien llaman en su casa Sancho Panza. Este tal Caballero de los Leones, que no ha mucho que se llamaba el de la Triste Figura, envía por mí a decir a vuestra grandeza sea servida de darle licencia para que, con su propósito y beneplácito y consentimiento, él venga a poner en obra su deseo, que no es otro, según él dice y yo pienso, que de servir a vuestra encumbrada altanería y fermosura; que en dársela vuestra señoría hará cosa que redunde en su pro, y él recibirá señaladísima merced y contento. -Por cierto, buen escudero -respondió la señora-, vos habéis dado la embajada vuestra con todas aquellas circunstancias que las tales embajadas piden. Levantaos del suelo, que escudero de tan gran caballero como es el de la Triste Figura, de quien ya tenemos acá mucha noticia, no es justo que esté de hinojos; levantaos, amigo, y decid a vuestro señor que venga mucho en hora buena a servirse de mí y del duque mi marido, en una casa de placer que aquí tenemos. Levantóse Sancho admirado, así de la hermosura de la buena señora como de su mucha crianza y cortesía, y más de lo que le había dicho que tenía noticia de su señor el Caballero de la Triste Figura, y que si no le había llamado el de los Leones, debía de ser por habérsele puesto tan nuevamente. Preguntóle la duquesa, cuyo título aún no se sabe: -Decidme, hermano escudero: este vuestro señor, ¿no es uno de quien anda impresa una historia que se llama del ingenioso hidalgo don Quijote de la Mancha, que tiene por señora de su alma a una tal Dulcinea del Toboso? -El mesmo es, señora -respondió Sancho-; y aquel escudero suyo que anda, o debe de andar, en la tal historia, a quien llaman Sancho Panza, soy yo, si no es que me trocaron en la cuna; quiero decir, que me trocaron en la estampa. -De todo eso me huelgo yo mucho -dijo la duquesa-. Id, hermano Panza, y decid a vuestro señor que él sea el bien llegado y el bien venido a mis estados, y que ninguna cosa me pudiera venir que más contento me diera. Sancho, con esta tan agradable respuesta, con grandísimo gusto volvió a su amo, a quien contó todo lo que la gran señora le había dicho, levantando con sus rústicos términos a los cielos su mucha fermosura, su gran donaire y cortesía. Don Quijote se gallardeó en la silla, púsose bien en los estribos, acomodóse la visera, arremetió a Rocinante, y con gentil denuedo fue a besar las manos a la duquesa; la cual, haciendo llamar al duque, su marido, le contó, en tanto que don Quijote llegaba, toda la embajada suya; y los dos, por haber leído la primera parte desta historia y haber entendido por ella el disparatado humor de don Quijote, con grandísimo gusto y con deseo de conocerle le atendían, con prosupuesto de seguirle el humor y conceder con él en cuanto les dijese, tratándole como a caballero andante los días que con ellos se detuviese, con todas las ceremonias acostumbradas en los libros de caballerías, que ellos habían leído, y aun les eran muy aficionados. En esto, llegó don Quijote, alzada la visera; y, dando muestras de apearse, acudió Sancho a tenerle el estribo; pero fue tan desgraciado que, al apearse del rucio, se le asió un pie en una soga del albarda, de tal modo que no fue posible desenredarle, antes quedó colgado dél, con la boca y los pechos en el suelo. Don Quijote, que no tenía en costumbre apearse sin que le tuviesen el estribo, pensando que ya Sancho había llegado a tenérsele, descargó de golpe el cuerpo, y llevóse tras sí la silla de Rocinante, que debía de estar mal cinchado, y la silla y él vinieron al suelo, no sin vergüenza suya y de muchas maldiciones que entre dientes echó al desdichado de Sancho, que aún todavía tenía el pie en la corma. El duque mandó a sus cazadores que acudiesen al caballero y al escudero, los cuales levantaron a don Quijote maltrecho de la caída, y, renqueando y como pudo, fue a hincar las rodillas ante los dos señores; pero el duque no lo consintió en ninguna manera, antes, apeándose de su caballo, fue a abrazar a don Quijote, diciéndole: -A mí me pesa, señor Caballero de la Triste Figura, que la primera que vuesa merced ha hecho en mi tierra haya sido tan mala como se ha visto; pero descuidos de escuderos suelen ser causa de otros peores sucesos. -El que yo he tenido en veros, valeroso príncipe -respondió don Quijote-, es imposible ser malo, aunque mi caída no parara hasta el profundo de los abismos, pues de allí me levantara y me sacara la gloria de haberos visto. Mi escudero, que Dios maldiga, mejor desata la lengua para decir malicias que ata y cincha una silla para que esté firme; pero, comoquiera que yo me halle, caído o levantado, a pie o a caballo, siempre estaré al servicio vuestro y al de mi señora la duquesa, digna consorte vuestra, y digna señora de la hermosura y universal princesa de la cortesía. -¡Pasito, mi señor don Quijote de la Mancha! -dijo el duque-, que adonde está mi señora doña Dulcinea del Toboso no es razón que se alaben otras fermosuras. Ya estaba a esta sazón libre Sancho Panza del lazo, y, hallándose allí cerca, antes que su amo respondiese, dijo: -No se puede negar, sino afirmar, que es muy hermosa mi señora Dulcinea del Toboso, pero donde menos se piensa se levanta la liebre; que yo he oído decir que esto que llaman naturaleza es como un alcaller que hace vasos de barro, y el que hace un vaso hermoso también puede hacer dos, y tres y ciento; dígolo porque mi señora la duquesa a fee que no va en zaga a mi ama la señora Dulcinea del Toboso. Volvióse don Quijote a la duquesa y dijo: -Vuestra grandeza imagine que no tuvo caballero andante en el mundo escudero más hablador ni más gracioso del que yo tengo, y él me sacará verdadero si algunos días quisiere vuestra gran celsitud servirse de mí. A lo que respondió la duquesa: -De que Sancho el bueno sea gracioso lo estimo yo en mucho, porque es señal que es discreto; que las gracias y los donaires, señor don Quijote, como vuesa merced bien sabe, no asientan sobre ingenios torpes; y, pues el buen Sancho es gracioso y donairoso, desde aquí le confirmo por discreto. -Y hablador -añadió don Quijote. -Tanto que mejor -dijo el duque-, porque muchas gracias no se pueden decir con pocas palabras. Y, porque no se nos vaya el tiempo en ellas, venga el gran Caballero de la Triste Figura... -De los Leones ha de decir vuestra alteza -dijo Sancho-, que ya no hay Triste Figura, ni figuro. -Sea el de los Leones -prosiguió el duque-. Digo que venga el señor Caballero de los Leones a un castillo mío que está aquí cerca, donde se le hará el acogimiento que a tan alta persona se debe justamente, y el que yo y la duquesa solemos hacer a todos los caballeros andantes que a él llegan. Ya en esto, Sancho había aderezado y cinchado bien la silla a Rocinante; y, subiendo en él don Quijote, y el duque en un hermoso caballo, pusieron a la duquesa en medio y encaminaron al castillo. Mandó la duquesa a Sancho que fuese junto a ella, porque gustaba infinito de oír sus discreciones. No se hizo de rogar Sancho, y entretejióse entre los tres, y hizo cuarto en la conversación, con gran gusto de la duquesa y del duque, que tuvieron a gran ventura acoger en su castillo tal caballero andante y tal escudero andado. Capítulo XXXI. Que trata de muchas y grandes cosas Suma era la alegría que llevaba consigo Sancho, viéndose, a su parecer, en privanza con la duquesa, porque se le figuraba que había de hallar en su castillo lo que en la casa de don Diego y en la de Basilio, siempre aficionado a la buena vida; y así, tomaba la ocasión por la melena en esto del regalarse cada y cuando que se le ofrecía. Cuenta, pues, la historia, que antes que a la casa de placer o castillo llegasen, se adelantó el duque y dio orden a todos sus criados del modo que habían de tratar a don Quijote; el cual, como llegó con la duquesa a las puertas del castillo, al instante salieron dél dos lacayos o palafreneros, vestidos hasta en pies de unas ropas que llaman de levantar, de finísimo raso carmesí, y, cogiendo a don Quijote en brazos, sin ser oído ni visto, le dijeron: -Vaya la vuestra grandeza a apear a mi señora la duquesa. Don Quijote lo hizo, y hubo grandes comedimientos entre los dos sobre el caso; pero, en efecto, venció la porfía de la duquesa, y no quiso decender o bajar del palafrén sino en los brazos del duque, diciendo que no se hallaba digna de dar a tan gran caballero tan inútil carga. En fin, salió el duque a apearla; y al entrar en un gran patio, llegaron dos hermosas doncellas y echaron sobre los hombros a don Quijote un gran manto de finísima escarlata, y en un instante se coronaron todos los corredores del patio de criados y criadas de aquellos señores, diciendo a grandes voces: -¡Bien sea venido la flor y la nata de los caballeros andantes! Y todos, o los más, derramaban pomos de aguas olorosas sobre don Quijote y sobre los duques, de todo lo cual se admiraba don Quijote; y aquél fue el primer día que de todo en todo conoció y creyó ser caballero andante verdadero, y no fantástico, viéndose tratar del mesmo modo que él había leído se trataban los tales caballeros en los pasados siglos. Sancho, desamparando al rucio, se cosió con la duquesa y se entró en el castillo; y, remordiéndole la conciencia de que dejaba al jumento solo, se llegó a una reverenda dueña, que con otras a recebir a la duquesa había salido, y con voz baja le dijo: -Señora González, o como es su gracia de vuesa merced... -Doña Rodríguez de Grijalba me llamo -respondió la dueña-. ¿Qué es lo que mandáis, hermano? A lo que respondió Sancho: -Querría que vuesa merced me la hiciese de salir a la puerta del castillo, donde hallará un asno rucio mío; vuesa merced sea servida de mandarle poner, o ponerle, en la caballeriza, porque el pobrecito es un poco medroso, y no se hallará a estar solo en ninguna de las maneras. -Si tan discreto es el amo como el mozo -respondió la dueña-, ¡medradas estamos! Andad, hermano, mucho de enhoramala para vos y para quien acá os trujo, y tened cuenta con vuestro jumento, que las dueñas desta casa no estamos acostumbradas a semejantes haciendas. -Pues en verdad -respondió Sancho- que he oído yo decir a mi señor, que es zahorí de las historias, contando aquella de Lanzarote, cuando de Bretaña vino, que damas curaban dél, y dueñas del su rocino; y que en el particular de mi asno, que no le trocara yo con el rocín del señor Lanzarote. -Hermano, si sois juglar -replicó la dueña-, guardad vuestras gracias para donde lo parezcan y se os paguen, que de mi no podréis llevar sino una higa. -¡Aun bien -respondió Sancho- que será bien madura, pues no perderá vuesa merced la quínola de sus años por punto menos! -Hijo de puta -dijo la dueña, toda ya encendida en cólera-, si soy vieja o no, a Dios daré la cuenta, que no a vos, bellaco, harto de ajos. Y esto dijo en voz tan alta, que lo oyó la duquesa; y, volviendo y viendo a la dueña tan alborotada y tan encarnizados los ojos, le preguntó con quién las había. -Aquí las he -respondió la dueña- con este buen hombre, que me ha pedido encarecidamente que vaya a poner en la caballeriza a un asno suyo que está a la puerta del castillo, trayéndome por ejemplo que así lo hicieron no sé dónde, que unas damas curaron a un tal Lanzarote, y unas dueñas a su rocino, y, sobre todo, por buen término me ha llamado vieja. -Eso tuviera yo por afrenta -respondió la duquesa-, más que cuantas pudieran decirme. Y, hablando con Sancho, le dijo: -Advertid, Sancho amigo, que doña Rodríguez es muy moza, y que aquellas tocas más las trae por autoridad y por la usanza que por los años. -Malos sean los que me quedan por vivir -respondió Sancho-, si lo dije por tanto; sólo lo dije porque es tan grande el cariño que tengo a mi jumento, que me pareció que no podía encomendarle a persona más caritativa que a la señora doña Rodríguez. Don Quijote, que todo lo oía, le dijo: -¿Pláticas son éstas, Sancho, para este lugar? -Señor -respondió Sancho-, cada uno ha de hablar de su menester dondequiera que estuviere; aquí se me acordó del rucio, y aquí hablé dél; y si en la caballeriza se me acordara, allí hablara. A lo que dijo el duque: -Sancho está muy en lo cierto, y no hay que culparle en nada; al rucio se le dará recado a pedir de boca, y descuide Sancho, que se le tratará como a su mesma persona. Con estos razonamientos, gustosos a todos sino a don Quijote, llegaron a lo alto y entraron a don Quijote en una sala adornada de telas riquísimas de oro y de brocado; seis doncellas le desarmaron y sirvieron de pajes, todas industriadas y advertidas del duque y de la duquesa de lo que habían de hacer, y de cómo habían de tratar a don Quijote, para que imaginase y viese que le trataban como caballero andante. Quedó don Quijote, después de desarmado, en sus estrechos greguescos y en su jubón de camuza, seco, alto, tendido, con las quijadas, que por de dentro se besaba la una con la otra; figura que, a no tener cuenta las doncellas que le servían con disimular la risa -que fue una de las precisas órdenes que sus señores les habían dado-, reventaran riendo. Pidiéronle que se dejase desnudar para una camisa, pero nunca lo consintió, diciendo que la honestidad parecía tan bien en los caballeros andantes como la valentía. Con todo, dijo que diesen la camisa a Sancho, y, encerrándose con él en una cuadra donde estaba un rico lecho, se desnudó y vistió la camisa; y, viéndose solo con Sancho, le dijo: -Dime, truhán moderno y majadero antiguo: ¿parécete bien deshonrar y afrentar a una dueña tan veneranda y tan digna de respeto como aquélla? ¿Tiempos eran aquéllos para acordarte del rucio, o señores son éstos para dejar mal pasar a las bestias, tratando tan elegantemente a sus dueños? Por quien Dios es, Sancho, que te reportes, y que no descubras la hilaza de manera que caigan en la cuenta de que eres de villana y grosera tela tejido. Mira, pecador de ti, que en tanto más es tenido el señor cuanto tiene más honrados y bien nacidos criados, y que una de las ventajas mayores que llevan los príncipes a los demás hombres es que se sirven de criados tan buenos como ellos. ¿No adviertes, angustiado de ti, y malaventurado de mí, que si veen que tú eres un grosero villano, o un mentecato gracioso, pensarán que yo soy algún echacuervos, o algún caballero de mohatra? No, no, Sancho amigo, huye, huye destos inconvinientes, que quien tropieza en hablador y en gracioso, al primer puntapié cae y da en truhán desgraciado. Enfrena la lengua, considera y rumia las palabras antes que te salgan de la boca, y advierte que hemos llegado a parte donde, con el favor de Dios y valor de mi brazo, hemos de salir mejorados en tercio y quinto en fama y en hacienda. Sancho le prometió con muchas veras de coserse la boca, o morderse la lengua, antes de hablar palabra que no fuese muy a propósito y bien considerada, como él se lo mandaba, y que descuidase acerca de lo tal, que nunca por él se descubriría quién ellos eran. Vistióse don Quijote, púsose su tahalí con su espada, echóse el mantón de escarlata a cuestas, púsose una montera de raso verde que las doncellas le dieron, y con este adorno salió a la gran sala, adonde halló a las doncellas puestas en ala, tantas a una parte como a otra, y todas con aderezo de darle aguamanos, la cual le dieron con muchas reverencias y ceremonias. Luego llegaron doce pajes con el maestresala, para llevarle a comer, que ya los señores le aguardaban. Cogiéronle en medio, y, lleno de pompa y majestad, le llevaron a otra sala, donde estaba puesta una rica mesa con solos cuatro servicios. La duquesa y el duque salieron a la puerta de la sala a recebirle, y con ellos un grave eclesiástico, destos que gobiernan las casas de los príncipes; destos que, como no nacen príncipes, no aciertan a enseñar cómo lo han de ser los que lo son; destos que quieren que la grandeza de los grandes se mida con la estrecheza de sus ánimos; destos que, queriendo mostrar a los que ellos gobiernan a ser limitados, les hacen ser miserables; destos tales, digo que debía de ser el grave religioso que con los duques salió a recebir a don Quijote. Hiciéronse mil corteses comedimientos, y, finalmente, cogiendo a don Quijote en medio, se fueron a sentar a la mesa. Convidó el duque a don Quijote con la cabecera de la mesa, y aunque él lo rehusó, las importunaciones del duque fueron tantas que la hubo de tomar. El eclesiástico se sentó frontero, y el duque y la duquesa a los dos lados. A todo estaba presente Sancho, embobado y atónito de ver la honra que a su señor aquellos príncipes le hacían; y, viendo las muchas ceremonias y ruegos que pasaron entre el duque y don Quijote para hacerle sentar a la cabecera de la mesa, dijo: -Si sus mercedes me dan licencia, les contaré un cuento que pasó en mi pueblo acerca desto de los asientos. Apenas hubo dicho esto Sancho, cuando don Quijote tembló, creyendo sin duda alguna que había de decir alguna necedad. Miróle Sancho y entendióle, y dijo: -No tema vuesa merced, señor mío, que yo me desmande, ni que diga cosa que no venga muy a pelo, que no se me han olvidado los consejos que poco ha vuesa merced me dio sobre el hablar mucho o poco, o bien o mal. -Yo no me acuerdo de nada, Sancho -respondió don Quijote-; di lo que quisieres, como lo digas presto. -Pues lo que quiero decir -dijo Sancho- es tan verdad, que mi señor don Quijote, que está presente, no me dejará mentir. -Por mí -replicó don Quijote-, miente tú, Sancho, cuanto quisieres, que yo no te iré a la mano, pero mira lo que vas a decir. -Tan mirado y remirado lo tengo, que a buen salvo está el que repica, como se verá por la obra. -Bien será -dijo don Quijote- que vuestras grandezas manden echar de aquí a este tonto, que dirá mil patochadas. -Por vida del duque -dijo la duquesa-, que no se ha de apartar de mí Sancho un punto: quiérole yo mucho, porque sé que es muy discreto. -Discretos días -dijo Sancho- viva vuestra santidad por el buen crédito que de mí tiene, aunque en mí no lo haya. Y el cuento que quiero decir es éste: «Convidó un hidalgo de mi pueblo, muy rico y principal, porque venía de los Ãlamos de Medina del Campo, que casó con doña Mencía de Quiñones, que fue hija de don Alonso de Marañón, caballero del hábito de Santiago, que se ahogó en la Herradura, por quien hubo aquella pendencia años ha en nuestro lugar, que, a lo que entiendo, mi señor don Quijote se halló en ella, de donde salió herido Tomasillo el Travieso, el hijo de Balbastro el herrero...» ¿No es verdad todo esto, señor nuestro amo? Dígalo, por su vida, porque estos señores no me tengan por algún hablador mentiroso. -Hasta ahora -dijo el eclesiástico-, más os tengo por hablador que por mentiroso, pero de aquí adelante no sé por lo que os tendré. -Tú das tantos testigos, Sancho, y tantas señas, que no puedo dejar de decir que debes de decir verdad. Pasa adelante y acorta el cuento, porque llevas camino de no acabar en dos días. -No ha de acortar tal -dijo la duquesa-, por hacerme a mí placer; antes, le ha de contar de la manera que le sabe, aunque no le acabe en seis días; que si tantos fuesen, serían para mí los mejores que hubiese llevado en mi vida. -«Digo, pues, señores míos -prosiguió Sancho-, que este tal hidalgo, que yo conozco como a mis manos, porque no hay de mi casa a la suya un tiro de ballesta, convidó un labrador pobre, pero honrado.» -Adelante, hermano -dijo a esta sazón el religioso-, que camino lleváis de no parar con vuestro cuento hasta el otro mundo. -A menos de la mitad pararé, si Dios fuere servido -respondió Sancho-. «Y así, digo que, llegando el tal labrador a casa del dicho hidalgo convidador, que buen poso haya su ánima, que ya es muerto, y por más señas dicen que hizo una muerte de un ángel, que yo no me hallé presente, que había ido por aquel tiempo a segar a Tembleque...» -Por vida vuestra, hijo, que volváis presto de Tembleque, y que, sin enterrar al hidalgo, si no queréis hacer más exequias, acabéis vuestro cuento. -«Es, pues, el caso -replicó Sancho- que, estando los dos para asentarse a la mesa, que parece que ahora los veo más que nunca...» Gran gusto recebían los duques del disgusto que mostraba tomar el buen religioso de la dilación y pausas con que Sancho contaba su cuento, y don Quijote se estaba consumiendo en cólera y en rabia. -«Digo, así -dijo Sancho-, que, estando, como he dicho, los dos para sentarse a la mesa, el labrador porfiaba con el hidalgo que tomase la cabecera de la mesa, y el hidalgo porfiaba también que el labrador la tomase, porque en su casa se había de hacer lo que él mandase; pero el labrador, que presumía de cortés y bien criado, jamás quiso, hasta que el hidalgo, mohíno, poniéndole ambas manos sobre los hombros, le hizo sentar por fuerza, diciéndole: ''Sentaos, majagranzas, que adondequiera que yo me siente será vuestra cabecera''.» Y éste es el cuento, y en verdad que creo que no ha sido aquí traído fuera de propósito. Púsose don Quijote de mil colores, que sobre lo moreno le jaspeaban y se le parecían; los señores disimularon la risa, porque don Quijote no acabase de correrse, habiendo entendido la malicia de Sancho; y, por mudar de plática y hacer que Sancho no prosiguiese con otros disparates, preguntó la duquesa a don Quijote que qué nuevas tenía de la señora Dulcinea, y que si le había enviado aquellos días algunos presentes de gigantes o malandrines, pues no podía dejar de haber vencido muchos. A lo que don Quijote respondió: -Señora mía, mis desgracias, aunque tuvieron principio, nunca tendrán fin. Gigantes he vencido, y follones y malandrines le he enviado, pero ¿adónde la habían de hallar, si está encantada y vuelta en la más fea labradora que imaginar se puede? -No sé -dijo Sancho Panza-, a mí me parece la más hermosa criatura del mundo; a lo menos, en la ligereza y en el brincar bien sé yo que no dará ella la ventaja a un volteador; a buena fe, señora duquesa, así salta desde el suelo sobre una borrica como si fuera un gato. -¿Habéisla visto vos encantada, Sancho? -preguntó el duque. -Y ¡cómo si la he visto! -respondió Sancho-. Pues, ¿quién diablos sino yo fue el primero que cayó en el achaque del encantorio? ¡Tan encantada está como mi padre! El eclesiástico, que oyó decir de gigantes, de follones y de encantos, cayó en la cuenta de que aquél debía de ser don Quijote de la Mancha, cuya historia leía el duque de ordinario, y él se lo había reprehendido muchas veces, diciéndole que era disparate leer tales disparates; y, enterándose ser verdad lo que sospechaba, con mucha cólera, hablando con el duque, le dijo: -Vuestra Excelencia, señor mío, tiene que dar cuenta a Nuestro Señor de lo que hace este buen hombre. Este don Quijote, o don Tonto, o como se llama, imagino yo que no debe de ser tan mentecato como Vuestra Excelencia quiere que sea, dándole ocasiones a la mano para que lleve adelante sus sandeces y vaciedades. Y, volviendo la plática a don Quijote, le dijo: -Y a vos, alma de cántaro, ¿quién os ha encajado en el celebro que sois caballero andante y que vencéis gigantes y prendéis malandrines? Andad en hora buena, y en tal se os diga: volveos a vuestra casa, y criad vuestros hijos, si los tenéis, y curad de vuestra hacienda, y dejad de andar vagando por el mundo, papando viento y dando que reír a cuantos os conocen y no conocen. ¿En dónde, nora tal, habéis vos hallado que hubo ni hay ahora caballeros andantes? ¿Dónde hay gigantes en España, o malandrines en la Mancha, ni Dulcineas encantadas, ni toda la caterva de las simplicidades que de vos se cuentan? Atento estuvo don Quijote a las razones de aquel venerable varón, y, viendo que ya callaba, sin guardar respeto a los duques, con semblante airado y alborotado rostro, se puso en pie y dijo... Pero esta respuesta capítulo por sí merece. Capítulo XXXII. De la respuesta que dio don Quijote a su reprehensor, con otros graves y graciosos sucesos Levantado, pues, en pie don Quijote, temblando de los pies a la cabeza como azogado, con presurosa y turbada lengua, dijo: -El lugar donde estoy, y la presencia ante quien me hallo y el respeto que siempre tuve y tengo al estado que vuesa merced profesa tienen y atan las manos de mi justo enojo; y, así por lo que he dicho como por saber que saben todos que las armas de los togados son las mesmas que las de la mujer, que son la lengua, entraré con la mía en igual batalla con vuesa merced, de quien se debía esperar antes buenos consejos que infames vituperios. Las reprehensiones santas y bien intencionadas otras circunstancias requieren y otros puntos piden: a lo menos, el haberme reprehendido en público y tan ásperamente ha pasado todos los límites de la buena reprehensión, pues las primeras mejor asientan sobre la blandura que sobre la aspereza, y no es bien que, sin tener conocimiento del pecado que se reprehende, llamar al pecador, sin más ni más, mentecato y tonto. Si no, dígame vuesa merced: ¿por cuál de las mentecaterías que en mí ha visto me condena y vitupera, y me manda que me vaya a mi casa a tener cuenta en el gobierno della y de mi mujer y de mis hijos, sin saber si la tengo o los tengo? ¿No hay más sino a troche moche entrarse por las casas ajenas a gobernar sus dueños, y, habiéndose criado algunos en la estrecheza de algún pupilaje, sin haber visto más mundo que el que puede contenerse en veinte o treinta leguas de distrito, meterse de rondón a dar leyes a la caballería y a juzgar de los caballeros andantes? ¿Por ventura es asumpto vano o es tiempo mal gastado el que se gasta en vagar por el mundo, no buscando los regalos dél, sino las asperezas por donde los buenos suben al asiento de la inmortalidad? Si me tuvieran por tonto los caballeros, los magníficos, los generosos, los altamente nacidos, tuviéralo por afrenta inreparable; pero de que me tengan por sandio los estudiantes, que nunca entraron ni pisaron las sendas de la caballería, no se me da un ardite: caballero soy y caballero he de morir si place al Altísimo. Unos van por el ancho campo de la ambición soberbia; otros, por el de la adulación servil y baja; otros, por el de la hipocresía engañosa, y algunos, por el de la verdadera religión; pero yo, inclinado de mi estrella, voy por la angosta senda de la caballería andante, por cuyo ejercicio desprecio la hacienda, pero no la honra. Yo he satisfecho agravios, enderezado tuertos, castigado insolencias, vencido gigantes y atropellado vestiglos; yo soy enamorado, no más de porque es forzoso que los caballeros andantes lo sean; y, siéndolo, no soy de los enamorados viciosos, sino de los platónicos continentes. Mis intenciones siempre las enderezo a buenos fines, que son de hacer bien a todos y mal a ninguno; si el que esto entiende, si el que esto obra, si el que desto trata merece ser llamado bobo, díganlo vuestras grandezas, duque y duquesa excelentes. -¡Bien, por Dios! -dijo Sancho-. No diga más vuestra merced, señor y amo mío, en su abono, porque no hay más que decir, ni más que pensar, ni más que perseverar en el mundo. Y más, que, negando este señor, como ha negado, que no ha habido en el mundo, ni los hay, caballeros andantes, ¿qué mucho que no sepa ninguna de las cosas que ha dicho? -¿Por ventura -dijo el eclesiástico- sois vos, hermano, aquel Sancho Panza que dicen, a quien vuestro amo tiene prometida una ínsula? -Sí soy -respondió Sancho-; y soy quien la merece tan bien como otro cualquiera; soy quien "júntate a los buenos y serás uno dellos", y soy yo de aquellos "no con quien naces, sino con quien paces", y de los "quien a buen árbol se arrima, buena sombra le cobija". Yo me he arrimado a buen señor, y ha muchos meses que ando en su compañía, y he de ser otro como él, Dios queriendo; y viva él y viva yo: que ni a él le faltarán imperios que mandar ni a mí ínsulas que gobernar. -No, por cierto, Sancho amigo -dijo a esta sazón el duque-, que yo, en nombre del señor don Quijote, os mando el gobierno de una que tengo de nones, de no pequeña calidad. -Híncate de rodillas, Sancho -dijo don Quijote-, y besa los pies a Su Excelencia por la merced que te ha hecho. Hízolo así Sancho; lo cual visto por el eclesiástico, se levantó de la mesa, mohíno además, diciendo: -Por el hábito que tengo, que estoy por decir que es tan sandio Vuestra Excelencia como estos pecadores. ¡Mirad si no han de ser ellos locos, pues los cuerdos canonizan sus locuras! Quédese Vuestra Excelencia con ellos; que, en tanto que estuvieren en casa, me estaré yo en la mía, y me escusaré de reprehender lo que no puedo remediar. Y, sin decir más ni comer más, se fue, sin que fuesen parte a detenerle los ruegos de los duques; aunque el duque no le dijo mucho, impedido de la risa que su impertinente cólera le había causado. Acabó de reír y dijo a don Quijote: -Vuesa merced, señor Caballero de los Leones, ha respondido por sí tan altamente que no le queda cosa por satisfacer deste que, aunque parece agravio, no lo es en ninguna manera; porque, así como no agravian las mujeres, no agravian los eclesiásticos, como vuesa merced mejor sabe. -Así es -respondió don Quijote-, y la causa es que el que no puede ser agraviado no puede agraviar a nadie. Las mujeres, los niños y los eclesiásticos, como no pueden defenderse, aunque sean ofendidos, no pueden ser afrentados; porque entre el agravio y la afrenta hay esta diferencia, como mejor Vuestra Excelencia sabe: la afrenta viene de parte de quien la puede hacer, y la hace y la sustenta; el agravio puede venir de cualquier parte, sin que afrente. Sea ejemplo: está uno en la calle descuidado, llegan diez con mano armada, y, dándole de palos, pone mano a la espada y hace su deber, pero la muchedumbre de los contrarios se le opone, y no le deja salir con su intención, que es de vengarse; este tal queda agraviado, pero no afrentado. Y lo mesmo confirmará otro ejemplo: está uno vuelto de espaldas, llega otro y dale de palos, y en dándoselos huye y no espera, y el otro le sigue y no alcanza; este que recibió los palos, recibió agravio, mas no afrenta, porque la afrenta ha de ser sustentada. Si el que le dio los palos, aunque se los dio a hurtacordel, pusiera mano a su espada y se estuviera quedo, haciendo rostro a su enemigo, quedara el apaleado agraviado y afrentado juntamente: agraviado, porque le dieron a traición; afrentado, porque el que le dio sustentó lo que había hecho, sin volver las espaldas y a pie quedo. Y así, según las leyes del maldito duelo, yo puedo estar agraviado, mas no afrentado; porque los niños no sienten, ni las mujeres, ni pueden huir, ni tienen para qué esperar, y lo mesmo los constituidos en la sacra religión, porque estos tres géneros de gente carecen de armas ofensivas y defensivas; y así, aunque naturalmente estén obligados a defenderse, no lo están para ofender a nadie. Y, aunque poco ha dije que yo podía estar agraviado, agora digo que no, en ninguna manera, porque quien no puede recebir afrenta, menos la puede dar; por las cuales razones yo no debo sentir, ni siento, las que aquel buen hombre me ha dicho; sólo quisiera que esperara algún poco, para darle a entender en el error en que está en pensar y decir que no ha habido, ni los hay, caballeros andantes en el mundo; que si lo tal oyera Amadís, o uno de los infinitos de su linaje, yo sé que no le fuera bien a su merced. -Eso juro yo bien -dijo Sancho-: cuchillada le hubieran dado que le abrieran de arriba abajo como una granada, o como a un melón muy maduro. ¡Bonitos eran ellos para sufrir semejantes cosquillas! Para mi santiguada, que tengo por cierto que si Reinaldos de Montalbán hubiera oído estas razones al hombrecito, tapaboca le hubiera dado que no hablara más en tres años. ¡No, sino tomárase con ellos y viera cómo escapaba de sus manos! Perecía de risa la duquesa en oyendo hablar a Sancho, y en su opinión le tenía por más gracioso y por más loco que a su amo; y muchos hubo en aquel tiempo que fueron deste mismo parecer. Finalmente, don Quijote se sosegó, y la comida se acabó, y, en levantando los manteles, llegaron cuatro doncellas, la una con una fuente de plata, y la otra con un aguamanil, asimismo de plata, y la otra con dos blanquísimas y riquísimas toallas al hombro, y la cuarta descubiertos los brazos hasta la mitad, y en sus blancas manos -que sin duda eran blancas- una redonda pella de jabón napolitano. Llegó la de la fuente, y con gentil donaire y desenvoltura encajó la fuente debajo de la barba de don Quijote; el cual, sin hablar palabra, admirado de semejante ceremonia, creyendo que debía ser usanza de aquella tierra en lugar de las manos lavar las barbas, y así tendió la suya todo cuanto pudo, y al mismo punto comenzó a llover el aguamanil, y la doncella del jabón le manoseó las barbas con mucha priesa, levantando copos de nieve, que no eran menos blancas las jabonaduras, no sólo por las barbas, mas por todo el rostro y por los ojos del obediente caballero, tanto, que se los hicieron cerrar por fuerza. El duque y la duquesa, que de nada desto eran sabidores, estaban esperando en qué había de parar tan extraordinario lavatorio. La doncella barbera, cuando le tuvo con un palmo de jabonadura, fingió que se le había acabado el agua, y mandó a la del aguamanil fuese por ella, que el señor don Quijote esperaría. Hízolo así, y quedó don Quijote con la más estraña figura y más para hacer reír que se pudiera imaginar. Mirábanle todos los que presentes estaban, que eran muchos, y como le veían con media vara de cuello, más que medianamente moreno, los ojos cerrados y las barbas llenas de jabón, fue gran maravilla y mucha discreción poder disimular la risa; las doncellas de la burla tenían los ojos bajos, sin osar mirar a sus señores; a ellos les retozaba la cólera y la risa en el cuerpo, y no sabían a qué acudir: o a castigar el atrevimiento de las muchachas, o darles premio por el gusto que recibían de ver a don Quijote de aquella suerte. Finalmente, la doncella del aguamanil vino, y acabaron de lavar a don Quijote, y luego la que traía las toallas le limpió y le enjugó muy reposadamente; y, haciéndole todas cuatro a la par una grande y profunda inclinación y reverencia, se querían ir; pero el duque, porque don Quijote no cayese en la burla, llamó a la doncella de la fuente, diciéndole: -Venid y lavadme a mí, y mirad que no se os acabe el agua. La muchacha, aguda y diligente, llegó y puso la fuente al duque como a don Quijote, y, dándose prisa, le lavaron y jabonaron muy bien, y, dejándole enjuto y limpio, haciendo reverencias se fueron. Después se supo que había jurado el duque que si a él no le lavaran como a don Quijote, había de castigar su desenvoltura, lo cual habían enmendado discretamente con haberle a él jabonado. Estaba atento Sancho a las ceremonias de aquel lavatorio, y dijo entre sí: -¡Válame Dios! ¿Si será también usanza en esta tierra lavar las barbas a los escuderos como a los caballeros? Porque, en Dios y en mi ánima que lo he bien menester, y aun que si me las rapasen a navaja, lo tendría a más beneficio. -¿Qué decís entre vos, Sancho? -preguntó la duquesa. -Digo, señora -respondió él-, que en las cortes de los otros príncipes siempre he oído decir que en levantando los manteles dan agua a las manos, pero no lejía a las barbas; y que por eso es bueno vivir mucho, por ver mucho; aunque también dicen que el que larga vida vive mucho mal ha de pasar, puesto que pasar por un lavatorio de éstos antes es gusto que trabajo. -No tengáis pena, amigo Sancho -dijo la duquesa-, que yo haré que mis doncellas os laven, y aun os metan en colada, si fuere menester. -Con las barbas me contento -respondió Sancho-, por ahora a lo menos, que andando el tiempo, Dios dijo lo que será. -Mirad, maestresala -dijo la duquesa-, lo que el buen Sancho pide, y cumplidle su voluntad al pie de la letra. El maestresala respondió que en todo sería servido el señor Sancho, y con esto se fue a comer, y llevó consigo a Sancho, quedándose a la mesa los duques y don Quijote, hablando en muchas y diversas cosas; pero todas tocantes al ejercicio de las armas y de la andante caballería. La duquesa rogó a don Quijote que le delinease y describiese, pues parecía tener felice memoria, la hermosura y facciones de la señora Dulcinea del Toboso; que, según lo que la fama pregonaba de su belleza, tenía por entendido que debía de ser la más bella criatura del orbe, y aun de toda la Mancha. Sospiró don Quijote, oyendo lo que la duquesa le mandaba, y dijo: -Si yo pudiera sacar mi corazón y ponerle ante los ojos de vuestra grandeza, aquí, sobre esta mesa y en un plato, quitara el trabajo a mi lengua de decir lo que apenas se puede pensar, porque Vuestra Excelencia la viera en él toda retratada; pero, ¿para qué es ponerme yo ahora a delinear y describir punto por punto y parte por parte la hermosura de la sin par Dulcinea, siendo carga digna de otros hombros que de los míos, empresa en quien se debían ocupar los pinceles de Parrasio, de Timantes y de Apeles, y los buriles de Lisipo, para pintarla y grabarla en tablas, en mármoles y en bronces, y la retórica ciceroniana y demostina para alabarla? -¿Qué quiere decir demostina, señor don Quijote -preguntó la duquesa-, que es vocablo que no le he oído en todos los días de mi vida? -Retórica demostina -respondió don Quijote- es lo mismo que decir retórica de Demóstenes, como ciceroniana, de Cicerón, que fueron los dos mayores retóricos del mundo. -Así es -dijo el duque-, y habéis andado deslumbrada en la tal pregunta. Pero, con todo eso, nos daría gran gusto el señor don Quijote si nos la pintase; que a buen seguro que, aunque sea en rasguño y bosquejo, que ella salga tal, que la tengan invidia las más hermosas. -Sí hiciera, por cierto -respondió don Quijote-, si no me la hubiera borrado de la idea la desgracia que poco ha que le sucedió, que es tal, que más estoy para llorarla que para describirla; porque habrán de saber vuestras grandezas que, yendo los días pasados a besarle las manos, y a recebir su bendición, beneplácito y licencia para esta tercera salida, hallé otra de la que buscaba: halléla encantada y convertida de princesa en labradora, de hermosa en fea, de ángel en diablo, de olorosa en pestífera, de bien hablada en rústica, de reposada en brincadora, de luz en tinieblas, y, finalmente, de Dulcinea del Toboso en una villana de Sayago. -¡Válame Dios! -dando una gran voz, dijo a este instante el duque-. ¿Quién ha sido el que tanto mal ha hecho al mundo? ¿Quién ha quitado dél la belleza que le alegraba, el donaire que le entretenía y la honestidad que le acreditaba? -¿Quién? -respondió don Quijote-. ¿Quién puede ser sino algún maligno encantador de los muchos invidiosos que me persiguen? Esta raza maldita, nacida en el mundo para escurecer y aniquilar las hazañas de los buenos, y para dar luz y levantar los fechos de los malos. Perseguido me han encantadores, encantadores me persiguen y encantadores me persiguirán hasta dar conmigo y con mis altas caballerías en el profundo abismo del olvido; y en aquella parte me dañan y hieren donde veen que más lo siento, porque quitarle a un caballero andante su dama es quitarle los ojos con que mira, y el sol con que se alumbra, y el sustento con que se mantiene. Otras muchas veces lo he dicho, y ahora lo vuelvo a decir: que el caballero andante sin dama es como el árbol sin hojas, el edificio sin cimiento y la sombra sin cuerpo de quien se cause. -No hay más que decir -dijo la duquesa-; pero si, con todo eso, hemos de dar crédito a la historia que del señor don Quijote de pocos días a esta parte ha salido a la luz del mundo, con general aplauso de las gentes, della se colige, si mal no me acuerdo, que nunca vuesa merced ha visto a la señora Dulcinea, y que esta tal señora no es en el mundo, sino que es dama fantástica, que vuesa merced la engendró y parió en su entendimiento, y la pintó con todas aquellas gracias y perfeciones que quiso. -En eso hay mucho que decir -respondió don Quijote-. Dios sabe si hay Dulcinea o no en el mundo, o si es fantástica o no es fantástica; y éstas no son de las cosas cuya averiguación se ha de llevar hasta el cabo. Ni yo engendré ni parí a mi señora, puesto que la contemplo como conviene que sea una dama que contenga en sí las partes que puedan hacerla famosa en todas las del mundo, como son: hermosa, sin tacha, grave sin soberbia, amorosa con honestidad, agradecida por cortés, cortés por bien criada, y, finalmente, alta por linaje, a causa que sobre la buena sangre resplandece y campea la hermosura con más grados de perfeción que en las hermosas humildemente nacidas. -Así es -dijo el duque-; pero hame de dar licencia el señor don Quijote para que diga lo que me fuerza a decir la historia que de sus hazañas he leído, de donde se infiere que, puesto que se conceda que hay Dulcinea, en el Toboso o fuera dél, y que sea hermosa en el sumo grado que vuesa merced nos la pinta, en lo de la alteza del linaje no corre parejas con las Orianas, con las Alastrajareas, con las Madásimas, ni con otras deste jaez, de quien están llenas las historias que vuesa merced bien sabe. -A eso puedo decir -respondió don Quijote- que Dulcinea es hija de sus obras, y que las virtudes adoban la sangre, y que en más se ha de estimar y tener un humilde virtuoso que un vicioso levantado; cuanto más, que Dulcinea tiene un jirón que la puede llevar a ser reina de corona y ceptro; que el merecimiento de una mujer hermosa y virtuosa a hacer mayores milagros se estiende, y, aunque no formalmente, virtualmente tiene en sí encerradas mayores venturas. -Digo, señor don Quijote -dijo la duquesa-, que en todo cuanto vuestra merced dice va con pie de plomo, y, como suele decirse, con la sonda en la mano; y que yo desde aquí adelante creeré y haré creer a todos los de mi casa, y aun al duque mi señor, si fuere menester, que hay Dulcinea en el Toboso, y que vive hoy día, y es hermosa, y principalmente nacida y merecedora que un tal caballero como es el señor don Quijote la sirva; que es lo más que puedo ni sé encarecer. Pero no puedo dejar de formar un escrúpulo, y tener algún no sé qué de ojeriza contra Sancho Panza: el escrúpulo es que dice la historia referida que el tal Sancho Panza halló a la tal señora Dulcinea, cuando de parte de vuestra merced le llevó una epístola, ahechando un costal de trigo, y, por más señas, dice que era rubión: cosa que me hace dudar en la alteza de su linaje. A lo que respondió don Quijote: -Señora mía, sabrá la vuestra grandeza que todas o las más cosas que a mí me suceden van fuera de los términos ordinarios de las que a los otros caballeros andantes acontecen, o ya sean encaminadas por el querer inescrutable de los hados, o ya vengan encaminadas por la malicia de algún encantador invidioso; y, como es cosa ya averiguada que todos o los más caballeros andantes y famosos, uno tenga gracia de no poder ser encantado, otro de ser de tan impenetrables carnes que no pueda ser herido, como lo fue el famoso Roldán, uno de los doce Pares de Francia, de quien se cuenta que no podía ser ferido sino por la planta del pie izquierdo, y que esto había de ser con la punta de un alfiler gordo, y no con otra suerte de arma alguna; y así, cuando Bernardo del Carpio le mató en Roncesvalles, viendo que no le podía llagar con fierro, le levantó del suelo entre los brazos y le ahogó, acordándose entonces de la muerte que dio Hércules a Anteón, aquel feroz gigante que decían ser hijo de la Tierra. Quiero inferir de lo dicho, que podría ser que yo tuviese alguna gracia déstas, no del no poder ser ferido, porque muchas veces la experiencia me ha mostrado que soy de carnes blandas y no nada impenetrables, ni la de no poder ser encantado, que ya me he visto metido en una jaula, donde todo el mundo no fuera poderoso a encerrarme, si no fuera a fuerzas de encantamentos; pero, pues de aquél me libré, quiero creer que no ha de haber otro alguno que me empezca; y así, viendo estos encantadores que con mi persona no pueden usar de sus malas mañas, vénganse en las cosas que más quiero, y quieren quitarme la vida maltratando la de Dulcinea, por quien yo vivo; y así, creo que, cuando mi escudero le llevó mi embajada, se la convirtieron en villana y ocupada en tan bajo ejercicio como es el de ahechar trigo; pero ya tengo yo dicho que aquel trigo ni era rubión ni trigo, sino granos de perlas orientales; y para prueba desta verdad quiero decir a vuestras magnitudes cómo, viniendo poco ha por el Toboso, jamás pude hallar los palacios de Dulcinea; y que otro día, habiéndola visto Sancho, mi escudero, en su mesma figura, que es la más bella del orbe, a mí me pareció una labradora tosca y fea, y no nada bien razonada, siendo la discreción del mundo; y, pues yo no estoy encantado, ni lo puedo estar, según buen discurso, ella es la encantada, la ofendida y la mudada, trocada y trastrocada, y en ella se han vengado de mí mis enemigos, y por ella viviré yo en perpetuas lágrimas, hasta verla en su prístino estado. Todo esto he dicho para que nadie repare en lo que Sancho dijo del cernido ni del ahecho de Dulcinea; que, pues a mí me la mudaron, no es maravilla que a él se la cambiasen. Dulcinea es principal y bien nacida, y de los hidalgos linajes que hay en el Toboso, que son muchos, antiguos y muy buenos, a buen seguro que no le cabe poca parte a la sin par Dulcinea, por quien su lugar será famoso y nombrado en los venideros siglos, como lo ha sido Troya por Elena, y España por la Cava, aunque con mejor título y fama. Por otra parte, quiero que entiendan vuestras señorías que Sancho Panza es uno de los más graciosos escuderos que jamás sirvió a caballero andante; tiene a veces unas simplicidades tan agudas, que el pensar si es simple o agudo causa no pequeño contento; tiene malicias que le condenan por bellaco, y descuidos que le confirman por bobo; duda de todo y créelo todo; cuando pienso que se va a despeñar de tonto, sale con unas discreciones, que le levantan al cielo. Finalmente, yo no le trocaría con otro escudero, aunque me diesen de añadidura una ciudad; y así, estoy en duda si será bien enviarle al gobierno de quien vuestra grandeza le ha hecho merced; aunque veo en él una cierta aptitud para esto de gobernar, que atusándole tantico el entendimiento, se saldría con cualquiera gobierno, como el rey con sus alcabalas; y más, que ya por muchas experiencias sabemos que no es menester ni mucha habilidad ni muchas letras para ser uno gobernador, pues hay por ahí ciento que apenas saber leer, y gobiernan como unos girifaltes; el toque está en que tengan buena intención y deseen acertar en todo; que nunca les faltará quien les aconseje y encamine en lo que han de hacer, como los gobernadores caballeros y no letrados, que sentencian con asesor. Aconsejaríale yo que ni tome cohecho, ni pierda derecho, y otras cosillas que me quedan en el estómago, que saldrán a su tiempo, para utilidad de Sancho y provecho de la ínsula que gobernare. A este punto llegaban de su coloquio el duque, la duquesa y don Quijote, cuando oyeron muchas voces y gran rumor de gente en el palacio; y a deshora entró Sancho en la sala, todo asustado, con un cernadero por babador, y tras él muchos mozos, o, por mejor decir, pícaros de cocina y otra gente menuda, y uno venía con un artesoncillo de agua, que en la color y poca limpieza mostraba ser de fregar; seguíale y perseguíale el de la artesa, y procuraba con toda solicitud ponérsela y encajársela debajo de las barbas, y otro pícaro mostraba querérselas lavar. -¿Qué es esto, hermanos? -preguntó la duquesa-. ¿Qué es esto? ¿Qué queréis a ese buen hombre? ¿Cómo y no consideráis que está electo gobernador? A lo que respondió el pícaro barbero: -No quiere este señor dejarse lavar, como es usanza, y como se la lavó el duque mi señor y el señor su amo. -Sí quiero -respondió Sancho con mucha cólera-, pero querría que fuese con toallas más limpias, con lejía mas clara y con manos no tan sucias; que no hay tanta diferencia de mí a mi amo, que a él le laven con agua de ángeles y a mí con lejía de diablos. Las usanzas de las tierras y de los palacios de los príncipes tanto son buenas cuanto no dan pesadumbre, pero la costumbre del lavatorio que aquí se usa peor es que de diciplinantes. Yo estoy limpio de barbas y no tengo necesidad de semejantes refrigerios; y el que se llegare a lavarme ni a tocarme a un pelo de la cabeza, digo, de mi barba, hablando con el debido acatamiento, le daré tal puñada que le deje el puño engastado en los cascos; que estas tales ceremonias y jabonaduras más parecen burlas que gasajos de huéspedes. Perecida de risa estaba la duquesa, viendo la cólera y oyendo las razones de Sancho, pero no dio mucho gusto a don Quijote verle tan mal adeliñado con la jaspeada toalla, y tan rodeado de tantos entretenidos de cocina; y así, haciendo una profunda reverencia a los duques, como que les pedía licencia para hablar, con voz reposada dijo a la canalla: -¡Hola, señores caballeros! Vuesas mercedes dejen al mancebo, y vuélvanse por donde vinieron, o por otra parte si se les antojare, que mi escudero es limpio tanto como otro, y esas artesillas son para él estrechas y penantes búcaros. Tomen mi consejo y déjenle, porque ni él ni yo sabemos de achaque de burlas. Cogióle la razón de la boca Sancho, y prosiguió diciendo: -¡No, sino lléguense a hacer burla del mostrenco, que así lo sufriré como ahora es de noche! Traigan aquí un peine, o lo que quisieren, y almohácenme estas barbas, y si sacaren dellas cosa que ofenda a la limpieza, que me trasquilen a cruces. A esta sazón, sin dejar la risa, dijo la duquesa: -Sancho Panza tiene razón en todo cuanto ha dicho, y la tendrá en todo cuanto dijere: él es limpio, y, como él dice, no tiene necesidad de lavarse; y si nuestra usanza no le contenta, su alma en su palma, cuanto más, que vosotros, ministros de la limpieza, habéis andado demasiadamente de remisos y descuidados, y no sé si diga atrevidos, a traer a tal personaje y a tales barbas, en lugar de fuentes y aguamaniles de oro puro y de alemanas toallas, artesillas y dornajos de palo y rodillas de aparadores. Pero, en fin, sois malos y mal nacidos, y no podéis dejar, como malandrines que sois, de mostrar la ojeriza que tenéis con los escuderos de los andantes caballeros. Creyeron los apicarados ministros, y aun el maestresala, que venía con ellos, que la duquesa hablaba de veras; y así, quitaron el cernadero del pecho de Sancho, y todos confusos y casi corridos se fueron y le dejaron; el cual, viéndose fuera de aquel, a su parecer, sumo peligro, se fue a hincar de rodillas ante la duquesa y dijo: -De grandes señoras, grandes mercedes se esperan; esta que la vuestra merced hoy me ha fecho no puede pagarse con menos, si no es con desear verme armado caballero andante, para ocuparme todos los días de mi vida en servir a tan alta señora. Labrador soy, Sancho Panza me llamo, casado soy, hijos tengo y de escudero sirvo: si con alguna destas cosas puedo servir a vuestra grandeza, menos tardaré yo en obedecer que vuestra señoría en mandar. -Bien parece, Sancho -respondió la duquesa-, que habéis aprendido a ser cortés en la escuela de la misma cortesía; bien parece, quiero decir, que os habéis criado a los pechos del señor don Quijote, que debe de ser la nata de los comedimientos y la flor de las ceremonias, o cirimonias, como vos decís. Bien haya tal señor y tal criado: el uno, por norte de la andante caballería; y el otro, por estrella de la escuderil fidelidad. Levantaos, Sancho amigo, que yo satisfaré vuestras cortesías con hacer que el duque mi señor, lo más presto que pudiere, os cumpla la merced prometida del gobierno. Con esto cesó la plática, y don Quijote se fue a reposar la siesta, y la duquesa pidió a Sancho que, si no tenía mucha gana de dormir, viniese a pasar la tarde con ella y con sus doncellas en una muy fresca sala. Sancho respondió que, aunque era verdad que tenía por costumbre dormir cuatro o cinco horas las siestas del verano, que, por servir a su bondad, él procuraría con todas sus fuerzas no dormir aquel día ninguna, y vendría obediente a su mandado, y fuese. El duque dio nuevas órdenes como se tratase a don Quijote como a caballero andante, sin salir un punto del estilo como cuentan que se trataban los antiguos caballeros. Capítulo XXXIII. De la sabrosa plática que la duquesa y sus doncellas pasaron con Sancho Panza, digna de que se lea y de que se note Cuenta, pues, la historia, que Sancho no durmió aquella siesta, sino que, por cumplir su palabra, vino en comiendo a ver a la duquesa; la cual, con el gusto que tenía de oírle, le hizo sentar junto a sí en una silla baja, aunque Sancho, de puro bien criado, no quería sentarse; pero la duquesa le dijo que se sentase como gobernador y hablase como escudero, puesto que por entrambas cosas merecía el mismo escaño del Cid Ruy Díaz Campeador. Encogió Sancho los hombros, obedeció y sentóse, y todas las doncellas y dueñas de la duquesa la rodearon, atentas, con grandísimo silencio, a escuchar lo que diría; pero la duquesa fue la que habló primero, diciendo: -Ahora que estamos solos, y que aquí no nos oye nadie, querría yo que el señor gobernador me asolviese ciertas dudas que tengo, nacidas de la historia que del gran don Quijote anda ya impresa; una de las cuales dudas es que, pues el buen Sancho nunca vio a Dulcinea, digo, a la señora Dulcinea del Toboso, ni le llevó la carta del señor don Quijote, porque se quedó en el libro de memoria en Sierra Morena, cómo se atrevió a fingir la respuesta, y aquello de que la halló ahechando trigo, siendo todo burla y mentira, y tan en daño de la buena opinión de la sin par Dulcinea, y todas que no vienen bien con la calidad y fidelidad de los buenos escuderos. A estas razones, sin responder con alguna, se levantó Sancho de la silla, y, con pasos quedos, el cuerpo agobiado y el dedo puesto sobre los labios, anduvo por toda la sala levantando los doseles; y luego, esto hecho, se volvió a sentar y dijo: -Ahora, señora mía, que he visto que no nos escucha nadie de solapa, fuera de los circunstantes, sin temor ni sobresalto responderé a lo que se me ha preguntado, y a todo aquello que se me preguntare; y lo primero que digo es que yo tengo a mi señor don Quijote por loco rematado, puesto que algunas veces dice cosas que, a mi parecer, y aun de todos aquellos que le escuchan, son tan discretas y por tan buen carril encaminadas, que el mesmo Satanás no las podría decir mejores; pero, con todo esto, verdaderamente y sin escrúpulo, a mí se me ha asentado que es un mentecato. Pues, como yo tengo esto en el magín, me atrevo a hacerle creer lo que no lleva pies ni cabeza, como fue aquello de la respuesta de la carta, y lo de habrá seis o ocho días, que aún no está en historia; conviene a saber: lo del encanto de mi señora doña Dulcinea, que le he dado a entender que está encantada, no siendo más verdad que por los cerros de Úbeda. Rogóle la duquesa que le contase aquel encantamento o burla, y Sancho se lo contó todo del mesmo modo que había pasado, de que no poco gusto recibieron los oyentes; y, prosiguiendo en su plática, dijo la duquesa: -De lo que el buen Sancho me ha contado me anda brincando un escrúpulo en el alma y un cierto susurro llega a mis oídos, que me dice: ''Pues don Quijote de la Mancha es loco, menguado y mentecato, y Sancho Panza su escudero lo conoce, y, con todo eso, le sirve y le sigue y va atenido a las vanas promesas suyas, sin duda alguna debe de ser él más loco y tonto que su amo; y, siendo esto así, como lo es, mal contado te será, señora duquesa, si al tal Sancho Panza le das ínsula que gobierne, porque el que no sabe gobernarse a sí, ¿cómo sabrá gobernar a otros?'' -Par Dios, señora -dijo Sancho-, que ese escrúpulo viene con parto derecho; pero dígale vuesa merced que hable claro, o como quisiere, que yo conozco que dice verdad: que si yo fuera discreto, días ha que había de haber dejado a mi amo. Pero ésta fue mi suerte, y ésta mi malandanza; no puedo más, seguirle tengo: somos de un mismo lugar, he comido su pan, quiérole bien, es agradecido, diome sus pollinos, y, sobre todo, yo soy fiel; y así, es imposible que nos pueda apartar otro suceso que el de la pala y azadón. Y si vuestra altanería no quisiere que se me dé el prometido gobierno, de menos me hizo Dios, y podría ser que el no dármele redundase en pro de mi conciencia; que, maguera tonto, se me entiende aquel refrán de ''por su mal le nacieron alas a la hormiga''; y aun podría ser que se fuese más aína Sancho escudero al cielo, que no Sancho gobernador. Tan buen pan hacen aquí como en Francia; y de noche todos los gatos son pardos, y asaz de desdichada es la persona que a las dos de la tarde no se ha desayunado; y no hay estómago que sea un palmo mayor que otro, el cual se puede llenar, como suele decirse, de paja y de heno; y las avecitas del campo tienen a Dios por su proveedor y despensero; y más calientan cuatro varas de paño de Cuenca que otras cuatro de límiste de Segovia; y al dejar este mundo y meternos la tierra adentro, por tan estrecha senda va el príncipe como el jornalero, y no ocupa más pies de tierra el cuerpo del Papa que el del sacristán, aunque sea más alto el uno que el otro; que al entrar en el hoyo todos nos ajustamos y encogemos, o nos hacen ajustar y encoger, mal que nos pese y a buenas noches. Y torno a decir que si vuestra señoría no me quisiere dar la ínsula por tonto, yo sabré no dárseme nada por discreto; y yo he oído decir que detrás de la cruz está el diablo, y que no es oro todo lo que reluce, y que de entre los bueyes, arados y coyundas sacaron al labrador Wamba para ser rey de España, y de entre los brocados, pasatiempos y riquezas sacaron a Rodrigo para ser comido de culebras, si es que las trovas de los romances antiguos no mienten. -Y ¡cómo que no mienten! -dijo a esta sazón doña Rodríguez la dueña, que era una de las escuchantes-: que un romance hay que dice que metieron al rey Rodrigo, vivo vivo, en una tumba llena de sapos, culebras y lagartos, y que de allí a dos días dijo el rey desde dentro de la tumba, con voz doliente y baja: Ya me comen, ya me comen por do más pecado había; y, según esto, mucha razón tiene este señor en decir que quiere más ser más labrador que rey, si le han de comer sabandijas. No pudo la duquesa tener la risa, oyendo la simplicidad de su dueña, ni dejó de admirarse en oír las razones y refranes de Sancho, a quien dijo: -Ya sabe el buen Sancho que lo que una vez promete un caballero procura cumplirlo, aunque le cueste la vida. El duque, mi señor y marido, aunque no es de los andantes, no por eso deja de ser caballero, y así, cumplirá la palabra de la prometida ínsula, a pesar de la invidia y de la malicia del mundo. Esté Sancho de buen ánimo, que cuando menos lo piense se verá sentado en la silla de su ínsula y en la de su estado, y empuñará su gobierno, que con otro de brocado de tres altos lo deseche. Lo que yo le encargo es que mire cómo gobierna sus vasallos, advirtiendo que todos son leales y bien nacidos. -Eso de gobernarlos bien -respondió Sancho- no hay para qué encargármelo, porque yo soy caritativo de mío y tengo compasión de los pobres; y a quien cuece y amasa, no le hurtes hogaza; y para mi santiguada que no me han de echar dado falso; soy perro viejo, y entiendo todo tus, tus, y sé despabilarme a sus tiempos, y no consiento que me anden musarañas ante los ojos, porque sé dónde me aprieta el zapato: dígolo porque los buenos tendrán conmigo mano y concavidad, y los malos, ni pie ni entrada. Y paréceme a mí que en esto de los gobiernos todo es comenzar, y podría ser que a quince días de gobernador me comiese las manos tras el oficio y supiese más dél que de la labor del campo, en que me he criado. -Vos tenéis razón razón, Sancho -dijo la duquesa-, que nadie nace enseñado, y de los hombres se hacen los obispos, que no de las piedras. Pero, volviendo a la plática que poco ha tratábamos del encanto de la señora Dulcinea, tengo por cosa cierta y más que averiguada que aquella imaginación que Sancho tuvo de burlar a su señor y darle a entender que la labradora era Dulcinea, y que si su señor no la conocía debía de ser por estar encantada, toda fue invención de alguno de los encantadores que al señor don Quijote persiguen; porque real y verdaderamente yo sé de buena parte que la villana que dio el brinco sobre la pollina era y es Dulcinea del Toboso, y que el buen Sancho, pensando ser el engañador, es el engañado; y no hay poner más duda en esta verdad que en las cosas que nunca vimos; y sepa el señor Sancho Panza que también tenemos acá encantadores que nos quieren bien, y nos dicen lo que pasa por el mundo, pura y sencillamente, sin enredos ni máquinas; y créame Sancho que la villana brincadora era y es Dulcinea del Toboso, que está encantada como la madre que la parió; y cuando menos nos pensemos, la habemos de ver en su propia figura, y entonces saldrá Sancho del engaño en que vive. -Bien puede ser todo eso -dijo Sancho Panza-; y agora quiero creer lo que mi amo cuenta de lo que vio en la cueva de Montesinos, donde dice que vio a la señora Dulcinea del Toboso en el mesmo traje y hábito que yo dije que la había visto cuando la encanté por solo mi gusto; y todo debió de ser al revés, como vuesa merced, señora mía, dice, porque de mi ruin ingenio no se puede ni debe presumir que fabricase en un instante tan agudo embuste, ni creo yo que mi amo es tan loco que con tan flaca y magra persuasión como la mía creyese una cosa tan fuera de todo término. Pero, señora, no por esto será bien que vuestra bondad me tenga por malévolo, pues no está obligado un porro como yo a taladrar los pensamientos y malicias de los pésimos encantadores: yo fingí aquello por escaparme de las riñas de mi señor don Quijote, y no con intención de ofenderle; y si ha salido al revés, Dios está en el cielo, que juzga los corazones. -Así es la verdad -dijo la duquesa-; pero dígame agora, Sancho, qué es esto que dice de la cueva de Montesinos, que gustaría saberlo. Entonces Sancho Panza le contó punto por punto lo que queda dicho acerca de la tal aventura. Oyendo lo cual la duquesa, dijo: -Deste suceso se puede inferir que, pues el gran don Quijote dice que vio allí a la mesma labradora que Sancho vio a la salida del Toboso, sin duda es Dulcinea, y que andan por aquí los encantadores muy listos y demasiadamente curiosos. -Eso digo yo -dijo Sancho Panza-, que si mi señora Dulcinea del Toboso está encantada, su daño; que yo no me tengo de tomar, yo, con los enemigos de mi amo, que deben de ser muchos y malos. Verdad sea que la que yo vi fue una labradora, y por labradora la tuve, y por tal labradora la juzgué; y si aquélla era Dulcinea, no ha de estar a mi cuenta, ni ha de correr por mí, o sobre ello, morena. No, sino ándense a cada triquete conmigo a dime y direte, "Sancho lo dijo, Sancho lo hizo, Sancho tornó y Sancho volvió", como si Sancho fuese algún quienquiera, y no fuese el mismo Sancho Panza, el que anda ya en libros por ese mundo adelante, según me dijo Sansón Carrasco, que, por lo menos, es persona bachillerada por Salamanca, y los tales no pueden mentir si no es cuando se les antoja o les viene muy a cuento; así que, no hay para qué nadie se tome conmigo, y pues que tengo buena fama, y, según oí decir a mi señor, que más vale el buen nombre que las muchas riquezas, encájenme ese gobierno y verán maravillas; que quien ha sido buen escudero será buen gobernador. -Todo cuanto aquí ha dicho el buen Sancho -dijo la duquesa- son sentencias catonianas, o, por lo menos, sacadas de las mesmas entrañas del mismo Micael Verino, florentibus occidit annis. En fin, en fin, hablando a su modo, debajo de mala capa suele haber buen bebedor. -En verdad, señora -respondió Sancho-, que en mi vida he bebido de malicia; con sed bien podría ser, porque no tengo nada de hipócrita: bebo cuando tengo gana, y cuando no la tengo y cuando me lo dan, por no parecer o melindroso o malcriado; que a un brindis de un amigo, ¿qué corazón ha de haber tan de mármol que no haga la razón? Pero, aunque las calzo, no las ensucio; cuanto más, que los escuderos de los caballeros andantes, casi de ordinario beben agua, porque siempre andan por florestas, selvas y prados, montañas y riscos, sin hallar una misericordia de vino, si dan por ella un ojo. -Yo lo creo así -respondió la duquesa-. Y por ahora, váyase Sancho a reposar, que después hablaremos más largo y daremos orden como vaya presto a encajarse, como él dice, aquel gobierno. De nuevo le besó las manos Sancho a la duquesa, y le suplicó le hiciese merced de que se tuviese buena cuenta con su rucio, porque era la lumbre de sus ojos. -¿Qué rucio es éste? -preguntó la duquesa. -Mi asno -respondió Sancho-, que por no nombrarle con este nombre, le suelo llamar el rucio; y a esta señora dueña le rogué, cuando entré en este castillo, tuviese cuenta con él, y azoróse de manera como si la hubiera dicho que era fea o vieja, debiendo ser más propio y natural de las dueñas pensar jumentos que autorizar las salas. ¡Oh, válame Dios, y cuán mal estaba con estas señoras un hidalgo de mi lugar! -Sería algún villano -dijo doña Rodríguez, la dueña-, que si él fuera hidalgo y bien nacido, él las pusiera sobre el cuerno de la luna. -Agora bien -dijo la duquesa-, no haya más: calle doña Rodríguez y sosiéguese el señor Panza, y quédese a mi cargo el regalo del rucio; que, por ser alhaja de Sancho, le pondré yo sobre las niñas de mis ojos. -En la caballeriza basta que esté -respondió Sancho-, que sobre las niñas de los ojos de vuestra grandeza ni él ni yo somos dignos de estar sólo un momento, y así lo consintiría yo como darme de puñaladas; que, aunque dice mi señor que en las cortesías antes se ha de perder por carta de más que de menos, en las jumentiles y así niñas se ha de ir con el compás en la mano y con medido término. -Llévele -dijo la duquesa- Sancho al gobierno, y allá le podrá regalar como quisiere, y aun jubilarle del trabajo. -No piense vuesa merced, señora duquesa, que ha dicho mucho -dijo Sancho-; que yo he visto ir más de dos asnos a los gobiernos, y que llevase yo el mío no sería cosa nueva. Las razones de Sancho renovaron en la duquesa la risa y el contento; y, enviándole a reposar, ella fue a dar cuenta al duque de lo que con él había pasado, y entre los dos dieron traza y orden de hacer una burla a don Quijote que fuese famosa y viniese bien con el estilo caballeresco, en el cual le hicieron muchas, tan propias y discretas, que son las mejores aventuras que en esta grande historia se contienen. Capítulo XXXIV. Que cuenta de la noticia que se tuvo de cómo se había de desencantar la sin par Dulcinea del Toboso, que es una de las aventuras más famosas deste libro Grande era el gusto que recebían el duque y la duquesa de la conversación de don Quijote y de la de Sancho Panza; y, confirmándose en la intención que tenían de hacerles algunas burlas que llevasen vislumbres y apariencias de aventuras, tomaron motivo de la que don Quijote ya les había contado de la cueva de Montesinos, para hacerle una que fuese famosa (pero de lo que más la duquesa se admiraba era que la simplicidad de Sancho fuese tanta que hubiese venido a creer ser verdad infalible que Dulcinea del Toboso estuviese encantada, habiendo sido él mesmo el encantador y el embustero de aquel negocio); y así, habiendo dado orden a sus criados de todo lo que habían de hacer, de allí a seis días le llevaron a caza de montería, con tanto aparato de monteros y cazadores como pudiera llevar un rey coronado. Diéronle a don Quijote un vestido de monte y a Sancho otro verde, de finísimo paño; pero don Quijote no se le quiso poner, diciendo que otro día había de volver al duro ejercicio de las armas y que no podía llevar consigo guardarropas ni reposterías. Sancho sí tomó el que le dieron, con intención de venderle en la primera ocasión que pudiese. Llegado, pues, el esperado día, armóse don Quijote, vistióse Sancho, y, encima de su rucio, que no le quiso dejar aunque le daban un caballo, se metió entre la tropa de los monteros. La duquesa salió bizarramente aderezada, y don Quijote, de puro cortés y comedido, tomó la rienda de su palafrén, aunque el duque no quería consentirlo, y, finalmente, llegaron a un bosque que entre dos altísimas montañas estaba, donde, tomados los puestos, paranzas y veredas, y repartida la gente por diferentes puestos, se comenzó la caza con grande estruendo, grita y vocería, de manera que unos a otros no podían oírse, así por el ladrido de los perros como por el son de las bocinas. Apeóse la duquesa, y, con un agudo venablo en las manos, se puso en un puesto por donde ella sabía que solían venir algunos jabalíes. Apeóse asimismo el duque y don Quijote, y pusiéronse a sus lados; Sancho se puso detrás de todos, sin apearse del rucio, a quien no osara desamparar, porque no le sucediese algún desmán. Y, apenas habían sentado el pie y puesto en ala con otros muchos criados suyos, cuando, acosado de los perros y seguido de los cazadores, vieron que hacia ellos venía un desmesurado jabalí, crujiendo dientes y colmillos y arrojando espuma por la boca; y en viéndole, embrazando su escudo y puesta mano a su espada, se adelantó a recebirle don Quijote. Lo mesmo hizo el duque con su venablo; pero a todos se adelantara la duquesa, si el duque no se lo estorbara. Sólo Sancho, en viendo al valiente animal, desamparó al rucio y dio a correr cuanto pudo, y, procurando subirse sobre una alta encina, no fue posible; antes, estando ya a la mitad dél, asido de una rama, pugnando subir a la cima, fue tan corto de ventura y tan desgraciado, que se desgajó la rama, y, al venir al suelo, se quedó en el aire, asido de un gancho de la encina, sin poder llegar al suelo. Y, viéndose así, y que el sayo verde se le rasgaba, y pareciéndole que si aquel fiero animal allí allegaba le podía alcanzar, comenzó a dar tantos gritos y a pedir socorro con tanto ahínco, que todos los que le oían y no le veían creyeron que estaba entre los dientes de alguna fiera. Finalmente, el colmilludo jabalí quedó atravesado de las cuchillas de muchos venablos que se le pusieron delante; y, volviendo la cabeza don Quijote a los gritos de Sancho, que ya por ellos le había conocido, viole pendiente de la encina y la cabeza abajo, y al rucio junto a él, que no le desamparó en su calamidad; y dice Cide Hamete que pocas veces vio a Sancho Panza sin ver al rucio, ni al rucio sin ver a Sancho: tal era la amistad y buena fe que entre los dos se guardaban. Llegó don Quijote y descolgó a Sancho; el cual, viéndose libre y en el suelo, miró lo desgarrado del sayo de monte, y pesóle en el alma; que pensó que tenía en el vestido un mayorazgo. En esto, atravesaron al jabalí poderoso sobre una acémila, y, cubriéndole con matas de romero y con ramas de mirto, le llevaron, como en señal de vitoriosos despojos, a unas grandes tiendas de campaña que en la mitad del bosque estaban puestas, donde hallaron las mesas en orden y la comida aderezada, tan sumptuosa y grande, que se echaba bien de ver en ella la grandeza y magnificencia de quien la daba. Sancho, mostrando las llagas a la duquesa de su roto vestido, dijo: -Si esta caza fuera de liebres o de pajarillos, seguro estuviera mi sayo de verse en este estremo. Yo no sé qué gusto se recibe de esperar a un animal que, si os alcanza con un colmillo, os puede quitar la vida; yo me acuerdo haber oído cantar un romance antiguo que dice: De los osos seas comido, como Favila el nombrado. -Ése fue un rey godo -dijo don Quijote-, que, yendo a caza de montería, le comió un oso. -Eso es lo que yo digo -respondió Sancho-: que no querría yo que los príncipes y los reyes se pusiesen en semejantes peligros, a trueco de un gusto que parece que no le había de ser, pues consiste en matar a un animal que no ha cometido delito alguno. -Antes os engañáis, Sancho -respondió el duque-, porque el ejercicio de la caza de monte es el más conveniente y necesario para los reyes y príncipes que otro alguno. La caza es una imagen de la guerra: hay en ella estratagemas, astucias, insidias para vencer a su salvo al enemigo; padécense en ella fríos grandísimos y calores intolerables; menoscábase el ocio y el sueño, corrobóranse las fuerzas, agilítanse los miembros del que la usa, y, en resolución, es ejercicio que se puede hacer sin perjuicio de nadie y con gusto de muchos; y lo mejor que él tiene es que no es para todos, como lo es el de los otros géneros de caza, excepto el de la volatería, que también es sólo para reyes y grandes señores. Así que, ¡oh Sancho!, mudad de opinión, y, cuando seáis gobernador, ocupaos en la caza y veréis como os vale un pan por ciento. -Eso no -respondió Sancho-: el buen gobernador, la pierna quebrada y en casa. ¡Bueno sería que viniesen los negociantes a buscarle fatigados y él estuviese en el monte holgándose! ¡Así enhoramala andaría el gobierno! Mía fe, señor, la caza y los pasatiempos más han de ser para los holgazanes que para los gobernadores. En lo que yo pienso entretenerme es en jugar al triunfo envidado las pascuas, y a los bolos los domingos y fiestas; que esas cazas ni cazos no dicen con mi condición ni hacen con mi conciencia. -Plega a Dios, Sancho, que así sea, porque del dicho al hecho hay gran trecho. -Haya lo que hubiere -replicó Sancho-, que al buen pagador no le duelen prendas, y más vale al que Dios ayuda que al que mucho madruga, y tripas llevan pies, que no pies a tripas; quiero decir que si Dios me ayuda, y yo hago lo que debo con buena intención, sin duda que gobernaré mejor que un gerifalte. ¡No, sino pónganme el dedo en la boca y verán si aprieto o no! -¡Maldito seas de Dios y de todos sus santos, Sancho maldito -dijo don Quijote-, y cuándo será el día, como otras muchas veces he dicho, donde yo te vea hablar sin refranes una razón corriente y concertada! Vuestras grandezas dejen a este tonto, señores míos, que les molerá las almas, no sólo puestas entre dos, sino entre dos mil refranes, traídos tan a sazón y tan a tiempo cuanto le dé Dios a él la salud, o a mí si los querría escuchar. -Los refranes de Sancho Panza -dijo la duquesa-, puesto que son más que los del Comendador Griego, no por eso son en menos de estimar, por la brevedad de las sentencias. De mí sé decir que me dan más gusto que otros, aunque sean mejor traídos y con más sazón acomodados. Con estos y otros entretenidos razonamientos, salieron de la tienda al bosque, y en requerir algunas paranzas, y presto, se les pasó el día y se les vino la noche, y no tan clara ni tan sesga como la sazón del tiempo pedía, que era en la mitad del verano; pero un cierto claroescuro que trujo consigo ayudó mucho a la intención de los duques; y, así como comenzó a anochecer, un poco más adelante del crepúsculo, a deshora pareció que todo el bosque por todas cuatro partes se ardía, y luego se oyeron por aquí y por allí, y por acá y por acullá, infinitas cornetas y otros instrumentos de guerra, como de muchas tropas de caballería que por el bosque pasaba. La luz del fuego, el son de los bélicos instrumentos, casi cegaron y atronaron los ojos y los oídos de los circunstantes, y aun de todos los que en el bosque estaban. Luego se oyeron infinitos lelilíes, al uso de moros cuando entran en las batallas, sonaron trompetas y clarines, retumbaron tambores, resonaron pífaros, casi todos a un tiempo, tan contino y tan apriesa, que no tuviera sentido el que no quedara sin él al son confuso de tantos intrumentos. Pasmóse el duque, suspendióse la duquesa, admiróse don Quijote, tembló Sancho Panza, y, finalmente, aun hasta los mesmos sabidores de la causa se espantaron. Con el temor les cogió el silencio, y un postillón que en traje de demonio les pasó por delante, tocando en voz de corneta un hueco y desmesurado cuerno, que un ronco y espantoso son despedía. -¡Hola, hermano correo! -dijo el duque-, ¿quién sois, adónde vais, y qué gente de guerra es la que por este bosque parece que atraviesa? A lo que respondió el correo con voz horrísona y desenfadada: -Yo soy el Diablo; voy a buscar a don Quijote de la Mancha; la gente que por aquí viene son seis tropas de encantadores, que sobre un carro triunfante traen a la sin par Dulcinea del Toboso. Encantada viene con el gallardo francés Montesinos, a dar orden a don Quijote de cómo ha de ser desencantada la tal señora. -Si vos fuérades diablo, como decís y como vuestra figura muestra, ya hubiérades conocido al tal caballero don Quijote de la Mancha, pues le tenéis delante. -En Dios y en mi conciencia -respondió el Diablo- que no miraba en ello, porque traigo en tantas cosas divertidos los pensamientos, que de la principal a que venía se me olvidaba. -Sin duda -dijo Sancho- que este demonio debe de ser hombre de bien y buen cristiano, porque, a no serlo, no jurara en Dios y en mi conciencia. Ahora yo tengo para mí que aun en el mesmo infierno debe de haber buena gente. Luego el Demonio, sin apearse, encaminando la vista a don Quijote, dijo: -A ti, el Caballero de los Leones (que entre las garras dellos te vea yo), me envía el desgraciado pero valiente caballero Montesinos, mandándome que de su parte te diga que le esperes en el mismo lugar que te topare, a causa que trae consigo a la que llaman Dulcinea del Toboso, con orden de darte la que es menester para desencantarla. Y, por no ser para más mi venida, no ha de ser más mi estada: los demonios como yo queden contigo, y los ángeles buenos con estos señores. Y, en diciendo esto, tocó el desaforado cuerno, y volvió las espaldas y fuese, sin esperar respuesta de ninguno. Renovóse la admiración en todos, especialmente en Sancho y don Quijote: en Sancho, en ver que, a despecho de la verdad, querían que estuviese encantada Dulcinea; en don Quijote, por no poder asegurarse si era verdad o no lo que le había pasado en la cueva de Montesinos. Y, estando elevado en estos pensamientos, el duque le dijo: -¿Piensa vuestra merced esperar, señor don Quijote? -Pues ¿no? -respondió él-. Aquí esperaré intrépido y fuerte, si me viniese a embestir todo el infierno. -Pues si yo veo otro diablo y oigo otro cuerno como el pasado, así esperaré yo aquí como en Flandes -dijo Sancho. En esto, se cerró más la noche, y comenzaron a discurrir muchas luces por el bosque, bien así como discurren por el cielo las exhalaciones secas de la tierra, que parecen a nuestra vista estrellas que corren. Oyóse asimismo un espantoso ruido, al modo de aquel que se causa de las ruedas macizas que suelen traer los carros de bueyes, de cuyo chirrío áspero y continuado se dice que huyen los lobos y los osos, si los hay por donde pasan. Añadióse a toda esta tempestad otra que las aumentó todas, que fue que parecía verdaderamente que a las cuatro partes del bosque se estaban dando a un mismo tiempo cuatro rencuentros o batallas, porque allí sonaba el duro estruendo de espantosa artillería, acullá se disparaban infinitas escopetas, cerca casi sonaban las voces de los combatientes, lejos se reiteraban los lililíes agarenos. Finalmente, las cornetas, los cuernos, las bocinas, los clarines, las trompetas, los tambores, la artillería, los arcabuces, y, sobre todo, el temeroso ruido de los carros, formaban todos juntos un son tan confuso y tan horrendo, que fue menester que don Quijote se valiese de todo su corazón para sufrirle; pero el de Sancho vino a tierra, y dio con él desmayado en las faldas de la duquesa, la cual le recibió en ellas, y a gran priesa mandó que le echasen agua en el rostro. Hízose así, y él volvió en su acuerdo, a tiempo que ya un carro de las rechinantes ruedas llegaba a aquel puesto. Tirábanle cuatro perezosos bueyes, todos cubiertos de paramentos negros; en cada cuerno traían atada y encendida una grande hacha de cera, y encima del carro venía hecho un asiento alto, sobre el cual venía sentado un venerable viejo, con una barba más blanca que la mesma nieve, y tan luenga que le pasaba de la cintura; su vestidura era una ropa larga de negro bocací, que, por venir el carro lleno de infinitas luces, se podía bien divisar y discernir todo lo que en él venía. Guiábanle dos feos demonios vestidos del mesmo bocací, con tan feos rostros, que Sancho, habiéndolos visto una vez, cerró los ojos por no verlos otra. Llegando, pues, el carro a igualar al puesto, se levantó de su alto asiento el viejo venerable, y, puesto en pie, dando una gran voz, dijo: -Yo soy el sabio Lirgandeo. Y pasó el carro adelante, sin hablar más palabra. Tras éste pasó otro carro de la misma manera, con otro viejo entronizado; el cual, haciendo que el carro se detuviese, con voz no menos grave que el otro, dijo: -Yo soy el sabio Alquife, el grande amigo de Urganda la Desconocida. Y pasó adelante. Luego, por el mismo continente, llegó otro carro; pero el que venía sentado en el trono no era viejo como los demás, sino hombrón robusto y de mala catadura, el cual, al llegar, levantándose en pie, como los otros, dijo con voz más ronca y más endiablada: -Yo soy Arcaláus el encantador, enemigo mortal de Amadís de Gaula y de toda su parentela. Y pasó adelante. Poco desviados de allí hicieron alto estos tres carros, y cesó el enfadoso ruido de sus ruedas, y luego se oyó otro, no ruido, sino un son de una suave y concertada música formado, con que Sancho se alegró, y lo tuvo a buena señal; y así, dijo a la duquesa, de quien un punto ni un paso se apartaba: -Señora, donde hay música no puede haber cosa mala. -Tampoco donde hay luces y claridad -respondió la duquesa. A lo que replicó Sancho: -Luz da el fuego y claridad las hogueras, como lo vemos en las que nos cercan, y bien podría ser que nos abrasasen, pero la música siempre es indicio de regocijos y de fiestas. -Ello dirá -dijo don Quijote, que todo lo escuchaba. Y dijo bien, como se muestra en el capítulo siguiente. Capítulo XXXV. Donde se prosigue la noticia que tuvo don Quijote del desencanto de Dulcinea, con otros admirables sucesos Al compás de la agradable música vieron que hacia ellos venía un carro de los que llaman triunfales tirado de seis mulas pardas, encubertadas, empero, de lienzo blanco, y sobre cada una venía un diciplinante de luz, asimesmo vestido de blanco, con una hacha de cera grande encendida en la mano. Era el carro dos veces, y aun tres, mayor que los pasados, y los lados, y encima dél, ocupaban doce otros diciplinantes albos como la nieve, todos con sus hachas encendidas, vista que admiraba y espantaba juntamente; y en un levantado trono venía sentada una ninfa, vestida de mil velos de tela de plata, brillando por todos ellos infinitas hojas de argentería de oro, que la hacían, si no rica, a lo menos vistosamente vestida. Traía el rostro cubierto con un transparente y delicado cendal, de modo que, sin impedirlo sus lizos, por entre ellos se descubría un hermosísimo rostro de doncella, y las muchas luces daban lugar para distinguir la belleza y los años, que, al parecer, no llegaban a veinte ni bajaban de diez y siete. Junto a ella venía una figura vestida de una ropa de las que llaman rozagantes, hasta los pies, cubierta la cabeza con un velo negro; pero, al punto que llegó el carro a estar frente a frente de los duques y de don Quijote, cesó la música de las chirimías, y luego la de las arpas y laúdes que en el carro sonaban; y, levantándose en pie la figura de la ropa, la apartó a entrambos lados, y, quitándose el velo del rostro, descubrió patentemente ser la mesma figura de la muerte, descarnada y fea, de que don Quijote recibió pesadumbre y Sancho miedo, y los duques hicieron algún sentimiento temeroso. Alzada y puesta en pie esta muerte viva, con voz algo dormida y con lengua no muy despierta, comenzó a decir desta manera: -Yo soy Merlín, aquel que las historias dicen que tuve por mi padre al diablo (mentira autorizada de los tiempos), príncipe de la Mágica y monarca y archivo de la ciencia zoroástrica, émulo a las edades y a los siglos que solapar pretenden las hazañas de los andantes bravos caballeros a quien yo tuve y tengo gran cariño. Y, puesto que es de los encantadores, de los magos o mágicos contino dura la condición, áspera y fuerte, la mía es tierna, blanda y amorosa, y amiga de hacer bien a todas gentes. En las cavernas lóbregas de Dite, donde estaba mi alma entretenida en formar ciertos rombos y caráteres, llegó la voz doliente de la bella y sin par Dulcinea del Toboso. Supe su encantamento y su desgracia, y su trasformación de gentil dama en rústica aldeana; condolíme, y, encerrando mi espíritu en el hueco desta espantosa y fiera notomía, después de haber revuelto cien mil libros desta mi ciencia endemoniada y torpe, vengo a dar el remedio que conviene a tamaño dolor, a mal tamaño. ¡Oh tú, gloria y honor de cuantos visten las túnicas de acero y de diamante, luz y farol, sendero, norte y guía de aquellos que, dejando el torpe sueño y las ociosas plumas, se acomodan a usar el ejercicio intolerable de las sangrientas y pesadas armas! A ti digo ¡oh varón, como se debe por jamás alabado!, a ti, valiente juntamente y discreto don Quijote, de la Mancha esplendor, de España estrella, que para recobrar su estado primo la sin par Dulcinea del Toboso, es menester que Sancho, tu escudero, se dé tres mil azotes y trecientos en ambas sus valientes posaderas, al aire descubiertas, y de modo que le escuezan, le amarguen y le enfaden. Y en esto se resuelven todos cuantos de su desgracia han sido los autores, y a esto es mi venida, mis señores. -¡Voto a tal! -dijo a esta sazón Sancho-. No digo yo tres mil azotes, pero así me daré yo tres como tres puñaladas. ¡Válate el diablo por modo de desencantar! ¡Yo no sé qué tienen que ver mis posas con los encantos! ¡Par Dios que si el señor Merlín no ha hallado otra manera como desencantar a la señora Dulcinea del Toboso, encantada se podrá ir a la sepultura! -Tomaros he yo -dijo don Quijote-, don villano, harto de ajos, y amarraros he a un árbol, desnudo como vuestra madre os parió; y no digo yo tres mil y trecientos, sino seis mil y seiscientos azotes os daré, tan bien pegados que no se os caigan a tres mil y trecientos tirones. Y no me repliquéis palabra, que os arrancaré el alma. Oyendo lo cual Merlín, dijo: -No ha de ser así, porque los azotes que ha de recebir el buen Sancho han de ser por su voluntad, y no por fuerza, y en el tiempo que él quisiere; que no se le pone término señalado; pero permítesele que si él quisiere redemir su vejación por la mitad de este vapulamiento, puede dejar que se los dé ajena mano, aunque sea algo pesada. -Ni ajena, ni propia, ni pesada, ni por pesar -replicó Sancho-: a mí no me ha de tocar alguna mano. ¿Parí yo, por ventura, a la señora Dulcinea del Toboso, para que paguen mis posas lo que pecaron sus ojos? El señor mi amo sí, que es parte suya, pues la llama a cada paso mi vida, mi alma, sustento y arrimo suyo, se puede y debe azotar por ella y hacer todas las diligencias necesarias para su desencanto; pero, ¿azotarme yo...? ¡Abernuncio! Apenas acabó de decir esto Sancho, cuando, levantándose en pie la argentada ninfa que junto al espíritu de Merlín venía, quitándose el sutil velo del rostro, le descubrió tal, que a todos pareció mas que demasiadamente hermoso, y, con un desenfado varonil y con una voz no muy adamada, hablando derechamente con Sancho Panza, dijo: -¡Oh malaventurado escudero, alma de cántaro, corazón de alcornoque, de entrañas guijeñas y apedernaladas! Si te mandaran, ladrón desuellacaras, que te arrojaras de una alta torre al suelo; si te pidieran, enemigo del género humano, que te comieras una docena de sapos, dos de lagartos y tres de culebras; si te persuadieran a que mataras a tu mujer y a tus hijos con algún truculento y agudo alfanje, no fuera maravilla que te mostraras melindroso y esquivo; pero hacer caso de tres mil y trecientos azotes, que no hay niño de la doctrina, por ruin que sea, que no se los lleve cada mes, admira, adarva, espanta a todas las entrañas piadosas de los que lo escuchan, y aun las de todos aquellos que lo vinieren a saber con el discurso del tiempo. Pon, ¡oh miserable y endurecido animal!, pon, digo, esos tus ojos de machuelo espantadizo en las niñas destos míos, comparados a rutilantes estrellas, y veráslos llorar hilo a hilo y madeja a madeja, haciendo surcos, carreras y sendas por los hermosos campos de mis mejillas. Muévate, socarrón y malintencionado monstro, que la edad tan florida mía, que aún se está todavía en el diez y... de los años, pues tengo diez y nueve y no llego a veinte, se consume y marchita debajo de la corteza de una rústica labradora; y si ahora no lo parezco, es merced particular que me ha hecho el señor Merlín, que está presente, sólo porque te enternezca mi belleza; que las lágrimas de una afligida hermosura vuelven en algodón los riscos, y los tigres en ovejas. Date, date en esas carnazas, bestión indómito, y saca de harón ese brío, que a sólo comer y más comer te inclina, y pon en libertad la lisura de mis carnes, la mansedumbre de mi condición y la belleza de mi faz; y si por mí no quieres ablandarte ni reducirte a algún razonable término, hazlo por ese pobre caballero que a tu lado tienes; por tu amo, digo, de quien estoy viendo el alma, que la tiene atravesada en la garganta, no diez dedos de los labios, que no espera sino tu rígida o blanda repuesta, o para salirse por la boca, o para volverse al estómago. Tentóse, oyendo esto, la garganta don Quijote y dijo, volviéndose al duque: -Por Dios, señor, que Dulcinea ha dicho la verdad, que aquí tengo el alma atravesada en la garganta, como una nuez de ballesta. -¿Qué decís vos a esto, Sancho? -preguntó la duquesa. -Digo, señora -respondió Sancho-, lo que tengo dicho: que de los azotes, abernuncio. -Abrenuncio habéis de decir, Sancho, y no como decís -dijo el duque. -Déjeme vuestra grandeza -respondió Sancho-, que no estoy agora para mirar en sotilezas ni en letras más a menos; porque me tienen tan turbado estos azotes que me han de dar, o me tengo de dar, que no sé lo que me digo, ni lo que me hago. Pero querría yo saber de la señora mi señora doña Dulcina del Toboso adónde aprendió el modo de rogar que tiene: viene a pedirme que me abra las carnes a azotes, y llámame alma de cántaro y bestión indómito, con una tiramira de malos nombres, que el diablo los sufra. ¿Por ventura son mis carnes de bronce, o vame a mí algo en que se desencante o no? ¿Qué canasta de ropa blanca, de camisas, de tocadores y de escarpines, anque no los gasto, trae delante de sí para ablandarme, sino un vituperio y otro, sabiendo aquel refrán que dicen por ahí, que un asno cargado de oro sube ligero por una montaña, y que dádivas quebrantan peñas, y a Dios rogando y con el mazo dando, y que más vale un "toma" que dos "te daré"? Pues el señor mi amo, que había de traerme la mano por el cerro y halagarme para que yo me hiciese de lana y de algodón cardado, dice que si me coge me amarrará desnudo a un árbol y me doblará la parada de los azotes; y habían de considerar estos lastimados señores que no solamente piden que se azote un escudero, sino un gobernador; como quien dice: "bebe con guindas". Aprendan, aprendan mucho de enhoramala a saber rogar, y a saber pedir, y a tener crianza, que no son todos los tiempos unos, ni están los hombres siempre de un buen humor. Estoy yo ahora reventando de pena por ver mi sayo verde roto, y vienen a pedirme que me azote de mi voluntad, estando ella tan ajena dello como de volverme cacique. -Pues en verdad, amigo Sancho -dijo el duque-, que si no os ablandáis más que una breva madura, que no habéis de empuñar el gobierno. ¡Bueno sería que yo enviase a mis insulanos un gobernador cruel, de entrañas pedernalinas, que no se doblega a las lágrimas de las afligidas doncellas, ni a los ruegos de discretos, imperiosos y antiguos encantadores y sabios! En resolución, Sancho, o vos habéis de ser azotado, o os han de azotar, o no habéis de ser gobernador. -Señor -respondió Sancho-, ¿no se me darían dos días de término para pensar lo que me está mejor? -No, en ninguna manera -dijo Merlín-; aquí, en este instante y en este lugar, ha de quedar asentado lo que ha de ser deste negocio, o Dulcinea volverá a la cueva de Montesinos y a su prístino estado de labradora, o ya, en el ser que está, será llevada a los Elíseos Campos, donde estará esperando se cumpla el número del vápulo. -Ea, buen Sancho -dijo la duquesa-, buen ánimo y buena correspondencia al pan que habéis comido del señor don Quijote, a quien todos debemos servir y agradar, por su buena condición y por sus altas caballerías. Dad el sí, hijo, desta azotaina, y váyase el diablo para diablo y el temor para mezquino; que un buen corazón quebranta mala ventura, como vos bien sabéis. A estas razones respondió con éstas disparatadas Sancho, que, hablando con Merlín, le preguntó: -Dígame vuesa merced, señor Merlín: cuando llegó aquí el diablo correo y dio a mi amo un recado del señor Montesinos, mandándole de su parte que le esperase aquí, porque venía a dar orden de que la señora doña Dulcinea del Toboso se desencantase, y hasta agora no hemos visto a Montesinos, ni a sus semejas. A lo cual respondió Merlín: -El Diablo, amigo Sancho, es un ignorante y un grandísimo bellaco: yo le envié en busca de vuestro amo, pero no con recado de Montesinos, sino mío, porque Montesinos se está en su cueva entendiendo, o, por mejor decir, esperando su desencanto, que aún le falta la cola por desollar. Si os debe algo, o tenéis alguna cosa que negociar con él, yo os lo traeré y pondré donde vos más quisiéredes. Y, por agora, acabad de dar el sí desta diciplina, y creedme que os será de mucho provecho, así para el alma como para el cuerpo: para el alma, por la caridad con que la haréis; para el cuerpo, porque yo sé que sois de complexión sanguínea, y no os podrá hacer daño sacaros un poco de sangre. -Muchos médicos hay en el mundo: hasta los encantadores son médicos -replicó Sancho-; pero, pues todos me lo dicen, aunque yo no me lo veo, digo que soy contento de darme los tres mil y trecientos azotes, con condición que me los tengo de dar cada y cuando que yo quisiere, sin que se me ponga tasa en los días ni en el tiempo; y yo procuraré salir de la deuda lo más presto que sea posible, porque goce el mundo de la hermosura de la señora doña Dulcinea del Toboso, pues, según parece, al revés de lo que yo pensaba, en efecto es hermosa. Ha de ser también condición que no he de estar obligado a sacarme sangre con la diciplina, y que si algunos azotes fueren de mosqueo, se me han de tomar en cuenta. Iten, que si me errare en el número, el señor Merlín, pues lo sabe todo, ha de tener cuidado de contarlos y de avisarme los que me faltan o los que me sobran. -De las sobras no habrá que avisar -respondió Merlín-, porque, llegando al cabal número, luego quedará de improviso desencantada la señora Dulcinea, y vendrá a buscar, como agradecida, al buen Sancho, y a darle gracias, y aun premios, por la buena obra. Así que no hay de qué tener escrúpulo de las sobras ni de las faltas, ni el cielo permita que yo engañe a nadie, aunque sea en un pelo de la cabeza. -¡Ea, pues, a la mano de Dios! -dijo Sancho-. Yo consiento en mi mala ventura; digo que yo acepto la penitencia con las condiciones apuntadas. Apenas dijo estas últimas palabras Sancho, cuando volvió a sonar la música de las chirimías y se volvieron a disparar infinitos arcabuces, y don Quijote se colgó del cuello de Sancho, dándole mil besos en la frente y en las mejillas. La duquesa y el duque y todos los circunstantes dieron muestras de haber recebido grandísimo contento, y el carro comenzó a caminar; y, al pasar, la hermosa Dulcinea inclinó la cabeza a los duques y hizo una gran reverencia a Sancho. Y ya, en esto, se venía a más andar el alba, alegre y risueña: las florecillas de los campos se descollaban y erguían, y los líquidos cristales de los arroyuelos, murmurando por entre blancas y pardas guijas, iban a dar tributo a los ríos que los esperaban. La tierra alegre, el cielo claro, el aire limpio, la luz serena, cada uno por sí y todos juntos, daban manifiestas señales que el día, que al aurora venía pisando las faldas, había de ser sereno y claro. Y, satisfechos los duques de la caza y de haber conseguido su intención tan discreta y felicemente, se volvieron a su castillo, con prosupuesto de segundar en sus burlas, que para ellos no había veras que más gusto les diesen. Capítulo XXXVI. Donde se cuenta la estraña y jamás imaginada aventura de la dueña Dolorida, alias de la condesa Trifaldi, con una carta que Sancho Panza escribió a su mujer Teresa Panza Tenía un mayordomo el duque de muy burlesco y desenfadado ingenio, el cual hizo la figura de Merlín y acomodó todo el aparato de la aventura pasada, compuso los versos y hizo que un paje hiciese a Dulcinea. Finalmente, con intervención de sus señores, ordenó otra del más gracioso y estraño artificio que puede imaginarse. Preguntó la duquesa a Sancho otro día si había comenzado la tarea de la penitencia que había de hacer por el desencanto de Dulcinea. Dijo que sí, y que aquella noche se había dado cinco azotes. Preguntóle la duquesa que con qué se los había dado. Respondió que con la mano. -Eso -replicó la duquesa- más es darse de palmadas que de azotes. Yo tengo para mí que el sabio Merlín no estará contento con tanta blandura; menester será que el buen Sancho haga alguna diciplina de abrojos, o de las de canelones, que se dejen sentir; porque la letra con sangre entra, y no se ha de dar tan barata la libertad de una tan gran señora como lo es Dulcinea por tan poco precio; y advierta Sancho que las obras de caridad que se hacen tibia y flojamente no tienen mérito ni valen nada. A lo que respondió Sancho: -Déme vuestra señoría alguna diciplina o ramal conveniente, que yo me daré con él como no me duela demasiado, porque hago saber a vuesa merced que, aunque soy rústico, mis carnes tienen más de algodón que de esparto, y no será bien que yo me descríe por el provecho ajeno. -Sea en buena hora -respondió la duquesa-: yo os daré mañana una diciplina que os venga muy al justo y se acomode con la ternura de vuestras carnes, como si fueran sus hermanas propias. A lo que dijo Sancho: -Sepa vuestra alteza, señora mía de mi ánima, que yo tengo escrita una carta a mi mujer Teresa Panza, dándole cuenta de todo lo que me ha sucedido después que me aparté della; aquí la tengo en el seno, que no le falta más de ponerle el sobreescrito; querría que vuestra discreción la leyese, porque me parece que va conforme a lo de gobernador, digo, al modo que deben de escribir los gobernadores. -¿Y quién la notó? -preguntó la duquesa. -¿Quién la había de notar sino yo, pecador de mí? -respondió Sancho. -¿Y escribístesla vos? -dijo la duquesa. -Ni por pienso -respondió Sancho-, porque yo no sé leer ni escribir, puesto que sé firmar. -Veámosla -dijo la duquesa-, que a buen seguro que vos mostréis en ella la calidad y suficiencia de vuestro ingenio. Sacó Sancho una carta abierta del seno, y, tomándola la duquesa, vio que decía desta manera: Carta de Sancho Panza a Teresa Panza, su mujer Si buenos azotes me daban, bien caballero me iba; si buen gobierno me tengo, buenos azotes me cuesta. Esto no lo entenderás tú, Teresa mía, por ahora; otra vez lo sabrás. Has de saber, Teresa, que tengo determinado que andes en coche, que es lo que hace al caso, porque todo otro andar es andar a gatas. Mujer de un gobernador eres, ¡mira si te roerá nadie los zancajos! Ahí te envío un vestido verde de cazador, que me dio mi señora la duquesa; acomódale en modo que sirva de saya y cuerpos a nuestra hija. Don Quijote, mi amo, según he oído decir en esta tierra, es un loco cuerdo y un mentecato gracioso, y que yo no le voy en zaga. Hemos estado en la cueva de Montesinos, y el sabio Merlín ha echado mano de mí para el desencanto de Dulcinea del Toboso, que por allá se llama Aldonza Lorenzo: con tres mil y trecientos azotes, menos cinco, que me he de dar, quedará desencantada como la madre que la parió. No dirás desto nada a nadie, porque pon lo tuyo en concejo, y unos dirán que es blanco y otros que es negro. De aquí a pocos días me partiré al gobierno, adonde voy con grandísimo deseo de hacer dineros, porque me han dicho que todos los gobernadores nuevos van con este mesmo deseo; tomaréle el pulso, y avisaréte si has de venir a estar conmigo o no. El rucio está bueno, y se te encomienda mucho; y no le pienso dejar, aunque me llevaran a ser Gran Turco. La duquesa mi señora te besa mil veces las manos; vuélvele el retorno con dos mil, que no hay cosa que menos cueste ni valga más barata, según dice mi amo, que los buenos comedimientos. No ha sido Dios servido de depararme otra maleta con otros cien escudos, como la de marras, pero no te dé pena, Teresa mía, que en salvo está el que repica, y todo saldrá en la colada del gobierno; sino que me ha dado gran pena que me dicen que si una vez le pruebo, que me tengo de comer las manos tras él; y si así fuese, no me costaría muy barato, aunque los estropeados y mancos ya se tienen su calonjía en la limosna que piden; así que, por una vía o por otra, tú has de ser rica, de buena ventura. Dios te la dé, como puede, y a mí me guarde para servirte. Deste castillo, a veinte de julio de 1614. Tu marido el gobernador, Sancho Panza. En acabando la duquesa de leer la carta, dijo a Sancho: -En dos cosas anda un poco descaminado el buen gobernador: la una, en decir o dar a entender que este gobierno se le han dado por los azotes que se ha de dar, sabiendo él, que no lo puede negar, que cuando el duque, mi señor, se le prometió, no se soñaba haber azotes en el mundo; la otra es que se muestra en ella muy codicioso, y no querría que orégano fuese, porque la codicia rompe el saco, y el gobernador codicioso hace la justicia desgobernada. -Yo no lo digo por tanto, señora -respondió Sancho-; y si a vuesa merced le parece que la tal carta no va como ha de ir, no hay sino rasgarla y hacer otra nueva, y podría ser que fuese peor si me lo dejan a mi caletre. -No, no -replicó la duquesa-, buena está ésta, y quiero que el duque la vea. Con esto se fueron a un jardín, donde habían de comer aquel día. Mostró la duquesa la carta de Sancho al duque, de que recibió grandísimo contento. Comieron, y después de alzado los manteles, y después de haberse entretenido un buen espacio con la sabrosa conversación de Sancho, a deshora se oyó el son tristísimo de un pífaro y el de un ronco y destemplado tambor. Todos mostraron alborotarse con la confusa, marcial y triste armonía, especialmente don Quijote, que no cabía en su asiento de puro alborotado; de Sancho no hay que decir sino que el miedo le llevó a su acostumbrado refugio, que era el lado o faldas de la duquesa, porque real y verdaderamente el son que se escuchaba era tristísimo y malencólico. Y, estando todos así suspensos, vieron entrar por el jardín adelante dos hombres vestidos de luto, tan luego y tendido que les arrastraba por el suelo; éstos venían tocando dos grandes tambores, asimismo cubiertos de negro. A su lado venía el pífaro, negro y pizmiento como los demás. Seguía a los tres un personaje de cuerpo agigantado, amantado, no que vestido, con una negrísima loba, cuya falda era asimismo desaforada de grande. Por encima de la loba le ceñía y atravesaba un ancho tahelí, también negro, de quien pendía un desmesurado alfanje de guarniciones y vaina negra. Venía cubierto el rostro con un trasparente velo negro, por quien se entreparecía una longísima barba, blanca como la nieve. Movía el paso al son de los tambores con mucha gravedad y reposo. En fin, su grandeza, su contoneo, su negrura y su acompañamiento pudiera y pudo suspender a todos aquellos que sin conocerle le miraron. Llegó, pues, con el espacio y prosopopeya referida a hincarse de rodillas ante el duque, que en pie, con los demás que allí estaban, le atendía; pero el duque en ninguna manera le consintió hablar hasta que se levantase. Hízolo así el espantajo prodigioso, y, puesto en pie, alzó el antifaz del rostro y hizo patente la más horrenda, la más larga, la más blanca y más poblada barba que hasta entonces humanos ojos habían visto, y luego desencajó y arrancó del ancho y dilatado pecho una voz grave y sonora, y, poniendo los ojos en el duque, dijo: -Altísimo y poderoso señor, a mí me llaman Trifaldín el de la Barba Blanca; soy escudero de la condesa Trifaldi, por otro nombre llamada la Dueña Dolorida, de parte de la cual traigo a vuestra grandeza una embajada, y es que la vuestra magnificencia sea servida de darla facultad y licencia para entrar a decirle su cuita, que es una de las más nuevas y más admirables que el más cuitado pensamiento del orbe pueda haber pensado. Y primero quiere saber si está en este vuestro castillo el valeroso y jamás vencido caballero don Quijote de la Mancha, en cuya busca viene a pie y sin desayunarse desde el reino de Candaya hasta este vuestro estado, cosa que se puede y debe tener a milagro o a fuerza de encantamento. Ella queda a la puerta desta fortaleza o casa de campo, y no aguarda para entrar sino vuestro beneplácito. Dije. Y tosió luego y manoseóse la barba de arriba abajo con entrambas manos, y con mucho sosiego estuvo atendiendo la respuesta del duque, que fue: -Ya, buen escudero Trifaldín de la Blanca Barba, ha muchos días que tenemos noticia de la desgracia de mi señora la condesa Trifaldi, a quien los encantadores la hacen llamar la Dueña Dolorida; bien podéis, estupendo escudero, decirle que entre y que aquí está el valiente caballero don Quijote de la Mancha, de cuya condición generosa puede prometerse con seguridad todo amparo y toda ayuda; y asimismo le podréis decir de mi parte que si mi favor le fuere necesario, no le ha de faltar, pues ya me tiene obligado a dársele el ser caballero, a quien es anejo y concerniente favorecer a toda suerte de mujeres, en especial a las dueñas viudas, menoscabadas y doloridas, cual lo debe estar su señoría. Oyendo lo cual Trifaldín, inclinó la rodilla hasta el suelo, y, haciendo al pífaro y tambores señal que tocasen, al mismo son y al mismo paso que había entrado, se volvió a salir del jardín, dejando a todos admirados de su presencia y compostura. Y, volviéndose el duque a don Quijote, le dijo: -En fin, famoso caballero, no pueden las tinieblas de malicia ni de la ignorancia encubrir y escurecer la luz del valor y de la virtud. Digo esto porque apenas ha seis días que la vuestra bondad está en este castillo, cuando ya os vienen a buscar de lueñas y apartadas tierras, y no en carrozas ni en dromedarios, sino a pie y en ayunas; los tristes, los afligidos, confiados que han de hallar en ese fortísimo brazo el remedio de sus cuitas y trabajos, merced a vuestras grandes hazañas, que corren y rodean todo lo descubierto de la tierra. -Quisiera yo, señor duque -respondió don Quijote-, que estuviera aquí presente aquel bendito religioso que a la mesa el otro día mostró tener tan mal talante y tan mala ojeriza contra los caballeros andantes, para que viera por vista de ojos si los tales caballeros son necesarios en el mundo: tocara, por lo menos, con la mano que los extraordinariamente afligidos y desconsolados, en casos grandes y en desdichas inormes no van a buscar su remedio a las casas de los letrados, ni a la de los sacristanes de las aldeas, ni al caballero que nunca ha acertado a salir de los términos de su lugar, ni al perezoso cortesano que antes busca nuevas para referirlas y contarlas, que procura hacer obras y hazañas para que otros las cuenten y las escriban; el remedio de las cuitas, el socorro de las necesidades, el amparo de las doncellas, el consuelo de las viudas, en ninguna suerte de personas se halla mejor que en los caballeros andantes, y de serlo yo doy infinitas gracias al cielo, y doy por muy bien empleado cualquier desmán y trabajo que en este tan honroso ejercicio pueda sucederme. Venga esta dueña y pida lo que quisiere, que yo le libraré su remedio en la fuerza de mi brazo y en la intrépida resolución de mi animoso espíritu. Capítulo XXXVII. Donde se prosigue la famosa aventura de la dueña Dolorida En estremo se holgaron el duque y la duquesa de ver cuán bien iba respondiendo a su intención don Quijote, y a esta sazón dijo Sancho: -No querría yo que esta señora dueña pusiese algún tropiezo a la promesa de mi gobierno, porque yo he oído decir a un boticario toledano que hablaba como un silguero que donde interviniesen dueñas no podía suceder cosa buena. ¡Válame Dios, y qué mal estaba con ellas el tal boticario! De lo que yo saco que, pues todas las dueñas son enfadosas e impertinentes, de cualquiera calidad y condición que sean, ¿qué serán las que son doloridas, como han dicho que es esta condesa Tres Faldas, o Tres Colas?; que en mi tierra faldas y colas, colas y faldas, todo es uno. -Calla, Sancho amigo -dijo don Quijote-, que, pues esta señora dueña de tan lueñes tierras viene a buscarme, no debe ser de aquellas que el boticario tenía en su número, cuanto más que ésta es condesa, y cuando las condesas sirven de dueñas, será sirviendo a reinas y a emperatrices, que en sus casas son señorísimas que se sirven de otras dueñas. A esto respondió doña Rodríguez, que se halló presente: -Dueñas tiene mi señora la duquesa en su servicio, que pudieran ser condesas si la fortuna quisiera, pero allá van leyes do quieren reyes; y nadie diga mal de las dueñas, y más de las antiguas y doncellas; que, aunque yo no lo soy, bien se me alcanza y se me trasluce la ventaja que hace una dueña doncella a una dueña viuda; y quien a nosotras trasquiló, las tijeras le quedaron en la mano. -Con todo eso -replicó Sancho-, hay tanto que trasquilar en las dueñas, según mi barbero, cuanto será mejor no menear el arroz, aunque se pegue. -Siempre los escuderos -respondió doña Rodríguez- son enemigos nuestros; que, como son duendes de las antesalas y nos veen a cada paso, los ratos que no rezan, que son muchos, los gastan en murmurar de nosotras, desenterrándonos los huesos y enterrándonos la fama. Pues mándoles yo a los leños movibles, que, mal que les pese, hemos de vivir en el mundo, y en las casas principales, aunque muramos de hambre y cubramos con un negro monjil nuestras delicadas o no delicadas carnes, como quien cubre o tapa un muladar con un tapiz en día de procesión. A fe que si me fuera dado, y el tiempo lo pidiera, que yo diera a entender, no sólo a los presentes, sino a todo el mundo, cómo no hay virtud que no se encierre en una dueña. -Yo creo -dijo la duquesa- que mi buena doña Rodríguez tiene razón, y muy grande; pero conviene que aguarde tiempo para volver por sí y por las demás dueñas, para confundir la mala opinión de aquel mal boticario, y desarraigar la que tiene en su pecho el gran Sancho Panza. A lo que Sancho respondió: -Después que tengo humos de gobernador se me han quitado los váguidos de escudero, y no se me da por cuantas dueñas hay un cabrahígo. Adelante pasaran con el coloquio dueñesco, si no oyeran que el pífaro y los tambores volvían a sonar, por donde entendieron que la dueña Dolorida entraba. Preguntó la duquesa al duque si sería bien ir a recebirla, pues era condesa y persona principal. -Por lo que tiene de condesa -respondió Sancho, antes que el duque respondiese-, bien estoy en que vuestras grandezas salgan a recebirla; pero por lo de dueña, soy de parecer que no se muevan un paso. -¿Quién te mete a ti en esto, Sancho? -dijo don Quijote. -¿Quién, señor? -respondió Sancho-. Yo me meto, que puedo meterme, como escudero que ha aprendido los términos de la cortesía en la escuela de vuesa merced, que es el más cortés y bien criado caballero que hay en toda la cortesanía; y en estas cosas, según he oído decir a vuesa merced, tanto se pierde por carta de más como por carta de menos; y al buen entendedor, pocas palabras. -Así es, como Sancho dice -dijo el duque-: veremos el talle de la condesa, y por él tantearemos la cortesía que se le debe. En esto, entraron los tambores y el pífaro, como la vez primera. Y aquí, con este breve capítulo, dio fin el autor, y comenzó el otro, siguiendo la mesma aventura, que es una de las más notables de la historia. Capítulo XXXVIII. Donde se cuenta la que dio de su mala andanza la dueña Dolorida Detrás de los tristes músicos comenzaron a entrar por el jardín adelante hasta cantidad de doce dueñas, repartidas en dos hileras, todas vestidas de unos monjiles anchos, al parecer, de anascote batanado, con unas tocas blancas de delgado canequí, tan luengas que sólo el ribete del monjil descubrían. Tras ellas venía la condesa Trifaldi, a quien traía de la mano el escudero Trifaldín de la Blanca Barba, vestida de finísima y negra bayeta por frisar, que, a venir frisada, descubriera cada grano del grandor de un garbanzo de los buenos de Martos. La cola, o falda, o como llamarla quisieren, era de tres puntas, las cuales se sustentaban en las manos de tres pajes, asimesmo vestidos de luto, haciendo una vistosa y matemática figura con aquellos tres ángulos acutos que las tres puntas formaban, por lo cual cayeron todos los que la falda puntiaguda miraron que por ella se debía llamar la condesa Trifaldi, como si dijésemos la condesa de las Tres Faldas; y así dice Benengeli que fue verdad, y que de su propio apellido se llama la condesa Lobuna, a causa que se criaban en su condado muchos lobos, y que si como eran lobos fueran zorras, la llamaran la condesa Zorruna, por ser costumbre en aquellas partes tomar los señores la denominación de sus nombres de la cosa o cosas en que más sus estados abundan; empero esta condesa, por favorecer la novedad de su falda, dejó el Lobuna y tomó el Trifaldi. Venían las doce dueñas y la señora a paso de procesión, cubiertos los rostros con unos velos negros y no trasparentes como el de Trifaldín, sino tan apretados que ninguna cosa se traslucían. Así como acabó de parecer el dueñesco escuadrón, el duque, la duquesa y don Quijote se pusieron en pie, y todos aquellos que la espaciosa procesión miraban. Pararon las doce dueñas y hicieron calle, por medio de la cual la Dolorida se adelantó, sin dejarla de la mano Trifaldín, viendo lo cual el duque, la duquesa y don Quijote, se adelantaron obra de doce pasos a recebirla. Ella, puesta las rodillas en el suelo, con voz antes basta y ronca que sutil y dilicada, dijo: -Vuestras grandezas sean servidas de no hacer tanta cortesía a este su criado; digo, a esta su criada, porque, según soy de dolorida, no acertaré a responder a lo que debo, a causa que mi estraña y jamás vista desdicha me ha llevado el entendimiento no sé adónde, y debe de ser muy lejos, pues cuanto más le busco menos le hallo. -Sin él estaría -respondió el duque-, señora condesa, el que no descubriese por vuestra persona vuestro valor, el cual, sin más ver, es merecedor de toda la nata de la cortesía y de toda la flor de las bien criadas ceremonias. Y, levantándola de la mano, la llevó a asentar en una silla junto a la duquesa, la cual la recibió asimismo con mucho comedimiento. Don Quijote callaba, y Sancho andaba muerto por ver el rostro de la Trifaldi y de alguna de sus muchas dueñas, pero no fue posible hasta que ellas de su grado y voluntad se descubrieron. Sosegados todos y puestos en silencio, estaban esperando quién le había de romper, y fue la dueña Dolorida con estas palabras: -Confiada estoy, señor poderosísimo, hermosísima señora y discretísimos circunstantes, que ha de hallar mi cuitísima en vuestros valerosísimos pechos acogimiento no menos plácido que generoso y doloroso, porque ella es tal, que es bastante a enternecer los mármoles, y a ablandar los diamantes, y a molificar los aceros de los más endurecidos corazones del mundo; pero, antes que salga a la plaza de vuestros oídos, por no decir orejas, quisiera que me hicieran sabidora si está en este gremio, corro y compañía el acendradísimo caballero don Quijote de la Manchísima y su escuderísimo Panza. -El Panza -antes que otro respondiese, dijo Sancho- aquí esta, y el don Quijotísimo asimismo; y así, podréis, dolorosísima dueñísima, decir lo que quisieridísimis, que todos estamos prontos y aparejadísimos a ser vuestros servidorísimos. En esto se levantó don Quijote, y, encaminando sus razones a la Dolorida dueña, dijo: -Si vuestras cuitas, angustiada señora, se pueden prometer alguna esperanza de remedio por algún valor o fuerzas de algún andante caballero, aquí están las mías, que, aunque flacas y breves, todas se emplearán en vuestro servicio. Yo soy don Quijote de la Mancha, cuyo asumpto es acudir a toda suerte de menesterosos, y, siendo esto así, como lo es, no habéis menester, señora, captar benevolencias ni buscar preámbulos, sino, a la llana y sin rodeos, decir vuestros males, que oídos os escuchan que sabrán, si no remediarlos, dolerse dellos. Oyendo lo cual, la Dolorida dueña hizo señal de querer arrojarse a los pies de don Quijote, y aun se arrojó, y, pugnando por abrazárselos, decía: -Ante estos pies y piernas me arrojo, ¡oh caballero invicto!, por ser los que son basas y colunas de la andante caballería; estos pies quiero besar, de cuyos pasos pende y cuelga todo el remedio de mi desgracia, ¡oh valeroso andante, cuyas verdaderas fazañas dejan atrás y escurecen las fabulosas de los Amadises, Esplandianes y Belianises! Y, dejando a don Quijote, se volvió a Sancho Panza, y, asiéndole de las manos, le dijo: -¡Oh tú, el más leal escudero que jamás sirvió a caballero andante en los presentes ni en los pasados siglos, más luengo en bondad que la barba de Trifaldín, mi acompañador, que está presente!, bien puedes preciarte que en servir al gran don Quijote sirves en cifra a toda la caterva de caballeros que han tratado las armas en el mundo. Conjúrote, por lo que debes a tu bondad fidelísima, me seas buen intercesor con tu dueño, para que luego favorezca a esta humilísima y desdichadísima condesa. A lo que respondió Sancho: -De que sea mi bondad, señoría mía, tan larga y grande como la barba de vuestro escudero, a mí me hace muy poco al caso; barbada y con bigotes tenga yo mi alma cuando desta vida vaya, que es lo que importa, que de las barbas de acá poco o nada me curo; pero, sin esas socaliñas ni plegarias, yo rogaré a mi amo, que sé que me quiere bien, y más agora que me ha menester para cierto negocio, que favorezca y ayude a vuesa merced en todo lo que pudiere. Vuesa merced desembaúle su cuita y cuéntenosla, y deje hacer, que todos nos entenderemos. Reventaban de risa con estas cosas los duques, como aquellos que habían tomado el pulso a la tal aventura, y alababan entre sí la agudeza y disimulación de la Trifaldi, la cual, volviéndose a sentar, dijo: -«Del famoso reino de Candaya, que cae entre la gran Trapobana y el mar del Sur, dos leguas más allá del cabo Comorín, fue señora la reina doña Maguncia, viuda del rey Archipiela, su señor y marido, de cuyo matrimonio tuvieron y procrearon a la infanta Antonomasia, heredera del reino, la cual dicha infanta Antonomasia se crió y creció debajo de mi tutela y doctrina, por ser yo la más antigua y la más principal dueña de su madre. Sucedió, pues, que, yendo días y viniendo días, la niña Antonomasia llegó a edad de catorce años, con tan gran perfeción de hermosura, que no la pudo subir más de punto la naturaleza. ¡Pues digamos agora que la discreción era mocosa! Así era discreta como bella, y era la más bella del mundo, y lo es, si ya los hados invidiosos y las parcas endurecidas no la han cortado la estambre de la vida. Pero no habrán, que no han de permitir los cielos que se haga tanto mal a la tierra como sería llevarse en agraz el racimo del más hermoso veduño del suelo. De esta hermosura, y no como se debe encarecida de mi torpe lengua, se enamoró un número infinito de príncipes, así naturales como estranjeros, entre los cuales osó levantar los pensamientos al cielo de tanta belleza un caballero particular que en la corte estaba, confiado en su mocedad y en su bizarría, y en sus muchas habilidades y gracias, y facilidad y felicidad de ingenio; porque hago saber a vuestras grandezas, si no lo tienen por enojo, que tocaba una guitarra que la hacía hablar, y más que era poeta y gran bailarín, y sabía hacer una jaula de pájaros, que solamente a hacerlas pudiera ganar la vida cuando se viera en estrema necesidad, que todas estas partes y gracias son bastantes a derribar una montaña, no que una delicada doncella. Pero toda su gentileza y buen donaire y todas sus gracias y habilidades fueran poca o ninguna parte para rendir la fortaleza de mi niña, si el ladrón desuellacaras no usara del remedio de rendirme a mí primero. Primero quiso el malandrín y desalmado vagamundo granjearme la voluntad y cohecharme el gusto, para que yo, mal alcaide, le entregase las llaves de la fortaleza que guardaba. En resolución: él me aduló el entendimiento y me rindió la voluntad con no sé qué dijes y brincos que me dio, pero lo que más me hizo postrar y dar conmigo por el suelo fueron unas coplas que le oí cantar una noche desde una reja que caía a una callejuela donde él estaba, que, si mal no me acuerdo, decían: De la dulce mi enemiga nace un mal que al alma hiere, y, por más tormento, quiere que se sienta y no se diga. Parecióme la trova de perlas, y su voz de almíbar, y después acá, digo, desde entonces, viendo el mal en que caí por estos y otros semejantes versos, he considerado que de las buenas y concertadas repúblicas se habían de desterrar los poetas, como aconsejaba Platón, a lo menos, los lascivos, porque escriben unas coplas, no como las del marqués de Mantua, que entretienen y hacen llorar los niños y a las mujeres, sino unas agudezas que, a modo de blandas espinas, os atraviesan el alma, y como rayos os hieren en ella, dejando sano el vestido. Y otra vez cantó: Ven, muerte, tan escondida que no te sienta venir, porque el placer del morir no me torne a dar la vida. Y deste jaez otras coplitas y estrambotes, que cantados encantan y escritos suspenden. Pues, ¿qué cuando se humillan a componer un género de verso que en Candaya se usaba entonces, a quien ellos llamaban seguidillas? Allí era el brincar de las almas, el retozar de la risa, el desasosiego de los cuerpos y, finalmente, el azogue de todos los sentidos. Y así, digo, señores míos, que los tales trovadores con justo título los debían desterrar a las islas de los Lagartos. Pero no tienen ellos la culpa, sino los simples que los alaban y las bobas que los creen; y si yo fuera la buena dueña que debía, no me habían de mover sus trasnochados conceptos, ni había de creer ser verdad aquel decir: "Vivo muriendo, ardo en el yelo, tiemblo en el fuego, espero sin esperanza, pártome y quédome", con otros imposibles desta ralea, de que están sus escritos llenos. Pues, ¿qué cuando prometen el fénix de Arabia, la corona de Aridiana, los caballos del Sol, del Sur las perlas, de Tíbar el oro y de Pancaya el bálsamo? Aquí es donde ellos alargan más la pluma, como les cuesta poco prometer lo que jamás piensan ni pueden cumplir. Pero, ¿dónde me divierto? ¡Ay de mí, desdichada! ¿Qué locura o qué desatino me lleva a contar las ajenas faltas, teniendo tanto que decir de las mías? ¡Ay de mí, otra vez, sin ventura!, que no me rindieron los versos, sino mi simplicidad; no me ablandaron las músicas, sino mi liviandad: mi mucha ignorancia y mi poco advertimiento abrieron el camino y desembarazaron la senda a los pasos de don Clavijo, que éste es el nombre del referido caballero; y así, siendo yo la medianera, él se halló una y muy muchas veces en la estancia de la por mí, y no por él, engañada Antonomasia, debajo del título de verdadero esposo; que, aunque pecadora, no consintiera que sin ser su marido la llegara a la vira de la suela de sus zapatillas. ¡No, no, eso no: el matrimonio ha de ir adelante en cualquier negocio destos que por mí se tratare! Solamente hubo un daño en este negocio, que fue el de la desigualdad, por ser don Clavijo un caballero particular, y la infanta Antonomasia heredera, como ya he dicho, del reino. Algunos días estuvo encubierta y solapada en la sagacidad de mi recato esta maraña, hasta que me pareció que la iba descubriendo a más andar no sé qué hinchazón del vientre de Antonomasia, cuyo temor nos hizo entrar en bureo a los tres, y salió dél que, antes que se saliese a luz el mal recado, don Clavijo pidiese ante el vicario por su mujer a Antonomasia, en fe de una cédula que de ser su esposa la infanta le había hecho, notada por mi ingenio, con tanta fuerza, que las de Sansón no pudieran romperla. Hiciéronse las diligencias, vio el vicario la cédula, tomó el tal vicario la confesión a la señora, confesó de plano, mandóla depositar en casa de un alguacil de corte muy honrado...» A esta sazón, dijo Sancho: -También en Candaya hay alguaciles de corte, poetas y seguidillas, por lo que puedo jurar que imagino que todo el mundo es uno. Pero dése vuesa merced priesa, señora Trifaldi, que es tarde y ya me muero por saber el fin desta tan larga historia. -Sí haré -respondió la condesa. Capítulo XXXIX. Donde la Trifaldi prosigue su estupenda y memorable historia De cualquiera palabra que Sancho decía, la duquesa gustaba tanto como se desesperaba don Quijote; y, mandándole que callase, la Dolorida prosiguió diciendo: -«En fin, al cabo de muchas demandas y respuestas, como la infanta se estaba siempre en sus trece, sin salir ni variar de la primera declaración, el vicario sentenció en favor de don Clavijo, y se la entregó por su legítima esposa, de lo que recibió tanto enojo la reina doña Maguncia, madre de la infanta Antonomasia, que dentro de tres días la enterramos.» -Debió de morir, sin duda -dijo Sancho. -¡Claro está! -respondió Trifaldín-, que en Candaya no se entierran las personas vivas, sino las muertas. -Ya se ha visto, señor escudero -replicó Sancho-, enterrar un desmayado creyendo ser muerto, y parecíame a mí que estaba la reina Maguncia obligada a desmayarse antes que a morirse; que con la vida muchas cosas se remedian, y no fue tan grande el disparate de la infanta que obligase a sentirle tanto. Cuando se hubiera casado esa señora con algún paje suyo, o con otro criado de su casa, como han hecho otras muchas, según he oído decir, fuera el daño sin remedio; pero el haberse casado con un caballero tan gentilhombre y tan entendido como aquí nos le han pintado, en verdad en verdad que, aunque fue necedad, no fue tan grande como se piensa; porque, según las reglas de mi señor, que está presente y no me dejará mentir, así como se hacen de los hombres letrados los obispos, se pueden hacer de los caballeros, y más si son andantes, los reyes y los emperadores. -Razón tienes, Sancho -dijo don Quijote-, porque un caballero andante, como tenga dos dedos de ventura, está en potencia propincua de ser el mayor señor del mundo. Pero, pase adelante la señora Dolorida, que a mí se me trasluce que le falta por contar lo amargo desta hasta aquí dulce historia. -Y ¡cómo si queda lo amargo! -respondió la condesa-, y tan amargo que en su comparación son dulces las tueras y sabrosas las adelfas. «Muerta, pues, la reina, y no desmayada, la enterramos; y, apenas la cubrimos con la tierra y apenas le dimos el último vale, cuando, quis talia fando temperet a lachrymis?, puesto sobre un caballo de madera, pareció encima de la sepultura de la reina el gigante Malambruno, primo cormano de Maguncia, que junto con ser cruel era encantador, el cual con sus artes, en venganza de la muerte de su cormana, y por castigo del atrevimiento de don Clavijo, y por despecho de la demasía de Antonomasia, los dejó encantados sobre la mesma sepultura: a ella, convertida en una jimia de bronce, y a él, en un espantoso cocodrilo de un metal no conocido, y entre los dos está un padrón, asimismo de metal, y en él escritas en lengua siríaca unas letras que, habiéndose declarado en la candayesca, y ahora en la castellana, encierran esta sentencia: "No cobrarán su primera forma estos dos atrevidos amantes hasta que el valeroso manchego venga conmigo a las manos en singular batalla, que para solo su gran valor guardan los hados esta nunca vista aventura". Hecho esto, sacó de la vaina un ancho y desmesurado alfanje, y, asiéndome a mí por los cabellos, hizo finta de querer segarme la gola y cortarme cercen la cabeza. Turbéme, pegóseme la voz a la garganta, quedé mohína en todo estremo, pero, con todo, me esforcé lo más que pude, y, con voz tembladora y doliente, le dije tantas y tales cosas, que le hicieron suspender la ejecución de tan riguroso castigo. Finalmente, hizo traer ante sí todas las dueñas de palacio, que fueron estas que están presentes, y, después de haber exagerado nuestra culpa y vituperado las condiciones de las dueñas, sus malas mañas y peores trazas, y cargando a todas la culpa que yo sola tenía, dijo que no quería con pena capital castigarnos, sino con otras penas dilatadas, que nos diesen una muerte civil y continua; y, en aquel mismo momento y punto que acabó de decir esto, sentimos todas que se nos abrían los poros de la cara, y que por toda ella nos punzaban como con puntas de agujas. Acudimos luego con las manos a los rostros, y hallámonos de la manera que ahora veréis.» Y luego la Dolorida y las demás dueñas alzaron los antifaces con que cubiertas venían, y descubrieron los rostros, todos poblados de barbas, cuáles rubias, cuáles negras, cuáles blancas y cuáles albarrazadas, de cuya vista mostraron quedar admirados el duque y la duquesa, pasmados don Quijote y Sancho, y atónitos todos los presentes. Y la Trifaldi prosiguió: -«Desta manera nos castigó aquel follón y malintencionado de Malambruno, cubriendo la blandura y morbidez de nuestros rostros con la aspereza destas cerdas, que pluguiera al cielo que antes con su desmesurado alfanje nos hubiera derribado las testas, que no que nos asombrara la luz de nuestras caras con esta borra que nos cubre; porque si entramos en cuenta, señores míos (y esto que voy a decir agora lo quisiera decir hechos mis ojos fuentes, pero la consideración de nuestra desgracia, y los mares que hasta aquí han llovido, los tienen sin humor y secos como aristas, y así, lo diré sin lágrimas), digo, pues, que ¿adónde podrá ir una dueña con barbas? ¿Qué padre o qué madre se dolerá della? ¿Quién la dará ayuda? Pues, aun cuando tiene la tez lisa y el rostro martirizado con mil suertes de menjurjes y mudas, apenas halla quien bien la quiera, ¿qué hará cuando descubra hecho un bosque su rostro? ¡Oh dueñas y compañeras mías, en desdichado punto nacimos, en hora menguada nuestros padres nos engendraron!» Y, diciendo esto, dio muestras de desmayarse. Capítulo XL. De cosas que atañen y tocan a esta aventura y a esta memorable historia Real y verdaderamente, todos los que gustan de semejantes historias como ésta deben de mostrarse agradecidos a Cide Hamete, su autor primero, por la curiosidad que tuvo en contarnos las semínimas della, sin dejar cosa, por menuda que fuese, que no la sacase a luz distintamente: pinta los pensamientos, descubre las imaginaciones, responde a las tácitas, aclara las dudas, resuelve los argumentos; finalmente, los átomos del más curioso deseo manifiesta. ¡Oh autor celebérrimo! ¡Oh don Quijote dichoso! ¡Oh Dulcinea famosa! ¡Oh Sancho Panza gracioso! Todos juntos y cada uno de por sí viváis siglos infinitos, para gusto y general pasatiempo de los vivientes. Dice, pues, la historia que, así como Sancho vio desmayada a la Dolorida, dijo: -Por la fe de hombre de bien, juro, y por el siglo de todos mis pasados los Panzas, que jamás he oído ni visto, ni mi amo me ha contado, ni en su pensamiento ha cabido, semejante aventura como ésta. Válgate mil satanases, por no maldecirte por encantador y gigante, Malambruno; y ¿no hallaste otro género de castigo que dar a estas pecadoras sino el de barbarlas? ¿Cómo y no fuera mejor, y a ellas les estuviera más a cuento, quitarles la mitad de las narices de medio arriba, aunque hablaran gangoso, que no ponerles barbas? Apostaré yo que no tienen hacienda para pagar a quien las rape. -Así es la verdad, señor -respondió una de las doce-, que no tenemos hacienda para mondarnos; y así, hemos tomado algunas de nosotras por remedio ahorrativo de usar de unos pegotes o parches pegajosos, y aplicándolos a los rostros, y tirando de golpe, quedamos rasas y lisas como fondo de mortero de piedra; que, puesto que hay en Candaya mujeres que andan de casa en casa a quitar el vello y a pulir las cejas y hacer otros menjurjes tocantes a mujeres, nosotras las dueñas de mi señora por jamás quisimos admitirlas, porque las más oliscan a terceras, habiendo dejado de ser primas; y si por el señor don Quijote no somos remediadas, con barbas nos llevarán a la sepultura. -Yo me pelaría las mías -dijo don Quijote- en tierra de moros, si no remediase las vuestras. A este punto, volvió de su desmayo la Trifaldi y dijo: -El retintín desa promesa, valeroso caballero, en medio de mi desmayo llegó a mis oídos, y ha sido parte para que yo dél vuelva y cobre todos mis sentidos; y así, de nuevo os suplico, andante ínclito y señor indomable, vuestra graciosa promesa se convierta en obra. -Por mí no quedará -respondió don Quijote-: ved, señora, qué es lo que tengo de hacer, que el ánimo está muy pronto para serviros. -Es el caso -respondió la Dolorida -que desde aquí al reino de Candaya, si se va por tierra, hay cinco mil leguas, dos más a menos; pero si se va por el aire y por la línea recta, hay tres mil y docientas y veinte y siete. Es también de saber que Malambruno me dijo que cuando la suerte me deparase al caballero nuestro libertador, que él le enviaría una cabalgadura harto mejor y con menos malicias que las que son de retorno, porque ha de ser aquel mesmo caballo de madera sobre quien llevó el valeroso Pierres robada a la linda Magalona, el cual caballo se rige por una clavija que tiene en la frente, que le sirve de freno, y vuela por el aire con tanta ligereza que parece que los mesmos diablos le llevan. Este tal caballo, según es tradición antigua, fue compuesto por aquel sabio Merlín; prestósele a Pierres, que era su amigo, con el cual hizo grandes viajes, y robó, como se ha dicho, a la linda Magalona, llevándola a las ancas por el aire, dejando embobados a cuantos desde la tierra los miraban; y no le prestaba sino a quien él quería, o mejor se lo pagaba; y desde el gran Pierres hasta ahora no sabemos que haya subido alguno en él. De allí le ha sacado Malambruno con sus artes, y le tiene en su poder, y se sirve dél en sus viajes, que los hace por momentos, por diversas partes del mundo, y hoy está aquí y mañana en Francia y otro día en Potosí; y es lo bueno que el tal caballo ni come, ni duerme ni gasta herraduras, y lleva un portante por los aires, sin tener alas, que el que lleva encima puede llevar una taza llena de agua en la mano sin que se le derrame gota, según camina llano y reposado; por lo cual la linda Magalona se holgaba mucho de andar caballera en él. A esto dijo Sancho: -Para andar reposado y llano, mi rucio, puesto que no anda por los aires; pero por la tierra, yo le cutiré con cuantos portantes hay en el mundo. Riéronse todos, y la Dolorida prosiguió: -Y este tal caballo, si es que Malambruno quiere dar fin a nuestra desgracia, antes que sea media hora entrada la noche, estará en nuestra presencia, porque él me significó que la señal que me daría por donde yo entendiese que había hallado el caballero que buscaba, sería enviarme el caballo, donde fuese con comodidad y presteza. -Y ¿cuántos caben en ese caballo? -preguntó Sancho. La Dolorida respondió: -Dos personas: la una en la silla y la otra en las ancas; y, por la mayor parte, estas tales dos personas son caballero y escudero, cuando falta alguna robada doncella. -Querría yo saber, señora Dolorida -dijo Sancho-, qué nombre tiene ese caballo. -El nombre -respondió la Dolorida- no es como el caballo de Belorofonte, que se llamaba Pegaso, ni como el del Magno Alejandro, llamado Bucéfalo, ni como el del furioso Orlando, cuyo nombre fue Brilladoro, ni menos Bayarte, que fue el de Reinaldos de Montalbán, ni Frontino, como el de Rugero, ni Bootes ni Peritoa, como dicen que se llaman los del Sol, ni tampoco se llama Orelia, como el caballo en que el desdichado Rodrigo, último rey de los godos, entró en la batalla donde perdió la vida y el reino. -Yo apostaré -dijo Sancho- que, pues no le han dado ninguno desos famosos nombres de caballos tan conocidos, que tampoco le habrán dado el de mi amo, Rocinante, que en ser propio excede a todos los que se han nombrado. -Así es -respondió la barbada condesa-, pero todavía le cuadra mucho, porque se llama Clavileño el Alígero, cuyo nombre conviene con el ser de leño, y con la clavija que trae en la frente, y con la ligereza con que camina; y así, en cuanto al nombre, bien puede competir con el famoso Rocinante. -No me descontenta el nombre -replicó Sancho-, pero ¿con qué freno o con qué jáquima se gobierna? -Ya he dicho -respondió la Trifaldi- que con la clavija, que, volviéndola a una parte o a otra, el caballero que va encima le hace caminar como quiere, o ya por los aires, o ya rastreando y casi barriendo la tierra, o por el medio, que es el que se busca y se ha de tener en todas las acciones bien ordenadas. -Ya lo querría ver -respondió Sancho-, pero pensar que tengo de subir en él, ni en la silla ni en las ancas, es pedir peras al olmo. ¡Bueno es que apenas puedo tenerme en mi rucio, y sobre un albarda más blanda que la mesma seda, y querrían ahora que me tuviese en unas ancas de tabla, sin cojín ni almohada alguna! Pardiez, yo no me pienso moler por quitar las barbas a nadie: cada cual se rape como más le viniere a cuento, que yo no pienso acompañar a mi señor en tan largo viaje. Cuanto más, que yo no debo de hacer al caso para el rapamiento destas barbas como lo soy para el desencanto de mi señora Dulcinea. -Sí sois, amigo -respondió la Trifaldi-, y tanto, que, sin vuestra presencia, entiendo que no haremos nada. -¡Aquí del rey! -dijo Sancho-: ¿qué tienen que ver los escuderos con las aventuras de sus señores? ¿Hanse de llevar ellos la fama de las que acaban, y hemos de llevar nosotros el trabajo? ¡Cuerpo de mí! Aun si dijesen los historiadores: "El tal caballero acabó la tal y tal aventura, pero con ayuda de fulano, su escudero, sin el cual fuera imposible el acabarla". Pero, ¡que escriban a secas: "Don Paralipomenón de las Tres Estrellas acabó la aventura de los seis vestiglos", sin nombrar la persona de su escudero, que se halló presente a todo, como si no fuera en el mundo! Ahora, señores, vuelvo a decir que mi señor se puede ir solo, y buen provecho le haga, que yo me quedaré aquí, en compañía de la duquesa mi señora, y podría ser que cuando volviese hallase mejorada la causa de la señora Dulcinea en tercio y quinto; porque pienso, en los ratos ociosos y desocupados, darme una tanda de azotes que no me la cubra pelo. -Con todo eso, le habéis de acompañar si fuere necesario, buen Sancho, porque os lo rogarán buenos; que no han de quedar por vuestro inútil temor tan poblados los rostros destas señoras; que, cierto, sería mal caso. -¡Aquí del rey otra vez! -replicó Sancho-. Cuando esta caridad se hiciera por algunas doncellas recogidas, o por algunas niñas de la doctrina, pudiera el hombre aventurarse a cualquier trabajo, pero que lo sufra por quitar las barbas a dueñas, ¡mal año! Mas que las viese yo a todas con barbas, desde la mayor hasta la menor, y de la más melindrosa hasta la más repulgada. -Mal estáis con las dueñas, Sancho amigo -dijo la duquesa-: mucho os vais tras la opinión del boticario toledano. Pues a fe que no tenéis razón; que dueñas hay en mi casa que pueden ser ejemplo de dueñas, que aquí está mi doña Rodríguez, que no me dejará decir otra cosa. -Mas que la diga vuestra excelencia -dijo Rodríguez-, que Dios sabe la verdad de todo, y buenas o malas, barbadas o lampiñas que seamos las dueñas, también nos parió nuestra madre como a las otras mujeres; y, pues Dios nos echó en el mundo, Él sabe para qué, y a su misericordia me atengo, y no a las barbas de nadie. -Ahora bien, señora Rodríguez -dijo don Quijote-, y señora Trifaldi y compañía, yo espero en el cielo que mirará con buenos ojos vuestras cuitas, que Sancho hará lo que yo le mandare, ya viniese Clavileño y ya me viese con Malambruno; que yo sé que no habría navaja que con más facilidad rapase a vuestras mercedes como mi espada raparía de los hombros la cabeza de Malambruno; que Dios sufre a los malos, pero no para siempre. -¡Ay! -dijo a esta sazón la Dolorida-, con benignos ojos miren a vuestra grandeza, valeroso caballero, todas las estrellas de las regiones celestes, e infundan en vuestro ánimo toda prosperidad y valentía para ser escudo y amparo del vituperoso y abatido género dueñesco, abominado de boticarios, murmurado de escuderos y socaliñado de pajes; que mal haya la bellaca que en la flor de su edad no se metió primero a ser monja que a dueña. ¡Desdichadas de nosotras las dueñas, que, aunque vengamos por línea recta, de varón en varón, del mismo Héctor el troyano, no dejaran de echaros un vos nuestras señoras, si pensasen por ello ser reinas! ¡Oh gigante Malambruno, que, aunque eres encantador, eres certísimo en tus promesas!, envíanos ya al sin par Clavileño, para que nuestra desdicha se acabe, que si entra el calor y estas nuestras barbas duran, ¡guay de nuestra ventura! Dijo esto con tanto sentimiento la Trifaldi, que sacó las lágrimas de los ojos de todos los circunstantes, y aun arrasó los de Sancho, y propuso en su corazón de acompañar a su señor hasta las últimas partes del mundo, si es que en ello consistiese quitar la lana de aquellos venerables rostros. Capítulo XLI. De la venida de Clavileño, con el fin desta dilatada aventura Llegó en esto la noche, y con ella el punto determinado en que el famoso caballo Clavileño viniese, cuya tardanza fatigaba ya a don Quijote, pareciéndole que, pues Malambruno se detenía en enviarle, o que él no era el caballero para quien estaba guardada aquella aventura, o que Malambruno no osaba venir con él a singular batalla. Pero veis aquí cuando a deshora entraron por el jardín cuatro salvajes, vestidos todos de verde yedra, que sobre sus hombros traían un gran caballo de madera. Pusiéronle de pies en el suelo, y uno de los salvajes dijo: -Suba sobre esta máquina el que tuviere ánimo para ello. -Aquí -dijo Sancho- yo no subo, porque ni tengo ánimo ni soy caballero. Y el salvaje prosiguió diciendo: -Y ocupe las ancas el escudero, si es que lo tiene, y fíese del valeroso Malambruno, que si no fuere de su espada, de ninguna otra, ni de otra malicia, será ofendido; y no hay más que torcer esta clavija que sobre el cuello trae puesta, que él los llevará por los aires adonde los atiende Malambruno; pero, porque la alteza y sublimidad del camino no les cause váguidos, se han de cubrir los ojos hasta que el caballo relinche, que será señal de haber dado fin a su viaje. Esto dicho, dejando a Clavileño, con gentil continente se volvieron por donde habían venido. La Dolorida, así como vio al caballo, casi con lágrimas dijo a don Quijote: -Valeroso caballero, las promesas de Malambruno han sido ciertas: el caballo está en casa, nuestras barbas crecen, y cada una de nosotras y con cada pelo dellas te suplicamos nos rapes y tundas, pues no está en más sino en que subas en él con tu escudero y des felice principio a vuestro nuevo viaje. -Eso haré yo, señora condesa Trifaldi, de muy buen grado y de mejor talante, sin ponerme a tomar cojín, ni calzarme espuelas, por no detenerme: tanta es la gana que tengo de veros a vos, señora, y a todas estas dueñas rasas y mondas. -Eso no haré yo -dijo Sancho-, ni de malo ni de buen talante, en ninguna manera; y si es que este rapamiento no se puede hacer sin que yo suba a las ancas, bien puede buscar mi señor otro escudero que le acompañe, y estas señoras otro modo de alisarse los rostros; que yo no soy brujo, para gustar de andar por los aires. Y ¿qué dirán mis insulanos cuando sepan que su gobernador se anda paseando por los vientos? Y otra cosa más: que habiendo tres mil y tantas leguas de aquí a Candaya, si el caballo se cansa o el gigante se enoja, tardaremos en dar la vuelta media docena de años, y ya ni habrá ínsula ni ínsulos en el mundo que me conozan; y, pues se dice comúnmente que en la tardanza va el peligro, y que cuando te dieren la vaquilla acudas con la soguilla, perdónenme las barbas destas señoras, que bien se está San Pedro en Roma; quiero decir que bien me estoy en esta casa, donde tanta merced se me hace y de cuyo dueño tan gran bien espero como es verme gobernador. A lo que el duque dijo: -Sancho amigo, la ínsula que yo os he prometido no es movible ni fugitiva: raíces tiene tan hondas, echadas en los abismos de la tierra, que no la arrancarán ni mudarán de donde está a tres tirones; y, pues vos sabéis que sé yo que no hay ninguno género de oficio destos de mayor cantía que no se granjee con alguna suerte de cohecho, cuál más, cuál menos, el que yo quiero llevar por este gobierno es que vais con vuestro señor don Quijote a dar cima y cabo a esta memorable aventura; que ahora volváis sobre Clavileño con la brevedad que su ligereza promete, ora la contraria fortuna os traiga y vuelva a pie, hecho romero, de mesón en mesón y de venta en venta, siempre que volviéredes hallaréis vuestra ínsula donde la dejáis, y a vuestros insulanos con el mesmo deseo de recebiros por su gobernador que siempre han tenido, y mi voluntad será la mesma; y no pongáis duda en esta verdad, señor Sancho, que sería hacer notorio agravio al deseo que de serviros tengo. -No más, señor -dijo Sancho-: yo soy un pobre escudero y no puedo llevar a cuestas tantas cortesías; suba mi amo, tápenme estos ojos y encomiéndenme a Dios, y avísenme si cuando vamos por esas altanerías podré encomendarme a Nuestro Señor o invocar los ángeles que me favorezcan. A lo que respondió Trifaldi: -Sancho, bien podéis encomendaros a Dios o a quien quisiéredes, que Malambruno, aunque es encantador, es cristiano, y hace sus encantamentos con mucha sagacidad y con mucho tiento, sin meterse con nadie. -¡Ea, pues -dijo Sancho-, Dios me ayude y la Santísima Trinidad de Gaeta! -Desde la memorable aventura de los batanes -dijo don Quijote-, nunca he visto a Sancho con tanto temor como ahora, y si yo fuera tan agorero como otros, su pusilanimidad me hiciera algunas cosquillas en el ánimo. Pero llegaos aquí, Sancho, que con licencia destos señores os quiero hablar aparte dos palabras. Y, apartando a Sancho entre unos árboles del jardín y asiéndole ambas las manos, le dijo: -Ya vees, Sancho hermano, el largo viaje que nos espera, y que sabe Dios cuándo volveremos dél, ni la comodidad y espacio que nos darán los negocios; así, querría que ahora te retirases en tu aposento, como que vas a buscar alguna cosa necesaria para el camino, y, en un daca las pajas, te dieses, a buena cuenta de los tres mil y trecientos azotes a que estás obligado, siquiera quinientos, que dados te los tendrás, que el comenzar las cosas es tenerlas medio acabadas. -¡Par Dios -dijo Sancho-, que vuestra merced debe de ser menguado! Esto es como aquello que dicen: "¡en priesa me vees y doncellez me demandas!" ¿Ahora que tengo de ir sentado en una tabla rasa, quiere vuestra merced que me lastime las posas? En verdad en verdad que no tiene vuestra merced razón. Vamos ahora a rapar estas dueñas, que a la vuelta yo le prometo a vuestra merced, como quien soy, de darme tanta priesa a salir de mi obligación, que vuestra merced se contente, y no le digo más. Y don Quijote respondió: -Pues con esa promesa, buen Sancho, voy consolado, y creo que la cumplirás, porque, en efecto, aunque tonto, eres hombre verídico. -No soy verde, sino moreno -dijo Sancho-, pero aunque fuera de mezcla, cumpliera mi palabra. Y con esto se volvieron a subir en Clavileño, y al subir dijo don Quijote: -Tapaos, Sancho, y subid, Sancho, que quien de tan lueñes tierras envía por nosotros no será para engañarnos, por la poca gloria que le puede redundar de engañar a quien dél se fía; y, puesto que todo sucediese al revés de lo que imagino, la gloria de haber emprendido esta hazaña no la podrá escurecer malicia alguna. -Vamos, señor -dijo Sancho-, que las barbas y lágrimas destas señoras las tengo clavadas en el corazón, y no comeré bocado que bien me sepa hasta verlas en su primera lisura. Suba vuesa merced y tápese primero, que si yo tengo de ir a las ancas, claro está que primero sube el de la silla. -Así es la verdad -replicó don Quijote. Y, sacando un pañuelo de la faldriquera, pidió a la Dolorida que le cubriese muy bien los ojos, y, habiéndoselos cubierto, se volvió a descubrir y dijo: -Si mal no me acuerdo, yo he leído en Virgilio aquello del Paladión de Troya, que fue un caballo de madera que los griegos presentaron a la diosa Palas, el cual iba preñado de caballeros armados, que después fueron la total ruina de Troya; y así, será bien ver primero lo que Clavileño trae en su estómago. -No hay para qué -dijo la Dolorida-, que yo le fío y sé que Malambruno no tiene nada de malicioso ni de traidor; vuesa merced, señor don Quijote, suba sin pavor alguno, y a mi daño si alguno le sucediere. Parecióle a don Quijote que cualquiera cosa que replicase acerca de su seguridad sería poner en detrimento su valentía; y así, sin más altercar, subió sobre Clavileño y le tentó la clavija, que fácilmente se rodeaba; y, como no tenía estribos y le colgaban las piernas, no parecía sino figura de tapiz flamenco pintada o tejida en algún romano triunfo. De mal talante y poco a poco llegó a subir Sancho, y, acomodándose lo mejor que pudo en las ancas, las halló algo duras y no nada blandas, y pidió al duque que, si fuese posible, le acomodasen de algún cojín o de alguna almohada, aunque fuese del estrado de su señora la duquesa, o del lecho de algún paje, porque las ancas de aquel caballo más parecían de mármol que de leño. A esto dijo la Trifaldi que ningún jaez ni ningún género de adorno sufría sobre sí Clavileño; que lo que podía hacer era ponerse a mujeriegas, y que así no sentiría tanto la dureza. Hízolo así Sancho, y, diciendo ''a Dios'', se dejó vendar los ojos, y, ya después de vendados, se volvió a descubrir, y, mirando a todos los del jardín tiernamente y con lágrimas, dijo que le ayudasen en aquel trance con sendos paternostres y sendas avemarías, porque Dios deparase quien por ellos los dijese cuando en semejantes trances se viesen. A lo que dijo don Quijote: -Ladrón, ¿estás puesto en la horca por ventura, o en el último término de la vida, para usar de semejantes plegarias? ¿No estás, desalmada y cobarde criatura, en el mismo lugar que ocupó la linda Magalona, del cual decendió, no a la sepultura, sino a ser reina de Francia, si no mienten las historias? Y yo, que voy a tu lado, ¿no puedo ponerme al del valeroso Pierres, que oprimió este mismo lugar que yo ahora oprimo? Cúbrete, cúbrete, animal descorazonado, y no te salga a la boca el temor que tienes, a lo menos en presencia mía. -Tápenme -respondió Sancho-; y, pues no quieren que me encomiende a Dios ni que sea encomendado, ¿qué mucho que tema no ande por aquí alguna región de diablos que den con nosotros en Peralvillo? Cubriéronse, y, sintiendo don Quijote que estaba como había de estar, tentó la clavija, y, apenas hubo puesto los dedos en ella, cuando todas las dueñas y cuantos estaban presentes levantaron las voces, diciendo: -¡Dios te guíe, valeroso caballero! -¡Dios sea contigo, escudero intrépido! -¡Ya, ya vais por esos aires, rompiéndolos con más velocidad que una saeta! -¡Ya comenzáis a suspender y admirar a cuantos desde la tierra os están mirando! -¡Tente, valeroso Sancho, que te bamboleas! ¡Mira no cayas, que será peor tu caída que la del atrevido mozo que quiso regir el carro del Sol, su padre! Oyó Sancho las voces, y, apretándose con su amo y ciñiéndole con los brazos, le dijo: -Señor, ¿cómo dicen éstos que vamos tan altos, si alcanzan acá sus voces, y no parecen sino que están aquí hablando junto a nosotros? -No repares en eso, Sancho, que, como estas cosas y estas volaterías van fuera de los cursos ordinarios, de mil leguas verás y oirás lo que quisieres. Y no me aprietes tanto, que me derribas; y en verdad que no sé de qué te turbas ni te espantas, que osaré jurar que en todos los días de mi vida he subido en cabalgadura de paso más llano: no parece sino que no nos movemos de un lugar. Destierra, amigo, el miedo, que, en efecto, la cosa va como ha de ir y el viento llevamos en popa. -Así es la verdad -respondió Sancho-, que por este lado me da un viento tan recio, que parece que con mil fuelles me están soplando. Y así era ello, que unos grandes fuelles le estaban haciendo aire: tan bien trazada estaba la tal aventura por el duque y la duquesa y su mayordomo, que no le faltó requisito que la dejase de hacer perfecta. Sintiéndose, pues, soplar don Quijote, dijo: -Sin duda alguna, Sancho, que ya debemos de llegar a la segunda región del aire, adonde se engendra el granizo, las nieves; los truenos, los relámpagos y los rayos se engendran en la tercera región, y si es que desta manera vamos subiendo, presto daremos en la región del fuego, y no sé yo cómo templar esta clavija para que no subamos donde nos abrasemos. En esto, con unas estopas ligeras de encenderse y apagarse, desde lejos, pendientes de una caña, les calentaban los rostros. Sancho, que sintió el calor, dijo: -Que me maten si no estamos ya en el lugar del fuego, o bien cerca, porque una gran parte de mi barba se me ha chamuscado, y estoy, señor, por descubrirme y ver en qué parte estamos. -No hagas tal -respondió don Quijote-, y acuérdate del verdadero cuento del licenciado Torralba, a quien llevaron los diablos en volandas por el aire, caballero en una caña, cerrados los ojos, y en doce horas llegó a Roma, y se apeó en Torre de Nona, que es una calle de la ciudad, y vio todo el fracaso y asalto y muerte de Borbón, y por la mañana ya estaba de vuelta en Madrid, donde dio cuenta de todo lo que había visto; el cual asimismo dijo que cuando iba por el aire le mandó el diablo que abriese los ojos, y los abrió, y se vio tan cerca, a su parecer, del cuerpo de la luna, que la pudiera asir con la mano, y que no osó mirar a la tierra por no desvanecerse. Así que, Sancho, no hay para qué descubrirnos; que, el que nos lleva a cargo, él dará cuenta de nosotros, y quizá vamos tomando puntas y subiendo en alto para dejarnos caer de una sobre el reino de Candaya, como hace el sacre o neblí sobre la garza para cogerla, por más que se remonte; y, aunque nos parece que no ha media hora que nos partimos del jardín, creéme que debemos de haber hecho gran camino. -No sé lo que es -respondió Sancho Panza-, sólo sé decir que si la señora Magallanes o Magalona se contentó destas ancas, que no debía de ser muy tierna de carnes. Todas estas pláticas de los dos valientes oían el duque y la duquesa y los del jardín, de que recibían estraordinario contento; y, queriendo dar remate a la estraña y bien fabricada aventura, por la cola de Clavileño le pegaron fuego con unas estopas, y al punto, por estar el caballo lleno de cohetes tronadores, voló por los aires, con estraño ruido, y dio con don Quijote y con Sancho Panza en el suelo, medio chamuscados. En este tiempo ya se habían desparecido del jardín todo el barbado escuadrón de las dueñas y la Trifaldi y todo, y los del jardín quedaron como desmayados, tendidos por el suelo. Don Quijote y Sancho se levantaron maltrechos, y, mirando a todas partes, quedaron atónitos de verse en el mesmo jardín de donde habían partido y de ver tendido por tierra tanto número de gente; y creció más su admiración cuando a un lado del jardín vieron hincada una gran lanza en el suelo y pendiente della y de dos cordones de seda verde un pergamino liso y blanco, en el cual, con grandes letras de oro, estaba escrito lo siguiente: El ínclito caballero don Quijote de la Mancha feneció y acabó la aventura de la condesa Trifaldi, por otro nombre llamada la dueña Dolorida, y compañía, con sólo intentarla. Malambruno se da por contento y satisfecho a toda su voluntad, y las barbas de las dueñas ya quedan lisas y mondas, y los reyes don Clavijo y Antonomasia en su prístino estado. Y, cuando se cumpliere el escuderil vápulo, la blanca paloma se verá libre de los pestíferos girifaltes que la persiguen, y en brazos de su querido arrullador; que así está ordenado por el sabio Merlín, protoencantador de los encantadores. Habiendo, pues, don Quijote leído las letras del pergamino, claro entendió que del desencanto de Dulcinea hablaban; y, dando muchas gracias al cielo de que con tan poco peligro hubiese acabado tan gran fecho, reduciendo a su pasada tez los rostros de las venerables dueñas, que ya no parecían, se fue adonde el duque y la duquesa aún no habían vuelto en sí, y, trabando de la mano al duque, le dijo: -¡Ea, buen señor, buen ánimo; buen ánimo, que todo es nada! La aventura es ya acabada sin daño de barras, como lo muestra claro el escrito que en aquel padrón está puesto. El duque, poco a poco, y como quien de un pesado sueño recuerda, fue volviendo en sí, y por el mismo tenor la duquesa y todos los que por el jardín estaban caídos, con tales muestras de maravilla y espanto, que casi se podían dar a entender haberles acontecido de veras lo que tan bien sabían fingir de burlas. Leyó el duque el cartel con los ojos medio cerrados, y luego, con los brazos abiertos, fue a abrazar a don Quijote, diciéndole ser el más buen caballero que en ningún siglo se hubiese visto. Sancho andaba mirando por la Dolorida, por ver qué rostro tenía sin las barbas, y si era tan hermosa sin ellas como su gallarda disposición prometía, pero dijéronle que, así como Clavileño bajó ardiendo por los aires y dio en el suelo, todo el escuadrón de las dueñas, con la Trifaldi, había desaparecido, y que ya iban rapadas y sin cañones. Preguntó la duquesa a Sancho que cómo le había ido en aquel largo viaje. A lo cual Sancho respondió: -Yo, señora, sentí que íbamos, según mi señor me dijo, volando por la región del fuego, y quise descubrirme un poco los ojos, pero mi amo, a quien pedí licencia para descubrirme, no la consintió; mas yo, que tengo no sé qué briznas de curioso y de desear saber lo que se me estorba y impide, bonitamente y sin que nadie lo viese, por junto a las narices aparté tanto cuanto el pañizuelo que me tapaba los ojos, y por allí miré hacia la tierra, y parecióme que toda ella no era mayor que un grano de mostaza, y los hombres que andaban sobre ella, poco mayores que avellanas; porque se vea cuán altos debíamos de ir entonces. A esto dijo la duquesa: -Sancho amigo, mirad lo que decís, que, a lo que parece, vos no vistes la tierra, sino los hombres que andaban sobre ella; y está claro que si la tierra os pareció como un grano de mostaza, y cada hombre como una avellana, un hombre solo había de cubrir toda la tierra. -Así es verdad -respondió Sancho-, pero, con todo eso, la descubrí por un ladito, y la vi toda. -Mirad, Sancho -dijo la duquesa-, que por un ladito no se vee el todo de lo que se mira. -Yo no sé esas miradas -replicó Sancho-: sólo sé que será bien que vuestra señoría entienda que, pues volábamos por encantamento, por encantamento podía yo ver toda la tierra y todos los hombres por doquiera que los mirara; y si esto no se me cree, tampoco creerá vuestra merced cómo, descubriéndome por junto a las cejas, me vi tan junto al cielo que no había de mí a él palmo y medio, y por lo que puedo jurar, señora mía, que es muy grande además. Y sucedió que íbamos por parte donde están las siete cabrillas; y en Dios y en mi ánima que, como yo en mi niñez fui en mi tierra cabrerizo, que así como las vi, ¡me dio una gana de entretenerme con ellas un rato...! Y si no le cumpliera me parece que reventara. Vengo, pues, y tomo, y ¿qué hago? Sin decir nada a nadie, ni a mi señor tampoco, bonita y pasitamente me apeé de Clavileño, y me entretuve con las cabrillas, que son como unos alhelíes y como unas flores, casi tres cuartos de hora, y Clavileño no se movió de un lugar, ni pasó adelante. -Y, en tanto que el buen Sancho se entretenía con las cabras -preguntó el duque-, ¿en qué se entretenía el señor don Quijote? A lo que don Quijote respondió: -Como todas estas cosas y estos tales sucesos van fuera del orden natural, no es mucho que Sancho diga lo que dice. De mí sé decir que ni me descubrí por alto ni por bajo, ni vi el cielo ni la tierra, ni la mar ni las arenas. Bien es verdad que sentí que pasaba por la región del aire, y aun que tocaba a la del fuego; pero que pasásemos de allí no lo puedo creer, pues, estando la región del fuego entre el cielo de la luna y la última región del aire, no podíamos llegar al cielo donde están las siete cabrillas que Sancho dice, sin abrasarnos; y, pues no nos asuramos, o Sancho miente o Sancho sueña. -Ni miento ni sueño -respondió Sancho-: si no, pregúntenme las señas de las tales cabras, y por ellas verán si digo verdad o no. -Dígalas, pues, Sancho -dijo la duquesa. -Son -respondió Sancho- las dos verdes, las dos encarnadas, las dos azules, y la una de mezcla. -Nueva manera de cabras es ésa -dijo el duque-, y por esta nuestra región del suelo no se usan tales colores; digo, cabras de tales colores. -Bien claro está eso -dijo Sancho-; sí, que diferencia ha de haber de las cabras del cielo a las del suelo. -Decidme, Sancho -preguntó el duque-: ¿vistes allá en entre esas cabras algún cabrón? -No, señor -respondió Sancho-, pero oí decir que ninguno pasaba de los cuernos de la luna. No quisieron preguntarle más de su viaje, porque les pareció que llevaba Sancho hilo de pasearse por todos los cielos, y dar nuevas de cuanto allá pasaba, sin haberse movido del jardín. En resolución, éste fue el fin de la aventura de la dueña Dolorida, que dio que reír a los duques, no sólo aquel tiempo, sino el de toda su vida, y que contar a Sancho siglos, si los viviera; y, llegándose don Quijote a Sancho, al oído le dijo: -Sancho, pues vos queréis que se os crea lo que habéis visto en el cielo, yo quiero que vos me creáis a mí lo que vi en la cueva de Montesinos; y no os digo más. Capítulo XLII. De los consejos que dio don Quijote a Sancho Panza antes que fuese a gobernar la ínsula, con otras cosas bien consideradas Con el felice y gracioso suceso de la aventura de la Dolorida, quedaron tan contentos los duques, que determinaron pasar con las burlas adelante, viendo el acomodado sujeto que tenían para que se tuviesen por veras; y así, habiendo dado la traza y órdenes que sus criados y sus vasallos habían de guardar con Sancho en el gobierno de la ínsula prometida, otro día, que fue el que sucedió al vuelo de Clavileño, dijo el duque a Sancho que se adeliñase y compusiese para ir a ser gobernador, que ya sus insulanos le estaban esperando como el agua de mayo. Sancho se le humilló y le dijo: -Después que bajé del cielo, y después que desde su alta cumbre miré la tierra y la vi tan pequeña, se templó en parte en mí la gana que tenía tan grande de ser gobernador; porque, ¿qué grandeza es mandar en un grano de mostaza, o qué dignidad o imperio el gobernar a media docena de hombres tamaños como avellanas, que, a mi parecer, no había más en toda la tierra? Si vuestra señoría fuese servido de darme una tantica parte del cielo, aunque no fuese más de media legua, la tomaría de mejor gana que la mayor ínsula del mundo. -Mirad, amigo Sancho -respondió el duque-: yo no puedo dar parte del cielo a nadie, aunque no sea mayor que una uña, que a solo Dios están reservadas esas mercedes y gracias. Lo que puedo dar os doy, que es una ínsula hecha y derecha, redonda y bien proporcionada, y sobremanera fértil y abundosa, donde si vos os sabéis dar maña, podéis con las riquezas de la tierra granjear las del cielo. -Ahora bien -respondió Sancho-, venga esa ínsula, que yo pugnaré por ser tal gobernador que, a pesar de bellacos, me vaya al cielo; y esto no es por codicia que yo tenga de salir de mis casillas ni de levantarme a mayores, sino por el deseo que tengo de probar a qué sabe el ser gobernador. -Si una vez lo probáis, Sancho -dijo el duque-, comeros heis las manos tras el gobierno, por ser dulcísima cosa el mandar y ser obedecido. A buen seguro que cuando vuestro dueño llegue a ser emperador, que lo será sin duda, según van encaminadas sus cosas, que no se lo arranquen comoquiera, y que le duela y le pese en la mitad del alma del tiempo que hubiere dejado de serlo. -Señor -replicó Sancho-, yo imagino que es bueno mandar, aunque sea a un hato de ganado. -Con vos me entierren, Sancho, que sabéis de todo -respondió el duque-, y yo espero que seréis tal gobernador como vuestro juicio promete, y quédese esto aquí y advertid que mañana en ese mesmo día habéis de ir al gobierno de la ínsula, y esta tarde os acomodarán del traje conveniente que habéis de llevar y de todas las cosas necesarias a vuestra partida. -Vístanme -dijo Sancho- como quisieren, que de cualquier manera que vaya vestido seré Sancho Panza. -Así es verdad -dijo el duque-, pero los trajes se han de acomodar con el oficio o dignidad que se profesa, que no sería bien que un jurisperito se vistiese como soldado, ni un soldado como un sacerdote. Vos, Sancho, iréis vestido parte de letrado y parte de capitán, porque en la ínsula que os doy tanto son menester las armas como las letras, y las letras como las armas. -Letras -respondió Sancho-, pocas tengo, porque aún no sé el A, B, C; pero bástame tener el Christus en la memoria para ser buen gobernador. De las armas manejaré las que me dieren, hasta caer, y Dios delante. -Con tan buena memoria -dijo el duque-, no podrá Sancho errar en nada. En esto llegó don Quijote, y, sabiendo lo que pasaba y la celeridad con que Sancho se había de partir a su gobierno, con licencia del duque le tomó por la mano y se fue con él a su estancia, con intención de aconsejarle cómo se había de haber en su oficio. Entrados, pues, en su aposento, cerró tras sí la puerta, y hizo casi por fuerza que Sancho se sentase junto a él, y con reposada voz le dijo: -Infinitas gracias doy al cielo, Sancho amigo, de que, antes y primero que yo haya encontrado con alguna buena dicha, te haya salido a ti a recebir y a encontrar la buena ventura. Yo, que en mi buena suerte te tenía librada la paga de tus servicios, me veo en los principios de aventajarme, y tú, antes de tiempo, contra la ley del razonable discurso, te vees premiado de tus deseos. Otros cohechan, importunan, solicitan, madrugan, ruegan, porfían, y no alcanzan lo que pretenden; y llega otro, y sin saber cómo ni cómo no, se halla con el cargo y oficio que otros muchos pretendieron; y aquí entra y encaja bien el decir que hay buena y mala fortuna en las pretensiones. Tú, que para mí, sin duda alguna, eres un porro, sin madrugar ni trasnochar y sin hacer diligencia alguna, con solo el aliento que te ha tocado de la andante caballería, sin más ni más te vees gobernador de una ínsula, como quien no dice nada. Todo esto digo, ¡oh Sancho!, para que no atribuyas a tus merecimientos la merced recebida, sino que des gracias al cielo, que dispone suavemente las cosas, y después las darás a la grandeza que en sí encierra la profesión de la caballería andante. Dispuesto, pues, el corazón a creer lo que te he dicho, está, ¡oh hijo!, atento a este tu Catón, que quiere aconsejarte y ser norte y guía que te encamine y saque a seguro puerto deste mar proceloso donde vas a engolfarte; que los oficios y grandes cargos no son otra cosa sino un golfo profundo de confusiones. Primeramente, ¡oh hijo!, has de temer a Dios, porque en el temerle está la sabiduría, y siendo sabio no podrás errar en nada. Lo segundo, has de poner los ojos en quien eres, procurando conocerte a ti mismo, que es el más difícil conocimiento que puede imaginarse. Del conocerte saldrá el no hincharte como la rana que quiso igualarse con el buey, que si esto haces, vendrá a ser feos pies de la rueda de tu locura la consideración de haber guardado puercos en tu tierra. -Así es la verdad -respondió Sancho-, pero fue cuando muchacho; pero después, algo hombrecillo, gansos fueron los que guardé, que no puercos; pero esto paréceme a mí que no hace al caso, que no todos los que gobiernan vienen de casta de reyes. -Así es verdad -replicó don Quijote-, por lo cual los no de principios nobles deben acompañar la gravedad del cargo que ejercitan con una blanda suavidad que, guiada por la prudencia, los libre de la murmuración maliciosa, de quien no hay estado que se escape. Haz gala, Sancho, de la humildad de tu linaje, y no te desprecies de decir que vienes de labradores; porque, viendo que no te corres, ninguno se pondrá a correrte; y préciate más de ser humilde virtuoso que pecador soberbio. Inumerables son aquellos que, de baja estirpe nacidos, han subido a la suma dignidad pontificia e imperatoria; y desta verdad te pudiera traer tantos ejemplos, que te cansaran. Mira, Sancho: si tomas por medio a la virtud, y te precias de hacer hechos virtuosos, no hay para qué tener envidia a los que los tienen de príncipes y señores, porque la sangre se hereda y la virtud se aquista, y la virtud vale por sí sola lo que la sangre no vale. Siendo esto así, como lo es, que si acaso viniere a verte cuando estés en tu ínsula alguno de tus parientes, no le deseches ni le afrentes; antes le has de acoger, agasajar y regalar, que con esto satisfarás al cielo, que gusta que nadie se desprecie de lo que él hizo, y corresponderás a lo que debes a la naturaleza bien concertada. Si trujeres a tu mujer contigo (porque no es bien que los que asisten a gobiernos de mucho tiempo estén sin las propias), enséñala, doctrínala y desbástala de su natural rudeza, porque todo lo que suele adquirir un gobernador discreto suele perder y derramar una mujer rústica y tonta. Si acaso enviudares, cosa que puede suceder, y con el cargo mejorares de consorte, no la tomes tal, que te sirva de anzuelo y de caña de pescar, y del no quiero de tu capilla, porque en verdad te digo que de todo aquello que la mujer del juez recibiere ha de dar cuenta el marido en la residencia universal, donde pagará con el cuatro tanto en la muerte las partidas de que no se hubiere hecho cargo en la vida. Nunca te guíes por la ley del encaje, que suele tener mucha cabida con los ignorantes que presumen de agudos. Hallen en ti más compasión las lágrimas del pobre, pero no más justicia, que las informaciones del rico. Procura descubrir la verdad por entre las promesas y dádivas del rico, como por entre los sollozos e importunidades del pobre. Cuando pudiere y debiere tener lugar la equidad, no cargues todo el rigor de la ley al delincuente, que no es mejor la fama del juez riguroso que la del compasivo. Si acaso doblares la vara de la justicia, no sea con el peso de la dádiva, sino con el de la misericordia. Cuando te sucediere juzgar algún pleito de algún tu enemigo, aparta las mientes de tu injuria y ponlas en la verdad del caso. No te ciegue la pasión propia en la causa ajena, que los yerros que en ella hicieres, las más veces, serán sin remedio; y si le tuvieren, será a costa de tu crédito, y aun de tu hacienda. Si alguna mujer hermosa veniere a pedirte justicia, quita los ojos de sus lágrimas y tus oídos de sus gemidos, y considera de espacio la sustancia de lo que pide, si no quieres que se anegue tu razón en su llanto y tu bondad en sus suspiros. Al que has de castigar con obras no trates mal con palabras, pues le basta al desdichado la pena del suplicio, sin la añadidura de las malas razones. Al culpado que cayere debajo de tu juridición considérale hombre miserable, sujeto a las condiciones de la depravada naturaleza nuestra, y en todo cuanto fuere de tu parte, sin hacer agravio a la contraria, muéstratele piadoso y clemente, porque, aunque los atributos de Dios todos son iguales, más resplandece y campea a nuestro ver el de la misericordia que el de la justicia. Si estos preceptos y estas reglas sigues, Sancho, serán luengos tus días, tu fama será eterna, tus premios colmados, tu felicidad indecible, casarás tus hijos como quisieres, títulos tendrán ellos y tus nietos, vivirás en paz y beneplácito de las gentes, y en los últimos pasos de la vida te alcanzará el de la muerte, en vejez suave y madura, y cerrarán tus ojos las tiernas y delicadas manos de tus terceros netezuelos. Esto que hasta aquí te he dicho son documentos que han de adornar tu alma; escucha ahora los que han de servir para adorno del cuerpo. Capítulo XLIII. De los consejos segundos que dio don Quijote a Sancho Panza ¿Quién oyera el pasado razonamiento de don Quijote que no le tuviera por persona muy cuerda y mejor intencionada? Pero, como muchas veces en el progreso desta grande historia queda dicho, solamente disparaba en tocándole en la caballería, y en los demás discursos mostraba tener claro y desenfadado entendimiento, de manera que a cada paso desacreditaban sus obras su juicio, y su juicio sus obras; pero en ésta destos segundos documentos que dio a Sancho, mostró tener gran donaire, y puso su discreción y su locura en un levantado punto. Atentísimamente le escuchaba Sancho, y procuraba conservar en la memoria sus consejos, como quien pensaba guardarlos y salir por ellos a buen parto de la preñez de su gobierno. Prosiguió, pues, don Quijote, y dijo: -En lo que toca a cómo has de gobernar tu persona y casa, Sancho, lo primero que te encargo es que seas limpio, y que te cortes las uñas, sin dejarlas crecer, como algunos hacen, a quien su ignorancia les ha dado a entender que las uñas largas les hermosean las manos, como si aquel escremento y añadidura que se dejan de cortar fuese uña, siendo antes garras de cernícalo lagartijero: puerco y extraordinario abuso. No andes, Sancho, desceñido y flojo, que el vestido descompuesto da indicios de ánimo desmazalado, si ya la descompostura y flojedad no cae debajo de socarronería, como se juzgó en la de Julio César. Toma con discreción el pulso a lo que pudiere valer tu oficio, y si sufriere que des librea a tus criados, dásela honesta y provechosa más que vistosa y bizarra, y repártela entre tus criados y los pobres: quiero decir que si has de vestir seis pajes, viste tres y otros tres pobres, y así tendrás pajes para el cielo y para el suelo; y este nuevo modo de dar librea no la alcanzan los vanagloriosos. No comas ajos ni cebollas, porque no saquen por el olor tu villanería. Anda despacio; habla con reposo, pero no de manera que parezca que te escuchas a ti mismo, que toda afectación es mala. Come poco y cena más poco, que la salud de todo el cuerpo se fragua en la oficina del estómago. Sé templado en el beber, considerando que el vino demasiado ni guarda secreto ni cumple palabra. Ten cuenta, Sancho, de no mascar a dos carrillos, ni de erutar delante de nadie. -Eso de erutar no entiendo -dijo Sancho. Y don Quijote le dijo: -Erutar, Sancho, quiere decir regoldar, y éste es uno de los más torpes vocablos que tiene la lengua castellana, aunque es muy sinificativo; y así, la gente curiosa se ha acogido al latín, y al regoldar dice erutar, y a los regüeldos, erutaciones; y, cuando algunos no entienden estos términos, importa poco, que el uso los irá introduciendo con el tiempo, que con facilidad se entiendan; y esto es enriquecer la lengua, sobre quien tiene poder el vulgo y el uso. -En verdad, señor -dijo Sancho-, que uno de los consejos y avisos que pienso llevar en la memoria ha de ser el de no regoldar, porque lo suelo hacer muy a menudo. -Erutar, Sancho, que no regoldar -dijo don Quijote. -Erutar diré de aquí adelante -respondió Sancho-, y a fee que no se me olvide. -También, Sancho, no has de mezclar en tus pláticas la muchedumbre de refranes que sueles; que, puesto que los refranes son sentencias breves, muchas veces los traes tan por los cabellos, que más parecen disparates que sentencias. -Eso Dios lo puede remediar -respondió Sancho-, porque sé más refranes que un libro, y viénenseme tantos juntos a la boca cuando hablo, que riñen por salir unos con otros, pero la lengua va arrojando los primeros que encuentra, aunque no vengan a pelo. Mas yo tendré cuenta de aquí adelante de decir los que convengan a la gravedad de mi cargo, que en casa llena presto se guisa la cena, y quien destaja no baraja, y a buen salvo está el que repica, y el dar y el tener seso ha menester. -¡Eso sí, Sancho! -dijo don Quijote-: ¡encaja, ensarta, enhila refranes, que nadie te va a la mano! ¡Castígame mi madre, y yo trómpogelas! Estoyte diciendo que escuses refranes, y en un instante has echado aquí una letanía dellos, que así cuadran con lo que vamos tratando como por los cerros de Úbeda. Mira, Sancho, no te digo yo que parece mal un refrán traído a propósito, pero cargar y ensartar refranes a troche moche hace la plática desmayada y baja. Cuando subieres a caballo, no vayas echando el cuerpo sobre el arzón postrero, ni lleves las piernas tiesas y tiradas y desviadas de la barriga del caballo, ni tampoco vayas tan flojo que parezca que vas sobre el rucio: que el andar a caballo a unos hace caballeros; a otros, caballerizos. Sea moderado tu sueño, que el que no madruga con el sol, no goza del día; y advierte, ¡oh Sancho!, que la diligencia es madre de la buena ventura, y la pereza, su contraria, jamás llegó al término que pide un buen deseo. Este último consejo que ahora darte quiero, puesto que no sirva para adorno del cuerpo, quiero que le lleves muy en la memoria, que creo que no te será de menos provecho que los que hasta aquí te he dado; y es que jamás te pongas a disputar de linajes, a lo menos, comparándolos entre sí, pues, por fuerza, en los que se comparan uno ha de ser el mejor, y del que abatieres serás aborrecido, y del que levantares en ninguna manera premiado. Tu vestido será calza entera, ropilla larga, herreruelo un poco más largo; greguescos, ni por pienso, que no les están bien ni a los caballeros ni a los gobernadores. Por ahora, esto se me ha ofrecido, Sancho, que aconsejarte; andará el tiempo, y, según las ocasiones, así serán mis documentos, como tú tengas cuidado de avisarme el estado en que te hallares. -Señor -respondió Sancho-, bien veo que todo cuanto vuestra merced me ha dicho son cosas buenas, santas y provechosas, pero ¿de qué han de servir, si de ninguna me acuerdo? Verdad sea que aquello de no dejarme crecer las uñas y de casarme otra vez, si se ofreciere, no se me pasará del magín, pero esotros badulaques y enredos y revoltillos, no se me acuerda ni acordará más dellos que de las nubes de antaño, y así, será menester que se me den por escrito, que, puesto que no sé leer ni escribir, yo se los daré a mi confesor para que me los encaje y recapacite cuando fuere menester. -¡Ah, pecador de mí -respondió don Quijote-, y qué mal parece en los gobernadores el no saber leer ni escribir!; porque has de saber, ¡oh Sancho!, que no saber un hombre leer, o ser zurdo, arguye una de dos cosas: o que fue hijo de padres demasiado de humildes y bajos, o él tan travieso y malo que no pudo entrar en el buen uso ni la buena doctrina. Gran falta es la que llevas contigo, y así, querría que aprendieses a firmar siquiera. -Bien sé firmar mi nombre -respondió Sancho-, que cuando fui prioste en mi lugar, aprendí a hacer unas letras como de marca de fardo, que decían que decía mi nombre; cuanto más, que fingiré que tengo tullida la mano derecha, y haré que firme otro por mí; que para todo hay remedio, si no es para la muerte; y, teniendo yo el mando y el palo, haré lo que quisiere; cuanto más, que el que tiene el padre alcalde... Y, siendo yo gobernador, que es más que ser alcalde, ¡llegaos, que la dejan ver! No, sino popen y calóñenme, que vendrán por lana y volverán trasquilados; y a quien Dios quiere bien, la casa le sabe; y las necedades del rico por sentencias pasan en el mundo; y, siéndolo yo, siendo gobernador y juntamente liberal, como lo pienso ser, no habrá falta que se me parezca. No, sino haceos miel, y paparos han moscas; tanto vales cuanto tienes, decía una mi agüela, y del hombre arraigado no te verás vengado. -¡Oh, maldito seas de Dios, Sancho! -dijo a esta sazón don Quijote-. ¡Sesenta mil satanases te lleven a ti y a tus refranes! Una hora ha que los estás ensartando y dándome con cada uno tragos de tormento. Yo te aseguro que estos refranes te han de llevar un día a la horca; por ellos te han de quitar el gobierno tus vasallos, o ha de haber entre ellos comunidades. Dime, ¿dónde los hallas, ignorante, o cómo los aplicas, mentecato, que para decir yo uno y aplicarle bien, sudo y trabajo como si cavase? -Por Dios, señor nuestro amo -replicó Sancho-, que vuesa merced se queja de bien pocas cosas. ¿A qué diablos se pudre de que yo me sirva de mi hacienda, que ninguna otra tengo, ni otro caudal alguno, sino refranes y más refranes? Y ahora se me ofrecen cuatro que venían aquí pintiparados, o como peras en tabaque, pero no los diré, porque al buen callar llaman Sancho. -Ese Sancho no eres tú -dijo don Quijote-, porque no sólo no eres buen callar, sino mal hablar y mal porfiar; y, con todo eso, querría saber qué cuatro refranes te ocurrían ahora a la memoria que venían aquí a propósito, que yo ando recorriendo la mía, que la tengo buena, y ninguno se me ofrece. -¿Qué mejores -dijo Sancho- que "entre dos muelas cordales nunca pongas tus pulgares", y "a idos de mi casa y qué queréis con mi mujer, no hay responder", y "si da el cántaro en la piedra o la piedra en el cántaro, mal para el cántaro", todos los cuales vienen a pelo? Que nadie se tome con su gobernador ni con el que le manda, porque saldrá lastimado, como el que pone el dedo entre dos muelas cordales, y aunque no sean cordales, como sean muelas, no importa; y a lo que dijere el gobernador no hay que replicar, como al "salíos de mi casa y qué queréis con mi mujer". Pues lo de la piedra en el cántaro un ciego lo verá. Así que, es menester que el que vee la mota en el ojo ajeno, vea la viga en el suyo, porque no se diga por él: "espantóse la muerta de la degollada", y vuestra merced sabe bien que más sabe el necio en su casa que el cuerdo en la ajena. -Eso no, Sancho -respondió don Quijote-, que el necio en su casa ni en la ajena sabe nada, a causa que sobre el aumento de la necedad no asienta ningún discreto edificio. Y dejemos esto aquí, Sancho, que si mal gobernares, tuya será la culpa, y mía la vergüenza; mas consuélome que he hecho lo que debía en aconsejarte con las veras y con la discreción a mí posible: con esto salgo de mi obligación y de mi promesa. Dios te guíe, Sancho, y te gobierne en tu gobierno, y a mí me saque del escrúpulo que me queda que has de dar con toda la ínsula patas arriba, cosa que pudiera yo escusar con descubrir al duque quién eres, diciéndole que toda esa gordura y esa personilla que tienes no es otra cosa que un costal lleno de refranes y de malicias. -Señor -replicó Sancho-, si a vuestra merced le parece que no soy de pro para este gobierno, desde aquí le suelto, que más quiero un solo negro de la uña de mi alma que a todo mi cuerpo; y así me sustentaré Sancho a secas con pan y cebolla, como gobernador con perdices y capones; y más que, mientras se duerme, todos son iguales, los grandes y los menores, los pobres y los ricos; y si vuestra merced mira en ello, verá que sólo vuestra merced me ha puesto en esto de gobernar: que yo no sé más de gobiernos de ínsulas que un buitre; y si se imagina que por ser gobernador me ha de llevar el diablo, más me quiero ir Sancho al cielo que gobernador al infierno. -Por Dios, Sancho -dijo don Quijote-, que, por solas estas últimas razones que has dicho, juzgo que mereces ser gobernador de mil ínsulas: buen natural tienes, sin el cual no hay ciencia que valga; encomiéndate a Dios, y procura no errar en la primera intención; quiero decir que siempre tengas intento y firme propósito de acertar en cuantos negocios te ocurrieren, porque siempre favorece el cielo los buenos deseos. Y vámonos a comer, que creo que ya estos señores nos aguardan. Capítulo XLIV. Cómo Sancho Panza fue llevado al gobierno, y de la estraña aventura que en el castillo sucedió a don Quijote Dicen que en el propio original desta historia se lee que, llegando Cide Hamete a escribir este capítulo, no le tradujo su intérprete como él le había escrito, que fue un modo de queja que tuvo el moro de sí mismo, por haber tomado entre manos una historia tan seca y tan limitada como esta de don Quijote, por parecerle que siempre había de hablar dél y de Sancho, sin osar estenderse a otras digresiones y episodios más graves y más entretenidos; y decía que el ir siempre atenido el entendimiento, la mano y la pluma a escribir de un solo sujeto y hablar por las bocas de pocas personas era un trabajo incomportable, cuyo fruto no redundaba en el de su autor, y que, por huir deste inconveniente, había usado en la primera parte del artificio de algunas novelas, como fueron la del Curioso impertinente y la del Capitán cautivo, que están como separadas de la historia, puesto que las demás que allí se cuentan son casos sucedidos al mismo don Quijote, que no podían dejar de escribirse. También pensó, como él dice, que muchos, llevados de la atención que piden las hazañas de don Quijote, no la darían a las novelas, y pasarían por ellas, o con priesa o con enfado, sin advertir la gala y artificio que en sí contienen, el cual se mostrara bien al descubierto cuando, por sí solas, sin arrimarse a las locuras de don Quijote ni a las sandeces de Sancho, salieran a luz. Y así, en esta segunda parte no quiso ingerir novelas sueltas ni pegadizas, sino algunos episodios que lo pareciesen, nacidos de los mesmos sucesos que la verdad ofrece; y aun éstos, limitadamente y con solas las palabras que bastan a declararlos; y, pues se contiene y cierra en los estrechos límites de la narración, teniendo habilidad, suficiencia y entendimiento para tratar del universo todo, pide no se desprecie su trabajo, y se le den alabanzas, no por lo que escribe, sino por lo que ha dejado de escribir. Y luego prosigue la historia diciendo que, en acabando de comer don Quijote, el día que dio los consejos a Sancho, aquella tarde se los dio escritos, para que él buscase quien se los leyese; pero, apenas se los hubo dado, cuando se le cayeron y vinieron a manos del duque, que los comunicó con la duquesa, y los dos se admiraron de nuevo de la locura y del ingenio de don Quijote; y así, llevando adelante sus burlas, aquella tarde enviaron a Sancho con mucho acompañamiento al lugar que para él había de ser ínsula. Acaeció, pues, que el que le llevaba a cargo era un mayordomo del duque, muy discreto y muy gracioso -que no puede haber gracia donde no hay discreción-, el cual había hecho la persona de la condesa Trifaldi, con el donaire que queda referido; y con esto, y con ir industriado de sus señores de cómo se había de haber con Sancho, salió con su intento maravillosamente. Digo, pues, que acaeció que, así como Sancho vio al tal mayordomo, se le figuró en su rostro el mesmo de la Trifaldi, y, volviéndose a su señor, le dijo: -Señor, o a mí me ha de llevar el diablo de aquí de donde estoy, en justo y en creyente, o vuestra merced me ha de confesar que el rostro deste mayordomo del duque, que aquí está, es el mesmo de la Dolorida. Miró don Quijote atentamente al mayordomo, y, habiéndole mirado, dijo a Sancho: -No hay para qué te lleve el diablo, Sancho, ni en justo ni en creyente, que no sé lo que quieres decir; que el rostro de la Dolorida es el del mayordomo, pero no por eso el mayordomo es la Dolorida; que, a serlo, implicaría contradición muy grande, y no es tiempo ahora de hacer estas averiguaciones, que sería entrarnos en intricados laberintos. Créeme, amigo, que es menester rogar a Nuestro Señor muy de veras que nos libre a los dos de malos hechiceros y de malos encantadores. -No es burla, señor -replicó Sancho-, sino que denantes le oí hablar, y no pareció sino que la voz de la Trifaldi me sonaba en los oídos. Ahora bien, yo callaré, pero no dejaré de andar advertido de aquí adelante, a ver si descubre otra señal que confirme o desfaga mi sospecha. -Así lo has de hacer, Sancho -dijo don Quijote-, y darásme aviso de todo lo que en este caso descubrieres y de todo aquello que en el gobierno te sucediere. Salió, en fin, Sancho, acompañado de mucha gente, vestido a lo letrado, y encima un gabán muy ancho de chamelote de aguas leonado, con una montera de lo mesmo, sobre un macho a la jineta, y detrás dél, por orden del duque, iba el rucio con jaeces y ornamentos jumentiles de seda y flamantes. Volvía Sancho la cabeza de cuando en cuando a mirar a su asno, con cuya compañía iba tan contento que no se trocara con el emperador de Alemaña. Al despedirse de los duques, les besó las manos, y tomó la bendición de su señor, que se la dio con lágrimas, y Sancho la recibió con pucheritos. Deja, lector amable, ir en paz y en hora buena al buen Sancho, y espera dos fanegas de risa, que te ha de causar el saber cómo se portó en su cargo, y, en tanto, atiende a saber lo que le pasó a su amo aquella noche; que si con ello no rieres, por lo menos desplegarás los labios con risa de jimia, porque los sucesos de don Quijote, o se han de celebrar con admiración, o con risa. Cuéntase, pues, que, apenas se hubo partido Sancho, cuando don Quijote sintió su soledad; y si le fuera posible revocarle la comisión y quitarle el gobierno, lo hiciera. Conoció la duquesa su melancolía, y preguntóle que de qué estaba triste; que si era por la ausencia de Sancho, que escuderos, dueñas y doncellas había en su casa que le servirían muy a satisfación de su deseo. -Verdad es, señora mía -respondió don Quijote-, que siento la ausencia de Sancho, pero no es ésa la causa principal que me hace parecer que estoy triste, y, de los muchos ofrecimientos que vuestra excelencia me hace, solamente acepto y escojo el de la voluntad con que se me hacen, y, en lo demás, suplico a Vuestra Excelencia que dentro de mi aposento consienta y permita que yo solo sea el que me sirva. -En verdad -dijo la duquesa-, señor don Quijote, que no ha de ser así: que le han de servir cuatro doncellas de las mías, hermosas como unas flores. -Para mí -respondió don Quijote- no serán ellas como flores, sino como espinas que me puncen el alma. Así entrarán ellas en mi aposento, ni cosa que lo parezca, como volar. Si es que vuestra grandeza quiere llevar adelante el hacerme merced sin yo merecerla, déjeme que yo me las haya conmigo, y que yo me sirva de mis puertas adentro, que yo ponga una muralla en medio de mis deseos y de mi honestidad; y no quiero perder esta costumbre por la liberalidad que vuestra alteza quiere mostrar conmigo. Y, en resolución, antes dormiré vestido que consentir que nadie me desnude. -No más, no más, señor don Quijote -replicó la duquesa-. Por mí digo que daré orden que ni aun una mosca entre en su estancia, no que una doncella; no soy yo persona, que por mí se ha de descabalar la decencia del señor don Quijote; que, según se me ha traslucido, la que más campea entre sus muchas virtudes es la de la honestidad. Desnúdese vuesa merced y vístase a sus solas y a su modo, como y cuando quisiere, que no habrá quien lo impida, pues dentro de su aposento hallará los vasos necesarios al menester del que duerme a puerta cerrada, porque ninguna natural necesidad le obligue a que la abra. Viva mil siglos la gran Dulcinea del Toboso, y sea su nombre estendido por toda la redondez de la tierra, pues mereció ser amada de tan valiente y tan honesto caballero, y los benignos cielos infundan en el corazón de Sancho Panza, nuestro gobernador, un deseo de acabar presto sus diciplinas, para que vuelva a gozar el mundo de la belleza de tan gran señora. A lo cual dijo don Quijote: -Vuestra altitud ha hablado como quien es, que en la boca de las buenas señoras no ha de haber ninguna que sea mala; y más venturosa y más conocida será en el mundo Dulcinea por haberla alabado vuestra grandeza, que por todas las alabanzas que puedan darle los más elocuentes de la tierra. -Agora bien, señor don Quijote -replicó la duquesa-, la hora de cenar se llega, y el duque debe de esperar: venga vuesa merced y cenemos, y acostaráse temprano, que el viaje que ayer hizo de Candaya no fue tan corto que no haya causado algún molimiento. -No siento ninguno, señora -respondió don Quijote-, porque osaré jurar a Vuestra Excelencia que en mi vida he subido sobre bestia más reposada ni de mejor paso que Clavileño; y no sé yo qué le pudo mover a Malambruno para deshacerse de tan ligera y tan gentil cabalgadura, y abrasarla así, sin más ni más. -A eso se puede imaginar -respondió la duquesa- que, arrepentido del mal que había hecho a la Trifaldi y compañía, y a otras personas, y de las maldades que como hechicero y encantador debía de haber cometido, quiso concluir con todos los instrumentos de su oficio, y, como a principal y que más le traía desasosegado, vagando de tierra en tierra, abrasó a Clavileño; que con sus abrasadas cenizas y con el trofeo del cartel queda eterno el valor del gran don Quijote de la Mancha. De nuevo nuevas gracias dio don Quijote a la duquesa, y, en cenando, don Quijote se retiró en su aposento solo, sin consentir que nadie entrase con él a servirle: tanto se temía de encontrar ocasiones que le moviesen o forzasen a perder el honesto decoro que a su señora Dulcinea guardaba, siempre puesta en la imaginación la bondad de Amadís, flor y espejo de los andantes caballeros. Cerró tras sí la puerta, y a la luz de dos velas de cera se desnudó, y al descalzarse -¡oh desgracia indigna de tal persona!- se le soltaron, no suspiros, ni otra cosa, que desacreditasen la limpieza de su policía, sino hasta dos docenas de puntos de una media, que quedó hecha celosía. Afligióse en estremo el buen señor, y diera él por tener allí un adarme de seda verde una onza de plata; digo seda verde porque las medias eran verdes. Aquí exclamó Benengeli, y, escribiendo, dijo ''¡Oh pobreza, pobreza! ¡No sé yo con qué razón se movió aquel gran poeta cordobés a llamarte dádiva santa desagradecida! Yo, aunque moro, bien sé, por la comunicación que he tenido con cristianos, que la santidad consiste en la caridad, humildad, fee, obediencia y pobreza; pero, con todo eso, digo que ha de tener mucho de Dios el que se viniere a contentar con ser pobre, si no es de aquel modo de pobreza de quien dice uno de sus mayores santos: "Tened todas las cosas como si no las tuviésedes"; y a esto llaman pobreza de espíritu; pero tú, segunda pobreza, que eres de la que yo hablo, ¿por qué quieres estrellarte con los hidalgos y bien nacidos más que con la otra gente? ¿Por qué los obligas a dar pantalia a los zapatos, y a que los botones de sus ropillas unos sean de seda, otros de cerdas, y otros de vidro? ¿Por qué sus cuellos, por la mayor parte, han de ser siempre escarolados, y no abiertos con molde?'' Y en esto se echará de ver que es antiguo el uso del almidón y de los cuellos abiertos. Y prosiguió: ''¡Miserable del bien nacido que va dando pistos a su honra, comiendo mal y a puerta cerrada, haciendo hipócrita al palillo de dientes con que sale a la calle después de no haber comido cosa que le obligue a limpiárselos! ¡Miserable de aquel, digo, que tiene la honra espantadiza, y piensa que desde una legua se le descubre el remiendo del zapato, el trasudor del sombrero, la hilaza del herreruelo y la hambre de su estómago!'' Todo esto se le renovó a don Quijote en la soltura de sus puntos, pero consolóse con ver que Sancho le había dejado unas botas de camino, que pensó ponerse otro día. Finalmente, él se recostó pensativo y pesaroso, así de la falta que Sancho le hacía como de la inreparable desgracia de sus medias, a quien tomara los puntos, aunque fuera con seda de otra color, que es una de las mayores señales de miseria que un hidalgo puede dar en el discurso de su prolija estrecheza. Mató las velas; hacía calor y no podía dormir; levantóse del lecho y abrió un poco la ventana de una reja que daba sobre un hermoso jardín, y, al abrirla, sintió y oyó que andaba y hablaba gente en el jardín. Púsose a escuchar atentamente. Levantaron la voz los de abajo, tanto, que pudo oír estas razones: -No me porfíes, ¡oh Emerencia!, que cante, pues sabes que, desde el punto que este forastero entró en este castillo y mis ojos le miraron, yo no sé cantar, sino llorar; cuanto más, que el sueño de mi señora tiene más de ligero que de pesado, y no querría que nos hallase aquí por todo el tesoro del mundo. Y, puesto caso que durmiese y no despertase, en vano sería mi canto si duerme y no despierta para oírle este nuevo Eneas, que ha llegado a mis regiones para dejarme escarnida. -No des en eso, Altisidora amiga -respondieron-, que sin duda la duquesa y cuantos hay en esa casa duermen, si no es el señor de tu corazón y el despertador de tu alma, porque ahora sentí que abría la ventana de la reja de su estancia, y sin duda debe de estar despierto; canta, lastimada mía, en tono bajo y suave al son de tu arpa, y, cuando la duquesa nos sienta, le echaremos la culpa al calor que hace. -No está en eso el punto, ¡oh Emerencia! -respondió la Altisidora-, sino en que no querría que mi canto descubriese mi corazón y fuese juzgada de los que no tienen noticia de las fuerzas poderosas de amor por doncella antojadiza y liviana. Pero venga lo que viniere, que más vale vergüenza en cara que mancilla en corazón. Y, en esto, sintió tocar una arpa suavísimamente. Oyendo lo cual, quedó don Quijote pasmado, porque en aquel instante se le vinieron a la memoria las infinitas aventuras semejantes a aquélla, de ventanas, rejas y jardines, músicas, requiebros y desvanecimientos que en los sus desvanecidos libros de caballerías había leído. Luego imaginó que alguna doncella de la duquesa estaba dél enamorada, y que la honestidad la forzaba a tener secreta su voluntad; temió no le rindiese, y propuso en su pensamiento el no dejarse vencer; y, encomendándose de todo buen ánimo y buen talante a su señora Dulcinea del Toboso, determinó de escuchar la música; y, para dar a entender que allí estaba, dio un fingido estornudo, de que no poco se alegraron las doncellas, que otra cosa no deseaban sino que don Quijote las oyese. Recorrida, pues, y afinada la arpa, Altisidora dio principio a este romance: -¡Oh, tú, que estás en tu lecho, entre sábanas de holanda, durmiendo a pierna tendida de la noche a la mañana, caballero el más valiente que ha producido la Mancha, más honesto y más bendito que el oro fino de Arabia! Oye a una triste doncella, bien crecida y mal lograda, que en la luz de tus dos soles se siente abrasar el alma. Tú buscas tus aventuras, y ajenas desdichas hallas; das las feridas, y niegas el remedio de sanarlas. Dime, valeroso joven, que Dios prospere tus ansias, si te criaste en la Libia, o en las montañas de Jaca; si sierpes te dieron leche; si, a dicha, fueron tus amas la aspereza de las selvas y el horror de las montañas. Muy bien puede Dulcinea, doncella rolliza y sana, preciarse de que ha rendido a una tigre y fiera brava. Por esto será famosa desde Henares a Jarama, desde el Tajo a Manzanares, desde Pisuerga hasta Arlanza. Trocáreme yo por ella, y diera encima una saya de las más gayadas mías, que de oro le adornan franjas. ¡Oh, quién se viera en tus brazos, o si no, junto a tu cama, rascándote la cabeza y matándote la caspa! Mucho pido, y no soy digna de merced tan señalada: los pies quisiera traerte, que a una humilde esto le basta. ¡Oh, qué de cofias te diera, qué de escarpines de plata, qué de calzas de damasco, qué de herreruelos de holanda! ¡Qué de finísimas perlas, cada cual como una agalla, que, a no tener compañeras, Las solas fueran llamadas! No mires de tu Tarpeya este incendio que me abrasa, Nerón manchego del mundo, ni le avives con tu saña. Niña soy, pulcela tierna, mi edad de quince no pasa: catorce tengo y tres meses, te juro en Dios y en mi ánima. No soy renca, ni soy coja, ni tengo nada de manca; los cabellos, como lirios, que, en pie, por el suelo arrastran. Y, aunque es mi boca aguileña y la nariz algo chata, ser mis dientes de topacios mi belleza al cielo ensalza. Mi voz, ya ves, si me escuchas, que a la que es más dulce iguala, y soy de disposición algo menos que mediana. Estas y otras gracias mías, son despojos de tu aljaba; desta casa soy doncella, y Altisidora me llaman. Aquí dio fin el canto de la malferida Altisidora, y comenzó el asombro del requirido don Quijote, el cual, dando un gran suspiro, dijo entre sí: -¡Que tengo de ser tan desdichado andante, que no ha de haber doncella que me mire que de mí no se enamore...! ¡Que tenga de ser tan corta de ventura la sin par Dulcinea del Toboso, que no la han de dejar a solas gozar de la incomparable firmeza mía...! ¿Qué la queréis, reinas? ¿A qué la perseguís, emperatrices? ¿Para qué la acosáis, doncellas de a catorce a quince años? Dejad, dejad a la miserable que triunfe, se goce y ufane con la suerte que Amor quiso darle en rendirle mi corazón y entregarle mi alma. Mirad, caterva enamorada, que para sola Dulcinea soy de masa y de alfenique, y para todas las demás soy de pedernal; para ella soy miel, y para vosotras acíbar; para mí sola Dulcinea es la hermosa, la discreta, la honesta, la gallarda y la bien nacida, y las demás, las feas, las necias, las livianas y las de peor linaje; para ser yo suyo, y no de otra alguna, me arrojó la naturaleza al mundo. Llore o cante Altisidora; desespérese Madama, por quien me aporrearon en el castillo del moro encantado, que yo tengo de ser de Dulcinea, cocido o asado, limpio, bien criado y honesto, a pesar de todas las potestades hechiceras de la tierra. Y, con esto, cerró de golpe la ventana, y, despechado y pesaroso, como si le hubiera acontecido alguna gran desgracia, se acostó en su lecho, donde le dejaremos por ahora, porque nos está llamando el gran Sancho Panza, que quiere dar principio a su famoso gobierno. Capítulo XLV. De cómo el gran Sancho Panza tomó la posesión de su ínsula, y del modo que comenzó a gobernar ¡Oh perpetuo descubridor de los antípodas, hacha del mundo, ojo del cielo, meneo dulce de las cantimploras, Timbrio aquí, Febo allí, tirador acá, médico acullá, padre de la Poesía, inventor de la Música: tú que siempre sales, y, aunque lo parece, nunca te pones! A ti digo, ¡oh sol, con cuya ayuda el hombre engendra al hombre!; a ti digo que me favorezcas, y alumbres la escuridad de mi ingenio, para que pueda discurrir por sus puntos en la narración del gobierno del gran Sancho Panza; que sin ti, yo me siento tibio, desmazalado y confuso. Digo, pues, que con todo su acompañamiento llegó Sancho a un lugar de hasta mil vecinos, que era de los mejores que el duque tenía. Diéronle a entender que se llamaba la ínsula Barataria, o ya porque el lugar se llamaba Baratario, o ya por el barato con que se le había dado el gobierno. Al llegar a las puertas de la villa, que era cercada, salió el regimiento del pueblo a recebirle; tocaron las campanas, y todos los vecinos dieron muestras de general alegría, y con mucha pompa le llevaron a la iglesia mayor a dar gracias a Dios, y luego, con algunas ridículas ceremonias, le entregaron las llaves del pueblo, y le admitieron por perpetuo gobernador de la ínsula Barataria. El traje, las barbas, la gordura y pequeñez del nuevo gobernador tenía admirada a toda la gente que el busilis del cuento no sabía, y aun a todos los que lo sabían, que eran muchos. Finalmente, en sacándole de la iglesia, le llevaron a la silla del juzgado y le sentaron en ella; y el mayordomo del duque le dijo: -Es costumbre antigua en esta ínsula, señor gobernador, que el que viene a tomar posesión desta famosa ínsula está obligado a responder a una pregunta que se le hiciere, que sea algo intricada y dificultosa, de cuya respuesta el pueblo toma y toca el pulso del ingenio de su nuevo gobernador; y así, o se alegra o se entristece con su venida. En tanto que el mayordomo decía esto a Sancho, estaba él mirando unas grandes y muchas letras que en la pared frontera de su silla estaban escritas; y, como él no sabía leer, preguntó que qué eran aquellas pinturas que en aquella pared estaban. Fuele respondido: -Señor, allí esta escrito y notado el día en que Vuestra Señoría tomó posesión desta ínsula, y dice el epitafio: Hoy día, a tantos de tal mes y de tal año, tomó la posesión desta ínsula el señor don Sancho Panza, que muchos años la goce. -Y ¿a quién llaman don Sancho Panza? -preguntó Sancho. -A vuestra señoría -respondió el mayordomo-, que en esta ínsula no ha entrado otro Panza sino el que está sentado en esa silla. -Pues advertid, hermano -dijo Sancho-, que yo no tengo don, ni en todo mi linaje le ha habido: Sancho Panza me llaman a secas, y Sancho se llamó mi padre, y Sancho mi agüelo, y todos fueron Panzas, sin añadiduras de dones ni donas; y yo imagino que en esta ínsula debe de haber más dones que piedras; pero basta: Dios me entiende, y podrá ser que, si el gobierno me dura cuatro días, yo escardaré estos dones, que, por la muchedumbre, deben de enfadar como los mosquitos. Pase adelante con su pregunta el señor mayordomo, que yo responderé lo mejor que supiere, ora se entristezca o no se entristezca el pueblo. A este instante entraron en el juzgado dos hombres, el uno vestido de labrador y el otro de sastre, porque traía unas tijeras en la mano, y el sastre dijo: -Señor gobernador, yo y este hombre labrador venimos ante vuestra merced en razón que este buen hombre llegó a mi tienda ayer (que yo, con perdón de los presentes, soy sastre examinado, que Dios sea bendito), y, poniéndome un pedazo de paño en las manos, me preguntó: ''Señor, ¿habría en esto paño harto para hacerme una caperuza?'' Yo, tanteando el paño, le respondí que sí; él debióse de imaginar, a lo que yo imagino, e imaginé bien, que sin duda yo le quería hurtar alguna parte del paño, fundándose en su malicia y en la mala opinión de los sastres, y replicóme que mirase si habría para dos; adivinéle el pensamiento y díjele que sí; y él, caballero en su dañada y primera intención, fue añadiendo caperuzas, y yo añadiendo síes, hasta que llegamos a cinco caperuzas, y ahora en este punto acaba de venir por ellas: yo se las doy, y no me quiere pagar la hechura, antes me pide que le pague o vuelva su paño. -¿Es todo esto así, hermano? -preguntó Sancho. -Sí, señor -respondió el hombre-, pero hágale vuestra merced que muestre las cinco caperuzas que me ha hecho. -De buena gana -respondió el sastre. Y, sacando encontinente la mano debajo del herreruelo, mostró en ella cinco caperuzas puestas en las cinco cabezas de los dedos de la mano, y dijo: -He aquí las cinco caperuzas que este buen hombre me pide, y en Dios y en mi conciencia que no me ha quedado nada del paño, y yo daré la obra a vista de veedores del oficio. Todos los presentes se rieron de la multitud de las caperuzas y del nuevo pleito. Sancho se puso a considerar un poco, y dijo: -Paréceme que en este pleito no ha de haber largas dilaciones, sino juzgar luego a juicio de buen varón; y así, yo doy por sentencia que el sastre pierda las hechuras, y el labrador el paño, y las caperuzas se lleven a los presos de la cárcel, y no haya más. Si la sentencia pasada de la bolsa del ganadero movió a admiración a los circunstantes, ésta les provocó a risa; pero, en fin, se hizo lo que mandó el gobernador; ante el cual se presentaron dos hombres ancianos; el uno traía una cañaheja por báculo, y el sin báculo dijo: -Señor, a este buen hombre le presté días ha diez escudos de oro en oro, por hacerle placer y buena obra, con condición que me los volviese cuando se los pidiese; pasáronse muchos días sin pedírselos, por no ponerle en mayor necesidad de volvérmelos que la que él tenía cuando yo se los presté; pero, por parecerme que se descuidaba en la paga, se los he pedido una y muchas veces, y no solamente no me los vuelve, pero me los niega y dice que nunca tales diez escudos le presté, y que si se los presté, que ya me los ha vuelto. Yo no tengo testigos ni del prestado ni de la vuelta, porque no me los ha vuelto; querría que vuestra merced le tomase juramento, y si jurare que me los ha vuelto, yo se los perdono para aquí y para delante de Dios. -¿Qué decís vos a esto, buen viejo del báculo? -dijo Sancho. A lo que dijo el viejo: -Yo, señor, confieso que me los prestó, y baje vuestra merced esa vara; y, pues él lo deja en mi juramento, yo juraré como se los he vuelto y pagado real y verdaderamente. Bajó el gobernador la vara, y, en tanto, el viejo del báculo dio el báculo al otro viejo, que se le tuviese en tanto que juraba, como si le embarazara mucho, y luego puso la mano en la cruz de la vara, diciendo que era verdad que se le habían prestado aquellos diez escudos que se le pedían; pero que él se los había vuelto de su mano a la suya, y que por no caer en ello se los volvía a pedir por momentos. Viendo lo cual el gran gobernador, preguntó al acreedor qué respondía a lo que decía su contrario; y dijo que sin duda alguna su deudor debía de decir verdad, porque le tenía por hombre de bien y buen cristiano, y que a él se le debía de haber olvidado el cómo y cuándo se los había vuelto, y que desde allí en adelante jamás le pidiría nada. Tornó a tomar su báculo el deudor, y, bajando la cabeza, se salió del juzgado. Visto lo cual Sancho, y que sin más ni más se iba, y viendo también la paciencia del demandante, inclinó la cabeza sobre el pecho, y, poniéndose el índice de la mano derecha sobre las cejas y las narices, estuvo como pensativo un pequeño espacio, y luego alzó la cabeza y mandó que le llamasen al viejo del báculo, que ya se había ido. Trujéronsele, y, en viéndole Sancho, le dijo: -Dadme, buen hombre, ese báculo, que le he menester. -De muy buena gana -respondió el viejo-: hele aquí, señor. Y púsosele en la mano. Tomóle Sancho, y, dándosele al otro viejo, le dijo: -Andad con Dios, que ya vais pagado. -¿Yo, señor? -respondió el viejo-. Pues, ¿vale esta cañaheja diez escudos de oro? -Sí -dijo el gobernador-; o si no, yo soy el mayor porro del mundo. Y ahora se verá si tengo yo caletre para gobernar todo un reino. Y mandó que allí, delante de todos, se rompiese y abriese la caña. Hízose así, y en el corazón della hallaron diez escudos en oro. Quedaron todos admirados, y tuvieron a su gobernador por un nuevo Salomón. Preguntáronle de dónde había colegido que en aquella cañaheja estaban aquellos diez escudos, y respondió que de haberle visto dar el viejo que juraba, a su contrario, aquel báculo, en tanto que hacía el juramento, y jurar que se los había dado real y verdaderamente, y que, en acabando de jurar, le tornó a pedir el báculo, le vino a la imaginación que dentro dél estaba la paga de lo que pedían. De donde se podía colegir que los que gobiernan, aunque sean unos tontos, tal vez los encamina Dios en sus juicios; y más, que él había oído contar otro caso como aquél al cura de su lugar, y que él tenía tan gran memoria, que, a no olvidársele todo aquello de que quería acordarse, no hubiera tal memoria en toda la ínsula. Finalmente, el un viejo corrido y el otro pagado, se fueron, y los presentes quedaron admirados, y el que escribía las palabras, hechos y movimientos de Sancho no acababa de determinarse si le tendría y pondría por tonto o por discreto. Luego, acabado este pleito, entró en el juzgado una mujer asida fuertemente de un hombre vestido de ganadero rico, la cual venía dando grandes voces, diciendo: -¡Justicia, señor gobernador, justicia, y si no la hallo en la tierra, la iré a buscar al cielo! Señor gobernador de mi ánima, este mal hombre me ha cogido en la mitad dese campo, y se ha aprovechado de mi cuerpo como si fuera trapo mal lavado, y, ¡desdichada de mí!, me ha llevado lo que yo tenía guardado más de veinte y tres años ha, defendiéndolo de moros y cristianos, de naturales y estranjeros; y yo, siempre dura como un alcornoque, conservándome entera como la salamanquesa en el fuego, o como la lana entre las zarzas, para que este buen hombre llegase ahora con sus manos limpias a manosearme. -Aun eso está por averiguar: si tiene limpias o no las manos este galán -dijo Sancho. Y, volviéndose al hombre, le dijo qué decía y respondía a la querella de aquella mujer. El cual, todo turbado, respondió: -Señores, yo soy un pobre ganadero de ganado de cerda, y esta mañana salía deste lugar de vender, con perdón sea dicho, cuatro puercos, que me llevaron de alcabalas y socaliñas poco menos de lo que ellos valían; volvíame a mi aldea, topé en el camino a esta buena dueña, y el diablo, que todo lo añasca y todo lo cuece, hizo que yogásemos juntos; paguéle lo soficiente, y ella, mal contenta, asió de mí, y no me ha dejado hasta traerme a este puesto. Dice que la forcé, y miente, para el juramento que hago o pienso hacer; y ésta es toda la verdad, sin faltar meaja. Entonces el gobernador le preguntó si traía consigo algún dinero en plata; él dijo que hasta veinte ducados tenía en el seno, en una bolsa de cuero. Mandó que la sacase y se la entregase, así como estaba, a la querellante; él lo hizo temblando; tomóla la mujer, y, haciendo mil zalemas a todos y rogando a Dios por la vida y salud del señor gobernador, que así miraba por las huérfanas menesterosas y doncellas; y con esto se salió del juzgado, llevando la bolsa asida con entrambas manos, aunque primero miró si era de plata la moneda que llevaba dentro. Apenas salió, cuando Sancho dijo al ganadero, que ya se le saltaban las lágrimas, y los ojos y el corazón se iban tras su bolsa: -Buen hombre, id tras aquella mujer y quitadle la bolsa, aunque no quiera, y volved aquí con ella. Y no lo dijo a tonto ni a sordo, porque luego partió como un rayo y fue a lo que se le mandaba. Todos los presentes estaban suspensos, esperando el fin de aquel pleito, y de allí a poco volvieron el hombre y la mujer más asidos y aferrados que la vez primera: ella la saya levantada y en el regazo puesta la bolsa, y el hombre pugnando por quitársela; mas no era posible, según la mujer la defendía, la cual daba voces diciendo: -¡Justicia de Dios y del mundo! Mire vuestra merced, señor gobernador, la poca vergüenza y el poco temor deste desalmado, que, en mitad de poblado y en mitad de la calle, me ha querido quitar la bolsa que vuestra merced mandó darme. -Y ¿háosla quitado? -preguntó el gobernador. -¿Cómo quitar? -respondió la mujer-. Antes me dejara yo quitar la vida que me quiten la bolsa. ¡Bonita es la niña! ¡Otros gatos me han de echar a las barbas, que no este desventurado y asqueroso! ¡Tenazas y martillos, mazos y escoplos no serán bastantes a sacármela de las uñas, ni aun garras de leones: antes el ánima de en mitad en mitad de las carnes! -Ella tiene razón -dijo el hombre-, y yo me doy por rendido y sin fuerzas, y confieso que las mías no son bastantes para quitársela, y déjola. Entonces el gobernador dijo a la mujer: -Mostrad, honrada y valiente, esa bolsa. Ella se la dio luego, y el gobernador se la volvió al hombre, y dijo a la esforzada y no forzada: -Hermana mía, si el mismo aliento y valor que habéis mostrado para defender esta bolsa le mostrárades, y aun la mitad menos, para defender vuestro cuerpo, las fuerzas de Hércules no os hicieran fuerza. Andad con Dios, y mucho de enhoramala, y no paréis en toda esta ínsula ni en seis leguas a la redonda, so pena de docientos azotes. ¡Andad luego digo, churrillera, desvergonzada y embaidora! Espantóse la mujer y fuese cabizbaja y mal contenta, y el gobernador dijo al hombre: -Buen hombre, andad con Dios a vuestro lugar con vuestro dinero, y de aquí adelante, si no le queréis perder, procurad que no os venga en voluntad de yogar con nadie. El hombre le dio las gracias lo peor que supo, y fuese, y los circunstantes quedaron admirados de nuevo de los juicios y sentencias de su nuevo gobernador. Todo lo cual, notado de su coronista, fue luego escrito al duque, que con gran deseo lo estaba esperando. Y quédese aquí el buen Sancho, que es mucha la priesa que nos da su amo, alborozado con la música de Altisidora. Capítulo XLVI. Del temeroso espanto cencerril y gatuno que recibió don Quijote en el discurso de los amores de la enamorada Altisidora Dejamos al gran don Quijote envuelto en los pensamientos que le habían causado la música de la enamorada doncella Altisidora. Acostóse con ellos, y, como si fueran pulgas, no le dejaron dormir ni sosegar un punto, y juntábansele los que le faltaban de sus medias; pero, como es ligero el tiempo, y no hay barranco que le detenga, corrió caballero en las horas, y con mucha presteza llegó la de la mañana. Lo cual visto por don Quijote, dejó las blandas plumas, y, no nada perezoso, se vistió su acamuzado vestido y se calzó sus botas de camino, por encubrir la desgracia de sus medias; arrojóse encima su mantón de escarlata y púsose en la cabeza una montera de terciopelo verde, guarnecida de pasamanos de plata; colgó el tahelí de sus hombros con su buena y tajadora espada, asió un gran rosario que consigo contino traía, y con gran prosopopeya y contoneo salió a la antesala, donde el duque y la duquesa estaban ya vestidos y como esperándole; y, al pasar por una galería, estaban aposta esperándole Altisidora y la otra doncella su amiga, y, así como Altisidora vio a don Quijote, fingió desmayarse, y su amiga la recogió en sus faldas, y con gran presteza la iba a desabrochar el pecho. Don Quijote, que lo vio, llegándose a ellas, dijo: -Ya sé yo de qué proceden estos accidentes. -No sé yo de qué -respondió la amiga-, porque Altisidora es la doncella más sana de toda esta casa, y yo nunca la he sentido un ¡ay! en cuanto ha que la conozco, que mal hayan cuantos caballeros andantes hay en el mundo, si es que todos son desagradecidos. Váyase vuesa merced, señor don Quijote, que no volverá en sí esta pobre niña en tanto que vuesa merced aquí estuviere. A lo que respondió don Quijote: -Haga vuesa merced, señora, que se me ponga un laúd esta noche en mi aposento, que yo consolaré lo mejor que pudiere a esta lastimada doncella; que en los principios amorosos los desengaños prestos suelen ser remedios calificados. Y con esto se fue, porque no fuese notado de los que allí le viesen. No se hubo bien apartado, cuando, volviendo en sí la desmayada Altisidora, dijo a su compañera: -Menester será que se le ponga el laúd, que sin duda don Quijote quiere darnos música, y no será mala, siendo suya. Fueron luego a dar cuenta a la duquesa de lo que pasaba y del laúd que pedía don Quijote, y ella, alegre sobremodo, concertó con el duque y con sus doncellas de hacerle una burla que fuese más risueña que dañosa, y con mucho contento esperaban la noche, que se vino tan apriesa como se había venido el día, el cual pasaron los duques en sabrosas pláticas con don Quijote. Y la duquesa aquel día real y verdaderamente despachó a un paje suyo, que había hecho en la selva la figura encantada de Dulcinea, a Teresa Panza, con la carta de su marido Sancho Panza, y con el lío de ropa que había dejado para que se le enviase, encargándole le trujese buena relación de todo lo que con ella pasase. Hecho esto, y llegadas las once horas de la noche, halló don Quijote una vihuela en su aposento; templóla, abrió la reja, y sintió que andaba gente en el jardín; y, habiendo recorrido los trastes de la vihuela y afinándola lo mejor que supo, escupió y remondóse el pecho, y luego, con una voz ronquilla, aunque entonada, cantó el siguiente romance, que él mismo aquel día había compuesto: -Suelen las fuerzas de amor sacar de quicio a las almas, tomando por instrumento la ociosidad descuidada. Suele el coser y el labrar, y el estar siempre ocupada, ser antídoto al veneno de las amorosas ansias. Las doncellas recogidas que aspiran a ser casadas, la honestidad es la dote y voz de sus alabanzas. Los andantes caballeros, y los que en la corte andan, requiébranse con las libres, con las honestas se casan. Hay amores de levante, que entre huéspedes se tratan, que llegan presto al poniente, porque en el partirse acaban. El amor recién venido, que hoy llegó y se va mañana, las imágines no deja bien impresas en el alma. Pintura sobre pintura ni se muestra ni señala; y do hay primera belleza, la segunda no hace baza. Dulcinea del Toboso del alma en la tabla rasa tengo pintada de modo que es imposible borrarla. La firmeza en los amantes es la parte más preciada, por quien hace amor milagros, y asimesmo los levanta. Aquí llegaba don Quijote de su canto, a quien estaban escuchando el duque y la duquesa, Altisidora y casi toda la gente del castillo, cuando de improviso, desde encima de un corredor que sobre la reja de don Quijote a plomo caía, descolgaron un cordel donde venían más de cien cencerros asidos, y luego, tras ellos, derramaron un gran saco de gatos, que asimismo traían cencerros menores atados a las colas. Fue tan grande el ruido de los cencerros y el mayar de los gatos, que, aunque los duques habían sido inventores de la burla, todavía les sobresaltó; y, temeroso, don Quijote quedó pasmado. Y quiso la suerte que dos o tres gatos se entraron por la reja de su estancia, y, dando de una parte a otra, parecía que una región de diablos andaba en ella. Apagaron las velas que en el aposento ardían, y andaban buscando por do escaparse. El descolgar y subir del cordel de los grandes cencerros no cesaba; la mayor parte de la gente del castillo, que no sabía la verdad del caso, estaba suspensa y admirada. Levantóse don Quijote en pie, y, poniendo mano a la espada, comenzó a tirar estocadas por la reja y a decir a grandes voces: -¡Afuera, malignos encantadores! ¡Afuera, canalla hechiceresca, que yo soy don Quijote de la Mancha, contra quien no valen ni tienen fuerza vuestras malas intenciones! Y, volviéndose a los gatos que andaban por el aposento, les tiró muchas cuchilladas; ellos acudieron a la reja, y por allí se salieron, aunque uno, viéndose tan acosado de las cuchilladas de don Quijote, le saltó al rostro y le asió de las narices con las uñas y los dientes, por cuyo dolor don Quijote comenzó a dar los mayores gritos que pudo. Oyendo lo cual el duque y la duquesa, y considerando lo que podía ser, con mucha presteza acudieron a su estancia, y, abriendo con llave maestra, vieron al pobre caballero pugnando con todas sus fuerzas por arrancar el gato de su rostro. Entraron con luces y vieron la desigual pelea; acudió el duque a despartirla, y don Quijote dijo a voces: -¡No me le quite nadie! ¡Déjenme mano a mano con este demonio, con este hechicero, con este encantador, que yo le daré a entender de mí a él quién es don Quijote de la Mancha! Pero el gato, no curándose destas amenazas, gruñía y apretaba. Mas, en fin, el duque se le desarraigó y le echó por la reja. Quedó don Quijote acribado el rostro y no muy sanas las narices, aunque muy despechado porque no le habían dejado fenecer la batalla que tan trabada tenía con aquel malandrín encantador. Hicieron traer aceite de Aparicio, y la misma Altisidora, con sus blanquísimas manos, le puso unas vendas por todo lo herido; y, al ponérselas, con voz baja le dijo: -Todas estas malandanzas te suceden, empedernido caballero, por el pecado de tu dureza y pertinacia; y plega a Dios que se le olvide a Sancho tu escudero el azotarse, porque nunca salga de su encanto esta tan amada tuya Dulcinea, ni tú lo goces, ni llegues a tálamo con ella, a lo menos viviendo yo, que te adoro. A todo esto no respondió don Quijote otra palabra si no fue dar un profundo suspiro, y luego se tendió en su lecho, agradeciendo a los duques la merced, no porque él tenía temor de aquella canalla gatesca, encantadora y cencerruna, sino porque había conocido la buena intención con que habían venido a socorrerle. Los duques le dejaron sosegar, y se fueron, pesarosos del mal suceso de la burla; que no creyeron que tan pesada y costosa le saliera a don Quijote aquella aventura, que le costó cinco días de encerramiento y de cama, donde le sucedió otra aventura más gustosa que la pasada, la cual no quiere su historiador contar ahora, por acudir a Sancho Panza, que andaba muy solícito y muy gracioso en su gobierno. Capítulo XLVII. Donde se prosigue cómo se portaba Sancho Panza en su gobierno Cuenta la historia que desde el juzgado llevaron a Sancho Panza a un suntuoso palacio, adonde en una gran sala estaba puesta una real y limpísima mesa; y, así como Sancho entró en la sala, sonaron chirimías, y salieron cuatro pajes a darle aguamanos, que Sancho recibió con mucha gravedad. Cesó la música, sentóse Sancho a la cabecera de la mesa, porque no había más de aquel asiento, y no otro servicio en toda ella. Púsose a su lado en pie un personaje, que después mostró ser médico, con una varilla de ballena en la mano. Levantaron una riquísima y blanca toalla con que estaban cubiertas las frutas y mucha diversidad de platos de diversos manjares; uno que parecía estudiante echó la bendición, y un paje puso un babador randado a Sancho; otro que hacía el oficio de maestresala, llegó un plato de fruta delante; pero, apenas hubo comido un bocado, cuando el de la varilla tocando con ella en el plato, se le quitaron de delante con grandísima celeridad; pero el maestresala le llegó otro de otro manjar. Iba a probarle Sancho; pero, antes que llegase a él ni le gustase, ya la varilla había tocado en él, y un paje alzádole con tanta presteza como el de la fruta. Visto lo cual por Sancho, quedó suspenso, y, mirando a todos, preguntó si se había de comer aquella comida como juego de maesecoral. A lo cual respondió el de la vara: -No se ha de comer, señor gobernador, sino como es uso y costumbre en las otras ínsulas donde hay gobernadores. Yo, señor, soy médico, y estoy asalariado en esta ínsula para serlo de los gobernadores della, y miro por su salud mucho más que por la mía, estudiando de noche y de día, y tanteando la complexión del gobernador, para acertar a curarle cuando cayere enfermo; y lo principal que hago es asistir a sus comidas y cenas, y a dejarle comer de lo que me parece que le conviene, y a quitarle lo que imagino que le ha de hacer daño y ser nocivo al estómago; y así, mandé quitar el plato de la fruta, por ser demasiadamente húmeda, y el plato del otro manjar también le mandé quitar, por ser demasiadamente caliente y tener muchas especies, que acrecientan la sed; y el que mucho bebe mata y consume el húmedo radical, donde consiste la vida. -Desa manera, aquel plato de perdices que están allí asadas, y, a mi parecer, bien sazonadas, no me harán algún daño. A lo que el médico respondió: -Ésas no comerá el señor gobernador en tanto que yo tuviere vida. -Pues, ¿por qué? -dijo Sancho. Y el médico respondió: -Porque nuestro maestro Hipócrates, norte y luz de la medicina, en un aforismo suyo, dice: Omnis saturatio mala, perdices autem pessima. Quiere decir: "Toda hartazga es mala; pero la de las perdices, malísima". -Si eso es así -dijo Sancho-, vea el señor doctor de cuantos manjares hay en esta mesa cuál me hará más provecho y cuál menos daño, y déjeme comer dél sin que me le apalee; porque, por vida del gobernador, y así Dios me le deje gozar, que me muero de hambre, y el negarme la comida, aunque le pese al señor doctor y él más me diga, antes será quitarme la vida que aumentármela. -Vuestra merced tiene razón, señor gobernador -respondió el médico-; y así, es mi parecer que vuestra merced no coma de aquellos conejos guisados que allí están, porque es manjar peliagudo. De aquella ternera, si no fuera asada y en adobo, aún se pudiera probar, pero no hay para qué. Y Sancho dijo: -Aquel platonazo que está más adelante vahando me parece que es olla podrida, que por la diversidad de cosas que en las tales ollas podridas hay, no podré dejar de topar con alguna que me sea de gusto y de provecho. -Absit! -dijo el médico-. Vaya lejos de nosotros tan mal pensamiento: no hay cosa en el mundo de peor mantenimiento que una olla podrida. Allá las ollas podridas para los canónigos, o para los retores de colegios, o para las bodas labradorescas, y déjennos libres las mesas de los gobernadores, donde ha de asistir todo primor y toda atildadura; y la razón es porque siempre y a doquiera y de quienquiera son más estimadas las medicinas simples que las compuestas, porque en las simples no se puede errar y en las compuestas sí, alterando la cantidad de las cosas de que son compuestas; mas lo que yo sé que ha de comer el señor gobernador ahora, para conservar su salud y corroborarla, es un ciento de cañutillos de suplicaciones y unas tajadicas subtiles de carne de membrillo, que le asienten el estómago y le ayuden a la digestión. Oyendo esto Sancho, se arrimó sobre el espaldar de la silla y miró de hito en hito al tal médico, y con voz grave le preguntó cómo se llamaba y dónde había estudiado. A lo que él respondió: -Yo, señor gobernador, me llamo el doctor Pedro Recio de Agüero, y soy natural de un lugar llamado Tirteafuera, que está entre Caracuel y Almodóvar del Campo, a la mano derecha, y tengo el grado de doctor por la universidad de Osuna. A lo que respondió Sancho, todo encendido en cólera: -Pues, señor doctor Pedro Recio de Mal Agüero, natural de Tirteafuera, lugar que está a la derecha mano como vamos de Caracuel a Almodóvar del Campo, graduado en Osuna, quíteseme luego delante, si no, voto al sol que tome un garrote y que a garrotazos, comenzando por él, no me ha de quedar médico en toda la ínsula, a lo menos de aquellos que yo entienda que son ignorantes; que a los médicos sabios, prudentes y discretos los pondré sobre mi cabeza y los honraré como a personas divinas. Y vuelvo a decir que se me vaya, Pedro Recio, de aquí; si no, tomaré esta silla donde estoy sentado y se la estrellaré en la cabeza; y pídanmelo en residencia, que yo me descargaré con decir que hice servicio a Dios en matar a un mal médico, verdugo de la república. Y denme de comer, o si no, tómense su gobierno, que oficio que no da de comer a su dueño no vale dos habas. Alborotóse el doctor, viendo tan colérico al gobernador, y quiso hacer tirteafuera de la sala, sino que en aquel instante sonó una corneta de posta en la calle, y, asomándose el maestresala a la ventana, volvió diciendo: -Correo viene del duque mi señor; algún despacho debe de traer de importancia. Entró el correo sudando y asustado, y, sacando un pliego del seno, le puso en las manos del gobernador, y Sancho le puso en las del mayordomo, a quien mandó leyese el sobreescrito, que decía así: A don Sancho Panza, gobernador de la ínsula Barataria, en su propia mano o en las de su secretario. Oyendo lo cual, Sancho dijo: -¿Quién es aquí mi secretario? Y uno de los que presentes estaban respondió: -Yo, señor, porque sé leer y escribir, y soy vizcaíno. -Con esa añadidura -dijo Sancho-, bien podéis ser secretario del mismo emperador. Abrid ese pliego, y mirad lo que dice. Hízolo así el recién nacido secretario, y, habiendo leído lo que decía, dijo que era negocio para tratarle a solas. Mandó Sancho despejar la sala, y que no quedasen en ella sino el mayordomo y el maestresala, y los demás y el médico se fueron; y luego el secretario leyó la carta, que así decía: A mi noticia ha llegado, señor don Sancho Panza, que unos enemigos míos y desa ínsula la han de dar un asalto furioso, no sé qué noche; conviene velar y estar alerta, porque no le tomen desapercebido. Sé también, por espías verdaderas, que han entrado en ese lugar cuatro personas disfrazadas para quitaros la vida, porque se temen de vuestro ingenio; abrid el ojo, y mirad quién llega a hablaros, y no comáis de cosa que os presentaren. Yo tendré cuidado de socorreros si os viéredes en trabajo, y en todo haréis como se espera de vuestro entendimiento. Deste lugar, a 16 de agosto, a las cuatro de la mañana. Vuestro amigo, El Duque. Quedó atónito Sancho, y mostraron quedarlo asimismo los circunstantes; y, volviéndose al mayordomo, le dijo: -Lo que agora se ha de hacer, y ha de ser luego, es meter en un calabozo al doctor Recio; porque si alguno me ha de matar, ha de ser él, y de muerte adminícula y pésima, como es la de la hambre. -También -dijo el maestresala- me parece a mí que vuesa merced no coma de todo lo que está en esta mesa, porque lo han presentado unas monjas, y, como suele decirse, detrás de la cruz está el diablo. -No lo niego -respondió Sancho-, y por ahora denme un pedazo de pan y obra de cuatro libras de uvas, que en ellas no podrá venir veneno; porque, en efecto, no puedo pasar sin comer, y si es que hemos de estar prontos para estas batallas que nos amenazan, menester será estar bien mantenidos, porque tripas llevan corazón, que no corazón tripas. Y vos, secretario, responded al duque mi señor y decidle que se cumplirá lo que manda como lo manda, sin faltar punto; y daréis de mi parte un besamanos a mi señora la duquesa, y que le suplico no se le olvide de enviar con un propio mi carta y mi lío a mi mujer Teresa Panza, que en ello recibiré mucha merced, y tendré cuidado de servirla con todo lo que mis fuerzas alcanzaren; y de camino podéis encajar un besamanos a mi señor don Quijote de la Mancha, porque vea que soy pan agradecido; y vos, como buen secretario y como buen vizcaíno, podéis añadir todo lo que quisiéredes y más viniere a cuento. Y álcense estos manteles, y denme a mí de comer, que yo me avendré con cuantas espías y matadores y encantadores vinieren sobre mí y sobre mi ínsula. En esto entró un paje, y dijo: -Aquí está un labrador negociante que quiere hablar a Vuestra Señoría en un negocio, según él dice, de mucha importancia. -Estraño caso es éste -dijo Sancho- destos negociantes. ¿Es posible que sean tan necios, que no echen de ver que semejantes horas como éstas no son en las que han de venir a negociar? ¿Por ventura los que gobernamos, los que somos jueces, no somos hombres de carne y de hueso, y que es menester que nos dejen descansar el tiempo que la necesidad pide, sino que quieren que seamos hechos de piedra marmol? Por Dios y en mi conciencia que si me dura el gobierno (que no durará, según se me trasluce), que yo ponga en pretina a más de un negociante. Agora decid a ese buen hombre que entre; pero adviértase primero no sea alguno de los espías, o matador mío. -No, señor -respondió el paje-, porque parece una alma de cántaro, y yo sé poco, o él es tan bueno como el buen pan. -No hay que temer -dijo el mayordomo-, que aquí estamos todos. -¿Sería posible -dijo Sancho-, maestresala, que agora que no está aquí el doctor Pedro Recio, que comiese yo alguna cosa de peso y de sustancia, aunque fuese un pedazo de pan y una cebolla? -Esta noche, a la cena, se satisfará la falta de la comida, y quedará Vuestra Señoría satisfecho y pagado -dijo el maestresala. -Dios lo haga -respondió Sancho. Y, en esto, entró el labrador, que era de muy buena presencia, y de mil leguas se le echaba de ver que era bueno y buena alma. Lo primero que dijo fue: -¿Quién es aquí el señor gobernador? -¿Quién ha de ser -respondió el secretario-, sino el que está sentado en la silla? -Humíllome, pues, a su presencia -dijo el labrador. Y, poniéndose de rodillas, le pidió la mano para besársela. Negósela Sancho, y mandó que se levantase y dijese lo que quisiese. Hízolo así el labrador, y luego dijo: -Yo, señor, soy labrador, natural de Miguel Turra, un lugar que está dos leguas de Ciudad Real. -¡Otro Tirteafuera tenemos! -dijo Sancho-. Decid, hermano, que lo que yo os sé decir es que sé muy bien a Miguel Turra, y que no está muy lejos de mi pueblo. -Es, pues, el caso, señor -prosiguió el labrador-, que yo, por la misericordia de Dios, soy casado en paz y en haz de la Santa Iglesia Católica Romana; tengo dos hijos estudiantes que el menor estudia para bachiller y el mayor para licenciado; soy viudo, porque se murió mi mujer, o, por mejor decir, me la mató un mal médico, que la purgó estando preñada, y si Dios fuera servido que saliera a luz el parto, y fuera hijo, yo le pusiere a estudiar para doctor, porque no tuviera invidia a sus hermanos el bachiller y el licenciado. -De modo -dijo Sancho- que si vuestra mujer no se hubiera muerto, o la hubieran muerto, vos no fuérades agora viudo. -No, señor, en ninguna manera -respondió el labrador. -¡Medrados estamos! -replicó Sancho-. Adelante, hermano, que es hora de dormir más que de negociar. -Digo, pues -dijo el labrador-, que este mi hijo que ha de ser bachiller se enamoró en el mesmo pueblo de una doncella llamada Clara Perlerina, hija de Andrés Perlerino, labrador riquísimo; y este nombre de Perlerines no les viene de abolengo ni otra alcurnia, sino porque todos los deste linaje son perláticos, y por mejorar el nombre los llaman Perlerines; aunque, si va decir la verdad, la doncella es como una perla oriental, y, mirada por el lado derecho, parece una flor del campo; por el izquierdo no tanto, porque le falta aquel ojo, que se le saltó de viruelas; y, aunque los hoyos del rostro son muchos y grandes, dicen los que la quieren bien que aquéllos no son hoyos, sino sepulturas donde se sepultan las almas de sus amantes. Es tan limpia que, por no ensuciar la cara, trae las narices, como dicen, arremangadas, que no parece sino que van huyendo de la boca; y, con todo esto, parece bien por estremo, porque tiene la boca grande, y, a no faltarle diez o doce dientes y muelas, pudiera pasar y echar raya entre las más bien formadas. De los labios no tengo qué decir, porque son tan sutiles y delicados que, si se usaran aspar labios, pudieran hacer dellos una madeja; pero, como tienen diferente color de la que en los labios se usa comúnmente, parecen milagrosos, porque son jaspeados de azul y verde y aberenjenado; y perdóneme el señor gobernador si por tan menudo voy pintando las partes de la que al fin al fin ha de ser mi hija, que la quiero bien y no me parece mal. -Pintad lo que quisiéredes -dijo Sancho-, que yo me voy recreando en la pintura, y si hubiera comido, no hubiera mejor postre para mí que vuestro retrato. -Eso tengo yo por servir -respondió el labrador-, pero tiempo vendrá en que seamos, si ahora no somos. Y digo, señor, que si pudiera pintar su gentileza y la altura de su cuerpo, fuera cosa de admiración; pero no puede ser, a causa de que ella está agobiada y encogida, y tiene las rodillas con la boca, y, con todo eso, se echa bien de ver que si se pudiera levantar, diera con la cabeza en el techo; y ya ella hubiera dado la mano de esposa a mi bachiller, sino que no la puede estender, que está añudada; y, con todo, en las uñas largas y acanaladas se muestra su bondad y buena hechura. -Está bien -dijo Sancho-, y haced cuenta, hermano, que ya la habéis pintado de los pies a la cabeza. ¿Qué es lo que queréis ahora? Y venid al punto sin rodeos ni callejuelas, ni retazos ni añadiduras. -Querría, señor -respondió el labrador-, que vuestra merced me hiciese merced de darme una carta de favor para mi consuegro, suplicándole sea servido de que este casamiento se haga, pues no somos desiguales en los bienes de fortuna, ni en los de la naturaleza; porque, para decir la verdad, señor gobernador, mi hijo es endemoniado, y no hay día que tres o cuatro veces no le atormenten los malignos espíritus; y de haber caído una vez en el fuego, tiene el rostro arrugado como pergamino, y los ojos algo llorosos y manantiales; pero tiene una condición de un ángel, y si no es que se aporrea y se da de puñadas él mesmo a sí mesmo, fuera un bendito. -¿Queréis otra cosa, buen hombre? -replicó Sancho. -Otra cosa querría -dijo el labrador-, sino que no me atrevo a decirlo; pero vaya, que, en fin, no se me ha de podrir en el pecho, pegue o no pegue. Digo, señor, que querría que vuesa merced me diese trecientos o seiscientos ducados para ayuda a la dote de mi bachiller; digo para ayuda de poner su casa, porque, en fin, han de vivir por sí, sin estar sujetos a las impertinencias de los suegros. -Mirad si queréis otra cosa -dijo Sancho-, y no la dejéis de decir por empacho ni por vergüenza. -No, por cierto -respondió el labrador. Y, apenas dijo esto, cuando, levantándose en pie el gobernador, asió de la silla en que estaba sentado y dijo: -¡Voto a tal, don patán rústico y mal mirado, que si no os apartáis y ascondéis luego de mi presencia, que con esta silla os rompa y abra la cabeza! Hideputa bellaco, pintor del mesmo demonio, ¿y a estas horas te vienes a pedirme seiscientos ducados?; y ¿dónde los tengo yo, hediondo?; y ¿por qué te los había de dar, aunque los tuviera, socarrón y mentecato?; y ¿qué se me da a mí de Miguel Turra, ni de todo el linaje de los Perlerines? ¡Va de mí, digo; si no, por vida del duque mi señor, que haga lo que tengo dicho! Tú no debes de ser de Miguel Turra, sino algún socarrón que, para tentarme, te ha enviado aquí el infierno. Dime, desalmado, aún no ha día y medio que tengo el gobierno, y ¿ya quieres que tenga seiscientos ducados? Hizo de señas el maestresala al labrador que se saliese de la sala, el cual lo hizo cabizbajo y, al parecer, temeroso de que el gobernador no ejecutase su cólera, que el bellacón supo hacer muy bien su oficio. Pero dejemos con su cólera a Sancho, y ándese la paz en el corro, y volvamos a don Quijote, que le dejamos vendado el rostro y curado de las gatescas heridas, de las cuales no sanó en ocho días, en uno de los cuales le sucedió lo que Cide Hamete promete de contar con la puntualidad y verdad que suele contar las cosas desta historia, por mínimas que sean. Capítulo XLVIII. De lo que le sucedió a don Quijote con doña Rodríguez, la dueña de la duquesa, con otros acontecimientos dignos de escritura y de memoria eterna Además estaba mohíno y malencólico el mal ferido don Quijote, vendado el rostro y señalado, no por la mano de Dios, sino por las uñas de un gato, desdichas anejas a la andante caballería. Seis días estuvo sin salir en público, en una noche de las cuales, estando despierto y desvelado, pensando en sus desgracias y en el perseguimiento de Altisidora, sintió que con una llave abrían la puerta de su aposento, y luego imaginó que la enamorada doncella venía para sobresaltar su honestidad y ponerle en condición de faltar a la fee que guardar debía a su señora Dulcinea del Toboso. -No -dijo creyendo a su imaginación, y esto, con voz que pudiera ser oída-; no ha de ser parte la mayor hermosura de la tierra para que yo deje de adorar la que tengo grabada y estampada en la mitad de mi corazón y en lo más escondido de mis entrañas, ora estés, señora mía, transformada en cebolluda labradora, ora en ninfa del dorado Tajo, tejiendo telas de oro y sirgo compuestas, ora te tenga Merlín, o Montesinos, donde ellos quisieren; que, adondequiera eres mía, y adoquiera he sido yo, y he de ser, tuyo. El acabar estas razones y el abrir de la puerta fue todo uno. Púsose en pie sobre la cama, envuelto de arriba abajo en una colcha de raso amarillo, una galocha en la cabeza, y el rostro y los bigotes vendados: el rostro, por los aruños; los bigotes, porque no se le desmayasen y cayesen; en el cual traje parecía la más extraordinaria fantasma que se pudiera pensar. Clavó los ojos en la puerta, y, cuando esperaba ver entrar por ella a la rendida y lastimada Altisidora, vio entrar a una reverendísima dueña con unas tocas blancas repulgadas y luengas, tanto, que la cubrían y enmantaban desde los pies a la cabeza. Entre los dedos de la mano izquierda traía una media vela encendida, y con la derecha se hacía sombra, porque no le diese la luz en los ojos, a quien cubrían unos muy grandes antojos. Venía pisando quedito, y movía los pies blandamente. Miróla don Quijote desde su atalaya, y cuando vio su adeliño y notó su silencio, pensó que alguna bruja o maga venía en aquel traje a hacer en él alguna mala fechuría, y comenzó a santiguarse con mucha priesa. Fuese llegando la visión, y, cuando llegó a la mitad del aposento, alzó los ojos y vio la priesa con que se estaba haciendo cruces don Quijote; y si él quedó medroso en ver tal figura, ella quedó espantada en ver la suya, porque, así como le vio tan alto y tan amarillo, con la colcha y con las vendas, que le desfiguraban, dio una gran voz, diciendo: -¡Jesús! ¿Qué es lo que veo? Y con el sobresalto se le cayó la vela de las manos; y, viéndose a escuras, volvió las espaldas para irse, y con el miedo tropezó en sus faldas y dio consigo una gran caída. Don Quijote, temeroso, comenzó a decir: -Conjúrote, fantasma, o lo que eres, que me digas quién eres, y que me digas qué es lo que de mí quieres. Si eres alma en pena, dímelo, que yo haré por ti todo cuanto mis fuerzas alcanzaren, porque soy católico cristiano y amigo de hacer bien a todo el mundo; que para esto tomé la orden de la caballería andante que profeso, cuyo ejercicio aun hasta hacer bien a las ánimas de purgatorio se estiende. La brumada dueña, que oyó conjurarse, por su temor coligió el de don Quijote, y con voz afligida y baja le respondió: -Señor don Quijote, si es que acaso vuestra merced es don Quijote, yo no soy fantasma, ni visión, ni alma de purgatorio, como vuestra merced debe de haber pensado, sino doña Rodríguez, la dueña de honor de mi señora la duquesa, que, con una necesidad de aquellas que vuestra merced suele remediar, a vuestra merced vengo. -Dígame, señora doña Rodríguez -dijo don Quijote-: ¿por ventura viene vuestra merced a hacer alguna tercería? Porque le hago saber que no soy de provecho para nadie, merced a la sin par belleza de mi señora Dulcinea del Toboso. Digo, en fin, señora doña Rodríguez, que, como vuestra merced salve y deje a una parte todo recado amoroso, puede volver a encender su vela, y vuelva, y departiremos de todo lo que más mandare y más en gusto le viniere, salvando, como digo, todo incitativo melindre. -¿Yo recado de nadie, señor mío? -respondió la dueña-. Mal me conoce vuestra merced; sí, que aún no estoy en edad tan prolongada que me acoja a semejantes niñerías, pues, Dios loado, mi alma me tengo en las carnes, y todos mis dientes y muelas en la boca, amén de unos pocos que me han usurpado unos catarros, que en esta tierra de Aragón son tan ordinarios. Pero espéreme vuestra merced un poco; saldré a encender mi vela, y volveré en un instante a contar mis cuitas, como a remediador de todas las del mundo. Y, sin esperar respuesta, se salió del aposento, donde quedó don Quijote sosegado y pensativo esperándola; pero luego le sobrevinieron mil pensamientos acerca de aquella nueva aventura, y parecíale ser mal hecho y peor pensado ponerse en peligro de romper a su señora la fee prometida, y decíase a sí mismo: -¿Quién sabe si el diablo, que es sutil y mañoso, querrá engañarme agora con una dueña, lo que no ha podido con emperatrices, reinas, duquesas, marquesas ni condesas? Que yo he oído decir muchas veces y a muchos discretos que, si él puede, antes os la dará roma que aguileña. Y ¿quién sabe si esta soledad, esta ocasión y este silencio despertará mis deseos que duermen, y harán que al cabo de mis años venga a caer donde nunca he tropezado? Y, en casos semejantes, mejor es huir que esperar la batalla. Pero yo no debo de estar en mi juicio, pues tales disparates digo y pienso; que no es posible que una dueña toquiblanca, larga y antojuna pueda mover ni levantar pensamiento lascivo en el más desalmado pecho del mundo. ¿Por ventura hay dueña en la tierra que tenga buenas carnes? ¿Por ventura hay dueña en el orbe que deje de ser impertinente, fruncida y melindrosa? ¡Afuera, pues, caterva dueñesca, inútil para ningún humano regalo! ¡Oh, cuán bien hacía aquella señora de quien se dice que tenía dos dueñas de bulto con sus antojos y almohadillas al cabo de su estrado, como que estaban labrando, y tanto le servían para la autoridad de la sala aquellas estatuas como las dueñas verdaderas! Y, diciendo esto, se arrojó del lecho, con intención de cerrar la puerta y no dejar entrar a la señora Rodríguez; mas, cuando la llegó a cerrar, ya la señora Rodríguez volvía, encendida una vela de cera blanca, y cuando ella vio a don Quijote de más cerca, envuelto en la colcha, con las vendas, galocha o becoquín, temió de nuevo, y, retirándose atrás como dos pasos, dijo: -¿Estamos seguras, señor caballero? Porque no tengo a muy honesta señal haberse vuesa merced levantado de su lecho. -Eso mesmo es bien que yo pregunte, señora -respondió don Quijote-; y así, pregunto si estaré yo seguro de ser acometido y forzado. -¿De quién o a quién pedís, señor caballero, esa seguridad? -respondió la dueña. -A vos y de vos la pido -replicó don Quijote-, porque ni yo soy de mármol ni vos de bronce, ni ahora son las diez del día, sino media noche, y aun un poco más, según imagino, y en una estancia más cerrada y secreta que lo debió de ser la cueva donde el traidor y atrevido Eneas gozó a la hermosa y piadosa Dido. Pero dadme, señora, la mano, que yo no quiero otra seguridad mayor que la de mi continencia y recato, y la que ofrecen esas reverendísimas tocas. Y, diciendo esto, besó su derecha mano, y le asió de la suya, que ella le dio con las mesmas ceremonias. Aquí hace Cide Hamete un paréntesis, y dice que por Mahoma que diera, por ver ir a los dos así asidos y trabados desde la puerta al lecho, la mejor almalafa de dos que tenía. Entróse, en fin, don Quijote en su lecho, y quedóse doña Rodríguez sentada en una silla, algo desviada de la cama, no quitándose los antojos ni la vela. Don Quijote se acorrucó y se cubrió todo, no dejando más de el rostro descubierto; y, habiéndose los dos sosegado, el primero que rompió el silencio fue don Quijote, diciendo: -Puede vuesa merced ahora, mi señora doña Rodríguez, descoserse y desbuchar todo aquello que tiene dentro de su cuitado corazón y lastimadas entrañas, que será de mí escuchada con castos oídos, y socorrida con piadosas obras. -Así lo creo yo -respondió la dueña-, que de la gentil y agradable presencia de vuesa merced no se podía esperar sino tan cristiana respuesta. «Es, pues, el caso, señor don Quijote, que, aunque vuesa merced me vee sentada en esta silla y en la mitad del reino de Aragón, y en hábito de dueña aniquilada y asendereada, soy natural de las Asturias de Oviedo, y de linaje que atraviesan por él muchos de los mejores de aquella provincia; pero mi corta suerte y el descuido de mis padres, que empobrecieron antes de tiempo, sin saber cómo ni cómo no, me trujeron a la corte, a Madrid, donde por bien de paz y por escusar mayores desventuras, mis padres me acomodaron a servir de doncella de labor a una principal señora; y quiero hacer sabidor a vuesa merced que en hacer vainillas y labor blanca ninguna me ha echado el pie adelante en toda la vida. Mis padres me dejaron sirviendo y se volvieron a su tierra, y de allí a pocos años se debieron de ir al cielo, porque eran además buenos y católicos cristianos. Quedé huérfana, y atenida al miserable salario y a las angustiadas mercedes que a las tales criadas se suele dar en palacio; y, en este tiempo, sin que diese yo ocasión a ello, se enamoró de mi un escudero de casa, hombre ya en días, barbudo y apersonado, y, sobre todo, hidalgo como el rey, porque era montañés. No tratamos tan secretamente nuestros amores que no viniesen a noticia de mi señora, la cual, por escusar dimes y diretes, nos casó en paz y en haz de la Santa Madre Iglesia Católica Romana, de cuyo matrimonio nació una hija para rematar con mi ventura, si alguna tenía; no porque yo muriese del parto, que le tuve derecho y en sazón, sino porque desde allí a poco murió mi esposo de un cierto espanto que tuvo, que, a tener ahora lugar para contarle, yo sé que vuestra merced se admirara.» Y, en esto, comenzó a llorar tiernamente, y dijo: -Perdóneme vuestra merced, señor don Quijote, que no va más en mi mano, porque todas las veces que me acuerdo de mi mal logrado se me arrasan los ojos de lágrimas. ¡Válame Dios, y con qué autoridad llevaba a mi señora a las ancas de una poderosa mula, negra como el mismo azabache! Que entonces no se usaban coches ni sillas, como agora dicen que se usan, y las señoras iban a las ancas de sus escuderos. Esto, a lo menos, no puedo dejar de contarlo, porque se note la crianza y puntualidad de mi buen marido. «Al entrar de la calle de Santiago, en Madrid, que es algo estrecha, venía a salir por ella un alcalde de corte con dos alguaciles delante, y, así como mi buen escudero le vio, volvió las riendas a la mula, dando señal de volver a acompañarle. Mi señora, que iba a las ancas, con voz baja le decía: ''-¿Qué hacéis, desventurado? ¿No veis que voy aquí?'' El alcalde, de comedido, detuvo la rienda al caballo y díjole: ''-Seguid, señor, vuestro camino, que yo soy el que debo acompañar a mi señora doña Casilda'', que así era el nombre de mi ama. Todavía porfiaba mi marido, con la gorra en la mano, a querer ir acompañando al alcalde, viendo lo cual mi señora, llena de cólera y enojo, sacó un alfiler gordo, o creo que un punzón, del estuche, y clavósele por los lomos, de manera que mi marido dio una gran voz y torció el cuerpo, de suerte que dio con su señora en el suelo. Acudieron dos lacayos suyos a levantarla, y lo mismo hizo el alcalde y los alguaciles; alborotóse la Puerta de Guadalajara, digo, la gente baldía que en ella estaba; vínose a pie mi ama, y mi marido acudió en casa de un barbero diciendo que llevaba pasadas de parte a parte las entrañas. Divulgóse la cortesía de mi esposo, tanto, que los muchachos le corrían por las calles, y por esto y porque él era algún tanto corto de vista, mi señora la duquesa le despidió, de cuyo pesar, sin duda alguna, tengo para mí que se le causó el mal de la muerte. Quedé yo viuda y desamparada, y con hija a cuestas, que iba creciendo en hermosura como la espuma de la mar. Finalmente, como yo tuviese fama de gran labrandera, mi señora la duquesa, que estaba recién casada con el duque mi señor, quiso traerme consigo a este reino de Aragón y a mi hija ni más ni menos, adonde, yendo días y viniendo días, creció mi hija, y con ella todo el donaire del mundo: canta como una calandria, danza como el pensamiento, baila como una perdida, lee y escribe como un maestro de escuela, y cuenta como un avariento. De su limpieza no digo nada: que el agua que corre no es más limpia, y debe de tener agora, si mal no me acuerdo, diez y seis años, cinco meses y tres días, uno más a menos. En resolución: de esta mi muchacha se enamoró un hijo de un labrador riquísimo que está en una aldea del duque mi señor, no muy lejos de aquí. En efecto, no sé cómo ni cómo no, ellos se juntaron, y, debajo de la palabra de ser su esposo, burló a mi hija, y no se la quiere cumplir; y, aunque el duque mi señor lo sabe, porque yo me he quejado a él, no una, sino muchas veces, y pedídole mande que el tal labrador se case con mi hija, hace orejas de mercader y apenas quiere oírme; y es la causa que, como el padre del burlador es tan rico y le presta dineros, y le sale por fiador de sus trampas por momentos, no le quiere descontentar ni dar pesadumbre en ningún modo.» Querría, pues, señor mío, que vuesa merced tomase a cargo el deshacer este agravio, o ya por ruegos, o ya por armas, pues, según todo el mundo dice, vuesa merced nació en él para deshacerlos y para enderezar los tuertos y amparar los miserables; y póngasele a vuesa merced por delante la orfandad de mi hija, su gentileza, su mocedad, con todas las buenas partes que he dicho que tiene; que en Dios y en mi conciencia que de cuantas doncellas tiene mi señora, que no hay ninguna que llegue a la suela de su zapato, y que una que llaman Altisidora, que es la que tienen por más desenvuelta y gallarda, puesta en comparación de mi hija, no la llega con dos leguas. Porque quiero que sepa vuesa merced, señor mío, que no es todo oro lo que reluce; porque esta Altisidorilla tiene más de presunción que de hermosura, y más de desenvuelta que de recogida, además que no está muy sana: que tiene un cierto allento cansado, que no hay sufrir el estar junto a ella un momento. Y aun mi señora la duquesa... Quiero callar, que se suele decir que las paredes tienen oídos. -¿Qué tiene mi señora la duquesa, por vida mía, señora doña Rodríguez? -preguntó don Quijote. -Con ese conjuro -respondió la dueña-, no puedo dejar de responder a lo que se me pregunta con toda verdad. ¿Vee vuesa merced, señor don Quijote, la hermosura de mi señora la duquesa, aquella tez de rostro, que no parece sino de una espada acicalada y tersa, aquellas dos mejillas de leche y de carmín, que en la una tiene el sol y en la otra la luna, y aquella gallardía con que va pisando y aun despreciando el suelo, que no parece sino que va derramando salud donde pasa? Pues sepa vuesa merced que lo puede agradecer, primero, a Dios, y luego, a dos fuentes que tiene en las dos piernas, por donde se desagua todo el mal humor de quien dicen los médicos que está llena. -¡Santa María! -dijo don Quijote-. Y ¿es posible que mi señora la duquesa tenga tales desaguaderos? No lo creyera si me lo dijeran frailes descalzos; pero, pues la señora doña Rodríguez lo dice, debe de ser así. Pero tales fuentes, y en tales lugares, no deben de manar humor, sino ámbar líquido. Verdaderamente que ahora acabo de creer que esto de hacerse fuentes debe de ser cosa importante para salud. Apenas acabó don Quijote de decir esta razón, cuando con un gran golpe abrieron las puertas del aposento, y del sobresalto del golpe se le cayó a doña Rodríguez la vela de la mano, y quedó la estancia como boca de lobo, como suele decirse. Luego sintió la pobre dueña que la asían de la garganta con dos manos, tan fuertemente que no la dejaban gañir, y que otra persona, con mucha presteza, sin hablar palabra, le alzaba las faldas, y con una, al parecer, chinela, le comenzó a dar tantos azotes, que era una compasión; y, aunque don Quijote se la tenía, no se meneaba del lecho, y no sabía qué podía ser aquello, y estábase quedo y callando, y aun temiendo no viniese por él la tanda y tunda azotesca. Y no fue vano su temor, porque, en dejando molida a la dueña los callados verdugos (la cual no osaba quejarse), acudieron a don Quijote, y, desenvolviéndole de la sábana y de la colcha, le pellizcaron tan a menudo y tan reciamente, que no pudo dejar de defenderse a puñadas, y todo esto en silencio admirable. Duró la batalla casi media hora; saliéronse las fantasmas, recogió doña Rodríguez sus faldas, y, gimiendo su desgracia, se salió por la puerta afuera, sin decir palabra a don Quijote, el cual, doloroso y pellizcado, confuso y pensativo, se quedó solo, donde le dejaremos deseoso de saber quién había sido el perverso encantador que tal le había puesto. Pero ello se dirá a su tiempo, que Sancho Panza nos llama, y el buen concierto de la historia lo pide. Capítulo XLIX. De lo que le sucedió a Sancho Panza rondando su ínsula Dejamos al gran gobernador enojado y mohíno con el labrador pintor y socarrón, el cual, industriado del mayordomo, y el mayordomo del duque, se burlaban de Sancho; pero él se las tenía tiesas a todos, maguera tonto, bronco y rollizo, y dijo a los que con él estaban, y al doctor Pedro Recio, que, como se acabó el secreto de la carta del duque, había vuelto a entrar en la sala: -Ahora verdaderamente que entiendo que los jueces y gobernadores deben de ser, o han de ser, de bronce, para no sentir las importunidades de los negociantes, que a todas horas y a todos tiempos quieren que los escuchen y despachen, atendiendo sólo a su negocio, venga lo que viniere; y si el pobre del juez no los escucha y despacha, o porque no puede o porque no es aquél el tiempo diputado para darles audiencia, luego les maldicen y murmuran, y les roen los huesos, y aun les deslindan los linajes. Negociante necio, negociante mentecato, no te apresures; espera sazón y coyuntura para negociar: no vengas a la hora del comer ni a la del dormir, que los jueces son de carne y de hueso y han de dar a la naturaleza lo que naturalmente les pide, si no es yo, que no le doy de comer a la mía, merced al señor doctor Pedro Recio Tirteafuera, que está delante, que quiere que muera de hambre, y afirma que esta muerte es vida, que así se la dé Dios a él y a todos los de su ralea: digo, a la de los malos médicos, que la de los buenos, palmas y lauros merecen. Todos los que conocían a Sancho Panza se admiraban, oyéndole hablar tan elegantemente, y no sabían a qué atribuirlo, sino a que los oficios y cargos graves, o adoban o entorpecen los entendimientos. Finalmente, el doctor Pedro Recio Agüero de Tirteafuera prometió de darle de cenar aquella noche, aunque excediese de todos los aforismos de Hipócrates. Con esto quedó contento el gobernador, y esperaba con grande ansia llegase la noche y la hora de cenar; y, aunque el tiempo, al parecer suyo, se estaba quedo, sin moverse de un lugar, todavía se llegó por él el tanto deseado, donde le dieron de cenar un salpicón de vaca con cebolla, y unas manos cocidas de ternera algo entrada en días. Entregóse en todo con más gusto que si le hubieran dado francolines de Milán, faisanes de Roma, ternera de Sorrento, perdices de Morón, o gansos de Lavajos; y, entre la cena, volviéndose al doctor, le dijo: -Mirad, señor doctor: de aquí adelante no os curéis de darme a comer cosas regaladas ni manjares esquisitos, porque será sacar a mi estómago de sus quicios, el cual está acostumbrado a cabra, a vaca, a tocino, a cecina, a nabos y a cebollas; y, si acaso le dan otros manjares de palacio, los recibe con melindre, y algunas veces con asco. Lo que el maestresala puede hacer es traerme estas que llaman ollas podridas, que mientras más podridas son, mejor huelen, y en ellas puede embaular y encerrar todo lo que él quisiere, como sea de comer, que yo se lo agradeceré y se lo pagaré algún día; y no se burle nadie conmigo, porque o somos o no somos: vivamos todos y comamos en buena paz compaña, pues, cuando Dios amanece, para todos amanece. Yo gobernaré esta ínsula sin perdonar derecho ni llevar cohecho, y todo el mundo traiga el ojo alerta y mire por el virote, porque les hago saber que el diablo está en Cantillana, y que, si me dan ocasión, han de ver maravillas. No, sino haceos miel, y comeros han moscas. -Por cierto, señor gobernador -dijo el maestresala-, que vuesa merced tiene mucha razón en cuanto ha dicho, y que yo ofrezco en nombre de todos los insulanos desta ínsula que han de servir a vuestra merced con toda puntualidad, amor y benevolencia, porque el suave modo de gobernar que en estos principios vuesa merced ha dado no les da lugar de hacer ni de pensar cosa que en deservicio de vuesa merced redunde. -Yo lo creo -respondió Sancho-, y serían ellos unos necios si otra cosa hiciesen o pensasen. Y vuelvo a decir que se tenga cuenta con mi sustento y con el de mi rucio, que es lo que en este negocio importa y hace más al caso; y, en siendo hora, vamos a rondar, que es mi intención limpiar esta ínsula de todo género de inmundicia y de gente vagamunda, holgazanes, y mal entretenida; porque quiero que sepáis, amigos, que la gente baldía y perezosa es en la república lo mesmo que los zánganos en las colmenas, que se comen la miel que las trabajadoras abejas hacen. Pienso favorecer a los labradores, guardar sus preeminencias a los hidalgos, premiar los virtuosos y, sobre todo, tener respeto a la religión y a la honra de los religiosos. ¿Qué os parece desto, amigos? ¿Digo algo, o quiébrome la cabeza? -Dice tanto vuesa merced, señor gobernador -dijo el mayordomo-, que estoy admirado de ver que un hombre tan sin letras como vuesa merced, que, a lo que creo, no tiene ninguna, diga tales y tantas cosas llenas de sentencias y de avisos, tan fuera de todo aquello que del ingenio de vuesa merced esperaban los que nos enviaron y los que aquí venimos. Cada día se veen cosas nuevas en el mundo: las burlas se vuelven en veras y los burladores se hallan burlados. Llegó la noche, y cenó el gobernador, con licencia del señor doctor Recio. Aderezáronse de ronda; salió con el mayordomo, secretario y maestresala, y el coronista que tenía cuidado de poner en memoria sus hechos, y alguaciles y escribanos, tantos que podían formar un mediano escuadrón. Iba Sancho en medio, con su vara, que no había más que ver, y pocas calles andadas del lugar, sintieron ruido de cuchilladas; acudieron allá, y hallaron que eran dos solos hombres los que reñían, los cuales, viendo venir a la justicia, se estuvieron quedos; y el uno dellos dijo: -¡Aquí de Dios y del rey! ¿Cómo y que se ha de sufrir que roben en poblado en este pueblo, y que salga a saltear en él en la mitad de las calles? -Sosegaos, hombre de bien -dijo Sancho-, y contadme qué es la causa desta pendencia, que yo soy el gobernador. El otro contrario dijo: -Señor gobernador, yo la diré con toda brevedad. Vuestra merced sabrá que este gentilhombre acaba de ganar ahora en esta casa de juego que está aquí frontero más de mil reales, y sabe Dios cómo; y, hallándome yo presente, juzgué más de una suerte dudosa en su favor, contra todo aquello que me dictaba la conciencia; alzóse con la ganancia, y, cuando esperaba que me había de dar algún escudo, por lo menos, de barato, como es uso y costumbre darle a los hombres principales como yo, que estamos asistentes para bien y mal pasar, y para apoyar sinrazones y evitar pendencias, él embolsó su dinero y se salió de la casa. Yo vine despechado tras él, y con buenas y corteses palabras le he pedido que me diese siquiera ocho reales, pues sabe que yo soy hombre honrado y que no tengo oficio ni beneficio, porque mis padres no me le enseñaron ni me le dejaron, y el socarrón, que no es más ladrón que Caco, ni más fullero que Andradilla, no quería darme más de cuatro reales; ¡porque vea vuestra merced, señor gobernador, qué poca vergüenza y qué poca conciencia! Pero a fee que, si vuesa merced no llegara, que yo le hiciera vomitar la ganancia, y que había de saber con cuántas entraba la romana. -¿Qué decís vos a esto? -preguntó Sancho. Y el otro respondió que era verdad cuanto su contrario decía, y no había querido darle más de cuatro reales porque se los daba muchas veces; y los que esperan barato han de ser comedidos y tomar con rostro alegre lo que les dieren, sin ponerse en cuentas con los gananciosos, si ya no supiesen de cierto que son fulleros y que lo que ganan es mal ganado; y que, para señal que él era hombre de bien y no ladrón, como decía, ninguna había mayor que el no haberle querido dar nada; que siempre los fulleros son tributarios de los mirones que los conocen. -Así es -dijo el mayordomo-. Vea vuestra merced, señor gobernador, qué es lo que se ha de hacer destos hombres. -Lo que se ha de hacer es esto -respondió Sancho-: vos, ganancioso, bueno, o malo, o indiferente, dad luego a este vuestro acuchillador cien reales, y más, habéis de desembolsar treinta para los pobres de la cárcel; y vos, que no tenéis oficio ni beneficio y andáis de nones en esta ínsula, tomad luego esos cien reales, y mañana en todo el día salid desta ínsula desterrado por diez años, so pena, si lo quebrantáredes, los cumpláis en la otra vida, colgándoos yo de una picota, o, a lo menos, el verdugo por mi mandado; y ninguno me replique, que le asentaré la mano. Desembolsó el uno, recibió el otro, éste se salió de la ínsula, y aquél se fue a su casa, y el gobernador quedó diciendo: -Ahora, yo podré poco, o quitaré estas casas de juego, que a mí se me trasluce que son muy perjudiciales. -Ésta, a lo menos -dijo un escribano-, no la podrá vuesa merced quitar, porque la tiene un gran personaje, y más es sin comparación lo que él pierde al año que lo que saca de los naipes. Contra otros garitos de menor cantía podrá vuestra merced mostrar su poder, que son los que más daño hacen y más insolencias encubren; que en las casas de los caballeros principales y de los señores no se atreven los famosos fulleros a usar de sus tretas; y, pues el vicio del juego se ha vuelto en ejercicio común, mejor es que se juegue en casas principales que no en la de algún oficial, donde cogen a un desdichado de media noche abajo y le desuellan vivo. -Agora, escribano -dijo Sancho-, yo sé que hay mucho que decir en eso. Y, en esto, llegó un corchete que traía asido a un mozo, y dijo: -Señor gobernador, este mancebo venía hacia nosotros, y, así como columbró la justicia, volvió las espaldas y comenzó a correr como un gamo, señal que debe de ser algún delincuente. Yo partí tras él, y, si no fuera porque tropezó y cayó, no le alcanzara jamás. -¿Por qué huías, hombre? -preguntó Sancho. A lo que el mozo respondió: -Señor, por escusar de responder a las muchas preguntas que las justicias hacen. -¿Qué oficio tienes? -Tejedor. -¿Y qué tejes? -Hierros de lanzas, con licencia buena de vuestra merced. -¿Graciosico me sois? ¿De chocarrero os picáis? ¡Está bien! Y ¿adónde íbades ahora? -Señor, a tomar el aire. -Y ¿adónde se toma el aire en esta ínsula? -Adonde sopla. -¡Bueno: respondéis muy a propósito! Discreto sois, mancebo; pero haced cuenta que yo soy el aire, y que os soplo en popa, y os encamino a la cárcel. ¡Asilde, hola, y llevadle, que yo haré que duerma allí sin aire esta noche! -¡Par Dios -dijo el mozo-, así me haga vuestra merced dormir en la cárcel como hacerme rey! -Pues, ¿por qué no te haré yo dormir en la cárcel? -respondió Sancho-. ¿No tengo yo poder para prenderte y soltarte cada y cuando que quisiere? -Por más poder que vuestra merced tenga -dijo el mozo-, no será bastante para hacerme dormir en la cárcel. -¿Cómo que no? -replicó Sancho-. Llevalde luego donde verá por sus ojos el desengaño, aunque más el alcaide quiera usar con él de su interesal liberalidad; que yo le pondré pena de dos mil ducados si te deja salir un paso de la cárcel. -Todo eso es cosa de risa -respondió el mozo-. El caso es que no me harán dormir en la cárcel cuantos hoy viven. -Dime, demonio -dijo Sancho-, ¿tienes algún ángel que te saque y que te quite los grillos que te pienso mandar echar? -Ahora, señor gobernador -respondió el mozo con muy buen donaire-, estemos a razón y vengamos al punto. Prosuponga vuestra merced que me manda llevar a la cárcel, y que en ella me echan grillos y cadenas, y que me meten en un calabozo, y se le ponen al alcaide graves penas si me deja salir, y que él lo cumple como se le manda; con todo esto, si yo no quiero dormir, y estarme despierto toda la noche, sin pegar pestaña, ¿será vuestra merced bastante con todo su poder para hacerme dormir, si yo no quiero? -No, por cierto -dijo el secretario-, y el hombre ha salido con su intención. -De modo -dijo Sancho- que no dejaréis de dormir por otra cosa que por vuestra voluntad, y no por contravenir a la mía. -No, señor -dijo el mozo-, ni por pienso. -Pues andad con Dios -dijo Sancho-; idos a dormir a vuestra casa, y Dios os dé buen sueño, que yo no quiero quitárosle; pero aconséjoos que de aquí adelante no os burléis con la justicia, porque toparéis con alguna que os dé con la burla en los cascos. Fuese el mozo, y el gobernador prosiguió con su ronda, y de allí a poco vinieron dos corchetes que traían a un hombre asido, y dijeron: -Señor gobernador, este que parece hombre no lo es, sino mujer, y no fea, que viene vestida en hábito de hombre. Llegáronle a los ojos dos o tres lanternas, a cuyas luces descubrieron un rostro de una mujer, al parecer, de diez y seis o pocos más años, recogidos los cabellos con una redecilla de oro y seda verde, hermosa como mil perlas. Miráronla de arriba abajo, y vieron que venía con unas medias de seda encarnada, con ligas de tafetán blanco y rapacejos de oro y aljófar; los greguescos eran verdes, de tela de oro, y una saltaembarca o ropilla de lo mesmo, suelta, debajo de la cual traía un jubón de tela finísima de oro y blanco, y los zapatos eran blancos y de hombre. No traía espada ceñida, sino una riquísima daga, y en los dedos, muchos y muy buenos anillos. Finalmente, la moza parecía bien a todos, y ninguno la conoció de cuantos la vieron, y los naturales del lugar dijeron que no podían pensar quién fuese, y los consabidores de las burlas que se habían de hacer a Sancho fueron los que más se admiraron, porque aquel suceso y hallazgo no venía ordenado por ellos; y así, estaban dudosos, esperando en qué pararía el caso. Sancho quedó pasmado de la hermosura de la moza, y preguntóle quién era, adónde iba y qué ocasión le había movido para vestirse en aquel hábito. Ella, puestos los ojos en tierra con honestísima vergüenza, respondió: -No puedo, señor, decir tan en público lo que tanto me importaba fuera secreto; una cosa quiero que se entienda: que no soy ladrón ni persona facinorosa, sino una doncella desdichada a quien la fuerza de unos celos ha hecho romper el decoro que a la honestidad se debe. Oyendo esto el mayordomo, dijo a Sancho: -Haga, señor gobernador, apartar la gente, porque esta señora con menos empacho pueda decir lo que quisiere. Mandólo así el gobernador; apartáronse todos, si no fueron el mayordomo, maestresala y el secretario. Viéndose, pues, solos, la doncella prosiguió diciendo: -«Yo, señores, soy hija de Pedro Pérez Mazorca, arrendador de las lanas deste lugar, el cual suele muchas veces ir en casa de mi padre.» -Eso no lleva camino -dijo el mayordomo-, señora, porque yo conozco muy bien a Pedro Pérez y sé que no tiene hijo ninguno, ni varón ni hembra; y más, que decís que es vuestro padre, y luego añadís que suele ir muchas veces en casa de vuestro padre. -Ya yo había dado en ello -dijo Sancho. -Ahora, señores, yo estoy turbada, y no sé lo que me digo -respondió la doncella-; pero la verdad es que yo soy hija de Diego de la Llana, que todos vuesas mercedes deben de conocer. -Aún eso lleva camino -respondió el mayordomo-, que yo conozco a Diego de la Llana, y sé que es un hidalgo principal y rico, y que tiene un hijo y una hija, y que después que enviudó no ha habido nadie en todo este lugar que pueda decir que ha visto el rostro de su hija; que la tiene tan encerrada que no da lugar al sol que la vea; y, con todo esto, la fama dice que es en estremo hermosa. -Así es la verdad -respondió la doncella-, y esa hija soy yo; si la fama miente o no en mi hermosura ya os habréis, señores, desengañado, pues me habéis visto. Y, en esto, comenzó a llorar tiernamente; viendo lo cual el secretario, se llegó al oído del maestresala y le dijo muy paso: -Sin duda alguna que a esta pobre doncella le debe de haber sucedido algo de importancia, pues en tal traje, y a tales horas, y siendo tan principal, anda fuera de su casa. -No hay dudar en eso -respondió el maestresala-; y más, que esa sospecha la confirman sus lágrimas. Sancho la consoló con las mejores razones que él supo, y le pidió que sin temor alguno les dijese lo que le había sucedido; que todos procurarían remediarlo con muchas veras y por todas las vías posibles. -«Es el caso, señores -respondió ella-, que mi padre me ha tenido encerrada diez años ha, que son los mismos que a mi madre come la tierra. En casa dicen misa en un rico oratorio, y yo en todo este tiempo no he visto que el sol del cielo de día, y la luna y las estrellas de noche, ni sé qué son calles, plazas, ni templos, ni aun hombres, fuera de mi padre y de un hermano mío, y de Pedro Pérez el arrendador, que, por entrar de ordinario en mi casa, se me antojó decir que era mi padre, por no declarar el mío. Este encerramiento y este negarme el salir de casa, siquiera a la iglesia, ha muchos días y meses que me trae muy desconsolada; quisiera yo ver el mundo, o, a lo menos, el pueblo donde nací, pareciéndome que este deseo no iba contra el buen decoro que las doncellas principales deben guardar a sí mesmas. Cuando oía decir que corrían toros y jugaban cañas, y se representaban comedias, preguntaba a mi hermano, que es un año menor que yo, que me dijese qué cosas eran aquéllas y otras muchas que yo no he visto; él me lo declaraba por los mejores modos que sabía, pero todo era encenderme más el deseo de verlo. Finalmente, por abreviar el cuento de mi perdición, digo que yo rogué y pedí a mi hermano, que nunca tal pidiera ni tal rogara...» Y tornó a renovar el llanto. El mayordomo le dijo: -Prosiga vuestra merced, señora, y acabe de decirnos lo que le ha sucedido, que nos tienen a todos suspensos sus palabras y sus lágrimas. -Pocas me quedan por decir -respondió la doncella-, aunque muchas lágrimas sí que llorar, porque los mal colocados deseos no pueden traer consigo otros descuentos que los semejantes. Habíase sentado en el alma del maestresala la belleza de la doncella, y llegó otra vez su lanterna para verla de nuevo; y parecióle que no eran lágrimas las que lloraba, sino aljófar o rocío de los prados, y aun las subía de punto y las llegaba a perlas orientales, y estaba deseando que su desgracia no fuese tanta como daban a entender los indicios de su llanto y de sus suspiros. Desesperábase el gobernador de la tardanza que tenía la moza en dilatar su historia, y díjole que acabase de tenerlos más suspensos, que era tarde y faltaba mucho que andar del pueblo. Ella, entre interrotos sollozos y mal formados suspiros, dijo: -«No es otra mi desgracia, ni mi infortunio es otro sino que yo rogué a mi hermano que me vistiese en hábitos de hombre con uno de sus vestidos y que me sacase una noche a ver todo el pueblo, cuando nuestro padre durmiese; él, importunado de mis ruegos, condecendió con mi deseo, y, poniéndome este vestido y él vestiéndose de otro mío, que le está como nacido, porque él no tiene pelo de barba y no parece sino una doncella hermosísima, esta noche, debe de haber una hora, poco más o menos, nos salimos de casa; y, guiados de nuestro mozo y desbaratado discurso, hemos rodeado todo el pueblo, y cuando queríamos volver a casa, vimos venir un gran tropel de gente, y mi hermano me dijo: ''Hermana, ésta debe de ser la ronda: aligera los pies y pon alas en ellos, y vente tras mí corriendo, porque no nos conozcan, que nos será mal contado''. Y, diciendo esto, volvió las espaldas y comenzó, no digo a correr, sino a volar; yo, a menos de seis pasos, caí, con el sobresalto, y entonces llegó el ministro de la justicia que me trujo ante vuestras mercedes, adonde, por mala y antojadiza, me veo avergonzada ante tanta gente.» -¿En efecto, señora -dijo Sancho-, no os ha sucedido otro desmán alguno, ni celos, como vos al principio de vuestro cuento dijistes, no os sacaron de vuestra casa? -No me ha sucedido nada, ni me sacaron celos, sino sólo el deseo de ver mundo, que no se estendía a más que a ver las calles de este lugar. Y acabó de confirmar ser verdad lo que la doncella decía llegar los corchetes con su hermano preso, a quien alcanzó uno dellos cuando se huyó de su hermana. No traía sino un faldellín rico y una mantellina de damasco azul con pasamanos de oro fino, la cabeza sin toca ni con otra cosa adornada que con sus mesmos cabellos, que eran sortijas de oro, según eran rubios y enrizados. Apartáronse con el gobernador, mayordomo y maestresala, y, sin que lo oyese su hermana, le preguntaron cómo venía en aquel traje, y él, con no menos vergüenza y empacho, contó lo mesmo que su hermana había contado, de que recibió gran gusto el enamorado maestresala. Pero el gobernador les dijo: -Por cierto, señores, que ésta ha sido una gran rapacería, y para contar esta necedad y atrevimiento no eran menester tantas largas, ni tantas lágrimas y suspiros; que con decir: ''Somos fulano y fulana, que nos salimos a espaciar de casa de nuestros padres con esta invención, sólo por curiosidad, sin otro designio alguno'', se acabara el cuento, y no gemidicos, y lloramicos, y darle. -Así es la verdad -respondió la doncella-, pero sepan vuesas mercedes que la turbación que he tenido ha sido tanta, que no me ha dejado guardar el término que debía. -No se ha perdido nada -respondió Sancho-. Vamos, y dejaremos a vuesas mercedes en casa de su padre; quizá no los habrá echado menos. Y, de aquí adelante, no se muestren tan niños, ni tan deseosos de ver mundo, que la doncella honrada, la pierna quebrada, y en casa; y la mujer y la gallina, por andar se pierden aína; y la que es deseosa de ver, también tiene deseo de ser vista. No digo más. El mancebo agradeció al gobernador la merced que quería hacerles de volverlos a su casa, y así, se encaminaron hacia ella, que no estaba muy lejos de allí. Llegaron, pues, y, tirando el hermano una china a una reja, al momento bajó una criada, que los estaba esperando, y les abrió la puerta, y ellos se entraron, dejando a todos admirados, así de su gentileza y hermosura como del deseo que tenían de ver mundo, de noche y sin salir del lugar; pero todo lo atribuyeron a su poca edad. Quedó el maestresala traspasado su corazón, y propuso de luego otro día pedírsela por mujer a su padre, teniendo por cierto que no se la negaría, por ser él criado del duque; y aun a Sancho le vinieron deseos y barruntos de casar al mozo con Sanchica, su hija, y determinó de ponerlo en plática a su tiempo, dándose a entender que a una hija de un gobernador ningún marido se le podía negar. Con esto, se acabó la ronda de aquella noche, y de allí a dos días el gobierno, con que se destroncaron y borraron todos sus designios, como se verá adelante. Capítulo L. Donde se declara quién fueron los encantadores y verdugos que azotaron a la dueña y pellizcaron y arañaron a don Quijote, con el suceso que tuvo el paje que llevó la carta a Teresa Sancha, mujer de Sancho Panza Dice Cide Hamete, puntualísimo escudriñador de los átomos desta verdadera historia, que al tiempo que doña Rodríguez salió de su aposento para ir a la estancia de don Quijote, otra dueña que con ella dormía lo sintió, y que, como todas las dueñas son amigas de saber, entender y oler, se fue tras ella, con tanto silencio, que la buena Rodríguez no lo echó de ver; y, así como la dueña la vio entrar en la estancia de don Quijote, porque no faltase en ella la general costumbre que todas las dueñas tienen de ser chismosas, al momento lo fue a poner en pico a su señora la duquesa, de cómo doña Rodríguez quedaba en el aposento de don Quijote. La duquesa se lo dijo al duque, y le pidió licencia para que ella y Altisidora viniesen a ver lo que aquella dueña quería con don Quijote; el duque se la dio, y las dos, con gran tiento y sosiego, paso ante paso, llegaron a ponerse junto a la puerta del aposento, y tan cerca, que oían todo lo que dentro hablaban; y, cuando oyó la duquesa que Rodríguez había echado en la calle el Aranjuez de sus fuentes, no lo pudo sufrir, ni menos Altisidora; y así, llenas de cólera y deseosas de venganza, entraron de golpe en el aposento, y acrebillaron a don Quijote y vapularon a la dueña del modo que queda contado; porque las afrentas que van derechas contra la hermosura y presunción de las mujeres, despierta en ellas en gran manera la ira y enciende el deseo de vengarse. Contó la duquesa al duque lo que le había pasado, de lo que se holgó mucho, y la duquesa, prosiguiendo con su intención de burlarse y recibir pasatiempo con don Quijote, despachó al paje que había hecho la figura de Dulcinea en el concierto de su desencanto -que tenía bien olvidado Sancho Panza con la ocupación de su gobierno- a Teresa Panza, su mujer, con la carta de su marido, y con otra suya, y con una gran sarta de corales ricos presentados. Dice, pues, la historia, que el paje era muy discreto y agudo, y, con deseo de servir a sus señores, partió de muy buena gana al lugar de Sancho; y, antes de entrar en él, vio en un arroyo estar lavando cantidad de mujeres, a quien preguntó si le sabrían decir si en aquel lugar vivía una mujer llamada Teresa Panza, mujer de un cierto Sancho Panza, escudero de un caballero llamado don Quijote de la Mancha, a cuya pregunta se levantó en pie una mozuela que estaba lavando, y dijo: -Esa Teresa Panza es mi madre, y ese tal Sancho, mi señor padre, y el tal caballero, nuestro amo. -Pues venid, doncella -dijo el paje-, y mostradme a vuestra madre, porque le traigo una carta y un presente del tal vuestro padre. -Eso haré yo de muy buena gana, señor mío -respondió la moza, que mostraba ser de edad de catorce años, poco más a menos. Y, dejando la ropa que lavaba a otra compañera, sin tocarse ni calzarse, que estaba en piernas y desgreñada, saltó delante de la cabalgadura del paje, y dijo: -Venga vuesa merced, que a la entrada del pueblo está nuestra casa, y mi madre en ella, con harta pena por no haber sabido muchos días ha de mi señor padre. -Pues yo se las llevo tan buenas -dijo el paje- que tiene que dar bien gracias a Dios por ellas. Finalmente, saltando, corriendo y brincando, llegó al pueblo la muchacha, y, antes de entrar en su casa, dijo a voces desde la puerta: -Salga, madre Teresa, salga, salga, que viene aquí un señor que trae cartas y otras cosas de mi buen padre. A cuyas voces salió Teresa Panza, su madre, hilando un copo de estopa, con una saya parda. Parecía, según era de corta, que se la habían cortado por vergonzoso lugar, con un corpezuelo asimismo pardo y una camisa de pechos. No era muy vieja, aunque mostraba pasar de los cuarenta, pero fuerte, tiesa, nervuda y avellanada; la cual, viendo a su hija, y al paje a caballo, le dijo: -¿Qué es esto, niña? ¿Qué señor es éste? -Es un servidor de mi señora doña Teresa Panza -respondió el paje. Y, diciendo y haciendo, se arrojó del caballo y se fue con mucha humildad a poner de hinojos ante la señora Teresa, diciendo: -Déme vuestra merced sus manos, mi señora doña Teresa, bien así como mujer legítima y particular del señor don Sancho Panza, gobernador propio de la ínsula Barataria. -¡Ay, señor mío, quítese de ahí; no haga eso -respondió Teresa-, que yo no soy nada palaciega, sino una pobre labradora, hija de un estripaterrones y mujer de un escudero andante, y no de gobernador alguno! -Vuesa merced -respondió el paje- es mujer dignísima de un gobernador archidignísimo; y, para prueba desta verdad, reciba vuesa merced esta carta y este presente. Y sacó al instante de la faldriquera una sarta de corales con estremos de oro, y se la echó al cuello y dijo: -Esta carta es del señor gobernador, y otra que traigo y estos corales son de mi señora la duquesa, que a vuestra merced me envía. Quedó pasmada Teresa, y su hija ni más ni menos, y la muchacha dijo: -Que me maten si no anda por aquí nuestro señor amo don Quijote, que debe de haber dado a padre el gobierno o condado que tantas veces le había prometido. -Así es la verdad -respondió el paje-: que, por respeto del señor don Quijote, es ahora el señor Sancho gobernador de la ínsula Barataria, como se verá por esta carta. -Léamela vuesa merced, señor gentilhombre -dijo Teresa-, porque, aunque yo sé hilar, no sé leer migaja. -Ni yo tampoco -añadió Sanchica-; pero espérenme aquí, que yo iré a llamar quien la lea, ora sea el cura mesmo, o el bachiller Sansón Carrasco, que vendrán de muy buena gana, por saber nuevas de mi padre. -No hay para qué se llame a nadie, que yo no sé hilar, pero sé leer, y la leeré. Y así, se la leyó toda, que, por quedar ya referida, no se pone aquí; y luego sacó otra de la duquesa, que decía desta manera: Amiga Teresa: Las buenas partes de la bondad y del ingenio de vuestro marido Sancho me movieron y obligaron a pedir a mi marido el duque le diese un gobierno de una ínsula, de muchas que tiene. Tengo noticia que gobierna como un girifalte, de lo que yo estoy muy contenta, y el duque mi señor, por el consiguiente; por lo que doy muchas gracias al cielo de no haberme engañado en haberle escogido para el tal gobierno; porque quiero que sepa la señora Teresa que con dificultad se halla un buen gobernador en el mundo, y tal me haga a mí Dios como Sancho gobierna. Ahí le envío, querida mía, una sarta de corales con estremos de oro; yo me holgara que fuera de perlas orientales, pero quien te da el hueso, no te querría ver muerta: tiempo vendrá en que nos conozcamos y nos comuniquemos, y Dios sabe lo que será. Encomiéndeme a Sanchica, su hija, y dígale de mi parte que se apareje, que la tengo de casar altamente cuando menos lo piense. Dícenme que en ese lugar hay bellotas gordas: envíeme hasta dos docenas, que las estimaré en mucho, por ser de su mano, y escríbame largo, avisándome de su salud y de su bienestar; y si hubiere menester alguna cosa, no tiene que hacer más que boquear: que su boca será medida, y Dios me la guarde. Deste lugar. Su amiga, que bien la quiere, La Duquesa. -¡Ay -dijo Teresa en oyendo la carta-, y qué buena y qué llana y qué humilde señora! Con estas tales señoras me entierren a mí, y no las hidalgas que en este pueblo se usan, que piensan que por ser hidalgas no las ha de tocar el viento, y van a la iglesia con tanta fantasía como si fuesen las mesmas reinas, que no parece sino que tienen a deshonra el mirar a una labradora; y veis aquí donde esta buena señora, con ser duquesa, me llama amiga, y me trata como si fuera su igual, que igual la vea yo con el más alto campanario que hay en la Mancha. Y, en lo que toca a las bellotas, señor mío, yo le enviaré a su señoría un celemín, que por gordas las pueden venir a ver a la mira y a la maravilla. Y por ahora, Sanchica, atiende a que se regale este señor: pon en orden este caballo, y saca de la caballeriza güevos, y corta tocino adunia, y démosle de comer como a un príncipe, que las buenas nuevas que nos ha traído y la buena cara que él tiene lo merece todo; y, en tanto, saldré yo a dar a mis vecinas las nuevas de nuestro contento, y al padre cura y a maese Nicolás el barbero, que tan amigos son y han sido de tu padre. -Sí haré, madre -respondió Sanchica-; pero mire que me ha de dar la mitad desa sarta; que no tengo yo por tan boba a mi señora la duquesa, que se la había de enviar a ella toda. -Todo es para ti, hija -respondió Teresa-, pero déjamela traer algunos días al cuello, que verdaderamente parece que me alegra el corazón. -También se alegrarán -dijo el paje- cuando vean el lío que viene en este portamanteo, que es un vestido de paño finísimo que el gobernador sólo un día llevó a caza, el cual todo le envía para la señora Sanchica. -Que me viva él mil años -respondió Sanchica-, y el que lo trae, ni más ni menos, y aun dos mil, si fuere necesidad. Salióse en esto Teresa fuera de casa, con las cartas, y con la sarta al cuello, y iba tañendo en las cartas como si fuera en un pandero; y, encontrándose acaso con el cura y Sansón Carrasco, comenzó a bailar y a decir: -¡A fee que agora que no hay pariente pobre! ¡Gobiernito tenemos! ¡No, sino tómese conmigo la más pintada hidalga, que yo la pondré como nueva! -¿Qué es esto, Teresa Panza? ¿Qué locuras son éstas, y qué papeles son ésos? -No es otra la locura sino que éstas son cartas de duquesas y de gobernadores, y estos que traigo al cuello son corales finos; las avemarías y los padres nuestros son de oro de martillo, y yo soy gobernadora. -De Dios en ayuso, no os entendemos, Teresa, ni sabemos lo que os decís. -Ahí lo podrán ver ellos -respondió Teresa. Y dioles las cartas. Leyólas el cura de modo que las oyó Sansón Carrasco, y Sansón y el cura se miraron el uno al otro, como admirados de lo que habían leído; y preguntó el bachiller quién había traído aquellas cartas. Respondió Teresa que se viniesen con ella a su casa y verían el mensajero, que era un mancebo como un pino de oro, y que le traía otro presente que valía más de tanto. Quitóle el cura los corales del cuello, y mirólos y remirólos, y, certificándose que eran finos, tornó a admirarse de nuevo, y dijo: -Por el hábito que tengo, que no sé qué me diga ni qué me piense de estas cartas y destos presentes: por una parte, veo y toco la fineza de estos corales, y por otra, leo que una duquesa envía a pedir dos docenas de bellotas. -¡Aderézame esas medidas! -dijo entonces Carrasco-. Agora bien, vamos a ver al portador deste pliego, que dél nos informaremos de las dificultades que se nos ofrecen. Hiciéronlo así, y volvióse Teresa con ellos. Hallaron al paje cribando un poco de cebada para su cabalgadura, y a Sanchica cortando un torrezno para empedrarle con güevos y dar de comer al paje, cuya presencia y buen adorno contentó mucho a los dos; y, después de haberle saludado cortésmente, y él a ellos, le preguntó Sansón les dijese nuevas así de don Quijote como de Sancho Panza; que, puesto que habían leído las cartas de Sancho y de la señora duquesa, todavía estaban confusos y no acababan de atinar qué sería aquello del gobierno de Sancho, y más de una ínsula, siendo todas o las más que hay en el mar Mediterráneo de Su Majestad. A lo que el paje respondió: -De que el señor Sancho Panza sea gobernador, no hay que dudar en ello; de que sea ínsula o no la que gobierna, en eso no me entremeto, pero basta que sea un lugar de más de mil vecinos; y, en cuanto a lo de las bellotas, digo que mi señora la duquesa es tan llana y tan humilde, que no -decía él- enviar a pedir bellotas a una labradora, pero que le acontecía enviar a pedir un peine prestado a una vecina suya. Porque quiero que sepan vuestras mercedes que las señoras de Aragón, aunque son tan principales, no son tan puntuosas y levantadas como las señoras castellanas; con más llaneza tratan con las gentes. Estando en la mitad destas pláticas, saltó Sanchica con un halda de güevos, y preguntó al paje: -Dígame, señor: ¿mi señor padre trae por ventura calzas atacadas después que es gobernador? -No he mirado en ello -respondió el paje-, pero sí debe de traer. -¡Ay Dios mío -replicó Sanchica-, y que será de ver a mi padre con pedorreras! ¿No es bueno sino que desde que nací tengo deseo de ver a mi padre con calzas atacadas? -Como con esas cosas le verá vuestra merced si vive -respondió el paje-. Par Dios, términos lleva de caminar con papahígo, con solos dos meses que le dure el gobierno. Bien echaron de ver el cura y el bachiller que el paje hablaba socarronamente, pero la fineza de los corales y el vestido de caza que Sancho enviaba lo deshacía todo; que ya Teresa les había mostrado el vestido. Y no dejaron de reírse del deseo de Sanchica, y más cuando Teresa dijo: -Señor cura, eche cata por ahí si hay alguien que vaya a Madrid, o a Toledo, para que me compre un verdugado redondo, hecho y derecho, y sea al uso y de los mejores que hubiere; que en verdad en verdad que tengo de honrar el gobierno de mi marido en cuanto yo pudiere, y aun que si me enojo, me tengo de ir a esa corte, y echar un coche, como todas; que la que tiene marido gobernador muy bien le puede traer y sustentar. -Y ¡cómo, madre! -dijo Sanchica-. Pluguiese a Dios que fuese antes hoy que mañana, aunque dijesen los que me viesen ir sentada con mi señora madre en aquel coche: ''¡Mirad la tal por cual, hija del harto de ajos, y cómo va sentada y tendida en el coche, como si fuera una papesa!'' Pero pisen ellos los lodos, y ándeme yo en mi coche, levantados los pies del suelo. ¡Mal año y mal mes para cuantos murmuradores hay en el mundo, y ándeme yo caliente, y ríase la gente! ¿Digo bien, madre mía? -Y ¡cómo que dices bien, hija! -respondió Teresa-. Y todas estas venturas, y aun mayores, me las tiene profetizadas mi buen Sancho, y verás tú, hija, cómo no para hasta hacerme condesa: que todo es comenzar a ser venturosas; y, como yo he oído decir muchas veces a tu buen padre, que así como lo es tuyo lo es de los refranes, cuando te dieren la vaquilla, corre con soguilla: cuando te dieren un gobierno, cógele; cuando te dieren un condado, agárrale, y cuando te hicieren tus, tus, con alguna buena dádiva, envásala. ¡No, sino dormíos, y no respondáis a las venturas y buenas dichas que están llamando a la puerta de vuestra casa! -Y ¿qué se me da a mí -añadió Sanchica- que diga el que quisiere cuando me vea entonada y fantasiosa: "Viose el perro en bragas de cerro...", y lo demás? Oyendo lo cual el cura, dijo: -Yo no puedo creer sino que todos los deste linaje de los Panzas nacieron cada uno con un costal de refranes en el cuerpo: ninguno dellos he visto que no los derrame a todas horas y en todas las pláticas que tienen. -Así es la verdad -dijo el paje-, que el señor gobernador Sancho a cada paso los dice, y, aunque muchos no vienen a propósito, todavía dan gusto, y mi señora la duquesa y el duque los celebran mucho. -¿Que todavía se afirma vuestra merced, señor mío -dijo el bachiller-, ser verdad esto del gobierno de Sancho, y de que hay duquesa en el mundo que le envíe presentes y le escriba? Porque nosotros, aunque tocamos los presentes y hemos leído las cartas, no lo creemos, y pensamos que ésta es una de las cosas de don Quijote, nuestro compatrioto, que todas piensa que son hechas por encantamento; y así, estoy por decir que quiero tocar y palpar a vuestra merced, por ver si es embajador fantástico o hombre de carne y hueso. -Señores, yo no sé más de mí -respondió el paje- sino que soy embajador verdadero, y que el señor Sancho Panza es gobernador efectivo, y que mis señores duque y duquesa pueden dar, y han dado, el tal gobierno; y que he oído decir que en él se porta valentísimamente el tal Sancho Panza; si en esto hay encantamento o no, vuestras mercedes lo disputen allá entre ellos, que yo no sé otra cosa, para el juramento que hago, que es por vida de mis padres, que los tengo vivos y los amo y los quiero mucho. -Bien podrá ello ser así -replicó el bachiller-, pero dubitat Augustinus. -Dude quien dudare -respondió el paje-, la verdad es la que he dicho, y esta que ha de andar siempre sobre la mentira,como el aceite sobre el agua; y si no, operibus credite, et non verbis: véngase alguno de vuesas mercedes conmigo, y verán con los ojos lo que no creen por los oídos. -Esa ida a mí toca -dijo Sanchica-: lléveme vuestra merced, señor, a las ancas de su rocín, que yo iré de muy buena gana a ver a mi señor padre. -Las hijas de los gobernadores no han de ir solas por los caminos, sino acompañadas de carrozas y literas y de gran número de sirvientes. -Par Dios -respondió Sancha-, tan bién me vaya yo sobre una pollina como sobre un coche. ¡Hallado la habéis la melindrosa! -Calla, mochacha -dijo Teresa-, que no sabes lo que te dices, y este señor está en lo cierto: que tal el tiempo, tal el tiento; cuando Sancho, Sancha, y cuando gobernador, señora, y no sé si diga algo. -Más dice la señora Teresa de lo que piensa -dijo el paje-; y denme de comer y despáchenme luego, porque pienso volverme esta tarde. A lo que dijo el cura: -Vuestra merced se vendrá a hacer penitencia conmigo, que la señora Teresa más tiene voluntad que alhajas para servir a tan buen huésped. Rehusólo el paje; pero, en efecto, lo hubo de conceder por su mejora, y el cura le llevó consigo de buena gana, por tener lugar de preguntarle de espacio por don Quijote y sus hazañas. El bachiller se ofreció de escribir las cartas a Teresa de la respuesta, pero ella no quiso que el bachiller se metiese en sus cosas, que le tenía por algo burlón; y así, dio un bollo y dos huevos a un monacillo que sabía escribir, el cual le escribió dos cartas, una para su marido y otra para la duquesa, notadas de su mismo caletre, que no son las peores que en esta grande historia se ponen, como se verá adelante. Capítulo LI. Del progreso del gobierno de Sancho Panza, con otros sucesos tales como buenos Amaneció el día que se siguió a la noche de la ronda del gobernador, la cual el maestresala pasó sin dormir, ocupado el pensamiento en el rostro, brío y belleza de la disfrazada doncella; y el mayordomo ocupó lo que della faltaba en escribir a sus señores lo que Sancho Panza hacía y decía, tan admirado de sus hechos como de sus dichos: porque andaban mezcladas sus palabras y sus acciones, con asomos discretos y tontos. Levantóse, en fin, el señor gobernador, y, por orden del doctor Pedro Recio, le hicieron desayunar con un poco de conserva y cuatro tragos de agua fría, cosa que la trocara Sancho con un pedazo de pan y un racimo de uvas; pero, viendo que aquello era más fuerza que voluntad, pasó por ello, con harto dolor de su alma y fatiga de su estómago, haciéndole creer Pedro Recio que los manjares pocos y delicados avivaban el ingenio, que era lo que más convenía a las personas constituidas en mandos y en oficios graves, donde se han de aprovechar no tanto de las fuerzas corporales como de las del entendimiento. Con esta sofistería padecía hambre Sancho, y tal, que en su secreto maldecía el gobierno y aun a quien se le había dado; pero, con su hambre y con su conserva, se puso a juzgar aquel día, y lo primero que se le ofreció fue una pregunta que un forastero le hizo, estando presentes a todo el mayordomo y los demás acólitos, que fue: -Señor, un caudaloso río dividía dos términos de un mismo señorío (y esté vuestra merced atento, porque el caso es de importancia y algo dificultoso). Digo, pues, que sobre este río estaba una puente, y al cabo della, una horca y una como casa de audiencia, en la cual de ordinario había cuatro jueces que juzgaban la ley que puso el dueño del río, de la puente y del señorío, que era en esta forma: "Si alguno pasare por esta puente de una parte a otra, ha de jurar primero adónde y a qué va; y si jurare verdad, déjenle pasar; y si dijere mentira, muera por ello ahorcado en la horca que allí se muestra, sin remisión alguna". Sabida esta ley y la rigurosa condición della, pasaban muchos, y luego en lo que juraban se echaba de ver que decían verdad, y los jueces los dejaban pasar libremente. Sucedió, pues, que, tomando juramento a un hombre, juró y dijo que para el juramento que hacía, que iba a morir en aquella horca que allí estaba, y no a otra cosa. Repararon los jueces en el juramento y dijeron: ''Si a este hombre le dejamos pasar libremente, mintió en su juramento, y, conforme a la ley, debe morir; y si le ahorcamos, él juró que iba a morir en aquella horca, y, habiendo jurado verdad, por la misma ley debe ser libre''. Pídese a vuesa merced, señor gobernador, qué harán los jueces del tal hombre; que aun hasta agora están dudosos y suspensos. Y, habiendo tenido noticia del agudo y elevado entendimiento de vuestra merced, me enviaron a mí a que suplicase a vuestra merced de su parte diese su parecer en tan intricado y dudoso caso. A lo que respondió Sancho: -Por cierto que esos señores jueces que a mí os envían lo pudieran haber escusado, porque yo soy un hombre que tengo más de mostrenco que de agudo; pero, con todo eso, repetidme otra vez el negocio de modo que yo le entienda: quizá podría ser que diese en el hito. Volvió otra y otra vez el preguntante a referir lo que primero había dicho, y Sancho dijo: -A mi parecer, este negocio en dos paletas le declararé yo, y es así: el tal hombre jura que va a morir en la horca, y si muere en ella, juró verdad, y por la ley puesta merece ser libre y que pase la puente; y si no le ahorcan, juró mentira, y por la misma ley merece que le ahorquen. -Así es como el señor gobernador dice -dijo el mensajero-; y cuanto a la entereza y entendimiento del caso, no hay más que pedir ni que dudar. -Digo yo, pues, agora -replicó Sancho- que deste hombre aquella parte que juró verdad la dejen pasar, y la que dijo mentira la ahorquen, y desta manera se cumplirá al pie de la letra la condición del pasaje. -Pues, señor gobernador -replicó el preguntador-, será necesario que el tal hombre se divida en partes, en mentirosa y verdadera; y si se divide, por fuerza ha de morir, y así no se consigue cosa alguna de lo que la ley pide, y es de necesidad espresa que se cumpla con ella. -Venid acá, señor buen hombre -respondió Sancho-; este pasajero que decís, o yo soy un porro, o él tiene la misma razón para morir que para vivir y pasar la puente; porque si la verdad le salva, la mentira le condena igualmente; y, siendo esto así, como lo es, soy de parecer que digáis a esos señores que a mí os enviaron que, pues están en un fil las razones de condenarle o asolverle, que le dejen pasar libremente, pues siempre es alabado más el hacer bien que mal, y esto lo diera firmado de mi nombre, si supiera firmar; y yo en este caso no he hablado de mío, sino que se me vino a la memoria un precepto, entre otros muchos que me dio mi amo don Quijote la noche antes que viniese a ser gobernador desta ínsula: que fue que, cuando la justicia estuviese en duda, me decantase y acogiese a la misericordia; y ha querido Dios que agora se me acordase, por venir en este caso como de molde. Así es -respondió el mayordomo-, y tengo para mí que el mismo Licurgo, que dio leyes a los lacedemonios, no pudiera dar mejor sentencia que la que el gran Panza ha dado. Y acábese con esto la audiencia desta mañana, y yo daré orden como el señor gobernador coma muy a su gusto. -Eso pido, y barras derechas -dijo Sancho-: denme de comer, y lluevan casos y dudas sobre mí, que yo las despabilaré en el aire. Cumplió su palabra el mayordomo, pareciéndole ser cargo de conciencia matar de hambre a tan discreto gobernador; y más, que pensaba concluir con él aquella misma noche haciéndole la burla última que traía en comisión de hacerle. Sucedió, pues, que, habiendo comido aquel día contra las reglas y aforismos del doctor Tirteafuera, al levantar de los manteles, entró un correo con una carta de don Quijote para el gobernador. Mandó Sancho al secretario que la leyese para sí, y que si no viniese en ella alguna cosa digna de secreto, la leyese en voz alta. Hízolo así el secretario, y, repasándola primero, dijo: -Bien se puede leer en voz alta, que lo que el señor don Quijote escribe a vuestra merced merece estar estampado y escrito con letras de oro, y dice así: Carta de don Quijote de la Mancha a Sancho Panza, gobernador de la ínsula Barataria Cuando esperaba oír nuevas de tus descuidos e impertinencias, Sancho amigo, las oí de tus discreciones, de que di por ello gracias particulares al cielo, el cual del estiércol sabe levantar los pobres, y de los tontos hacer discretos. Dícenme que gobiernas como si fueses hombre, y que eres hombre como si fueses bestia, según es la humildad con que te tratas; y quiero que adviertas, Sancho, que muchas veces conviene y es necesario, por la autoridad del oficio, ir contra la humildad del corazón; porque el buen adorno de la persona que está puesta en graves cargos ha de ser conforme a lo que ellos piden, y no a la medida de lo que su humilde condición le inclina. Vístete bien, que un palo compuesto no parece palo. No digo que traigas dijes ni galas, ni que siendo juez te vistas como soldado, sino que te adornes con el hábito que tu oficio requiere, con tal que sea limpio y bien compuesto. Para ganar la voluntad del pueblo que gobiernas, entre otras has de hacer dos cosas: la una, ser bien criado con todos, aunque esto ya otra vez te lo he dicho; y la otra, procurar la abundancia de los mantenimientos; que no hay cosa que más fatigue el corazón de los pobres que la hambre y la carestía. No hagas muchas pragmáticas; y si las hicieres, procura que sean buenas, y, sobre todo, que se guarden y cumplan; que las pragmáticas que no se guardan, lo mismo es que si no lo fuesen; antes dan a entender que el príncipe que tuvo discreción y autoridad para hacerlas, no tuvo valor para hacer que se guardasen; y las leyes que atemorizan y no se ejecutan, vienen a ser como la viga, rey de las ranas: que al principio las espantó, y con el tiempo la menospreciaron y se subieron sobre ella. Sé padre de las virtudes y padrastro de los vicios. No seas siempre riguroso, ni siempre blando, y escoge el medio entre estos dos estremos, que en esto está el punto de la discreción. Visita las cárceles, las carnicerías y las plazas, que la presencia del gobernador en lugares tales es de mucha importancia: consuela a los presos, que esperan la brevedad de su despacho; es coco a los carniceros, que por entonces igualan los pesos, y es espantajo a las placeras, por la misma razón. No te muestres, aunque por ventura lo seas -lo cual yo no creo-, codicioso, mujeriego ni glotón; porque, en sabiendo el pueblo y los que te tratan tu inclinación determinada, por allí te darán batería, hasta derribarte en el profundo de la perdición. Mira y remira, pasa y repasa los consejos y documentos que te di por escrito antes que de aquí partieses a tu gobierno, y verás como hallas en ellos, si los guardas, una ayuda de costa que te sobrelleve los trabajos y dificultades que a cada paso a los gobernadores se les ofrecen. Escribe a tus señores y muéstrateles agradecido, que la ingratitud es hija de la soberbia, y uno de los mayores pecados que se sabe, y la persona que es agradecida a los que bien le han hecho, da indicio que también lo será a Dios, que tantos bienes le hizo y de contino le hace. La señora duquesa despachó un propio con tu vestido y otro presente a tu mujer Teresa Panza; por momentos esperamos respuesta. Yo he estado un poco mal dispuesto de un cierto gateamiento que me sucedió no muy a cuento de mis narices; pero no fue nada, que si hay encantadores que me maltraten, también los hay que me defiendan. Avísame si el mayordomo que está contigo tuvo que ver en las acciones de la Trifaldi, como tú sospechaste, y de todo lo que te sucediere me irás dando aviso, pues es tan corto el camino; cuanto más, que yo pienso dejar presto esta vida ociosa en que estoy, pues no nací para ella. Un negocio se me ha ofrecido, que creo que me ha de poner en desgracia destos señores; pero, aunque se me da mucho, no se me da nada, pues, en fin en fin, tengo de cumplir antes con mi profesión que con su gusto, conforme a lo que suele decirse: amicus Plato, sed magis amica veritas. Dígote este latín porque me doy a entender que, después que eres gobernador, lo habrás aprendido. Y a Dios, el cual te guarde de que ninguno te tenga lástima. Tu amigo, Don Quijote de la Mancha. Oyó Sancho la carta con mucha atención, y fue celebrada y tenida por discreta de los que la oyeron; y luego Sancho se levantó de la mesa, y, llamando al secretario, se encerró con él en su estancia, y, sin dilatarlo más, quiso responder luego a su señor don Quijote, y dijo al secretario que, sin añadir ni quitar cosa alguna, fuese escribiendo lo que él le dijese, y así lo hizo; y la carta de la respuesta fue del tenor siguiente: Carta de Sancho Panza a don Quijote de la Mancha La ocupación de mis negocios es tan grande que no tengo lugar para rascarme la cabeza, ni aun para cortarme las uñas; y así, las traigo tan crecidas cual Dios lo remedie. Digo esto, señor mío de mi alma, porque vuesa merced no se espante si hasta agora no he dado aviso de mi bien o mal estar en este gobierno, en el cual tengo más hambre que cuando andábamos los dos por las selvas y por los despoblados. Escribióme el duque, mi señor, el otro día, dándome aviso que habían entrado en esta ínsula ciertas espías para matarme, y hasta agora yo no he descubierto otra que un cierto doctor que está en este lugar asalariado para matar a cuantos gobernadores aquí vinieren: llámase el doctor Pedro Recio, y es natural de Tirteafuera: ¡porque vea vuesa merced qué nombre para no temer que he de morir a sus manos! Este tal doctor dice él mismo de sí mismo que él no cura las enfermedades cuando las hay, sino que las previene, para que no vengan; y las medecinas que usa son dieta y más dieta, hasta poner la persona en los huesos mondos, como si no fuese mayor mal la flaqueza que la calentura. Finalmente, él me va matando de hambre, y yo me voy muriendo de despecho, pues cuando pensé venir a este gobierno a comer caliente y a beber frío, y a recrear el cuerpo entre sábanas de holanda, sobre colchones de pluma, he venido a hacer penitencia, como si fuera ermitaño; y, como no la hago de mi voluntad, pienso que, al cabo al cabo, me ha de llevar el diablo. Hasta agora no he tocado derecho ni llevado cohecho, y no puedo pensar en qué va esto; porque aquí me han dicho que los gobernadores que a esta ínsula suelen venir, antes de entrar en ella, o les han dado o les han prestado los del pueblo muchos dineros, y que ésta es ordinaria usanza en los demás que van a gobiernos, no solamente en éste. Anoche, andando de ronda, topé una muy hermosa doncella en traje de varón y un hermano suyo en hábito de mujer; de la moza se enamoró mi maestresala, y la escogió en su imaginación para su mujer, según él ha dicho, y yo escogí al mozo para mi yerno; hoy los dos pondremos en plática nuestros pensamientos con el padre de entrambos, que es un tal Diego de la Llana, hidalgo y cristiano viejo cuanto se quiere. Yo visito las plazas, como vuestra merced me lo aconseja, y ayer hallé una tendera que vendía avellanas nuevas, y averigüéle que había mezclado con una hanega de avellanas nuevas otra de viejas, vanas y podridas; apliquélas todas para los niños de la doctrina, que las sabrían bien distinguir, y sentenciéla que por quince días no entrase en la plaza. Hanme dicho que lo hice valerosamente; lo que sé decir a vuestra merced es que es fama en este pueblo que no hay gente más mala que las placeras, porque todas son desvergonzadas, desalmadas y atrevidas, y yo así lo creo, por las que he visto en otros pueblos. De que mi señora la duquesa haya escrito a mi mujer Teresa Panza y enviádole el presente que vuestra merced dice, estoy muy satisfecho, y procuraré de mostrarme agradecido a su tiempo: bésele vuestra merced las manos de mi parte, diciendo que digo yo que no lo ha echado en saco roto, como lo verá por la obra. No querría que vuestra merced tuviese trabacuentas de disgusto con esos mis señores, porque si vuestra merced se enoja con ellos, claro está que ha de redundar en mi daño, y no será bien que, pues se me da a mí por consejo que sea agradecido, que vuestra merced no lo sea con quien tantas mercedes le tiene hechas y con tanto regalo ha sido tratado en su castillo. Aquello del gateado no entiendo, pero imagino que debe de ser alguna de las malas fechorías que con vuestra merced suelen usar los malos encantadores; yo lo sabré cuando nos veamos. Quisiera enviarle a vuestra merced alguna cosa, pero no sé qué envíe, si no es algunos cañutos de jeringas, que para con vejigas los hacen en esta ínsula muy curiosos; aunque si me dura el oficio, yo buscaré qué enviar de haldas o de mangas. Si me escribiere mi mujer Teresa Panza, pague vuestra merced el porte y envíeme la carta,que tengo grandísimo deseo de saber del estado de mi casa, de mi mujer y de mis hijos. Y con esto, Dios libre a vuestra merced de mal intencionados encantadores, y a mí me saque con bien y en paz deste gobierno, que lo dudo, porque le pienso dejar con la vida, según me trata el doctor Pedro Recio. Criado de vuestra merced, Sancho Panza, el Gobernador. Cerró la carta el secretario y despachó luego al correo; y, juntándose los burladores de Sancho, dieron orden entre sí cómo despacharle del gobierno; y aquella tarde la pasó Sancho en hacer algunas ordenanzas tocantes al buen gobierno de la que él imaginaba ser ínsula, y ordenó que no hubiese regatones de los bastimentos en la república, y que pudiesen meter en ella vino de las partes que quisiesen, con aditamento que declarasen el lugar de donde era, para ponerle el precio según su estimación, bondad y fama, y el que lo aguase o le mudase el nombre, perdiese la vida por ello. Moderó el precio de todo calzado, principalmente el de los zapatos, por parecerle que corría con exorbitancia; puso tasa en los salarios de los criados, que caminaban a rienda suelta por el camino del interese; puso gravísimas penas a los que cantasen cantares lascivos y descompuestos, ni de noche ni de día. Ordenó que ningún ciego cantase milagro en coplas si no trujese testimonio auténtico de ser verdadero, por parecerle que los más que los ciegos cantan son fingidos, en perjuicio de los verdaderos. Hizo y creó un alguacil de pobres, no para que los persiguiese, sino para que los examinase si lo eran, porque a la sombra de la manquedad fingida y de la llaga falsa andan los brazos ladrones y la salud borracha. En resolución: él ordenó cosas tan buenas que hasta hoy se guardan en aquel lugar, y se nombran Las constituciones del gran gobernador Sancho Panza. Capítulo LII. Donde se cuenta la aventura de la segunda dueña Dolorida, o Angustiada, llamada por otro nombre doña Rodríguez Cuenta Cide Hamete que estando ya don Quijote sano de sus aruños, le pareció que la vida que en aquel castillo tenía era contra toda la orden de caballería que profesaba, y así, determinó de pedir licencia a los duques para partirse a Zaragoza, cuyas fiestas llegaban cerca, adonde pensaba ganar el arnés que en las tales fiestas se conquista. Y, estando un día a la mesa con los duques, y comenzando a poner en obra su intención y pedir la licencia, veis aquí a deshora entrar por la puerta de la gran sala dos mujeres, como después pareció, cubiertas de luto de los pies a la cabeza, y la una dellas, llegándose a don Quijote, se le echó a los pies tendida de largo a largo, la boca cosida con los pies de don Quijote, y daba unos gemidos tan tristes, tan profundos y tan dolorosos, que puso en confusión a todos los que la oían y miraban; y, aunque los duques pensaron que sería alguna burla que sus criados querían hacer a don Quijote, todavía, viendo con el ahínco que la mujer suspiraba, gemía y lloraba, los tuvo dudosos y suspensos, hasta que don Quijote, compasivo, la levantó del suelo y hizo que se descubriese y quitase el manto de sobre la faz llorosa. Ella lo hizo así, y mostró ser lo que jamás se pudiera pensar, porque descubrió el rostro de doña Rodríguez, la dueña de casa, y la otra enlutada era su hija, la burlada del hijo del labrador rico. Admiráronse todos aquellos que la conocían, y más los duques que ninguno; que, puesto que la tenían por boba y de buena pasta, no por tanto que viniese a hacer locuras. Finalmente, doña Rodríguez, volviéndose a los señores, les dijo: -Vuesas excelencias sean servidos de darme licencia que yo departa un poco con este caballero, porque así conviene para salir con bien del negocio en que me ha puesto el atrevimiento de un mal intencionado villano. El duque dijo que él se la daba, y que departiese con el señor don Quijote cuanto le viniese en deseo. Ella, enderezando la voz y el rostro a don Quijote, dijo: -Días ha, valeroso caballero, que os tengo dada cuenta de la sinrazón y alevosía que un mal labrador tiene fecha a mi muy querida y amada fija, que es esta desdichada que aquí está presente, y vos me habedes prometido de volver por ella, enderezándole el tuerto que le tienen fecho, y agora ha llegado a mi noticia que os queredes partir deste castillo, en busca de las buenas venturas que Dios os depare; y así, querría que, antes que os escurriésedes por esos caminos, desafiásedes a este rústico indómito, y le hiciésedes que se casase con mi hija, en cumplimiento de la palabra que le dio de ser su esposo, antes y primero que yogase con ella; porque pensar que el duque mi señor me ha de hacer justicia es pedir peras al olmo, por la ocasión que ya a vuesa merced en puridad tengo declarada. Y con esto, Nuestro Señor dé a vuesa merced mucha salud, y a nosotras no nos desampare. A cuyas razones respondió don Quijote, con mucha gravedad y prosopopeya: -Buena dueña, templad vuestras lágrimas, o, por mejor decir, enjugadlas y ahorrad de vuestros suspiros, que yo tomo a mi cargo el remedio de vuestra hija, a la cual le hubiera estado mejor no haber sido tan fácil en creer promesas de enamorados, las cuales, por la mayor parte, son ligeras de prometer y muy pesadas de cumplir; y así, con licencia del duque mi señor, yo me partiré luego en busca dese desalmado mancebo, y le hallaré, y le desafiaré, y le mataré cada y cuando que se escusare de cumplir la prometida palabra; que el principal asumpto de mi profesión es perdonar a los humildes y castigar a los soberbios; quiero decir: acorrer a los miserables y destruir a los rigurosos. -No es menester -respondió el duque- que vuesa merced se ponga en trabajo de buscar al rústico de quien esta buena dueña se queja, ni es menester tampoco que vuesa merced me pida a mí licencia para desafiarle; que yo le doy por desafiado, y tomo a mi cargo de hacerle saber este desafío, y que le acete, y venga a responder por sí a este mi castillo, donde a entrambos daré campo seguro, guardando todas las condiciones que en tales actos suelen y deben guardarse, guardando igualmente su justicia a cada uno, como están obligados a guardarla todos aquellos príncipes que dan campo franco a los que se combaten en los términos de sus señoríos. -Pues con ese seguro y con buena licencia de vuestra grandeza -replicó don Quijote-, desde aquí digo que por esta vez renuncio a mi hidalguía, y me allano y ajusto con la llaneza del dañador, y me hago igual con él, habilitándole para poder combatir conmigo; y así, aunque ausente, le desafío y repto, en razón de que hizo mal en defraudar a esta pobre, que fue doncella y ya por su culpa no lo es, y que le ha de cumplir la palabra que le dio de ser su legítimo esposo, o morir en la demanda. Y luego, descalzándose un guante, le arrojó en mitad de la sala, y el duque le alzó, diciendo que, como ya había dicho, él acetaba el tal desafío en nombre de su vasallo, y señalaba el plazo de allí a seis días; y el campo, en la plaza de aquel castillo; y las armas, las acostumbradas de los caballeros: lanza y escudo, y arnés tranzado, con todas las demás piezas, sin engaño, superchería o superstición alguna, examinadas y vistas por los jueces del campo. -Pero, ante todas cosas, es menester que esta buena dueña y esta mala doncella pongan el derecho de su justicia en manos del señor don Quijote; que de otra manera no se hará nada, ni llegará a debida ejecución el tal desafío. -Yo sí pongo -respondió la dueña. -Y yo también -añadió la hija, toda llorosa y toda vergonzosa y de mal talante. Tomado, pues, este apuntamiento, y habiendo imaginado el duque lo que había de hacer en el caso, las enlutadas se fueron, y ordenó la duquesa que de allí adelante no las tratasen como a sus criadas, sino como a señoras aventureras que venían a pedir justicia a su casa; y así, les dieron cuarto aparte y las sirvieron como a forasteras, no sin espanto de las demás criadas, que no sabían en qué había de parar la sandez y desenvoltura de doña Rodríguez y de su malandante hija. Estando en esto, para acabar de regocijar la fiesta y dar buen fin a la comida, veis aquí donde entró por la sala el paje que llevó las cartas y presentes a Teresa Panza, mujer del gobernador Sancho Panza, de cuya llegada recibieron gran contento los duques, deseosos de saber lo que le había sucedido en su viaje; y, preguntándoselo, respondió el paje que no lo podía decir tan en público ni con breves palabras: que sus excelencias fuesen servidos de dejarlo para a solas, y que entretanto se entretuviesen con aquellas cartas. Y, sacando dos cartas, las puso en manos de la duquesa. La una decía en el sobreescrito: Carta para mi señora la duquesa tal, de no sé dónde, y la otra: A mi marido Sancho Panza, gobernador de la ínsula Barataria, que Dios prospere más años que a mí. No se le cocía el pan, como suele decirse, a la duquesa hasta leer su carta, y abriéndola y leído para sí, y viendo que la podía leer en voz alta para que el duque y los circunstantes la oyesen, leyó desta manera: Carta de Teresa Panza a la Duquesa Mucho contento me dio, señora mía, la carta que vuesa grandeza me escribió, que en verdad que la tenía bien deseada. La sarta de corales es muy buena, y el vestido de caza de mi marido no le va en zaga. De que vuestra señoría haya hecho gobernador a Sancho, mi consorte, ha recebido mucho gusto todo este lugar, puesto que no hay quien lo crea, principalmente el cura, y mase Nicolás el barbero, y Sansón Carrasco el bachiller; pero a mí no se me da nada; que, como ello sea así, como lo es, diga cada uno lo que quisiere; aunque, si va a decir verdad, a no venir los corales y el vestido, tampoco yo lo creyera, porque en este pueblo todos tienen a mi marido por un porro, y que, sacado de gobernar un hato de cabras, no pueden imaginar para qué gobierno pueda ser bueno. Dios lo haga, y lo encamine como vee que lo han menester sus hijos. Yo, señora de mi alma, estoy determinada, con licencia de vuesa merced, de meter este buen día en mi casa, yéndome a la corte a tenderme en un coche, para quebrar los ojos a mil envidiosos que ya tengo; y así, suplico a vuesa excelencia mande a mi marido me envíe algún dinerillo, y que sea algo qué, porque en la corte son los gastos grandes: que el pan vale a real, y la carne, la libra, a treinta maravedís, que es un juicio; y si quisiere que no vaya, que me lo avise con tiempo, porque me están bullendo los pies por ponerme en camino; que me dicen mis amigas y mis vecinas que, si yo y mi hija andamos orondas y pomposas en la corte, vendrá a ser conocido mi marido por mí más que yo por él, siendo forzoso que pregunten muchos: ''-¿Quién son estas señoras deste coche?'' Y un criado mío responder: ''-La mujer y la hija de Sancho Panza, gobernador de la ínsula Barataria''; y desta manera será conocido Sancho, y yo seré estimada, y a Roma por todo. Pésame, cuanto pesarme puede, que este año no se han cogido bellotas en este pueblo; con todo eso, envío a vuesa alteza hasta medio celemín, que una a una las fui yo a coger y a escoger al monte, y no las hallé más mayores; yo quisiera que fueran como huevos de avestruz. No se le olvide a vuestra pomposidad de escribirme, que yo tendré cuidado de la respuesta, avisando de mi salud y de todo lo que hubiere que avisar deste lugar, donde quedo rogando a Nuestro Señor guarde a vuestra grandeza, y a mí no olvide. Sancha, mi hija, y mi hijo besan a vuestra merced las manos. La que tiene más deseo de ver a vuestra señoría que de escribirla, su criada, Teresa Panza. Grande fue el gusto que todos recibieron de oír la carta de Teresa Panza, principalmente los duques, y la duquesa pidió parecer a don Quijote si sería bien abrir la carta que venía para el gobernador, que imaginaba debía de ser bonísima. Don Quijote dijo que él la abriría por darles gusto, y así lo hizo, y vio que decía desta manera: Carta de Teresa Panza a Sancho Panza su marido Tu carta recibí, Sancho mío de mi alma, y yo te prometo y juro como católica cristiana que no faltaron dos dedos para volverme loca de contento. Mira, hermano: cuando yo llegué a oír que eres gobernador, me pensé allí caer muerta de puro gozo, que ya sabes tú que dicen que así mata la alegría súbita como el dolor grande. A Sanchica, tu hija, se le fueron las aguas sin sentirlo, de puro contento. El vestido que me enviaste tenía delante, y los corales que me envió mi señora la duquesa al cuello, y las cartas en las manos, y el portador dellas allí presente, y, con todo eso, creía y pensaba que era todo sueño lo que veía y lo que tocaba; porque, ¿quién podía pensar que un pastor de cabras había de venir a ser gobernador de ínsulas? Ya sabes tú, amigo, que decía mi madre que era menester vivir mucho para ver mucho: dígolo porque pienso ver más si vivo más; porque no pienso parar hasta verte arrendador o alcabalero, que son oficios que, aunque lleva el diablo a quien mal los usa, en fin en fin, siempre tienen y manejan dineros. Mi señora la duquesa te dirá el deseo que tengo de ir a la corte; mírate en ello, y avísame de tu gusto, que yo procuraré honrarte en ella andando en coche. El cura, el barbero, el bachiller y aun el sacristán no pueden creer que eres gobernador, y dicen que todo es embeleco, o cosas de encantamento, como son todas las de don Quijote tu amo; y dice Sansón que ha de ir a buscarte y a sacarte el gobierno de la cabeza, y a don Quijote la locura de los cascos; yo no hago sino reírme, y mirar mi sarta, y dar traza del vestido que tengo de hacer del tuyo a nuestra hija. Unas bellotas envié a mi señora la duquesa; yo quisiera que fueran de oro. Envíame tú algunas sartas de perlas, si se usan en esa ínsula. Las nuevas deste lugar son que la Berrueca casó a su hija con un pintor de mala mano, que llegó a este pueblo a pintar lo que saliese; mandóle el Concejo pintar las armas de Su Majestad sobre las puertas del Ayuntamiento, pidió dos ducados, diéronselos adelantados, trabajó ocho días, al cabo de los cuales no pintó nada, y dijo que no acertaba a pintar tantas baratijas; volvió el dinero, y, con todo eso, se casó a título de buen oficial; verdad es que ya ha dejado el pincel y tomado el azada, y va al campo como gentilhombre. El hijo de Pedro de Lobo se ha ordenado de grados y corona, con intención de hacerse clérigo; súpolo Minguilla, la nieta de Mingo Silvato, y hale puesto demanda de que la tiene dada palabra de casamiento; malas lenguas quieren decir que ha estado encinta dél, pero él lo niega a pies juntillas. Hogaño no hay aceitunas, ni se halla una gota de vinagre en todo este pueblo. Por aquí pasó una compañía de soldados; lleváronse de camino tres mozas deste pueblo; no te quiero decir quién son: quizá volverán, y no faltará quien las tome por mujeres, con sus tachas buenas o malas. Sanchica hace puntas de randas; gana cada día ocho maravedís horros, que los va echando en una alcancía para ayuda a su ajuar; pero ahora que es hija de un gobernador, tú le darás la dote sin que ella lo trabaje. La fuente de la plaza se secó; un rayo cayó en la picota, y allí me las den todas. Espero respuesta désta y la resolución de mi ida a la corte; y, con esto, Dios te me guarde más años que a mí o tantos, porque no querría dejarte sin mí en este mundo. Tu mujer, Teresa Panza. Las cartas fueron solenizadas, reídas, estimadas y admiradas; y, para acabar de echar el sello, llegó el correo, el que traía la que Sancho enviaba a don Quijote, que asimesmo se leyó públicamente, la cual puso en duda la sandez del gobernador. Retiróse la duquesa, para saber del paje lo que le había sucedido en el lugar de Sancho, el cual se lo contó muy por estenso, sin dejar circunstancia que no refiriese; diole las bellotas, y más un queso que Teresa le dio, por ser muy bueno, que se aventajaba a los de Tronchón Recibiólo la duquesa con grandísimo gusto, con el cual la dejaremos, por contar el fin que tuvo el gobierno del gran Sancho Panza, flor y espejo de todos los insulanos gobernadores. Capítulo LIII. Del fatigado fin y remate que tuvo el gobierno de Sancho Panza ''Pensar que en esta vida las cosas della han de durar siempre en un estado es pensar en lo escusado; antes parece que ella anda todo en redondo, digo, a la redonda: la primavera sigue al verano, el verano al estío, el estío al otoño, y el otoño al invierno, y el invierno a la primavera, y así torna a andarse el tiempo con esta rueda continua; sola la vida humana corre a su fin ligera más que el tiempo, sin esperar renovarse si no es en la otra, que no tiene términos que la limiten''. Esto dice Cide Hamete, filósofo mahomético; porque esto de entender la ligereza e instabilidad de la vida presente, y de la duración de la eterna que se espera, muchos sin lumbre de fe, sino con la luz natural, lo han entendido; pero aquí, nuestro autor lo dice por la presteza con que se acabó, se consumió, se deshizo, se fue como en sombra y humo el gobierno de Sancho. El cual, estando la séptima noche de los días de su gobierno en su cama, no harto de pan ni de vino, sino de juzgar y dar pareceres y de hacer estatutos y pragmáticas, cuando el sueño, a despecho y pesar de la hambre, le comenzaba a cerrar los párpados, oyó tan gran ruido de campanas y de voces, que no parecía sino que toda la ínsula se hundía. Sentóse en la cama, y estuvo atento y escuchando, por ver si daba en la cuenta de lo que podía ser la causa de tan grande alboroto; pero no sólo no lo supo, pero, añadiéndose al ruido de voces y campanas el de infinitas trompetas y atambores, quedó más confuso y lleno de temor y espanto; y, levantándose en pie, se puso unas chinelas, por la humedad del suelo, y, sin ponerse sobrerropa de levantar, ni cosa que se pareciese, salió a la puerta de su aposento, a tiempo cuando vio venir por unos corredores más de veinte personas con hachas encendidas en las manos y con las espadas desenvainadas, gritando todos a grandes voces: -¡Arma, arma, señor gobernador, arma!; que han entrado infinitos enemigos en la ínsula, y somos perdidos si vuestra industria y valor no nos socorre. Con este ruido, furia y alboroto llegaron donde Sancho estaba, atónito y embelesado de lo que oía y veía; y, cuando llegaron a él, uno le dijo: -¡Ãrmese luego vuestra señoría, si no quiere perderse y que toda esta ínsula se pierda! -¿Qué me tengo de armar -respondió Sancho-, ni qué sé yo de armas ni de socorros? Estas cosas mejor será dejarlas para mi amo don Quijote, que en dos paletas las despachará y pondrá en cobro; que yo, pecador fui a Dios, no se me entiende nada destas priesas. -¡Ah, señor gobernador! -dijo otro-. ¿Qué relente es ése? Ãrmese vuesa merced, que aquí le traemos armas ofensivas y defensivas, y salga a esa plaza, y sea nuestra guía y nuestro capitán, pues de derecho le toca el serlo, siendo nuestro gobernador. -Ãrmenme norabuena -replicó Sancho. Y al momento le trujeron dos paveses, que venían proveídos dellos, y le pusieron encima de la camisa, sin dejarle tomar otro vestido, un pavés delante y otro detrás, y, por unas concavidades que traían hechas, le sacaron los brazos, y le liaron muy bien con unos cordeles, de modo que quedó emparedado y entablado, derecho como un huso, sin poder doblar las rodillas ni menearse un solo paso. Pusiéronle en las manos una lanza, a la cual se arrimó para poder tenerse en pie. Cuando así le tuvieron, le dijeron que caminase, y los guiase y animase a todos; que, siendo él su norte, su lanterna y su lucero, tendrían buen fin sus negocios. -¿Cómo tengo de caminar, desventurado yo -respondió Sancho-, que no puedo jugar las choquezuelas de las rodillas, porque me lo impiden estas tablas que tan cosidas tengo con mis carnes? Lo que han de hacer es llevarme en brazos y ponerme, atravesado o en pie, en algún postigo, que yo le guardaré, o con esta lanza o con mi cuerpo. -Ande, señor gobernador -dijo otro-, que más el miedo que las tablas le impiden el paso; acabe y menéese, que es tarde, y los enemigos crecen, y las voces se aumentan y el peligro carga. Por cuyas persuasiones y vituperios probó el pobre gobernador a moverse, y fue dar consigo en el suelo tan gran golpe, que pensó que se había hecho pedazos. Quedó como galápago encerrado y cubierto con sus conchas, o como medio tocino metido entre dos artesas, o bien así como barca que da al través en la arena; y no por verle caído aquella gente burladora le tuvieron compasión alguna; antes, apagando las antorchas, tornaron a reforzar las voces, y a reiterar el ¡arma! con tan gran priesa, pasando por encima del pobre Sancho, dándole infinitas cuchilladas sobre los paveses, que si él no se recogiera y encogiera, metiendo la cabeza entre los paveses, lo pasara muy mal el pobre gobernador, el cual, en aquella estrecheza recogido, sudaba y trasudaba, y de todo corazón se encomendaba a Dios que de aquel peligro le sacase. Unos tropezaban en él, otros caían, y tal hubo que se puso encima un buen espacio, y desde allí, como desde atalaya, gobernaba los ejércitos, y a grandes voces decía: -¡Aquí de los nuestros, que por esta parte cargan más los enemigos! ¡Aquel portillo se guarde, aquella puerta se cierre, aquellas escalas se tranquen! ¡Vengan alcancías, pez y resina en calderas de aceite ardiendo! ¡Trinchéense las calles con colchones! En fin, él nombraba con todo ahínco todas las baratijas e instrumentos y pertrechos de guerra con que suele defenderse el asalto de una ciudad, y el molido Sancho, que lo escuchaba y sufría todo, decía entre sí: -¡Oh, si mi Señor fuese servido que se acabase ya de perder esta ínsula, y me viese yo o muerto o fuera desta grande angustia! Oyó el cielo su petición, y, cuando menos lo esperaba, oyó voces que decían: -¡Vitoria, vitoria! ¡Los enemigos van de vencida! ¡Ea, señor gobernador, levántese vuesa merced y venga a gozar del vencimiento y a repartir los despojos que se han tomado a los enemigos, por el valor dese invencible brazo! -Levántenme -dijo con voz doliente el dolorido Sancho. Ayudáronle a levantar, y, puesto en pie, dijo: -El enemigo que yo hubiere vencido quiero que me le claven en la frente. Yo no quiero repartir despojos de enemigos, sino pedir y suplicar a algún amigo, si es que le tengo, que me dé un trago de vino, que me seco, y me enjugue este sudor, que me hago agua. Limpiáronle, trujéronle el vino, desliáronle los paveses, sentóse sobre su lecho y desmayóse del temor, del sobresalto y del trabajo. Ya les pesaba a los de la burla de habérsela hecho tan pesada; pero el haber vuelto en sí Sancho les templó la pena que les había dado su desmayo. Preguntó qué hora era, respondiéronle que ya amanecía. Calló, y, sin decir otra cosa, comenzó a vestirse, todo sepultado en silencio, y todos le miraban y esperaban en qué había de parar la priesa con que se vestía. Vistióse, en fin, y poco a poco, porque estaba molido y no podía ir mucho a mucho, se fue a la caballeriza, siguiéndole todos los que allí se hallaban, y, llegándose al rucio, le abrazó y le dio un beso de paz en la frente, y, no sin lágrimas en los ojos, le dijo: -Venid vos acá, compañero mío y amigo mío, y conllevador de mis trabajos y miserias: cuando yo me avenía con vos y no tenía otros pensamientos que los que me daban los cuidados de remendar vuestros aparejos y de sustentar vuestro corpezuelo, dichosas eran mis horas, mis días y mis años; pero, después que os dejé y me subí sobre las torres de la ambición y de la soberbia, se me han entrado por el alma adentro mil miserias, mil trabajos y cuatro mil desasosiegos. Y, en tanto que estas razones iba diciendo, iba asimesmo enalbardando el asno, sin que nadie nada le dijese. Enalbardado, pues, el rucio, con gran pena y pesar subió sobre él, y, encaminando sus palabras y razones al mayordomo, al secretario, al maestresala y a Pedro Recio el doctor, y a otros muchos que allí presentes estaban, dijo: -Abrid camino, señores míos, y dejadme volver a mi antigua libertad; dejadme que vaya a buscar la vida pasada, para que me resucite de esta muerte presente. Yo no nací para ser gobernador, ni para defender ínsulas ni ciudades de los enemigos que quisieren acometerlas. Mejor se me entiende a mí de arar y cavar, podar y ensarmentar las viñas, que de dar leyes ni de defender provincias ni reinos. Bien se está San Pedro en Roma: quiero decir, que bien se está cada uno usando el oficio para que fue nacido. Mejor me está a mí una hoz en la mano que un cetro de gobernador; más quiero hartarme de gazpachos que estar sujeto a la miseria de un médico impertinente que me mate de hambre; y más quiero recostarme a la sombra de una encina en el verano y arroparme con un zamarro de dos pelos en el invierno, en mi libertad, que acostarme con la sujeción del gobierno entre sábanas de holanda y vestirme de martas cebollinas. Vuestras mercedes se queden con Dios, y digan al duque mi señor que, desnudo nací, desnudo me hallo: ni pierdo ni gano; quiero decir, que sin blanca entré en este gobierno y sin ella salgo, bien al revés de como suelen salir los gobernadores de otras ínsulas. Y apártense: déjenme ir, que me voy a bizmar; que creo que tengo brumadas todas las costillas, merced a los enemigos que esta noche se han paseado sobre mí. -No ha de ser así, señor gobernador -dijo el doctor Recio-, que yo le daré a vuesa merced una bebida contra caídas y molimientos, que luego le vuelva en su prístina entereza y vigor; y, en lo de la comida, yo prometo a vuesa merced de enmendarme, dejándole comer abundantemente de todo aquello que quisiere. -¡Tarde piache! -respondió Sancho-. Así dejaré de irme como volverme turco. No son estas burlas para dos veces. Por Dios que así me quede en éste, ni admita otro gobierno, aunque me le diesen entre dos platos, como volar al cielo sin alas. Yo soy del linaje de los Panzas, que todos son testarudos, y si una vez dicen nones, nones han de ser, aunque sean pares, a pesar de todo el mundo. Quédense en esta caballeriza las alas de la hormiga, que me levantaron en el aire para que me comiesen vencejos y otros pájaros, y volvámonos a andar por el suelo con pie llano, que, si no le adornaren zapatos picados de cordobán, no le faltarán alpargatas toscas de cuerda. Cada oveja con su pareja, y nadie tienda más la pierna de cuanto fuere larga la sábana; y déjenme pasar, que se me hace tarde. A lo que el mayordomo dijo: -Señor gobernador, de muy buena gana dejáramos ir a vuesa merced, puesto que nos pesará mucho de perderle, que su ingenio y su cristiano proceder obligan a desearle; pero ya se sabe que todo gobernador está obligado, antes que se ausente de la parte donde ha gobernado, dar primero residencia: déla vuesa merced de los diez días que ha que tiene el gobierno, y váyase a la paz de Dios. -Nadie me la puede pedir -respondió Sancho-, si no es quien ordenare el duque mi señor; yo voy a verme con él, y a él se la daré de molde; cuanto más que, saliendo yo desnudo, como salgo, no es menester otra señal para dar a entender que he gobernado como un ángel. -Par Dios que tiene razón el gran Sancho -dijo el doctor Recio-, y que soy de parecer que le dejemos ir, porque el duque ha de gustar infinito de verle. Todos vinieron en ello, y le dejaron ir, ofreciéndole primero compañía y todo aquello que quisiese para el regalo de su persona y para la comodidad de su viaje. Sancho dijo que no quería más de un poco de cebada para el rucio y medio queso y medio pan para él; que, pues el camino era tan corto, no había menester mayor ni mejor repostería. Abrazáronle todos, y él, llorando, abrazó a todos, y los dejó admirados, así de sus razones como de su determinación tan resoluta y tan discreta. Capítulo LIV. Que trata de cosas tocantes a esta historia, y no a otra alguna Resolviéronse el duque y la duquesa de que el desafío que don Quijote hizo a su vasallo, por la causa ya referida, pasase adelante; y, puesto que el mozo estaba en Flandes, adonde se había ido huyendo, por no tener por suegra a doña Rodríguez, ordenaron de poner en su lugar a un lacayo gascón, que se llamaba Tosilos, industriándole primero muy bien de todo lo que había de hacer. De allí a dos días dijo el duque a don Quijote como desde allí a cuatro vendría su contrario, y se presentaría en el campo, armado como caballero, y sustentaría como la doncella mentía por mitad de la barba, y aun por toda la barba entera, si se afirmaba que él le hubiese dado palabra de casamiento. Don Quijote recibió mucho gusto con las tales nuevas, y se prometió a sí mismo de hacer maravillas en el caso, y tuvo a gran ventura habérsele ofrecido ocasión donde aquellos señores pudiesen ver hasta dónde se estendía el valor de su poderoso brazo; y así, con alborozo y contento, esperaba los cuatro días, que se le iban haciendo, a la cuenta de su deseo, cuatrocientos siglos. Dejémoslos pasar nosotros, como dejamos pasar otras cosas, y vamos a acompañar a Sancho, que entre alegre y triste venía caminando sobre el rucio a buscar a su amo, cuya compañía le agradaba más que ser gobernador de todas las ínsulas del mundo. Sucedió, pues, que, no habiéndose alongado mucho de la ínsula del su gobierno -que él nunca se puso a averiguar si era ínsula, ciudad, villa o lugar la que gobernaba-, vio que por el camino por donde él iba venían seis peregrinos con sus bordones, de estos estranjeros que piden la limosna cantando, los cuales, en llegando a él, se pusieron en ala, y, levantando las voces todos juntos, comenzaron a cantar en su lengua lo que Sancho no pudo entender, si no fue una palabra que claramente pronunciaba limosna, por donde entendió que era limosna la que en su canto pedían; y como él, según dice Cide Hamete, era caritativo además, sacó de sus alforjas medio pan y medio queso, de que venía proveído, y dióselo, diciéndoles por señas que no tenía otra cosa que darles. Ellos lo recibieron de muy buena gana, y dijeron: -¡Guelte! ¡Guelte! -No entiendo -respondió Sancho- qué es lo que me pedís, buena gente. Entonces uno de ellos sacó una bolsa del seno y mostrósela a Sancho, por donde entendió que le pedían dineros; y él, poniéndose el dedo pulgar en la garganta y estendiendo la mano arriba, les dio a entender que no tenía ostugo de moneda, y, picando al rucio, rompió por ellos; y, al pasar, habiéndole estado mirando uno dellos con mucha atención, arremetió a él, echándole los brazos por la cintura; en voz alta y muy castellana, dijo: -¡Válame Dios! ¿Qué es lo que veo? ¿Es posible que tengo en mis brazos al mi caro amigo, al mi buen vecino Sancho Panza? Sí tengo, sin duda, porque yo ni duermo, ni estoy ahora borracho. Admiróse Sancho de verse nombrar por su nombre y de verse abrazar del estranjero peregrino, y, después de haberle estado mirando sin hablar palabra, con mucha atención, nunca pudo conocerle; pero, viendo su suspensión el peregrino, le dijo: -¿Cómo, y es posible, Sancho Panza hermano, que no conoces a tu vecino Ricote el morisco, tendero de tu lugar? Entonces Sancho le miró con más atención y comenzó a rafigurarle, y , finalmente, le vino a conocer de todo punto, y, sin apearse del jumento, le echó los brazos al cuello, y le dijo: -¿Quién diablos te había de conocer, Ricote, en ese traje de moharracho que traes? Dime: ¿quién te ha hecho franchote, y cómo tienes atrevimiento de volver a España, donde si te cogen y conocen tendrás harta mala ventura? -Si tú no me descubres, Sancho -respondió el peregrino-, seguro estoy que en este traje no habrá nadie que me conozca; y apartémonos del camino a aquella alameda que allí parece, donde quieren comer y reposar mis compañeros, y allí comerás con ellos, que son muy apacible gente. Yo tendré lugar de contarte lo que me ha sucedido después que me partí de nuestro lugar, por obedecer el bando de Su Majestad, que con tanto rigor a los desdichados de mi nación amenazaba, según oíste. Hízolo así Sancho, y, hablando Ricote a los demás peregrinos, se apartaron a la alameda que se parecía, bien desviados del camino real. Arrojaron los bordones, quitáronse las mucetas o esclavinas y quedaron en pelota, y todos ellos eran mozos y muy gentileshombres, excepto Ricote, que ya era hombre entrado en años. Todos traían alforjas, y todas, según pareció, venían bien proveídas, a lo menos, de cosas incitativas y que llaman a la sed de dos leguas. Tendiéronse en el suelo, y, haciendo manteles de las yerbas, pusieron sobre ellas pan, sal, cuchillos, nueces, rajas de queso, huesos mondos de jamón, que si no se dejaban mascar, no defendían el ser chupados. Pusieron asimismo un manjar negro que dicen que se llama cavial, y es hecho de huevos de pescados, gran despertador de la colambre. No faltaron aceitunas, aunque secas y sin adobo alguno, pero sabrosas y entretenidas. Pero lo que más campeó en el campo de aquel banquete fueron seis botas de vino, que cada uno sacó la suya de su alforja; hasta el buen Ricote, que se había transformado de morisco en alemán o en tudesco, sacó la suya, que en grandeza podía competir con las cinco. Comenzaron a comer con grandísimo gusto y muy de espacio, saboreándose con cada bocado, que le tomaban con la punta del cuchillo, y muy poquito de cada cosa, y luego, al punto, todos a una, levantaron los brazos y las botas en el aire; puestas las bocas en su boca, clavados los ojos en el cielo, no parecía sino que ponían en él la puntería; y desta manera, meneando las cabezas a un lado y a otro, señales que acreditaban el gusto que recebían, se estuvieron un buen espacio, trasegando en sus estómagos las entrañas de las vasijas. Todo lo miraba Sancho, y de ninguna cosa se dolía; antes, por cumplir con el refrán, que él muy bien sabía, de "cuando a Roma fueres, haz como vieres", pidió a Ricote la bota, y tomó su puntería como los demás, y no con menos gusto que ellos. Cuatro veces dieron lugar las botas para ser empinadas; pero la quinta no fue posible, porque ya estaban más enjutas y secas que un esparto, cosa que puso mustia la alegría que hasta allí habían mostrado. De cuando en cuando, juntaba alguno su mano derecha con la de Sancho, y decía: -Español y tudesqui, tuto uno: bon compaño. Y Sancho respondía: Bon compaño, jura Di! Y disparaba con una risa que le duraba un hora, sin acordarse entonces de nada de lo que le había sucedido en su gobierno; porque sobre el rato y tiempo cuando se come y bebe, poca jurisdición suelen tener los cuidados. Finalmente, el acabársele el vino fue principio de un sueño que dio a todos, quedándose dormidos sobre las mismas mesas y manteles; solos Ricote y Sancho quedaron alerta, porque habían comido más y bebido menos; y, apartando Ricote a Sancho, se sentaron al pie de una haya, dejando a los peregrinos sepultados en dulce sueño; y Ricote, sin tropezar nada en su lengua morisca, en la pura castellana le dijo las siguientes razones: -«Bien sabes, ¡oh Sancho Panza, vecino y amigo mío!, como el pregón y bando que Su Majestad mandó publicar contra los de mi nación puso terror y espanto en todos nosotros; a lo menos, en mí le puso de suerte que me parece que antes del tiempo que se nos concedía para que hiciésemos ausencia de España, ya tenía el rigor de la pena ejecutado en mi persona y en la de mis hijos. Ordené, pues, a mi parecer como prudente, bien así como el que sabe que para tal tiempo le han de quitar la casa donde vive y se provee de otra donde mudarse; ordené, digo, de salir yo solo, sin mi familia, de mi pueblo, y ir a buscar donde llevarla con comodidad y sin la priesa con que los demás salieron; porque bien vi, y vieron todos nuestros ancianos, que aquellos pregones no eran sólo amenazas, como algunos decían, sino verdaderas leyes, que se habían de poner en ejecución a su determinado tiempo; y forzábame a creer esta verdad saber yo los ruines y disparatados intentos que los nuestros tenían, y tales, que me parece que fue inspiración divina la que movió a Su Majestad a poner en efecto tan gallarda resolución, no porque todos fuésemos culpados, que algunos había cristianos firmes y verdaderos; pero eran tan pocos que no se podían oponer a los que no lo eran, y no era bien criar la sierpe en el seno, teniendo los enemigos dentro de casa. Finalmente, con justa razón fuimos castigados con la pena del destierro, blanda y suave al parecer de algunos, pero al nuestro, la más terrible que se nos podía dar. Doquiera que estamos lloramos por España, que, en fin, nacimos en ella y es nuestra patria natural; en ninguna parte hallamos el acogimiento que nuestra desventura desea, y en Berbería, y en todas las partes de Ãfrica, donde esperábamos ser recebidos, acogidos y regalados, allí es donde más nos ofenden y maltratan. No hemos conocido el bien hasta que le hemos perdido; y es el deseo tan grande, que casi todos tenemos de volver a España, que los más de aquellos, y son muchos, que saben la lengua como yo, se vuelven a ella, y dejan allá sus mujeres y sus hijos desamparados: tanto es el amor que la tienen; y agora conozco y experimento lo que suele decirse: que es dulce el amor de la patria. Salí, como digo, de nuestro pueblo, entré en Francia, y, aunque allí nos hacían buen acogimiento, quise verlo todo. Pasé a Italia y llegué a Alemania, y allí me pareció que se podía vivir con más libertad, porque sus habitadores no miran en muchas delicadezas: cada uno vive como quiere, porque en la mayor parte della se vive con libertad de conciencia. Dejé tomada casa en un pueblo junto a Augusta; juntéme con estos peregrinos, que tienen por costumbre de venir a España muchos dellos, cada año, a visitar los santuarios della, que los tienen por sus Indias, y por certísima granjería y conocida ganancia. Ãndanla casi toda, y no hay pueblo ninguno de donde no salgan comidos y bebidos, como suele decirse, y con un real, por lo menos, en dineros, y al cabo de su viaje salen con más de cien escudos de sobra que, trocados en oro, o ya en el hueco de los bordones, o entre los remiendos de las esclavinas, o con la industria que ellos pueden, los sacan del reino y los pasan a sus tierras, a pesar de las guardas de los puestos y puertos donde se registran. Ahora es mi intención, Sancho, sacar el tesoro que dejé enterrado, que por estar fuera del pueblo lo podré hacer sin peligro y escribir o pasar desde Valencia a mi hija y a mi mujer, que sé que está en Argel, y dar traza como traerlas a algún puerto de Francia, y desde allí llevarlas a Alemania, donde esperaremos lo que Dios quisiere hacer de nosotros; que, en resolución, Sancho, yo sé cierto que la Ricota mi hija y Francisca Ricota, mi mujer, son católicas cristianas, y, aunque yo no lo soy tanto, todavía tengo más de cristiano que de moro, y ruego siempre a Dios me abra los ojos del entendimiento y me dé a conocer cómo le tengo de servir. Y lo que me tiene admirado es no saber por qué se fue mi mujer y mi hija antes a Berbería que a Francia, adonde podía vivir como cristiana.» A lo que respondió Sancho: -Mira, Ricote, eso no debió estar en su mano, porque las llevó Juan Tiopieyo, el hermano de tu mujer; y, como debe de ser fino moro, fuese a lo más bien parado, y séte decir otra cosa: que creo que vas en balde a buscar lo que dejaste encerrado; porque tuvimos nuevas que habían quitado a tu cuñado y tu mujer muchas perlas y mucho dinero en oro que llevaban por registrar. -Bien puede ser eso -replicó Ricote-, pero yo sé, Sancho, que no tocaron a mi encierro, porque yo no les descubrí dónde estaba, temeroso de algún desmán; y así, si tú, Sancho, quieres venir conmigo y ayudarme a sacarlo y a encubrirlo, yo te daré docientos escudos, con que podrás remediar tus necesidades, que ya sabes que sé yo que las tienes muchas. -Yo lo hiciera -respondió Sancho-, pero no soy nada codicioso; que, a serlo, un oficio dejé yo esta mañana de las manos, donde pudiera hacer las paredes de mi casa de oro, y comer antes de seis meses en platos de plata; y, así por esto como por parecerme haría traición a mi rey en dar favor a sus enemigos, no fuera contigo, si como me prometes docientos escudos, me dieras aquí de contado cuatrocientos. -Y ¿qué oficio es el que has dejado, Sancho? -preguntó Ricote. -He dejado de ser gobernador de una ínsula -respondió Sancho-, y tal, que a buena fee que no hallen otra como ella a tres tirones. -¿Y dónde está esa ínsula? -preguntó Ricote. -¿Adónde? -respondió Sancho-. Dos leguas de aquí, y se llama la ínsula Barataria. -Calla, Sancho -dijo Ricote-, que las ínsulas están allá dentro de la mar; que no hay ínsulas en la tierra firme. -¿Cómo no? -replicó Sancho-. Dígote, Ricote amigo, que esta mañana me partí della, y ayer estuve en ella gobernando a mi placer, como un sagitario; pero, con todo eso, la he dejado, por parecerme oficio peligroso el de los gobernadores. -Y ¿qué has ganado en el gobierno? -preguntó Ricote. -He ganado -respondió Sancho- el haber conocido que no soy bueno para gobernar, si no es un hato de ganado, y que las riquezas que se ganan en los tales gobiernos son a costa de perder el descanso y el sueño, y aun el sustento; porque en las ínsulas deben de comer poco los gobernadores, especialmente si tienen médicos que miren por su salud. -Yo no te entiendo, Sancho -dijo Ricote-, pero paréceme que todo lo que dices es disparate; que, ¿quién te había de dar a ti ínsulas que gobernases? ¿Faltaban hombres en el mundo más hábiles para gobernadores que tú eres? Calla, Sancho, y vuelve en ti, y mira si quieres venir conmigo, como te he dicho, a ayudarme a sacar el tesoro que dejé escondido; que en verdad que es tanto, que se puede llamar tesoro, y te daré con que vivas, como te he dicho. -Ya te he dicho, Ricote -replicó Sancho-, que no quiero; conténtate que por mí no serás descubierto, y prosigue en buena hora tu camino, y déjame seguir el mío; que yo sé que lo bien ganado se pierde, y lo malo, ello y su dueño. -No quiero porfiar, Sancho -dijo Ricote-, pero dime: ¿hallástete en nuestro lugar, cuando se partió dél mi mujer, mi hija y mi cuñado? -Sí hallé -respondió Sancho-, y séte decir que salió tu hija tan hermosa que salieron a verla cuantos había en el pueblo, y todos decían que era la más bella criatura del mundo. Iba llorando y abrazaba a todas sus amigas y conocidas, y a cuantos llegaban a verla, y a todos pedía la encomendasen a Dios y a Nuestra Señora su madre; y esto, con tanto sentimiento, que a mí me hizo llorar, que no suelo ser muy llorón. Y a fee que muchos tuvieron deseo de esconderla y salir a quitársela en el camino; pero el miedo de ir contra el mandado del rey los detuvo. Principalmente se mostró más apasionado don Pedro Gregorio, aquel mancebo mayorazgo rico que tú conoces, que dicen que la quería mucho, y después que ella se partió, nunca más él ha parecido en nuestro lugar, y todos pensamos que iba tras ella para robarla; pero hasta ahora no se ha sabido nada. -Siempre tuve yo mala sospecha -dijo Ricote- de que ese caballero adamaba a mi hija; pero, fiado en el valor de mi Ricota, nunca me dio pesadumbre el saber que la quería bien; que ya habrás oído decir, Sancho, que las moriscas pocas o ninguna vez se mezclaron por amores con cristianos viejos, y mi hija, que, a lo que yo creo, atendía a ser más cristiana que enamorada, no se curaría de las solicitudes de ese señor mayorazgo. -Dios lo haga -replicó Sancho-, que a entrambos les estaría mal. Y déjame partir de aquí, Ricote amigo, que quiero llegar esta noche adonde está mi señor don Quijote. -Dios vaya contigo, Sancho hermano, que ya mis compañeros se rebullen, y también es hora que prosigamos nuestro camino. Y luego se abrazaron los dos, y Sancho subió en su rucio, y Ricote se arrimó a su bordón, y se apartaron. Capítulo LV. De cosas sucedidas a Sancho en el camino, y otras que no hay más que ver El haberse detenido Sancho con Ricote no le dio lugar a que aquel día llegase al castillo del duque, puesto que llegó media legua dél, donde le tomó la noche, algo escura y cerrada; pero, como era verano, no le dio mucha pesadumbre; y así, se apartó del camino con intención de esperar la mañana; y quiso su corta y desventurada suerte que, buscando lugar donde mejor acomodarse, cayeron él y el rucio en una honda y escurísima sima que entre unos edificios muy antiguos estaba, y al tiempo del caer, se encomendó a Dios de todo corazón, pensando que no había de parar hasta el profundo de los abismos. Y no fue así, porque a poco más de tres estados dio fondo el rucio, y él se halló encima dél, sin haber recebido lisión ni daño alguno. Tentóse todo el cuerpo, y recogió el aliento, por ver si estaba sano o agujereado por alguna parte; y, viéndose bueno, entero y católico de salud, no se hartaba de dar gracias a Dios Nuestro Señor de la merced que le había hecho, porque sin duda pensó que estaba hecho mil pedazos. Tentó asimismo con las manos por las paredes de la sima, por ver si sería posible salir della sin ayuda de nadie; pero todas las halló rasas y sin asidero alguno, de lo que Sancho se congojó mucho, especialmente cuando oyó que el rucio se quejaba tierna y dolorosamente; y no era mucho, ni se lamentaba de vicio, que, a la verdad, no estaba muy bien parado. -¡Ay -dijo entonces Sancho Panza-, y cuán no pensados sucesos suelen suceder a cada paso a los que viven en este miserable mundo! ¿Quién dijera que el que ayer se vio entronizado gobernador de una ínsula, mandando a sus sirvientes y a sus vasallos, hoy se había de ver sepultado en una sima, sin haber persona alguna que le remedie, ni criado ni vasallo que acuda a su socorro? Aquí habremos de perecer de hambre yo y mi jumento, si ya no nos morimos antes, él de molido y quebrantado, y yo de pesaroso. A lo menos, no seré yo tan venturoso como lo fue mi señor don Quijote de la Mancha cuando decendió y bajó a la cueva de aquel encantado Montesinos, donde halló quien le regalase mejor que en su casa, que no parece sino que se fue a mesa puesta y a cama hecha. Allí vio él visiones hermosas y apacibles, y yo veré aquí, a lo que creo, sapos y culebras. ¡Desdichado de mí, y en qué han parado mis locuras y fantasías! De aquí sacarán mis huesos, cuando el cielo sea servido que me descubran, mondos, blancos y raídos, y los de mi buen rucio con ellos, por donde quizá se echará de ver quién somos, a lo menos de los que tuvieren noticia que nunca Sancho Panza se apartó de su asno, ni su asno de Sancho Panza. Otra vez digo: ¡miserables de nosotros, que no ha querido nuestra corta suerte que muriésemos en nuestra patria y entre los nuestros, donde ya que no hallara remedio nuestra desgracia, no faltara quien dello se doliera, y en la hora última de nuestro pasamiento nos cerrara los ojos! ¡Oh compañero y amigo mío, qué mal pago te he dado de tus buenos servicios! Perdóname y pide a la fortuna, en el mejor modo que supieres, que nos saque deste miserable trabajo en que estamos puestos los dos; que yo prometo de ponerte una corona de laurel en la cabeza, que no parezcas sino un laureado poeta, y de darte los piensos doblados. Desta manera se lamentaba Sancho Panza, y su jumento le escuchaba sin responderle palabra alguna: tal era el aprieto y angustia en que el pobre se hallaba. Finalmente, habiendo pasado toda aquella noche en miserables quejas y lamentaciones, vino el día, con cuya claridad y resplandor vio Sancho que era imposible de toda imposibilidad salir de aquel pozo sin ser ayudado, y comenzó a lamentarse y dar voces, por ver si alguno le oía; pero todas sus voces eran dadas en desierto, pues por todos aquellos contornos no había persona que pudiese escucharle, y entonces se acabó de dar por muerto. Estaba el rucio boca arriba, y Sancho Panza le acomodó de modo que le puso en pie, que apenas se podía tener; y, sacando de las alforjas, que también habían corrido la mesma fortuna de la caída, un pedazo de pan, lo dio a su jumento, que no le supo mal, y díjole Sancho, como si lo entendiera: -Todos los duelos con pan son buenos. En esto, descubrió a un lado de la sima un agujero, capaz de caber por él una persona, si se agobiaba y encogía. Acudió a él Sancho Panza, y, agazapándose, se entró por él y vio que por de dentro era espacioso y largo, y púdolo ver, porque por lo que se podía llamar techo entraba un rayo de sol que lo descubría todo. Vio también que se dilataba y alargaba por otra concavidad espaciosa; viendo lo cual, volvió a salir adonde estaba el jumento, y con una piedra comenzó a desmoronar la tierra del agujero, de modo que en poco espacio hizo lugar donde con facilidad pudiese entrar el asno, como lo hizo; y, cogiéndole del cabestro, comenzó a caminar por aquella gruta adelante, por ver si hallaba alguna salida por otra parte. A veces iba a escuras, y a veces sin luz, pero ninguna vez sin miedo. -¡Válame Dios todopoderoso! -decía entre sí-. Esta que para mí es desventura, mejor fuera para aventura de mi amo don Quijote. Él sí que tuviera estas profundidades y mazmorras por jardines floridos y por palacios de Galiana, y esperara salir de esta escuridad y estrecheza a algún florido prado; pero yo, sin ventura, falto de consejo y menoscabado de ánimo, a cada paso pienso que debajo de los pies de improviso se ha de abrir otra sima más profunda que la otra, que acabe de tragarme. ¡Bien vengas mal, si vienes solo! Desta manera y con estos pensamientos le pareció que habría caminado poco más de media legua, al cabo de la cual descubrió una confusa claridad, que pareció ser ya de día, y que por alguna parte entraba, que daba indicio de tener fin abierto aquel, para él, camino de la otra vida. Aquí le deja Cide Hamete Benengeli, y vuelve a tratar de don Quijote, que, alborozado y contento, esperaba el plazo de la batalla que había de hacer con el robador de la honra de la hija de doña Rodríguez, a quien pensaba enderezar el tuerto y desaguisado que malamente le tenían fecho. Sucedió, pues, que, saliéndose una mañana a imponerse y ensayarse en lo que había de hacer en el trance en que otro día pensaba verse, dando un repelón o arremetida a Rocinante, llegó a poner los pies tan junto a una cueva, que, a no tirarle fuertemente las riendas, fuera imposible no caer en ella. En fin, le detuvo y no cayó, y, llegándose algo más cerca, sin apearse, miró aquella hondura; y, estándola mirando, oyó grandes voces dentro; y, escuchando atentamente, pudo percebir y entender que el que las daba decía: -¡Ah de arriba! ¿Hay algún cristiano que me escuche, o algún caballero caritativo que se duela de un pecador enterrado en vida, o un desdichado desgobernado gobernador? Parecióle a don Quijote que oía la voz de Sancho Panza, de que quedó suspenso y asombrado, y, levantando la voz todo lo que pudo, dijo: -¿Quién está allá bajo? ¿Quién se queja? -¿Quién puede estar aquí, o quién se ha de quejar -respondieron-, sino el asendereado de Sancho Panza, gobernador, por sus pecados y por su mala andanza, de la ínsula Barataria, escudero que fue del famoso caballero don Quijote de la Mancha? Oyendo lo cual don Quijote, se le dobló la admiración y se le acrecentó el pasmo, viniéndosele al pensamiento que Sancho Panza debía de ser muerto, y que estaba allí penando su alma, y llevado desta imaginación dijo: -Conjúrote por todo aquello que puedo conjurarte como católico cristiano, que me digas quién eres; y si eres alma en pena, dime qué quieres que haga por ti; que, pues es mi profesión favorecer y acorrer a los necesitados deste mundo, también lo seré para acorrer y ayudar a los menesterosos del otro mundo, que no pueden ayudarse por sí propios. -Desa manera -respondieron-, vuestra merced que me habla debe de ser mi señor don Quijote de la Mancha, y aun en el órgano de la voz no es otro, sin duda. -Don Quijote soy -replicó don Quijote-, el que profeso socorrer y ayudar en sus necesidades a los vivos y a los muertos. Por eso dime quién eres, que me tienes atónito; porque si eres mi escudero Sancho Panza, y te has muerto, como no te hayan llevado los diablos, y, por la misericordia de Dios, estés en el purgatorio, sufragios tiene nuestra Santa Madre la Iglesia Católica Romana bastantes a sacarte de las penas en que estás, y yo, que lo solicitaré con ella, por mi parte, con cuanto mi hacienda alcanzare; por eso, acaba de declararte y dime quién eres. -¡Voto a tal! -respondieron-, y por el nacimiento de quien vuesa merced quisiere, juro, señor don Quijote de la Mancha, que yo soy su escudero Sancho Panza, y que nunca me he muerto en todos los días de mi vida; sino que, habiendo dejado mi gobierno por cosas y causas que es menester más espacio para decirlas, anoche caí en esta sima donde yago, el rucio conmigo, que no me dejará mentir, pues, por más señas, está aquí conmigo. Y hay más: que no parece sino que el jumento entendió lo que Sancho dijo, porque al momento comenzó a rebuznar, tan recio, que toda la cueva retumbaba. -¡Famoso testigo! -dijo don Quijote-. El rebuzno conozco como si le pariera, y tu voz oigo, Sancho mío. Espérame; iré al castillo del duque, que está aquí cerca, y traeré quien te saque desta sima, donde tus pecados te deben de haber puesto. -Vaya vuesa merced -dijo Sancho-, y vuelva presto, por un solo Dios, que ya no lo puedo llevar el estar aquí sepultado en vida, y me estoy muriendo de miedo. Dejóle don Quijote, y fue al castillo a contar a los duques el suceso de Sancho Panza, de que no poco se maravillaron, aunque bien entendieron que debía de haber caído por la correspondencia de aquella gruta que de tiempos inmemoriales estaba allí hecha; pero no podían pensar cómo había dejado el gobierno sin tener ellos aviso de su venida. Finalmente, como dicen, llevaron sogas y maromas; y, a costa de mucha gente y de mucho trabajo, sacaron al rucio y a Sancho Panza de aquellas tinieblas a la luz del sol. Viole un estudiante, y dijo: -Desta manera habían de salir de sus gobiernos todos los malos gobernadores, como sale este pecador del profundo del abismo: muerto de hambre, descolorido, y sin blanca, a lo que yo creo. Oyólo Sancho, y dijo: -Ocho días o diez ha, hermano murmurador, que entré a gobernar la ínsula que me dieron, en los cuales no me vi harto de pan siquiera un hora; en ellos me han perseguido médicos, y enemigos me han brumado los güesos; ni he tenido lugar de hacer cohechos, ni de cobrar derechos; y, siendo esto así, como lo es, no merecía yo, a mi parecer, salir de esta manera; pero el hombre pone y Dios dispone, y Dios sabe lo mejor y lo que le está bien a cada uno; y cual el tiempo, tal el tiento; y nadie diga "desta agua no beberé", que adonde se piensa que hay tocinos, no hay estacas; y Dios me entiende, y basta, y no digo más, aunque pudiera. -No te enojes, Sancho, ni recibas pesadumbre de lo que oyeres, que será nunca acabar: ven tú con segura conciencia, y digan lo que dijeren; y es querer atar las lenguas de los maldicientes lo mesmo que querer poner puertas al campo. Si el gobernador sale rico de su gobierno, dicen dél que ha sido un ladrón, y si sale pobre, que ha sido un para poco y un mentecato. -A buen seguro -respondió Sancho- que por esta vez antes me han de tener por tonto que por ladrón. En estas pláticas llegaron, rodeados de muchachos y de otra mucha gente, al castillo, adonde en unos corredores estaban ya el duque y la duquesa esperando a don Quijote y a Sancho, el cual no quiso subir a ver al duque sin que primero no hubiese acomodado al rucio en la caballeriza, porque decía que había pasado muy mala noche en la posada; y luego subió a ver a sus señores, ante los cuales, puesto de rodillas, dijo: -Yo, señores, porque lo quiso así vuestra grandeza, sin ningún merecimiento mío, fui a gobernar vuestra ínsula Barataria, en la cual entré desnudo, y desnudo me hallo: ni pierdo, ni gano. Si he gobernado bien o mal, testigos he tenido delante, que dirán lo que quisieren. He declarado dudas, sentenciado pleitos, siempre muerto de hambre, por haberlo querido así el doctor Pedro Recio, natural de Tirteafuera, médico insulano y gobernadoresco. Acometiéronnos enemigos de noche, y, habiéndonos puesto en grande aprieto, dicen los de la ínsula que salieron libres y con vitoria por el valor de mi brazo, que tal salud les dé Dios como ellos dicen verdad. En resolución, en este tiempo yo he tanteado las cargas que trae consigo, y las obligaciones, el gobernar, y he hallado por mi cuenta que no las podrán llevar mis hombros, ni son peso de mis costillas, ni flechas de mi aljaba; y así, antes que diese conmigo al través el gobierno, he querido yo dar con el gobierno al través, y ayer de mañana dejé la ínsula como la hallé: con las mismas calles, casas y tejados que tenía cuando entré en ella. No he pedido prestado a nadie, ni metídome en granjerías; y, aunque pensaba hacer algunas ordenanzas provechosas, no hice ninguna, temeroso que no se habían de guardar: que es lo mesmo hacerlas que no hacerlas. Salí, como digo, de la ínsula sin otro acompañamiento que el de mi rucio; caí en una sima, víneme por ella adelante, hasta que, esta mañana, con la luz del sol, vi la salida, pero no tan fácil que, a no depararme el cielo a mi señor don Quijote, allí me quedara hasta la fin del mundo. Así que, mis señores duque y duquesa, aquí está vuestro gobernador Sancho Panza, que ha granjeado en solos diez días que ha tenido el gobierno a conocer que no se le ha de dar nada por ser gobernador, no que de una ínsula, sino de todo el mundo; y, con este presupuesto, besando a vuestras mercedes los pies, imitando al juego de los muchachos, que dicen "Salta tú, y dámela tú", doy un salto del gobierno, y me paso al servicio de mi señor don Quijote; que, en fin, en él, aunque como el pan con sobresalto, hártome, a lo menos, y para mí, como yo esté harto, eso me hace que sea de zanahorias que de perdices. Con esto dio fin a su larga plática Sancho, temiendo siempre don Quijote que había de decir en ella millares de disparates; y, cuando le vio acabar con tan pocos, dio en su corazón gracias al cielo, y el duque abrazó a Sancho, y le dijo que le pesaba en el alma de que hubiese dejado tan presto el gobierno; pero que él haría de suerte que se le diese en su estado otro oficio de menos carga y de más provecho. Abrazóle la duquesa asimismo, y mandó que le regalasen, porque daba señales de venir mal molido y peor parado. Capítulo LVI. De la descomunal y nunca vista batalla que pasó entre don Quijote de la Mancha y el lacayo Tosilos, en la defensa de la hija de la dueña doña Rodríguez No quedaron arrepentidos los duques de la burla hecha a Sancho Panza del gobierno que le dieron; y más, que aquel mismo día vino su mayordomo, y les contó punto por punto, todas casi, las palabras y acciones que Sancho había dicho y hecho en aquellos días, y finalmente les encareció el asalto de la ínsula, y el miedo de Sancho, y su salida, de que no pequeño gusto recibieron. Después desto, cuenta la historia que se llegó el día de la batalla aplazada, y, habiendo el duque una y muy muchas veces advertido a su lacayo Tosilos cómo se había de avenir con don Quijote para vencerle sin matarle ni herirle, ordenó que se quitasen los hierros a las lanzas, diciendo a don Quijote que no permitía la cristiandad, de que él se preciaba, que aquella batalla fuese con tanto riesgo y peligro de las vidas, y que se contentase con que le daba campo franco en su tierra, puesto que iba contra el decreto del Santo Concilio, que prohíbe los tales desafíos, y no quisiese llevar por todo rigor aquel trance tan fuerte. Don Quijote dijo que Su Excelencia dispusiese las cosas de aquel negocio como más fuese servido; que él le obedecería en todo. Llegado, pues, el temeroso día, y habiendo mandado el duque que delante de la plaza del castillo se hiciese un espacioso cadahalso, donde estuviesen los jueces del campo y las dueñas, madre y hija, demandantes, había acudido de todos los lugares y aldeas circunvecinas infinita gente, a ver la novedad de aquella batalla; que nunca otra tal no habían visto, ni oído decir en aquella tierra los que vivían ni los que habían muerto. El primero que entró en el campo y estacada fue el maestro de las ceremonias, que tanteó el campo, y le paseó todo, porque en él no hubiese algún engaño, ni cosa encubierta donde se tropezase y cayese; luego entraron las dueñas y se sentaron en sus asientos, cubiertas con los mantos hasta los ojos y aun hasta los pechos, con muestras de no pequeño sentimiento. Presente don Quijote en la estacada, de allí a poco, acompañado de muchas trompetas, asomó por una parte de la plaza, sobre un poderoso caballo, hundiéndola toda, el grande lacayo Tosilos, calada la visera y todo encambronado, con unas fuertes y lucientes armas. El caballo mostraba ser frisón, ancho y de color tordillo; de cada mano y pie le pendía una arroba de lana. Venía el valeroso combatiente bien informado del duque su señor de cómo se había de portar con el valeroso don Quijote de la Mancha, advertido que en ninguna manera le matase, sino que procurase huir el primer encuentro por escusar el peligro de su muerte, que estaba cierto si de lleno en lleno le encontrase. Paseó la plaza, y, llegando donde las dueñas estaban, se puso algún tanto a mirar a la que por esposo le pedía. Llamó el maese de campo a don Quijote, que ya se había presentado en la plaza, y junto con Tosilos habló a las dueñas, preguntándoles si consentían que volviese por su derecho don Quijote de la Mancha. Ellas dijeron que sí, y que todo lo que en aquel caso hiciese lo daban por bien hecho, por firme y por valedero. Ya en este tiempo estaban el duque y la duquesa puestos en una galería que caía sobre la estacada, toda la cual estaba coronada de infinita gente, que esperaba ver el riguroso trance nunca visto. Fue condición de los combatientes que si don Quijote vencía, su contrario se había de casar con la hija de doña Rodríguez; y si él fuese vencido, quedaba libre su contendor de la palabra que se le pedía, sin dar otra satisfación alguna. Partióles el maestro de las ceremonias el sol, y puso a los dos cada uno en el puesto donde habían de estar. Sonaron los atambores, llenó el aire el son de las trompetas, temblaba debajo de los pies la tierra; estaban suspensos los corazones de la mirante turba, temiendo unos y esperando otros el bueno o el mal suceso de aquel caso. Finalmente, don Quijote, encomendándose de todo su corazón a Dios Nuestro Señor y a la señora Dulcinea del Toboso, estaba aguardando que se le diese señal precisa de la arremetida; empero, nuestro lacayo tenía diferentes pensamientos: no pensaba él sino en lo que agora diré: Parece ser que, cuando estuvo mirando a su enemiga, le pareció la más hermosa mujer que había visto en toda su vida, y el niño ceguezuelo, a quien suelen llamar de ordinario Amor por esas calles, no quiso perder la ocasión que se le ofreció de triunfar de una alma lacayuna y ponerla en la lista de sus trofeos; y así, llegándose a él bonitamente, sin que nadie le viese, le envasó al pobre lacayo una flecha de dos varas por el lado izquierdo, y le pasó el corazón de parte a parte; y púdolo hacer bien al seguro, porque el Amor es invisible, y entra y sale por do quiere, sin que nadie le pida cuenta de sus hechos. Digo, pues, que, cuando dieron la señal de la arremetida, estaba nuestro lacayo transportado, pensando en la hermosura de la que ya había hecho señora de su libertad, y así, no atendió al son de la trompeta, como hizo don Quijote, que, apenas la hubo oído, cuando arremetió, y, a todo el correr que permitía Rocinante, partió contra su enemigo; y, viéndole partir su buen escudero Sancho, dijo a grandes voces: -¡Dios te guíe, nata y flor de los andantes caballeros! ¡Dios te dé la vitoria, pues llevas la razón de tu parte! Y, aunque Tosilos vio venir contra sí a don Quijote, no se movió un paso de su puesto; antes, con grandes voces, llamó al maese de campo, el cual venido a ver lo que quería, le dijo: -Señor, ¿esta batalla no se hace porque yo me case, o no me case, con aquella señora? -Así es -le fue respondido. -Pues yo -dijo el lacayo- soy temeroso de mi conciencia, y pondríala en gran cargo si pasase adelante en esta batalla; y así, digo que yo me doy por vencido y que quiero casarme luego con aquella señora. Quedó admirado el maese de campo de las razones de Tosilos; y, como era uno de los sabidores de la máquina de aquel caso, no le supo responder palabra. Detúvose don Quijote en la mitad de su carrera, viendo que su enemigo no le acometía. El duque no sabía la ocasión porque no se pasaba adelante en la batalla, pero el maese de campo le fue a declarar lo que Tosilos decía, de lo que quedó suspenso y colérico en estremo. En tanto que esto pasaba, Tosilos se llegó adonde doña Rodríguez estaba, y dijo a grandes voces: -Yo, señora, quiero casarme con vuestra hija, y no quiero alcanzar por pleitos ni contiendas lo que puedo alcanzar por paz y sin peligro de la muerte. Oyó esto el valeroso don Quijote, y dijo: -Pues esto así es, yo quedo libre y suelto de mi promesa: cásense en hora buena, y, pues Dios Nuestro Señor se la dio, San Pedro se la bendiga. El duque había bajado a la plaza del castillo, y, llegándose a Tosilos, le dijo: -¿Es verdad, caballero, que os dais por vencido, y que, instigado de vuestra temerosa conciencia, os queréis casar con esta doncella? -Sí, señor -respondió Tosilos. -Él hace muy bien -dijo a esta sazón Sancho Panza-, porque lo que has de dar al mur, dalo al gato, y sacarte ha de cuidado. Ãbase Tosilos desenlazando la celada, y rogaba que apriesa le ayudasen, porque le iban faltando los espíritus del aliento, y no podía verse encerrado tanto tiempo en la estrecheza de aquel aposento. Quitáronsela apriesa, y quedó descubierto y patente su rostro de lacayo. Viendo lo cual doña Rodríguez y su hija, dando grandes voces, dijeron: -¡Éste es engaño, engaño es éste! ¡A Tosilos, el lacayo del duque mi señor, nos han puesto en lugar de mi verdadero esposo! ¡Justicia de Dios y del Rey, de tanta malicia, por no decir bellaquería! -No vos acuitéis, señoras -dijo don Quijote-, que ni ésta es malicia ni es bellaquería; y si la es, y no ha sido la causa el duque, sino los malos encantadores que me persiguen, los cuales, invidiosos de que yo alcanzase la gloria deste vencimiento, han convertido el rostro de vuestro esposo en el de este que decís que es lacayo del duque. Tomad mi consejo, y, a pesar de la malicia de mis enemigos, casaos con él, que sin duda es el mismo que vos deseáis alcanzar por esposo. El duque, que esto oyó, estuvo por romper en risa toda su cólera, y dijo: -Son tan extraordinarias las cosas que suceden al señor don Quijote que estoy por creer que este mi lacayo no lo es; pero usemos deste ardid y maña: dilatemos el casamiento quince días, si quieren, y tengamos encerrado a este personaje que nos tiene dudosos, en los cuales podría ser que volviese a su prístina figura; que no ha de durar tanto el rancor que los encantadores tienen al señor don Quijote, y más, yéndoles tan poco en usar estos embelecos y transformaciones. -¡Oh señor! -dijo Sancho-, que ya tienen estos malandrines por uso y costumbre de mudar las cosas, de unas en otras, que tocan a mi amo. Un caballero que venció los días pasados, llamado el de los Espejos, le volvieron en la figura del bachiller Sansón Carrasco, natural de nuestro pueblo y grande amigo nuestro, y a mi señora Dulcinea del Toboso la han vuelto en una rústica labradora; y así, imagino que este lacayo ha de morir y vivir lacayo todos los días de su vida. A lo que dijo la hija de Rodríguez: -Séase quien fuere este que me pide por esposa, que yo se lo agradezco; que más quiero ser mujer legítima de un lacayo que no amiga y burlada de un caballero, puesto que el que a mí me burló no lo es. En resolución, todos estos cuentos y sucesos pararon en que Tosilos se recogiese, hasta ver en qué paraba su transformación; aclamaron todos la vitoria por don Quijote, y los más quedaron tristes y melancólicos de ver que no se habían hecho pedazos los tan esperados combatientes, bien así como los mochachos quedan tristes cuando no sale el ahorcado que esperan, porque le ha perdonado, o la parte, o la justicia. Fuese la gente, volviéronse el duque y don Quijote al castillo, encerraron a Tosilos, quedaron doña Rodríguez y su hija contentísimas de ver que, por una vía o por otra, aquel caso había de parar en casamiento, y Tosilos no esperaba menos. Capítulo LVII. Que trata de cómo don Quijote se despidió del duque, y de lo que le sucedió con la discreta y desenvuelta Altisidora, doncella de la duquesa Ya le pareció a don Quijote que era bien salir de tanta ociosidad como la que en aquel castillo tenía; que se imaginaba ser grande la falta que su persona hacía en dejarse estar encerrado y perezoso entre los infinitos regalos y deleites que como a caballero andante aquellos señores le hacían, y parecíale que había de dar cuenta estrecha al cielo de aquella ociosidad y encerramiento; y así, pidió un día licencia a los duques para partirse. Diéronsela, con muestras de que en gran manera les pesaba de que los dejase. Dio la duquesa las cartas de su mujer a Sancho Panza, el cual lloró con ellas, y dijo: -¿Quién pensara que esperanzas tan grandes como las que en el pecho de mi mujer Teresa Panza engendraron las nuevas de mi gobierno habían de parar en volverme yo agora a las arrastradas aventuras de mi amo don Quijote de la Mancha? Con todo esto, me contento de ver que mi Teresa correspondió a ser quien es, enviando las bellotas a la duquesa; que, a no habérselas enviado, quedando yo pesaroso, me mostrara ella desagradecida. Lo que me consuela es que esta dádiva no se le puede dar nombre de cohecho, porque ya tenía yo el gobierno cuando ella las envió, y está puesto en razón que los que reciben algún beneficio, aunque sea con niñerías, se muestren agradecidos. En efecto, yo entré desnudo en el gobierno y salgo desnudo dél; y así, podré decir con segura conciencia, que no es poco: "Desnudo nací, desnudo me hallo: ni pierdo ni gano". Esto pasaba entre sí Sancho el día de la partida; y, saliendo don Quijote, habiéndose despedido la noche antes de los duques, una mañana se presentó armado en la plaza del castillo. Mirábanle de los corredores toda la gente del castillo, y asimismo los duques salieron a verle. Estaba Sancho sobre su rucio, con sus alforjas, maleta y repuesto, contentísimo, porque el mayordomo del duque, el que fue la Trifaldi, le había dado un bolsico con docientos escudos de oro, para suplir los menesteres del camino, y esto aún no lo sabía don Quijote. Estando, como queda dicho, mirándole todos, a deshora, entre las otras dueñas y doncellas de la duquesa, que le miraban, alzó la voz la desenvuelta y discreta Altisidora, y en son lastimero dijo: -Escucha, mal caballero; detén un poco las riendas; no fatigues las ijadas de tu mal regida bestia. Mira, falso, que no huyas de alguna serpiente fiera, sino de una corderilla que está muy lejos de oveja. Tú has burlado, monstruo horrendo, la más hermosa doncella que Dïana vio en sus montes, que Venus miró en sus selvas. Cruel Vireno, fugitivo Eneas, Barrabás te acompañe; allá te avengas. Tú llevas, ¡llevar impío!, en las garras de tus cerras las entrañas de una humilde, como enamorada, tierna. Llévaste tres tocadores, y unas ligas, de unas piernas que al mármol puro se igualan en lisas, blancas y negras. Llévaste dos mil suspiros, que, a ser de fuego, pudieran abrasar a dos mil Troyas, si dos mil Troyas hubiera. Cruel Vireno, fugitivo Eneas, Barrabás te acompañe; allá te avengas. De ese Sancho, tu escudero, las entrañas sean tan tercas y tan duras, que no salga de su encanto Dulcinea. De la culpa que tú tienes lleve la triste la pena; que justos por pecadores tal vez pagan en mi tierra. Tus más finas aventuras en desventuras se vuelvan, en sueños tus pasatiempos, en olvidos tus firmezas. Cruel Vireno, fugitivo Eneas, Barrabás te acompañe; allá te avengas. Seas tenido por falso desde Sevilla a Marchena, desde Granada hasta Loja, de Londres a Inglaterra. Si jugares al reinado, los cientos, o la primera, los reyes huyan de ti; ases ni sietes no veas. Si te cortares los callos, sangre las heridas viertan, y quédente los raigones si te sacares las muelas. Cruel Vireno, fugitivo Eneas, Barrabás te acompañe; allá te avengas. En tanto que, de la suerte que se ha dicho, se quejaba la lastimada Altisidora, la estuvo mirando don Quijote, y, sin responderla palabra, volviendo el rostro a Sancho, le dijo: -Por el siglo de tus pasados, Sancho mío, te conjuro que me digas una verdad. Dime, ¿llevas por ventura los tres tocadores y las ligas que esta enamorada doncella dice? A lo que Sancho respondió: -Los tres tocadores sí llevo; pero las ligas, como por los cerros de Úbeda. Quedó la duquesa admirada de la desenvoltura de Altisidora, que, aunque la tenía por atrevida, graciosa y desenvuelta, no en grado que se atreviera a semejantes desenvolturas; y, como no estaba advertida desta burla, creció más su admiración. El duque quiso reforzar el donaire, y dijo: -No me parece bien, señor caballero, que, habiendo recebido en este mi castillo el buen acogimiento que en él se os ha hecho, os hayáis atrevido a llevaros tres tocadores, por lo menos, si por lo más las ligas de mi doncella; indicios son de mal pecho y muestras que no corresponden a vuestra fama. Volvedle las ligas; si no, yo os desafío a mortal batalla, sin tener temor que malandrines encantadores me vuelvan ni muden el rostro, como han hecho en el de Tosilos mi lacayo, el que entró con vos en batalla. -No quiera Dios -respondió don Quijote- que yo desenvaine mi espada contra vuestra ilustrísima persona, de quien tantas mercedes he recebido; los tocadores volveré, porque dice Sancho que los tiene; las ligas es imposible, porque ni yo las he recebido ni él tampoco; y si esta vuestra doncella quisiere mirar sus escondrijos, a buen seguro que las halle. Yo, señor duque, jamás he sido ladrón, ni lo pienso ser en toda mi vida, como Dios no me deje de su mano. Esta doncella habla, como ella dice, como enamorada, de lo que yo no le tengo culpa; y así, no tengo de qué pedirle perdón ni a ella ni a Vuestra Excelencia, a quien suplico me tenga en mejor opinión, y me dé de nuevo licencia para seguir mi camino. -Déosle Dios tan bueno -dijo la duquesa-, señor don Quijote, que siempre oigamos buenas nuevas de vuestras fechurías. Y andad con Dios; que, mientras más os detenéis, más aumentáis el fuego en los pechos de las doncellas que os miran; y a la mía yo la castigaré de modo, que de aquí adelante no se desmande con la vista ni con las palabras. -Una no más quiero que me escuches, ¡oh valeroso don Quijote! -dijo entonces Altisidora-; y es que te pido perdón del latrocinio de las ligas, porque, en Dios y en mi ánima que las tengo puestas, y he caído en el descuido del que yendo sobre el asno, le buscaba. -¿No lo dije yo? -dijo Sancho-. ¡Bonico soy yo para encubrir hurtos! Pues, a quererlos hacer, de paleta me había venido la ocasión en mi gobierno. Abajó la cabeza don Quijote y hizo reverencia a los duques y a todos los circunstantes, y, volviendo las riendas a Rocinante, siguiéndole Sancho sobre el rucio, se salió del castillo, enderezando su camino a Zaragoza. Capítulo LVIII. Que trata de cómo menudearon sobre don Quijote aventuras tantas, que no se daban vagar unas a otras Cuando don Quijote se vio en la campaña rasa, libre y desembarazado de los requiebros de Altisidora, le pareció que estaba en su centro, y que los espíritus se le renovaban para proseguir de nuevo el asumpto de sus caballerías, y, volviéndose a Sancho, le dijo: -La libertad, Sancho, es uno de los más preciosos dones que a los hombres dieron los cielos; con ella no pueden igualarse los tesoros que encierra la tierra ni el mar encubre; por la libertad, así como por la honra, se puede y debe aventurar la vida, y, por el contrario, el cautiverio es el mayor mal que puede venir a los hombres. Digo esto, Sancho, porque bien has visto el regalo, la abundancia que en este castillo que dejamos hemos tenido; pues en metad de aquellos banquetes sazonados y de aquellas bebidas de nieve, me parecía a mí que estaba metido entre las estrechezas de la hambre, porque no lo gozaba con la libertad que lo gozara si fueran míos; que las obligaciones de las recompensas de los beneficios y mercedes recebidas son ataduras que no dejan campear al ánimo libre. ¡Venturoso aquél a quien el cielo dio un pedazo de pan, sin que le quede obligación de agradecerlo a otro que al mismo cielo! -Con todo eso -dijo Sancho- que vuesa merced me ha dicho, no es bien que se quede sin agradecimiento de nuestra parte docientos escudos de oro que en una bolsilla me dio el mayordomo del duque, que como píctima y confortativo la llevo puesta sobre el corazón, para lo que se ofreciere; que no siempre hemos de hallar castillos donde nos regalen, que tal vez toparemos con algunas ventas donde nos apaleen. En estos y otros razonamientos iban los andantes, caballero y escudero, cuando vieron, habiendo andado poco más de una legua, que encima de la yerba de un pradillo verde, encima de sus capas, estaban comiendo hasta una docena de hombres, vestidos de labradores. Junto a sí tenían unas como sábanas blancas, con que cubrían alguna cosa que debajo estaba; estaban empinadas y tendidas, y de trecho a trecho puestas. Llegó don Quijote a los que comían, y, saludándolos primero cortésmente, les preguntó que qué era lo que aquellos lienzos cubrían. Uno dellos le respondió: -Señor, debajo destos lienzos están unas imágines de relieve y entabladura que han de servir en un retablo que hacemos en nuestra aldea; llevámoslas cubiertas, porque no se desfloren, y en hombros, porque no se quiebren. -Si sois servidos -respondió don Quijote-, holgaría de verlas, pues imágines que con tanto recato se llevan, sin duda deben de ser buenas. -Y ¡cómo si lo son! -dijo otro-. Si no, dígalo lo que cuesta: que en verdad que no hay ninguna que no esté en más de cincuenta ducados; y, porque vea vuestra merced esta verdad, espere vuestra merced, y verla ha por vista de ojos. Y, levantándose, dejó de comer y fue a quitar la cubierta de la primera imagen, que mostró ser la de San Jorge puesto a caballo, con una serpiente enroscada a los pies y la lanza atravesada por la boca, con la fiereza que suele pintarse. Toda la imagen parecía una ascua de oro, como suele decirse. Viéndola don Quijote, dijo: -Este caballero fue uno de los mejores andantes que tuvo la milicia divina: llamóse don San Jorge, y fue además defendedor de doncellas. Veamos esta otra. Descubrióla el hombre, y pareció ser la de San Martín puesto a caballo, que partía la capa con el pobre; y, apenas la hubo visto don Quijote, cuando dijo: -Este caballero también fue de los aventureros cristianos, y creo que fue más liberal que valiente, como lo puedes echar de ver, Sancho, en que está partiendo la capa con el pobre y le da la mitad; y sin duda debía de ser entonces invierno, que, si no, él se la diera toda, según era de caritativo. -No debió de ser eso -dijo Sancho-, sino que se debió de atener al refrán que dicen: que para dar y tener, seso es menester. Rióse don Quijote y pidió que quitasen otro lienzo, debajo del cual se descubrió la imagen del Patrón de las Españas a caballo, la espada ensangrentada, atropellando moros y pisando cabezas; y, en viéndola, dijo don Quijote: -Éste sí que es caballero, y de las escuadras de Cristo; éste se llama don San Diego Matamoros, uno de los más valientes santos y caballeros que tuvo el mundo y tiene agora el cielo. Luego descubrieron otro lienzo, y pareció que encubría la caída de San Pablo del caballo abajo, con todas las circunstancias que en el retablo de su conversión suelen pintarse. Cuando le vido tan al vivo, que dijeran que Cristo le hablaba y Pablo respondía. -Éste -dijo don Quijote- fue el mayor enemigo que tuvo la Iglesia de Dios Nuestro Señor en su tiempo, y el mayor defensor suyo que tendrá jamás: caballero andante por la vida, y santo a pie quedo por la muerte, trabajador incansable en la viña del Señor, doctor de las gentes, a quien sirvieron de escuelas los cielos y de catedrático y maestro que le enseñase el mismo Jesucristo. No había más imágines, y así, mandó don Quijote que las volviesen a cubrir, y dijo a los que las llevaban: -Por buen agüero he tenido, hermanos, haber visto lo que he visto, porque estos santos y caballeros profesaron lo que yo profeso, que es el ejercicio de las armas; sino que la diferencia que hay entre mí y ellos es que ellos fueron santos y pelearon a lo divino, y yo soy pecador y peleo a lo humano. Ellos conquistaron el cielo a fuerza de brazos, porque el cielo padece fuerza, y yo hasta agora no sé lo que conquisto a fuerza de mis trabajos; pero si mi Dulcinea del Toboso saliese de los que padece, mejorándose mi ventura y adobándoseme el juicio, podría ser que encaminase mis pasos por mejor camino del que llevo. -Dios lo oiga y el pecado sea sordo -dijo Sancho a esta ocasión. Admiráronse los hombres, así de la figura como de las razones de don Quijote, sin entender la mitad de lo que en ellas decir quería. Acabaron de comer, cargaron con sus imágines, y, despidiéndose de don Quijote, siguieron su viaje. Quedó Sancho de nuevo como si jamás hubiera conocido a su señor, admirado de lo que sabía, pareciéndole que no debía de haber historia en el mundo ni suceso que no lo tuviese cifrado en la uña y clavado en la memoria, y díjole: -En verdad, señor nuestramo, que si esto que nos ha sucedido hoy se puede llamar aventura, ella ha sido de las más suaves y dulces que en todo el discurso de nuestra peregrinación nos ha sucedido: della habemos salido sin palos y sobresalto alguno, ni hemos echado mano a las espadas, ni hemos batido la tierra con los cuerpos, ni quedamos hambrientos. Bendito sea Dios, que tal me ha dejado ver con mis propios ojos. -Tú dices bien, Sancho -dijo don Quijote-, pero has de advertir que no todos los tiempos son unos, ni corren de una misma suerte, y esto que el vulgo suele llamar comúnmente agüeros, que no se fundan sobre natural razón alguna, del que es discreto han de ser tenidos y juzgar por buenos acontecimientos. Levántase uno destos agoreros por la mañana, sale de su casa, encuéntrase con un fraile de la orden del bienaventurado San Francisco, y, como si hubiera encontrado con un grifo, vuelve las espaldas y vuélvese a su casa. Derrámasele al otro Mendoza la sal encima de la mesa, y derrámasele a él la melancolía por el corazón, como si estuviese obligada la naturaleza a dar señales de las venideras desgracias con cosas tan de poco momento como las referidas. El discreto y cristiano no ha de andar en puntillos con lo que quiere hacer el cielo. Llega Cipión a Ãfrica, tropieza en saltando en tierra, tiénenlo por mal agüero sus soldados; pero él, abrazándose con el suelo, dijo: ''No te me podrás huir, Ãfrica, porque te tengo asida y entre mis brazos''. Así que, Sancho, el haber encontrado con estas imágines ha sido para mí felicísimo acontecimiento. -Yo así lo creo -respondió Sancho-, y querría que vuestra merced me dijese qué es la causa por que dicen los españoles cuando quieren dar alguna batalla, invocando aquel San Diego Matamoros: "¡Santiago, y cierra, España!" ¿Está por ventura España abierta, y de modo que es menester cerrarla, o qué ceremonia es ésta? -Simplicísimo eres, Sancho -respondió don Quijote-; y mira que este gran caballero de la cruz bermeja háselo dado Dios a España por patrón y amparo suyo, especialmente en los rigurosos trances que con los moros los españoles han tenido; y así, le invocan y llaman como a defensor suyo en todas las batallas que acometen, y muchas veces le han visto visiblemente en ellas, derribando, atropellando, destruyendo y matando los agarenos escuadrones; y desta verdad te pudiera traer muchos ejemplos que en las verdaderas historias españolas se cuentan. Mudó Sancho plática, y dijo a su amo: -Maravillado estoy, señor, de la desenvoltura de Altisidora, la doncella de la duquesa: bravamente la debe de tener herida y traspasada aquel que llaman Amor, que dicen que es un rapaz ceguezuelo que, con estar lagañoso, o, por mejor decir, sin vista, si toma por blanco un corazón, por pequeño que sea, le acierta y traspasa de parte a parte con sus flechas. He oído decir también que en la vergüenza y recato de las doncellas se despuntan y embotan las amorosas saetas, pero en esta Altisidora más parece que se aguzan que despuntan. -Advierte, Sancho -dijo don Quijote-, que el amor ni mira respetos ni guarda términos de razón en sus discursos, y tiene la misma condición que la muerte: que así acomete los altos alcázares de los reyes como las humildes chozas de los pastores, y cuando toma entera posesión de una alma, lo primero que hace es quitarle el temor y la vergüenza; y así, sin ella declaró Altisidora sus deseos, que engendraron en mi pecho antes confusión que lástima. -¡Crueldad notoria! -dijo Sancho-. ¡Desagradecimiento inaudito! Yo de mí sé decir que me rindiera y avasallara la más mínima razón amorosa suya. ¡Hideputa, y qué corazón de mármol, qué entrañas de bronce y qué alma de argamasa! Pero no puedo pensar qué es lo que vio esta doncella en vuestra merced que así la rindiese y avasallase: qué gala, qué brío, qué donaire, qué rostro, que cada cosa por sí déstas, o todas juntas, le enamoraron; que en verdad en verdad que muchas veces me paro a mirar a vuestra merced desde la punta del pie hasta el último cabello de la cabeza, y que veo más cosas para espantar que para enamorar; y, habiendo yo también oído decir que la hermosura es la primera y principal parte que enamora, no teniendo vuestra merced ninguna, no sé yo de qué se enamoró la pobre. -Advierte, Sancho -respondió don Quijote-, que hay dos maneras de hermosura: una del alma y otra del cuerpo; la del alma campea y se muestra en el entendimiento, en la honestidad, en el buen proceder, en la liberalidad y en la buena crianza, y todas estas partes caben y pueden estar en un hombre feo; y cuando se pone la mira en esta hermosura, y no en la del cuerpo, suele nacer el amor con ímpetu y con ventajas. Yo, Sancho, bien veo que no soy hermoso, pero también conozco que no soy disforme; y bástale a un hombre de bien no ser monstruo para ser bien querido, como tenga los dotes del alma que te he dicho. En estas razones y pláticas se iban entrando por una selva que fuera del camino estaba, y a deshora, sin pensar en ello, se halló don Quijote enredado entre unas redes de hilo verde, que desde unos árboles a otros estaban tendidas; y, sin poder imaginar qué pudiese ser aquello, dijo a Sancho: -Paréceme, Sancho, que esto destas redes debe de ser una de las más nuevas aventuras que pueda imaginar. Que me maten si los encantadores que me persiguen no quieren enredarme en ellas y detener mi camino, como en venganza de la riguridad que con Altisidora he tenido. Pues mándoles yo que, aunque estas redes, si como son hechas de hilo verde fueran de durísimos diamantes, o más fuertes que aquélla con que el celoso dios de los herreros enredó a Venus y a Marte, así la rompiera como si fuera de juncos marinos o de hilachas de algodón. Y, queriendo pasar adelante y romperlo todo, al improviso se le ofrecieron delante, saliendo de entre unos árboles, dos hermosísimas pastoras; a lo menos, vestidas como pastoras, sino que los pellicos y sayas eran de fino brocado, digo, que las sayas eran riquísimos faldellines de tabí de oro. Traían los cabellos sueltos por las espaldas, que en rubios podían competir con los rayos del mismo sol; los cuales se coronaban con dos guirnaldas de verde laurel y de rojo amaranto tejidas. La edad, al parecer, ni bajaba de los quince ni pasaba de los diez y ocho. Vista fue ésta que admiró a Sancho, suspendió a don Quijote, hizo parar al sol en su carrera para verlas, y tuvo en maravilloso silencio a todos cuatro. En fin, quien primero habló fue una de las dos zagalas, que dijo a don Quijote: -Detened, señor caballero, el paso, y no rompáis las redes, que no para daño vuestro, sino para nuestro pasatiempo, ahí están tendidas; y, porque sé que nos habéis de preguntar para qué se han puesto y quién somos, os lo quiero decir en breves palabras. En una aldea que está hasta dos leguas de aquí, donde hay mucha gente principal y muchos hidalgos y ricos, entre muchos amigos y parientes se concertó que con sus hijos, mujeres y hijas, vecinos, amigos y parientes, nos viniésemos a holgar a este sitio, que es uno de los más agradables de todos estos contornos, formando entre todos una nueva y pastoril Arcadia, vistiéndonos las doncellas de zagalas y los mancebos de pastores. Traemos estudiadas dos églogas, una del famoso poeta Garcilaso, y otra del excelentísimo Camoes, en su misma lengua portuguesa, las cuales hasta agora no hemos representado. Ayer fue el primero día que aquí llegamos; tenemos entre estos ramos plantadas algunas tiendas, que dicen se llaman de campaña, en el margen de un abundoso arroyo que todos estos prados fertiliza; tendimos la noche pasada estas redes de estos árboles para engañar los simples pajarillos, que, ojeados con nuestro ruido, vinieren a dar en ellas. Si gustáis, señor, de ser nuestro huésped, seréis agasajado liberal y cortésmente; porque por agora en este sitio no ha de entrar la pesadumbre ni la melancolía. Calló y no dijo más. A lo que respondió don Quijote: -Por cierto, hermosísima señora, que no debió de quedar más suspenso ni admirado Anteón cuando vio al improviso bañarse en las aguas a Diana, como yo he quedado atónito en ver vuestra belleza. Alabo el asumpto de vuestros entretenimientos, y el de vuestros ofrecimientos agradezco; y, si os puedo servir, con seguridad de ser obedecidas me lo podéis mandar; porque no es ésta la profesión mía, sino de mostrarme agradecido y bienhechor con todo género de gente, en especial con la principal que vuestras personas representa; y, si como estas redes, que deben de ocupar algún pequeño espacio, ocuparan toda la redondez de la tierra, buscara yo nuevos mundos por do pasar sin romperlas; y porque deis algún crédito a esta mi exageración, ved que os lo promete, por lo menos, don Quijote de la Mancha, si es que ha llegado a vuestros oídos este nombre. -¡Ay, amiga de mi alma -dijo entonces la otra zagala-, y qué ventura tan grande nos ha sucedido! ¿Ves este señor que tenemos delante? Pues hágote saber que es el más valiente, y el más enamorado, y el más comedido que tiene el mundo, si no es que nos miente y nos engaña una historia que de sus hazañas anda impresa y yo he leído. Yo apostaré que este buen hombre que viene consigo es un tal Sancho Panza, su escudero, a cuyas gracias no hay ningunas que se le igualen. -Así es la verdad -dijo Sancho-: que yo soy ese gracioso y ese escudero que vuestra merced dice, y este señor es mi amo, el mismo don Quijote de la Mancha historiado y referido. -¡Ay! -dijo la otra-. Supliquémosle, amiga, que se quede; que nuestros padres y nuestros hermanos gustarán infinito dello, que también he oído yo decir de su valor y de sus gracias lo mismo que tú me has dicho, y, sobre todo, dicen dél que es el más firme y más leal enamorado que se sabe, y que su dama es una tal Dulcinea del Toboso, a quien en toda España la dan la palma de la hermosura. -Con razón se la dan -dijo don Quijote-, si ya no lo pone en duda vuestra sin igual belleza. No os canséis, señoras, en detenerme, porque las precisas obligaciones de mi profesión no me dejan reposar en ningún cabo. Llegó, en esto, adonde los cuatro estaban un hermano de una de las dos pastoras, vestido asimismo de pastor, con la riqueza y galas que a las de las zagalas correspondía; contáronle ellas que el que con ellas estaba era el valeroso don Quijote de la Mancha, y el otro, su escudero Sancho, de quien tenía él ya noticia, por haber leído su historia. Ofreciósele el gallardo pastor, pidióle que se viniese con él a sus tiendas; húbolo de conceder don Quijote, y así lo hizo. Llegó, en esto, el ojeo, llenáronse las redes de pajarillos diferentes que, engañados de la color de las redes, caían en el peligro de que iban huyendo. Juntáronse en aquel sitio más de treinta personas, todas bizarramente de pastores y pastoras vestidas, y en un instante quedaron enteradas de quiénes eran don Quijote y su escudero, de que no poco contento recibieron, porque ya tenían dél noticia por su historia. Acudieron a las tiendas, hallaron las mesas puestas, ricas, abundantes y limpias; honraron a don Quijote dándole el primer lugar en ellas; mirábanle todos, y admirábanse de verle. Finalmente, alzados los manteles, con gran reposo alzó don Quijote la voz, y dijo: -Entre los pecados mayores que los hombres cometen, aunque algunos dicen que es la soberbia, yo digo que es el desagradecimiento, ateniéndome a lo que suele decirse: que de los desagradecidos está lleno el infierno. Este pecado, en cuanto me ha sido posible, he procurado yo huir desde el instante que tuve uso de razón; y si no puedo pagar las buenas obras que me hacen con otras obras, pongo en su lugar los deseos de hacerlas, y cuando éstos no bastan, las publico; porque quien dice y publica las buenas obras que recibe, también las recompensara con otras, si pudiera; porque, por la mayor parte, los que reciben son inferiores a los que dan; y así, es Dios sobre todos, porque es dador sobre todos y no pueden corresponder las dádivas del hombre a las de Dios con igualdad, por infinita distancia; y esta estrecheza y cortedad, en cierto modo, la suple el agradecimiento. Yo, pues, agradecido a la merced que aquí se me ha hecho, no pudiendo corresponder a la misma medida, conteniéndome en los estrechos límites de mi poderío, ofrezco lo que puedo y lo que tengo de mi cosecha; y así, digo que sustentaré dos días naturales en metad de ese camino real que va a Zaragoza, que estas señoras zagalas contrahechas que aquí están son las más hermosas doncellas y más corteses que hay en el mundo, excetado sólo a la sin par Dulcinea del Toboso, única señora de mis pensamientos, con paz sea dicho de cuantos y cuantas me escuchan. Oyendo lo cual, Sancho, que con grande atención le había estado escuchando, dando una gran voz, dijo: -¿Es posible que haya en el mundo personas que se atrevan a decir y a jurar que este mi señor es loco? Digan vuestras mercedes, señores pastores: ¿hay cura de aldea, por discreto y por estudiante que sea, que pueda decir lo que mi amo ha dicho, ni hay caballero andante, por más fama que tenga de valiente, que pueda ofrecer lo que mi amo aquí ha ofrecido? Volvióse don Quijote a Sancho, y, encendido el rostro y colérico, le dijo: -¿Es posible, ¡oh Sancho!, que haya en todo el orbe alguna persona que diga que no eres tonto, aforrado de lo mismo, con no sé qué ribetes de malicioso y de bellaco? ¿Quién te mete a ti en mis cosas, y en averiguar si soy discreto o majadero? Calla y no me repliques, sino ensilla, si está desensillado Rocinante: vamos a poner en efecto mi ofrecimiento, que, con la razón que va de mi parte, puedes dar por vencidos a todos cuantos quisieren contradecirla. Y, con gran furia y muestras de enojo, se levantó de la silla, dejando admirados a los circunstantes, haciéndoles dudar si le podían tener por loco o por cuerdo. Finalmente, habiéndole persuadido que no se pusiese en tal demanda, que ellos daban por bien conocida su agradecida voluntad y que no eran menester nuevas demostraciones para conocer su ánimo valeroso, pues bastaban las que en la historia de sus hechos se referían, con todo esto, salió don Quijote con su intención; y, puesto sobre Rocinante, embrazando su escudo y tomando su lanza, se puso en la mitad de un real camino que no lejos del verde prado estaba. Siguióle Sancho sobre su rucio, con toda la gente del pastoral rebaño, deseosos de ver en qué paraba su arrogante y nunca visto ofrecimiento. Puesto, pues, don Quijote en mitad del camino -como os he dicho-, hirió el aire con semejantes palabras: -¡Oh vosotros, pasajeros y viandantes, caballeros, escuderos, gente de a pie y de a caballo que por este camino pasáis, o habéis de pasar en estos dos días siguientes! Sabed que don Quijote de la Mancha, caballero andante, está aquí puesto para defender que a todas las hermosuras y cortesías del mundo exceden las que se encierran en las ninfas habitadoras destos prados y bosques, dejando a un lado a la señora de mi alma Dulcinea del Toboso. Por eso, el que fuere de parecer contrario, acuda, que aquí le espero. Dos veces repitió estas mismas razones, y dos veces no fueron oídas de ningún aventurero; pero la suerte, que sus cosas iba encaminando de mejor en mejor, ordenó que de allí a poco se descubriese por el camino muchedumbre de hombres de a caballo, y muchos dellos con lanzas en las manos, caminando todos apiñados, de tropel y a gran priesa. No los hubieron bien visto los que con don Quijote estaban, cuando, volviendo las espaldas, se apartaron bien lejos del camino, porque conocieron que si esperaban les podía suceder algún peligro; sólo don Quijote, con intrépido corazón, se estuvo quedo, y Sancho Panza se escudó con las ancas de Rocinante. Llegó el tropel de los lanceros, y uno dellos, que venía más delante, a grandes voces comenzó a decir a don Quijote: -¡Apártate, hombre del diablo, del camino, que te harán pedazos estos toros! -¡Ea, canalla -respondió don Quijote-, para mí no hay toros que valgan, aunque sean de los más bravos que cría Jarama en sus riberas! Confesad, malandrines, así a carga cerrada, que es verdad lo que yo aquí he publicado; si no, conmigo sois en batalla. No tuvo lugar de responder el vaquero, ni don Quijote le tuvo de desviarse, aunque quisiera; y así, el tropel de los toros bravos y el de los mansos cabestros, con la multitud de los vaqueros y otras gentes que a encerrar los llevaban a un lugar donde otro día habían de correrse, pasaron sobre don Quijote, y sobre Sancho, Rocinante y el rucio, dando con todos ellos en tierra, echándole a rodar por el suelo. Quedó molido Sancho, espantado don Quijote, aporreado el rucio y no muy católico Rocinante; pero, en fin, se levantaron todos, y don Quijote, a gran priesa, tropezando aquí y cayendo allí, comenzó a correr tras la vacada, diciendo a voces: -¡Deteneos y esperad, canalla malandrina, que un solo caballero os espera, el cual no tiene condición ni es de parecer de los que dicen que al enemigo que huye, hacerle la puente de plata! Pero no por eso se detuvieron los apresurados corredores, ni hicieron más caso de sus amenazas que de las nubes de antaño. Detúvole el cansancio a don Quijote, y, más enojado que vengado, se sentó en el camino, esperando a que Sancho, Rocinante y el rucio llegasen. Llegaron, volvieron a subir amo y mozo, y, sin volver a despedirse de la Arcadia fingida o contrahecha, y con más vergüenza que gusto, siguieron su camino. Capítulo LIX. Donde se cuenta del extraordinario suceso, que se puede tener por aventura, que le sucedió a don Quijote Al polvo y al cansancio que don Quijote y Sancho sacaron del descomedimiento de los toros, socorrió una fuente clara y limpia que entre una fresca arboleda hallaron, en el margen de la cual, dejando libres, sin jáquima y freno, al rucio y a Rocinante, los dos asendereados amo y mozo se sentaron. Acudió Sancho a la repostería de su alforjas, y dellas sacó de lo que él solía llamar condumio; enjuagóse la boca, lavóse don Quijote el rostro, con cuyo refrigerio cobraron aliento los espíritus desalentados. No comía don Quijote, de puro pesaroso, ni Sancho no osaba tocar a los manjares que delante tenía, de puro comedido, y esperaba a que su señor hiciese la salva; pero, viendo que, llevado de sus imaginaciones, no se acordaba de llevar el pan a la boca, no abrió la suya, y, atropellando por todo género de crianza, comenzó a embaular en el estómago el pan y queso que se le ofrecía. -Come, Sancho amigo -dijo don Quijote-, sustenta la vida, que más que a mí te importa, y déjame morir a mí a manos de mis pensamientos y a fuerzas de mis desgracias. Yo, Sancho, nací para vivir muriendo, y tú para morir comiendo; y, porque veas que te digo verdad en esto, considérame impreso en historias, famoso en las armas, comedido en mis acciones, respetado de príncipes, solicitado de doncellas; al cabo al cabo, cuando esperaba palmas, triunfos y coronas, granjeadas y merecidas por mis valerosas hazañas, me he visto esta mañana pisado y acoceado y molido de los pies de animales inmundos y soeces. Esta consideración me embota los dientes, entorpece las muelas, y entomece las manos, y quita de todo en todo la gana del comer, de manera que pienso dejarme morir de hambre: muerte la más cruel de las muertes. -Desa manera -dijo Sancho, sin dejar de mascar apriesa- no aprobará vuestra merced aquel refrán que dicen: "muera Marta, y muera harta". Yo, a lo menos, no pienso matarme a mí mismo; antes pienso hacer como el zapatero, que tira el cuero con los dientes hasta que le hace llegar donde él quiere; yo tiraré mi vida comiendo hasta que llegue al fin que le tiene determinado el cielo; y sepa, señor, que no hay mayor locura que la que toca en querer desesperarse como vuestra merced, y créame, y después de comido, échese a dormir un poco sobre los colchones verdes destas yerbas, y verá como cuando despierte se halla algo más aliviado. Hízolo así don Quijote, pareciéndole que las razones de Sancho más eran de filósofo que de mentecato, y díjole: -Si tú, ¡oh Sancho!, quisieses hacer por mí lo que yo ahora te diré, serían mis alivios más ciertos y mis pesadumbres no tan grandes; y es que, mientras yo duermo, obedeciendo tus consejos, tú te desviases un poco lejos de aquí, y con las riendas de Rocinante, echando al aire tus carnes, te dieses trecientos o cuatrocientos azotes a buena cuenta de los tres mil y tantos que te has de dar por el desencanto de Dulcinea; que es lástima no pequeña que aquella pobre señora esté encantada por tu descuido y negligencia. -Hay mucho que decir en eso -dijo Sancho-. Durmamos, por ahora, entrambos, y después, Dios dijo lo que será. Sepa vuestra merced que esto de azotarse un hombre a sangre fría es cosa recia, y más si caen los azotes sobre un cuerpo mal sustentado y peor comido: tenga paciencia mi señora Dulcinea, que, cuando menos se cate, me verá hecho una criba, de azotes; y hasta la muerte, todo es vida; quiero decir que aún yo la tengo, junto con el deseo de cumplir con lo que he prometido. Agradeciéndoselo don Quijote, comió algo, y Sancho mucho, y echáronse a dormir entrambos, dejando a su albedrío y sin orden alguna pacer del abundosa yerba de que aquel prado estaba lleno a los dos continuos compañeros y amigos Rocinante y el rucio. Despertaron algo tarde, volvieron a subir y a seguir su camino, dándose priesa para llegar a una venta que, al parecer, una legua de allí se descubría. Digo que era venta porque don Quijote la llamó así, fuera del uso que tenía de llamar a todas las ventas castillos. Llegaron, pues, a ella; preguntaron al huésped si había posada. Fueles respondido que sí, con toda la comodidad y regalo que pudiera hallar en Zaragoza. Apeáronse y recogió Sancho su repostería en un aposento, de quien el huésped le dio la llave; llevó las bestias a la caballeriza, echóles sus piensos, salió a ver lo que don Quijote, que estaba sentado sobre un poyo, le mandaba, dando particulares gracias al cielo de que a su amo no le hubiese parecido castillo aquella venta. Llegóse la hora del cenar; recogiéronse a su estancia; preguntó Sancho al huésped que qué tenía para darles de cenar. A lo que el huésped respondió que su boca sería medida; y así, que pidiese lo que quisiese: que de las pajaricas del aire, de las aves de la tierra y de los pescados del mar estaba proveída aquella venta. -No es menester tanto -respondió Sancho-, que con un par de pollos que nos asen tendremos lo suficiente, porque mi señor es delicado y come poco, y yo no soy tragantón en demasía. Respondióle el huésped que no tenía pollos, porque los milanos los tenían asolados. -Pues mande el señor huésped -dijo Sancho- asar una polla que sea tierna. -¿Polla? ¡Mi padre! -respondió el huésped-. En verdad en verdad que envié ayer a la ciudad a vender más de cincuenta; pero, fuera de pollas, pida vuestra merced lo que quisiere. -Desa manera -dijo Sancho-, no faltará ternera o cabrito. -En casa, por ahora -respondió el huésped-, no lo hay, porque se ha acabado; pero la semana que viene lo habrá de sobra. -¡Medrados estamos con eso! -respondió Sancho-. Yo pondré que se vienen a resumirse todas estas faltas en las sobras que debe de haber de tocino y huevos. -¡Por Dios -respondió el huésped-, que es gentil relente el que mi huésped tiene!, pues hele dicho que ni tengo pollas ni gallinas, y ¿quiere que tenga huevos? Discurra, si quisiere, por otras delicadezas, y déjese de pedir gallinas. -Resolvámonos, cuerpo de mí -dijo Sancho-, y dígame finalmente lo que tiene, y déjese de discurrimientos, señor huésped. Dijo el ventero: -Lo que real y verdaderamente tengo son dos uñas de vaca que parecen manos de ternera, o dos manos de ternera que parecen uñas de vaca; están cocidas con sus garbanzos, cebollas y tocino, y la hora de ahora están diciendo: ''¡Coméme! ¡Coméme!'' -Por mías las marco desde aquí -dijo Sancho-; y nadie las toque, que yo las pagaré mejor que otro, porque para mí ninguna otra cosa pudiera esperar de más gusto, y no se me daría nada que fuesen manos, como fuesen uñas. -Nadie las tocará -dijo el ventero-, porque otros huéspedes que tengo, de puro principales, traen consigo cocinero, despensero y repostería. -Si por principales va -dijo Sancho-, ninguno más que mi amo; pero el oficio que él trae no permite despensas ni botillerías: ahí nos tendemos en mitad de un prado y nos hartamos de bellotas o de nísperos. Esta fue la plática que Sancho tuvo con el ventero, sin querer Sancho pasar adelante en responderle; que ya le había preguntado qué oficio o qué ejercicio era el de su amo. Llegóse, pues, la hora del cenar, recogióse a su estancia don Quijote, trujo el huésped la olla, así como estaba, y sentóse a cenar muy de propósito. Parece ser que en otro aposento que junto al de don Quijote estaba, que no le dividía más que un sutil tabique, oyó decir don Quijote: -Por vida de vuestra merced, señor don Jerónimo, que en tanto que trae la cena leamos otro capítulo de la segunda parte de Don Quijote de la Mancha. Apenas oyó su nombre don Quijote, cuando se puso en pie, y con oído alerto escuchó lo que dél trataban, y oyó que el tal don Jerónimo referido respondió: -¿Para qué quiere vuestra merced, señor don Juan, que leamos estos disparates? Y el que hubiere leído la primera parte de la historia de don Quijote de la Mancha no es posible que pueda tener gusto en leer esta segunda. -Con todo eso -dijo el don Juan-, será bien leerla, pues no hay libro tan malo que no tenga alguna cosa buena. Lo que a mí en éste más desplace es que pinta a don Quijote ya desenamorado de Dulcinea del Toboso. Oyendo lo cual don Quijote, lleno de ira y de despecho, alzó la voz y dijo: -Quienquiera que dijere que don Quijote de la Mancha ha olvidado, ni puede olvidar, a Dulcinea del Toboso, yo le haré entender con armas iguales que va muy lejos de la verdad; porque la sin par Dulcinea del Toboso ni puede ser olvidada, ni en don Quijote puede caber olvido: su blasón es la firmeza, y su profesión, el guardarla con suavidad y sin hacerse fuerza alguna. -¿Quién es el que nos responde? -respondieron del otro aposento. -¿Quién ha de ser -respondió Sancho- sino el mismo don Quijote de la Mancha, que hará bueno cuanto ha dicho, y aun cuanto dijere?; que al buen pagador no le duelen prendas. Apenas hubo dicho esto Sancho, cuando entraron por la puerta de su aposento dos caballeros, que tales lo parecían, y uno dellos echando los brazos al cuello de don Quijote, le dijo: -Ni vuestra presencia puede desmentir vuestro nombre, ni vuestro nombre puede no acreditar vuestra presencia: sin duda, vos, señor, sois el verdadero don Quijote de la Mancha, norte y lucero de la andante caballería, a despecho y pesar del que ha querido usurpar vuestro nombre y aniquilar vuestras hazañas, como lo ha hecho el autor deste libro que aquí os entrego. Y, poniéndole un libro en las manos, que traía su compañero, le tomó don Quijote, y, sin responder palabra, comenzó a hojearle, y de allí a un poco se le volvió, diciendo: -En esto poco que he visto he hallado tres cosas en este autor dignas de reprehensión. La primera es algunas palabras que he leído en el prólogo; la otra, que el lenguaje es aragonés, porque tal vez escribe sin artículos, y la tercera, que más le confirma por ignorante, es que yerra y se desvía de la verdad en lo más principal de la historia; porque aquí dice que la mujer de Sancho Panza mi escudero se llama Mari Gutiérrez, y no llama tal, sino Teresa Panza; y quien en esta parte tan principal yerra, bien se podrá temer que yerra en todas las demás de la historia. A esto dijo Sancho: -¡Donosa cosa de historiador! ¡Por cierto, bien debe de estar en el cuento de nuestros sucesos, pues llama a Teresa Panza, mi mujer, Mari Gutiérrez! Torne a tomar el libro, señor, y mire si ando yo por ahí y si me ha mudado el nombre. -Por lo que he oído hablar, amigo -dijo don Jerónimo-, sin duda debéis de ser Sancho Panza, el escudero del señor don Quijote. -Sí soy -respondió Sancho-, y me precio dello. -Pues a fe -dijo el caballero- que no os trata este autor moderno con la limpieza que en vuestra persona se muestra: píntaos comedor, y simple, y no nada gracioso, y muy otro del Sancho que en la primera parte de la historia de vuestro amo se describe. -Dios se lo perdone -dijo Sancho-. Dejárame en mi rincón, sin acordarse de mí, porque quien las sabe las tañe, y bien se está San Pedro en Roma. Los dos caballeros pidieron a don Quijote se pasase a su estancia a cenar con ellos, que bien sabían que en aquella venta no había cosas pertenecientes para su persona. Don Quijote, que siempre fue comedido, condecenció con su demanda y cenó con ellos; quedóse Sancho con la olla con mero mixto imperio; sentóse en cabecera de mesa, y con él el ventero, que no menos que Sancho estaba de sus manos y de sus uñas aficionado. En el discurso de la cena preguntó don Juan a don Quijote qué nuevas tenía de la señora Dulcinea del Toboso: si se había casado, si estaba parida o preñada, o si, estando en su entereza, se acordaba -guardando su honestidad y buen decoro- de los amorosos pensamientos del señor don Quijote. A lo que él respondió: -Dulcinea se está entera, y mis pensamientos, más firmes que nunca; las correspondencias, en su sequedad antigua; su hermosura, en la de una soez labradora transformada. Y luego les fue contando punto por punto el encanto de la señora Dulcinea, y lo que le había sucedido en la cueva de Montesinos, con la orden que el sabio Merlín le había dado para desencantarla, que fue la de los azotes de Sancho. Sumo fue el contento que los dos caballeros recibieron de oír contar a don Quijote los estraños sucesos de su historia, y así quedaron admirados de sus disparates como del elegante modo con que los contaba. Aquí le tenían por discreto, y allí se les deslizaba por mentecato, sin saber determinarse qué grado le darían entre la discreción y la locura. Acabó de cenar Sancho, y, dejando hecho equis al ventero, se pasó a la estancia de su amo; y, en entrando, dijo: -Que me maten, señores, si el autor deste libro que vuesas mercedes tienen quiere que no comamos buenas migas juntos; yo querría que, ya que me llama comilón, como vuesas mercedes dicen, no me llamase también borracho. -Sí llama -dijo don Jerónimo-, pero no me acuerdo en qué manera, aunque sé que son malsonantes las razones, y además, mentirosas, según yo echo de ver en la fisonomía del buen Sancho que está presente. -Créanme vuesas mercedes -dijo Sancho- que el Sancho y el don Quijote desa historia deben de ser otros que los que andan en aquella que compuso Cide Hamete Benengeli, que somos nosotros: mi amo, valiente, discreto y enamorado; y yo, simple gracioso, y no comedor ni borracho. -Yo así lo creo -dijo don Juan-; y si fuera posible, se había de mandar que ninguno fuera osado a tratar de las cosas del gran don Quijote, si no fuese Cide Hamete, su primer autor, bien así como mandó Alejandro que ninguno fuese osado a retratarle sino Apeles. -Retráteme el que quisiere -dijo don Quijote-, pero no me maltrate; que muchas veces suele caerse la paciencia cuando la cargan de injurias. -Ninguna -dijo don Juan- se le puede hacer al señor don Quijote de quien él no se pueda vengar, si no la repara en el escudo de su paciencia, que, a mi parecer, es fuerte y grande. En estas y otras pláticas se pasó gran parte de la noche; y, aunque don Juan quisiera que don Quijote leyera más del libro, por ver lo que discantaba, no lo pudieron acabar con él, diciendo que él lo daba por leído y lo confirmaba por todo necio, y que no quería, si acaso llegase a noticia de su autor que le había tenido en sus manos, se alegrase con pensar que le había leído; pues de las cosas obscenas y torpes, los pensamientos se han de apartar, cuanto más los ojos. Preguntáronle que adónde llevaba determinado su viaje. Respondió que a Zaragoza, a hallarse en las justas del arnés, que en aquella ciudad suelen hacerse todos los años. Díjole don Juan que aquella nueva historia contaba como don Quijote, sea quien se quisiere, se había hallado en ella en una sortija, falta de invención, pobre de letras, pobrísima de libreas, aunque rica de simplicidades. -Por el mismo caso -respondió don Quijote-, no pondré los pies en Zaragoza, y así sacaré a la plaza del mundo la mentira dese historiador moderno, y echarán de ver las gentes como yo no soy el don Quijote que él dice. -Hará muy bien -dijo don Jerónimo-; y otras justas hay en Barcelona, donde podrá el señor don Quijote mostrar su valor. -Así lo pienso hacer -dijo don Quijote-; y vuesas mercedes me den licencia, pues ya es hora para irme al lecho, y me tengan y pongan en el número de sus mayores amigos y servidores. -Y a mí también -dijo Sancho-: quizá seré bueno para algo. Con esto se despidieron, y don Quijote y Sancho se retiraron a su aposento, dejando a don Juan y a don Jerónimo admirados de ver la mezcla que había hecho de su discreción y de su locura; y verdaderamente creyeron que éstos eran los verdaderos don Quijote y Sancho, y no los que describía su autor aragonés. Madrugó don Quijote, y, dando golpes al tabique del otro aposento, se despidió de sus huéspedes. Pagó Sancho al ventero magníficamente, y aconsejóle que alabase menos la provisión de su venta, o la tuviese más proveída. Capítulo LX. De lo que sucedió a don Quijote yendo a Barcelona Era fresca la mañana, y daba muestras de serlo asimesmo el día en que don Quijote salió de la venta, informándose primero cuál era el más derecho camino para ir a Barcelona sin tocar en Zaragoza: tal era el deseo que tenía de sacar mentiroso aquel nuevo historiador que tanto decían que le vituperaba. Sucedió, pues, que en más de seis días no le sucedió cosa digna de ponerse en escritura, al cabo de los cuales, yendo fuera de camino, le tomó la noche entre unas espesas encinas o alcornoques; que en esto no guarda la puntualidad Cide Hamete que en otras cosas suele. Apeáronse de sus bestias amo y mozo, y, acomodándose a los troncos de los árboles, Sancho, que había merendado aquel día, se dejó entrar de rondón por las puertas del sueño; pero don Quijote, a quien desvelaban sus imaginaciones mucho más que la hambre, no podía pegar sus ojos; antes iba y venía con el pensamiento por mil géneros de lugares. Ya le parecía hallarse en la cueva de Montesinos; ya ver brincar y subir sobre su pollina a la convertida en labradora Dulcinea; ya que le sonaban en los oídos las palabras del sabio Merlín que le referían las condiciones y diligencias que se habían de hacer y tener en el desencanto de Dulcinea. Desesperábase de ver la flojedad y caridad poca de Sancho su escudero, pues, a lo que creía, solos cinco azotes se había dado, número desigual y pequeño para los infinitos que le faltaban; y desto recibió tanta pesadumbre y enojo, que hizo este discurso: -Si nudo gordiano cortó el Magno Alejandro, diciendo: ''Tanto monta cortar como desatar'', y no por eso dejó de ser universal señor de toda la Asia, ni más ni menos podría suceder ahora en el desencanto de Dulcinea, si yo azotase a Sancho a pesar suyo; que si la condición deste remedio está en que Sancho reciba los tres mil y tantos azotes, ¿qué se me da a mí que se los dé él, o que se los dé otro, pues la sustancia está en que él los reciba, lleguen por do llegaren? Con esta imaginación se llegó a Sancho, habiendo primero tomado las riendas de Rocinante, y acomodádolas en modo que pudiese azotarle con ellas, comenzóle a quitar las cintas, que es opinión que no tenía más que la delantera, en que se sustentaban los greguescos; pero, apenas hubo llegado, cuando Sancho despertó en todo su acuerdo, y dijo: -¿Qué es esto? ¿Quién me toca y desencinta? -Yo soy -respondió don Quijote-, que vengo a suplir tus faltas y a remediar mis trabajos: véngote a azotar, Sancho, y a descargar, en parte, la deuda a que te obligaste. Dulcinea perece; tú vives en descuido; yo muero deseando; y así, desatácate por tu voluntad, que la mía es de darte en esta soledad, por lo menos, dos mil azotes. -Eso no -dijo Sancho-; vuesa merced se esté quedo; si no, por Dios verdadero que nos han de oír los sordos. Los azotes a que yo me obligué han de ser voluntarios, y no por fuerza, y ahora no tengo gana de azotarme; basta que doy a vuesa merced mi palabra de vapularme y mosquearme cuando en voluntad me viniere. -No hay dejarlo a tu cortesía, Sancho -dijo don Quijote-, porque eres duro de corazón, y, aunque villano, blando de carnes. Y así, procuraba y pugnaba por desenlazarle. Viendo lo cual Sancho Panza, se puso en pie, y, arremetiendo a su amo, se abrazó con él a brazo partido, y, echándole una zancadilla, dio con él en el suelo boca arriba; púsole la rodilla derecha sobre el pecho, y con las manos le tenía las manos, de modo que ni le dejaba rodear ni alentar. Don Quijote le decía: -¿Cómo, traidor? ¿Contra tu amo y señor natural te desmandas? ¿Con quien te da su pan te atreves? -Ni quito rey, ni pongo rey -respondió Sancho-, sino ayúdome a mí, que soy mi señor. Vuesa merced me prometa que se estará quedo, y no tratará de azotarme por agora, que yo le dejaré libre y desembarazado; donde no, Aquí morirás, traidor, enemigo de doña Sancha. Prometióselo don Quijote, y juró por vida de sus pensamientos no tocarle en el pelo de la ropa, y que dejaría en toda su voluntad y albedrío el azotarse cuando quisiese. Levantóse Sancho, y desvióse de aquel lugar un buen espacio; y, yendo a arrimarse a otro árbol, sintió que le tocaban en la cabeza, y, alzando las manos, topó con dos pies de persona, con zapatos y calzas. Tembló de miedo; acudió a otro árbol, y sucedióle lo mesmo. Dio voces llamando a don Quijote que le favoreciese. Hízolo así don Quijote, y, preguntándole qué le había sucedido y de qué tenía miedo, le respondió Sancho que todos aquellos árboles estaban llenos de pies y de piernas humanas. Tentólos don Quijote, y cayó luego en la cuenta de lo que podía ser, y díjole a Sancho: -No tienes de qué tener miedo, porque estos pies y piernas que tientas y no vees, sin duda son de algunos forajidos y bandoleros que en estos árboles están ahorcados; que por aquí los suele ahorcar la justicia cuando los coge, de veinte en veinte y de treinta en treinta; por donde me doy a entender que debo de estar cerca de Barcelona. Y así era la verdad como él lo había imaginado. Al parecer alzaron los ojos, y vieron los racimos de aquellos árboles, que eran cuerpos de bandoleros. Ya, en esto, amanecía, y si los muertos los habían espantado, no menos los atribularon más de cuarenta bandoleros vivos que de improviso les rodearon, diciéndoles en lengua catalana que estuviesen quedos, y se detuviesen, hasta que llegase su capitán. Hallóse don Quijote a pie, su caballo sin freno, su lanza arrimada a un árbol, y, finalmente, sin defensa alguna; y así, tuvo por bien de cruzar las manos e inclinar la cabeza, guardándose para mejor sazón y coyuntura. Acudieron los bandoleros a espulgar al rucio, y a no dejarle ninguna cosa de cuantas en las alforjas y la maleta traía; y avínole bien a Sancho que en una ventrera que tenía ceñida venían los escudos del duque y los que habían sacado de su tierra, y, con todo eso, aquella buena gente le escardara y le mirara hasta lo que entre el cuero y la carne tuviera escondido, si no llegara en aquella sazón su capitán, el cual mostró ser de hasta edad de treinta y cuatro años, robusto, más que de mediana proporción, de mirar grave y color morena. Venía sobre un poderoso caballo, vestida la acerada cota, y con cuatro pistoletes -que en aquella tierra se llaman pedreñales- a los lados. Vio que sus escuderos, que así llaman a los que andan en aquel ejercicio, iban a despojar a Sancho Panza; mandóles que no lo hiciesen, y fue luego obedecido; y así se escapó la ventrera. Admiróle ver lanza arrimada al árbol, escudo en el suelo, y a don Quijote armado y pensativo, con la más triste y melancólica figura que pudiera formar la misma tristeza. Llegóse a él diciéndole: -No estéis tan triste, buen hombre, porque no habéis caído en las manos de algún cruel Osiris, sino en las de Roque Guinart, que tienen más de compasivas que de rigurosas. -No es mi tristeza -respondió don Quijote- haber caído en tu poder, ¡oh valeroso Roque, cuya fama no hay límites en la tierra que la encierren!, sino por haber sido tal mi descuido, que me hayan cogido tus soldados sin el freno, estando yo obligado, según la orden de la andante caballería, que profeso, a vivir contino alerta, siendo a todas horas centinela de mí mismo; porque te hago saber, ¡oh gran Roque!, que si me hallaran sobre mi caballo, con mi lanza y con mi escudo, no les fuera muy fácil rendirme, porque yo soy don Quijote de la Mancha, aquel que de sus hazañas tiene lleno todo el orbe. Luego Roque Guinart conoció que la enfermedad de don Quijote tocaba más en locura que en valentía, y, aunque algunas veces le había oído nombrar, nunca tuvo por verdad sus hechos, ni se pudo persuadir a que semejante humor reinase en corazón de hombre; y holgóse en estremo de haberle encontrado, para tocar de cerca lo que de lejos dél había oído; y así, le dijo: -Valeroso caballero, no os despechéis ni tengáis a siniestra fortuna ésta en que os halláis, que podía ser que en estos tropiezos vuestra torcida suerte se enderezase; que el cielo, por estraños y nunca vistos rodeos, de los hombres no imaginados, suele levantar los caídos y enriquecer los pobres. Ya le iba a dar las gracias don Quijote, cuando sintieron a sus espaldas un ruido como de tropel de caballos, y no era sino un solo, sobre el cual venía a toda furia un mancebo, al parecer de hasta veinte años, vestido de damasco verde, con pasamanos de oro, greguescos y saltaembarca, con sombrero terciado, a la valona, botas enceradas y justas, espuelas, daga y espada doradas, una escopeta pequeña en las manos y dos pistolas a los lados. Al ruido volvió Roque la cabeza y vio esta hermosa figura, la cual, en llegando a él, dijo: -En tu busca venía, ¡oh valeroso Roque!, para hallar en ti, si no remedio, a lo menos alivio en mi desdicha; y, por no tenerte suspenso, porque sé que no me has conocido, quiero decirte quién soy: y soy Claudia Jerónima, hija de Simón Forte, tu singular amigo y enemigo particular de Clauquel Torrellas, que asimismo lo es tuyo, por ser uno de los de tu contrario bando; y ya sabes que este Torrellas tiene un hijo que don Vicente Torrellas se llama, o, a lo menos, se llamaba no ha dos horas. Éste, pues, por abreviar el cuento de mi desventura, te diré en breves palabras la que me ha causado. Viome, requebróme, escuchéle, enamoréme, a hurto de mi padre; porque no hay mujer, por retirada que esté y recatada que sea, a quien no le sobre tiempo para poner en ejecución y efecto sus atropellados deseos. Finalmente, él me prometió de ser mi esposo, y yo le di la palabra de ser suya, sin que en obras pasásemos adelante. Supe ayer que, olvidado de lo que me debía, se casaba con otra, y que esta mañana iba a desposarse, nueva que me turbó el sentido y acabó la paciencia; y, por no estar mi padre en el lugar, le tuve yo de ponerme en el traje que vees, y apresurando el paso a este caballo, alcancé a don Vicente obra de una legua de aquí; y, sin ponerme a dar quejas ni a oír disculpas, le disparé estas escopetas, y, por añadidura, estas dos pistolas; y, a lo que creo, le debí de encerrar más de dos balas en el cuerpo, abriéndole puertas por donde envuelta en su sangre saliese mi honra. Allí le dejo entre sus criados, que no osaron ni pudieron ponerse en su defensa. Vengo a buscarte para que me pases a Francia, donde tengo parientes con quien viva, y asimesmo a rogarte defiendas a mi padre, porque los muchos de don Vicente no se atrevan a tomar en él desaforada venganza. Roque, admirado de la gallardía, bizarría, buen talle y suceso de la hermosa Claudia, le dijo: -Ven, señora, y vamos a ver si es muerto tu enemigo, que después veremos lo que más te importare. Don Quijote, que estaba escuchando atentamente lo que Claudia había dicho y lo que Roque Guinart respondió, dijo: -No tiene nadie para qué tomar trabajo en defender a esta señora, que lo tomo yo a mi cargo: denme mi caballo y mis armas, y espérenme aquí, que yo iré a buscar a ese caballero, y, muerto o vivo, le haré cumplir la palabra prometida a tanta belleza. -Nadie dude de esto -dijo Sancho-, porque mi señor tiene muy buena mano para casamentero, pues no ha muchos días que hizo casar a otro que también negaba a otra doncella su palabra; y si no fuera porque los encantadores que le persiguen le mudaron su verdadera figura en la de un lacayo, ésta fuera la hora que ya la tal doncella no lo fuera. Roque, que atendía más a pensar en el suceso de la hermosa Claudia que en las razones de amo y mozo, no las entendió; y, mandando a sus escuderos que volviesen a Sancho todo cuanto le habían quitado del rucio, mandándoles asimesmo que se retirasen a la parte donde aquella noche habían estado alojados, y luego se partió con Claudia a toda priesa a buscar al herido, o muerto, don Vicente. Llegaron al lugar donde le encontró Claudia, y no hallaron en él sino recién derramada sangre; pero, tendiendo la vista por todas partes, descubrieron por un recuesto arriba alguna gente, y diéronse a entender, como era la verdad, que debía ser don Vicente, a quien sus criados, o muerto o vivo, llevaban, o para curarle, o para enterrarle; diéronse priesa a alcanzarlos, que, como iban de espacio, con facilidad lo hicieron. Hallaron a don Vicente en los brazos de sus criados, a quien con cansada y debilitada voz rogaba que le dejasen allí morir, porque el dolor de las heridas no consentía que más adelante pasase. Arrojáronse de los caballos Claudia y Roque, llegáronse a él, temieron los criados la presencia de Roque, y Claudia se turbó en ver la de don Vicente; y así, entre enternecida y rigurosa, se llegó a él, y asiéndole de las manos, le dijo: -Si tú me dieras éstas, conforme a nuestro concierto, nunca tú te vieras en este paso. Abrió los casi cerrados ojos el herido caballero, y, conociendo a Claudia, le dijo: -Bien veo, hermosa y engañada señora, que tú has sido la que me has muerto: pena no merecida ni debida a mis deseos, con los cuales, ni con mis obras, jamás quise ni supe ofenderte. -Luego, ¿no es verdad -dijo Claudia- que ibas esta mañana a desposarte con Leonora, la hija del rico Balvastro? -No, por cierto -respondió don Vicente-; mi mala fortuna te debió de llevar estas nuevas, para que, celosa, me quitases la vida, la cual, pues la dejo en tus manos y en tus brazos, tengo mi suerte por venturosa. Y, para asegurarte desta verdad, aprieta la mano y recíbeme por esposo, si quisieres, que no tengo otra mayor satisfación que darte del agravio que piensas que de mí has recebido. Apretóle la mano Claudia, y apretósele a ella el corazón, de manera que sobre la sangre y pecho de don Vicente se quedó desmayada, y a él le tomó un mortal parasismo. Confuso estaba Roque, y no sabía qué hacerse. Acudieron los criados a buscar agua que echarles en los rostros, y trujéronla, con que se los bañaron. Volvió de su desmayo Claudia, pero no de su parasismo don Vicente, porque se le acabó la vida. Visto lo cual de Claudia, habiéndose enterado que ya su dulce esposo no vivía, rompió los aires con suspiros, hirió los cielos con quejas, maltrató sus cabellos, entregándolos al viento, afeó su rostro con sus propias manos, con todas las muestras de dolor y sentimiento que de un lastimado pecho pudieran imaginarse. -¡Oh cruel e inconsiderada mujer -decía-, con qué facilidad te moviste a poner en ejecución tan mal pensamiento! ¡Oh fuerza rabiosa de los celos, a qué desesperado fin conducís a quien os da acogida en su pecho! ¡Oh esposo mío, cuya desdichada suerte, por ser prenda mía, te ha llevado del tálamo a la sepultura! Tales y tan tristes eran las quejas de Claudia, que sacaron las lágrimas de los ojos de Roque, no acostumbrados a verterlas en ninguna ocasión. Lloraban los criados, desmayábase a cada paso Claudia, y todo aquel circuito parecía campo de tristeza y lugar de desgracia. Finalmente, Roque Guinart ordenó a los criados de don Vicente que llevasen su cuerpo al lugar de su padre, que estaba allí cerca, para que le diesen sepultura. Claudia dijo a Roque que querría irse a un monasterio donde era abadesa una tía suya, en el cual pensaba acabar la vida, de otro mejor esposo y más eterno acompañada. Alabóle Roque su buen propósito, ofreciósele de acompañarla hasta donde quisiese, y de defender a su padre de los parientes y de todo el mundo, si ofenderle quisiese. No quiso su compañía Claudia, en ninguna manera, y, agradeciendo sus ofrecimientos con las mejores razones que supo, se despedió dél llorando. Los criados de don Vicente llevaron su cuerpo, y Roque se volvió a los suyos, y este fin tuvieron los amores de Claudia Jerónima. Pero, ¿qué mucho, si tejieron la trama de su lamentable historia las fuerzas invencibles y rigurosas de los celos? Halló Roque Guinart a sus escuderos en la parte donde les había ordenado, y a don Quijote entre ellos, sobre Rocinante, haciéndoles una plática en que les persuadía dejasen aquel modo de vivir tan peligroso, así para el alma como para el cuerpo; pero, como los más eran gascones, gente rústica y desbaratada, no les entraba bien la plática de don Quijote. Llegado que fue Roque, preguntó a Sancho Panza si le habían vuelto y restituido las alhajas y preseas que los suyos del rucio le habían quitado. Sancho respondió que sí, sino que le faltaban tres tocadores, que valían tres ciudades. -¿Qué es lo que dices, hombre? -dijo uno de los presentes-, que yo los tengo, y no valen tres reales. -Así es -dijo don Quijote-, pero estímalos mi escudero en lo que ha dicho, por habérmelos dado quien me los dio. Mandóselos volver al punto Roque Guinart, y, mandando poner los suyos en ala, mandó traer allí delante todos los vestidos, joyas, y dineros, y todo aquello que desde la última repartición habían robado; y, haciendo brevemente el tanteo, volviendo lo no repartible y reduciéndolo a dineros, lo repartió por toda su compañía, con tanta legalidad y prudencia que no pasó un punto ni defraudó nada de la justicia distributiva. Hecho esto, con lo cual todos quedaron contentos, satisfechos y pagados, dijo Roque a don Quijote: -Si no se guardase esta puntualidad con éstos, no se podría vivir con ellos. A lo que dijo Sancho: -Según lo que aquí he visto, es tan buena la justicia, que es necesaria que se use aun entre los mesmos ladrones. Oyólo un escudero, y enarboló el mocho de un arcabuz, con el cual, sin duda, le abriera la cabeza a Sancho, si Roque Guinart no le diera voces que se detuviese. Pasmóse Sancho, y propuso de no descoser los labios en tanto que entre aquella gente estuviese. Llegó, en esto, uno o algunos de aquellos escuderos que estaban puestos por centinelas por los caminos para ver la gente que por ellos venía y dar aviso a su mayor de lo que pasaba, y éste dijo: -Señor, no lejos de aquí, por el camino que va a Barcelona, viene un gran tropel de gente. A lo que respondió Roque: -¿Has echado de ver si son de los que nos buscan, o de los que nosotros buscamos? -No, sino de los que buscamos -respondió el escudero. -Pues salid todos -replicó Roque-, y traédmelos aquí luego, sin que se os escape ninguno. Hiciéronlo así, y, quedándose solos don Quijote, Sancho y Roque, aguardaron a ver lo que los escuderos traían; y, en este entretanto, dijo Roque a don Quijote: -Nueva manera de vida le debe de parecer al señor don Quijote la nuestra, nuevas aventuras, nuevos sucesos, y todos peligrosos; y no me maravillo que así le parezca, porque realmente le confieso que no hay modo de vivir más inquieto ni más sobresaltado que el nuestro. A mí me han puesto en él no sé qué deseos de venganza, que tienen fuerza de turbar los más sosegados corazones; yo, de mi natural, soy compasivo y bien intencionado; pero, como tengo dicho, el querer vengarme de un agravio que se me hizo, así da con todas mis buenas inclinaciones en tierra, que persevero en este estado, a despecho y pesar de lo que entiendo; y, como un abismo llama a otro y un pecado a otro pecado, hanse eslabonado las venganzas de manera que no sólo las mías, pero las ajenas tomo a mi cargo; pero Dios es servido de que, aunque me veo en la mitad del laberinto de mis confusiones, no pierdo la esperanza de salir dél a puerto seguro. Admirado quedó don Quijote de oír hablar a Roque tan buenas y concertadas razones, porque él se pensaba que, entre los de oficios semejantes de robar, matar y saltear no podía haber alguno que tuviese buen discurso, y respondióle: -Señor Roque, el principio de la salud está en conocer la enfermedad y en querer tomar el enfermo las medicinas que el médico le ordena: vuestra merced está enfermo, conoce su dolencia, y el cielo, o Dios, por mejor decir, que es nuestro médico, le aplicará medicinas que le sanen, las cuales suelen sanar poco a poco y no de repente y por milagro; y más, que los pecadores discretos están más cerca de enmendarse que los simples; y, pues vuestra merced ha mostrado en sus razones su prudencia, no hay sino tener buen ánimo y esperar mejoría de la enfermedad de su conciencia; y si vuestra merced quiere ahorrar camino y ponerse con facilidad en el de su salvación, véngase conmigo, que yo le enseñaré a ser caballero andante, donde se pasan tantos trabajos y desventuras que, tomándolas por penitencia, en dos paletas le pondrán en el cielo. Rióse Roque del consejo de don Quijote, a quien, mudando plática, contó el trágico suceso de Claudia Jerónima, de que le pesó en estremo a Sancho, que no le había parecido mal la belleza, desenvoltura y brío de la moza. Llegaron, en esto, los escuderos de la presa, trayendo consigo dos caballeros a caballo, y dos peregrinos a pie, y un coche de mujeres con hasta seis criados, que a pie y a caballo las acompañaban, con otros dos mozos de mulas que los caballeros traían. Cogiéronlos los escuderos en medio, guardando vencidos y vencedores gran silencio, esperando a que el gran Roque Guinart hablase, el cual preguntó a los caballeros que quién eran y adónde iban, y qué dinero llevaban. Uno dellos le respondió: -Señor, nosotros somos dos capitanes de infantería española; tenemos nuestras compañías en Nápoles y vamos a embarcarnos en cuatro galeras, que dicen están en Barcelona con orden de pasar a Sicilia; llevamos hasta docientos o trecientos escudos, con que, a nuestro parecer, vamos ricos y contentos, pues la estrecheza ordinaria de los soldados no permite mayores tesoros. Preguntó Roque a los peregrinos lo mesmo que a los capitanes; fuele respondido que iban a embarcarse para pasar a Roma, y que entre entrambos podían llevar hasta sesenta reales. Quiso saber también quién iba en el coche, y adónde, y el dinero que llevaban; y uno de los de a caballo dijo: -Mi señora doña Guiomar de Quiñones, mujer del regente de la Vicaría de Nápoles, con una hija pequeña, una doncella y una dueña, son las que van en el coche; acompañámosla seis criados, y los dineros son seiscientos escudos. -De modo -dijo Roque Guinart-, que ya tenemos aquí novecientos escudos y sesenta reales; mis soldados deben de ser hasta sesenta; mírese a cómo le cabe a cada uno, porque yo soy mal contador. Oyendo decir esto los salteadores, levantaron la voz, diciendo: -¡Viva Roque Guinart muchos años, a pesar de los lladres que su perdición procuran! Mostraron afligirse los capitanes, entristecióse la señora regenta, y no se holgaron nada los peregrinos, viendo la confiscación de sus bienes. Túvolos así un rato suspensos Roque, pero no quiso que pasase adelante su tristeza, que ya se podía conocer a tiro de arcabuz, y, volviéndose a los capitanes, dijo: -Vuesas mercedes, señores capitanes, por cortesía, sean servidos de prestarme sesenta escudos, y la señora regenta ochenta, para contentar esta escuadra que me acompaña, porque el abad, de lo que canta yanta, y luego puédense ir su camino libre y desembarazadamente, con un salvoconduto que yo les daré, para que, si toparen otras de algunas escuadras mías que tengo divididas por estos contornos, no les hagan daño; que no es mi intención de agraviar a soldados ni a mujer alguna, especialmente a las que son principales. Infinitas y bien dichas fueron las razones con que los capitanes agradecieron a Roque su cortesía y liberalidad, que, por tal la tuvieron, en dejarles su mismo dinero. La señora doña Guiomar de Quiñones se quiso arrojar del coche para besar los pies y las manos del gran Roque, pero él no lo consintió en ninguna manera; antes le pidió perdón del agravio que le hacía, forzado de cumplir con las obligaciones precisas de su mal oficio. Mandó la señora regenta a un criado suyo diese luego los ochenta escudos que le habían repartido, y ya los capitanes habían desembolsado los sesenta. Iban los peregrinos a dar toda su miseria, pero Roque les dijo que se estuviesen quedos, y volviéndose a los suyos, les dijo: -Destos escudos dos tocan a cada uno, y sobran veinte: los diez se den a estos peregrinos, y los otros diez a este buen escudero, porque pueda decir bien de esta aventura. Y, trayéndole aderezo de escribir, de que siempre andaba proveído, Roque les dio por escrito un salvoconduto para los mayorales de sus escuadras, y, despidiéndose dellos, los dejó ir libres, y admirados de su nobleza, de su gallarda disposición y estraño proceder, teniéndole más por un Alejandro Magno que por ladrón conocido. Uno de los escuderos dijo en su lengua gascona y catalana: -Este nuestro capitán más es para frade que para bandolero: si de aquí adelante quisiere mostrarse liberal séalo con su hacienda y no con la nuestra. No lo dijo tan paso el desventurado que dejase de oírlo Roque, el cual, echando mano a la espada, le abrió la cabeza casi en dos partes, diciéndole: -Desta manera castigo yo a los deslenguados y atrevidos. Pasmáronse todos, y ninguno le osó decir palabra: tanta era la obediencia que le tenían. Apartóse Roque a una parte y escribió una carta a un su amigo, a Barcelona, dándole aviso como estaba consigo el famoso don Quijote de la Mancha, aquel caballero andante de quien tantas cosas se decían; y que le hacía saber que era el más gracioso y el más entendido hombre del mundo, y que de allí a cuatro días, que era el de San Juan Bautista, se le pondría en mitad de la playa de la ciudad, armado de todas sus armas, sobre Rocinante, su caballo, y a su escudero Sancho sobre un asno, y que diese noticia desto a sus amigos los Niarros, para que con él se solazasen; que él quisiera que carecieran deste gusto los Cadells, sus contrarios, pero que esto era imposible, a causa que las locuras y discreciones de don Quijote y los donaires de su escudero Sancho Panza no podían dejar de dar gusto general a todo el mundo. Despachó estas cartas con uno de sus escuderos, que, mudando el traje de bandolero en el de un labrador, entró en Barcelona y la dio a quien iba. Capítulo LXI. De lo que le sucedió a don Quijote en la entrada de Barcelona, con otras cosas que tienen más de lo verdadero que de lo discreto Tres días y tres noches estuvo don Quijote con Roque, y si estuviera trecientos años, no le faltara qué mirar y admirar en el modo de su vida: aquí amanecían, acullá comían; unas veces huían, sin saber de quién, y otras esperaban, sin saber a quién. Dormían en pie, interrompiendo el sueño, mudándose de un lugar a otro. Todo era poner espías, escuchar centinelas, soplar las cuerdas de los arcabuces, aunque traían pocos, porque todos se servían de pedreñales. Roque pasaba las noches apartado de los suyos, en partes y lugares donde ellos no pudiesen saber dónde estaba; porque los muchos bandos que el visorrey de Barcelona había echado sobre su vida le traían inquieto y temeroso, y no se osaba fiar de ninguno, temiendo que los mismos suyos, o le habían de matar, o entregar a la justicia: vida, por cierto, miserable y enfadosa. En fin, por caminos desusados, por atajos y sendas encubiertas, partieron Roque, don Quijote y Sancho con otros seis escuderos a Barcelona. Llegaron a su playa la víspera de San Juan en la noche, y, abrazando Roque a don Quijote y a Sancho, a quien dio los diez escudos prometidos, que hasta entonces no se los había dado, los dejó, con mil ofrecimientos que de la una a la otra parte se hicieron. Volvióse Roque; quedóse don Quijote esperando el día, así, a caballo, como estaba, y no tardó mucho cuando comenzó a descubrirse por los balcones del Oriente la faz de la blanca aurora, alegrando las yerbas y las flores, en lugar de alegrar el oído; aunque al mesmo instante alegraron también el oído el son de muchas chirimías y atabales, ruido de cascabeles, ''¡trapa, trapa, aparta, aparta!'' de corredores, que, al parecer, de la ciudad salían. Dio lugar la aurora al sol, que, un rostro mayor que el de una rodela, por el más bajo horizonte, poco a poco, se iba levantando. Tendieron don Quijote y Sancho la vista por todas partes: vieron el mar, hasta entonces dellos no visto; parecióles espaciosísimo y largo, harto más que las lagunas de Ruidera, que en la Mancha habían visto; vieron las galeras que estaban en la playa, las cuales, abatiendo las tiendas, se descubrieron llenas de flámulas y gallardetes, que tremolaban al viento y besaban y barrían el agua; dentro sonaban clarines, trompetas y chirimías, que cerca y lejos llenaban el aire de suaves y belicosos acentos. Comenzaron a moverse y a hacer modo de escaramuza por las sosegadas aguas, correspondiéndoles casi al mismo modo infinitos caballeros que de la ciudad sobre hermosos caballos y con vistosas libreas salían. Los soldados de las galeras disparaban infinita artillería, a quien respondían los que estaban en las murallas y fuertes de la ciudad, y la artillería gruesa con espantoso estruendo rompía los vientos, a quien respondían los cañones de crujía de las galeras. El mar alegre, la tierra jocunda, el aire claro, sólo tal vez turbio del humo de la artillería, parece que iba infundiendo y engendrando gusto súbito en todas las gentes. No podía imaginar Sancho cómo pudiesen tener tantos pies aquellos bultos que por el mar se movían. En esto, llegaron corriendo, con grita, lililíes y algazara, los de las libreas adonde don Quijote suspenso y atónito estaba, y uno dellos, que era el avisado de Roque, dijo en alta voz a don Quijote: -Bien sea venido a nuestra ciudad el espejo, el farol, la estrella y el norte de toda la caballería andante, donde más largamente se contiene. Bien sea venido, digo, el valeroso don Quijote de la Mancha: no el falso, no el ficticio, no el apócrifo que en falsas historias estos días nos han mostrado, sino el verdadero, el legal y el fiel que nos describió Cide Hamete Benengeli, flor de los historiadores. No respondió don Quijote palabra, ni los caballeros esperaron a que la respondiese, sino, volviéndose y revolviéndose con los demás que los seguían, comenzaron a hacer un revuelto caracol al derredor de don Quijote; el cual, volviéndose a Sancho, dijo: -Éstos bien nos han conocido: yo apostaré que han leído nuestra historia y aun la del aragonés recién impresa. Volvió otra vez el caballero que habló a don Quijote, y díjole: -Vuesa merced, señor don Quijote, se venga con nosotros, que todos somos sus servidores y grandes amigos de Roque Guinart. A lo que don Quijote respondió: -Si cortesías engendran cortesías, la vuestra, señor caballero, es hija o parienta muy cercana de las del gran Roque. Llevadme do quisiéredes, que yo no tendré otra voluntad que la vuestra, y más si la queréis ocupar en vuestro servicio. Con palabras no menos comedidas que éstas le respondió el caballero, y, encerrándole todos en medio, al son de las chirimías y de los atabales, se encaminaron con él a la ciudad, al entrar de la cual, el malo, que todo lo malo ordena, y los muchachos, que son más malos que el malo, dos dellos traviesos y atrevidos se entraron por toda la gente, y, alzando el uno de la cola del rucio y el otro la de Rocinante, les pusieron y encajaron sendos manojos de aliagas. Sintieron los pobres animales las nuevas espuelas, y, apretando las colas, aumentaron su disgusto, de manera que, dando mil corcovos, dieron con sus dueños en tierra. Don Quijote, corrido y afrentado, acudió a quitar el plumaje de la cola de su matalote, y Sancho, el de su rucio. Quisieran los que guiaban a don Quijote castigar el atrevimiento de los muchachos, y no fue posible, porque se encerraron entre más de otros mil que los seguían. Volvieron a subir don Quijote y Sancho; con el mismo aplauso y música llegaron a la casa de su guía, que era grande y principal, en fin, como de caballero rico; donde le dejaremos por agora, porque así lo quiere Cide Hamete. Capítulo LXII. Que trata de la aventura de la cabeza encantada, con otras niñerías que no pueden dejar de contarse Don Antonio Moreno se llamaba el huésped de don Quijote, caballero rico y discreto, y amigo de holgarse a lo honesto y afable, el cual, viendo en su casa a don Quijote, andaba buscando modos como, sin su perjuicio, sacase a plaza sus locuras; porque no son burlas las que duelen, ni hay pasatiempos que valgan si son con daño de tercero. Lo primero que hizo fue hacer desarmar a don Quijote y sacarle a vistas con aquel su estrecho y acamuzado vestido -como ya otras veces le hemos descrito y pintado- a un balcón que salía a una calle de las más principales de la ciudad, a vista de las gentes y de los muchachos, que como a mona le miraban. Corrieron de nuevo delante dél los de las libreas, como si para él solo, no para alegrar aquel festivo día, se las hubieran puesto; y Sancho estaba contentísimo, por parecerle que se había hallado, sin saber cómo ni cómo no, otras bodas de Camacho, otra casa como la de don Diego de Miranda y otro castillo como el del duque. Comieron aquel día con don Antonio algunos de sus amigos, honrando todos y tratando a don Quijote como a caballero andante, de lo cual, hueco y pomposo, no cabía en sí de contento. Los donaires de Sancho fueron tantos, que de su boca andaban como colgados todos los criados de casa y todos cuantos le oían. Estando a la mesa, dijo don Antonio a Sancho: -Acá tenemos noticia, buen Sancho, que sois tan amigo de manjar blanco y de albondiguillas, que, si os sobran, las guardáis en el seno para el otro día. -No, señor, no es así -respondió Sancho-, porque tengo más de limpio que de goloso, y mi señor don Quijote, que está delante, sabe bien que con un puño de bellotas, o de nueces, nos solemos pasar entrambos ocho días. Verdad es que si tal vez me sucede que me den la vaquilla, corro con la soguilla; quiero decir que como lo que me dan, y uso de los tiempos como los hallo; y quienquiera que hubiere dicho que yo soy comedor aventajado y no limpio, téngase por dicho que no acierta; y de otra manera dijera esto si no mirara a las barbas honradas que están a la mesa. -Por cierto -dijo don Quijote-, que la parsimonia y limpieza con que Sancho come se puede escribir y grabar en láminas de bronce, para que quede en memoria eterna de los siglos venideros. Verdad es que, cuando él tiene hambre, parece algo tragón, porque come apriesa y masca a dos carrillos; pero la limpieza siempre la tiene en su punto, y en el tiempo que fue gobernador aprendió a comer a lo melindroso: tanto, que comía con tenedor las uvas y aun los granos de la granada. -¡Cómo! -dijo don Antonio-. ¿Gobernador ha sido Sancho? -Sí -respondió Sancho-, y de una ínsula llamada la Barataria. Diez días la goberné a pedir de boca; en ellos perdí el sosiego, y aprendí a despreciar todos los gobiernos del mundo; salí huyendo della, caí en una cueva, donde me tuve por muerto, de la cual salí vivo por milagro. Contó don Quijote por menudo todo el suceso del gobierno de Sancho, con que dio gran gusto a los oyentes. Levantados los manteles, y tomando don Antonio por la mano a don Quijote, se entró con él en un apartado aposento, en el cual no había otra cosa de adorno que una mesa, al parecer de jaspe, que sobre un pie de lo mesmo se sostenía, sobre la cual estaba puesta, al modo de las cabezas de los emperadores romanos, de los pechos arriba, una que semejaba ser de bronce. Paseóse don Antonio con don Quijote por todo el aposento, rodeando muchas veces la mesa, después de lo cual dijo: -Agora, señor don Quijote, que estoy enterado que no nos oye y escucha alguno, y está cerrada la puerta, quiero contar a vuestra merced una de las más raras aventuras, o, por mejor decir, novedades que imaginarse pueden, con condición que lo que a vuestra merced dijere lo ha de depositar en los últimos retretes del secreto. -Así lo juro -respondió don Quijote-, y aun le echaré una losa encima, para más seguridad; porque quiero que sepa vuestra merced, señor don Antonio -que ya sabía su nombre-, que está hablando con quien, aunque tiene oídos para oír, no tiene lengua para hablar; así que, con seguridad puede vuestra merced trasladar lo que tiene en su pecho en el mío y hacer cuenta que lo ha arrojado en los abismos del silencio. -En fee de esa promesa -respondió don Antonio-, quiero poner a vuestra merced en admiración con lo que viere y oyere, y darme a mí algún alivio de la pena que me causa no tener con quien comunicar mis secretos, que no son para fiarse de todos. Suspenso estaba don Quijote, esperando en qué habían de parar tantas prevenciones. En esto, tomándole la mano don Antonio, se la paseó por la cabeza de bronce y por toda la mesa, y por el pie de jaspe sobre que se sostenía, y luego dijo: -Esta cabeza, señor don Quijote, ha sido hecha y fabricada por uno de los mayores encantadores y hechiceros que ha tenido el mundo, que creo era polaco de nación y dicípulo del famoso Escotillo, de quien tantas maravillas se cuentan; el cual estuvo aquí en mi casa, y por precio de mil escudos que le di, labró esta cabeza, que tiene propiedad y virtud de responder a cuantas cosas al oído le preguntaren. Guardó rumbos, pintó carácteres, observó astros, miró puntos, y, finalmente, la sacó con la perfeción que veremos mañana, porque los viernes está muda, y hoy, que lo es, nos ha de hacer esperar hasta mañana. En este tiempo podrá vuestra merced prevenirse de lo que querrá preguntar, que por esperiencia sé que dice verdad en cuanto responde. Admirado quedó don Quijote de la virtud y propiedad de la cabeza, y estuvo por no creer a don Antonio; pero, por ver cuán poco tiempo había para hacer la experiencia, no quiso decirle otra cosa sino que le agradecía el haberle descubierto tan gran secreto. Salieron del aposento, cerró la puerta don Antonio con llave, y fuéronse a la sala, donde los demás caballeros estaban. En este tiempo les había contado Sancho muchas de las aventuras y sucesos que a su amo habían acontecido. Aquella tarde sacaron a pasear a don Quijote, no armado, sino de rúa, vestido un balandrán de paño leonado, que pudiera hacer sudar en aquel tiempo al mismo yelo. Ordenaron con sus criados que entretuviesen a Sancho de modo que no le dejasen salir de casa. Iba don Quijote, no sobre Rocinante, sino sobre un gran macho de paso llano, y muy bien aderezado. Pusiéronle el balandrán, y en las espaldas, sin que lo viese, le cosieron un pargamino, donde le escribieron con letras grandes: Éste es don Quijote de la Mancha. En comenzando el paseo, llevaba el rétulo los ojos de cuantos venían a verle, y como leían: Éste es don Quijote de la Mancha, admirábase don Quijote de ver que cuantos le miraban le nombraban y conocían; y, volviéndose a don Antonio, que iba a su lado, le dijo: -Grande es la prerrogativa que encierra en sí la andante caballería, pues hace conocido y famoso al que la profesa por todos los términos de la tierra; si no, mire vuestra merced, señor don Antonio, que hasta los muchachos desta ciudad, sin nunca haberme visto, me conocen. -Así es, señor don Quijote -respondió don Antonio-, que, así como el fuego no puede estar escondido y encerrado, la virtud no puede dejar de ser conocida, y la que se alcanza por la profesión de las armas resplandece y campea sobre todas las otras. Acaeció, pues, que, yendo don Quijote con el aplauso que se ha dicho, un castellano que leyó el rétulo de las espaldas, alzó la voz, diciendo: -¡Válgate el diablo por don Quijote de la Mancha! ¿Cómo que hasta aquí has llegado, sin haberte muerto los infinitos palos que tienes a cuestas? Tu eres loco, y si lo fueras a solas y dentro de las puertas de tu locura, fuera menos mal; pero tienes propiedad de volver locos y mentecatos a cuantos te tratan y comunican; si no, mírenlo por estos señores que te acompañan. Vuélvete, mentecato, a tu casa, y mira por tu hacienda, por tu mujer y tus hijos, y déjate destas vaciedades que te carcomen el seso y te desnatan el entendimiento. -Hermano -dijo don Antonio-, seguid vuestro camino, y no deis consejos a quien no os los pide. El señor don Quijote de la Mancha es muy cuerdo, y nosotros, que le acompañamos, no somos necios; la virtud se ha de honrar dondequiera que se hallare, y andad en hora mala, y no os metáis donde no os llaman. -Pardiez, vuesa merced tiene razón -respondió el castellano-, que aconsejar a este buen hombre es dar coces contra el aguijón; pero, con todo eso, me da muy gran lástima que el buen ingenio que dicen que tiene en todas las cosas este mentecato se le desagüe por la canal de su andante caballería; y la enhoramala que vuesa merced dijo, sea para mí y para todos mis descendientes si de hoy más, aunque viviese más años que Matusalén, diere consejo a nadie, aunque me lo pida. Apartóse el consejero; siguió adelante el paseo; pero fue tanta la priesa que los muchachos y toda la gente tenía leyendo el rétulo, que se le hubo de quitar don Antonio, como que le quitaba otra cosa. Llegó la noche, volviéronse a casa; hubo sarao de damas, porque la mujer de don Antonio, que era una señora principal y alegre, hermosa y discreta, convidó a otras sus amigas a que viniesen a honrar a su huésped y a gustar de sus nunca vistas locuras. Vinieron algunas, cenóse espléndidamente y comenzóse el sarao casi a las diez de la noche. Entre las damas había dos de gusto pícaro y burlonas, y, con ser muy honestas, eran algo descompuestas, por dar lugar que las burlas alegrasen sin enfado. Éstas dieron tanta priesa en sacar a danzar a don Quijote, que le molieron, no sólo el cuerpo, pero el ánima. Era cosa de ver la figura de don Quijote, largo, tendido, flaco, amarillo, estrecho en el vestido, desairado, y, sobre todo, no nada ligero. Requebrábanle como a hurto las damiselas, y él, también como a hurto, las desdeñaba; pero, viéndose apretar de requiebros, alzó la voz y dijo: -Fugite, partes adversae!: dejadme en mi sosiego, pensamientos mal venidos. Allá os avenid, señoras, con vuestros deseos, que la que es reina de los míos, la sin par Dulcinea del Toboso, no consiente que ningunos otros que los suyos me avasallen y rindan. Y, diciendo esto, se sentó en mitad de la sala, en el suelo, molido y quebrantado de tan bailador ejercicio. Hizo don Antonio que le llevasen en peso a su lecho, y el primero que asió dél fue Sancho, diciéndole: -¡Nora en tal, señor nuestro amo, lo habéis bailado! ¿Pensáis que todos los valientes son danzadores y todos los andantes caballeros bailarines? Digo que si lo pensáis, que estáis engañado; hombre hay que se atreverá a matar a un gigante antes que hacer una cabriola. Si hubiérades de zapatear, yo supliera vuestra falta, que zapateo como un girifalte; pero en lo del danzar, no doy puntada. Con estas y otras razones dio que reír Sancho a los del sarao, y dio con su amo en la cama, arropándole para que sudase la frialdad de su baile. Otro día le pareció a don Antonio ser bien hacer la experiencia de la cabeza encantada, y con don Quijote, Sancho y otros dos amigos, con las dos señoras que habían molido a don Quijote en el baile, que aquella propia noche se habían quedado con la mujer de don Antonio, se encerró en la estancia donde estaba la cabeza. Contóles la propiedad que tenía, encargóles el secreto y díjoles que aquél era el primero día donde se había de probar la virtud de la tal cabeza encantada; y si no eran los dos amigos de don Antonio, ninguna otra persona sabía el busilis del encanto, y aun si don Antonio no se le hubiera descubierto primero a sus amigos, también ellos cayeran en la admiración en que los demás cayeron, sin ser posible otra cosa: con tal traza y tal orden estaba fabricada. El primero que se llegó al oído de la cabeza fue el mismo don Antonio, y díjole en voz sumisa, pero no tanto que de todos no fuese entendida: -Dime, cabeza, por la virtud que en ti se encierra: ¿qué pensamientos tengo yo agora? Y la cabeza le respondió, sin mover los labios, con voz clara y distinta, de modo que fue de todos entendida, esta razón: -Yo no juzgo de pensamientos. Oyendo lo cual, todos quedaron atónitos, y más viendo que en todo el aposento ni al derredor de la mesa no había persona humana que responder pudiese. -¿Cuántos estamos aquí? -tornó a preguntar don Antonio. Y fuele respondido por el propio tenor, paso: -Estáis tú y tu mujer, con dos amigos tuyos, y dos amigas della, y un caballero famoso llamado don Quijote de la Mancha, y un su escudero que Sancho Panza tiene por nombre. ¡Aquí sí que fue el admirarse de nuevo, aquí sí que fue el erizarse los cabellos a todos de puro espanto! Y, apartándose don Antonio de la cabeza, dijo: -Esto me basta para darme a entender que no fui engañado del que te me vendió, ¡cabeza sabia, cabeza habladora, cabeza respondona y admirable cabeza! Llegue otro y pregúntele lo que quisiere. Y, como las mujeres de ordinario son presurosas y amigas de saber, la primera que se llegó fue una de las dos amigas de la mujer de don Antonio, y lo que le preguntó fue: -Dime, cabeza, ¿qué haré yo para ser muy hermosa? Y fuele respondido: -Sé muy honesta. -No te pregunto más -dijo la preguntanta. Llegó luego la compañera, y dijo: -Querría saber, cabeza, si mi marido me quiere bien, o no. Y respondiéronle: -Mira las obras que te hace, y echarlo has de ver. Apartóse la casada diciendo: -Esta respuesta no tenía necesidad de pregunta, porque, en efecto, las obras que se hacen declaran la voluntad que tiene el que las hace. Luego llegó uno de los dos amigos de don Antonio, y preguntóle: -¿Quién soy yo? Y fuele respondido: -Tú lo sabes. -No te pregunto eso -respondió el caballero-, sino que me digas si me conoces tú. -Sí conozco -le respondieron-, que eres don Pedro Noriz. -No quiero saber más, pues esto basta para entender, ¡oh cabeza!, que lo sabes todo. Y, apartándose, llegó el otro amigo y preguntóle: -Dime, cabeza, ¿qué deseos tiene mi hijo el mayorazgo? -Ya yo he dicho -le respondieron- que yo no juzgo de deseos, pero, con todo eso, te sé decir que los que tu hijo tiene son de enterrarte. -Eso es -dijo el caballero-: lo que veo por los ojos, con el dedo lo señalo. Y no preguntó más. Llegóse la mujer de don Antonio, y dijo: -Yo no sé, cabeza, qué preguntarte; sólo querría saber de ti si gozaré muchos años de buen marido. Y respondiéronle: -Sí gozarás, porque su salud y su templanza en el vivir prometen muchos años de vida, la cual muchos suelen acortar por su destemplanza. Llegóse luego don Quijote, y dijo: -Dime tú, el que respondes: ¿fue verdad o fue sueño lo que yo cuento que me pasó en la cueva de Montesinos? ¿Serán ciertos los azotes de Sancho mi escudero? ¿Tendrá efeto el desencanto de Dulcinea? -A lo de la cueva -respondieron- hay mucho que decir: de todo tiene; los azotes de Sancho irán de espacio, el desencanto de Dulcinea llegará a debida ejecución. -No quiero saber más -dijo don Quijote-; que como yo vea a Dulcinea desencantada, haré cuenta que vienen de golpe todas las venturas que acertare a desear. El último preguntante fue Sancho, y lo que preguntó fue: -¿Por ventura, cabeza, tendré otro gobierno? ¿Saldré de la estrecheza de escudero? ¿Volveré a ver a mi mujer y a mis hijos? A lo que le respondieron: -Gobernarás en tu casa; y si vuelves a ella, verás a tu mujer y a tus hijos; y, dejando de servir, dejarás de ser escudero. -¡Bueno, par Dios! -dijo Sancho Panza-. Esto yo me lo dijera: no dijera más el profeta Perogrullo. -Bestia -dijo don Quijote-, ¿qué quieres que te respondan? ¿No basta que las respuestas que esta cabeza ha dado correspondan a lo que se le pregunta? -Sí basta -respondió Sancho-, pero quisiera yo que se declarara más y me dijera más. Con esto se acabaron las preguntas y las respuestas, pero no se acabó la admiración en que todos quedaron, excepto los dos amigos de don Antonio, que el caso sabían. El cual quiso Cide Hamete Benengeli declarar luego, por no tener suspenso al mundo, creyendo que algún hechicero y extraordinario misterio en la tal cabeza se encerraba; y así, dice que don Antonio Moreno, a imitación de otra cabeza que vio en Madrid, fabricada por un estampero, hizo ésta en su casa, para entretenerse y suspender a los ignorantes; y la fábrica era de esta suerte: la tabla de la mesa era de palo, pintada y barnizada como jaspe, y el pie sobre que se sostenía era de lo mesmo, con cuatro garras de águila que dél salían, para mayor firmeza del peso. La cabeza, que parecía medalla y figura de emperador romano, y de color de bronce, estaba toda hueca, y ni más ni menos la tabla de la mesa, en que se encajaba tan justamente, que ninguna señal de juntura se parecía. El pie de la tabla era ansimesmo hueco, que respondía a la garganta y pechos de la cabeza, y todo esto venía a responder a otro aposento que debajo de la estancia de la cabeza estaba. Por todo este hueco de pie, mesa, garganta y pechos de la medalla y figura referida se encaminaba un cañón de hoja de lata, muy justo, que de nadie podía ser visto. En el aposento de abajo correspondiente al de arriba se ponía el que había de responder, pegada la boca con el mesmo cañón, de modo que, a modo de cerbatana, iba la voz de arriba abajo y de abajo arriba, en palabras articuladas y claras; y de esta manera no era posible conocer el embuste. Un sobrino de don Antonio, estudiante agudo y discreto, fue el respondiente; el cual, estando avisado de su señor tío de los que habían de entrar con él en aquel día en el aposento de la cabeza, le fue fácil responder con presteza y puntualidad a la primera pregunta; a las demás respondió por conjeturas, y, como discreto, discretamente. Y dice más Cide Hamete: que hasta diez o doce días duró esta maravillosa máquina; pero que, divulgándose por la ciudad que don Antonio tenía en su casa una cabeza encantada, que a cuantos le preguntaban respondía, temiendo no llegase a los oídos de las despiertas centinelas de nuestra Fe, habiendo declarado el caso a los señores inquisidores, le mandaron que lo deshiciese y no pasase más adelante, porque el vulgo ignorante no se escandalizase; pero en la opinión de don Quijote y de Sancho Panza, la cabeza quedó por encantada y por respondona, más a satisfación de don Quijote que de Sancho. Los caballeros de la ciudad, por complacer a don Antonio y por agasajar a don Quijote y dar lugar a que descubriese sus sandeces, ordenaron de correr sortija de allí a seis días; que no tuvo efecto por la ocasión que se dirá adelante. Diole gana a don Quijote de pasear la ciudad a la llana y a pie, temiendo que, si iba a caballo, le habían de perseguir los mochachos, y así, él y Sancho, con otros dos criados que don Antonio le dio, salieron a pasearse. Sucedió, pues, que, yendo por una calle, alzó los ojos don Quijote, y vio escrito sobre una puerta, con letras muy grandes: Aquí se imprimen libros; de lo que se contentó mucho, porque hasta entonces no había visto emprenta alguna, y deseaba saber cómo fuese. Entró dentro, con todo su acompañamiento, y vio tirar en una parte, corregir en otra, componer en ésta, enmendar en aquélla, y, finalmente, toda aquella máquina que en las emprentas grandes se muestra. Llegábase don Quijote a un cajón y preguntaba qué era aquéllo que allí se hacía; dábanle cuenta los oficiales, admirábase y pasaba adelante. Llegó en otras a uno, y preguntóle qué era lo que hacía. El oficial le respondió: -Señor, este caballero que aquí está -y enseñóle a un hombre de muy buen talle y parecer y de alguna gravedad- ha traducido un libro toscano en nuestra lengua castellana, y estoyle yo componiendo, para darle a la estampa. -¿Qué título tiene el libro? -preguntó don Quijote. -A lo que el autor respondió: -Señor, el libro, en toscano, se llama Le bagatele. -Y ¿qué responde le bagatele en nuestro castellano? -preguntó don Quijote. -Le bagatele -dijo el autor- es como si en castellano dijésemos los juguetes; y, aunque este libro es en el nombre humilde, contiene y encierra en sí cosas muy buenas y sustanciales. -Yo -dijo don Quijote- sé algún tanto de el toscano, y me precio de cantar algunas estancias del Ariosto. Pero dígame vuesa merced, señor mío, y no digo esto porque quiero examinar el ingenio de vuestra merced, sino por curiosidad no más: ¿ha hallado en su escritura alguna vez nombrar piñata? -Sí, muchas veces -respondió el autor. -Y ¿cómo la traduce vuestra merced en castellano? -preguntó don Quijote. -¿Cómo la había de traducir -replicó el autor-, sino diciendo olla? -¡Cuerpo de tal -dijo don Quijote-, y qué adelante está vuesa merced en el toscano idioma! Yo apostaré una buena apuesta que adonde diga en el toscano piache, dice vuesa merced en el castellano place; y adonde diga più, dice más, y el su declara con arriba, y el giù con abajo. -Sí declaro, por cierto -dijo el autor-, porque ésas son sus propias correspondencias. -Osaré yo jurar -dijo don Quijote- que no es vuesa merced conocido en el mundo, enemigo siempre de premiar los floridos ingenios ni los loables trabajos. ¡Qué de habilidades hay perdidas por ahí! ¡Qué de ingenios arrinconados! ¡Qué de virtudes menospreciadas! Pero, con todo esto, me parece que el traducir de una lengua en otra, como no sea de las reinas de las lenguas, griega y latina, es como quien mira los tapices flamencos por el revés, que, aunque se veen las figuras, son llenas de hilos que las escurecen, y no se veen con la lisura y tez de la haz; y el traducir de lenguas fáciles, ni arguye ingenio ni elocución, como no le arguye el que traslada ni el que copia un papel de otro papel. Y no por esto quiero inferir que no sea loable este ejercicio del traducir; porque en otras cosas peores se podría ocupar el hombre, y que menos provecho le trujesen. Fuera desta cuenta van los dos famosos traductores: el uno, el doctor Cristóbal de Figueroa, en su Pastor Fido, y el otro, don Juan de Jáurigui, en su Aminta, donde felizmente ponen en duda cuál es la tradución o cuál el original. Pero dígame vuestra merced: este libro, ¿imprímese por su cuenta, o tiene ya vendido el privilegio a algún librero? -Por mi cuenta lo imprimo -respondió el autor-, y pienso ganar mil ducados, por lo menos, con esta primera impresión, que ha de ser de dos mil cuerpos, y se han de despachar a seis reales cada uno, en daca las pajas. -¡Bien está vuesa merced en la cuenta! -respondió don Quijote-. Bien parece que no sabe las entradas y salidas de los impresores, y las correspondencias que hay de unos a otros; yo le prometo que, cuando se vea cargado de dos mil cuerpos de libros, vea tan molido su cuerpo, que se espante, y más si el libro es un poco avieso y no nada picante. -Pues, ¿qué? -dijo el autor-. ¿Quiere vuesa merced que se lo dé a un librero, que me dé por el privilegio tres maravedís, y aún piensa que me hace merced en dármelos? Yo no imprimo mis libros para alcanzar fama en el mundo, que ya en él soy conocido por mis obras: provecho quiero, que sin él no vale un cuatrín la buena fama. -Dios le dé a vuesa merced buena manderecha -respondió don Quijote. Y pasó adelante a otro cajón, donde vio que estaban corrigiendo un pliego de un libro que se intitulaba Luz del alma; y,en viéndole, dijo: -Estos tales libros, aunque hay muchos deste género, son los que se deben imprimir, porque son muchos los pecadores que se usan, y son menester infinitas luces para tantos desalumbrados. Pasó adelante y vio que asimesmo estaban corrigiendo otro libro; y, preguntando su título, le respondieron que se llamaba la Segunda parte del Ingenioso Hidalgo don Quijote de la Mancha, compuesta por un tal vecino de Tordesillas. -Ya yo tengo noticia deste libro -dijo don Quijote-, y en verdad y en mi conciencia que pensé que ya estaba quemado y hecho polvos, por impertinente; pero su San Martín se le llegará, como a cada puerco, que las historias fingidas tanto tienen de buenas y de deleitables cuanto se llegan a la verdad o la semejanza della, y las verdaderas tanto son mejores cuanto son más verdaderas. Y, diciendo esto, con muestras de algún despecho, se salió de la emprenta. Y aquel mesmo día ordenó don Antonio de llevarle a ver las galeras que en la playa estaban, de que Sancho se regocijó mucho, a causa que en su vida las había visto. Avisó don Antonio al cuatralbo de las galeras como aquella tarde había de llevar a verlas a su huésped el famoso don Quijote de la Mancha, de quien ya el cuatralbo y todos los vecinos de la ciudad tenían noticia; y lo que le sucedió en ellas se dirá en el siguiente capítulo. Capítulo LXIII. De lo mal que le avino a Sancho Panza con la visita de las galeras, y la nueva aventura de la hermosa morisca Grandes eran los discursos que don Quijote hacía sobre la respuesta de la encantada cabeza, sin que ninguno dellos diese en el embuste, y todos paraban con la promesa, que él tuvo por cierto, del desencanto de Dulcinea. Allí iba y venía, y se alegraba entre sí mismo, creyendo que había de ver presto su cumplimiento; y Sancho, aunque aborrecía el ser gobernador, como queda dicho, todavía deseaba volver a mandar y a ser obedecido; que esta mala ventura trae consigo el mando, aunque sea de burlas. En resolución, aquella tarde don Antonio Moreno, su huésped, y sus dos amigos, con don Quijote y Sancho, fueron a las galeras. El cuatralbo, que estaba avisado de su buena venida, por ver a los dos tan famosos Quijote y Sancho, apenas llegaron a la marina, cuando todas las galeras abatieron tienda, y sonaron las chirimías; arrojaron luego el esquife al agua, cubierto de ricos tapetes y de almohadas de terciopelo carmesí, y, en poniendo que puso los pies en él don Quijote, disparó la capitana el cañón de crujía, y las otras galeras hicieron lo mesmo, y, al subir don Quijote por la escala derecha, toda la chusma le saludó como es usanza cuando una persona principal entra en la galera, diciendo: ''¡Hu, hu, hu!'' tres veces. Diole la mano el general, que con este nombre le llamaremos, que era un principal caballero valenciano; abrazó a don Quijote, diciéndole: -Este día señalaré yo con piedra blanca, por ser uno de los mejores que pienso llevar en mi vida, habiendo visto al señor don Quijote de la Mancha: tiempo y señal que nos muestra que en él se encierra y cifra todo el valor del andante caballería. Con otras no menos corteses razones le respondió don Quijote, alegre sobremanera de verse tratar tan a lo señor. Entraron todos en la popa, que estaba muy bien aderezada, y sentáronse por los bandines, pasóse el cómitre en crujía, y dio señal con el pito que la chusma hiciese fuera ropa, que se hizo en un instante. Sancho, que vio tanta gente en cueros, quedó pasmado, y más cuando vio hacer tienda con tanta priesa, que a él le pareció que todos los diablos andaban allí trabajando; pero esto todo fueron tortas y pan pintado para lo que ahora diré. Estaba Sancho sentado sobre el estanterol, junto al espalder de la mano derecha, el cual ya avisado de lo que había de hacer, asió de Sancho, y, levantándole en los brazos, toda la chusma puesta en pie y alerta, comenzando de la derecha banda, le fue dando y volteando sobre los brazos de la chusma de banco en banco, con tanta priesa, que el pobre Sancho perdió la vista de los ojos, y sin duda pensó que los mismos demonios le llevaban, y no pararon con él hasta volverle por la siniestra banda y ponerle en la popa. Quedó el pobre molido, y jadeando, y trasudando, sin poder imaginar qué fue lo que sucedido le había. Don Quijote, que vio el vuelo sin alas de Sancho, preguntó al general si eran ceremonias aquéllas que se usaban con los primeros que entraban en las galeras; porque si acaso lo fuese, él, que no tenía intención de profesar en ellas, no quería hacer semejantes ejercicios, y que votaba a Dios que, si alguno llegaba a asirle para voltearle, que le había de sacar el alma a puntillazos; y, diciendo esto, se levantó en pie y empuñó la espada. A este instante abatieron tienda, y con grandísimo ruido dejaron caer la entena de alto abajo. Pensó Sancho que el cielo se desencajaba de sus quicios y venía a dar sobre su cabeza; y, agobiándola, lleno de miedo, la puso entre las piernas. No las tuvo todas consigo don Quijote; que también se estremeció y encogió de hombros y perdió la color del rostro. La chusma izó la entena con la misma priesa y ruido que la habían amainado, y todo esto, callando, como si no tuvieran voz ni aliento. Hizo señal el cómitre que zarpasen el ferro, y, saltando en mitad de la crujía con el corbacho o rebenque, comenzó a mosquear las espaldas de la chusma, y a largarse poco a poco a la mar. Cuando Sancho vio a una moverse tantos pies colorados, que tales pensó él que eran los remos, dijo entre sí: -Éstas sí son verdaderamente cosas encantadas, y no las que mi amo dice. ¿Qué han hecho estos desdichados, que ansí los azotan, y cómo este hombre solo, que anda por aquí silbando, tiene atrevimiento para azotar a tanta gente? Ahora yo digo que éste es infierno, o, por lo menos, el purgatorio. Don Quijote, que vio la atención con que Sancho miraba lo que pasaba, le dijo: -¡Ah Sancho amigo, y con qué brevedad y cuán a poca costa os podíades vos, si quisiésedes, desnudar de medio cuerpo arriba, y poneros entre estos señores, y acabar con el desencanto de Dulcinea! Pues con la miseria y pena de tantos, no sentiríades vos mucho la vuestra; y más, que podría ser que el sabio Merlín tomase en cuenta cada azote déstos, por ser dados de buena mano, por diez de los que vos finalmente os habéis de dar. Preguntar quería el general qué azotes eran aquéllos, o qué desencanto de Dulcinea, cuando dijo el marinero: -Señal hace Monjuí de que hay bajel de remos en la costa por la banda del poniente. Esto oído, saltó el general en la crujía, y dijo: -¡Ea hijos, no se nos vaya! Algún bergantín de cosarios de Argel debe de ser éste que la atalaya nos señala. Llegáronse luego las otras tres galeras a la capitana, a saber lo que se les ordenaba. Mandó el general que las dos saliesen a la mar, y él con la otra iría tierra a tierra, porque ansí el bajel no se les escaparía. Apretó la chusma los remos, impeliendo las galeras con tanta furia, que parecía que volaban. Las que salieron a la mar, a obra de dos millas descubrieron un bajel, que con la vista le marcaron por de hasta catorce o quince bancos, y así era la verdad; el cual bajel, cuando descubrió las galeras, se puso en caza, con intención y esperanza de escaparse por su ligereza; pero avínole mal, porque la galera capitana era de los más ligeros bajeles que en la mar navegaban, y así le fue entrando, que claramente los del bergantín conocieron que no podían escaparse; y así, el arráez quisiera que dejaran los remos y se entregaran, por no irritar a enojo al capitán que nuestras galeras regía. Pero la suerte, que de otra manera lo guiaba, ordenó que, ya que la capitana llegaba tan cerca que podían los del bajel oír las voces que desde ella les decían que se rindiesen, dos toraquís, que es como decir dos turcos borrachos, que en el bergantín venían con estos doce, dispararon dos escopetas, con que dieron muerte a dos soldados que sobre nuestras arrumbadas venían. Viendo lo cual, juró el general de no dejar con vida a todos cuantos en el bajel tomase, y, llegando a embestir con toda furia, se le escapó por debajo de la palamenta. Pasó la galera adelante un buen trecho; los del bajel se vieron perdidos, hicieron vela en tanto que la galera volvía, y de nuevo, a vela y a remo, se pusieron en caza; pero no les aprovechó su diligencia tanto como les dañó su atrevimiento, porque, alcanzándoles la capitana a poco más de media milla, les echó la palamenta encima y los cogió vivos a todos. Llegaron en esto las otras dos galeras, y todas cuatro con la presa volvieron a la playa, donde infinita gente los estaba esperando, deseosos de ver lo que traían. Dio fondo el general cerca de tierra, y conoció que estaba en la marina el virrey de la ciudad. Mandó echar el esquife para traerle, y mandó amainar la entena para ahorcar luego luego al arráez y a los demás turcos que en el bajel había cogido, que serían hasta treinta y seis personas, todos gallardos, y los más, escopeteros turcos. Preguntó el general quién era el arráez del bergantín y fuele respondido por uno de los cautivos, en lengua castellana, que después pareció ser renegado español: -Este mancebo, señor, que aquí vees es nuestro arráez. Y mostróle uno de los más bellos y gallardos mozos que pudiera pintar la humana imaginación. La edad, al parecer, no llegaba a veinte años. Preguntóle el general: -Dime, mal aconsejado perro, ¿quién te movió a matarme mis soldados, pues veías ser imposible el escaparte? ¿Ese respeto se guarda a las capitanas? ¿No sabes tú que no es valentía la temeridad? Las esperanzas dudosas han de hacer a los hombres atrevidos, pero no temerarios. Responder quería el arráez; pero no pudo el general, por entonces, oír la respuesta, por acudir a recebir al virrey, que ya entraba en la galera, con el cual entraron algunos de sus criados y algunas personas del pueblo. -¡Buena ha estado la caza, señor general! -dijo el virrey. -Y tan buena -respondió el general- cual la verá Vuestra Excelencia agora colgada de esta entena. -¿Cómo ansí? -replicó el virrey. -Porque me han muerto -respondió el general-, contra toda ley y contra toda razón y usanza de guerra, dos soldados de los mejores que en estas galeras venían, y yo he jurado de ahorcar a cuantos he cautivado, principalmente a este mozo, que es el arráez del bergantín. Y enseñóle al que ya tenía atadas las manos y echado el cordel a la garganta, esperando la muerte. Miróle el virrey, y, viéndole tan hermoso, y tan gallardo, y tan humilde, dándole en aquel instante una carta de recomendación su hermosura, le vino deseo de escusar su muerte; y así, le preguntó: -Dime, arráez, ¿eres turco de nación, o moro, o renegado? A lo cual el mozo respondió, en lengua asimesmo castellana: -Ni soy turco de nación, ni moro, ni renegado. -Pues, ¿qué eres? -replicó el virrey. -Mujer cristiana -respondió el mancebo. -¿Mujer y cristiana, y en tal traje y en tales pasos? Más es cosa para admirarla que para creerla. -Suspended -dijo el mozo-, ¡oh señores!, la ejecución de mi muerte, que no se perderá mucho en que se dilate vuestra venganza en tanto que yo os cuente mi vida. ¿Quién fuera el de corazón tan duro que con estas razones no se ablandara, o, a lo menos, hasta oír las que el triste y lastimado mancebo decir quería? El general le dijo que dijese lo que quisiese, pero que no esperase alcanzar perdón de su conocida culpa. Con esta licencia, el mozo comenzó a decir desta manera: -«De aquella nación más desdichada que prudente, sobre quien ha llovido estos días un mar de desgracias, nací yo, de moriscos padres engendrada. En la corriente de su desventura fui yo por dos tíos míos llevada a Berbería, sin que me aprovechase decir que era cristiana, como, en efecto, lo soy, y no de las fingidas ni aparentes, sino de las verdaderas y católicas. No me valió, con los que tenían a cargo nuestro miserable destierro, decir esta verdad, ni mis tíos quisieron creerla; antes la tuvieron por mentira y por invención para quedarme en la tierra donde había nacido, y así, por fuerza más que por grado, me trujeron consigo. Tuve una madre cristiana y un padre discreto y cristiano, ni más ni menos; mamé la fe católica en la leche; criéme con buenas costumbres; ni en la lengua ni en ellas jamás, a mi parecer, di señales de ser morisca. Al par y al paso destas virtudes, que yo creo que lo son, creció mi hermosura, si es que tengo alguna; y, aunque mi recato y mi encerramiento fue mucho, no debió de ser tanto que no tuviese lugar de verme un mancebo caballero, llamado don Gaspar Gregorio, hijo mayorazgo de un caballero que junto a nuestro lugar otro suyo tiene. Cómo me vio, cómo nos hablamos, cómo se vio perdido por mí y cómo yo no muy ganada por él, sería largo de contar, y más en tiempo que estoy temiendo que, entre la lengua y la garganta, se ha de atravesar el riguroso cordel que me amenaza; y así, sólo diré cómo en nuestro destierro quiso acompañarme don Gregorio. Mezclóse con los moriscos que de otros lugares salieron, porque sabía muy bien la lengua, y en el viaje se hizo amigo de dos tíos míos que consigo me traían; porque mi padre, prudente y prevenido, así como oyó el primer bando de nuestro destierro, se salió del lugar y se fue a buscar alguno en los reinos estraños que nos acogiese. Dejó encerradas y enterradas, en una parte de quien yo sola tengo noticia, muchas perlas y piedras de gran valor, con algunos dineros en cruzados y doblones de oro. Mandóme que no tocase al tesoro que dejaba en ninguna manera, si acaso antes que él volviese nos desterraban. Hícelo así, y con mis tíos, como tengo dicho, y otros parientes y allegados pasamos a Berbería; y el lugar donde hicimos asiento fue en Argel, como si le hiciéramos en el mismo infierno. Tuvo noticia el rey de mi hermosura, y la fama se la dio de mis riquezas, que, en parte, fue ventura mía. Llamóme ante sí, preguntóme de qué parte de España era y qué dineros y qué joyas traía. Díjele el lugar, y que las joyas y dineros quedaban en él enterrados, pero que con facilidad se podrían cobrar si yo misma volviese por ellos. Todo esto le dije, temerosa de que no le cegase mi hermosura, sino su codicia. Estando conmigo en estas pláticas, le llegaron a decir cómo venía conmigo uno de los más gallardos y hermosos mancebos que se podía imaginar. Luego entendí que lo decían por don Gaspar Gregorio, cuya belleza se deja atrás las mayores que encarecer se pueden. Turbéme, considerando el peligro que don Gregorio corría, porque entre aquellos bárbaros turcos en más se tiene y estima un mochacho o mancebo hermoso que una mujer, por bellísima que sea. Mandó luego el rey que se le trujesen allí delante para verle, y preguntóme si era verdad lo que de aquel mozo le decían. Entonces yo, casi como prevenida del cielo, le dije que sí era; pero que le hacía saber que no era varón, sino mujer como yo, y que le suplicaba me la dejase ir a vestir en su natural traje, para que de todo en todo mostrase su belleza y con menos empacho pareciese ante su presencia. Díjome que fuese en buena hora, y que otro día hablaríamos en el modo que se podía tener para que yo volviese a España a sacar el escondido tesoro. Hablé con don Gaspar, contéle el peligro que corría el mostrar ser hombre; vestíle de mora, y aquella mesma tarde le truje a la presencia del rey, el cual, en viéndole, quedó admirado y hizo disignio de guardarla para hacer presente della al Gran Señor; y, por huir del peligro que en el serrallo de sus mujeres podía tener y temer de sí mismo, la mandó poner en casa de unas principales moras que la guardasen y la sirviesen, adonde le llevaron luego. Lo que los dos sentimos (que no puedo negar que no le quiero) se deje a la consideración de los que se apartan si bien se quieren. Dio luego traza el rey de que yo volviese a España en este bergantín y que me acompañasen dos turcos de nación, que fueron los que mataron vuestros soldados. Vino también conmigo este renegado español -señalando al que había hablado primero-, del cual sé yo bien que es cristiano encubierto y que viene con más deseo de quedarse en España que de volver a Berbería; la demás chusma del bergantín son moros y turcos, que no sirven de más que de bogar al remo. Los dos turcos, codiciosos e insolentes, sin guardar el orden que traíamos de que a mí y a este renegado en la primer parte de España, en hábito de cristianos, de que venimos proveídos, nos echasen en tierra, primero quisieron barrer esta costa y hacer alguna presa, si pudiesen, temiendo que si primero nos echaban en tierra, por algún acidente que a los dos nos sucediese, podríamos descubrir que quedaba el bergantín en la mar, y si acaso hubiese galeras por esta costa, los tomasen. Anoche descubrimos esta playa, y, sin tener noticia destas cuatro galeras, fuimos descubiertos, y nos ha sucedido lo que habéis visto. En resolución: don Gregorio queda en hábito de mujer entre mujeres, con manifiesto peligro de perderse, y yo me veo atadas las manos, esperando, o, por mejor decir, temiendo perder la vida, que ya me cansa.» Éste es, señores, el fin de mi lamentable historia, tan verdadera como desdichada; lo que os ruego es que me dejéis morir como cristiana, pues, como ya he dicho, en ninguna cosa he sido culpante de la culpa en que los de mi nación han caído. Y luego calló, preñados los ojos de tiernas lágrimas, a quien acompañaron muchas de los que presentes estaban. El virrey, tierno y compasivo, sin hablarle palabra, se llegó a ella y le quitó con sus manos el cordel que las hermosas de la mora ligaba. En tanto, pues, que la morisca cristiana su peregrina historia trataba, tuvo clavados los ojos en ella un anciano peregrino que entró en la galera cuando entró el virrey; y, apenas dio fin a su plática la morisca, cuando él se arrojó a sus pies, y, abrazado dellos, con interrumpidas palabras de mil sollozos y suspiros, le dijo: -¡Oh Ana Félix, desdichada hija mía! Yo soy tu padre Ricote, que volvía a buscarte por no poder vivir sin ti, que eres mi alma. A cuyas palabras abrió los ojos Sancho, y alzó la cabeza (que inclinada tenía, pensando en la desgracia de su paseo), y, mirando al peregrino, conoció ser el mismo Ricote que topó el día que salió de su gobierno, y confirmóse que aquélla era su hija, la cual, ya desatada, abrazó a su padre, mezclando sus lágrimas con las suyas; el cual dijo al general y al virrey: -Ésta, señores, es mi hija, más desdichada en sus sucesos que en su nombre. Ana Félix se llama, con el sobrenombre de Ricote, famosa tanto por su hermosura como por mi riqueza. Yo salí de mi patria a buscar en reinos estraños quien nos albergase y recogiese, y, habiéndole hallado en Alemania, volví en este hábito de peregrino, en compañía de otros alemanes, a buscar mi hija y a desenterrar muchas riquezas que dejé escondidas. No hallé a mi hija; hallé el tesoro, que conmigo traigo, y agora, por el estraño rodeo que habéis visto, he hallado el tesoro que más me enriquece, que es a mi querida hija. Si nuestra poca culpa y sus lágrimas y las mías, por la integridad de vuestra justicia, pueden abrir puertas a la misericordia, usadla con nosotros, que jamás tuvimos pensamiento de ofenderos, ni convenimos en ningún modo con la intención de los nuestros, que justamente han sido desterrados. Entonces dijo Sancho: -Bien conozco a Ricote, y sé que es verdad lo que dice en cuanto a ser Ana Félix su hija; que en esotras zarandajas de ir y venir, tener buena o mala intención, no me entremeto. Admirados del estraño caso todos los presentes, el general dijo: -Una por una vuestras lágrimas no me dejarán cumplir mi juramento: vivid, hermosa Ana Félix, los años de vida que os tiene determinados el cielo, y lleven la pena de su culpa los insolentes y atrevidos que la cometieron. Y mandó luego ahorcar de la entena a los dos turcos que a sus dos soldados habían muerto; pero el virrey le pidió encarecidamente no los ahorcase, pues más locura que valentía había sido la suya. Hizo el general lo que el virrey le pedía, porque no se ejecutan bien las venganzas a sangre helada. Procuraron luego dar traza de sacar a don Gaspar Gregorio del peligro en que quedaba. Ofreció Ricote para ello más de dos mil ducados que en perlas y en joyas tenía. Diéronse muchos medios, pero ninguno fue tal como el que dio el renegado español que se ha dicho, el cual se ofreció de volver a Argel en algún barco pequeño, de hasta seis bancos, armado de remeros cristianos, porque él sabía dónde, cómo y cuándo podía y debía desembarcar, y asimismo no ignoraba la casa donde don Gaspar quedaba. Dudaron el general y el virrey el fiarse del renegado, ni confiar de los cristianos que habían de bogar el remo; fióle Ana Félix, y Ricote, su padre, dijo que salía a dar el rescate de los cristianos, si acaso se perdiesen. Firmados, pues, en este parecer, se desembarcó el virrey, y don Antonio Moreno se llevó consigo a la morisca y a su padre, encargándole el virrey que los regalase y acariciase cuanto le fuese posible; que de su parte le ofrecía lo que en su casa hubiese para su regalo. Tanta fue la benevolencia y caridad que la hermosura de Ana Félix infundió en su pecho. Capítulo LXIV. Que trata de la aventura que más pesadumbre dio a don Quijote de cuantas hasta entonces le habían sucedido La mujer de don Antonio Moreno cuenta la historia que recibió grandísimo contento de ver a Ana Félix en su casa. Recibióla con mucho agrado, así enamorada de su belleza como de su discreción, porque en lo uno y en lo otro era estremada la morisca, y toda la gente de la ciudad, como a campana tañida, venían a verla. Dijo don Quijote a don Antonio que el parecer que habían tomado en la libertad de don Gregorio no era bueno, porque tenía más de peligroso que de conveniente, y que sería mejor que le pusiesen a él en Berbería con sus armas y caballo; que él le sacaría a pesar de toda la morisma, como había hecho don Gaiferos a su esposa Melisendra. -Advierta vuesa merced -dijo Sancho, oyendo esto- que el señor don Gaiferos sacó a sus esposa de tierra firme y la llevó a Francia por tierra firme; pero aquí, si acaso sacamos a don Gregorio, no tenemos por dónde traerle a España, pues está la mar en medio. -Para todo hay remedio, si no es para la muerte -respondió don Quijote-; pues, llegando el barco a la marina, nos podremos embarcar en él, aunque todo el mundo lo impida. -Muy bien lo pinta y facilita vuestra merced -dijo Sancho-, pero del dicho al hecho hay gran trecho, y yo me atengo al renegado, que me parece muy hombre de bien y de muy buenas entrañas. Don Antonio dijo que si el renegado no saliese bien del caso, se tomaría el espediente de que el gran don Quijote pasase en Berbería. De allí a dos días partió el renegado en un ligero barco de seis remos por banda, armado de valentísima chusma; y de allí a otros dos se partieron las galeras a Levante, habiendo pedido el general al visorrey fuese servido de avisarle de lo que sucediese en la libertad de don Gregorio y en el caso de Ana Félix; quedó el visorrey de hacerlo así como se lo pedía. Y una mañana, saliendo don Quijote a pasearse por la playa armado de todas sus armas, porque, como muchas veces decía, ellas eran sus arreos, y su descanso el pelear, y no se hallaba sin ellas un punto, vio venir hacía él un caballero, armado asimismo de punta en blanco, que en el escudo traía pintada una luna resplandeciente; el cual, llegándose a trecho que podía ser oído, en altas voces, encaminando sus razones a don Quijote, dijo: -Insigne caballero y jamás como se debe alabado don Quijote de la Mancha, yo soy el Caballero de la Blanca Luna, cuyas inauditas hazañas quizá te le habrán traído a la memoria. Vengo a contender contigo y a probar la fuerza de tus brazos, en razón de hacerte conocer y confesar que mi dama, sea quien fuere, es sin comparación más hermosa que tu Dulcinea del Toboso; la cual verdad si tú la confiesas de llano en llano, escusarás tu muerte y el trabajo que yo he de tomar en dártela; y si tú peleares y yo te venciere, no quiero otra satisfación sino que, dejando las armas y absteniéndote de buscar aventuras, te recojas y retires a tu lugar por tiempo de un año, donde has de vivir sin echar mano a la espada, en paz tranquila y en provechoso sosiego, porque así conviene al aumento de tu hacienda y a la salvación de tu alma; y si tú me vencieres, quedará a tu discreción mi cabeza, y serán tuyos los despojos de mis armas y caballo, y pasará a la tuya la fama de mis hazañas. Mira lo que te está mejor, y respóndeme luego, porque hoy todo el día traigo de término para despachar este negocio. Don Quijote quedó suspenso y atónito, así de la arrogancia del Caballero de la Blanca Luna como de la causa por que le desafiaba; y con reposo y ademán severo le respondió: -Caballero de la Blanca Luna, cuyas hazañas hasta agora no han llegado a mi noticia, yo osaré jurar que jamás habéis visto a la ilustre Dulcinea; que si visto la hubiérades, yo sé que procurárades no poneros en esta demanda, porque su vista os desengañara de que no ha habido ni puede haber belleza que con la suya comparar se pueda; y así, no diciéndoos que mentís, sino que no acertáis en lo propuesto, con las condiciones que habéis referido, aceto vuestro desafío, y luego, porque no se pase el día que traéis determinado; y sólo exceto de las condiciones la de que se pase a mí la fama de vuestras hazañas, porque no sé cuáles ni qué tales sean: con las mías me contento, tales cuales ellas son. Tomad, pues, la parte del campo que quisiéredes, que yo haré lo mesmo, y a quien Dios se la diere, San Pedro se la bendiga. Habían descubierto de la ciudad al Caballero de la Blanca Luna, y díchoselo al visorrey que estaba hablando con don Quijote de la Mancha. El visorrey, creyendo sería alguna nueva aventura fabricada por don Antonio Moreno, o por otro algún caballero de la ciudad, salió luego a la playa con don Antonio y con otros muchos caballeros que le acompañaban, a tiempo cuando don Quijote volvía las riendas a Rocinante para tomar del campo lo necesario. Viendo, pues, el visorrey que daban los dos señales de volverse a encontrar, se puso en medio, preguntándoles qué era la causa que les movía a hacer tan de improviso batalla. El Caballero de la Blanca Luna respondió que era precedencia de hermosura, y en breves razones le dijo las mismas que había dicho a don Quijote, con la acetación de las condiciones del desafío hechas por entrambas partes. Llegóse el visorrey a don Antonio, y preguntóle paso si sabía quién era el tal Caballero de la Blanca Luna, o si era alguna burla que querían hacer a don Quijote. Don Antonio le respondió que ni sabía quién era, ni si era de burlas ni de veras el tal desafío. Esta respuesta tuvo perplejo al visorrey en si les dejaría o no pasar adelante en la batalla; pero, no pudiéndose persuadir a que fuese sino burla, se apartó diciendo: -Señores caballeros, si aquí no hay otro remedio sino confesar o morir, y el señor don Quijote está en sus trece y vuestra merced el de la Blanca Luna en sus catorce, a la mano de Dios, y dense. Agradeció el de la Blanca Luna con corteses y discretas razones al visorrey la licencia que se les daba, y don Quijote hizo lo mesmo; el cual, encomendándose al cielo de todo corazón y a su Dulcinea -como tenía de costumbre al comenzar de las batallas que se le ofrecían-, tornó a tomar otro poco más del campo, porque vio que su contrario hacía lo mesmo, y, sin tocar trompeta ni otro instrumento bélico que les diese señal de arremeter, volvieron entrambos a un mesmo punto las riendas a sus caballos; y, como era más ligero el de la Blanca Luna, llegó a don Quijote a dos tercios andados de la carrera, y allí le encontró con tan poderosa fuerza, sin tocarle con la lanza (que la levantó, al parecer, de propósito), que dio con Rocinante y con don Quijote por el suelo una peligrosa caída. Fue luego sobre él, y, poniéndole la lanza sobre la visera, le dijo: -Vencido sois, caballero, y aun muerto, si no confesáis las condiciones de nuestro desafío. Don Quijote, molido y aturdido, sin alzarse la visera, como si hablara dentro de una tumba, con voz debilitada y enferma, dijo: -Dulcinea del Toboso es la más hermosa mujer del mundo, y yo el más desdichado caballero de la tierra, y no es bien que mi flaqueza defraude esta verdad. Aprieta, caballero, la lanza, y quítame la vida, pues me has quitado la honra. -Eso no haré yo, por cierto -dijo el de la Blanca Luna-: viva, viva en su entereza la fama de la hermosura de la señora Dulcinea del Toboso, que sólo me contento con que el gran don Quijote se retire a su lugar un año, o hasta el tiempo que por mí le fuere mandado, como concertamos antes de entrar en esta batalla. Todo esto oyeron el visorrey y don Antonio, con otros muchos que allí estaban, y oyeron asimismo que don Quijote respondió que como no le pidiese cosa que fuese en perjuicio de Dulcinea, todo lo demás cumpliría como caballero puntual y verdadero. Hecha esta confesión, volvió las riendas el de la Blanca Luna, y, haciendo mesura con la cabeza al visorrey, a medio galope se entró en la ciudad. Mandó el visorrey a don Antonio que fuese tras él, y que en todas maneras supiese quién era. Levantaron a don Quijote, descubriéronle el rostro y halláronle sin color y trasudando. Rocinante, de puro malparado, no se pudo mover por entonces. Sancho, todo triste, todo apesarado, no sabía qué decirse ni qué hacerse: parecíale que todo aquel suceso pasaba en sueños y que toda aquella máquina era cosa de encantamento. Veía a su señor rendido y obligado a no tomar armas en un año; imaginaba la luz de la gloria de sus hazañas escurecida, las esperanzas de sus nuevas promesas deshechas, como se deshace el humo con el viento. Temía si quedaría o no contrecho Rocinante, o deslocado su amo; que no fuera poca ventura si deslocado quedara. Finalmente, con una silla de manos, que mandó traer el visorrey, le llevaron a la ciudad, y el visorrey se volvió también a ella, con deseo de saber quién fuese el Caballero de la Blanca Luna, que de tan mal talante había dejado a don Quijote. Capítulo LXV. Donde se da noticia quién era el de la Blanca Luna, con la libertad de Don Gregorio, y de otros sucesos Siguió don Antonio Moreno al Caballero de la Blanca Luna, y siguiéronle también, y aun persiguiéronle, muchos muchachos, hasta que le cerraron en un mesón dentro de la ciudad. Entró el don Antonio con deseo de conocerle; salió un escudero a recebirle y a desarmarle; encerróse en una sala baja, y con él don Antonio, que no se le cocía el pan hasta saber quién fuese. Viendo, pues, el de la Blanca Luna que aquel caballero no le dejaba, le dijo: -Bien sé, señor, a lo que venís, que es a saber quién soy; y, porque no hay para qué negároslo, en tanto que este mi criado me desarma os lo diré, sin faltar un punto a la verdad del caso. Sabed, señor, que a mí me llaman el bachiller Sansón Carrasco; soy del mesmo lugar de don Quijote de la Mancha, cuya locura y sandez mueve a que le tengamos lástima todos cuantos le conocemos, y entre los que más se la han tenido he sido yo; y, creyendo que está su salud en su reposo y en que se esté en su tierra y en su casa, di traza para hacerle estar en ella; y así, habrá tres meses que le salí al camino como caballero andante, llamándome el Caballero de los Espejos, con intención de pelear con él y vencerle, sin hacerle daño, poniendo por condición de nuestra pelea que el vencido quedase a discreción del vencedor; y lo que yo pensaba pedirle, porque ya le juzgaba por vencido, era que se volviese a su lugar y que no saliese dél en todo un año, en el cual tiempo podría ser curado; pero la suerte lo ordenó de otra manera, porque él me venció a mí y me derribó del caballo, y así, no tuvo efecto mi pensamiento: él prosiguió su camino, y yo me volví, vencido, corrido y molido de la caída, que fue además peligrosa; pero no por esto se me quitó el deseo de volver a buscarle y a vencerle, como hoy se ha visto. Y como él es tan puntual en guardar las órdenes de la andante caballería, sin duda alguna guardará la que le he dado, en cumplimiento de su palabra. Esto es, señor, lo que pasa, sin que tenga que deciros otra cosa alguna; suplícoos no me descubráis ni le digáis a don Quijote quién soy, porque tengan efecto los buenos pensamientos míos y vuelva a cobrar su juicio un hombre que le tiene bonísimo, como le dejen las sandeces de la caballería. -¡Oh señor -dijo don Antonio-, Dios os perdone el agravio que habéis hecho a todo el mundo en querer volver cuerdo al más gracioso loco que hay en él! ¿No veis, señor, que no podrá llegar el provecho que cause la cordura de don Quijote a lo que llega el gusto que da con sus desvaríos? Pero yo imagino que toda la industria del señor bachiller no ha de ser parte para volver cuerdo a un hombre tan rematadamente loco; y si no fuese contra caridad, diría que nunca sane don Quijote, porque con su salud, no solamente perdemos sus gracias, sino las de Sancho Panza, su escudero, que cualquiera dellas puede volver a alegrar a la misma melancolía. Con todo esto, callaré, y no le diré nada, por ver si salgo verdadero en sospechar que no ha de tener efecto la diligencia hecha por el señor Carrasco. El cual respondió que ya una por una estaba en buen punto aquel negocio, de quien esperaba feliz suceso. Y, habiéndose ofrecido don Antonio de hacer lo que más le mandase, se despidió dél; y, hecho liar sus armas sobre un macho, luego al mismo punto, sobre el caballo con que entró en la batalla, se salió de la ciudad aquel mismo día y se volvió a su patria, sin sucederle cosa que obligue a contarla en esta verdadera historia. Contó don Antonio al visorrey todo lo que Carrasco le había contado, de lo que el visorrey no recibió mucho gusto, porque en el recogimiento de don Quijote se perdía el que podían tener todos aquellos que de sus locuras tuviesen noticia. Seis días estuvo don Quijote en el lecho, marrido, triste, pensativo y mal acondicionado, yendo y viniendo con la imaginación en el desdichado suceso de su vencimiento. Consolábale Sancho, y, entre otras razones, le dijo: -Señor mío, alce vuestra merced la cabeza y alégrese, si puede, y dé gracias al cielo que, ya que le derribó en la tierra, no salió con alguna costilla quebrada; y, pues sabe que donde las dan las toman, y que no siempre hay tocinos donde hay estacas, dé una higa al médico, pues no le ha menester para que le cure en esta enfermedad: volvámonos a nuestra casa y dejémonos de andar buscando aventuras por tierras y lugares que no sabemos; y, si bien se considera, yo soy aquí el más perdidoso, aunque es vuestra merced el más mal parado. Yo, que dejé con el gobierno los deseos de ser más gobernador, no dejé la gana de ser conde, que jamás tendrá efecto si vuesa merced deja de ser rey, dejando el ejercicio de su caballería; y así, vienen a volverse en humo mis esperanzas. -Calla, Sancho, pues ves que mi reclusión y retirada no ha de pasar de un año; que luego volveré a mis honrados ejercicios, y no me ha de faltar reino que gane y algún condado que darte. -Dios lo oiga -dijo Sancho-, y el pecado sea sordo, que siempre he oído decir que más vale buena esperanza que ruin posesión. En esto estaban cuando entró don Antonio, diciendo con muestras de grandísimo contento: -¡Albricias, señor don Quijote, que don Gregorio y el renegado que fue por él está en la playa! ¿Qué digo en la playa? Ya está en casa del visorrey, y será aquí al momento. Alegróse algún tanto don Quijote, y dijo: -En verdad que estoy por decir que me holgara que hubiera sucedido todo al revés, porque me obligara a pasar en Berbería, donde con la fuerza de mi brazo diera libertad no sólo a don Gregorio, sino a cuantos cristianos cautivos hay en Berbería. Pero, ¿qué digo, miserable? ¿No soy yo el vencido? ¿No soy yo el derribado? ¿No soy yo el que no puede tomar arma en un año? Pues, ¿qué prometo? ¿De qué me alabo, si antes me conviene usar de la rueca que de la espada? -Déjese deso, señor -dijo Sancho-: viva la gallina, aunque con su pepita, que hoy por ti y mañana por mí; y en estas cosas de encuentros y porrazos no hay tomarles tiento alguno, pues el que hoy cae puede levantarse mañana, si no es que se quiere estar en la cama; quiero decir que se deje desmayar, sin cobrar nuevos bríos para nuevas pendencias. Y levántese vuestra merced agora para recebir a don Gregorio, que me parece que anda la gente alborotada, y ya debe de estar en casa. Y así era la verdad; porque, habiendo ya dado cuenta don Gregorio y el renegado al visorrey de su ida y vuelta, deseoso don Gregorio de ver a Ana Félix, vino con el renegado a casa de don Antonio; y, aunque don Gregorio, cuando le sacaron de Argel, fue con hábitos de mujer, en el barco los trocó por los de un cautivo que salió consigo; pero en cualquiera que viniera, mostrara ser persona para ser codiciada, servida y estimada, porque era hermoso sobremanera, y la edad, al parecer, de diez y siete o diez y ocho años. Ricote y su hija salieron a recebirle: el padre con lágrimas y la hija con honestidad. No se abrazaron unos a otros, porque donde hay mucho amor no suele haber demasiada desenvoltura. Las dos bellezas juntas de don Gregorio y Ana Félix admiraron en particular a todos juntos los que presentes estaban. El silencio fue allí el que habló por los dos amantes, y los ojos fueron las lenguas que descubrieron sus alegres y honestos pensamientos. Contó el renegado la industria y medio que tuvo para sacar a don Gregorio; contó don Gregorio los peligros y aprietos en que se había visto con las mujeres con quien había quedado, no con largo razonamiento, sino con breves palabras, donde mostró que su discreción se adelantaba a sus años. Finalmente, Ricote pagó y satisfizo liberalmente así al renegado como a los que habían bogado al remo. Reincorporóse y redújose el renegado con la Iglesia, y, de miembro podrido, volvió limpio y sano con la penitencia y el arrepentimiento. De allí a dos días trató el visorrey con don Antonio qué modo tendrían para que Ana Félix y su padre quedasen en España, pareciéndoles no ser de inconveniente alguno que quedasen en ella hija tan cristiana y padre, al parecer, tan bien intencionado. Don Antonio se ofreció venir a la corte a negociarlo, donde había de venir forzosamente a otros negocios, dando a entender que en ella, por medio del favor y de las dádivas, muchas cosas dificultosas se acaban. -No -dijo Ricote, que se halló presente a esta plática- hay que esperar en favores ni en dádivas, porque con el gran don Bernardino de Velasco, conde de Salazar, a quien dio Su Majestad cargo de nuestra expulsión, no valen ruegos, no promesas, no dádivas, no lástimas; porque, aunque es verdad que él mezcla la misericordia con la justicia, como él vee que todo el cuerpo de nuestra nación está contaminado y podrido, usa con él antes del cauterio que abrasa que del ungüento que molifica; y así, con prudencia, con sagacidad, con diligencia y con miedos que pone, ha llevado sobre sus fuertes hombros a debida ejecución el peso desta gran máquina, sin que nuestras industrias, estratagemas, solicitudes y fraudes hayan podido deslumbrar sus ojos de Argos, que contino tiene alerta, porque no se le quede ni encubra ninguno de los nuestros, que, como raíz escondida, que con el tiempo venga después a brotar, y a echar frutos venenosos en España, ya limpia, ya desembarazada de los temores en que nuestra muchedumbre la tenía. ¡Heroica resolución del gran Filipo Tercero, y inaudita prudencia en haberla encargado al tal don Bernardino de Velasco! -Una por una, yo haré, puesto allá, las diligencias posibles, y haga el cielo lo que más fuere servido -dijo don Antonio-. Don Gregorio se irá conmigo a consolar la pena que sus padres deben tener por su ausencia; Ana Félix se quedará con mi mujer en mi casa, o en un monasterio, y yo sé que el señor visorrey gustará se quede en la suya el buen Ricote, hasta ver cómo yo negocio. El visorrey consintió en todo lo propuesto, pero don Gregorio, sabiendo lo que pasaba, dijo que en ninguna manera podía ni quería dejar a doña Ana Félix; pero, teniendo intención de ver a sus padres, y de dar traza de volver por ella, vino en el decretado concierto. Quedóse Ana Félix con la mujer de don Antonio, y Ricote en casa del visorrey. Llegóse el día de la partida de don Antonio, y el de don Quijote y Sancho, que fue de allí a otros dos; que la caída no le concedió que más presto se pusiese en camino. Hubo lágrimas, hubo suspiros, desmayos y sollozos al despedirse don Gregorio de Ana Félix. Ofrecióle Ricote a don Gregorio mil escudos, si los quería; pero él no tomó ninguno, sino solos cinco que le prestó don Antonio, prometiendo la paga dellos en la corte. Con esto, se partieron los dos, y don Quijote y Sancho después, como se ha dicho: don Quijote desarmado y de camino, Sancho a pie, por ir el rucio cargado con las armas. Capítulo LXVI. Que trata de lo que verá el que lo leyere, o lo oirá el que lo escuchare leer Al salir de Barcelona, volvió don Quijote a mirar el sitio donde había caído, y dijo: -¡Aquí fue Troya! ¡Aquí mi desdicha, y no mi cobardía, se llevó mis alcanzadas glorias; aquí usó la fortuna conmigo de sus vueltas y revueltas; aquí se escurecieron mis hazañas; aquí, finalmente, cayó mi ventura para jamás levantarse! Oyendo lo cual Sancho, dijo: -Tan de valientes corazones es, señor mío, tener sufrimiento en las desgracias como alegría en las prosperidades; y esto lo juzgo por mí mismo, que si cuando era gobernador estaba alegre, agora que soy escudero de a pie, no estoy triste; porque he oído decir que esta que llaman por ahí Fortuna es una mujer borracha y antojadiza, y, sobre todo, ciega, y así, no vee lo que hace, ni sabe a quién derriba, ni a quién ensalza. -Muy filósofo estás, Sancho -respondió don Quijote-, muy a lo discreto hablas: no sé quién te lo enseña. Lo que te sé decir es que no hay fortuna en el mundo, ni las cosas que en él suceden, buenas o malas que sean, vienen acaso, sino por particular providencia de los cielos, y de aquí viene lo que suele decirse: que cada uno es artífice de su ventura. Yo lo he sido de la mía, pero no con la prudencia necesaria, y así, me han salido al gallarín mis presunciones; pues debiera pensar que al poderoso grandor del caballo del de la Blanca Luna no podía resistir la flaqueza de Rocinante. Atrevíme en fin, hice lo que puede, derribáronme, y, aunque perdí la honra, no perdí, ni puedo perder, la virtud de cumplir mi palabra. Cuando era caballero andante, atrevido y valiente, con mis obras y con mis manos acreditaba mis hechos; y agora, cuando soy escudero pedestre, acreditaré mis palabras cumpliendo la que di de mi promesa. Camina, pues, amigo Sancho, y vamos a tener en nuestra tierra el año del noviciado, con cuyo encerramiento cobraremos virtud nueva para volver al nunca de mí olvidado ejercicio de las armas. -Señor -respondió Sancho-, no es cosa tan gustosa el caminar a pie, que me mueva e incite a hacer grandes jornadas. Dejemos estas armas colgadas de algún árbol, en lugar de un ahorcado, y, ocupando yo las espaldas del rucio, levantados los pies del suelo, haremos las jornadas como vuestra merced las pidiere y midiere; que pensar que tengo de caminar a pie y hacerlas grandes es pensar en lo escusado. -Bien has dicho, Sancho -respondió don Quijote-: cuélguense mis armas por trofeo, y al pie dellas, o alrededor dellas, grabaremos en los árboles lo que en el trofeo de las armas de Roldán estaba escrito: Nadie las mueva que estar no pueda con Roldán a prueba. -Todo eso me parece de perlas -respondió Sancho-; y, si no fuera por la falta que para el camino nos había de hacer Rocinante, también fuera bien dejarle colgado. -¡Pues ni él ni las armas -replicó don Quijote- quiero que se ahorquen, porque no se diga que a buen servicio, mal galardón! -Muy bien dice vuestra merced -respondió Sancho-, porque, según opinión de discretos, la culpa del asno no se ha de echar a la albarda; y, pues deste suceso vuestra merced tiene la culpa, castíguese a sí mesmo, y no revienten sus iras por las ya rotas y sangrientas armas, ni por las mansedumbres de Rocinante, ni por la blandura de mis pies, queriendo que caminen más de lo justo. En estas razones y pláticas se les pasó todo aquel día, y aun otros cuatro, sin sucederles cosa que estorbase su camino; y al quinto día, a la entrada de un lugar, hallaron a la puerta de un mesón mucha gente, que, por ser fiesta, se estaba allí solazando. Cuando llegaba a ellos don Quijote, un labrador alzó la voz diciendo: -Alguno destos dos señores que aquí vienen, que no conocen las partes, dirá lo que se ha de hacer en nuestra apuesta. -Sí diré, por cierto -respondió don Quijote-, con toda rectitud, si es que alcanzo a entenderla. -«Es, pues, el caso -dijo el labrador-, señor bueno, que un vecino deste lugar, tan gordo que pesa once arrobas, desafió a correr a otro su vecino, que no pesa más que cinco. Fue la condición que habían de correr una carrera de cien pasos con pesos iguales; y, habiéndole preguntado al desafiador cómo se había de igualar el peso, dijo que el desafiado, que pesa cinco arrobas, se pusiese seis de hierro a cuestas, y así se igualarían las once arrobas del flaco con las once del gordo.» -Eso no -dijo a esta sazón Sancho, antes que don Quijote respondiese-. Y a mí, que ha pocos días que salí de ser gobernador y juez, como todo el mundo sabe, toca averiguar estas dudas y dar parecer en todo pleito. -Responde en buen hora -dijo don Quijote-, Sancho amigo, que yo no estoy para dar migas a un gato, según traigo alborotado y trastornado el juicio. Con esta licencia, dijo Sancho a los labradores, que estaban muchos alrededor dél la boca abierta, esperando la sentencia de la suya: -Hermanos, lo que el gordo pide no lleva camino, ni tiene sombra de justicia alguna; porque si es verdad lo que se dice, que el desafiado puede escoger las armas, no es bien que éste las escoja tales que le impidan ni estorben el salir vencedor; y así, es mi parecer que el gordo desafiador se escamonde, monde, entresaque, pula y atilde, y saque seis arrobas de sus carnes, de aquí o de allí de su cuerpo, como mejor le pareciere y estuviere; y desta manera, quedando en cinco arrobas de peso, se igualará y ajustará con las cinco de su contrario, y así podrán correr igualmente. -¡Voto a tal -dijo un labrador que escuchó la sentencia de Sancho- que este señor ha hablado como un bendito y sentenciado como un canónigo! Pero a buen seguro que no ha de querer quitarse el gordo una onza de sus carnes, cuanto más seis arrobas. -Lo mejor es que no corran -respondió otro-, porque el flaco no se muela con el peso, ni el gordo se descarne; y échese la mitad de la apuesta en vino, y llevemos estos señores a la taberna de lo caro, y sobre mí la capa cuando llueva. -Yo, señores -respondió don Quijote-, os lo agradezco, pero no puedo detenerme un punto, porque pensamientos y sucesos tristes me hacen parecer descortés y caminar más que de paso. Y así, dando de las espuelas a Rocinante, pasó adelante, dejándolos admirados de haber visto y notado así su estraña figura como la discreción de su criado, que por tal juzgaron a Sancho. Y otro de los labradores dijo: -Si el criado es tan discreto, ¡cuál debe de ser el amo! Yo apostaré que si van a estudiar a Salamanca, que a un tris han de venir a ser alcaldes de corte; que todo es burla, sino estudiar y más estudiar, y tener favor y ventura; y cuando menos se piensa el hombre, se halla con una vara en la mano o con una mitra en la cabeza. Aquella noche la pasaron amo y mozo en mitad del campo, al cielo raso y descubierto; y otro día, siguiendo su camino, vieron que hacia ellos venía un hombre de a pie, con unas alforjas al cuello y una azcona o chuzo en la mano, propio talle de correo de a pie; el cual, como llegó junto a don Quijote, adelantó el paso, y medio corriendo llegó a él, y, abrazándole por el muslo derecho, que no alcanzaba a más, le dijo, con muestras de mucha alegría: -¡Oh mi señor don Quijote de la Mancha, y qué gran contento ha de llegar al corazón de mi señor el duque cuando sepa que vuestra merced vuelve a su castillo, que todavía se está en él con mi señora la duquesa! -No os conozco, amigo -respondió don Quijote-, ni sé quién sois, si vos no me lo decís. -Yo, señor don Quijote -respondió el correo-, soy Tosilos, el lacayo del duque mi señor, que no quise pelear con vuestra merced sobre el casamiento de la hija de doña Rodríguez. -¡Válame Dios! -dijo don Quijote-. ¿Es posible que sois vos el que los encantadores mis enemigos transformaron en ese lacayo que decís, por defraudarme de la honra de aquella batalla? -Calle, señor bueno -replicó el cartero-, que no hubo encanto alguno ni mudanza de rostro ninguna: tan lacayo Tosilos entré en la estacada como Tosilos lacayo salí della. Yo pensé casarme sin pelear, por haberme parecido bien la moza, pero sucedióme al revés mi pensamiento, pues, así como vuestra merced se partió de nuestro castillo, el duque mi señor me hizo dar cien palos por haber contravenido a las ordenanzas que me tenía dadas antes de entrar en la batalla, y todo ha parado en que la muchacha es ya monja, y doña Rodríguez se ha vuelto a Castilla, y yo voy ahora a Barcelona, a llevar un pliego de cartas al virrey, que le envía mi amo. Si vuestra merced quiere un traguito, aunque caliente, puro, aquí llevo una calabaza llena de lo caro, con no sé cuántas rajitas de queso de Tronchón, que servirán de llamativo y despertador de la sed, si acaso está durmiendo. -Quiero el envite -dijo Sancho-, y échese el resto de la cortesía, y escancie el buen Tosilos, a despecho y pesar de cuantos encantadores hay en las Indias. -En fin -dijo don Quijote-, tú eres, Sancho, el mayor glotón del mundo y el mayor ignorante de la tierra, pues no te persuades que este correo es encantado, y este Tosilos contrahecho. Quédate con él y hártate, que yo me iré adelante poco a poco, esperándote a que vengas. Rióse el lacayo, desenvainó su calabaza, desalforjó sus rajas, y, sacando un panecillo, él y Sancho se sentaron sobre la yerba verde, y en buena paz compaña despabilaron y dieron fondo con todo el repuesto de las alforjas, con tan buenos alientos, que lamieron el pliego de las cartas, sólo porque olía a queso. Dijo Tosilos a Sancho: -Sin duda este tu amo, Sancho amigo, debe de ser un loco. -¿Cómo debe? -respondió Sancho-. No debe nada a nadie, que todo lo paga, y más cuando la moneda es locura. Bien lo veo yo, y bien se lo digo a él; pero, ¿qué aprovecha? Y más agora que va rematado, porque va vencido del Caballero de la Blanca Luna. Rogóle Tosilos le contase lo que le había sucedido, pero Sancho le respondió que era descortesía dejar que su amo le esperase; que otro día, si se encontrasen, habría lugar par ello. Y, levantándose, después de haberse sacudido el sayo y las migajas de las barbas, antecogió al rucio, y, diciendo ''a Dios'', dejó a Tosilos y alcanzó a su amo, que a la sombra de un árbol le estaba esperando. Capítulo LXVII. De la resolución que tomó don Quijote de hacerse pastor y seguir la vida del campo, en tanto que se pasaba el año de su promesa, con otros sucesos en verdad gustosos y buenos Si muchos pensamientos fatigaban a don Quijote antes de ser derribado, muchos más le fatigaron después de caído. A la sombra del árbol estaba, como se ha dicho, y allí, como moscas a la miel, le acudían y picaban pensamientos: unos iban al desencanto de Dulcinea y otros a la vida que había de hacer en su forzosa retirada. Llegó Sancho y alabóle la liberal condición del lacayo Tosilos. -¿Es posible -le dijo don Quijote- que todavía, ¡oh Sancho!, pienses que aquél sea verdadero lacayo? Parece que se te ha ido de las mientes haber visto a Dulcinea convertida y transformada en labradora, y al Caballero de los Espejos en el bachiller Carrasco, obras todas de los encantadores que me persiguen. Pero dime agora: ¿preguntaste a ese Tosilos que dices qué ha hecho Dios de Altisidora: si ha llorado mi ausencia, o si ha dejado ya en las manos del olvido los enamorados pensamientos que en mi presencia la fatigaban? -No eran -respondió Sancho- los que yo tenía tales que me diesen lugar a preguntar boberías. ¡Cuerpo de mí!, señor, ¿está vuestra merced ahora en términos de inquirir pensamientos ajenos, especialmente amorosos? -Mira, Sancho -dijo don Quijote-, mucha diferencia hay de las obras que se hacen por amor a las que se hacen por agradecimiento. Bien puede ser que un caballero sea desamorado, pero no puede ser, hablando en todo rigor, que sea desagradecido. Quísome bien, al parecer, Altisidora; diome los tres tocadores que sabes, lloró en mi partida, maldíjome, vituperóme, quejóse, a despecho de la vergüenza, públicamente: señales todas de que me adoraba, que las iras de los amantes suelen parar en maldiciones. Yo no tuve esperanzas que darle, ni tesoros que ofrecerle, porque las mías las tengo entregadas a Dulcinea, y los tesoros de los caballeros andantes son, como los de los duendes, aparentes y falsos, y sólo puedo darle estos acuerdos que della tengo, sin perjuicio, pero, de los que tengo de Dulcinea, a quien tú agravias con la remisión que tienes en azotarte y en castigar esas carnes, que vea yo comidas de lobos, que quieren guardarse antes para los gusanos que para el remedio de aquella pobre señora. -Señor -respondió Sancho-, si va a decir la verdad, yo no me puedo persuadir que los azotes de mis posaderas tengan que ver con los desencantos de los encantados, que es como si dijésemos: "Si os duele la cabeza, untaos las rodillas". A lo menos, yo osaré jurar que en cuantas historias vuesa merced ha leído que tratan de la andante caballería no ha visto algún desencantado por azotes; pero, por sí o por no, yo me los daré, cuando tenga gana y el tiempo me dé comodidad para castigarme. -Dios lo haga -respondió don Quijote-, y los cielos te den gracia para que caigas en la cuenta y en la obligación que te corre de ayudar a mi señora, que lo es tuya, pues tú eres mío. En estas pláticas iban siguiendo su camino, cuando llegaron al mesmo sitio y lugar donde fueron atropellados de los toros. Reconocióle don Quijote; dijo a Sancho: -Éste es el prado donde topamos a las bizarras pastoras y gallardos pastores que en él querían renovar e imitar a la pastoral Arcadia, pensamiento tan nuevo como discreto, a cuya imitación, si es que a ti te parece bien, querría, ¡oh Sancho!, que nos convirtiésemos en pastores, siquiera el tiempo que tengo de estar recogido. Yo compraré algunas ovejas, y todas las demás cosas que al pastoral ejercicio son necesarias, y llamándome yo el pastor Quijotiz, y tú el pastor Pancino, nos andaremos por los montes, por las selvas y por los prados, cantando aquí, endechando allí, bebiendo de los líquidos cristales de las fuentes, o ya de los limpios arroyuelos, o de los caudalosos ríos. Daránnos con abundantísima mano de su dulcísimo fruto las encinas, asiento los troncos de los durísimos alcornoques, sombra los sauces, olor las rosas, alfombras de mil colores matizadas los estendidos prados, aliento el aire claro y puro, luz la luna y las estrellas, a pesar de la escuridad de la noche, gusto el canto, alegría el lloro, Apolo versos, el amor conceptos, con que podremos hacernos eternos y famosos, no sólo en los presentes, sino en los venideros siglos. -Pardiez -dijo Sancho-, que me ha cuadrado, y aun esquinado, tal género de vida; y más, que no la ha de haber aún bien visto el bachiller Sansón Carrasco y maese Nicolás el barbero, cuando la han de querer seguir, y hacerse pastores con nosotros; y aun quiera Dios no le venga en voluntad al cura de entrar también en el aprisco, según es de alegre y amigo de holgarse. -Tú has dicho muy bien -dijo don Quijote-; y podrá llamarse el bachiller Sansón Carrasco, si entra en el pastoral gremio, como entrará sin duda, el pastor Sansonino, o ya el pastor Carrascón; el barbero Nicolás se podrá llamar Miculoso, como ya el antiguo Boscán se llamó Nemoroso; al cura no sé qué nombre le pongamos, si no es algún derivativo de su nombre, llamándole el pastor Curiambro. Las pastoras de quien hemos de ser amantes, como entre peras podremos escoger sus nombres; y, pues el de mi señora cuadra así al de pastora como al de princesa, no hay para qué cansarme en buscar otro que mejor le venga; tú, Sancho, pondrás a la tuya el que quisieres. -No pienso -respondió Sancho- ponerle otro alguno sino el de Teresona, que le vendrá bien con su gordura y con el propio que tiene, pues se llama Teresa; y más, que, celebrándola yo en mis versos, vengo a descubrir mis castos deseos, pues no ando a buscar pan de trastrigo por las casas ajenas. El cura no será bien que tenga pastora, por dar buen ejemplo; y si quisiere el bachiller tenerla, su alma en su palma. -¡Válame Dios -dijo don Quijote-, y qué vida nos hemos de dar, Sancho amigo! ¡Qué de churumbelas han de llegar a nuestros oídos, qué de gaitas zamoranas, qué tamborines, y qué de sonajas, y qué de rabeles! Pues, ¡qué si destas diferencias de músicas resuena la de los albogues! Allí se verá casi todos los instrumentos pastorales. -¿Qué son albogues -preguntó Sancho-, que ni los he oído nombrar, ni los he visto en toda mi vida? -Albogues son -respondió don Quijote- unas chapas a modo de candeleros de azófar, que, dando una con otra por lo vacío y hueco, hace un son, si no muy agradable ni armónico, no descontenta, y viene bien con la rusticidad de la gaita y del tamborín; y este nombre albogues es morisco, como lo son todos aquellos que en nuestra lengua castellana comienzan en al, conviene a saber: almohaza, almorzar, alhombra, alguacil, alhucema, almacén, alcancía, y otros semejantes, que deben ser pocos más; y solos tres tiene nuestra lengua que son moriscos y acaban en i, y son: borceguí, zaquizamí y maravedí. Alhelí y alfaquí, tanto por el al primero como por el i en que acaban, son conocidos por arábigos. Esto te he dicho, de paso, por habérmelo reducido a la memoria la ocasión de haber nombrado albogues; y hanos de ayudar mucho al parecer en perfeción este ejercicio el ser yo algún tanto poeta, como tú sabes, y el serlo también en estremo el bachiller Sansón Carrasco. Del cura no digo nada; pero yo apostaré que debe de tener sus puntas y collares de poeta; y que las tenga también maese Nicolás, no dudo en ello, porque todos, o los más, son guitarristas y copleros. Yo me quejaré de ausencia; tú te alabarás de firme enamorado; el pastor Carrascón, de desdeñado; y el cura Curiambro, de lo que él más puede servirse, y así, andará la cosa que no haya más que desear. A lo que respondió Sancho: -Yo soy, señor, tan desgraciado que temo no ha de llegar el día en que en tal ejercicio me vea. ¡Oh, qué polidas cuchares tengo de hacer cuando pastor me vea! ¡Qué de migas, qué de natas, qué de guirnaldas y qué de zarandajas pastoriles, que, puesto que no me granjeen fama de discreto, no dejarán de granjearme la de ingenioso! Sanchica mi hija nos llevará la comida al hato. Pero, ¡guarda!, que es de buen parecer, y hay pastores más maliciosos que simples, y no querría que fuese por lana y volviese trasquilada; y también suelen andar los amores y los no buenos deseos por los campos como por las ciudades, y por las pastorales chozas como por los reales palacios, y, quitada la causa se quita el pecado; y ojos que no veen, corazón que no quiebra; y más vale salto de mata que ruego de hombres buenos. -No más refranes, Sancho -dijo don Quijote-, pues cualquiera de los que has dicho basta para dar a entender tu pensamiento; y muchas veces te he aconsejado que no seas tan pródigo en refranes y que te vayas a la mano en decirlos; pero paréceme que es predicar en desierto, y "castígame mi madre, y yo trómpogelas". -Paréceme -respondió Sancho- que vuesa merced es como lo que dicen: "Dijo la sartén a la caldera: Quítate allá ojinegra". Estáme reprehendiendo que no diga yo refranes, y ensártalos vuesa merced de dos en dos. -Mira, Sancho -respondió don Quijote-: yo traigo los refranes a propósito, y vienen cuando los digo como anillo en el dedo; pero tráeslos tan por los cabellos, que los arrastras, y no los guías; y si no me acuerdo mal, otra vez te he dicho que los refranes son sentencias breves, sacadas de la experiencia y especulación de nuestros antiguos sabios; y el refrán que no viene a propósito, antes es disparate que sentencia. Pero dejémonos desto, y, pues ya viene la noche, retirémonos del camino real algún trecho, donde pasaremos esta noche, y Dios sabe lo que será mañana. Retiráronse, cenaron tarde y mal, bien contra la voluntad de Sancho, a quien se le representaban las estrechezas de la andante caballería usadas en las selvas y en los montes, si bien tal vez la abundancia se mostraba en los castillos y casas, así de don Diego de Miranda como en las bodas del rico Camacho, y de don Antonio Moreno; pero consideraba no ser posible ser siempre de día ni siempre de noche, y así, pasó aquélla durmiendo, y su amo velando. Capítulo LXVIII. De la cerdosa aventura que le aconteció a don Quijote Era la noche algo escura, puesto que la luna estaba en el cielo, pero no en parte que pudiese ser vista: que tal vez la señora Diana se va a pasear a los antípodas, y deja los montes negros y los valles escuros. Cumplió don Quijote con la naturaleza durmiendo el primer sueño, sin dar lugar al segundo; bien al revés de Sancho, que nunca tuvo segundo, porque le duraba el sueño desde la noche hasta la mañana, en que se mostraba su buena complexión y pocos cuidados. Los de don Quijote le desvelaron de manera que despertó a Sancho y le dijo: -Maravillado estoy, Sancho, de la libertad de tu condición: yo imagino que eres hecho de mármol, o de duro bronce, en quien no cabe movimiento ni sentimiento alguno. Yo velo cuando tú duermes, yo lloro cuando cantas, yo me desmayo de ayuno cuanto tú estás perezoso y desalentado de puro harto. De buenos criados es conllevar las penas de sus señores y sentir sus sentimientos, por el bien parecer siquiera. Mira la serenidad desta noche, la soledad en que estamos, que nos convida a entremeter alguna vigilia entre nuestro sueño. Levántate, por tu vida, y desvíate algún trecho de aquí, y con buen ánimo y denuedo agradecido date trecientos o cuatrocientos azotes a buena cuenta de los del desencanto de Dulcinea; y esto rogando te lo suplico, que no quiero venir contigo a los brazos, como la otra vez, porque sé que los tienes pesados. Después que te hayas dado, pasaremos lo que resta de la noche cantando, yo mi ausencia y tú tu firmeza, dando desde agora principio al ejercicio pastoral que hemos de tener en nuestra aldea. -Señor -respondió Sancho-, no soy yo religioso para que desde la mitad de mi sueño me levante y me dicipline, ni menos me parece que del estremo del dolor de los azotes se pueda pasar al de la música. Vuesa merced me deje dormir y no me apriete en lo del azotarme; que me hará hacer juramento de no tocarme jamás al pelo del sayo, no que al de mis carnes. -¡Oh alma endurecida! ¡Oh escudero sin piedad! ¡Oh pan mal empleado y mercedes mal consideradas las que te he hecho y pienso de hacerte! Por mí te has visto gobernador, y por mí te vees con esperanzas propincuas de ser conde, o tener otro título equivalente, y no tardará el cumplimiento de ellas más de cuanto tarde en pasar este año; que yo post tenebras spero lucem. -No entiendo eso -replico Sancho-; sólo entiendo que, en tanto que duermo, ni tengo temor, ni esperanza, ni trabajo ni gloria; y bien haya el que inventó el sueño, capa que cubre todos los humanos pensamientos, manjar que quita la hambre, agua que ahuyenta la sed, fuego que calienta el frío, frío que templa el ardor, y, finalmente, moneda general con que todas las cosas se compran, balanza y peso que iguala al pastor con el rey y al simple con el discreto. Sola una cosa tiene mala el sueño, según he oído decir, y es que se parece a la muerte, pues de un dormido a un muerto hay muy poca diferencia. -Nunca te he oído hablar, Sancho -dijo don Quijote-, tan elegantemente como ahora, por donde vengo a conocer ser verdad el refrán que tú algunas veces sueles decir: "No con quien naces, sino con quien paces". -¡Ah, pesia tal -replicó Sancho-, señor nuestro amo! No soy yo ahora el que ensarta refranes, que también a vuestra merced se le caen de la boca de dos en dos mejor que a mí, sino que debe de haber entre los míos y los suyos esta diferencia: que los de vuestra merced vendrán a tiempo y los míos a deshora; pero, en efecto, todos son refranes. En esto estaban, cuando sintieron un sordo estruendo y un áspero ruido, que por todos aquellos valles se estendía. Levantóse en pie don Quijote y puso mano a la espada, y Sancho se agazapó debajo del rucio, poniéndose a los lados el lío de las armas, y la albarda de su jumento, tan temblando de miedo como alborotado don Quijote. De punto en punto iba creciendo el ruido, y, llegándose cerca a los dos temerosos; a lo menos, al uno, que al otro, ya se sabe su valentía. Es, pues, el caso que llevaban unos hombres a vender a una feria más de seiscientos puercos, con los cuales caminaban a aquellas horas, y era tanto el ruido que llevaban y el gruñir y el bufar, que ensordecieron los oídos de don Quijote y de Sancho, que no advirtieron lo que ser podía. Llegó de tropel la estendida y gruñidora piara, y, sin tener respeto a la autoridad de don Quijote, ni a la de Sancho, pasaron por cima de los dos, deshaciendo las trincheas de Sancho, y derribando no sólo a don Quijote, sino llevando por añadidura a Rocinante. El tropel, el gruñir, la presteza con que llegaron los animales inmundos, puso en confusión y por el suelo a la albarda, a las armas, al rucio, a Rocinante, a Sancho y a don Quijote. Levantóse Sancho como mejor pudo, y pidió a su amo la espada, diciéndole que quería matar media docena de aquellos señores y descomedidos puercos, que ya había conocido que lo eran. Don Quijote le dijo: -Déjalos estar, amigo, que esta afrenta es pena de mi pecado, y justo castigo del cielo es que a un caballero andante vencido le coman adivas, y le piquen avispas y le hollen puercos. -También debe de ser castigo del cielo -respondió Sancho- que a los escuderos de los caballeros vencidos los puncen moscas, los coman piojos y les embista la hambre. Si los escuderos fuéramos hijos de los caballeros a quien servimos, o parientes suyos muy cercanos, no fuera mucho que nos alcanzara la pena de sus culpas hasta la cuarta generación; pero, ¿qué tienen que ver los Panzas con los Quijotes? Ahora bien: tornémonos a acomodar y durmamos lo poco que queda de la noche, y amanecerá Dios y medraremos. -Duerme tú, Sancho -respondió don Quijote-, que naciste para dormir; que yo, que nací para velar, en el tiempo que falta de aquí al día, daré rienda a mis pensamientos, y los desfogaré en un madrigalete, que, sin que tú lo sepas, anoche compuse en la memoria. -A mí me parece -respondió Sancho- que los pensamientos que dan lugar a hacer coplas no deben de ser muchos. Vuesa merced coplee cuanto quisiere, que yo dormiré cuanto pudiere. Y luego, tomando en el suelo cuanto quiso, se acurrucó y durmió a sueño suelto, sin que fianzas, ni deudas, ni dolor alguno se lo estorbase. Don Quijote, arrimado a un tronco de una haya o de un alcornoque -que Cide Hamete Benengeli no distingue el árbol que era-, al son de sus mesmos suspiros, cantó de esta suerte: -Amor, cuando yo pienso en el mal que me das, terrible y fuerte, voy corriendo a la muerte, pensando así acabar mi mal inmenso; mas, en llegando al paso que es puerto en este mar de mi tormento, tanta alegría siento, que la vida se esfuerza y no le paso. Así el vivir me mata, que la muerte me torna a dar la vida. ¡Oh condición no oída, la que conmigo muerte y vida trata! Cada verso déstos acompañaba con muchos suspiros y no pocas lágrimas, bien como aquél cuyo corazón tenía traspasado con el dolor del vencimiento y con la ausencia de Dulcinea. Llegóse en esto el día, dio el sol con sus rayos en los ojos a Sancho, despertó y esperezóse, sacudiéndose y estirándose los perezosos miembros; miró el destrozo que habían hecho los puercos en su repostería, y maldijo la piara y aun más adelante. Finalmente, volvieron los dos a su comenzado camino, y al declinar de la tarde vieron que hacia ellos venían hasta diez hombres de a caballo y cuatro o cinco de a pie. Sobresaltóse el corazón de don Quijote y azoróse el de Sancho, porque la gente que se les llegaba traía lanzas y adargas y venía muy a punto de guerra. Volvióse don Quijote a Sancho, y díjole: -Si yo pudiera, Sancho, ejercitar mis armas, y mi promesa no me hubiera atado los brazos, esta máquina que sobre nosotros viene la tuviera yo por tortas y pan pintado, pero podría ser fuese otra cosa de la que tememos. Llegaron, en esto, los de a caballo, y arbolando las lanzas, sin hablar palabra alguna rodearon a don Quijote y se las pusieron a las espaldas y pechos, amenazándole de muerte. Uno de los de a pie, puesto un dedo en la boca, en señal de que callase, asió del freno de Rocinante y le sacó del camino; y los demás de a pie, antecogiendo a Sancho y al rucio, guardando todos maravilloso silencio, siguieron los pasos del que llevaba a don Quijote, el cual dos o tres veces quiso preguntar adónde le llevaban o qué querían; pero, apenas comenzaba a mover los labios, cuando se los iban a cerrar con los hierros de las lanzas; y a Sancho le acontecía lo mismo, porque, apenas daba muestras de hablar, cuando uno de los de a pie, con un aguijón, le punzaba, y al rucio ni más ni menos como si hablar quisiera. Cerró la noche, apresuraron el paso, creció en los dos presos el miedo, y más cuando oyeron que de cuando en cuando les decían: -¡Caminad, trogloditas! -¡Callad, bárbaros! -¡Pagad, antropófagos! -¡No os quejéis, scitas, ni abráis los ojos, Polifemos matadores, leones carniceros! Y otros nombres semejantes a éstos, con que atormentaban los oídos de los miserables amo y mozo. Sancho iba diciendo entre sí: -¿Nosotros tortolitas? ¿Nosotros barberos ni estropajos? ¿Nosotros perritas, a quien dicen cita, cita? No me contentan nada estos nombres: a mal viento va esta parva; todo el mal nos viene junto, como al perro los palos, y ¡ojalá parase en ellos lo que amenaza esta aventura tan desventurada! Iba don Quijote embelesado, sin poder atinar con cuantos discursos hacía qué serían aquellos nombres llenos de vituperios que les ponían, de los cuales sacaba en limpio no esperar ningún bien y temer mucho mal. Llegaron, en esto, un hora casi de la noche, a un castillo, que bien conoció don Quijote que era el del duque, donde había poco que habían estado. -¡Váleme Dios! -dijo, así como conoció la estancia- y ¿qué será esto? Sí que en esta casa todo es cortesía y buen comedimiento, pero para los vencidos el bien se vuelve en mal y el mal en peor. Entraron al patio principal del castillo, y viéronle aderezado y puesto de manera que les acrecentó la admiración y les dobló el miedo, como se verá en el siguiente capítulo. Capítulo LXIX. Del más raro y más nuevo suceso que en todo el discurso desta grande historia avino a don Quijote Apeáronse los de a caballo, y, junto con los de a pie, tomando en peso y arrebatadamente a Sancho y a don Quijote, los entraron en el patio, alrededor del cual ardían casi cien hachas, puestas en sus blandones, y, por los corredores del patio, más de quinientas luminarias; de modo que, a pesar de la noche, que se mostraba algo escura, no se echaba de ver la falta del día. En medio del patio se levantaba un túmulo como dos varas del suelo, cubierto todo con un grandísimo dosel de terciopelo negro, alrededor del cual, por sus gradas, ardían velas de cera blanca sobre más de cien candeleros de plata; encima del cual túmulo se mostraba un cuerpo muerto de una tan hermosa doncella, que hacía parecer con su hermosura hermosa a la misma muerte. Tenía la cabeza sobre una almohada de brocado, coronada con una guirnalda de diversas y odoríferas flores tejida, las manos cruzadas sobre el pecho, y, entre ellas, un ramo de amarilla y vencedora palma. A un lado del patio estaba puesto un teatro, y en dos sillas sentados dos personajes, que, por tener coronas en la cabeza y ceptros en las manos, daban señales de ser algunos reyes, ya verdaderos o ya fingidos. Al lado deste teatro, adonde se subía por algunas gradas, estaban otras dos sillas, sobre las cuales los que trujeron los presos sentaron a don Quijote y a Sancho, todo esto callando y dándoles a entender con señales a los dos que asimismo callasen; pero, sin que se lo señalaran, callaron ellos, porque la admiración de lo que estaban mirando les tenía atadas las lenguas. Subieron, en esto, al teatro, con mucho acompañamiento, dos principales personajes, que luego fueron conocidos de don Quijote ser el duque y la duquesa, sus huéspedes, los cuales se sentaron en dos riquísimas sillas, junto a los dos que parecían reyes. ¿Quién no se había de admirar con esto, añadiéndose a ello haber conocido don Quijote que el cuerpo muerto que estaba sobre el túmulo era el de la hermosa Altisidora? Al subir el duque y la duquesa en el teatro, se levantaron don Quijote y Sancho y les hicieron una profunda humillación, y los duques hicieron lo mesmo, inclinando algún tanto las cabezas. Salió, en esto, de través un ministro, y, llegándose a Sancho, le echó una ropa de bocací negro encima, toda pintada con llamas de fuego, y, quitándole la caperuza, le puso en la cabeza una coroza, al modo de las que sacan los penitenciados por el Santo Oficio; y díjole al oído que no descosiese los labios, porque le echarían una mordaza, o le quitarían la vida. Mirábase Sancho de arriba abajo, veíase ardiendo en llamas, pero como no le quemaban, no las estimaba en dos ardites. Quitóse la coroza, viola pintada de diablos, volviósela a poner, diciendo entre sí: -Aún bien, que ni ellas me abrasan ni ellos me llevan. Mirábale también don Quijote, y, aunque el temor le tenía suspensos los sentidos, no dejó de reírse de ver la figura de Sancho. Comenzó, en esto, a salir, al parecer, debajo del túmulo un son sumiso y agradable de flautas, que, por no ser impedido de alguna humana voz, porque en aquel sitio el mesmo silencio guardaba silencio a sí mismo, se mostraba blando y amoroso. Luego hizo de sí improvisa muestra, junto a la almohada del, al parecer, cadáver, un hermoso mancebo vestido a lo romano, que, al son de una arpa, que él mismo tocaba, cantó con suavísima y clara voz estas dos estancias: -En tanto que en sí vuelve Altisidora, muerta por la crueldad de don Quijote, y en tanto que en la corte encantadora se vistieren las damas de picote, y en tanto que a sus dueñas mi señora vistiere de bayeta y de anascote, cantaré su belleza y su desgracia, con mejor plectro que el cantor de Tracia. Y aun no se me figura que me toca aqueste oficio solamente en vida; mas, con la lengua muerta y fría en la boca, pienso mover la voz a ti debida. Libre mi alma de su estrecha roca, por el estigio lago conducida, celebrándote irá, y aquel sonido hará parar las aguas del olvido. -No más -dijo a esta sazón uno de los dos que parecían reyes-: no más, cantor divino; que sería proceder en infinito representarnos ahora la muerte y las gracias de la sin par Altisidora, no muerta, como el mundo ignorante piensa, sino viva en las lenguas de la Fama, y en la pena que para volverla a la perdida luz ha de pasar Sancho Panza, que está presente; y así, ¡oh tú, Radamanto, que conmigo juzgas en las cavernas lóbregas de Lite!, pues sabes todo aquello que en los inescrutables hados está determinado acerca de volver en sí esta doncella, dilo y decláralo luego, porque no se nos dilate el bien que con su nueva vuelta esperamos. Apenas hubo dicho esto Minos, juez y compañero de Radamanto, cuando, levantándose en pie Radamanto, dijo: -¡Ea, ministros de esta casa, altos y bajos, grandes y chicos, acudid unos tras otros y sellad el rostro de Sancho con veinte y cuatro mamonas, y doce pellizcos y seis alfilerazos en brazos y lomos, que en esta ceremonia consiste la salud de Altisidora! Oyendo lo cual Sancho Panza, rompió el silencio, y dijo: -¡Voto a tal, así me deje yo sellar el rostro ni manosearme la cara como volverme moro! ¡Cuerpo de mí! ¿Qué tiene que ver manosearme el rostro con la resurreción desta doncella? Regostóse la vieja a los bledos. Encantan a Dulcinea, y azótanme para que se desencante; muérese Altisidora de males que Dios quiso darle, y hanla de resucitar hacerme a mí veinte y cuatro mamonas, y acribarme el cuerpo a alfilerazos y acardenalarme los brazos a pellizcos. ¡Esas burlas, a un cuñado, que yo soy perro viejo, y no hay conmigo tus, tus! -¡Morirás! -dijo en alta voz Radamanto-. Ablándate, tigre; humíllate, Nembrot soberbio, y sufre y calla, pues no te piden imposibles. Y no te metas en averiguar las dificultades deste negocio: mamonado has de ser, acrebillado te has de ver, pellizcado has de gemir. ¡Ea, digo, ministros, cumplid mi mandamiento; si no, por la fe de hombre de bien, que habéis de ver para lo que nacistes! Parecieron, en esto, que por el patio venían, hasta seis dueñas en procesión, una tras otra, las cuatro con antojos, y todas levantadas las manos derechas en alto, con cuatro dedos de muñecas de fuera, para hacer las manos más largas, como ahora se usa. No las hubo visto Sancho, cuando, bramando como un toro, dijo: -Bien podré yo dejarme manosear de todo el mundo, pero consentir que me toquen dueñas, ¡eso no! Gatéenme el rostro, como hicieron a mi amo en este mesmo castillo; traspásenme el cuerpo con puntas de dagas buidas; atenácenme los brazos con tenazas de fuego, que yo lo llevaré en paciencia, o serviré a estos señores; pero que me toquen dueñas no lo consentiré, si me llevase el diablo. Rompió también el silencio don Quijote, diciendo a Sancho: -Ten paciencia, hijo, y da gusto a estos señores, y muchas gracias al cielo por haber puesto tal virtud en tu persona, que con el martirio della desencantes los encantados y resucites los muertos. Ya estaban las dueñas cerca de Sancho, cuando él, más blando y más persuadido, poniéndose bien en la silla, dio rostro y barba a la primera, la cual la hizo una mamona muy bien sellada, y luego una gran reverencia. -¡Menos cortesía; menos mudas, señora dueña -dijo Sancho-; que por Dios que traéis las manos oliendo a vinagrillo! Finalmente, todas las dueñas le sellaron, y otra mucha gente de casa le pellizcaron; pero lo que él no pudo sufrir fue el punzamiento de los alfileres; y así, se levantó de la silla, al parecer mohíno, y, asiendo de una hacha encendida que junto a él estaba, dio tras las dueñas, y tras todos su verdugos, diciendo: -¡Afuera, ministros infernales, que no soy yo de bronce, para no sentir tan extraordinarios martirios! En esto, Altisidora, que debía de estar cansada por haber estado tanto tiempo supina, se volvió de un lado; visto lo cual por los circunstantes, casi todos a una voz dijeron: -¡Viva es Altisidora! ¡Altisidora vive! Mandó Radamanto a Sancho que depusiese la ira, pues ya se había alcanzado el intento que se procuraba. Así como don Quijote vio rebullir a Altisidora, se fue a poner de rodillas delante de Sancho, diciéndole: -Agora es tiempo, hijo de mis entrañas, no que escudero mío, que te des algunos de los azotes que estás obligado a dar por el desencanto de Dulcinea. Ahora, digo, que es el tiempo donde tienes sazonada la virtud, y con eficacia de obrar el bien que de ti se espera. A lo que respondió Sancho: -Esto me parece argado sobre argado, y no miel sobre hojuelas. Bueno sería que tras pellizcos, mamonas y alfilerazos viniesen ahora los azotes. No tienen más que hacer sino tomar una gran piedra, y atármela al cuello, y dar conmigo en un pozo, de lo que a mí no pesaría mucho, si es que para curar los males ajenos tengo yo de ser la vaca de la boda. Déjenme; si no, por Dios que lo arroje y lo eche todo a trece, aunque no se venda. Ya en esto, se había sentado en el túmulo Altisidora, y al mismo instante sonaron las chirimías, a quien acompañaron las flautas y las voces de todos, que aclamaban: -¡Viva Altisidora! ¡Altisidora viva! Levantáronse los duques y los reyes Minos y Radamanto, y todos juntos, con don Quijote y Sancho, fueron a recebir a Altisidora y a bajarla del túmulo; la cual, haciendo de la desmayada, se inclinó a los duques y a los reyes, y, mirando de través a don Quijote, le dijo: -Dios te lo perdone, desamorado caballero, pues por tu crueldad he estado en el otro mundo, a mi parecer, más de mil años; y a ti, ¡oh el más compasivo escudero que contiene el orbe!, te agradezco la vida que poseo. Dispón desde hoy más, amigo Sancho, de seis camisas mías que te mando para que hagas otras seis para ti; y, si no son todas sanas, a lo menos son todas limpias. Besóle por ello las manos Sancho, con la coroza en la mano y las rodillas en el suelo. Mandó el duque que se la quitasen, y le volviesen su caperuza, y le pusiesen el sayo, y le quitasen la ropa de las llamas. Suplicó Sancho al duque que le dejasen la ropa y mitra, que las quería llevar a su tierra, por señal y memoria de aquel nunca visto suceso. La duquesa respondió que sí dejarían, que ya sabía él cuán grande amiga suya era. Mandó el duque despejar el patio, y que todos se recogiesen a sus estancias, y que a don Quijote y a Sancho los llevasen a las que ellos ya se sabían. Capítulo LXX. Que sigue al de sesenta y nueve, y trata de cosas no escusadas para la claridad desta historia Durmió Sancho aquella noche en una carriola, en el mesmo aposento de don Quijote, cosa que él quisiera escusarla, si pudiera, porque bien sabía que su amo no le había de dejar dormir a preguntas y a respuestas, y no se hallaba en disposición de hablar mucho, porque los dolores de los martirios pasados los tenía presentes, y no le dejaban libre la lengua, y viniérale más a cuento dormir en una choza solo, que no en aquella rica estancia acompañado. Salióle su temor tan verdadero y su sospecha tan cierta, que, apenas hubo entrado su señor en el lecho, cuando dijo: -¿Qué te parece, Sancho, del suceso desta noche? Grande y poderosa es la fuerza del desdén desamorado, como por tus mismos ojos has visto muerta a Altisidora, no con otras saetas, ni con otra espada, ni con otro instrumento bélico, ni con venenos mortíferos, sino con la consideración del rigor y el desdén con que yo siempre la he tratado. -Muriérase ella en hora buena cuanto quisiera y como quisiera -respondió Sancho-, y dejárame a mí en mi casa, pues ni yo la enamoré ni la desdeñé en mi vida. Yo no sé ni puedo pensar cómo sea que la salud de Altisidora, doncella más antojadiza que discreta, tenga que ver, como otra vez he dicho, con los martirios de Sancho Panza. Agora sí que vengo a conocer clara y distintamente que hay encantadores y encantos en el mundo, de quien Dios me libre, pues yo no me sé librar; con todo esto, suplico a vuestra merced me deje dormir y no me pregunte más, si no quiere que me arroje por una ventana abajo. -Duerme, Sancho amigo -respondió don Quijote-, si es que te dan lugar los alfilerazos y pellizcos recebidos, y las mamonas hechas. -Ningún dolor -replicó Sancho- llegó a la afrenta de las mamonas, no por otra cosa que por habérmelas hecho dueña, que confundidas sean; y torno a suplicar a vuesa merced me deje dormir, porque el sueño es alivio de las miserias de los que las tienen despiertas. Sea así -dijo don Quijote-, y Dios te acompañe. Durmiéronse los dos, y en este tiempo quiso escribir y dar cuenta Cide Hamete, autor desta grande historia, qué les movió a los duques a levantar el edificio de la máquina referida. Y dice que, no habiéndosele olvidado al bachiller Sansón Carrasco cuando el Caballero de los Espejos fue vencido y derribado por don Quijote, cuyo vencimiento y caída borró y deshizo todos sus designios, quiso volver a probar la mano, esperando mejor suceso que el pasado; y así, informándose del paje que llevó la carta y presente a Teresa Panza, mujer de Sancho, adónde don Quijote quedaba, buscó nuevas armas y caballo, y puso en el escudo la blanca luna, llevándolo todo sobre un macho, a quien guiaba un labrador, y no Tomé Cecial, su antiguo escudero, porque no fuese conocido de Sancho ni de don Quijote. Llegó, pues, al castillo del duque, que le informó el camino y derrota que don Quijote llevaba, con intento de hallarse en las justas de Zaragoza. Díjole asimismo las burlas que le había hecho con la traza del desencanto de Dulcinea, que había de ser a costa de las posaderas de Sancho. En fin, dio cuenta de la burla que Sancho había hecho a su amo, dándole a entender que Dulcinea estaba encantada y transformada en labradora, y cómo la duquesa su mujer había dado a entender a Sancho que él era el que se engañaba, porque verdaderamente estaba encantada Dulcinea; de que no poco se rió y admiró el bachiller, considerando la agudeza y simplicidad de Sancho, como del estremo de la locura de don Quijote. Pidióle el duque que si le hallase, y le venciese o no, se volviese por allí a darle cuenta del suceso. Hízolo así el bachiller; partióse en su busca, no le halló en Zaragoza, pasó adelante y sucedióle lo que queda referido. Volvióse por el castillo del duque y contóselo todo, con las condiciones de la batalla, y que ya don Quijote volvía a cumplir, como buen caballero andante, la palabra de retirarse un año en su aldea, en el cual tiempo podía ser, dijo el bachiller, que sanase de su locura; que ésta era la intención que le había movido a hacer aquellas transformaciones, por ser cosa de lástima que un hidalgo tan bien entendido como don Quijote fuese loco. Con esto, se despidió del duque, y se volvió a su lugar, esperando en él a don Quijote, que tras él venía. De aquí tomó ocasión el duque de hacerle aquella burla: tanto era lo que gustaba de las cosas de Sancho y de don Quijote; y haciendo tomar los caminos cerca y lejos del castillo por todas las partes que imaginó que podría volver don Quijote, con muchos criados suyos de a pie y de a caballo, para que por fuerza o de grado le trujesen al castillo, si le hallasen. Halláronle, dieron aviso al duque, el cual, ya prevenido de todo lo que había de hacer, así como tuvo noticia de su llegada, mandó encender las hachas y las luminarias del patio y poner a Altisidora sobre el túmulo, con todos los aparatos que se han contado, tan al vivo, y tan bien hechos, que de la verdad a ellos había bien poca diferencia. Y dice más Cide Hamete: que tiene para sí ser tan locos los burladores como los burlados, y que no estaban los duques dos dedos de parecer tontos, pues tanto ahínco ponían en burlarse de dos tontos. Los cuales, el uno durmiendo a sueño suelto, y el otro velando a pensamientos desatados, les tomó el día y la gana de levantarse; que las ociosas plumas, ni vencido ni vencedor, jamás dieron gusto a don Quijote. Altisidora -en la opinión de don Quijote, vuelta de muerte a vida-, siguiendo el humor de sus señores, coronada con la misma guirnalda que en el túmulo tenía, y vestida una tunicela de tafetán blanco, sembrada de flores de oro, y sueltos los cabellos por las espaldas, arrimada a un báculo de negro y finísimo ébano, entró en el aposento de don Quijote, con cuya presencia turbado y confuso, se encogió y cubrió casi todo con las sábanas y colchas de la cama, muda la lengua, sin que acertase a hacerle cortesía ninguna. Sentóse Altisidora en una silla, junto a su cabecera, y, después de haber dado un gran suspiro, con voz tierna y debilitada le dijo: -Cuando las mujeres principales y las recatadas doncellas atropellan por la honra, y dan licencia a la lengua que rompa por todo inconveniente, dando noticia en público de los secretos que su corazón encierra, en estrecho término se hallan. Yo, señor don Quijote de la Mancha, soy una déstas, apretada, vencida y enamorada; pero, con todo esto, sufrida y honesta; tanto que, por serlo tanto, reventó mi alma por mi silencio y perdí la vida. Dos días ha que con la consideración del rigor con que me has tratado, ¡Oh más duro que mármol a mis quejas, empedernido caballero!, he estado muerta, o, a lo menos, juzgada por tal de los que me han visto; y si no fuera porque el Amor, condoliéndose de mí, depositó mi remedio en los martirios deste buen escudero, allá me quedara en el otro mundo. -Bien pudiera el Amor -dijo Sancho- depositarlos en los de mi asno, que yo se lo agradeciera. Pero dígame, señora, así el cielo la acomode con otro más blando amante que mi amo: ¿qué es lo que vio en el otro mundo? ¿Qué hay en el infierno? Porque quien muere desesperado, por fuerza ha de tener aquel paradero. -La verdad que os diga -respondió Altisidora-, yo no debí de morir del todo, pues no entré en el infierno; que, si allá entrara, una por una no pudiera salir dél, aunque quisiera. La verdad es que llegué a la puerta, adonde estaban jugando hasta una docena de diablos a la pelota, todos en calzas y en jubón, con valonas guarnecidas con puntas de randas flamencas, y con unas vueltas de lo mismo, que les servían de puños, con cuatro dedos de brazo de fuera, porque pareciesen las manos más largas, en las cuales tenían unas palas de fuego; y lo que más me admiró fue que les servían, en lugar de pelotas, libros, al parecer, llenos de viento y de borra, cosa maravillosa y nueva; pero esto no me admiró tanto como el ver que, siendo natural de los jugadores el alegrarse los gananciosos y entristecerse los que pierden, allí en aquel juego todos gruñían, todos regañaban y todos se maldecían. -Eso no es maravilla -respondió Sancho-, porque los diablos, jueguen o no jueguen, nunca pueden estar contentos, ganen o no ganen. -Así debe de ser -respondió Altisidora-; mas hay otra cosa que también me admira, quiero decir me admiró entonces, y fue que al primer voleo no quedaba pelota en pie, ni de provecho para servir otra vez; y así, menudeaban libros nuevos y viejos, que era una maravilla. A uno dellos, nuevo, flamante y bien encuadernado, le dieron un papirotazo que le sacaron las tripas y le esparcieron las hojas. Dijo un diablo a otro: ''Mirad qué libro es ése''. Y el diablo le respondió: ''Ésta es la Segunda parte de la historia de don Quijote de la Mancha, no compuesta por Cide Hamete, su primer autor, sino por un aragonés, que él dice ser natural de Tordesillas''. ''Quitádmele de ahí -respondió el otro diablo-, y metedle en los abismos del infierno: no le vean más mis ojos''. ''¿Tan malo es?'', respondió el otro. ''Tan malo -replicó el primero-, que si de propósito yo mismo me pusiera a hacerle peor, no acertara''. Prosiguieron su juego, peloteando otros libros, y yo, por haber oído nombrar a don Quijote, a quien tanto adamo y quiero, procuré que se me quedase en la memoria esta visión. -Visión debió de ser, sin duda -dijo don Quijote-, porque no hay otro yo en el mundo, y ya esa historia anda por acá de mano en mano, pero no para en ninguna, porque todos la dan del pie. Yo no me he alterado en oír que ando como cuerpo fantástico por las tinieblas del abismo, ni por la claridad de la tierra, porque no soy aquel de quien esa historia trata. Si ella fuere buena, fiel y verdadera, tendrá siglos de vida; pero si fuere mala, de su parto a la sepultura no será muy largo el camino. Iba Altisidora a proseguir en quejarse de don Quijote, cuando le dijo don Quijote: -Muchas veces os he dicho, señora, que a mí me pesa de que hayáis colocado en mí vuestros pensamientos, pues de los míos antes pueden ser agradecidos que remediados; yo nací para ser de Dulcinea del Toboso, y los hados, si los hubiera, me dedicaron para ella; y pensar que otra alguna hermosura ha de ocupar el lugar que en mi alma tiene es pensar lo imposible. Suficiente desengaño es éste para que os retiréis en los límites de vuestra honestidad, pues nadie se puede obligar a lo imposible. Oyendo lo cual Altisidora, mostrando enojarse y alterarse, le dijo: -¡Vive el Señor, don bacallao, alma de almirez, cuesco de dátil, más terco y duro que villano rogado cuando tiene la suya sobre el hito, que si arremeto a vos, que os tengo de sacar los ojos! ¿Pensáis por ventura, don vencido y don molido a palos, que yo me he muerto por vos? Todo lo que habéis visto esta noche ha sido fingido; que no soy yo mujer que por semejantes camellos había de dejar que me doliese un negro de la uña, cuanto más morirme. -Eso creo yo muy bien -dijo Sancho-, que esto del morirse los enamorados es cosa de risa: bien lo pueden ellos decir, pero hacer, créalo Judas. Estando en estas pláticas, entró el músico, cantor y poeta que había cantado las dos ya referidas estancias, el cual, haciendo una gran reverencia a don Quijote, dijo: -Vuestra merced, señor caballero, me cuente y tenga en el número de sus mayores servidores, porque ha muchos días que le soy muy aficionado, así por su fama como por sus hazañas. Don Quijote le respondió: -Vuestra merced me diga quién es, porque mi cortesía responda a sus merecimientos. El mozo respondió que era el músico y panegírico de la noche antes. -Por cierto -replicó don Quijote-, que vuestra merced tiene estremada voz, pero lo que cantó no me parece que fue muy a propósito; porque, ¿qué tienen que ver las estancias de Garcilaso con la muerte desta señora? -No se maraville vuestra merced deso -respondió el músico-, que ya entre los intonsos poetas de nuestra edad se usa que cada uno escriba como quisiere, y hurte de quien quisiere, venga o no venga a pelo de su intento, y ya no hay necedad que canten o escriban que no se atribuya a licencia poética. Responder quisiera don Quijote, pero estorbáronlo el duque y la duquesa, que entraron a verle, entre los cuales pasaron una larga y dulce plática, en la cual dijo Sancho tantos donaires y tantas malicias, que dejaron de nuevo admirados a los duques, así con su simplicidad como con su agudeza. Don Quijote les suplicó le diesen licencia para partirse aquel mismo día, pues a los vencidos caballeros, como él, más les convenía habitar una zahúrda que no reales palacios. Diéronsela de muy buena gana, y la duquesa le preguntó si quedaba en su gracia Altisidora. Él le respondió: -Señora mía, sepa Vuestra Señoría que todo el mal desta doncella nace de ociosidad, cuyo remedio es la ocupación honesta y continua. Ella me ha dicho aquí que se usan randas en el infierno; y, pues ella las debe de saber hacer, no las deje de la mano, que, ocupada en menear los palillos, no se menearán en su imaginación la imagen o imágines de lo que bien quiere; y ésta es la verdad, éste mi parecer y éste es mi consejo. -Y el mío -añadió Sancho-, pues no he visto en toda mi vida randera que por amor se haya muerto; que las doncellas ocupadas más ponen sus pensamientos en acabar sus tareas que en pensar en sus amores. Por mí lo digo, pues, mientras estoy cavando, no me acuerdo de mi oíslo; digo, de mi Teresa Panza, a quien quiero más que a las pestañas de mis ojos. -Vos decís muy bien, Sancho -dijo la duquesa-, y yo haré que mi Altisidora se ocupe de aquí adelante en hacer alguna labor blanca, que la sabe hacer por estremo. -No hay para qué, señora -respondió Altisidora-, usar dese remedio, pues la consideración de las crueldades que conmigo ha usado este malandrín mostrenco me le borrarán de la memoria sin otro artificio alguno. Y, con licencia de vuestra grandeza, me quiero quitar de aquí, por no ver delante de mis ojos ya no su triste figura, sino su fea y abominable catadura. -Eso me parece -dijo el duque- a lo que suele decirse: Porque aquel que dice injurias, cerca está de perdonar. Hizo Altisidora muestra de limpiarse las lágrimas con un pañuelo, y, haciendo reverencia a sus señores, se salió del aposento. -Mándote yo -dijo Sancho-, pobre doncella, mándote, digo, mala ventura, pues las has habido con una alma de esparto y con un corazón de encina. ¡A fee que si las hubieras conmigo, que otro gallo te cantara! Acabóse la plática, vistióse don Quijote, comió con los duques, y partióse aquella tarde. Capítulo LXXI. De lo que a don Quijote le sucedió con su escudero Sancho yendo a su aldea Iba el vencido y asendereado don Quijote pensativo además por una parte, y muy alegre por otra. Causaba su tristeza el vencimiento; y la alegría, el considerar en la virtud de Sancho, como lo había mostrado en la resurreción de Altisidora, aunque con algún escrúpulo se persuadía a que la enamorada doncella fuese muerta de veras. No iba nada Sancho alegre, porque le entristecía ver que Altisidora no le había cumplido la palabra de darle las camisas; y, yendo y viniendo en esto, dijo a su amo: -En verdad, señor, que soy el más desgraciado médico que se debe de hallar en el mundo, en el cual hay físicos que, con matar al enfermo que curan, quieren ser pagados de su trabajo, que no es otro sino firmar una cedulilla de algunas medicinas, que no las hace él, sino el boticario, y cátalo cantusado; y a mí, que la salud ajena me cuesta gotas de sangre, mamonas, pellizcos, alfilerazos y azotes, no me dan un ardite. Pues yo les voto a tal que si me traen a las manos otro algún enfermo, que, antes que le cure, me han de untar las mías; que el abad de donde canta yanta, y no quiero creer que me haya dado el cielo la virtud que tengo para que yo la comunique con otros de bóbilis, bóbilis. -Tú tienes razón, Sancho amigo -respondió don Quijote-, y halo hecho muy mal Altisidora en no haberte dado las prometidas camisas; y, puesto que tu virtud es gratis data, que no te ha costado estudio alguno, más que estudio es recebir martirios en tu persona. De mí te sé decir que si quisieras paga por los azotes del desencanto de Dulcinea, ya te la hubiera dado tal como buena; pero no sé si vendrá bien con la cura la paga, y no querría que impidiese el premio a la medicina. Con todo eso, me parece que no se perderá nada en probarlo: mira, Sancho, el que quieres, y azótate luego, y págate de contado y de tu propia mano, pues tienes dineros míos. A cuyos ofrecimientos abrió Sancho los ojos y las orejas de un palmo, y dio consentimiento en su corazón a azotarse de buena gana; y dijo a su amo: -Agora bien, señor, yo quiero disponerme a dar gusto a vuestra merced en lo que desea, con provecho mío; que el amor de mis hijos y de mi mujer me hace que me muestre interesado. Dígame vuestra merced: ¿cuánto me dará por cada azote que me diere? -Si yo te hubiera de pagar, Sancho -respondió don Quijote-, conforme lo que merece la grandeza y calidad deste remedio, el tesoro de Venecia, las minas del Potosí fueran poco para pagarte; toma tú el tiento a lo que llevas mío, y pon el precio a cada azote. -Ellos -respondió Sancho- son tres mil y trecientos y tantos; de ellos me he dado hasta cinco: quedan los demás; entren entre los tantos estos cinco, y vengamos a los tres mil y trecientos, que a cuartillo cada uno, que no llevaré menos si todo el mundo me lo mandase, montan tres mil y trecientos cuartillos, que son los tres mil, mil y quinientos medios reales, que hacen setecientos y cincuenta reales; y los trecientos hacen ciento y cincuenta medios reales, que vienen a hacer setenta y cinco reales, que, juntándose a los setecientos y cincuenta, son por todos ochocientos y veinte y cinco reales. Éstos desfalcaré yo de los que tengo de vuestra merced, y entraré en mi casa rico y contento, aunque bien azotado; porque no se toman truchas..., y no digo más. -¡Oh Sancho bendito! ¡Oh Sancho amable -respondió don Quijote-, y cuán obligados hemos de quedar Dulcinea y yo a servirte todos los días que el cielo nos diere de vida! Si ella vuelve al ser perdido, que no es posible sino que vuelva, su desdicha habrá sido dicha, y mi vencimiento, felicísimo triunfo. Y mira, Sancho, cuándo quieres comenzar la diciplina, que porque la abrevies te añado cien reales. -¿Cuándo? -replicó Sancho-. Esta noche, sin falta. Procure vuestra merced que la tengamos en el campo, al cielo abierto, que yo me abriré mis carnes. Llegó la noche, esperada de don Quijote con la mayor ansia del mundo, pareciéndole que las ruedas del carro de Apolo se habían quebrado, y que el día se alargaba más de lo acostumbrado, bien así como acontece a los enamorados, que jamás ajustan la cuenta de sus deseos. Finalmente, se entraron entre unos amenos árboles que poco desviados del camino estaban, donde, dejando vacías la silla y albarda de Rocinante y el rucio, se tendieron sobre la verde yerba y cenaron del repuesto de Sancho; el cual, haciendo del cabestro y de la jáquima del rucio un poderoso y flexible azote, se retiró hasta veinte pasos de su amo, entre unas hayas. Don Quijote, que le vio ir con denuedo y con brío, le dijo: -Mira, amigo, que no te hagas pedazos; da lugar que unos azotes aguarden a otros; no quieras apresurarte tanto en la carrera, que en la mitad della te falte el aliento; quiero decir que no te des tan recio que te falte la vida antes de llegar al número deseado. Y, porque no pierdas por carta de más ni de menos, yo estaré desde aparte contando por este mi rosario los azotes que te dieres. Favorézcate el cielo conforme tu buena intención merece. -Al buen pagador no le duelen prendas -respondió Sancho-: yo pienso darme de manera que, sin matarme, me duela; que en esto debe de consistir la sustancia deste milagro. Desnudóse luego de medio cuerpo arriba, y, arrebatando el cordel, comenzó a darse, y comenzó don Quijote a contar los azotes. Hasta seis o ocho se habría dado Sancho, cuando le pareció ser pesada la burla y muy barato el precio della, y, deteniéndose un poco, dijo a su amo que se llamaba a engaño, porque merecía cada azote de aquéllos ser pagado a medio real, no que a cuartillo. -Prosigue, Sancho amigo, y no desmayes -le dijo don Quijote-, que yo doblo la parada del precio. -Dese modo -dijo Sancho-, ¡a la mano de Dios, y lluevan azotes! Pero el socarrón dejó de dárselos en las espaldas, y daba en los árboles, con unos suspiros de cuando en cuando, que parecía que con cada uno dellos se le arrancaba el alma. Tierna la de don Quijote, temeroso de que no se le acabase la vida, y no consiguiese su deseo por la imprudencia de Sancho, le dijo: -Por tu vida, amigo, que se quede en este punto este negocio, que me parece muy áspera esta medicina, y será bien dar tiempo al tiempo; que no se ganó Zamora en un hora. Más de mil azotes, si yo no he contado mal, te has dado: bastan por agora; que el asno, hablando a lo grosero, sufre la carga, mas no la sobrecarga. -No, no, señor -respondió Sancho-, no se ha de decir por mí: "a dineros pagados, brazos quebrados". Apártese vuestra merced otro poco y déjeme dar otros mil azotes siquiera, que a dos levadas déstas habremos cumplido con esta partida, y aún nos sobrará ropa. -Pues tú te hallas con tan buena disposición -dijo don Quijote-, el cielo te ayude, y pégate, que yo me aparto. Volvió Sancho a su tarea con tanto denuedo, que ya había quitado las cortezas a muchos árboles: tal era la riguridad con que se azotaba; y, alzando una vez la voz, y dando un desaforado azote en una haya, dijo: -¡Aquí morirás, Sansón, y cuantos con él son! Acudió don Quijote luego al son de la lastimada voz y del golpe del riguroso azote, y, asiendo del torcido cabestro que le servía de corbacho a Sancho, le dijo: -No permita la suerte, Sancho amigo, que por el gusto mío pierdas tú la vida, que ha de servir para sustentar a tu mujer y a tus hijos: espere Dulcinea mejor coyuntura, que yo me contendré en los límites de la esperanza propincua, y esperaré que cobres fuerzas nuevas, para que se concluya este negocio a gusto de todos. -Pues vuestra merced, señor mío, lo quiere así -respondió Sancho-, sea en buena hora, y écheme su ferreruelo sobre estas espaldas, que estoy sudando y no querría resfriarme; que los nuevos diciplinantes corren este peligro. Hízolo así don Quijote, y, quedándose en pelota, abrigó a Sancho, el cual se durmió hasta que le despertó el sol, y luego volvieron a proseguir su camino, a quien dieron fin, por entonces, en un lugar que tres leguas de allí estaba. Apeáronse en un mesón, que por tal le reconoció don Quijote, y no por castillo de cava honda, torres, rastrillos y puente levadiza; que, después que le vencieron, con más juicio en todas las cosas discurría, como agora se dirá. Alojáronle en una sala baja, a quien servían de guadameciles unas sargas viejas pintadas, como se usan en las aldeas. En una dellas estaba pintada de malísima mano el robo de Elena, cuando el atrevido huésped se la llevó a Menalao, y en otra estaba la historia de Dido y de Eneas, ella sobre una alta torre, como que hacía señas con una media sábana al fugitivo huésped, que por el mar, sobre una fragata o bergantín, se iba huyendo. Notó en las dos historias que Elena no iba de muy mala gana, porque se reía a socapa y a lo socarrón; pero la hermosa Dido mostraba verter lágrimas del tamaño de nueces por los ojos. Viendo lo cual don Quijote, dijo: -Estas dos señoras fueron desdichadísimas, por no haber nacido en esta edad, y yo sobre todos desdichado en no haber nacido en la suya: encontrara a aquestos señores, ni fuera abrasada Troya, ni Cartago destruida, pues con sólo que yo matara a Paris se escusaran tantas desgracias. -Yo apostaré -dijo Sancho- que antes de mucho tiempo no ha de haber bodegón, venta ni mesón, o tienda de barbero, donde no ande pintada la historia de nuestras hazañas. Pero querría yo que la pintasen manos de otro mejor pintor que el que ha pintado a éstas. -Tienes razón, Sancho -dijo don Quijote-, porque este pintor es como Orbaneja, un pintor que estaba en Úbeda; que, cuando le preguntaban qué pintaba, respondía: ''Lo que saliere''; y si por ventura pintaba un gallo, escribía debajo: "Éste es gallo", porque no pensasen que era zorra. Desta manera me parece a mí, Sancho, que debe de ser el pintor o escritor, que todo es uno, que sacó a luz la historia deste nuevo don Quijote que ha salido: que pintó o escribió lo que saliere; o habrá sido como un poeta que andaba los años pasados en la corte, llamado Mauleón, el cual respondía de repente a cuanto le preguntaban; y, preguntándole uno que qué quería decir Deum de Deo, respondió: ''Dé donde diere''. Pero, dejando esto aparte, dime si piensas, Sancho, darte otra tanda esta noche, y si quieres que sea debajo de techado, o al cielo abierto. -Pardiez, señor -respondió Sancho-, que para lo que yo pienso darme, eso se me da en casa que en el campo; pero, con todo eso, querría que fuese entre árboles, que parece que me acompañan y me ayudan a llevar mi trabajo maravillosamente. -Pues no ha de ser así, Sancho amigo -respondió don Quijote-, sino que para que tomes fuerzas, lo hemos de guardar para nuestra aldea, que, a lo más tarde, llegaremos allá después de mañana. Sancho respondió que hiciese su gusto, pero que él quisiera concluir con brevedad aquel negocio a sangre caliente y cuando estaba picado el molino, porque en la tardanza suele estar muchas veces el peligro; y a Dios rogando y con el mazo dando, y que más valía un "toma" que dos "te daré", y el pájaro en la mano que el buitre volando. -No más refranes, Sancho, por un solo Dios -dijo don Quijote-, que parece que te vuelves al sicut erat; habla a lo llano, a lo liso, a lo no intricado, como muchas veces te he dicho, y verás como te vale un pan por ciento. -No sé qué mala ventura es esta mía -respondió Sancho-, que no sé decir razón sin refrán, ni refrán que no me parezca razón; pero yo me enmendaré, si pudiere. Y, con esto, cesó por entonces su plática. Capítulo LXXII. De cómo don Quijote y Sancho llegaron a su aldea Todo aquel día, esperando la noche, estuvieron en aquel lugar y mesón don Quijote y Sancho: el uno, para acabar en la campaña rasa la tanda de su diciplina, y el otro, para ver el fin della, en el cual consistía el de su deseo. Llegó en esto al mesón un caminante a caballo, con tres o cuatro criados, uno de los cuales dijo al que el señor dellos parecía: -Aquí puede vuestra merced, señor don Ãlvaro Tarfe, pasar hoy la siesta: la posada parece limpia y fresca. Oyendo esto don Quijote, le dijo a Sancho: -Mira, Sancho: cuando yo hojeé aquel libro de la segunda parte de mi historia, me parece que de pasada topé allí este nombre de don Ãlvaro Tarfe. -Bien podrá ser -respondió Sancho-. Dejémosle apear, que después se lo preguntaremos. El caballero se apeó, y, frontero del aposento de don Quijote, la huéspeda le dio una sala baja, enjaezada con otras pintadas sargas, como las que tenía la estancia de don Quijote. Púsose el recién venido caballero a lo de verano, y, saliéndose al portal del mesón, que era espacioso y fresco, por el cual se paseaba don Quijote, le preguntó: -¿Adónde bueno camina vuestra merced, señor gentilhombre? Y don Quijote le respondió: -A una aldea que está aquí cerca, de donde soy natural. Y vuestra merced, ¿dónde camina? -Yo, señor -respondió el caballero-, voy a Granada, que es mi patria. -¡Y buena patria! -replicó don Quijote-. Pero, dígame vuestra merced, por cortesía, su nombre, porque me parece que me ha de importar saberlo más de lo que buenamente podré decir. -Mi nombre es don Ãlvaro Tarfe -respondió el huésped. A lo que replicó don Quijote: -Sin duda alguna pienso que vuestra merced debe de ser aquel don Ãlvaro Tarfe que anda impreso en la Segunda parte de la historia de don Quijote de la Mancha, recién impresa y dada a la luz del mundo por un autor moderno. -El mismo soy -respondió el caballero-, y el tal don Quijote, sujeto principal de la tal historia, fue grandísimo amigo mío, y yo fui el que le sacó de su tierra, o, a lo menos, le moví a que viniese a unas justas que se hacían en Zaragoza, adonde yo iba; y, en verdad en verdad que le hice muchas amistades, y que le quité de que no le palmease las espaldas el verdugo, por ser demasiadamente atrevido. -Y, dígame vuestra merced, señor don Ãlvaro, ¿parezco yo en algo a ese tal don Quijote que vuestra merced dice? -No, por cierto -respondió el huésped-: en ninguna manera. -Y ese don Quijote -dijo el nuestro-, ¿traía consigo a un escudero llamado Sancho Panza? -Sí traía -respondió don Ãlvaro-; y, aunque tenía fama de muy gracioso, nunca le oí decir gracia que la tuviese. -Eso creo yo muy bien -dijo a esta sazón Sancho-, porque el decir gracias no es para todos, y ese Sancho que vuestra merced dice, señor gentilhombre, debe de ser algún grandísimo bellaco, frión y ladrón juntamente, que el verdadero Sancho Panza soy yo, que tengo más gracias que llovidas; y si no, haga vuestra merced la experiencia, y ándese tras de mí, por los menos un año, y verá que se me caen a cada paso, y tales y tantas que, sin saber yo las más veces lo que me digo, hago reír a cuantos me escuchan; y el verdadero don Quijote de la Mancha, el famoso, el valiente y el discreto, el enamorado, el desfacedor de agravios, el tutor de pupilos y huérfanos, el amparo de las viudas, el matador de las doncellas, el que tiene por única señora a la sin par Dulcinea del Toboso, es este señor que está presente, que es mi amo; todo cualquier otro don Quijote y cualquier otro Sancho Panza es burlería y cosa de sueño. -¡Por Dios que lo creo! -respondió don Ãlvaro-, porque más gracias habéis dicho vos, amigo, en cuatro razones que habéis hablado, que el otro Sancho Panza en cuantas yo le oí hablar, que fueron muchas. Más tenía de comilón que de bien hablado, y más de tonto que de gracioso, y tengo por sin duda que los encantadores que persiguen a don Quijote el bueno han querido perseguirme a mí con don Quijote el malo. Pero no sé qué me diga; que osaré yo jurar que le dejo metido en la casa del Nuncio, en Toledo, para que le curen, y agora remanece aquí otro don Quijote, aunque bien diferente del mío. -Yo -dijo don Quijote- no sé si soy bueno, pero sé decir que no soy el malo; para prueba de lo cual quiero que sepa vuesa merced, mi señor don Ãlvaro Tarfe, que en todos los días de mi vida no he estado en Zaragoza; antes, por haberme dicho que ese don Quijote fantástico se había hallado en las justas desa ciudad, no quise yo entrar en ella, por sacar a las barbas del mundo su mentira; y así, me pasé de claro a Barcelona, archivo de la cortesía, albergue de los estranjeros, hospital de los pobres, patria de los valientes, venganza de los ofendidos y correspondencia grata de firmes amistades, y, en sitio y en belleza, única. Y, aunque los sucesos que en ella me han sucedido no son de mucho gusto, sino de mucha pesadumbre, los llevo sin ella, sólo por haberla visto. Finalmente, señor don Ãlvaro Tarfe, yo soy don Quijote de la Mancha, el mismo que dice la fama, y no ese desventurado que ha querido usurpar mi nombre y honrarse con mis pensamientos. A vuestra merced suplico, por lo que debe a ser caballero, sea servido de hacer una declaración ante el alcalde deste lugar, de que vuestra merced no me ha visto en todos los días de su vida hasta agora, y de que yo no soy el don Quijote impreso en la segunda parte, ni este Sancho Panza mi escudero es aquél que vuestra merced conoció. -Eso haré yo de muy buena gana -respondió don Ãlvaro-, puesto que cause admiración ver dos don Quijotes y dos Sanchos a un mismo tiempo, tan conformes en los nombres como diferentes en las acciones; y vuelvo a decir y me afirmo que no he visto lo que he visto, ni ha pasado por mí lo que ha pasado. -Sin duda -dijo Sancho- que vuestra merced debe de estar encantado, como mi señora Dulcinea del Toboso, y pluguiera al cielo que estuviera su desencanto de vuestra merced en darme otros tres mil y tantos azotes como me doy por ella, que yo me los diera sin interés alguno. -No entiendo eso de azotes -dijo don Ãlvaro. Y Sancho le respondió que era largo de contar, pero que él se lo contaría si acaso iban un mesmo camino. Llegóse en esto la hora de comer; comieron juntos don Quijote y don Ãlvaro. Entró acaso el alcalde del pueblo en el mesón, con un escribano, ante el cual alcalde pidió don Quijote, por una petición, de que a su derecho convenía de que don Ãlvaro Tarfe, aquel caballero que allí estaba presente, declarase ante su merced como no conocía a don Quijote de la Mancha, que asimismo estaba allí presente, y que no era aquél que andaba impreso en una historia intitulada: Segunda parte de don Quijote de la Mancha, compuesta por un tal de Avellaneda, natural de Tordesillas. Finalmente, el alcalde proveyó jurídicamente; la declaración se hizo con todas las fuerzas que en tales casos debían hacerse, con lo que quedaron don Quijote y Sancho muy alegres, como si les importara mucho semejante declaración y no mostrara claro la diferencia de los dos don Quijotes y la de los dos Sanchos sus obras y sus palabras. Muchas de cortesías y ofrecimientos pasaron entre don Ãlvaro y don Quijote, en las cuales mostró el gran manchego su discreción, de modo que desengañó a don Ãlvaro Tarfe del error en que estaba; el cual se dio a entender que debía de estar encantado, pues tocaba con la mano dos tan contrarios don Quijotes. Llegó la tarde, partiéronse de aquel lugar, y a obra de media legua se apartaban dos caminos diferentes, el uno que guiaba a la aldea de don Quijote, y el otro el que había de llevar don Ãlvaro. En este poco espacio le contó don Quijote la desgracia de su vencimiento y el encanto y el remedio de Dulcinea, que todo puso en nueva admiración a don Ãlvaro, el cual, abrazando a don Quijote y a Sancho, siguió su camino, y don Quijote el suyo, que aquella noche la pasó entre otros árboles, por dar lugar a Sancho de cumplir su penitencia, que la cumplió del mismo modo que la pasada noche, a costa de las cortezas de las hayas, harto más que de sus espaldas, que las guardó tanto, que no pudieran quitar los azotes una mosca, aunque la tuviera encima. No perdió el engañado don Quijote un solo golpe de la cuenta, y halló que con los de la noche pasada era tres mil y veinte y nueve. Parece que había madrugado el sol a ver el sacrificio, con cuya luz volvieron a proseguir su camino, tratando entre los dos del engaño de don Ãlvaro y de cuán bien acordado había sido tomar su declaración ante la justicia, y tan auténticamente. Aquel día y aquella noche caminaron sin sucederles cosa digna de contarse, si no fue que en ella acabó Sancho su tarea, de que quedó don Quijote contento sobremodo, y esperaba el día, por ver si en el camino topaba ya desencantada a Dulcinea su señora; y, siguiendo su camino, no topaba mujer ninguna que no iba a reconocer si era Dulcinea del Toboso, teniendo por infalible no poder mentir las promesas de Merlín. Con estos pensamientos y deseos subieron una cuesta arriba, desde la cual descubrieron su aldea, la cual, vista de Sancho, se hincó de rodillas y dijo: -Abre los ojos, deseada patria, y mira que vuelve a ti Sancho Panza, tu hijo, si no muy rico, muy bien azotado. Abre los brazos y recibe también tu hijo don Quijote, que si viene vencido de los brazos ajenos, viene vencedor de sí mismo; que, según él me ha dicho, es el mayor vencimiento que desearse puede. Dineros llevo, porque si buenos azotes me daban, bien caballero me iba. -Déjate desas sandeces -dijo don Quijote-, y vamos con pie derecho a entrar en nuestro lugar, donde daremos vado a nuestras imaginaciones, y la traza que en la pastoral vida pensamos ejercitar. Con esto, bajaron de la cuesta y se fueron a su pueblo. Capítulo LXXIII. De los agüeros que tuvo don Quijote al entrar de su aldea, con otros sucesos que adornan y acreditan esta grande historia A la entrada del cual, según dice Cide Hamete, vio don Quijote que en las eras del lugar estaban riñendo dos mochachos, y el uno dijo al otro: -No te canses Periquillo, que no la has de ver en todos los días de tu vida. Oyólo don Quijote, y dijo a Sancho: -¿No adviertes, amigo, lo que aquel mochacho ha dicho: ''no la has de ver en todos los días de tu vida''? -Pues bien, ¿qué importa -respondió Sancho- que haya dicho eso el mochacho? -¿Qué? -replicó don Quijote-. ¿No vees tú que, aplicando aquella palabra a mi intención, quiere significar que no tengo de ver más a Dulcinea? Queríale responder Sancho, cuando se lo estorbó ver que por aquella campaña venía huyendo una liebre, seguida de muchos galgos y cazadores, la cual, temerosa, se vino a recoger y a agazapar debajo de los pies del rucio. Cogióla Sancho a mano salva y presentósela a don Quijote, el cual estaba diciendo: -Malum signum! Malum signum! Liebre huye, galgos la siguen: ¡Dulcinea no parece! -Estraño es vuesa merced -dijo Sancho-. Presupongamos que esta liebre es Dulcinea del Toboso y estos galgos que la persiguen son los malandrines encantadores que la transformaron en labradora: ella huye, yo la cojo y la pongo en poder de vuesa merced, que la tiene en sus brazos y la regala: ¿qué mala señal es ésta, ni qué mal agüero se puede tomar de aquí? Los dos mochachos de la pendencia se llegaron a ver la liebre, y al uno dellos preguntó Sancho que por qué reñían. Y fuele respondido por el que había dicho ''no la verás más en toda tu vida'', que él había tomado al otro mochacho una jaula de grillos, la cual no pensaba volvérsela en toda su vida. Sacó Sancho cuatro cuartos de la faltriquera y dióselos al mochacho por la jaula, y púsosela en las manos a don Quijote, diciendo: -He aquí, señor, rompidos y desbaratados estos agüeros, que no tienen que ver más con nuestros sucesos, según que yo imagino, aunque tonto, que con las nubes de antaño. Y si no me acuerdo mal, he oído decir al cura de nuestro pueblo que no es de personas cristianas ni discretas mirar en estas niñerías; y aun vuesa merced mismo me lo dijo los días pasados, dándome a entender que eran tontos todos aquellos cristianos que miraban en agüeros. Y no es menester hacer hincapié en esto, sino pasemos adelante y entremos en nuestra aldea. Llegaron los cazadores, pidieron su liebre, y diósela don Quijote; pasaron adelante, y, a la entrada del pueblo, toparon en un pradecillo rezando al cura y al bachiller Carrasco. Y es de saber que Sancho Panza había echado sobre el rucio y sobre el lío de las armas, para que sirviese de repostero, la túnica de bocací, pintada de llamas de fuego que le vistieron en el castillo del duque la noche que volvió en sí Altisidora. Acomodóle también la coroza en la cabeza, que fue la más nueva transformación y adorno con que se vio jamás jumento en el mundo. Fueron luego conocidos los dos del cura y del bachiller, que se vinieron a ellos con los brazos abiertos. Apeóse don Quijote y abrazólos estrechamente; y los mochachos, que son linces no escusados, divisaron la coroza del jumento y acudieron a verle, y decían unos a otros: -Venid, mochachos, y veréis el asno de Sancho Panza más galán que Mingo, y la bestia de don Quijote más flaca hoy que el primer día. Finalmente, rodeados de mochachos y acompañados del cura y del bachiller, entraron en el pueblo, y se fueron a casa de don Quijote, y hallaron a la puerta della al ama y a su sobrina, a quien ya habían llegado las nuevas de su venida. Ni más ni menos se las habían dado a Teresa Panza, mujer de Sancho, la cual, desgreñada y medio desnuda, trayendo de la mano a Sanchica, su hija, acudió a ver a su marido; y, viéndole no tan bien adeliñado como ella se pensaba que había de estar un gobernador, le dijo: -¿Cómo venís así, marido mío, que me parece que venís a pie y despeado, y más traéis semejanza de desgobernado que de gobernador? -Calla, Teresa -respondió Sancho-, que muchas veces donde hay estacas no hay tocinos, y vámonos a nuestra casa, que allá oirás maravillas. Dineros traigo, que es lo que importa, ganados por mi industria y sin daño de nadie. -Traed vos dinero, mi buen marido -dijo Teresa-, y sean ganados por aquí o por allí, que, comoquiera que los hayáis ganado, no habréis hecho usanza nueva en el mundo. Abrazó Sanchica a su padre, y preguntóle si traía algo, que le estaba esperando como el agua de mayo; y, asiéndole de un lado del cinto, y su mujer de la mano, tirando su hija al rucio, se fueron a su casa, dejando a don Quijote en la suya, en poder de su sobrina y de su ama, y en compañía del cura y del bachiller. Don Quijote, sin guardar términos ni horas, en aquel mismo punto se apartó a solas con el bachiller y el cura, y en breves razones les contó su vencimiento, y la obligación en que había quedado de no salir de su aldea en un año, la cual pensaba guardar al pie de la letra, sin traspasarla en un átomo, bien así como caballero andante, obligado por la puntualidad y orden de la andante caballería, y que tenía pensado de hacerse aquel año pastor, y entretenerse en la soledad de los campos, donde a rienda suelta podía dar vado a sus amorosos pensamientos, ejercitándose en el pastoral y virtuoso ejercicio; y que les suplicaba, si no tenían mucho que hacer y no estaban impedidos en negocios más importantes, quisiesen ser sus compañeros; que él compraría ovejas y ganado suficiente que les diese nombre de pastores; y que les hacía saber que lo más principal de aquel negocio estaba hecho, porque les tenía puestos los nombres, que les vendrían como de molde. Díjole el cura que los dijese. Respondió don Quijote que él se había de llamar el pastor Quijotiz; y el bachiller, el pastor Carrascón; y el cura, el pastor Curambro; y Sancho Panza, el pastor Pancino. Pasmáronse todos de ver la nueva locura de don Quijote; pero, porque no se les fuese otra vez del pueblo a sus caballerías, esperando que en aquel año podría ser curado, concedieron con su nueva intención, y aprobaron por discreta su locura, ofreciéndosele por compañeros en su ejercicio. -Y más -dijo Sansón Carrasco-, que, como ya todo el mundo sabe, yo soy celebérrimo poeta y a cada paso compondré versos pastoriles, o cortesanos, o como más me viniere a cuento, para que nos entretengamos por esos andurriales donde habemos de andar; y lo que más es menester, señores míos, es que cada uno escoja el nombre de la pastora que piensa celebrar en sus versos, y que no dejemos árbol, por duro que sea, donde no la retule y grabe su nombre, como es uso y costumbre de los enamorados pastores. -Eso está de molde -respondió don Quijote-, puesto que yo estoy libre de buscar nombre de pastora fingida, pues está ahí la sin par Dulcinea del Toboso, gloria de estas riberas, adorno de estos prados, sustento de la hermosura, nata de los donaires, y, finalmente, sujeto sobre quien puede asentar bien toda alabanza, por hipérbole que sea. -Así es verdad -dijo el cura-, pero nosotros buscaremos por ahí pastoras mañeruelas, que si no nos cuadraren, nos esquinen. A lo que añadió Sansón Carrasco: -Y cuando faltaren, darémosles los nombres de las estampadas e impresas, de quien está lleno el mundo: Fílidas, Amarilis, Dianas, Fléridas, Galateas y Belisardas; que, pues las venden en las plazas, bien las podemos comprar nosotros y tenerlas por nuestras. Si mi dama, o, por mejor decir, mi pastora, por ventura se llamare Ana, la celebraré debajo del nombre de Anarda; y si Francisca, la llamaré yo Francenia; y si Lucía, Lucinda, que todo se sale allá; y Sancho Panza, si es que ha de entrar en esta cofadría, podrá celebrar a su mujer Teresa Panza con nombre de Teresaina. Rióse don Quijote de la aplicación del nombre, y el cura le alabó infinito su honesta y honrada resolución, y se ofreció de nuevo a hacerle compañía todo el tiempo que le vacase de atender a sus forzosas obligaciones. Con esto, se despidieron dél, y le rogaron y aconsejaron tuviese cuenta con su salud, con regalarse lo que fuese bueno. Quiso la suerte que su sobrina y el ama oyeron la plática de los tres; y, así como se fueron, se entraron entrambas con don Quijote, y la sobrina le dijo: -¿Qué es esto, señor tío? ¿Ahora que pensábamos nosotras que vuestra merced volvía a reducirse en su casa, y pasar en ella una vida quieta y honrada, se quiere meter en nuevos laberintos, haciéndose Pastorcillo, tú que vienes, pastorcico, tú que vas? Pues en verdad que está ya duro el alcacel para zampoñas. A lo que añadió el ama: Y ¿podrá vuestra merced pasar en el campo las siestas del verano, los serenos del invierno, el aullido de los lobos? No, por cierto, que éste es ejercicio y oficio de hombres robustos, curtidos y criados para tal ministerio casi desde las fajas y mantillas. Aun, mal por mal, mejor es ser caballero andante que pastor. Mire, señor, tome mi consejo, que no se le doy sobre estar harta de pan y vino, sino en ayunas, y sobre cincuenta años que tengo de edad: estése en su casa, atienda a su hacienda, confiese a menudo, favorezca a los pobres, y sobre mi ánima si mal le fuere. -Callad, hijas -les respondió don Quijote-, que yo sé bien lo que me cumple. Llevadme al lecho, que me parece que no estoy muy bueno, y tened por cierto que, ahora sea caballero andante o pastor por andar, no dejaré siempre de acudir a lo que hubiéredes menester, como lo veréis por la obra. Y las buenas hijas -que lo eran sin duda ama y sobrina- le llevaron a la cama, donde le dieron de comer y regalaron lo posible. Capítulo LXXIV. De cómo don Quijote cayó malo, y del testamento que hizo, y su muerte Como las cosas humanas no sean eternas, yendo siempre en declinación de sus principios hasta llegar a su último fin, especialmente las vidas de los hombres, y como la de don Quijote no tuviese privilegio del cielo para detener el curso de la suya, llegó su fin y acabamiento cuando él menos lo pensaba; porque, o ya fuese de la melancolía que le causaba el verse vencido, o ya por la disposición del cielo, que así lo ordenaba, se le arraigó una calentura que le tuvo seis días en la cama, en los cuales fue visitado muchas veces del cura, del bachiller y del barbero, sus amigos, sin quitársele de la cabecera Sancho Panza, su buen escudero. Éstos, creyendo que la pesadumbre de verse vencido y de no ver cumplido su deseo en la libertad y desencanto de Dulcinea le tenía de aquella suerte, por todas las vías posibles procuraban alegrarle, diciéndole el bachiller que se animase y levantase, para comenzar su pastoral ejercicio, para el cual tenía ya compuesta una écloga, que mal año para cuantas Sanazaro había compuesto, y que ya tenía comprados de su propio dinero dos famosos perros para guardar el ganado: el uno llamado Barcino, y el otro Butrón, que se los había vendido un ganadero del Quintanar. Pero no por esto dejaba don Quijote sus tristezas. Llamaron sus amigos al médico, tomóle el pulso, y no le contentó mucho, y dijo que, por sí o por no, atendiese a la salud de su alma, porque la del cuerpo corría peligro. Oyólo don Quijote con ánimo sosegado, pero no lo oyeron así su ama, su sobrina y su escudero, los cuales comenzaron a llorar tiernamente, como si ya le tuvieran muerto delante. Fue el parecer del médico que melancolías y desabrimientos le acababan. Rogó don Quijote que le dejasen solo, porque quería dormir un poco. Hiciéronlo así y durmió de un tirón, como dicen, más de seis horas; tanto, que pensaron el ama y la sobrina que se había de quedar en el sueño. Despertó al cabo del tiempo dicho, y, dando una gran voz, dijo: -¡Bendito sea el poderoso Dios, que tanto bien me ha hecho! En fin, sus misericordias no tienen límite, ni las abrevian ni impiden los pecados de los hombres. Estuvo atenta la sobrina a las razones del tío, y pareciéronle más concertadas que él solía decirlas, a lo menos, en aquella enfermedad, y preguntóle: -¿Qué es lo que vuestra merced dice, señor? ¿Tenemos algo de nuevo? ¿Qué misericordias son éstas, o qué pecados de los hombres? -Las misericordias -respondió don Quijote-, sobrina, son las que en este instante ha usado Dios conmigo, a quien, como dije, no las impiden mis pecados. Yo tengo juicio ya, libre y claro, sin las sombras caliginosas de la ignorancia, que sobre él me pusieron mi amarga y continua leyenda de los detestables libros de las caballerías. Ya conozco sus disparates y sus embelecos, y no me pesa sino que este desengaño ha llegado tan tarde, que no me deja tiempo para hacer alguna recompensa, leyendo otros que sean luz del alma. Yo me siento, sobrina, a punto de muerte; querría hacerla de tal modo, que diese a entender que no había sido mi vida tan mala que dejase renombre de loco, que, puesto que lo he sido, no querría confirmar esta verdad en mi muerte. Llámame, amiga, a mis buenos amigos: el cura, al bachiller Sansón Carrasco y a maese Nicolás, el barbero, que quiero confesarme y hacer mi testamento. Pero de este trabajo se escusó la sobrina con la entrada de los tres. Apenas los vio don Quijote, cuando dijo: -Dadme albricias, buenos señores, de que ya yo no soy don Quijote de la Mancha, sino Alonso Quijano, a quien mis costumbres me dieron renombre de Bueno. Ya soy enemigo de Amadís de Gaula y de toda la infinita caterva de su linaje, ya me son odiosas todas las historias profanas del andante caballería, ya conozco mi necedad y el peligro en que me pusieron haberlas leído, ya, por misericordia de Dios, escarmentando en cabeza propia, las abomino. Cuando esto le oyeron decir los tres, creyeron, sin duda, que alguna nueva locura le había tomado. Y Sansón le dijo: -¿Ahora, señor don Quijote, que tenemos nueva que está desencantada la señora Dulcinea, sale vuestra merced con eso? Y ¿agora que estamos tan a pique de ser pastores, para pasar cantando la vida, como unos príncipes, quiere vuesa merced hacerse ermitaño? Calle, por su vida, vuelva en sí, y déjese de cuentos. -Los de hasta aquí -replicó don Quijote-, que han sido verdaderos en mi daño, los ha de volver mi muerte, con ayuda del cielo, en mi provecho. Yo, señores, siento que me voy muriendo a toda priesa; déjense burlas aparte, y traíganme un confesor que me confiese y un escribano que haga mi testamento, que en tales trances como éste no se ha de burlar el hombre con el alma; y así, suplico que, en tanto que el señor cura me confiesa, vayan por el escribano. Miráronse unos a otros, admirados de las razones de don Quijote, y, aunque en duda, le quisieron creer; y una de las señales por donde conjeturaron se moría fue el haber vuelto con tanta facilidad de loco a cuerdo, porque a las ya dichas razones añadió otras muchas tan bien dichas, tan cristianas y con tanto concierto, que del todo les vino a quitar la duda, y a creer que estaba cuerdo. Hizo salir la gente el cura, y quedóse solo con él, y confesóle. El bachiller fue por el escribano, y de allí a poco volvió con él y con Sancho Panza; el cual Sancho, que ya sabía por nuevas del bachiller en qué estado estaba su señor, hallando a la ama y a la sobrina llorosas, comenzó a hacer pucheros y a derramar lágrimas. Acabóse la confesión, y salió el cura, diciendo: -Verdaderamente se muere, y verdaderamente está cuerdo Alonso Quijano el Bueno; bien podemos entrar para que haga su testamento. Estas nuevas dieron un terrible empujón a los ojos preñados de ama, sobrina y de Sancho Panza, su buen escudero, de tal manera, que los hizo reventar las lágrimas de los ojos y mil profundos suspiros del pecho; porque, verdaderamente, como alguna vez se ha dicho, en tanto que don Quijote fue Alonso Quijano el Bueno, a secas, y en tanto que fue don Quijote de la Mancha, fue siempre de apacible condición y de agradable trato, y por esto no sólo era bien querido de los de su casa, sino de todos cuantos le conocían. Entró el escribano con los demás, y, después de haber hecho la cabeza del testamento y ordenado su alma don Quijote, con todas aquellas circunstancias cristianas que se requieren, llegando a las mandas, dijo: -Ãtem, es mi voluntad que de ciertos dineros que Sancho Panza, a quien en mi locura hice mi escudero, tiene, que, porque ha habido entre él y mí ciertas cuentas, y dares y tomares, quiero que no se le haga cargo dellos, ni se le pida cuenta alguna, sino que si sobrare alguno, después de haberse pagado de lo que le debo, el restante sea suyo, que será bien poco, y buen provecho le haga; y, si como estando yo loco fui parte para darle el gobierno de la ínsula, pudiera agora, estando cuerdo, darle el de un reino, se le diera, porque la sencillez de su condición y fidelidad de su trato lo merece. Y, volviéndose a Sancho, le dijo: -Perdóname, amigo, de la ocasión que te he dado de parecer loco como yo, haciéndote caer en el error en que yo he caído, de que hubo y hay caballeros andantes en el mundo. -¡Ay! -respondió Sancho, llorando-: no se muera vuestra merced, señor mío, sino tome mi consejo y viva muchos años, porque la mayor locura que puede hacer un hombre en esta vida es dejarse morir, sin más ni más, sin que nadie le mate, ni otras manos le acaben que las de la melancolía. Mire no sea perezoso, sino levántese desa cama, y vámonos al campo vestidos de pastores, como tenemos concertado: quizá tras de alguna mata hallaremos a la señora doña Dulcinea desencantada, que no haya más que ver. Si es que se muere de pesar de verse vencido, écheme a mí la culpa, diciendo que por haber yo cinchado mal a Rocinante le derribaron; cuanto más, que vuestra merced habrá visto en sus libros de caballerías ser cosa ordinaria derribarse unos caballeros a otros, y el que es vencido hoy ser vencedor mañana. -Así es -dijo Sansón-, y el buen Sancho Panza está muy en la verdad destos casos. -Señores -dijo don Quijote-, vámonos poco a poco, pues ya en los nidos de antaño no hay pájaros hogaño: yo fui loco, y ya soy cuerdo; fui don Quijote de la Mancha, y soy agora, como he dicho, Alonso Quijano el Bueno. Pueda con vuestras mercedes mi arrepentimiento y mi verdad volverme a la estimación que de mí se tenía, y prosiga adelante el señor escribano. »Ãtem, mando toda mi hacienda, a puerta cerrada, a Antonia Quijana, mi sobrina, que está presente, habiendo sacado primero de lo más bien parado della lo que fuere menester para cumplir las mandas que dejo hechas; y la primera satisfación que se haga quiero que sea pagar el salario que debo del tiempo que mi ama me ha servido, y más veinte ducados para un vestido. Dejo por mis albaceas al señor cura y al señor bachiller Sansón Carrasco, que están presentes. »Ãtem, es mi voluntad que si Antonia Quijana, mi sobrina, quisiere casarse, se case con hombre de quien primero se haya hecho información que no sabe qué cosas sean libros de caballerías; y, en caso que se averiguare que lo sabe, y, con todo eso, mi sobrina quisiere casarse con él, y se casare, pierda todo lo que le he mandado, lo cual puedan mis albaceas distribuir en obras pías a su voluntad. »Ãtem, suplico a los dichos señores mis albaceas que si la buena suerte les trujere a conocer al autor que dicen que compuso una historia que anda por ahí con el título de Segunda parte de las hazañas de don Quijote de la Mancha, de mi parte le pidan, cuan encarecidamente ser pueda, perdone la ocasión que sin yo pensarlo le di de haber escrito tantos y tan grandes disparates como en ella escribe, porque parto desta vida con escrúpulo de haberle dado motivo para escribirlos. Cerró con esto el testamento, y, tomándole un desmayo, se tendió de largo a largo en la cama. Alborotáronse todos y acudieron a su remedio, y en tres días que vivió después deste donde hizo el testamento, se desmayaba muy a menudo. Andaba la casa alborotada; pero, con todo, comía la sobrina, brindaba el ama, y se regocijaba Sancho Panza; que esto del heredar algo borra o templa en el heredero la memoria de la pena que es razón que deje el muerto. En fin, llegó el último de don Quijote, después de recebidos todos los sacramentos, y después de haber abominado con muchas y eficaces razones de los libros de caballerías. Hallóse el escribano presente, y dijo que nunca había leído en ningún libro de caballerías que algún caballero andante hubiese muerto en su lecho tan sosegadamente y tan cristiano como don Quijote; el cual, entre compasiones y lágrimas de los que allí se hallaron, dio su espíritu: quiero decir que se murió. Viendo lo cual el cura, pidió al escribano le diese por testimonio como Alonso Quijano el Bueno, llamado comúnmente don Quijote de la Mancha, había pasado desta presente vida y muerto naturalmente; y que el tal testimonio pedía para quitar la ocasión de algún otro autor que Cide Hamete Benengeli le resucitase falsamente, y hiciese inacabables historias de sus hazañas. Este fin tuvo el Ingenioso Hidalgo de la Mancha, cuyo lugar no quiso poner Cide Hamete puntualmente, por dejar que todas las villas y lugares de la Mancha contendiesen entre sí por ahijársele y tenérsele por suyo, como contendieron las siete ciudades de Grecia por Homero. Déjanse de poner aquí los llantos de Sancho, sobrina y ama de don Quijote, los nuevos epitafios de su sepultura, aunque Sansón Carrasco le puso éste: Yace aquí el Hidalgo fuerte que a tanto estremo llegó de valiente, que se advierte que la muerte no triunfó de su vida con su muerte. Tuvo a todo el mundo en poco; fue el espantajo y el coco del mundo, en tal coyuntura, que acreditó su ventura morir cuerdo y vivir loco. Y el prudentísimo Cide Hamete dijo a su pluma: -Aquí quedarás, colgada desta espetera y deste hilo de alambre, ni sé si bien cortada o mal tajada péñola mía, adonde vivirás luengos siglos, si presuntuosos y malandrines historiadores no te descuelgan para profanarte. Pero, antes que a ti lleguen, les puedes advertir, y decirles en el mejor modo que pudieres: ''¡Tate, tate, folloncicos! De ninguno sea tocada; porque esta impresa, buen rey, para mí estaba guardada. Para mí sola nació don Quijote, y yo para él; él supo obrar y yo escribir; solos los dos somos para en uno, a despecho y pesar del escritor fingido y tordesillesco que se atrevió, o se ha de atrever, a escribir con pluma de avestruz grosera y mal deliñada las hazañas de mi valeroso caballero, porque no es carga de sus hombros ni asunto de su resfriado ingenio; a quien advertirás, si acaso llegas a conocerle, que deje reposar en la sepultura los cansados y ya podridos huesos de don Quijote, y no le quiera llevar, contra todos los fueros de la muerte, a Castilla la Vieja, haciéndole salir de la fuesa donde real y verdaderamente yace tendido de largo a largo, imposibilitado de hacer tercera jornada y salida nueva; que, para hacer burla de tantas como hicieron tantos andantes caballeros, bastan las dos que él hizo, tan a gusto y beneplácito de las gentes a cuya noticia llegaron, así en éstos como en los estraños reinos''. Y con esto cumplirás con tu cristiana profesión, aconsejando bien a quien mal te quiere, y yo quedaré satisfecho y ufano de haber sido el primero que gozó el fruto de sus escritos enteramente, como deseaba, pues no ha sido otro mi deseo que poner en aborrecimiento de los hombres las fingidas y disparatadas historias de los libros de caballerías, que, por las de mi verdadero don Quijote, van ya tropezando, y han de caer del todo, sin duda alguna. Vale. Fin End of Project Gutenberg's Don Quijote, by Miguel de Cervantes Saavedra *** END OF THIS PROJECT GUTENBERG EBOOK DON QUIJOTE *** ***** This file should be named 2000-8.txt or 2000-8.zip ***** This and all associated files of various formats will be found in: http://www.gutenberg.org/2/0/0/2000/ Produced by an anonymous Project Gutenberg volunteer. Text file corrections and new HTML file by Joaquin Cuenca Abela. Updated editions will replace the previous one--the old editions will be renamed. Creating the works from public domain print editions means that no one owns a United States copyright in these works, so the Foundation (and you!) can copy and distribute it in the United States without permission and without paying copyright royalties. Special rules, set forth in the General Terms of Use part of this license, apply to copying and distributing Project Gutenberg-tm electronic works to protect the PROJECT GUTENBERG-tm concept and trademark. Project Gutenberg is a registered trademark, and may not be used if you charge for the eBooks, unless you receive specific permission. If you do not charge anything for copies of this eBook, complying with the rules is very easy. You may use this eBook for nearly any purpose such as creation of derivative works, reports, performances and research. They may be modified and printed and given away--you may do practically ANYTHING with public domain eBooks. Redistribution is subject to the trademark license, especially commercial redistribution. *** START: FULL LICENSE *** THE FULL PROJECT GUTENBERG LICENSE PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK To protect the Project Gutenberg-tm mission of promoting the free distribution of electronic works, by using or distributing this work (or any other work associated in any way with the phrase "Project Gutenberg"), you agree to comply with all the terms of the Full Project Gutenberg-tm License (available with this file or online at http://gutenberg.net/license). Section 1. General Terms of Use and Redistributing Project Gutenberg-tm electronic works 1.A. By reading or using any part of this Project Gutenberg-tm electronic work, you indicate that you have read, understand, agree to and accept all the terms of this license and intellectual property (trademark/copyright) agreement. If you do not agree to abide by all the terms of this agreement, you must cease using and return or destroy all copies of Project Gutenberg-tm electronic works in your possession. If you paid a fee for obtaining a copy of or access to a Project Gutenberg-tm electronic work and you do not agree to be bound by the terms of this agreement, you may obtain a refund from the person or entity to whom you paid the fee as set forth in paragraph 1.E.8. 1.B. "Project Gutenberg" is a registered trademark. It may only be used on or associated in any way with an electronic work by people who agree to be bound by the terms of this agreement. There are a few things that you can do with most Project Gutenberg-tm electronic works even without complying with the full terms of this agreement. See paragraph 1.C below. There are a lot of things you can do with Project Gutenberg-tm electronic works if you follow the terms of this agreement and help preserve free future access to Project Gutenberg-tm electronic works. See paragraph 1.E below. 1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation" or PGLAF), owns a compilation copyright in the collection of Project Gutenberg-tm electronic works. Nearly all the individual works in the collection are in the public domain in the United States. If an individual work is in the public domain in the United States and you are located in the United States, we do not claim a right to prevent you from copying, distributing, performing, displaying or creating derivative works based on the work as long as all references to Project Gutenberg are removed. Of course, we hope that you will support the Project Gutenberg-tm mission of promoting free access to electronic works by freely sharing Project Gutenberg-tm works in compliance with the terms of this agreement for keeping the Project Gutenberg-tm name associated with the work. You can easily comply with the terms of this agreement by keeping this work in the same format with its attached full Project Gutenberg-tm License when you share it without charge with others. 1.D. The copyright laws of the place where you are located also govern what you can do with this work. Copyright laws in most countries are in a constant state of change. If you are outside the United States, check the laws of your country in addition to the terms of this agreement before downloading, copying, displaying, performing, distributing or creating derivative works based on this work or any other Project Gutenberg-tm work. The Foundation makes no representations concerning the copyright status of any work in any country outside the United States. 1.E. Unless you have removed all references to Project Gutenberg: 1.E.1. The following sentence, with active links to, or other immediate access to, the full Project Gutenberg-tm License must appear prominently whenever any copy of a Project Gutenberg-tm work (any work on which the phrase "Project Gutenberg" appears, or with which the phrase "Project Gutenberg" is associated) is accessed, displayed, performed, viewed, copied or distributed: This eBook is for the use of anyone anywhere at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.net 1.E.2. If an individual Project Gutenberg-tm electronic work is derived from the public domain (does not contain a notice indicating that it is posted with permission of the copyright holder), the work can be copied and distributed to anyone in the United States without paying any fees or charges. If you are redistributing or providing access to a work with the phrase "Project Gutenberg" associated with or appearing on the work, you must comply either with the requirements of paragraphs 1.E.1 through 1.E.7 or obtain permission for the use of the work and the Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or 1.E.9. 1.E.3. If an individual Project Gutenberg-tm electronic work is posted with the permission of the copyright holder, your use and distribution must comply with both paragraphs 1.E.1 through 1.E.7 and any additional terms imposed by the copyright holder. Additional terms will be linked to the Project Gutenberg-tm License for all works posted with the permission of the copyright holder found at the beginning of this work. 1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm License terms from this work, or any files containing a part of this work or any other work associated with Project Gutenberg-tm. 1.E.5. Do not copy, display, perform, distribute or redistribute this electronic work, or any part of this electronic work, without prominently displaying the sentence set forth in paragraph 1.E.1 with active links or immediate access to the full terms of the Project Gutenberg-tm License. 1.E.6. You may convert to and distribute this work in any binary, compressed, marked up, nonproprietary or proprietary form, including any word processing or hypertext form. However, if you provide access to or distribute copies of a Project Gutenberg-tm work in a format other than "Plain Vanilla ASCII" or other format used in the official version posted on the official Project Gutenberg-tm web site (www.gutenberg.net), you must, at no additional cost, fee or expense to the user, provide a copy, a means of exporting a copy, or a means of obtaining a copy upon request, of the work in its original "Plain Vanilla ASCII" or other form. Any alternate format must include the full Project Gutenberg-tm License as specified in paragraph 1.E.1. 1.E.7. Do not charge a fee for access to, viewing, displaying, performing, copying or distributing any Project Gutenberg-tm works unless you comply with paragraph 1.E.8 or 1.E.9. 1.E.8. You may charge a reasonable fee for copies of or providing access to or distributing Project Gutenberg-tm electronic works provided that - You pay a royalty fee of 20% of the gross profits you derive from the use of Project Gutenberg-tm works calculated using the method you already use to calculate your applicable taxes. The fee is owed to the owner of the Project Gutenberg-tm trademark, but he has agreed to donate royalties under this paragraph to the Project Gutenberg Literary Archive Foundation. Royalty payments must be paid within 60 days following each date on which you prepare (or are legally required to prepare) your periodic tax returns. Royalty payments should be clearly marked as such and sent to the Project Gutenberg Literary Archive Foundation at the address specified in Section 4, "Information about donations to the Project Gutenberg Literary Archive Foundation." - You provide a full refund of any money paid by a user who notifies you in writing (or by e-mail) within 30 days of receipt that s/he does not agree to the terms of the full Project Gutenberg-tm License. You must require such a user to return or destroy all copies of the works possessed in a physical medium and discontinue all use of and all access to other copies of Project Gutenberg-tm works. - You provide, in accordance with paragraph 1.F.3, a full refund of any money paid for a work or a replacement copy, if a defect in the electronic work is discovered and reported to you within 90 days of receipt of the work. - You comply with all other terms of this agreement for free distribution of Project Gutenberg-tm works. 1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm electronic work or group of works on different terms than are set forth in this agreement, you must obtain permission in writing from both the Project Gutenberg Literary Archive Foundation and Michael Hart, the owner of the Project Gutenberg-tm trademark. Contact the Foundation as set forth in Section 3 below. 1.F. 1.F.1. Project Gutenberg volunteers and employees expend considerable effort to identify, do copyright research on, transcribe and proofread public domain works in creating the Project Gutenberg-tm collection. Despite these efforts, Project Gutenberg-tm electronic works, and the medium on which they may be stored, may contain "Defects," such as, but not limited to, incomplete, inaccurate or corrupt data, transcription errors, a copyright or other intellectual property infringement, a defective or damaged disk or other medium, a computer virus, or computer codes that damage or cannot be read by your equipment. 1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right of Replacement or Refund" described in paragraph 1.F.3, the Project Gutenberg Literary Archive Foundation, the owner of the Project Gutenberg-tm trademark, and any other party distributing a Project Gutenberg-tm electronic work under this agreement, disclaim all liability to you for damages, costs and expenses, including legal fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH DAMAGE. 1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a defect in this electronic work within 90 days of receiving it, you can receive a refund of the money (if any) you paid for it by sending a written explanation to the person you received the work from. If you received the work on a physical medium, you must return the medium with your written explanation. The person or entity that provided you with the defective work may elect to provide a replacement copy in lieu of a refund. If you received the work electronically, the person or entity providing it to you may choose to give you a second opportunity to receive the work electronically in lieu of a refund. If the second copy is also defective, you may demand a refund in writing without further opportunities to fix the problem. 1.F.4. Except for the limited right of replacement or refund set forth in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE. 1.F.5. Some states do not allow disclaimers of certain implied warranties or the exclusion or limitation of certain types of damages. If any disclaimer or limitation set forth in this agreement violates the law of the state applicable to this agreement, the agreement shall be interpreted to make the maximum disclaimer or limitation permitted by the applicable state law. The invalidity or unenforceability of any provision of this agreement shall not void the remaining provisions. 1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the trademark owner, any agent or employee of the Foundation, anyone providing copies of Project Gutenberg-tm electronic works in accordance with this agreement, and any volunteers associated with the production, promotion and distribution of Project Gutenberg-tm electronic works, harmless from all liability, costs and expenses, including legal fees, that arise directly or indirectly from any of the following which you do or cause to occur: (a) distribution of this or any Project Gutenberg-tm work, (b) alteration, modification, or additions or deletions to any Project Gutenberg-tm work, and (c) any Defect you cause. Section 2. Information about the Mission of Project Gutenberg-tm Project Gutenberg-tm is synonymous with the free distribution of electronic works in formats readable by the widest variety of computers including obsolete, old, middle-aged and new computers. It exists because of the efforts of hundreds of volunteers and donations from people in all walks of life. Volunteers and financial support to provide volunteers with the assistance they need are critical to reaching Project Gutenberg-tm's goals and ensuring that the Project Gutenberg-tm collection will remain freely available for generations to come. In 2001, the Project Gutenberg Literary Archive Foundation was created to provide a secure and permanent future for Project Gutenberg-tm and future generations. To learn more about the Project Gutenberg Literary Archive Foundation and how your efforts and donations can help, see Sections 3 and 4 and the Foundation web page at http://www.pglaf.org. Section 3. Information about the Project Gutenberg Literary Archive Foundation The Project Gutenberg Literary Archive Foundation is a non profit 501(c)(3) educational corporation organized under the laws of the state of Mississippi and granted tax exempt status by the Internal Revenue Service. The Foundation's EIN or federal tax identification number is 64-6221541. Its 501(c)(3) letter is posted at http://pglaf.org/fundraising. Contributions to the Project Gutenberg Literary Archive Foundation are tax deductible to the full extent permitted by U.S. federal laws and your state's laws. The Foundation's principal office is located at 4557 Melan Dr. S. Fairbanks, AK, 99712., but its volunteers and employees are scattered throughout numerous locations. Its business office is located at 809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email business@pglaf.org. Email contact links and up to date contact information can be found at the Foundation's web site and official page at http://pglaf.org For additional contact information: Dr. Gregory B. Newby Chief Executive and Director gbnewby@pglaf.org Section 4. Information about Donations to the Project Gutenberg Literary Archive Foundation Project Gutenberg-tm depends upon and cannot survive without wide spread public support and donations to carry out its mission of increasing the number of public domain and licensed works that can be freely distributed in machine readable form accessible by the widest array of equipment including outdated equipment. Many small donations ($1 to $5,000) are particularly important to maintaining tax exempt status with the IRS. The Foundation is committed to complying with the laws regulating charities and charitable donations in all 50 states of the United States. Compliance requirements are not uniform and it takes a considerable effort, much paperwork and many fees to meet and keep up with these requirements. We do not solicit donations in locations where we have not received written confirmation of compliance. To SEND DONATIONS or determine the status of compliance for any particular state visit http://pglaf.org While we cannot and do not solicit contributions from states where we have not met the solicitation requirements, we know of no prohibition against accepting unsolicited donations from donors in such states who approach us with offers to donate. International donations are gratefully accepted, but we cannot make any statements concerning tax treatment of donations received from outside the United States. U.S. laws alone swamp our small staff. Please check the Project Gutenberg Web pages for current donation methods and addresses. Donations are accepted in a number of other ways including including checks, online payments and credit card donations. To donate, please visit: http://pglaf.org/donate Section 5. General Information About Project Gutenberg-tm electronic works. Professor Michael S. Hart is the originator of the Project Gutenberg-tm concept of a library of electronic works that could be freely shared with anyone. For thirty years, he produced and distributed Project Gutenberg-tm eBooks with only a loose network of volunteer support. Project Gutenberg-tm eBooks are often created from several printed editions, all of which are confirmed as Public Domain in the U.S. unless a copyright notice is included. Thus, we do not necessarily keep eBooks in compliance with any particular paper edition. Most people start at our Web site which has the main PG search facility: http://www.gutenberg.net This Web site includes information about Project Gutenberg-tm, including how to make donations to the Project Gutenberg Literary Archive Foundation, how to help produce our new eBooks, and how to subscribe to our email newsletter to hear about new eBooks. presage-0.8.8/resources/profiles/0000755000175000017500000000000011764714756014035 500000000000000presage-0.8.8/resources/profiles/generate_presage_config.sh0000755000175000017500000000377511737142176021144 00000000000000#!/bin/sh ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # This script takes the configuration $TEMPLATE file, the output file # name and the pkgdatadir as arguments and writes to $OUTPUT file, # replacing all tokens (in the form of ::TOKEN::) in $TEMPLATE. # exit on error set -e if [ $# -lt 3 ]; then echo "Usage: $0 template output pkgdatadir" exit 1 fi TEMPLATE=$1 OUTPUT=$2 PACKAGEDATADIR=$3 # Determining whether PACKAGEDATADIR is in a format which will be # understood by SQLite on Cygwin, whereby SQLite will not be # able to open a database file when specified as an absolute path # rooted at / (e.g. /var/database_en.db) # # Sqlite has no problem using a relative path (which is of no use to # us) or opening a database file rooted at cygwin's root # (e.g. c:/cygwin/var/database_en.db) # case `uname` in CYGWIN*) PACKAGEDATADIR=`cygpath -m $PACKAGEDATADIR`; ;; MINGW*) PACKAGEDATADIR=`cd $PACKAGEDATADIR && pwd -W`; PACKAGEDATADIR=`echo $PACKAGEDATADIR | sed -e 's|/|\\\\\\\\|g'`; ;; *) ;; esac # Replace the token in $TEMPLATE and write result to $OUTPUT sed -e " s|::PACKAGEDATADIR::|${PACKAGEDATADIR}| " ${TEMPLATE} > ${OUTPUT} presage-0.8.8/resources/profiles/Makefile.am0000644000175000017500000000334611737142176016006 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in EXTRA_DIST = presage.xml.template generate_presage_config.sh BUILT_SOURCES = presage.xml CLEANFILES = presage.xml # added dependency on Makefile to regenerate configuration file in the # event it had previously been built and then the package reconfigured # to install to a different location. presage.xml: Makefile presage.xml.template generate_presage_config.sh ${srcdir}/generate_presage_config.sh ${srcdir}/presage.xml.template presage.xml ${pkgdatadir}; # ${prefix}/etc directory sysconf_DATA = presage.xml # # ${prefix}/share directory # dist_data_DATA = presage.xml # # ${prefix}/share/${package-name} directory # dist_pkgdata_DATA = presage.xml # # ${prefix}/var directory # dist_localstate_DATA = presage.xml # # ${prefix}/com directory # dist_sharedstate_DATA = presage.xml # presage-0.8.8/resources/profiles/Makefile.in0000644000175000017500000003412611763440355016016 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = resources/profiles DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(sysconfdir)" DATA = $(sysconf_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = presage.xml.template generate_presage_config.sh BUILT_SOURCES = presage.xml CLEANFILES = presage.xml # ${prefix}/etc directory sysconf_DATA = presage.xml all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu resources/profiles/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu resources/profiles/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-sysconfDATA: $(sysconf_DATA) @$(NORMAL_INSTALL) test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" @list='$(sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ done uninstall-sysconfDATA: @$(NORMAL_UNINSTALL) @list='$(sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(sysconfdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sysconfdir)" && rm -f $$files tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(sysconfdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sysconfDATA install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sysconfDATA .MAKE: all check install install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ install-sysconfDATA installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ uninstall uninstall-am uninstall-sysconfDATA # added dependency on Makefile to regenerate configuration file in the # event it had previously been built and then the package reconfigured # to install to a different location. presage.xml: Makefile presage.xml.template generate_presage_config.sh ${srcdir}/generate_presage_config.sh ${srcdir}/presage.xml.template presage.xml ${pkgdatadir}; # # ${prefix}/share directory # dist_data_DATA = presage.xml # # ${prefix}/share/${package-name} directory # dist_pkgdata_DATA = presage.xml # # ${prefix}/var directory # dist_localstate_DATA = presage.xml # # ${prefix}/com directory # dist_sharedstate_DATA = presage.xml # # 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: presage-0.8.8/resources/profiles/presage.xml.template0000644000175000017500000001234211763437013017724 00000000000000 ERROR DefaultAbbreviationExpansionPredictor DefaultSmoothedNgramPredictor UserSmoothedNgramPredictor DefaultRecencyPredictor ERROR 80 yes ERROR 6 no 0 ERROR 1000 60 Meritocracy ERROR false SmoothedNgramPredictor ERROR ::PACKAGEDATADIR::/database_en.db 0.01 0.1 0.89 false ERROR SmoothedNgramPredictor ERROR ${HOME}/.presage/lm.db 0.01 0.1 0.89 true ERROR RecencyPredictor ERROR 1 1 20 DictionaryPredictor ERROR /usr/share/dict/words 0.000001 AbbreviationExpansionPredictor ERROR ::PACKAGEDATADIR::/abbreviations_en.txt DejavuPredictor ERROR ::PACKAGEDATADIR::/dejavu_memory_en.txt 3 ARPAPredictor ERROR ::PACKAGEDATADIR::/arpa_en.arpa ::PACKAGEDATADIR::/arpa_en.vocab 100 presage-0.8.8/bindings/0000755000175000017500000000000011764714756011775 500000000000000presage-0.8.8/bindings/presage.i0000644000175000017500000000307511737142176013511 00000000000000 ########## # Presage, an extensible predictive text entry system # --------------------------------------------------- # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Build instructions # swig -c++ -python -I../src presage.i # g++ -c -fpic presage_wrap.cxx ../src/presage.cpp -I/usr/include/python2.4 -I/usr/lib/python2.4/config -I../src # g++ -shared presage.o presage_wrap.o -L../../build/src/.libs -lpresage -o _presage.so ## Test with # python runme.py %module(directors="1") presage %include "std_vector.i" %include "std_string.i" %feature("director") PresageCallback; %{ #include "presage.h" #include "presageException.h" #include "presageCallback.h" %} namespace std { %template() vector< string >; } /* Let's just grab the original header file here */ %include "presage.h" %include "presageException.h" %include "presageCallback.h"presage-0.8.8/bindings/python/0000755000175000017500000000000011764714756013316 500000000000000presage-0.8.8/bindings/python/presage_python_demo.in0000644000175000017500000001031511737142176017610 00000000000000#!/usr/bin/python ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import getopt PROGRAM_NAME = 'presage_python_demo' config = None suggestions = None def disclaimer(): print """ Presage python demo ----------------------- This program is intended as a demonstration of Presage ONLY. The Presage project aims to provide an intelligent predictive text entry platform. Its intent is NOT to provide a predictive text entry user interface. Think of Presage as the predictive backend that sits behind a shiny user interface and does all the predictive heavy lifting. """ def print_version(): print """ %s (%s) version %s Copyright (C) 2004 Matteo Vescovi. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. """ % (PROGRAM_NAME, '@PACKAGE_NAME@', '@PACKAGE_VERSION@') def print_usage(): print """ Usage: %s [OPTION]... At the prompt, type in some text. Hit enter to generate a prediction. Any text input is valid, including no text, a single character, or a long string. -c, --config CONFIG use config file CONFIG -s, --suggestions N set prediction size to N suggestions -h, --help display this help and exit -v, --version output version information and exit Direct your bug reports to: %s """ % (PROGRAM_NAME, '@PACKAGE_BUGREPORT@') def parse_cmd_line_args(): global config global suggestions short_options = "c:s:hv" long_options = ["config=", "suggestions=", "help", "version"] try: opts, args = getopt.getopt(sys.argv[1:], short_options, long_options) except getopt.GetoptError, err: print str(err) sys.exit(1) for opt, arg in opts: if opt in ('-v', '--version'): print_version() sys.exit() elif opt in ('-h', '--help'): print_usage() sys.exit() elif opt in ('-c', '--config'): config = arg elif opt in ('-s', '--suggestions'): suggestions = arg def main(): try: import presage except ImportError, e: print ''' Error: failed to import module presage. Check that presage python binding is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). Check that presage library is properly installed (if installed in a non-standard location, please set LD_LIBRARY_PATH (PATH, LIBPATH) accordingly). ''' print e sys.exit(1) try: # Define and create PresageCallback object class DemoCallback(presage.PresageCallback): def __init__(self): presage.PresageCallback.__init__(self) self.buffer = '' def get_past_stream(self): return self.buffer def get_future_stream(self): return '' # Presage owns callback, so we create it and disown it callback = DemoCallback().__disown__() # Create Presage object if config: prsg = presage.Presage(callback, config) else: prsg = presage.Presage(callback) if suggestions: prsg.config('Presage.Selector.SUGGESTIONS', suggestions) print "Enter text at the prompt (press enter on empty line to exit):" str = None while str != "": str = raw_input("> ") callback.buffer += str print prsg.predict() # Destroy Presage object del prsg except presage.PresageException,ex: print ex.what() sys.exit(1) print "Goodbye" if __name__ == '__main__': parse_cmd_line_args() disclaimer() main() presage-0.8.8/bindings/python/presage_python_demo.10000644000175000017500000000177411763440470017350 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH PRESAGE_PYTHON_DEMO "1" "June 2012" "presage_python_demo " "User Commands" .SH NAME presage_python_demo \- presage demo program (Python) .SH SYNOPSIS .B presage_python_demo [\fIOPTION\fR]... .SH DESCRIPTION At the prompt, type in some text. Hit enter to generate a prediction. Any text input is valid, including no text, a single character, or a long string. .TP \fB\-c\fR, \fB\-\-config\fR CONFIG use config file CONFIG .TP \fB\-s\fR, \fB\-\-suggestions\fR N set prediction size to N suggestions .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit .TP \fB\-v\fR, \fB\-\-version\fR output version information and exit .PP Direct your bug reports to: matteo.vescovi@yahoo.co.uk .PP presage_python_demo (presage) version 0.8.8 Copyright \(co 2004 Matteo Vescovi. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. presage-0.8.8/bindings/python/Makefile.am0000644000175000017500000000671111763437013015262 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if HAVE_SWIG if HAVE_PYTHON if ENABLE_PYTHON_BINDING PRESAGE_INTERFACE = ../../src/lib/presage.h \ ../../src/lib/presageException.h \ ../../src/lib/presageCallback.h SWIG_INTERFACE = ../presage.i BUILT_SOURCES = presage_wrap.cpp presage_wrap.h presage.py CLEANFILES = presage_wrap.cpp presage_wrap.h presage.py EXTRA_DIST = presage_python_demo all-local: presage_wrap.cpp presage_wrap.h presage.py @case "`uname`" in \ MINGW*) \ $(PYTHON) setup.py build --compiler=mingw32 \ ;; \ *) \ CPPFLAGS=$(CPPFLAGS) CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" $(PYTHON) setup.py build \ ;; \ esac; # python on MinGW/MSYS requires pure Windows style paths # Using following (cd $dir && pwd -W) hack to get a nearly # native Windows path, then translating the forward slash # to a backward slash to make python distutils jolly. # P.S. the backslash has to be escaped thrice, hence a single # backslash turns into a sequence of eight (neat, huh?) # install-exec-local: @case "`uname`" in \ MINGW*) \ NATIVE_WINDOWS_PREFIX="`cd $(DESTDIR)$(prefix) && pwd -W`"; \ NATIVE_WINDOWS_PREFIX="`echo $$NATIVE_WINDOWS_PREFIX | sed -e 's|/|\\\\\\\\|g'`"; \ $(PYTHON) setup.py install --prefix="$$NATIVE_WINDOWS_PREFIX" \ ;; \ *) \ $(PYTHON) setup.py install --prefix=$(DESTDIR)$(prefix) \ ;; \ esac; # This rule cleans up stuff installed by Python's setup.py # Unfortunately, Python's distutils do not provide an uninstall # command, so we have to make up for it here in uninstall-local # hook. This might break if distutils' behaviour changes as automake # has no control over what distutils install command does. # uninstall-local: rm -f $(DESTDIR)$(libdir)/python*/site-packages/_presage.so rm -f $(DESTDIR)$(libdir)/python*/site-packages/presage.py rm -f $(DESTDIR)$(libdir)/python*/site-packages/presage.pyc rm -f $(DESTDIR)$(libdir)/python*/site-packages/python_presage-*.egg-info rm -f $(DESTDIR)$(bindir)/presage_python_demo clean-local: rm -rf build presage_wrap.cpp presage_wrap.h presage.py: $(SWIG_INTERFACE) $(PRESAGE_INTERFACE) $(SWIG) -c++ -python -I$(top_srcdir)/src/lib -o presage_wrap.cpp -outdir . $(srcdir)/$(SWIG_INTERFACE) if HAVE_HELP2MAN presage_python_demo.1: presage_python_demo.in $(top_srcdir)/configure.ac chmod u+x ./presage_python_demo help2man --output=$@ --no-info --name="presage demo program (Python)" ./presage_python_demo dist_man_MANS = presage_python_demo.1 DISTCLEANFILES = presage_python_demo.1 endif endif # ENABLE_PYTHON_BINDING endif # HAVE_PYTHON endif # HAVE_SWIG presage-0.8.8/bindings/python/Makefile.in0000644000175000017500000005142711763440354015301 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = bindings/python DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/presage_python_demo.in \ $(srcdir)/setup.py.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = setup.py presage_python_demo CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" NROFF = nroff MANS = $(dist_man_MANS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@PRESAGE_INTERFACE = ../../src/lib/presage.h \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ../../src/lib/presageException.h \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ../../src/lib/presageCallback.h @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@SWIG_INTERFACE = ../presage.i @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@BUILT_SOURCES = presage_wrap.cpp presage_wrap.h presage.py @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@CLEANFILES = presage_wrap.cpp presage_wrap.h presage.py @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@EXTRA_DIST = presage_python_demo @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@dist_man_MANS = presage_python_demo.1 @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@DISTCLEANFILES = presage_python_demo.1 all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bindings/python/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu bindings/python/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): setup.py: $(top_builddir)/config.status $(srcdir)/setup.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ presage_python_demo: $(top_builddir)/config.status $(srcdir)/presage_python_demo.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(dist_man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @list=''; test -n "$(man1dir)" || exit 0; \ { for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ test -z "$$files" || { \ echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am @ENABLE_PYTHON_BINDING_FALSE@all-local: @HAVE_PYTHON_FALSE@all-local: @HAVE_SWIG_FALSE@all-local: all-am: Makefile $(MANS) all-local installdirs: for dir in "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) @ENABLE_PYTHON_BINDING_FALSE@uninstall-local: @HAVE_PYTHON_FALSE@uninstall-local: @HAVE_SWIG_FALSE@uninstall-local: @ENABLE_PYTHON_BINDING_FALSE@install-exec-local: @HAVE_PYTHON_FALSE@install-exec-local: @HAVE_SWIG_FALSE@install-exec-local: @ENABLE_PYTHON_BINDING_FALSE@clean-local: @HAVE_PYTHON_FALSE@clean-local: @HAVE_SWIG_FALSE@clean-local: clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-exec-local install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-local uninstall-man uninstall-man: uninstall-man1 .MAKE: all check install install-am install-strip .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool clean-local distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-exec-local \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am uninstall uninstall-am uninstall-local uninstall-man \ uninstall-man1 @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@all-local: presage_wrap.cpp presage_wrap.h presage.py @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ @case "`uname`" in \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ MINGW*) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(PYTHON) setup.py build --compiler=mingw32 \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ *) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ CPPFLAGS=$(CPPFLAGS) CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" $(PYTHON) setup.py build \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ esac; # python on MinGW/MSYS requires pure Windows style paths # Using following (cd $dir && pwd -W) hack to get a nearly # native Windows path, then translating the forward slash # to a backward slash to make python distutils jolly. # P.S. the backslash has to be escaped thrice, hence a single # backslash turns into a sequence of eight (neat, huh?) # @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@install-exec-local: @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ @case "`uname`" in \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ MINGW*) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ NATIVE_WINDOWS_PREFIX="`cd $(DESTDIR)$(prefix) && pwd -W`"; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ NATIVE_WINDOWS_PREFIX="`echo $$NATIVE_WINDOWS_PREFIX | sed -e 's|/|\\\\\\\\|g'`"; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(PYTHON) setup.py install --prefix="$$NATIVE_WINDOWS_PREFIX" \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ *) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(PYTHON) setup.py install --prefix=$(DESTDIR)$(prefix) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ esac; # This rule cleans up stuff installed by Python's setup.py # Unfortunately, Python's distutils do not provide an uninstall # command, so we have to make up for it here in uninstall-local # hook. This might break if distutils' behaviour changes as automake # has no control over what distutils install command does. # @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@uninstall-local: @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -f $(DESTDIR)$(libdir)/python*/site-packages/_presage.so @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -f $(DESTDIR)$(libdir)/python*/site-packages/presage.py @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -f $(DESTDIR)$(libdir)/python*/site-packages/presage.pyc @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -f $(DESTDIR)$(libdir)/python*/site-packages/python_presage-*.egg-info @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -f $(DESTDIR)$(bindir)/presage_python_demo @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@clean-local: @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -rf build @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@presage_wrap.cpp presage_wrap.h presage.py: $(SWIG_INTERFACE) $(PRESAGE_INTERFACE) @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(SWIG) -c++ -python -I$(top_srcdir)/src/lib -o presage_wrap.cpp -outdir . $(srcdir)/$(SWIG_INTERFACE) @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@presage_python_demo.1: presage_python_demo.in $(top_srcdir)/configure.ac @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ chmod u+x ./presage_python_demo @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ help2man --output=$@ --no-info --name="presage demo program (Python)" ./presage_python_demo # 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: presage-0.8.8/bindings/python/setup.py.in0000644000175000017500000000366211763437013015347 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Process this file with configure to produce setup.py def getenv_list(var_name): from os import getenv var = getenv(var_name) if var: return var.split() else: return [] from distutils.core import setup, Extension setup(name='python-@PACKAGE_NAME@', version='@PACKAGE_VERSION@', description='Presage Python binding', author='Matteo Vescovi', author_email='@PACKAGE_BUGREPORT@', maintainer='Matteo Vescovi', maintainer_email='@PACKAGE_BUGREPORT@', url='http://presage.sourceforge.net/', py_modules=['presage'], scripts=['presage_python_demo'], ext_modules=[Extension('_presage', ['presage_wrap.cpp'], include_dirs=['@top_srcdir@/src/lib'], library_dirs=['../../src/lib/.libs'], libraries=['presage'], extra_compile_args=getenv_list('CPPFLAGS') + getenv_list('CXXFLAGS'), extra_link_args=getenv_list('LDFLAGS'))] ) presage-0.8.8/bindings/python/presage_python_demo0000644000175000017500000001030111764437313017176 00000000000000#!/usr/bin/python ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import getopt PROGRAM_NAME = 'presage_python_demo' config = None suggestions = None def disclaimer(): print """ Presage python demo ----------------------- This program is intended as a demonstration of Presage ONLY. The Presage project aims to provide an intelligent predictive text entry platform. Its intent is NOT to provide a predictive text entry user interface. Think of Presage as the predictive backend that sits behind a shiny user interface and does all the predictive heavy lifting. """ def print_version(): print """ %s (%s) version %s Copyright (C) 2004 Matteo Vescovi. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. """ % (PROGRAM_NAME, 'presage', '0.8.8') def print_usage(): print """ Usage: %s [OPTION]... At the prompt, type in some text. Hit enter to generate a prediction. Any text input is valid, including no text, a single character, or a long string. -c, --config CONFIG use config file CONFIG -s, --suggestions N set prediction size to N suggestions -h, --help display this help and exit -v, --version output version information and exit Direct your bug reports to: %s """ % (PROGRAM_NAME, 'matteo.vescovi@yahoo.co.uk') def parse_cmd_line_args(): global config global suggestions short_options = "c:s:hv" long_options = ["config=", "suggestions=", "help", "version"] try: opts, args = getopt.getopt(sys.argv[1:], short_options, long_options) except getopt.GetoptError, err: print str(err) sys.exit(1) for opt, arg in opts: if opt in ('-v', '--version'): print_version() sys.exit() elif opt in ('-h', '--help'): print_usage() sys.exit() elif opt in ('-c', '--config'): config = arg elif opt in ('-s', '--suggestions'): suggestions = arg def main(): try: import presage except ImportError, e: print ''' Error: failed to import module presage. Check that presage python binding is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). Check that presage library is properly installed (if installed in a non-standard location, please set LD_LIBRARY_PATH (PATH, LIBPATH) accordingly). ''' print e sys.exit(1) try: # Define and create PresageCallback object class DemoCallback(presage.PresageCallback): def __init__(self): presage.PresageCallback.__init__(self) self.buffer = '' def get_past_stream(self): return self.buffer def get_future_stream(self): return '' # Presage owns callback, so we create it and disown it callback = DemoCallback().__disown__() # Create Presage object if config: prsg = presage.Presage(callback, config) else: prsg = presage.Presage(callback) if suggestions: prsg.config('Presage.Selector.SUGGESTIONS', suggestions) print "Enter text at the prompt (press enter on empty line to exit):" str = None while str != "": str = raw_input("> ") callback.buffer += str print prsg.predict() # Destroy Presage object del prsg except presage.PresageException,ex: print ex.what() sys.exit(1) print "Goodbye" if __name__ == '__main__': parse_cmd_line_args() disclaimer() main() presage-0.8.8/bindings/c/0000755000175000017500000000000011764714757012220 500000000000000presage-0.8.8/bindings/c/libpresage-1.def0000644000175000017500000000041711737142176015063 00000000000000LIBRARY libpresage-1.dll EXPORTS presage_completion presage_config presage_config_set presage_context presage_context_change presage_free presage_free_string presage_free_string_array presage_new presage_new_with_config presage_predict presage_prefix presage_save_config presage-0.8.8/bindings/c/Makefile.am0000644000175000017500000000236711737142176014172 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2010 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in # TESTS = presage_c_demo check_PROGRAMS = presage_c_demo presage_c_demo_SOURCES = presage_c_demo.c presage_c_demo_LDADD = ../../src/lib/libpresage.la presage_c_demo_CFLAGS = -I$(top_srcdir)/src/lib CLEANFILES = \ presage_c_demo.xml EXTRA_DIST = \ README_Visual_Studio.txt \ libpresage-1.def presage-0.8.8/bindings/c/presage_c_demo.c0000644000175000017500000000633411737142176015234 00000000000000 /****************************************************** * Presage, an extensible predictive text entry system * --------------------------------------------------- * * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ #include "presage.h" #include static const char* PAST = "did you not sa"; static const char* FUTURE = ""; static const char* get_past_stream(void* arg) { return (char*) arg; } static const char* get_future_stream(void* arg) { return (char*) arg; } int main() { presage_t prsg; char* completion; char** prediction; char* context; int context_change; char* prefix; char* value; size_t i; if (PRESAGE_OK != presage_new_with_config (get_past_stream, (void *) PAST, get_future_stream, (void *) FUTURE, "presage_c_demo.xml", &prsg)) { return PRESAGE_ERROR; } if (PRESAGE_OK == presage_predict (prsg, &prediction)) { for (i = 0; prediction[i] != 0; i++) printf ("prediction[%d]: %s\n", i, prediction[i]); presage_free_string_array (prediction); } if (PRESAGE_OK == presage_completion (prsg, "savages", &completion)) { printf ("completion: %s\n", completion); presage_free_string (completion); } if (PRESAGE_OK == presage_context (prsg, &context)) { printf ("context: %s\n", context); presage_free_string (context); } if (PRESAGE_OK == presage_context_change (prsg, &context_change)) { printf ("context_change: %d\n", context_change); } if (PRESAGE_OK == presage_prefix (prsg, &prefix)) { printf ("prefix: %s\n", prefix); presage_free_string (prefix); } if (PRESAGE_OK == presage_config (prsg, "Presage.Selector.SUGGESTIONS", &value)) { printf ("SUGGESTIONS: %s\n", value); presage_free_string (value); } presage_config_set (prsg, "Presage.Selector.SUGGESTIONS", "10"); if (PRESAGE_OK == presage_predict (prsg, &prediction)) { for (i = 0; prediction[i] != 0; i++) printf ("prediction[%d]: %s\n", i, prediction[i]); presage_free_string_array (prediction); } presage_save_config (prsg); presage_free (prsg); return 0; } presage-0.8.8/bindings/c/README_Visual_Studio.txt0000644000175000017500000000135011737142176016475 00000000000000____________________________________________ Linking to libpresage DLL with Visual Studio ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to link to libpresage DLL (built with MinGW/MSYS) with Visual Studio, one first needs to create an import library compatible with Visual Studio. This is done using the LIB tool that comes with Visual Studio: LIB /MACHINE:x86 /DEF:libpresage-1.def /OUT:libpresage-1.lib The LIB tool takes libpresage-1.def and libpresage-1.dll files as input, and generates the libpresage-1.lib import library. One can now link their application against the libpresage DLL with Visual Studio with the following command: CL /EHsc /Ic:\presage\include presage_c_demo.c c:\presage\bin\libpresage-1.lib presage-0.8.8/bindings/c/Makefile.in0000644000175000017500000004416311763440354014201 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2010 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # TESTS = presage_c_demo VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ check_PROGRAMS = presage_c_demo$(EXEEXT) subdir = bindings/c DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am_presage_c_demo_OBJECTS = presage_c_demo-presage_c_demo.$(OBJEXT) presage_c_demo_OBJECTS = $(am_presage_c_demo_OBJECTS) presage_c_demo_DEPENDENCIES = ../../src/lib/libpresage.la presage_c_demo_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(presage_c_demo_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(presage_c_demo_SOURCES) DIST_SOURCES = $(presage_c_demo_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ presage_c_demo_SOURCES = presage_c_demo.c presage_c_demo_LDADD = ../../src/lib/libpresage.la presage_c_demo_CFLAGS = -I$(top_srcdir)/src/lib CLEANFILES = \ presage_c_demo.xml EXTRA_DIST = \ README_Visual_Studio.txt \ libpresage-1.def all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bindings/c/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu bindings/c/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list presage_c_demo$(EXEEXT): $(presage_c_demo_OBJECTS) $(presage_c_demo_DEPENDENCIES) @rm -f presage_c_demo$(EXEEXT) $(presage_c_demo_LINK) $(presage_c_demo_OBJECTS) $(presage_c_demo_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/presage_c_demo-presage_c_demo.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< presage_c_demo-presage_c_demo.o: presage_c_demo.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(presage_c_demo_CFLAGS) $(CFLAGS) -MT presage_c_demo-presage_c_demo.o -MD -MP -MF $(DEPDIR)/presage_c_demo-presage_c_demo.Tpo -c -o presage_c_demo-presage_c_demo.o `test -f 'presage_c_demo.c' || echo '$(srcdir)/'`presage_c_demo.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/presage_c_demo-presage_c_demo.Tpo $(DEPDIR)/presage_c_demo-presage_c_demo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='presage_c_demo.c' object='presage_c_demo-presage_c_demo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(presage_c_demo_CFLAGS) $(CFLAGS) -c -o presage_c_demo-presage_c_demo.o `test -f 'presage_c_demo.c' || echo '$(srcdir)/'`presage_c_demo.c presage_c_demo-presage_c_demo.obj: presage_c_demo.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(presage_c_demo_CFLAGS) $(CFLAGS) -MT presage_c_demo-presage_c_demo.obj -MD -MP -MF $(DEPDIR)/presage_c_demo-presage_c_demo.Tpo -c -o presage_c_demo-presage_c_demo.obj `if test -f 'presage_c_demo.c'; then $(CYGPATH_W) 'presage_c_demo.c'; else $(CYGPATH_W) '$(srcdir)/presage_c_demo.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/presage_c_demo-presage_c_demo.Tpo $(DEPDIR)/presage_c_demo-presage_c_demo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='presage_c_demo.c' object='presage_c_demo-presage_c_demo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(presage_c_demo_CFLAGS) $(CFLAGS) -c -o presage_c_demo-presage_c_demo.obj `if test -f 'presage_c_demo.c'; then $(CYGPATH_W) 'presage_c_demo.c'; else $(CYGPATH_W) '$(srcdir)/presage_c_demo.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean \ clean-checkPROGRAMS clean-generic clean-libtool ctags \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am # 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: presage-0.8.8/bindings/Makefile.am0000644000175000017500000000176611737142176013752 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = python c EXTRA_DIST = presage.i presage-0.8.8/bindings/Makefile.in0000644000175000017500000004431011763440354013751 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = bindings DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = python c EXTRA_DIST = presage.i all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bindings/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu bindings/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ ctags ctags-recursive distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am # 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: presage-0.8.8/Makefile.in0000644000175000017500000006464511763440356012173 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########## # Presage, an extensible predictive text entry system # --------------------------------------------------- # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.hin \ $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ THANKS TODO compile config.guess config.sub depcomp install-sh \ ltmain.sh missing py-compile ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir dist dist-all distcheck ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d "$(distdir)" \ || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr "$(distdir)"; }; } am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = src test resources bindings apps doc BUILT_SOURCES = dirs.h CLEANFILES = dirs.h EXTRA_DIST = FAQ # Ensure local m4 macros are included during autoreconf and automatic # aclocal.m4 remaking ACLOCAL_AMFLAGS = -I m4 all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then \ rm -f stamp-h1; \ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ else :; fi stamp-h1: $(srcdir)/config.hin $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.hin: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # 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. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ 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; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) config.hin $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) config.hin $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.hin $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) config.hin $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_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 case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @$(am__cd) '$(distuninstallcheck_dir)' \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile config.h installdirs: installdirs-recursive installdirs-am: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \ ctags-recursive install install-am install-strip \ tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-generic \ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-hdr \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-recursive uninstall uninstall-am dirs.h: Makefile @echo_win_native () { \ location="$$1"; \ unix_path="$$2"; \ \ native_windows_path="`mkdir -p $$unix_path && cd $$unix_path && pwd -W`"; \ native_windows_path="`echo $$native_windows_path | sed -e 's|/|\\\\\\\\|g'`"; \ \ echo "#define $$location \"$$native_windows_path\"" >> $@; \ }; \ \ case "`uname`" in \ MINGW*) \ echo "// $@ generated by Makefile" > $@; \ echo_win_native "prefix" "$(prefix)"; \ echo_win_native "bindir" "$(bindir)"; \ echo_win_native "libdir" "$(libdir)"; \ echo_win_native "sysconfdir" "$(sysconfdir)"; \ echo_win_native "datadir" "$(datadir)"; \ echo_win_native "pkgdatadir" "$(pkgdatadir)"; \ echo_win_native "localstatedir" "$(localstatedir)"; \ ;; \ *) \ echo "// $@ generated by Makefile" > $@; \ echo '#define prefix "$(prefix)"' >> $@; \ echo '#define bindir "$(bindir)"' >> $@; \ echo '#define libdir "$(libdir)"' >> $@; \ echo '#define sysconfdir "$(sysconfdir)"' >> $@; \ echo '#define datadir "$(datadir)"' >> $@; \ echo '#define pkgdatadir "$(pkgdatadir)"' >> $@; \ echo '#define localstatedir "$(localstatedir)"' >> $@; \ ;; \ esac; # Build Debian package debian: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.tar.gz ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.tar.bz2 ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.tar.Z ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.shar.gz ;;\ *.zip*) \ unzip $(distdir).zip && \ cp $(DIST_ARCHIVES) $(PACKAGE)_$(VERSION).orig.zip ;;\ esac mkdir $(distdir)/debian cp -R $(srcdir)/debian/* $(distdir)/debian/ (cd $(distdir) && \ dpkg-buildpackage -us -uc -rfakeroot) debiancheck: @echo @echo "==== Begin lintian check ====" lintian $(PACKAGE)_$(VERSION)*.changes @echo "==== End lintian check ====" debianclean: rm -f *.deb rm -f $(PACKAGE)_$(VERSION)*.dsc rm -f $(PACKAGE)_$(VERSION)*.changes rm -f $(PACKAGE)_$(VERSION).orig.* rm -f $(PACKAGE)_$(VERSION)*.diff.* # 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: presage-0.8.8/apps/0000755000175000017500000000000011764714757011144 500000000000000presage-0.8.8/apps/python/0000755000175000017500000000000011764714760012457 500000000000000presage-0.8.8/apps/python/pyprompter.xpm0000644000175000017500000001007211737142176015342 00000000000000/* XPM */ static char * pyprompter_xpm[] = { "32 32 120 2", " c None", ". c #59739B", "+ c #59749B", "@ c #59739C", "# c #F7F7FA", "$ c #EBEEF3", "% c #F0F2F6", "& c #7C91B0", "* c #6F86A8", "= c #CED5E2", "- c #8094B3", "; c #59739A", "> c #E7EBF0", ", c #BBC5D6", "' c #59749C", ") c #FBFCFC", "! c #EAEEF2", "~ c #DEE3EB", "{ c #F9FAFB", "] c #788DAE", "^ c #A1B0C6", "/ c #90A2BC", "( c #637BA1", "_ c #7A8EAF", ": c #91A3BD", "< c #FFFFFF", "[ c #B5C0D3", "} c #B2BED1", "| c #B2BED0", "1 c #768CAD", "2 c #C6CFDD", "3 c #CBD3E0", "4 c #A6B4CA", "5 c #A8B5CB", "6 c #A9B6CB", "7 c #CDD5E0", "8 c #F2F4F8", "9 c #EDF0F4", "0 c #C4CEDC", "a c #EDEEF3", "b c #BDC8D7", "c c #BDC7D7", "d c #DCE1EA", "e c #C3CCDB", "f c #E2E6ED", "g c #F4F5F9", "h c #899CB7", "i c #7A8FAF", "j c #5F789F", "k c #6D83A7", "l c #7B8FB0", "m c #EBEEF4", "n c #E8ECF1", "o c #748AAB", "p c #5A6390", "q c #5C5E8C", "r c #47496D", "s c #52567E", "t c #566E95", "u c #6273A2", "v c #516289", "w c #5E6A97", "x c #555881", "y c #475677", "z c #646799", "A c #A09AEC", "B c #9793E1", "C c #9E98E9", "D c #48587A", "E c #565580", "F c #50567D", "G c #66689B", "H c #485779", "I c #67699D", "J c #3A4560", "K c #7F7ABB", "L c #535E86", "M c #7678B4", "N c #5E5D8D", "O c #9292DD", "P c #415471", "Q c #FDFDFE", "R c #8598B6", "S c #E7EBF1", "T c #6A6BA0", "U c #646294", "V c #8D87CF", "W c #5B638F", "X c #59628E", "Y c #9D98E8", "Z c #656195", "` c #646B9D", " . c #4B6082", ".. c #F7F9FA", "+. c #EEF0F5", "@. c #EEF1F6", "#. c #7288AA", "$. c #6E6DA5", "%. c #5E6593", "&. c #596690", "*. c #938DD9", "=. c #46476B", "-. c #736FAA", ";. c #A09AEB", ">. c #8A87CD", ",. c #5A5E89", "'. c #6477A6", "). c #7A75B4", "!. c #7470AC", "~. c #0F0D16", "{. c #4D4A73", "]. c #7773B0", "^. c #938ED9", "/. c #7975B3", "(. c #7571AD", "_. c #625F92", ":. c #716DA7", "<. c #7974B2", "[. c #4B4970", "}. c #847EC2", " ", " ", " ", " ", " ", " ", " . + . @ + ", " # $ $ $ $ $ $ $ $ $ % & . . . . . . . . ", " % * * * * * * * * * = - . . . . . . . . . ; ", " > . . . . . . . . . , - . . . . . . . . . . ' ", " > . . . . . . . . . , - . . . . . . . . . . . ", " ) % % % % % % ! ~ ~ { ] . . . . . . . . . . . + ", " ^ / / / ( . . . . . . _ / / / / : ", " < [ [ [ [ [ [ } | | < 1 . . . . . . 2 3 4 4 4 4 5 6 6 6 7 8 ", " 9 . . . . . . . . . 0 1 . . . . . . , - . . . . . . . . - a ", " 9 . . . . . . . . . 0 1 . . . . . . , - . . . . . . . . - a ", " < 0 0 0 0 0 0 b c c < 1 . . . . . . 2 d c c c c e 0 0 0 f g ", " h i i i j . . . . . . k i i i i l ", " < m m m m m m n ~ ~ < o p q r s t u v w x y . @ ", " 9 . . . . . . . . . 0 1 z A B C D E F G A H . ", " 9 . . . . . . . . . 0 1 I A J K L z M N O P ", " Q R R R R R R R R R S 1 T A U V W X Y Z ` . ", " ..+.+.+.+.+.+.+.+.+.@.#.$.A A A %.&.*.A =. ", " -.;.>.A ,.'.).A ", " !.A ~.{. ].^. ", " /.C (._. ", " :.<. ].[. ", " }. ", " ", " ", " ", " "}; presage-0.8.8/apps/python/pyprompter.10000644000175000017500000000222211763440602014666 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH PYPROMPTER "1" "June 2012" "pyprompter " "User Commands" .SH NAME pyprompter \- the intelligent predictive wxPython text editor .SH SYNOPSIS .B pyprompter [\fIoptions\fR] .SH OPTIONS .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit .TP \fB\-v\fR, \fB\-\-version\fR output version information and exit .PP Prompter is a simple predictive text editor, written to demonstrate the use of presage, the intelligent predictive text entry system. .PP Begin editing. While editing, prompter uses presage to generate predictions and displays them in a pop\-up prediction list. If the desired text is displayed in the prediction list, select it by double clicking on it or by highlighting it with the arrow keys and then pressing ENTER; the desired text will be automatically entered. .PP Direct your bug reports to: matteo.vescovi@yahoo.co.uk .PP pyprompter (presage) version 0.8.8 Copyright \(co 2004 Matteo Vescovi. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. presage-0.8.8/apps/python/pyprompter.desktop0000644000175000017500000000036411737142176016212 00000000000000[Desktop Entry] Name=pyprompter GenericName=Predictive text editor Comment=Predictive text editor powered by presage Exec=pyprompter Icon=pyprompter Terminal=false Type=Application StartupNotify=true Categories=GNOME;GTK;Utility;Accessibility; presage-0.8.8/apps/python/pyprompter.png0000644000175000017500000000336111737142176015325 00000000000000‰PNG  IHDR0$ÏE¹ sBIT|dˆ pHYsÐÐÞÖ®tEXtSoftwarewww.inkscape.org›î<tEXtTitlepyprompteríLò/tEXtAuthorMatteo Vescovi¿_‰¸IY›ÖŸxö—,Ù÷ùŸó?Ǿ>çž«H)©&ºº{ê¯ß6k•À 0 //G#áÔrõ)å­€º\G?ùÍóbb:ùиm˜è@x2 _tª«X–•Q¥Ö©ƒì?ô¢vqbÆãÀT¢‘°Y©±°¤T½ršþs#´¡¡ÎÏþ}÷ %N‚ð?¶tu÷|; §+1ÉlžxÂÙvÔŠ¿´á«Àë]Ý=Û¢‘ð¼]£eïý*ãËÀŸºº{»_´v?´KõZšW:R ÕùÙ•ÁÁ®îž#vþBUkÏ®öìêøoâÀ£ÀÁrD¡(J;l¥G~õ·š–l¹v=™ÎU¡ Ü‹(5[ˆ'RMw®¿.x€ãï `˜š-?~Ÿ‡¯mk/G[O¤~×ÜT?u3’"¥”Éô¼–/jeë¡eIaZò?º¬[¨47Õóã_þ•K³ÙòÑ«jùíþ½Ä)tú!OUCU•%ãòyÝjC]À-þøâIÏi‡¬¹©žÈc{Ù>uøx¹þ#®¼®ÃWÚ[xäþ»¿e´"ü?ÿ5À¶Žllirä à÷:¿ç®vróEG¶kë–%û·lZçÞº²F…¢LÌfo»v}x4QÑ¡N7L†Gܺ¶á¦¼U¡Ú˜¯ÆsÃÒfYRW*™Èºº{B¶œ# ¬ŠFÂúÍHŠiZg Ó²3AÊ̯Íõºk×Ýó*ÉÌõ§àÌì$^_-^_ЮÄŽD#áï–# UUîxïìˆãy 6PÃέ›ÂÀЩ×›°Lƒ‹#°cû÷˜‹‘«7ÜN~.EffhjÙÄÀ‰—hlX‡iênÙÜ ¥qóvôÀ»ÄXN#Û¹uóâç ¯žï|ëçhz»€çžÿÙä4‰Ï°kǃ¼õ¯^r¡Yîl»‹ÛïàÙ¿<¼àæ™h${Mm[ùÑC‡?'§&>}âT¤·¿R}<ðyÁç$ü,)E!_Ìç„‚·,¬ ¸Ês»¼„V·p~è6µmå¶ÖNúúÿ>:rá̳N´ð´óÐKP…§ßK`Åʾî;tXrPv¹.·'É^2Å6ŸŒI)í ×j; yiÌggýAÈ `~ôãóÏS‰±S@(—¾Ü·°–Ë%I¦â§jV5úº5k|¾.€b1Ç‘ç{÷ϽÇò…,ñ~->9x, Ë¢6¿Ø²OÎO uª¹ä´ã~ÿŠf_MéšµP˜Ãï¯{áøë¿?6ëÛ¯ëÚôD|à)€b!WX°9?ðæ„®Ï8Õ¬j.— w©âä Yòù쌔røÁçyš–Ÿ·,Uu1›ŒI)ßOVu )Šê®+ ä³2IL.Ån¯OU]˜–A:“[ŽfUEQ¼ÃúÍd2ž|»¨ë…ËKñ‚†ÀôôòùLßR»¨j—.~¦gß+…bî3`b©­¡(Šçî¶ŒŸ››šŽ\ŽfUÈåRŸŸ”¡ùGFÏ~Ø{ô kj:æ—£ùo½`EôöÜ(âIEND®B`‚presage-0.8.8/apps/python/pypresagemate.in0000644000175000017500000000650611737142176015600 00000000000000#!/usr/bin/python ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # Copyright (C) 2009 John Hills # Copyright (C) 2009 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import getopt import os PROGRAM_NAME = 'pypresagemate' def print_version(): print """ %s (%s) version %s Copyright (C) 2010 Matteo Vescovi. Copyright (C) 2010 John Hills. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. """ % (PROGRAM_NAME, '@PACKAGE_NAME@', '@PACKAGE_VERSION@') def print_usage(): print """ Usage: %s [options] Options: -h, --help display this help and exit -v, --version output version information and exit Pypresagemate is a universal predictive text companion. Pypresagemate works alongside any AT-SPI aware application. The Assistive Technology Service Provider Interface (AT-SPI) is a toolkit-neutral way of providing accessibility facilities in applications. Pypresagemate works in the background by tracking what keystrokes are typed and displaying predictions in its window. When a prediction is selected, text is sent to the active application. Direct your bug reports to: %s """ % (PROGRAM_NAME, '@PACKAGE_BUGREPORT@') def parse_cmd_line_args(): short_options = "hv" long_options = ["help", "version"] try: opts, args = getopt.getopt(sys.argv[1:], short_options, long_options) except getopt.GetoptError, err: print str(err) sys.exit(1) for opt, arg in opts: if opt in ('-v', '--version'): print_version() sys.exit() elif opt in ('-h', '--help'): print_usage() sys.exit() if __name__ == "__main__": parse_cmd_line_args() try: import presagemate.presagemate except ImportError, e: print ''' Error: failed to import module presagemate. Check that prompter is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). ''' print e else: if not config: # try to locate presage.xml config file scriptdir = os.path.dirname(sys.argv[0]) # in scriptdir/etc conffile = os.path.join(scriptdir, 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile else: # in scriptdir/../etc conffile = os.path.join(scriptdir, '..', 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile print 'Configuration file: ' + str(config) presage-0.8.8/apps/python/Makefile.am0000644000175000017500000000631011737142176014427 00000000000000 ########### # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if HAVE_SWIG if HAVE_PYTHON if ENABLE_PYTHON_BINDING # pypresagemate uses autotools dist_bin_SCRIPTS = \ pypresagemate presagematedir = $(pythondir)/presagemate presagemate_PYTHON = \ presagemate/__init__.py \ presagemate/presagemate.py # pyprompter delegates to setup.py EXTRA_DIST = pyprompter \ prompter/__init__.py \ prompter/prompter.py all-local: $(EXTRA_DIST) @case "`uname`" in \ MINGW*) \ $(PYTHON) setup.py build --compiler=mingw32 \ ;; \ *) \ $(PYTHON) setup.py build \ ;; \ esac; # python on MinGW/MSYS requires pure Windows style paths # Using following (cd $dir && pwd -W) hack to get a nearly # native Windows path, then translating the forward slash # to a backward slash to make python distutils jolly. # P.S. the backslash has to be escaped thrice, hence a single # backslash turns into a sequence of eight (neat, huh?) # install-exec-local: @case "`uname`" in \ MINGW*) \ NATIVE_WINDOWS_PREFIX="`cd $(DESTDIR)$(prefix) && pwd -W`"; \ NATIVE_WINDOWS_PREFIX="`echo $$NATIVE_WINDOWS_PREFIX | sed -e 's|/|\\\\\\\\|g'`"; \ $(PYTHON) setup.py install --prefix="$$NATIVE_WINDOWS_PREFIX" \ ;; \ *) \ $(PYTHON) setup.py install --prefix=$(DESTDIR)$(prefix) \ ;; \ esac; # This rule cleans up stuff installed by Python's setup.py # Unfortunately, Python's distutils do not provide an uninstall # command, so we have to make up for it here in uninstall-local # hook. This might break if distutils' behaviour changes as automake # has no control over what distutils install command does. # uninstall-local: rm -rf $(DESTDIR)$(libdir)/python*/site-packages/prompter rm -f $(DESTDIR)$(libdir)/python*/site-packages/pyprompter-*.egg-info rm -f $(DESTDIR)$(bindir)/pyprompter clean-local: rm -rf build if HAVE_HELP2MAN pyprompter.1: pyprompter.in $(top_srcdir)/configure.ac chmod u+x ./pyprompter help2man --output=$@ --no-info --name="the intelligent predictive wxPython text editor" ./pyprompter dist_man_MANS = pyprompter.1 DISTCLEANFILES= pyprompter.1 endif desktopdir = $(datadir)/applications dist_desktop_DATA = pyprompter.desktop svgicondir = $(datadir)/icons/hicolor/scalable/apps dist_svgicon_DATA = pyprompter.svg pixmapsdir = $(datadir)/pixmaps dist_pixmaps_DATA = pyprompter.png pyprompter.xpm endif endif endif presage-0.8.8/apps/python/pyprompter.svg0000644000175000017500000001207311737142176015340 00000000000000 pyprompter image/svg+xml pyprompter Matteo Vescovi prompter, the intelligent predictive text editor pyprompter presage predictive text entry py presage-0.8.8/apps/python/pyprompter0000644000175000017500000000711511764437313014543 00000000000000#!/usr/bin/python ########## # Presage, an extensible predictive text entry system # --------------------------------------------------- # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import getopt import os PROGRAM_NAME = 'pyprompter' config = None suggestions = None def print_version(): print """ %s (%s) version %s Copyright (C) 2004 Matteo Vescovi. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. """ % (PROGRAM_NAME, 'presage', '0.8.8') def print_usage(): print """ Usage: %s [options] Options: -h, --help display this help and exit -v, --version output version information and exit Prompter is a simple predictive text editor, written to demonstrate the use of presage, the intelligent predictive text entry system. Begin editing. While editing, prompter uses presage to generate predictions and displays them in a pop-up prediction list. If the desired text is displayed in the prediction list, select it by double clicking on it or by highlighting it with the arrow keys and then pressing ENTER; the desired text will be automatically entered. Direct your bug reports to: %s """ % (PROGRAM_NAME, 'matteo.vescovi@yahoo.co.uk') def parse_cmd_line_args(): short_options = "c:s:hv" long_options = ["config=", "suggestions=", "help", "version"] try: opts, args = getopt.getopt(sys.argv[1:], short_options, long_options) except getopt.GetoptError, err: print str(err) sys.exit(1) for opt, arg in opts: if opt in ('-v', '--version'): print_version() sys.exit() elif opt in ('-h', '--help'): print_usage() sys.exit() elif opt in ('-c', '--config'): global config config = arg elif opt in ('-s', '--suggestions'): global suggestions suggestions = arg if __name__ == "__main__": parse_cmd_line_args() try: import prompter.prompter except ImportError, e: print ''' Error: failed to import module prompter. Check that prompter is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). ''' print e else: if not config: # try to locate presage.xml config file scriptdir = os.path.dirname(sys.argv[0]) # in scriptdir/etc conffile = os.path.join(scriptdir, 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile else: # in scriptdir/../etc conffile = os.path.join(scriptdir, '..', 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile print 'Configuration file: ' + str(config) app = prompter.prompter.Prompter("0.8.8", config, suggestions) app.MainLoop() presage-0.8.8/apps/python/pyprompter.in0000644000175000017500000000714511737142176015153 00000000000000#!/usr/bin/python ########## # Presage, an extensible predictive text entry system # --------------------------------------------------- # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import getopt import os PROGRAM_NAME = 'pyprompter' config = None suggestions = None def print_version(): print """ %s (%s) version %s Copyright (C) 2004 Matteo Vescovi. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. """ % (PROGRAM_NAME, '@PACKAGE_NAME@', '@PACKAGE_VERSION@') def print_usage(): print """ Usage: %s [options] Options: -h, --help display this help and exit -v, --version output version information and exit Prompter is a simple predictive text editor, written to demonstrate the use of presage, the intelligent predictive text entry system. Begin editing. While editing, prompter uses presage to generate predictions and displays them in a pop-up prediction list. If the desired text is displayed in the prediction list, select it by double clicking on it or by highlighting it with the arrow keys and then pressing ENTER; the desired text will be automatically entered. Direct your bug reports to: %s """ % (PROGRAM_NAME, '@PACKAGE_BUGREPORT@') def parse_cmd_line_args(): short_options = "c:s:hv" long_options = ["config=", "suggestions=", "help", "version"] try: opts, args = getopt.getopt(sys.argv[1:], short_options, long_options) except getopt.GetoptError, err: print str(err) sys.exit(1) for opt, arg in opts: if opt in ('-v', '--version'): print_version() sys.exit() elif opt in ('-h', '--help'): print_usage() sys.exit() elif opt in ('-c', '--config'): global config config = arg elif opt in ('-s', '--suggestions'): global suggestions suggestions = arg if __name__ == "__main__": parse_cmd_line_args() try: import prompter.prompter except ImportError, e: print ''' Error: failed to import module prompter. Check that prompter is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). ''' print e else: if not config: # try to locate presage.xml config file scriptdir = os.path.dirname(sys.argv[0]) # in scriptdir/etc conffile = os.path.join(scriptdir, 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile else: # in scriptdir/../etc conffile = os.path.join(scriptdir, '..', 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile print 'Configuration file: ' + str(config) app = prompter.prompter.Prompter("@PACKAGE_VERSION@", config, suggestions) app.MainLoop() presage-0.8.8/apps/python/Makefile.in0000644000175000017500000006702011763440354014443 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########### # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = apps/python DIST_COMMON = $(am__dist_bin_SCRIPTS_DIST) \ $(am__dist_desktop_DATA_DIST) $(am__dist_pixmaps_DATA_DIST) \ $(am__dist_svgicon_DATA_DIST) $(am__presagemate_PYTHON_DIST) \ $(dist_man_MANS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/pypresagemate.in $(srcdir)/pyprompter.in \ $(srcdir)/setup.py.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = pyprompter pypresagemate setup.py CONFIG_CLEAN_VPATH_FILES = am__dist_bin_SCRIPTS_DIST = pypresagemate am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(presagematedir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(desktopdir)" \ "$(DESTDIR)$(pixmapsdir)" "$(DESTDIR)$(svgicondir)" SCRIPTS = $(dist_bin_SCRIPTS) SOURCES = DIST_SOURCES = am__presagemate_PYTHON_DIST = presagemate/__init__.py \ presagemate/presagemate.py py_compile = $(top_srcdir)/py-compile man1dir = $(mandir)/man1 NROFF = nroff MANS = $(dist_man_MANS) am__dist_desktop_DATA_DIST = pyprompter.desktop am__dist_pixmaps_DATA_DIST = pyprompter.png pyprompter.xpm am__dist_svgicon_DATA_DIST = pyprompter.svg DATA = $(dist_desktop_DATA) $(dist_pixmaps_DATA) $(dist_svgicon_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # pypresagemate uses autotools @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@dist_bin_SCRIPTS = \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ pypresagemate @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@presagematedir = $(pythondir)/presagemate @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@presagemate_PYTHON = \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ presagemate/__init__.py \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ presagemate/presagemate.py # pyprompter delegates to setup.py @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@EXTRA_DIST = pyprompter \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ prompter/__init__.py \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ prompter/prompter.py @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@dist_man_MANS = pyprompter.1 @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@DISTCLEANFILES = pyprompter.1 @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@desktopdir = $(datadir)/applications @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@dist_desktop_DATA = pyprompter.desktop @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@svgicondir = $(datadir)/icons/hicolor/scalable/apps @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@dist_svgicon_DATA = pyprompter.svg @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@pixmapsdir = $(datadir)/pixmaps @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@dist_pixmaps_DATA = pyprompter.png pyprompter.xpm all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu apps/python/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu apps/python/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): pyprompter: $(top_builddir)/config.status $(srcdir)/pyprompter.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ pypresagemate: $(top_builddir)/config.status $(srcdir)/pypresagemate.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ setup.py: $(top_builddir)/config.status $(srcdir)/setup.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-presagematePYTHON: $(presagemate_PYTHON) @$(NORMAL_INSTALL) test -z "$(presagematedir)" || $(MKDIR_P) "$(DESTDIR)$(presagematedir)" @list='$(presagemate_PYTHON)'; dlist=; list2=; test -n "$(presagematedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ if test -f $$b$$p; then \ $(am__strip_dir) \ dlist="$$dlist $$f"; \ list2="$$list2 $$b$$p"; \ else :; fi; \ done; \ for file in $$list2; do echo $$file; done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(presagematedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(presagematedir)" || exit $$?; \ done || exit $$?; \ if test -n "$$dlist"; then \ if test -z "$(DESTDIR)"; then \ PYTHON=$(PYTHON) $(py_compile) --basedir "$(presagematedir)" $$dlist; \ else \ PYTHON=$(PYTHON) $(py_compile) --destdir "$(DESTDIR)" --basedir "$(presagematedir)" $$dlist; \ fi; \ else :; fi uninstall-presagematePYTHON: @$(NORMAL_UNINSTALL) @list='$(presagemate_PYTHON)'; test -n "$(presagematedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ filesc=`echo "$$files" | sed 's|$$|c|'`; \ fileso=`echo "$$files" | sed 's|$$|o|'`; \ echo " ( cd '$(DESTDIR)$(presagematedir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(presagematedir)" && rm -f $$files || exit $$?; \ echo " ( cd '$(DESTDIR)$(presagematedir)' && rm -f" $$filesc ")"; \ cd "$(DESTDIR)$(presagematedir)" && rm -f $$filesc || exit $$?; \ echo " ( cd '$(DESTDIR)$(presagematedir)' && rm -f" $$fileso ")"; \ cd "$(DESTDIR)$(presagematedir)" && rm -f $$fileso install-man1: $(dist_man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @list=''; test -n "$(man1dir)" || exit 0; \ { for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ test -z "$$files" || { \ echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } install-dist_desktopDATA: $(dist_desktop_DATA) @$(NORMAL_INSTALL) test -z "$(desktopdir)" || $(MKDIR_P) "$(DESTDIR)$(desktopdir)" @list='$(dist_desktop_DATA)'; test -n "$(desktopdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(desktopdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(desktopdir)" || exit $$?; \ done uninstall-dist_desktopDATA: @$(NORMAL_UNINSTALL) @list='$(dist_desktop_DATA)'; test -n "$(desktopdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(desktopdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(desktopdir)" && rm -f $$files install-dist_pixmapsDATA: $(dist_pixmaps_DATA) @$(NORMAL_INSTALL) test -z "$(pixmapsdir)" || $(MKDIR_P) "$(DESTDIR)$(pixmapsdir)" @list='$(dist_pixmaps_DATA)'; test -n "$(pixmapsdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pixmapsdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pixmapsdir)" || exit $$?; \ done uninstall-dist_pixmapsDATA: @$(NORMAL_UNINSTALL) @list='$(dist_pixmaps_DATA)'; test -n "$(pixmapsdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pixmapsdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pixmapsdir)" && rm -f $$files install-dist_svgiconDATA: $(dist_svgicon_DATA) @$(NORMAL_INSTALL) test -z "$(svgicondir)" || $(MKDIR_P) "$(DESTDIR)$(svgicondir)" @list='$(dist_svgicon_DATA)'; test -n "$(svgicondir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(svgicondir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(svgicondir)" || exit $$?; \ done uninstall-dist_svgiconDATA: @$(NORMAL_UNINSTALL) @list='$(dist_svgicon_DATA)'; test -n "$(svgicondir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(svgicondir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(svgicondir)" && rm -f $$files tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am @ENABLE_PYTHON_BINDING_FALSE@all-local: @HAVE_PYTHON_FALSE@all-local: @HAVE_SWIG_FALSE@all-local: all-am: Makefile $(SCRIPTS) $(MANS) $(DATA) all-local installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(presagematedir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(pixmapsdir)" "$(DESTDIR)$(svgicondir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @ENABLE_PYTHON_BINDING_FALSE@uninstall-local: @HAVE_PYTHON_FALSE@uninstall-local: @HAVE_SWIG_FALSE@uninstall-local: @ENABLE_PYTHON_BINDING_FALSE@install-exec-local: @HAVE_PYTHON_FALSE@install-exec-local: @HAVE_SWIG_FALSE@install-exec-local: @ENABLE_PYTHON_BINDING_FALSE@clean-local: @HAVE_PYTHON_FALSE@clean-local: @HAVE_SWIG_FALSE@clean-local: clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_desktopDATA install-dist_pixmapsDATA \ install-dist_svgiconDATA install-man install-presagematePYTHON install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-dist_binSCRIPTS install-exec-local install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_binSCRIPTS uninstall-dist_desktopDATA \ uninstall-dist_pixmapsDATA uninstall-dist_svgiconDATA \ uninstall-local uninstall-man uninstall-presagematePYTHON uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool clean-local distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_binSCRIPTS install-dist_desktopDATA \ install-dist_pixmapsDATA install-dist_svgiconDATA install-dvi \ install-dvi-am install-exec install-exec-am install-exec-local \ install-html install-html-am install-info install-info-am \ install-man install-man1 install-pdf install-pdf-am \ install-presagematePYTHON install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ uninstall uninstall-am uninstall-dist_binSCRIPTS \ uninstall-dist_desktopDATA uninstall-dist_pixmapsDATA \ uninstall-dist_svgiconDATA uninstall-local uninstall-man \ uninstall-man1 uninstall-presagematePYTHON @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@all-local: $(EXTRA_DIST) @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ @case "`uname`" in \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ MINGW*) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(PYTHON) setup.py build --compiler=mingw32 \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ *) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(PYTHON) setup.py build \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ esac; # python on MinGW/MSYS requires pure Windows style paths # Using following (cd $dir && pwd -W) hack to get a nearly # native Windows path, then translating the forward slash # to a backward slash to make python distutils jolly. # P.S. the backslash has to be escaped thrice, hence a single # backslash turns into a sequence of eight (neat, huh?) # @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@install-exec-local: @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ @case "`uname`" in \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ MINGW*) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ NATIVE_WINDOWS_PREFIX="`cd $(DESTDIR)$(prefix) && pwd -W`"; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ NATIVE_WINDOWS_PREFIX="`echo $$NATIVE_WINDOWS_PREFIX | sed -e 's|/|\\\\\\\\|g'`"; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(PYTHON) setup.py install --prefix="$$NATIVE_WINDOWS_PREFIX" \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ *) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ $(PYTHON) setup.py install --prefix=$(DESTDIR)$(prefix) \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ ;; \ @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ esac; # This rule cleans up stuff installed by Python's setup.py # Unfortunately, Python's distutils do not provide an uninstall # command, so we have to make up for it here in uninstall-local # hook. This might break if distutils' behaviour changes as automake # has no control over what distutils install command does. # @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@uninstall-local: @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -rf $(DESTDIR)$(libdir)/python*/site-packages/prompter @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -f $(DESTDIR)$(libdir)/python*/site-packages/pyprompter-*.egg-info @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -f $(DESTDIR)$(bindir)/pyprompter @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@clean-local: @ENABLE_PYTHON_BINDING_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ rm -rf build @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@pyprompter.1: pyprompter.in $(top_srcdir)/configure.ac @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ chmod u+x ./pyprompter @ENABLE_PYTHON_BINDING_TRUE@@HAVE_HELP2MAN_TRUE@@HAVE_PYTHON_TRUE@@HAVE_SWIG_TRUE@ help2man --output=$@ --no-info --name="the intelligent predictive wxPython text editor" ./pyprompter # 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: presage-0.8.8/apps/python/presagemate/0000755000175000017500000000000011764714760014754 500000000000000presage-0.8.8/apps/python/presagemate/presagemate.py0000644000175000017500000003340611737142176017545 00000000000000#!/usr/bin/python ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # Copyright (C) 2009 John Hills # Copyright (C) 2009 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import string try: import presage except ImportError, ex: print ''' Error: failed to import module presage. Check that presage python binding is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). Check that presage library is properly installed (if installed in a non-standard location, please set LD_LIBRARY_PATH (PATH, LIBPATH) accordingly). ''' try: import pyatspi except ImportError, ex: print ''' Error: failed to import module pyatspi. Check that pyatspi python binding is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). Check that pyatspi library is properly installed (if installed in a non-standard location, please set LD_LIBRARY_PATH (PATH, LIBPATH) accordingly). ''' try: import gtk except ImportError, ex: print ''' Error: failed to import module gtk. Check that gtk python binding is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). Check that gtk library is properly installed (if installed in a non-standard location, please set LD_LIBRARY_PATH (PATH, LIBPATH) accordingly). ''' import ConfigParser import os import pango import atexit import Xlib import Xlib.display def process_event(event): global char_index global prediction global ignore_keys #print "event_string: " + event.event_string if (event.type == pyatspi.KEY_PRESS) & (event.is_text == True): if (len(event.event_string) == 1) & (event.event_string.isalpha() == True): if ignore_keys == 0: char_index += 1 callback.buffer += event.event_string prediction = prsg.predict() else: ignore_keys -= 1 elif event.event_string.lower() == "space": char_index = 0 if ignore_keys == 0: callback.buffer += ' ' prediction = prsg.predict() else: ignore_keys -= 1 elif event.event_string.lower() == "backspace": char_index = 0 if ignore_keys == 0: callback.buffer = callback.buffer[:-1] # cut out the last character prediction = prsg.predict() else: ignore_keys -= 1 elif event.event_string.lower() == "return": char_index = 0 if ignore_keys == 0: callback.buffer = '\n' prediction = prsg.predict() else: ignore_keys -= 1 elif event.event_string[0] == "F": # -25 is the function key offset, I use F25-34 remapped to the F1-10 keys f_key = int(event.event_string[1:]) - 25 if (f_key >= 0) & (len(prediction) > f_key): predicted_word = prediction[f_key] if predicted_word == "i": predicted_word = predicted_word.upper() completion = prsg.completion(predicted_word) print 'Prediction: ' + predicted_word print 'Completion: ' + completion for ch in completion: keyval = gtk.gdk.unicode_to_keyval(ord(ch)) reg.generateKeyboardEvent(keyval, None, pyatspi.KEY_SYM) callback.buffer += completion prediction = prsg.predict() # theres no way to consume keypresses so we ignore the keypress we have added ignore_keys = len(completion) char_index = 0 if ignore_keys == 0: update_gui(prediction) def update_gui(prediction): prediction_string = str() for index, word in enumerate(prediction): if word == "i": word = word.upper() pred = 'F' + str(index + 1) + ' ', word + '\n' prediction_string += ''.join(pred) "Set label text omitting the last \n" label.set_text(prediction_string[0:(len(prediction_string) - 1)]) def quit_app(widget): remap_keys(False) position = window.get_position() set_position_config(position[0], position[1]) gtk.main_quit() exit() return gtk.FALSE def delete_event(widget, event, data=None): quit_app(widget) def frame_event(window, event, data=None): state = event.new_window_state if state & gtk.gdk.WINDOW_STATE_ICONIFIED: # re-map F1-10 to F1-10 when the window is iconified remap_keys(False) else: # re-map F1-10 to F25-34 when the window is uniconified remap_keys(True) def get_config(): writeconfig_flag = False config = ConfigParser.SafeConfigParser() config.read(os.path.expanduser('~/.pypresagematerc')) if config.has_section('Config') == False: config.add_section('Config') try: pangofont = config.get('Config', 'pangofont') except: config.set('Config', 'pangofont', 'monospace 14') writeconfig_flag = True try: window_position_x = config.getint('Config', 'window_position_x') except: config.set('Config', 'window_position_x', '0') writeconfig_flag = True try: window_position_y = config.getint('Config', 'window_position_y') except: config.set('Config', 'window_position_y', '0') writeconfig_flag = True if writeconfig_flag == True: configfile = open(os.path.expanduser('~/.pypresagematerc'), 'wb') try: config.write(configfile) finally: configfile.close() return config def set_position_config(x, y): config = ConfigParser.SafeConfigParser() config.read(os.path.expanduser('~/.pypresagematerc')) config.set('Config', 'window_position_x', str(x)) config.set('Config', 'window_position_y', str(y)) configfile = open(os.path.expanduser('~/.pypresagematerc'), 'wb') try: config.write(configfile) finally: configfile.close() def remap_keys(remap): """ Remap keycode -> keysym for function keys The keycode -> keysym mapping is so that the keycode generated when the F1 key is pressed sends the F25 keysym. But to do that you need to know the keycodes for F1-10, for Linux on x86 the keycode for F1 is 67 but for other platforms it could be different. So the code looks up the keycode mapped to F1 keysym if that is non zero (i.e. F1 is mapped) I map that keycode to F1 or F25 as required, if F1 is not mapped I lookup the keycode for F25 and if that is non zero I map that keycode to F1 or F25 as required. If F1 and F25 are not mapped to any keycode I use 67 as the keycode for the F1 key. The code assumes that the keycodes for F1-10 are sequential which may not be true for all platforms. A more robust solution may be found by accessing the keyboard layout somehow but I haven't had time to look yet. """ display = Xlib.display.Display() # only keycodes 8 to 255 are defined first_keycode = 8 keymaps_orig = display.get_keyboard_mapping(first_keycode, 255 - first_keycode) keymaps = list(keymaps_orig) if remap == True: keysym = 65494 else: keysym = 65470 keycode_F1 = display.keysym_to_keycode(65470) keycode_F25 = display.keysym_to_keycode(65494) # set first_fkeycode to a sensible default incase F1 and F25 are not mapped first_fkeycode = 67 if keycode_F1 > 0: first_fkeycode = keycode_F1 elif keycode_F25 > 0: first_fkeycode = keycode_F25 for i in range(0, int(number_of_suggestions)): keymaps[(i + first_fkeycode - first_keycode)][0] = keysym + i keymaps[(i + first_fkeycode - first_keycode)][2] = keysym + i keymaps[(i + first_fkeycode - first_keycode)][4] = keysym + i display.change_keyboard_mapping(first_keycode, keymaps, onerror = None) display.sync() display.close() def popup_menu(widget, event): if event.button == 3: menu.popup(None, None, None, event.button, event.time) return True return False def apply_preferences(widget): print "apply" def close_preferences(widget): print "close" def update_no_selections(widget): global number_of_suggestions number_of_suggestions = int(widget.get_value()) prsg.config("Presage.Selector.SUGGESTIONS", str(number_of_suggestions)) remap_keys(True) def preferences(widget): preferences = gtk.Window(gtk.WINDOW_TOPLEVEL) preferences.set_title("pypresagemate preferences") preferences.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) preferences_box = gtk.VBox() notebook = gtk.Notebook() notebook.set_tab_pos(gtk.POS_TOP) appearance_frame = gtk.Frame() appearance_tab = gtk.Label("Appearance") notebook.append_page(appearance_frame, appearance_tab) appearance_placeholder = gtk.Label("\n\nconfiguration\nplaceholder\n\n") appearance_frame.add(appearance_placeholder) presage_frame = gtk.Frame() presage_tab = gtk.Label("Presage") notebook.append_page(presage_frame, presage_tab) presage_placeholder = gtk.Label("\n\nPresage library configuration\n\n") adj = gtk.Adjustment(float(number_of_suggestions), 3, 10, 1, 0, 0) no_of_selections = gtk.SpinButton(adj, 0, 0) no_of_selections.connect("output", update_no_selections) presage_frame.add(no_of_selections) preferences_box.add(notebook) preferences_buttons = gtk.HButtonBox() apply_button = gtk.Button("Apply") apply_button.connect("clicked", apply_preferences) close_button = gtk.Button("Close") close_button.connect("clicked", close_preferences) preferences_buttons.add(apply_button) preferences_buttons.add(close_button) preferences_box.add(preferences_buttons) preferences.add(preferences_box) preferences.show_all() def about(widget): comments = '''pypresagemate is a universal predictive text companion. pypresagemate is powered by presage, an intelligent predictive text entry system. ''' license = '''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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ''' about = gtk.AboutDialog() about.set_program_name('pypresagemate') about.set_version("0.1") about.set_copyright("(c) Matteo Vescovi\n(c) John Hills") about.set_website("http://presage.sourceforge.net/") about.set_comments(comments) if os.path.isfile("/usr/local/share/presage/presage.png"): about.set_logo(gtk.gdk.pixbuf_new_from_file("/usr/local/share/presage/presage.png")) about.run() about.destroy() config = get_config() pangofont = config.get('Config', 'pangofont') window_position_x = config.getint('Config', 'window_position_x') window_position_y = config.getint('Config', 'window_position_y') ignore_keys = 0 char_index = 0 reg = pyatspi.Registry # Define and create PresageCallback object class SimpleCallback(presage.PresageCallback): def __init__(self): presage.PresageCallback.__init__(self) self.buffer = '' def get_past_stream(self): return self.buffer def get_future_stream(self): return '' # Presage owns callback, so we create it and disown it callback = SimpleCallback().__disown__() prsg = presage.Presage(callback) number_of_suggestions = prsg.config("Presage.Selector.SUGGESTIONS") "limit suggestions to 10 as that should be enough for anybody :-)" if int(number_of_suggestions) > int(10): number_of_suggestions = 10 prsg.config("Presage.Selector.SUGGESTIONS", "10") prediction = prsg.predict() reg.registerKeystrokeListener(process_event, mask=pyatspi.allModifiers()) window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.connect("delete-event", delete_event) window.connect("window-state-event", frame_event) window.set_keep_above(True) #window.set_decorated(False) window.move(window_position_x, window_position_y) window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#c0c0ff")) label = gtk.Label("pypresagemate") label.set_justify(gtk.JUSTIFY_LEFT) label.set_width_chars(20) font_desc = pango.FontDescription(pangofont) label.modify_font(font_desc) window.connect("button-press-event", popup_menu) window.add_events(gtk.gdk.BUTTON_PRESS_MASK) menu = gtk.Menu() menu_item1 = gtk.MenuItem('About') menu_item2 = gtk.MenuItem('Preferences') menu_item3 = gtk.MenuItem('Quit') menu.append(menu_item1) menu.append(menu_item2) menu.append(menu_item3) menu_item1.connect("activate", about) menu_item2.connect("activate", preferences) menu_item3.connect("activate", quit_app) menu.show_all() update_gui(prediction) window.add(label) window.show_all() # remap keys if program closes other than by closing gtk atexit.register(remap_keys, False) gtk.main() reg.start() presage-0.8.8/apps/python/presagemate/__init__.py0000644000175000017500000000161711737142176017006 00000000000000########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. presage-0.8.8/apps/python/prompter/0000755000175000017500000000000011764714760014327 500000000000000presage-0.8.8/apps/python/prompter/prompter.py0000644000175000017500000006442311763437013016472 00000000000000########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys try: import wx import wx.stc except ImportError, ex: print ''' Error: failed to import module wxPython. wxPython is a Python binding for the wxWidgets toolkit. Check that wxPython is properly installed. ''' print ex sys.exit(1) try: import presage except ImportError, ex: print ''' Error: failed to import module presage. Check that presage python binding is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). Check that presage library is properly installed (if installed in a non-standard location, please set LD_LIBRARY_PATH (PATH, LIBPATH) accordingly). ''' print ex sys.exit(1) ########## # Prompter # class Prompter(wx.App): def __init__(self, version, config=None, suggestions=None, redirect=False): self.version = version # do this first, wx.App.__init__() calls OnInit() self.config = config self.suggestions = suggestions wx.App.__init__(self, redirect) def OnInit(self): self.frame = PrompterFrame(parent=None, id=-1, title='pyprompter', version=self.version, config=self.config, suggestions=self.suggestions) self.SetTopWindow(self.frame) return True ############### # PrompterFrame # class PrompterFrame(wx.Frame): wildcard = "Text files (*.txt)|*.txt|" \ "All files (*.*)|*.*" def __init__(self, parent, id, title, version, config, suggestions): wx.Frame.__init__(self, parent, id, title) self.version = version self.editor = PrompterEditor(self, config, suggestions) self.MakeMenuBar() self.MakeToolBar() self.sizer = wx.BoxSizer(wx.HORIZONTAL) self.sizer.Add(self.editor, 1, wx.EXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(True) self.Show() def MakeMenuBar(self): def BindMenu(item, handler): self.Bind(wx.EVT_MENU, handler, item) # file menu self.fileMenu = wx.Menu() BindMenu(self.fileMenu.Append(wx.ID_NEW, "&New\tCTRL+N"), self.OnFileMenuNew) BindMenu(self.fileMenu.Append(wx.ID_OPEN, "&Open\tCTRL+O"), self.OnFileMenuOpen) self.fileMenu.AppendSeparator() BindMenu(self.fileMenu.Append(wx.ID_SAVE, "&Save\tCTRL+S"), self.OnFileMenuSave) BindMenu(self.fileMenu.Append(wx.ID_SAVEAS, "Save &As\tSHIFT+CTRL+S"), self.OnFileMenuSaveAs) self.fileMenu.AppendSeparator() BindMenu(self.fileMenu.Append(wx.ID_CLOSE, "&Close\tCTRL+W"), self.OnFileMenuClose) BindMenu(self.fileMenu.Append(wx.ID_EXIT, "&Quit\tCTRL+Q"), self.OnFileMenuQuit) # edit menu self.editMenu = wx.Menu() BindMenu(self.editMenu.Append(wx.ID_UNDO, "&Undo\tCTRL+Z"), self.OnEditMenuUndo) BindMenu(self.editMenu.Append(wx.ID_REDO, "&Redo\tSHIFT+CTRL+Z"), self.OnEditMenuRedo) self.editMenu.AppendSeparator() BindMenu(self.editMenu.Append(wx.ID_CUT, "Cu&t\tCTRL+X"), self.OnEditMenuCut) BindMenu(self.editMenu.Append(wx.ID_COPY, "&Copy\tCTRL+C"), self.OnEditMenuCopy) BindMenu(self.editMenu.Append(wx.ID_PASTE, "&Paste\tCTRL+V"), self.OnEditMenuPaste) self.editMenu.AppendSeparator() BindMenu(self.editMenu.Append(wx.ID_SELECTALL, "Select &All\tCTRL+A"), self.OnEditMenuSelectAll) # view menu self.viewMenu = wx.Menu() self.ID_TOGGLE_WORD_WRAP = wx.NewId() # need to save wxMenuItem object returned by Append() to test if checked or not self.word_wrap = self.viewMenu.Append(self.ID_TOGGLE_WORD_WRAP, "&Word wrap", "Toggle word wrap mode", wx.ITEM_CHECK) BindMenu(self.word_wrap, self.OnViewMenuWordWrap) # turn text_wrap checked menu item on at start-up self.viewMenu.Check(self.ID_TOGGLE_WORD_WRAP, True) self.viewMenu.AppendSeparator() BindMenu(self.viewMenu.Append(wx.ID_ZOOM_IN, "L&arger text\tCTRL++"), self.OnViewMenuLargerText) BindMenu(self.viewMenu.Append(wx.ID_ZOOM_OUT, "S&maller text\tCTRL+-"), self.OnViewMenuSmallerText) self.viewMenu.AppendSeparator() self.ID_SHOW_TOOLBAR = wx.NewId() self.show_toolbar_view_menu_item = self.viewMenu.Append(self.ID_SHOW_TOOLBAR, "Show &Toolbar", "Show Toolbar", wx.ITEM_CHECK) BindMenu(self.show_toolbar_view_menu_item, self.OnViewMenuShowToolbar) self.viewMenu.Check(self.ID_SHOW_TOOLBAR, True) # presage menu self.presageMenu = wx.Menu() self.ID_PROMPT_ME = wx.NewId() BindMenu(self.presageMenu.Append(self.ID_PROMPT_ME, "&Prompt me\tCTRL+P"), self.OnPresageMenuPromptMe) self.ID_TOGGLE_FUNCTION_KEYS_MODE = wx.NewId() self.function_mode_presage_menu_item = self.presageMenu.Append(self.ID_TOGGLE_FUNCTION_KEYS_MODE, "&Function keys\tCTRL+F", "Toggle function keys mode", wx.ITEM_CHECK) self.presageMenu.Check(self.ID_TOGGLE_FUNCTION_KEYS_MODE, True) BindMenu(self.function_mode_presage_menu_item, self.OnPresageMenuToggleFunctionMode) self.ID_TOGGLE_AUTOPUNCTUATION_MODE = wx.NewId() self.autopunctuation_mode_presage_menu_item = self.presageMenu.Append(self.ID_TOGGLE_AUTOPUNCTUATION_MODE, "&Autopunctuation\tCTRL+A", "Toggle autopunctuation mode", wx.ITEM_CHECK) self.presageMenu.Check(self.ID_TOGGLE_AUTOPUNCTUATION_MODE, True) BindMenu(self.autopunctuation_mode_presage_menu_item, self.OnPresageMenuToggleAutopunctuationMode) # help menu self.helpMenu = wx.Menu() BindMenu(self.helpMenu.Append(wx.ID_HELP, "&Contents"), self.OnHelpMenuContents) self.helpMenu.AppendSeparator() BindMenu(self.helpMenu.Append(wx.ID_ABOUT, "&About"), self.OnHelpMenuAbout) # menu bar self.menuBar = wx.MenuBar() self.menuBar.Append(self.fileMenu, "&File") self.menuBar.Append(self.editMenu, "&Edit") self.menuBar.Append(self.viewMenu, "&View") self.menuBar.Append(self.presageMenu, "&Presage") self.menuBar.Append(self.helpMenu, "&Help") self.SetMenuBar(self.menuBar) # grey out menu items self.fileMenu.Enable(wx.ID_SAVE, False) self.fileMenu.Enable(wx.ID_SAVEAS, False) self.editMenu.Enable(wx.ID_UNDO, False) self.editMenu.Enable(wx.ID_REDO, False) def MakeToolBar(self): def BindTool(item, handler): self.Bind(wx.EVT_TOOL, handler, item) self.Bind(wx.EVT_TOOL_RCLICKED, handler, item) self.toolbar = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT) tsize = (16,16) new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize) open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize) save_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, tsize) undo_bmp = wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_TOOLBAR, tsize) redo_bmp = wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_TOOLBAR, tsize) cut_bmp = wx.ArtProvider.GetBitmap(wx.ART_CUT, wx.ART_TOOLBAR, tsize) copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize) paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR, tsize) prompt_me_bmp= wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_TOOLBAR, tsize) self.toolbar.SetToolBitmapSize(tsize) BindTool(self.toolbar.AddLabelTool(wx.ID_NEW, "New", new_bmp, shortHelp="New", longHelp="New file"), self.OnFileMenuNew) BindTool(self.toolbar.AddLabelTool(wx.ID_OPEN, "Open", open_bmp, shortHelp="Open", longHelp="Open file"), self.OnFileMenuOpen) BindTool(self.toolbar.AddLabelTool(wx.ID_SAVE, "Save", save_bmp, shortHelp="Save", longHelp="Save file"), self.OnFileMenuSave) self.toolbar.AddSeparator() BindTool(self.toolbar.AddLabelTool(wx.ID_UNDO, "Undo", undo_bmp, shortHelp="Undo", longHelp="Undo last action"), self.OnEditMenuUndo) BindTool(self.toolbar.AddLabelTool(wx.ID_REDO, "Redo", redo_bmp, shortHelp="Redo", longHelp="Redo last action"), self.OnEditMenuRedo) self.toolbar.AddSeparator() BindTool(self.toolbar.AddLabelTool(wx.ID_CUT, "Cut", cut_bmp, shortHelp="Cut", longHelp="Cut selection"), self.OnEditMenuCut) BindTool(self.toolbar.AddLabelTool(wx.ID_COPY, "Copy", copy_bmp, shortHelp="Copy", longHelp="Copy selection"), self.OnEditMenuCopy) BindTool(self.toolbar.AddLabelTool(wx.ID_PASTE, "Paste", paste_bmp, shortHelp="Paste", longHelp="Paste selection"), self.OnEditMenuPaste) self.toolbar.AddSeparator() BindTool(self.toolbar.AddLabelTool(self.ID_PROMPT_ME, "Prompt me", prompt_me_bmp, shortHelp="Prompt me", longHelp="Prompt me with a prediction"), self.OnPresageMenuPromptMe) self.toolbar.Realize() # menu handlers def OnFileMenuNew(self, event): self.editor.file = None self.editor.ClearAll() self.fileMenu.Enable(wx.ID_SAVE, False) self.fileMenu.Enable(wx.ID_SAVEAS, False) def OnFileMenuOpen(self, event): print "Opening a file.." # Create the dialog. In this case the current directory is forced as the starting # directory for the dialog, and no default file name is forced. This can easilly # be changed in your program. This is an 'open' dialog, and allows multitple # file selections as well. # # Finally, if the directory is changed in the process of getting files, this # dialog is set up to change the current working directory to the path chosen. dlg = wx.FileDialog( self, message="Choose a file", defaultDir="", defaultFile="", wildcard=self.wildcard, style=wx.OPEN | wx.CHANGE_DIR ) # Show the dialog and retrieve the user response. If it is the OK response, # process the data. if dlg.ShowModal() == wx.ID_OK: # This returns a Python list of files that were selected. path = dlg.GetPath() print ("Opening %s\n" % path) try: fsock = open(path, 'r') contents = fsock.read() fsock.close() self.editor.SetText(contents) self.editor.file = path # remember file we're editing self.fileMenu.Enable(wx.ID_SAVE, False) self.fileMenu.Enable(wx.ID_SAVEAS, True) except IOError: dialog = wx.MessageDialog(self, "Error opening file %s" % path, "Error opening file", wx.OK) dialog.ShowModal() dialog.Destroy() # Destroy the dialog. Don't do this until you are done with it! # BAD things can happen otherwise! dlg.Destroy() def OnFileMenuSave(self, event): print "Save file" if self.editor.file == None: self.OnFileMenuSaveAs(event) else: self.__SaveFile(self.editor.file) self.fileMenu.Enable(wx.ID_SAVE, False) def OnFileMenuSaveAs(self, event): print "Save file as" # Create the dialog. In this case the current directory is forced as the starting # directory for the dialog, and no default file name is forced. This can easilly # be changed in your program. This is an 'save' dialog. # # Unlike the 'open dialog' example found elsewhere, this example does NOT # force the current working directory to change if the user chooses a different # directory than the one initially set. dlg = wx.FileDialog( self, message="Save file as ...", defaultDir="", defaultFile="", wildcard=self.wildcard, style=wx.SAVE ) # This sets the default filter that the user will initially see. Otherwise, # the first filter in the list will be used by default. dlg.SetFilterIndex(2) # Show the dialog and retrieve the user response. If it is the OK response, # process the data. if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.editor.file = path # remember file we're editing has changed self.__SaveFile(path) self.fileMenu.Enable(wx.ID_SAVE, False) # Destroy the dialog. Don't do this until you are done with it! # BAD things can happen otherwise! dlg.Destroy() def OnFileMenuClose(self, event): self.OnFileMenuNew(event) # this will do for now def OnFileMenuQuit(self, event): print "This should first check that changes have been saved..." self.Close(True) def OnEditMenuUndo(self, event): if self.editor.CanUndo(): self.editor.Undo() print "Undo last action" def OnEditMenuRedo(self, event): if self.editor.CanRedo(): self.editor.Redo() print "Redo last action" def OnEditMenuCut(self, event): self.clip = self.editor.GetSelectedText() self.editor.ReplaceSelection('') print "Cut selected text: " + self.clip def OnEditMenuCopy(self, event): self.clip = self.editor.GetSelectedText() print "Stored selected text into clip: " + self.clip def OnEditMenuPaste(self, event): self.editor.ReplaceSelection(self.clip) print "Replace selection with: " + self.clip def OnEditMenuSelectAll(self, event): self.editor.SelectAll() def OnViewMenuWordWrap(self, event): self.editor.ToggleWordWrapMode() def OnViewMenuLargerText(self, event): self.editor.IncreaseTextSize() def OnViewMenuSmallerText(self, event): self.editor.DecreaseTextSize() def OnViewMenuShowToolbar(self, event): if event.Checked(): self.toolbar.Show() else: self.toolbar.Hide() self.SendSizeEvent() # cause Frame to reevaluate childrens' positions def OnPresageMenuPromptMe(self, event): self.editor.ShowPrediction() def OnPresageMenuToggleFunctionMode(self, event): self.editor.function_keys_enabled = event.Checked() def OnPresageMenuToggleAutopunctuationMode(self, event): self.editor.autopunctuation = event.Checked() def OnHelpMenuContents(self, event): message = "Sorry, help not written yet." dialog = wx.MessageDialog(self, message, "pyprompter help", wx.OK) dialog.ShowModal() dialog.Destroy() def OnHelpMenuAbout(self, event): self.__ShowAboutDialogBox() def __ShowAboutDialogBox(self): name = 'pyprompter' version = self.version copyright = '(C) 2008 Matteo Vescovi' description = '''This program is intended as a demonstration of Presage ONLY. The Presage project aims to provide an intelligent predictive text entry platform. Its intent is NOT to provide a predictive text entry user interface. Think of Presage as the predictive backend that sits behind a shiny user interface and does all the predictive heavy lifting. ''' website = 'http://presage.sourceforge.net/' devs = ["Matteo Vescovi"] license = '''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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ''' # AboutBox and AboutDialogInfo were introduced in wxPython 2.7.1.1 if wx.VERSION > (2, 7, 1, 1): # build about dialog information info = wx.AboutDialogInfo() info.SetName(name) info.SetVersion(version) info.SetCopyright(copyright) info.SetDescription(description) info.SetWebSite(website) info.SetDevelopers(devs) info.SetDocWriters(devs) info.SetArtists(devs) #info.SetTranslators(devs) info.SetLicense(license) #info.SetIcon() # show about dialog box wx.AboutBox(info) else: message = name + ' ' + version + '\n' \ + '\n' \ + copyright + '\n' \ + '\n' \ + description + '\n' \ + website dialog = wx.MessageDialog(self, message, "About pyprompter", wx.OK) dialog.ShowModal() dialog.Destroy() def __SaveFile(self, path): try: fp = open(path, 'w') # Create file anew fp.write(self.editor.GetText()) fp.close() except IOError: dialog = wx.MessageDialog(self, "Error saving file %s" % path, "Error saving file", wx.OK) dialog.ShowModal() dialog.Destroy() ################ # PrompterEditor # class PrompterEditor(wx.stc.StyledTextCtrl): def __init__(self, parent, config, suggestions): wx.stc.StyledTextCtrl.__init__(self, parent) self.parent = parent # remember parent access frame menus self.file = None # remember what file to save to self.append_whitespace_on_completion = True self.autopunctuation = True self.autopunctuation_whitespace = ' ' self.autopunctuation_chars = ".,;:'?!$%&" self.function_keys_enabled = True self.Bind(wx.EVT_CHAR, self.OnChar) self.Bind(wx.stc.EVT_STC_USERLISTSELECTION, self.OnUserListSelection) self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModified) class PrompterPresageCallback(presage.PresageCallback): def __init__(self, edtr): presage.PresageCallback.__init__(self) self.editor = edtr def get_past_stream(self): result = self.editor.GetTextRange(0, self.editor.GetCurrentPos()) return str(result) def get_future_stream(self): result = self.editor.GetTextRange(self.editor.GetCurrentPos(), self.editor.GetTextLength()) return str(result) callback = PrompterPresageCallback(self).__disown__() if config: self.prsg = presage.Presage(callback, config) else: self.prsg = presage.Presage(callback) if suggestions: self.prsg.config('Presage.Selector.SUGGESTIONS', suggestions) self.SetCodePage(wx.stc.STC_CP_UTF8) # set unicode codepage self.SetWrapMode(wx.stc.STC_WRAP_WORD) self.AutoCompSetAutoHide(False) self.separator = ',' self.AutoCompSetSeparator(44) #self.AutoCompSetIgnoreCase(1) self.AutoCompSetMaxHeight(int(self.prsg.config("Presage.Selector.SUGGESTIONS"))) self.text_size = 10 self.StyleSetSize(wx.stc.STC_STYLE_DEFAULT, self.text_size) # hide margings for i in range(5): self.SetMarginWidth(i, 0) # delaying the __ShowPrediction until after the parent frame and # the STC are shown. wx.CallAfter(self.__ShowPrediction) wx.CallAfter(self.SetSTCFocus, 1) def OnChar(self, event): print "------------ OnChar() handler" keycode = event.GetKeyCode() if self.__FunctionKey(keycode): self.__HandleFunctionKey(keycode) else: key = unichr(keycode) self.parent.fileMenu.Enable(wx.ID_SAVE, True) self.parent.fileMenu.Enable(wx.ID_SAVEAS, True) if self.__AutoPunctuation(key): # autopunctuation takes care of adding text and updating # prsg, nothing to do here. pass else: self.AddText(key) self.__ShowPrediction() def ShowPrediction(self, string = ''): self.__ShowPrediction(string) def __ShowPrediction(self, string = ''): print "------------ __ShowPrediction()" try: prefix = self.prsg.prefix() context = self.prsg.context() context_change = self.prsg.context_change() self.prediction = self.prsg.predict() if self.function_keys_enabled: self.prediction = self.__PrependFunctionLabel(self.prediction) self.suggestions = self.separator.join(self.prediction); except presage.PresageException, ex: print 'Caught exception %s' % (ex) print ' code: %d' % (ex.code()) print ' what: %s' % (ex.what()) print "String: " + string print "Prefix: " + prefix print "Prefix len: " + str(len(prefix)) print "Context: " + context print "Context change: " + str(context_change) print "Prediction: " + self.suggestions if self.AutoCompActive(): self.AutoCompCancel() # AutoCompShow() does not generate an event when autocompletion is # successful, hence it is not possible to notify presage that # the current token was completed. #self.AutoCompShow(len(prefix), suggestions) # UserListShow() throws an EVT_STC_USERLISTSELECTION event that we # can handle to notify presage that the token was automatically # completed. self.UserListShow(1, self.suggestions) def __AutoPunctuation(self, char): if self.autopunctuation: # autopunctuation is enabled if char in self.autopunctuation_chars: # char is an autopunctuation character curr_pos = self.GetCurrentPos() if curr_pos > 0: # previous character exists prev_pos = curr_pos - 1 prev_char = chr(self.GetCharAt(prev_pos)) if prev_char in self.autopunctuation_whitespace: # previous character is an autopunctuation whitespace # swap whitespace and current char self.SetSelection(prev_pos, curr_pos) self.ReplaceSelection(char + ' ') return True return False def __FunctionKey(self, keycode): result = False if self.function_keys_enabled: self.function_keys = [wx.WXK_F1, wx.WXK_F2, wx.WXK_F3, wx.WXK_F4, wx.WXK_F5, wx.WXK_F6, wx.WXK_F7, wx.WXK_F8, wx.WXK_F9, wx.WXK_F10, wx.WXK_F11, wx.WXK_F12] if keycode in self.function_keys: result = True return result def __HandleFunctionKey(self, key): print "Got function key " + str(key) try: idx = self.function_keys.index(key) print self.prediction[idx] if self.AutoCompActive(): self.AutoCompCancel() self.UserListShow(1, self.suggestions) self.AutoCompSelect(self.prediction[idx]) self.AutoCompComplete() except IndexError: print 'Key not in prediction completion list' def __PrependFunctionLabel(self, prediction): return ['F' + str(i + 1) + ' ' + prediction[i] for i in range(len(prediction))] def __RemoveFunctionLabel(self, completion): idx = completion.find(' ') if not idx == -1: completion = completion[idx+1:] return completion def OnUserListSelection(self, event): completion = unicode(event.GetText()) if self.function_keys_enabled: completion = self.__RemoveFunctionLabel(completion) prefix_length = len(unicode(self.prsg.prefix())) print "----------- OnUserListSelection() handler" print "Completion: " + completion print "Prefix length: " + str(prefix_length) print "To be added: " + completion[prefix_length:] # no need to call complete, using callbacks #self.prsg.complete(completion.encode('utf-8')) self.AddText(completion[prefix_length:]) if self.append_whitespace_on_completion: self.AddText(' ') # no need to update, using callbacks #self.prsg.update(' ') # schedule showing of prediction after current and pending events # are dealt with (thanks to Robin Dunn for pointing this out) wx.CallAfter(self.__ShowPrediction) def OnModified(self, event): # grey out or enable menu items self.parent.fileMenu.Enable(wx.ID_SAVE, True) self.parent.fileMenu.Enable(wx.ID_SAVEAS, True) if self.CanUndo(): self.parent.editMenu.Enable(wx.ID_UNDO, True) else: self.parent.editMenu.Enable(wx.ID_UNDO, False) if self.CanRedo(): self.parent.editMenu.Enable(wx.ID_REDO, True) else: self.parent.editMenu.Enable(wx.ID_REDO, False) def ToggleWordWrapMode(self): if self.parent.word_wrap.IsChecked(): self.SetWrapMode(wx.stc.STC_WRAP_WORD) else: self.SetWrapMode(wx.stc.STC_WRAP_NONE) def IncreaseTextSize(self): self.text_size += 1 self.StyleSetSize(wx.stc.STC_STYLE_DEFAULT, self.text_size) def DecreaseTextSize(self): if self.text_size > 1: self.text_size -= 1 self.StyleSetSize(wx.stc.STC_STYLE_DEFAULT, self.text_size) presage-0.8.8/apps/python/prompter/__init__.py0000644000175000017500000000161711737142176016361 00000000000000########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. presage-0.8.8/apps/python/pypresagemate0000644000175000017500000000647211764437313015175 00000000000000#!/usr/bin/python ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # Copyright (C) 2009 John Hills # Copyright (C) 2009 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import getopt import os PROGRAM_NAME = 'pypresagemate' def print_version(): print """ %s (%s) version %s Copyright (C) 2010 Matteo Vescovi. Copyright (C) 2010 John Hills. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. """ % (PROGRAM_NAME, 'presage', '0.8.8') def print_usage(): print """ Usage: %s [options] Options: -h, --help display this help and exit -v, --version output version information and exit Pypresagemate is a universal predictive text companion. Pypresagemate works alongside any AT-SPI aware application. The Assistive Technology Service Provider Interface (AT-SPI) is a toolkit-neutral way of providing accessibility facilities in applications. Pypresagemate works in the background by tracking what keystrokes are typed and displaying predictions in its window. When a prediction is selected, text is sent to the active application. Direct your bug reports to: %s """ % (PROGRAM_NAME, 'matteo.vescovi@yahoo.co.uk') def parse_cmd_line_args(): short_options = "hv" long_options = ["help", "version"] try: opts, args = getopt.getopt(sys.argv[1:], short_options, long_options) except getopt.GetoptError, err: print str(err) sys.exit(1) for opt, arg in opts: if opt in ('-v', '--version'): print_version() sys.exit() elif opt in ('-h', '--help'): print_usage() sys.exit() if __name__ == "__main__": parse_cmd_line_args() try: import presagemate.presagemate except ImportError, e: print ''' Error: failed to import module presagemate. Check that prompter is properly installed (if installed in a non-standard location, please set PYTHONPATH accordingly). ''' print e else: if not config: # try to locate presage.xml config file scriptdir = os.path.dirname(sys.argv[0]) # in scriptdir/etc conffile = os.path.join(scriptdir, 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile else: # in scriptdir/../etc conffile = os.path.join(scriptdir, '..', 'etc', 'presage.xml') if os.path.isfile(conffile): config = conffile print 'Configuration file: ' + str(config) presage-0.8.8/apps/python/setup.py.in0000644000175000017500000000274311737142176014520 00000000000000 ########## # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Process this file with configure to produce setup.py from distutils.core import setup, Extension setup(name='pyprompter', version='@PACKAGE_VERSION@', description='Pyprompter, the intelligent predictive wxPython text editor powered by presage', author='Matteo Vescovi', author_email='@PACKAGE_BUGREPORT@', maintainer='Matteo Vescovi', maintainer_email='@PACKAGE_BUGREPORT@', url='http://presage.sourceforge.net/', package_dir={'prompter': '@top_srcdir@/apps/python/prompter'}, packages=['prompter'], scripts=['pyprompter'], ) presage-0.8.8/apps/gtk/0000755000175000017500000000000011764714757011731 500000000000000presage-0.8.8/apps/gtk/gpresagemate/0000755000175000017500000000000011764714757014375 500000000000000presage-0.8.8/apps/gtk/gpresagemate/Makefile.am0000644000175000017500000000275511737142176016350 00000000000000 ########### # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in if BUILD_GTK_PRESAGE_MATE bin_PROGRAMS = gpresagemate gpresagemate_SOURCES = gpresagemate.cpp gpresagemate_CPPFLAGS = $(GNOME_CFLAGS) $(GTHREAD_CFLAGS) -I$(top_srcdir)/src/lib gpresagemate_LDADD = $(GNOME_LIBS) $(GTHREAD_LIBS) -lXevie ../../../src/lib/libpresage.la # if HAVE_HELP2MAN # gpresagemate.1: gpresagemate$(EXEEXT) gpresagemate.cpp $(top_srcdir)/configure.ac # help2man --output=$@ --no-info --name="GTK presage mate" ./gpresagemate$(EXEEXT) # # dist_man_MANS = gpresagemate.1 # # DISTCLEANFILES = gpresagemate.1 # endif endifpresage-0.8.8/apps/gtk/gpresagemate/Makefile.in0000644000175000017500000005041511763440354016353 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 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. @SET_MAKE@ ########### # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @BUILD_GTK_PRESAGE_MATE_TRUE@bin_PROGRAMS = gpresagemate$(EXEEXT) subdir = apps/gtk/gpresagemate DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/cppunit.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am__gpresagemate_SOURCES_DIST = gpresagemate.cpp @BUILD_GTK_PRESAGE_MATE_TRUE@am_gpresagemate_OBJECTS = gpresagemate-gpresagemate.$(OBJEXT) gpresagemate_OBJECTS = $(am_gpresagemate_OBJECTS) am__DEPENDENCIES_1 = @BUILD_GTK_PRESAGE_MATE_TRUE@gpresagemate_DEPENDENCIES = \ @BUILD_GTK_PRESAGE_MATE_TRUE@ $(am__DEPENDENCIES_1) \ @BUILD_GTK_PRESAGE_MATE_TRUE@ $(am__DEPENDENCIES_1) \ @BUILD_GTK_PRESAGE_MATE_TRUE@ ../../../src/lib/libpresage.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(gpresagemate_SOURCES) DIST_SOURCES = $(am__gpresagemate_SOURCES_DIST) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_CONFIG = @CPPUNIT_CONFIG@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ GREP = @GREP@ GTHREAD_CFLAGS = @GTHREAD_CFLAGS@ GTHREAD_LIBS = @GTHREAD_LIBS@ HAVE_DOT = @HAVE_DOT@ HAVE_DOXYGEN = @HAVE_DOXYGEN@ HAVE_HELP2MAN = @HAVE_HELP2MAN@ IDNGRAM2LM = @IDNGRAM2LM@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SQLITE_LIBS = @SQLITE_LIBS@ STRIP = @STRIP@ SWIG = @SWIG@ TEXT2IDNGRAM = @TEXT2IDNGRAM@ TEXT2WFREQ = @TEXT2WFREQ@ UNIX2DOS = @UNIX2DOS@ VERSION = @VERSION@ WFREQ2VOCAB = @WFREQ2VOCAB@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @BUILD_GTK_PRESAGE_MATE_TRUE@gpresagemate_SOURCES = gpresagemate.cpp @BUILD_GTK_PRESAGE_MATE_TRUE@gpresagemate_CPPFLAGS = $(GNOME_CFLAGS) $(GTHREAD_CFLAGS) -I$(top_srcdir)/src/lib @BUILD_GTK_PRESAGE_MATE_TRUE@gpresagemate_LDADD = $(GNOME_LIBS) $(GTHREAD_LIBS) -lXevie ../../../src/lib/libpresage.la all: all-am .SUFFIXES: .SUFFIXES: .cpp .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu apps/gtk/gpresagemate/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu apps/gtk/gpresagemate/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list gpresagemate$(EXEEXT): $(gpresagemate_OBJECTS) $(gpresagemate_DEPENDENCIES) @rm -f gpresagemate$(EXEEXT) $(CXXLINK) $(gpresagemate_OBJECTS) $(gpresagemate_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpresagemate-gpresagemate.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< gpresagemate-gpresagemate.o: gpresagemate.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpresagemate_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gpresagemate-gpresagemate.o -MD -MP -MF $(DEPDIR)/gpresagemate-gpresagemate.Tpo -c -o gpresagemate-gpresagemate.o `test -f 'gpresagemate.cpp' || echo '$(srcdir)/'`gpresagemate.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/gpresagemate-gpresagemate.Tpo $(DEPDIR)/gpresagemate-gpresagemate.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gpresagemate.cpp' object='gpresagemate-gpresagemate.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpresagemate_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gpresagemate-gpresagemate.o `test -f 'gpresagemate.cpp' || echo '$(srcdir)/'`gpresagemate.cpp gpresagemate-gpresagemate.obj: gpresagemate.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpresagemate_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gpresagemate-gpresagemate.obj -MD -MP -MF $(DEPDIR)/gpresagemate-gpresagemate.Tpo -c -o gpresagemate-gpresagemate.obj `if test -f 'gpresagemate.cpp'; then $(CYGPATH_W) 'gpresagemate.cpp'; else $(CYGPATH_W) '$(srcdir)/gpresagemate.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/gpresagemate-gpresagemate.Tpo $(DEPDIR)/gpresagemate-gpresagemate.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gpresagemate.cpp' object='gpresagemate-gpresagemate.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gpresagemate_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gpresagemate-gpresagemate.obj `if test -f 'gpresagemate.cpp'; then $(CYGPATH_W) 'gpresagemate.cpp'; else $(CYGPATH_W) '$(srcdir)/gpresagemate.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ clean-generic clean-libtool ctags distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-binPROGRAMS # if HAVE_HELP2MAN # gpresagemate.1: gpresagemate$(EXEEXT) gpresagemate.cpp $(top_srcdir)/configure.ac # help2man --output=$@ --no-info --name="GTK presage mate" ./gpresagemate$(EXEEXT) # # dist_man_MANS = gpresagemate.1 # # DISTCLEANFILES = gpresagemate.1 # endif # 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: presage-0.8.8/apps/gtk/gpresagemate/gpresagemate.cpp0000644000175000017500000003134711737142176017463 00000000000000/********************************************************* * Presage, an extensible predictive text entry system * ------------------------------------------------------ * * Copyright (C) 2008 John Hills * Copyright (C) 2008 Matteo Vescovi 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * **********(*)*/ /* * A simple GTK presage application that uses the X window system * XEvIE extension to intercept key presses and insert user selected * predictions into currently focused X windows application provided * the X server has a working XEvIE extension enabled. * * /etc/X11/xorg.conf requires the following lines to enable XEvIE * Section "Extensions" * Option "XEVIE" "Enable" * EndSection * * * Based on code by Matteo Vescovi and xeviedemo.c from * http://freedesktop.org/wiki/Software/XEvIE * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_PTHREAD_H # include #endif #ifdef HAVE_X11_XLIB_H # include #endif #ifdef HAVE_X11_XPROTO_H # include #endif #ifdef HAVE_X11_X_H # include #endif #ifdef HAVE_X11_EXTENSIONS_XEVIE_H # include #endif #ifdef HAVE_X11_XUTIL_H # include #endif #ifdef HAVE_X11_KEYSYMDEF_H # include #endif #include #include #include #include #include "presage.h" std::string suggestions; std::string config; unsigned int no_suggestions; std::stringstream buffer; class StringstreamPresageCallback : public PresageCallback { public: StringstreamPresageCallback(std::stringstream& stream) : m_stream(stream) { } ~StringstreamPresageCallback() { } std::string get_past_stream() const { if (&m_stream) { return m_stream.str(); } else { return m_empty; } } std::string get_future_stream() const { return m_empty; } private: std::stringstream& m_stream; const std::string m_empty; }; StringstreamPresageCallback callback(buffer); Presage presage(&callback); Display *dpy; static KeySym get_keysym (XEvent *ev) { XKeyEvent *key_ev; char buffer[64]; int bufsize = 63; KeySym key; XComposeStatus compose; int char_count; key_ev = (XKeyEvent *)ev; char_count = XLookupString(key_ev, buffer, bufsize, &key, &compose); buffer[char_count] = '\0'; printf (" State: %x KeyCode: %x\n", key_ev->state & ShiftMask, key_ev->keycode); char_count = XLookupString(key_ev, buffer, bufsize, &key, &compose); buffer[char_count] = '\0'; printf (" Char Count: %d KeySym: %lu char: |%c|\n", char_count, key, buffer[0]); return key; } void get_prediction( unsigned int key, char* append_string, int complete_flag, GtkWidget* label ) { std::ostringstream os; std::string disp_string; std::string prediction; static std::vector< std::string > predictions; char disp_string_c[BUFSIZ]; append_string[0] = 0; if(complete_flag == TRUE){ // check that a prediction is available if((key - XK_F1) < predictions.size()){ prediction = presage.completion(predictions[key - XK_F1]); strcpy(append_string, prediction.c_str()); buffer << prediction; } key = ' '; } // cast key back to char in order to be inserted as a character on // the buffer stream // // REVISIT: this WILL break for Unicode chars // buffer << (char) key; predictions = presage.predict(); for (int i = 0; i < (int) predictions.size(); i++) { os << 'F' << i+1 << " " << predictions[i] << std::endl; } disp_string = os.str(); strcpy(disp_string_c, disp_string.c_str()); if(disp_string_c[0] != 0) { /* get GTK thread lock */ gdk_threads_enter (); gtk_label_set_text(GTK_LABEL(label), disp_string_c ); printf ("label:\n%s\n", disp_string_c); /* release GTK thread lock */ gdk_threads_leave (); } } void init() { int major, minor; // initialize presage if (suggestions.empty()) { suggestions = presage.config("Presage.Selector.SUGGESTIONS"); } else { presage.config("Presage.Selector.SUGGESTIONS", suggestions); } no_suggestions = atoi(suggestions.c_str()); // initialize XEvIE dpy = XOpenDisplay(NULL); if(XevieStart(dpy)) printf("XevieStart(dpy) initialized\n"); else { printf("XevieStart(dpy) initialization failed\n Check that XEvIE X extension is enabled and that only one client is trying to do event interception\n"); exit(1); } XevieQueryVersion(dpy, &major, &minor); printf("XEvIE major = %d, minor = %d\n", major, minor); XevieSelectInput(dpy, KeyPressMask | KeyReleaseMask ); } void shutdown() { XevieEnd (dpy); } gint print_hi(gpointer ununsed) { printf("hi!\n"); return TRUE; } void handle_x_event ( XEvent& event, GtkWidget* label ) { KeySym key; char completion_string_c[BUFSIZ]; int completion_word_index = 0; int completion_flag = FALSE; switch(event.type) { case KeyPress: key = get_keysym(&event); if((isalpha(key) || isspace(key) || ispunct(key) || key == XK_BackSpace) && key < 256){ XevieSendEvent(dpy, &event, XEVIE_UNMODIFIED); get_prediction(tolower(key), completion_string_c, FALSE, label); if(((key == ',') || (key == '.') || (key == '?') || (key == ';') || (key == ':')) && (completion_word_index == 0) && (completion_flag == TRUE)) { event.xkey.keycode = XKeysymToKeycode(dpy, XK_BackSpace); event.type = KeyPress; XSendEvent(dpy, InputFocus, TRUE, KeyPressMask, &event); event.type = KeyRelease; XSendEvent(dpy, InputFocus, TRUE, KeyReleaseMask, &event); event.type = KeyPress; XSendEvent(dpy, InputFocus, TRUE, KeyPressMask, &event); event.type = KeyRelease; XSendEvent(dpy, InputFocus, TRUE, KeyReleaseMask, &event); event.xkey.keycode = XKeysymToKeycode(dpy, key); event.type = KeyPress; XSendEvent(dpy, InputFocus, TRUE, KeyPressMask, &event); event.type = KeyRelease; XSendEvent(dpy, InputFocus, TRUE, KeyReleaseMask, &event); event.xkey.keycode = XKeysymToKeycode(dpy, XK_space); event.type = KeyPress; XSendEvent(dpy, InputFocus, TRUE, KeyPressMask, &event); event.type = KeyRelease; XSendEvent(dpy, InputFocus, TRUE, KeyReleaseMask, &event); } else if(isspace(key)) completion_word_index = 0; else completion_word_index++; completion_flag = FALSE; } // check for function keys else if(((key - XK_F1) >= 0) && ((key - XK_F1) <= no_suggestions-1)) { // inform presage that the prediction was successful. // and ask presage to predict next token get_prediction(tolower(key), completion_string_c, TRUE, label); char s[64]; printf("%d\n", completion_word_index ); // send the rest of the completion string and a ' ' to the client while(completion_string_c[completion_word_index] != '\0'){ s[0] = completion_string_c[completion_word_index]; s[1] = '\0'; event.xkey.keycode = XKeysymToKeycode(dpy, XStringToKeysym(s)); event.type = KeyPress; XSendEvent(dpy, InputFocus, TRUE, KeyPressMask, &event); event.type = KeyRelease; XSendEvent(dpy, InputFocus, TRUE, KeyReleaseMask, &event); event.xkey.time++; completion_word_index++; } completion_word_index = 0; completion_flag = TRUE; event.xkey.keycode = XKeysymToKeycode(dpy, XK_space); event.type = KeyPress; XSendEvent(dpy, InputFocus, TRUE, KeyPressMask, &event); event.type = KeyRelease; XSendEvent(dpy, InputFocus, TRUE, KeyReleaseMask, &event); } else { // anything else just send it to the client XevieSendEvent(dpy, &event, XEVIE_UNMODIFIED); completion_word_index = 0; completion_flag = FALSE; } break; case KeyRelease: XevieSendEvent(dpy, &event, XEVIE_UNMODIFIED); break; default: printf(" unknown event %x\n", event.type); break; } } void* presage_thread (void* label) { XEvent event; for (;;) { // get XEvIE event XNextEvent (dpy, &event); printf ("Got XEvent\n"); handle_x_event (event, GTK_WIDGET(label)); } return NULL; } gboolean delete_event( GtkWidget *widget, GdkEvent *gdk_event, gpointer data ) { /* If you return FALSE in the "delete_event" signal handler, * GTK will emit the "destroy" signal. Returning TRUE means * you don't want the window to be destroyed. * This is useful for popping up 'are you sure you want to quit?' * type dialogs. */ g_print ("delete event occurred\n"); gtk_main_quit (); shutdown (); /* Change TRUE to FALSE and the main window will be destroyed with * a "delete_event". */ return TRUE; } /* Another callback */ void destroy( GtkWidget *widget, gpointer data ) { g_print ("destroy event occurred\n"); } int main ( int argc, char *argv[] ) { GtkWidget *window; GtkWidget *label; pthread_t thread; /* init threads */ g_thread_init (NULL); gdk_threads_init (); gdk_threads_enter (); /* init GTK+ */ gtk_init (&argc, &argv); gtk_set_locale (); gtk_rc_parse ("~/.presagegtkrc"); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "gpresagemate"); gtk_window_set_default_size (GTK_WINDOW(window), 150, 180); gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_NONE); /* When the window is given the "delete_event" signal (this is given * by the window manager, usually by the "close" option, or on the * titlebar), we ask it to call the delete_event () function * as defined above. The data passed to the callback * function is NULL and is ignored in the callback function. */ g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (delete_event), NULL); /* Here we connect the "destroy" event to a signal handler. * This event occurs when we call gtk_widget_destroy() on the window, * or if we return FALSE in the "delete_event" callback. */ g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); label = gtk_label_new ("gpresagemate"); gtk_widget_set_name(label, "presage_suggestions"); gtk_container_add (GTK_CONTAINER(window), label); gtk_widget_show (window); gtk_widget_show (label); init (); if (0 != pthread_create (&thread, NULL, presage_thread, label)) { perror("Failed to spawn presage thread"); exit(2); } gtk_main (); /* clean up threads */ gdk_threads_leave (); return 0; } presage-0.8.8/apps/gtk/Makefile.am0000644000175000017500000000176411737142176013703 00000000000000 ########### # Presage, an extensible predictive text entry system # ------------------------------------------------------ # # Copyright (C) 2008 Matteo Vescovi # # 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., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## Process this file with automake to produce Makefile.in SUBDIRS = \ gpresagemate \ gprompter presage-0.8.8/apps/gtk/gprompter/0000755000175000017500000000000011764714760013742 500000000000000presage-0.8.8/apps/gtk/gprompter/gprompter.10000644000175000017500000000160511764437334015764 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH GPROMPTER "1" "June 2012" "gprompter (presage) version 0.8.8" "User Commands" .SH NAME gprompter \- the intelligent predictive GTK+ text editor .SH SYNOPSIS .B gprompter [\fIOPTION\fR]... .SH DESCRIPTION Gprompter is a cross\-platform predictive text editor. Gprompter displays predictions in a contextual pop\-up box as each letter is typed. Predictions can be easily selected and inserted in the document. .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit .TP \fB\-v\fR, \fB\-\-version\fR output version information and exit .PP Direct your bug reports to: matteo.vescovi@yahoo.co.uk .SH COPYRIGHT Copyright \(co 2009 Matteo Vescovi. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, to the extent permitted by law. presage-0.8.8/apps/gtk/gprompter/gprompter.svg0000644000175000017500000001147111737142176016422 00000000000000 gprompter image/svg+xml gprompter Matteo Vescovi gprompter, the intelligent predictive text editor gprompter presage predictive text entry g presage-0.8.8/apps/gtk/gprompter/scintilla/0000755000175000017500000000000011764714760015724 500000000000000presage-0.8.8/apps/gtk/gprompter/scintilla/src/0000755000175000017500000000000011764714757016521 500000000000000presage-0.8.8/apps/gtk/gprompter/scintilla/src/ScintillaBase.h0000644000175000017500000000475211640062361021313 00000000000000// Scintilla source code edit control /** @file ScintillaBase.h ** Defines an enhanced subclass of Editor with calltips, autocomplete and context menu. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SCINTILLABASE_H #define SCINTILLABASE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif #ifdef SCI_LEXER class LexState; #endif /** */ class ScintillaBase : public Editor { // Private so ScintillaBase objects can not be copied ScintillaBase(const ScintillaBase &); ScintillaBase &operator=(const ScintillaBase &); protected: /** Enumeration of commands and child windows. */ enum { idCallTip=1, idAutoComplete=2, idcmdUndo=10, idcmdRedo=11, idcmdCut=12, idcmdCopy=13, idcmdPaste=14, idcmdDelete=15, idcmdSelectAll=16 }; bool displayPopupMenu; Menu popup; AutoComplete ac; CallTip ct; int listType; ///< 0 is an autocomplete list int maxListWidth; /// Maximum width of list, in average character widths #ifdef SCI_LEXER LexState *DocumentLexState(); void SetLexer(uptr_t wParam); void SetLexerLanguage(const char *languageName); void Colourise(int start, int end); #endif ScintillaBase(); virtual ~ScintillaBase(); virtual void Initialise() = 0; virtual void Finalise() = 0; virtual void AddCharUTF(char *s, unsigned int len, bool treatAsDBCS=false); void Command(int cmdId); virtual void CancelModes(); virtual int KeyCommand(unsigned int iMessage); void AutoCompleteStart(int lenEntered, const char *list); void AutoCompleteCancel(); void AutoCompleteMove(int delta); int AutoCompleteGetCurrent(); int AutoCompleteGetCurrentText(char *buffer); void AutoCompleteCharacterAdded(char ch); void AutoCompleteCharacterDeleted(); void AutoCompleteCompleted(); void AutoCompleteMoveToCurrentWord(); static void AutoCompleteDoubleClick(void *p); void CallTipClick(); void CallTipShow(Point pt, const char *defn); virtual void CreateCallTipWindow(PRectangle rc) = 0; virtual void AddToPopUp(const char *label, int cmd=0, bool enabled=true) = 0; void ContextMenu(Point pt); virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt); void NotifyStyleToNeeded(int endStyleNeeded); void NotifyLexerChanged(Document *doc, void *userData); public: // Public so scintilla_send_message can use it virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/ScintillaBase.cxx0000644000175000017500000005357211763437013021700 00000000000000// Scintilla source code edit control /** @file ScintillaBase.cxx ** An enhanced subclass of Editor with calltips, autocomplete and context menu. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #include "PropSetSimple.h" #ifdef SCI_LEXER #include "SciLexer.h" #include "LexerModule.h" #include "Catalogue.h" #endif #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "CallTip.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "AutoComplete.h" #include "CharClassify.h" #include "Decoration.h" #include "Document.h" #include "Selection.h" #include "PositionCache.h" #include "Editor.h" #include "ScintillaBase.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif ScintillaBase::ScintillaBase() { displayPopupMenu = true; listType = 0; maxListWidth = 0; } ScintillaBase::~ScintillaBase() { } void ScintillaBase::Finalise() { Editor::Finalise(); popup.Destroy(); } void ScintillaBase::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { bool isFillUp = ac.Active() && ac.IsFillUpChar(*s); if (!isFillUp) { Editor::AddCharUTF(s, len, treatAsDBCS); } if (ac.Active()) { AutoCompleteCharacterAdded(s[0]); // For fill ups add the character after the autocompletion has // triggered so containers see the key so can display a calltip. if (isFillUp) { Editor::AddCharUTF(s, len, treatAsDBCS); } } } void ScintillaBase::Command(int cmdId) { switch (cmdId) { case idAutoComplete: // Nothing to do break; case idCallTip: // Nothing to do break; case idcmdUndo: WndProc(SCI_UNDO, 0, 0); break; case idcmdRedo: WndProc(SCI_REDO, 0, 0); break; case idcmdCut: WndProc(SCI_CUT, 0, 0); break; case idcmdCopy: WndProc(SCI_COPY, 0, 0); break; case idcmdPaste: WndProc(SCI_PASTE, 0, 0); break; case idcmdDelete: WndProc(SCI_CLEAR, 0, 0); break; case idcmdSelectAll: WndProc(SCI_SELECTALL, 0, 0); break; } } int ScintillaBase::KeyCommand(unsigned int iMessage) { // Most key commands cancel autocompletion mode if (ac.Active()) { switch (iMessage) { // Except for these case SCI_LINEDOWN: AutoCompleteMove(1); return 0; case SCI_LINEUP: AutoCompleteMove(-1); return 0; case SCI_PAGEDOWN: AutoCompleteMove(ac.lb->GetVisibleRows()); return 0; case SCI_PAGEUP: AutoCompleteMove(-ac.lb->GetVisibleRows()); return 0; case SCI_VCHOME: AutoCompleteMove(-5000); return 0; case SCI_LINEEND: AutoCompleteMove(5000); return 0; case SCI_DELETEBACK: DelCharBack(true); AutoCompleteCharacterDeleted(); EnsureCaretVisible(); return 0; case SCI_DELETEBACKNOTLINE: DelCharBack(false); AutoCompleteCharacterDeleted(); EnsureCaretVisible(); return 0; case SCI_TAB: AutoCompleteCompleted(); return 0; case SCI_NEWLINE: AutoCompleteCompleted(); return 0; default: AutoCompleteCancel(); } } if (ct.inCallTipMode) { if ( (iMessage != SCI_CHARLEFT) && (iMessage != SCI_CHARLEFTEXTEND) && (iMessage != SCI_CHARRIGHT) && (iMessage != SCI_CHARRIGHTEXTEND) && (iMessage != SCI_EDITTOGGLEOVERTYPE) && (iMessage != SCI_DELETEBACK) && (iMessage != SCI_DELETEBACKNOTLINE) ) { ct.CallTipCancel(); } if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) { if (sel.MainCaret() <= ct.posStartCallTip) { ct.CallTipCancel(); } } } return Editor::KeyCommand(iMessage); } void ScintillaBase::AutoCompleteDoubleClick(void *p) { ScintillaBase *sci = reinterpret_cast(p); sci->AutoCompleteCompleted(); } void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) { //Platform::DebugPrintf("AutoComplete %s\n", list); ct.CallTipCancel(); if (ac.chooseSingle && (listType == 0)) { if (list && !strchr(list, ac.GetSeparator())) { const char *typeSep = strchr(list, ac.GetTypesep()); int lenInsert = typeSep ? static_cast(typeSep-list) : static_cast(strlen(list)); if (ac.ignoreCase) { SetEmptySelection(sel.MainCaret() - lenEntered); pdoc->DeleteChars(sel.MainCaret(), lenEntered); SetEmptySelection(sel.MainCaret()); pdoc->InsertString(sel.MainCaret(), list, lenInsert); SetEmptySelection(sel.MainCaret() + lenInsert); } else { SetEmptySelection(sel.MainCaret()); pdoc->InsertString(sel.MainCaret(), list + lenEntered, lenInsert - lenEntered); SetEmptySelection(sel.MainCaret() + lenInsert - lenEntered); } return; } } ac.Start(wMain, idAutoComplete, sel.MainCaret(), PointMainCaret(), lenEntered, vs.lineHeight, IsUnicodeMode(), technology); PRectangle rcClient = GetClientRectangle(); Point pt = LocationFromPosition(sel.MainCaret() - lenEntered); PRectangle rcPopupBounds = wMain.GetMonitorRect(pt); if (rcPopupBounds.Height() == 0) rcPopupBounds = rcClient; int heightLB = 100; int widthLB = 100; if (pt.x >= rcClient.right - widthLB) { HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB); Redraw(); pt = PointMainCaret(); } PRectangle rcac; rcac.left = pt.x - ac.lb->CaretFromEdge(); if (pt.y >= rcPopupBounds.bottom - heightLB && // Wont fit below. pt.y >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2) { // and there is more room above. rcac.top = pt.y - heightLB; if (rcac.top < rcPopupBounds.top) { heightLB -= (rcPopupBounds.top - rcac.top); rcac.top = rcPopupBounds.top; } } else { rcac.top = pt.y + vs.lineHeight; } rcac.right = rcac.left + widthLB; rcac.bottom = Platform::Minimum(rcac.top + heightLB, rcPopupBounds.bottom); ac.lb->SetPositionRelative(rcac, wMain); ac.lb->SetFont(vs.styles[STYLE_DEFAULT].font); unsigned int aveCharWidth = vs.styles[STYLE_DEFAULT].aveCharWidth; ac.lb->SetAverageCharWidth(aveCharWidth); ac.lb->SetDoubleClickAction(AutoCompleteDoubleClick, this); ac.SetList(list); // Fiddle the position of the list so it is right next to the target and wide enough for all its strings PRectangle rcList = ac.lb->GetDesiredRect(); int heightAlloced = rcList.bottom - rcList.top; widthLB = Platform::Maximum(widthLB, rcList.right - rcList.left); if (maxListWidth != 0) widthLB = Platform::Minimum(widthLB, aveCharWidth*maxListWidth); // Make an allowance for large strings in list rcList.left = pt.x - ac.lb->CaretFromEdge(); rcList.right = rcList.left + widthLB; if (((pt.y + vs.lineHeight) >= (rcPopupBounds.bottom - heightAlloced)) && // Wont fit below. ((pt.y + vs.lineHeight / 2) >= (rcPopupBounds.bottom + rcPopupBounds.top) / 2)) { // and there is more room above. rcList.top = pt.y - heightAlloced; } else { rcList.top = pt.y + vs.lineHeight; } rcList.bottom = rcList.top + heightAlloced; ac.lb->SetPositionRelative(rcList, wMain); ac.Show(true); if (lenEntered != 0) { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCancel() { if (ac.Active()) { SCNotification scn = {0}; scn.nmhdr.code = SCN_AUTOCCANCELLED; scn.wParam = 0; scn.listType = 0; NotifyParent(scn); } ac.Cancel(); } void ScintillaBase::AutoCompleteMove(int delta) { ac.Move(delta); } void ScintillaBase::AutoCompleteMoveToCurrentWord() { char wordCurrent[1000]; int i; int startWord = ac.posStart - ac.startLen; for (i = startWord; i < sel.MainCaret() && i - startWord < 1000; i++) wordCurrent[i - startWord] = pdoc->CharAt(i); wordCurrent[Platform::Minimum(i - startWord, 999)] = '\0'; ac.Select(wordCurrent); } void ScintillaBase::AutoCompleteCharacterAdded(char ch) { if (ac.IsFillUpChar(ch)) { AutoCompleteCompleted(); } else if (ac.IsStopChar(ch)) { AutoCompleteCancel(); } else { AutoCompleteMoveToCurrentWord(); } } void ScintillaBase::AutoCompleteCharacterDeleted() { if (sel.MainCaret() < ac.posStart - ac.startLen) { AutoCompleteCancel(); } else if (ac.cancelAtStartPos && (sel.MainCaret() <= ac.posStart)) { AutoCompleteCancel(); } else { AutoCompleteMoveToCurrentWord(); } SCNotification scn = {0}; scn.nmhdr.code = SCN_AUTOCCHARDELETED; scn.wParam = 0; scn.listType = 0; NotifyParent(scn); } void ScintillaBase::AutoCompleteCompleted() { int item = ac.lb->GetSelection(); char selected[1000]; selected[0] = '\0'; if (item != -1) { ac.lb->GetValue(item, selected, sizeof(selected)); } else { AutoCompleteCancel(); return; } ac.Show(false); SCNotification scn = {0}; scn.nmhdr.code = listType > 0 ? SCN_USERLISTSELECTION : SCN_AUTOCSELECTION; scn.message = 0; scn.wParam = listType; scn.listType = listType; Position firstPos = ac.posStart - ac.startLen; scn.position = firstPos; scn.lParam = firstPos; scn.text = selected; NotifyParent(scn); if (!ac.Active()) return; ac.Cancel(); if (listType > 0) return; Position endPos = sel.MainCaret(); if (ac.dropRestOfWord) endPos = pdoc->ExtendWordSelect(endPos, 1, true); if (endPos < firstPos) return; UndoGroup ug(pdoc); if (endPos != firstPos) { pdoc->DeleteChars(firstPos, endPos - firstPos); } SetEmptySelection(ac.posStart); if (item != -1) { pdoc->InsertCString(firstPos, selected); SetEmptySelection(firstPos + static_cast(strlen(selected))); } SetLastXChosen(); } int ScintillaBase::AutoCompleteGetCurrent() { if (!ac.Active()) return -1; return ac.lb->GetSelection(); } int ScintillaBase::AutoCompleteGetCurrentText(char *buffer) { if (ac.Active()) { int item = ac.lb->GetSelection(); char selected[1000]; selected[0] = '\0'; if (item != -1) { ac.lb->GetValue(item, selected, sizeof(selected)); if (buffer != NULL) strcpy(buffer, selected); return static_cast(strlen(selected)); } } if (buffer != NULL) *buffer = '\0'; return 0; } void ScintillaBase::CallTipShow(Point pt, const char *defn) { ac.Cancel(); // If container knows about STYLE_CALLTIP then use it in place of the // STYLE_DEFAULT for the face name, size and character set. Also use it // for the foreground and background colour. int ctStyle = ct.UseStyleCallTip() ? STYLE_CALLTIP : STYLE_DEFAULT; if (ct.UseStyleCallTip()) { ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back); } PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt, vs.lineHeight, defn, vs.styles[ctStyle].fontName, vs.styles[ctStyle].sizeZoomed, CodePage(), vs.styles[ctStyle].characterSet, vs.technology, wMain); // If the call-tip window would be out of the client // space PRectangle rcClient = GetClientRectangle(); int offset = vs.lineHeight + rc.Height(); // adjust so it displays below the text. if (rc.top < rcClient.top) { rc.top += offset; rc.bottom += offset; } // adjust so it displays above the text. if (rc.bottom > rcClient.bottom) { rc.top -= offset; rc.bottom -= offset; } // Now display the window. CreateCallTipWindow(rc); ct.wCallTip.SetPositionRelative(rc, wMain); ct.wCallTip.Show(); } void ScintillaBase::CallTipClick() { SCNotification scn = {0}; scn.nmhdr.code = SCN_CALLTIPCLICK; scn.position = ct.clickPlace; NotifyParent(scn); } void ScintillaBase::ContextMenu(Point pt) { if (displayPopupMenu) { bool writable = !WndProc(SCI_GETREADONLY, 0, 0); popup.CreatePopUp(); AddToPopUp("Undo", idcmdUndo, writable && pdoc->CanUndo()); AddToPopUp("Redo", idcmdRedo, writable && pdoc->CanRedo()); AddToPopUp(""); AddToPopUp("Cut", idcmdCut, writable && !sel.Empty()); AddToPopUp("Copy", idcmdCopy, !sel.Empty()); AddToPopUp("Paste", idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0)); AddToPopUp("Delete", idcmdDelete, writable && !sel.Empty()); AddToPopUp(""); AddToPopUp("Select All", idcmdSelectAll); popup.Show(pt, wMain); } } void ScintillaBase::CancelModes() { AutoCompleteCancel(); ct.CallTipCancel(); Editor::CancelModes(); } void ScintillaBase::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { CancelModes(); Editor::ButtonDown(pt, curTime, shift, ctrl, alt); } #ifdef SCI_LEXER #ifdef SCI_NAMESPACE namespace Scintilla { #endif class LexState : public LexInterface { const LexerModule *lexCurrent; void SetLexerModule(const LexerModule *lex); PropSetSimple props; public: int lexLanguage; LexState(Document *pdoc_); virtual ~LexState(); void SetLexer(uptr_t wParam); void SetLexerLanguage(const char *languageName); const char *DescribeWordListSets(); void SetWordList(int n, const char *wl); int GetStyleBitsNeeded() const; const char *GetName() const; void *PrivateCall(int operation, void *pointer); const char *PropertyNames(); int PropertyType(const char *name); const char *DescribeProperty(const char *name); void PropSet(const char *key, const char *val); const char *PropGet(const char *key) const; int PropGetInt(const char *key, int defaultValue=0) const; int PropGetExpanded(const char *key, char *result) const; }; #ifdef SCI_NAMESPACE } #endif LexState::LexState(Document *pdoc_) : LexInterface(pdoc_) { lexCurrent = 0; performingStyle = false; lexLanguage = SCLEX_CONTAINER; } LexState::~LexState() { if (instance) { instance->Release(); instance = 0; } } LexState *ScintillaBase::DocumentLexState() { if (!pdoc->pli) { pdoc->pli = new LexState(pdoc); } return static_cast(pdoc->pli); } void LexState::SetLexerModule(const LexerModule *lex) { if (lex != lexCurrent) { if (instance) { instance->Release(); instance = 0; } lexCurrent = lex; if (lexCurrent) instance = lexCurrent->Create(); pdoc->LexerChanged(); } } void LexState::SetLexer(uptr_t wParam) { lexLanguage = wParam; if (lexLanguage == SCLEX_CONTAINER) { SetLexerModule(0); } else { const LexerModule *lex = Catalogue::Find(lexLanguage); if (!lex) lex = Catalogue::Find(SCLEX_NULL); SetLexerModule(lex); } } void LexState::SetLexerLanguage(const char *languageName) { const LexerModule *lex = Catalogue::Find(languageName); if (!lex) lex = Catalogue::Find(SCLEX_NULL); if (lex) lexLanguage = lex->GetLanguage(); SetLexerModule(lex); } const char *LexState::DescribeWordListSets() { if (instance) { return instance->DescribeWordListSets(); } else { return 0; } } void LexState::SetWordList(int n, const char *wl) { if (instance) { int firstModification = instance->WordListSet(n, wl); if (firstModification >= 0) { pdoc->ModifiedAt(firstModification); } } } int LexState::GetStyleBitsNeeded() const { return lexCurrent ? lexCurrent->GetStyleBitsNeeded() : 5; } const char *LexState::GetName() const { return lexCurrent ? lexCurrent->languageName : ""; } void *LexState::PrivateCall(int operation, void *pointer) { if (pdoc && instance) { return instance->PrivateCall(operation, pointer); } else { return 0; } } const char *LexState::PropertyNames() { if (instance) { return instance->PropertyNames(); } else { return 0; } } int LexState::PropertyType(const char *name) { if (instance) { return instance->PropertyType(name); } else { return SC_TYPE_BOOLEAN; } } const char *LexState::DescribeProperty(const char *name) { if (instance) { return instance->DescribeProperty(name); } else { return 0; } } void LexState::PropSet(const char *key, const char *val) { props.Set(key, val); if (instance) { int firstModification = instance->PropertySet(key, val); if (firstModification >= 0) { pdoc->ModifiedAt(firstModification); } } } const char *LexState::PropGet(const char *key) const { return props.Get(key); } int LexState::PropGetInt(const char *key, int defaultValue) const { return props.GetInt(key, defaultValue); } int LexState::PropGetExpanded(const char *key, char *result) const { return props.GetExpanded(key, result); } #endif void ScintillaBase::NotifyStyleToNeeded(int endStyleNeeded) { #ifdef SCI_LEXER if (DocumentLexState()->lexLanguage != SCLEX_CONTAINER) { int lineEndStyled = pdoc->LineFromPosition(pdoc->GetEndStyled()); int endStyled = pdoc->LineStart(lineEndStyled); DocumentLexState()->Colourise(endStyled, endStyleNeeded); return; } #endif Editor::NotifyStyleToNeeded(endStyleNeeded); } void ScintillaBase::NotifyLexerChanged(Document *, void *) { #ifdef SCI_LEXER int bits = DocumentLexState()->GetStyleBitsNeeded(); vs.EnsureStyle((1 << bits) - 1); #endif } sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { switch (iMessage) { case SCI_AUTOCSHOW: listType = 0; AutoCompleteStart(wParam, reinterpret_cast(lParam)); break; case SCI_AUTOCCANCEL: ac.Cancel(); break; case SCI_AUTOCACTIVE: return ac.Active(); case SCI_AUTOCPOSSTART: return ac.posStart; case SCI_AUTOCCOMPLETE: AutoCompleteCompleted(); break; case SCI_AUTOCSETSEPARATOR: ac.SetSeparator(static_cast(wParam)); break; case SCI_AUTOCGETSEPARATOR: return ac.GetSeparator(); case SCI_AUTOCSTOPS: ac.SetStopChars(reinterpret_cast(lParam)); break; case SCI_AUTOCSELECT: ac.Select(reinterpret_cast(lParam)); break; case SCI_AUTOCGETCURRENT: return AutoCompleteGetCurrent(); case SCI_AUTOCGETCURRENTTEXT: return AutoCompleteGetCurrentText(reinterpret_cast(lParam)); case SCI_AUTOCSETCANCELATSTART: ac.cancelAtStartPos = wParam != 0; break; case SCI_AUTOCGETCANCELATSTART: return ac.cancelAtStartPos; case SCI_AUTOCSETFILLUPS: ac.SetFillUpChars(reinterpret_cast(lParam)); break; case SCI_AUTOCSETCHOOSESINGLE: ac.chooseSingle = wParam != 0; break; case SCI_AUTOCGETCHOOSESINGLE: return ac.chooseSingle; case SCI_AUTOCSETIGNORECASE: ac.ignoreCase = wParam != 0; break; case SCI_AUTOCGETIGNORECASE: return ac.ignoreCase; case SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR: ac.ignoreCaseBehaviour = wParam; break; case SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR: return ac.ignoreCaseBehaviour; case SCI_USERLISTSHOW: listType = wParam; AutoCompleteStart(0, reinterpret_cast(lParam)); break; case SCI_AUTOCSETAUTOHIDE: ac.autoHide = wParam != 0; break; case SCI_AUTOCGETAUTOHIDE: return ac.autoHide; case SCI_AUTOCSETDROPRESTOFWORD: ac.dropRestOfWord = wParam != 0; break; case SCI_AUTOCGETDROPRESTOFWORD: return ac.dropRestOfWord; case SCI_AUTOCSETMAXHEIGHT: ac.lb->SetVisibleRows(wParam); break; case SCI_AUTOCGETMAXHEIGHT: return ac.lb->GetVisibleRows(); case SCI_AUTOCSETMAXWIDTH: maxListWidth = wParam; break; case SCI_AUTOCGETMAXWIDTH: return maxListWidth; case SCI_REGISTERIMAGE: ac.lb->RegisterImage(wParam, reinterpret_cast(lParam)); break; case SCI_REGISTERRGBAIMAGE: ac.lb->RegisterRGBAImage(wParam, sizeRGBAImage.x, sizeRGBAImage.y, reinterpret_cast(lParam)); break; case SCI_CLEARREGISTEREDIMAGES: ac.lb->ClearRegisteredImages(); break; case SCI_AUTOCSETTYPESEPARATOR: ac.SetTypesep(static_cast(wParam)); break; case SCI_AUTOCGETTYPESEPARATOR: return ac.GetTypesep(); case SCI_CALLTIPSHOW: CallTipShow(LocationFromPosition(wParam), reinterpret_cast(lParam)); break; case SCI_CALLTIPCANCEL: ct.CallTipCancel(); break; case SCI_CALLTIPACTIVE: return ct.inCallTipMode; case SCI_CALLTIPPOSSTART: return ct.posStartCallTip; case SCI_CALLTIPSETHLT: ct.SetHighlight(wParam, lParam); break; case SCI_CALLTIPSETBACK: ct.colourBG = ColourDesired(wParam); vs.styles[STYLE_CALLTIP].back = ct.colourBG; InvalidateStyleRedraw(); break; case SCI_CALLTIPSETFORE: ct.colourUnSel = ColourDesired(wParam); vs.styles[STYLE_CALLTIP].fore = ct.colourUnSel; InvalidateStyleRedraw(); break; case SCI_CALLTIPSETFOREHLT: ct.colourSel = ColourDesired(wParam); InvalidateStyleRedraw(); break; case SCI_CALLTIPUSESTYLE: ct.SetTabSize((int)wParam); InvalidateStyleRedraw(); break; case SCI_CALLTIPSETPOSITION: ct.SetPosition(wParam != 0); InvalidateStyleRedraw(); break; case SCI_USEPOPUP: displayPopupMenu = wParam != 0; break; #ifdef SCI_LEXER case SCI_SETLEXER: DocumentLexState()->SetLexer(wParam); break; case SCI_GETLEXER: return DocumentLexState()->lexLanguage; case SCI_COLOURISE: if (DocumentLexState()->lexLanguage == SCLEX_CONTAINER) { pdoc->ModifiedAt(wParam); NotifyStyleToNeeded((lParam == -1) ? pdoc->Length() : lParam); } else { DocumentLexState()->Colourise(wParam, lParam); } Redraw(); break; case SCI_SETPROPERTY: DocumentLexState()->PropSet(reinterpret_cast(wParam), reinterpret_cast(lParam)); break; case SCI_GETPROPERTY: return StringResult(lParam, DocumentLexState()->PropGet(reinterpret_cast(wParam))); case SCI_GETPROPERTYEXPANDED: return DocumentLexState()->PropGetExpanded(reinterpret_cast(wParam), reinterpret_cast(lParam)); case SCI_GETPROPERTYINT: return DocumentLexState()->PropGetInt(reinterpret_cast(wParam), lParam); case SCI_SETKEYWORDS: DocumentLexState()->SetWordList(wParam, reinterpret_cast(lParam)); break; case SCI_SETLEXERLANGUAGE: DocumentLexState()->SetLexerLanguage(reinterpret_cast(lParam)); break; case SCI_GETLEXERLANGUAGE: return StringResult(lParam, DocumentLexState()->GetName()); case SCI_PRIVATELEXERCALL: return reinterpret_cast( DocumentLexState()->PrivateCall(wParam, reinterpret_cast(lParam))); case SCI_GETSTYLEBITSNEEDED: return DocumentLexState()->GetStyleBitsNeeded(); case SCI_PROPERTYNAMES: return StringResult(lParam, DocumentLexState()->PropertyNames()); case SCI_PROPERTYTYPE: return DocumentLexState()->PropertyType(reinterpret_cast(wParam)); case SCI_DESCRIBEPROPERTY: return StringResult(lParam, DocumentLexState()->DescribeProperty(reinterpret_cast(wParam))); case SCI_DESCRIBEKEYWORDSETS: return StringResult(lParam, DocumentLexState()->DescribeWordListSets()); #endif default: return Editor::WndProc(iMessage, wParam, lParam); } return 0l; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Style.h0000644000175000017500000000406611726020232017670 00000000000000// Scintilla source code edit control /** @file Style.h ** Defines the font and colour style for a class of text. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef STYLE_H #define STYLE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif struct FontSpecification { const char *fontName; int weight; bool italic; int size; int characterSet; int extraFontFlag; FontSpecification() : fontName(0), weight(SC_WEIGHT_NORMAL), italic(false), size(10 * SC_FONT_SIZE_MULTIPLIER), characterSet(0), extraFontFlag(0) { } bool EqualTo(const FontSpecification &other) const; }; // Just like Font but only has a copy of the FontID so should not delete it class FontAlias : public Font { // Private so FontAlias objects can not be copied FontAlias(const FontAlias &); FontAlias &operator=(const FontAlias &); public: FontAlias(); virtual ~FontAlias(); void MakeAlias(Font &fontOrigin); void ClearFont(); }; struct FontMeasurements { unsigned int ascent; unsigned int descent; XYPOSITION aveCharWidth; XYPOSITION spaceWidth; int sizeZoomed; FontMeasurements(); void Clear(); }; /** */ class Style : public FontSpecification, public FontMeasurements { public: ColourDesired fore; ColourDesired back; bool eolFilled; bool underline; enum ecaseForced {caseMixed, caseUpper, caseLower}; ecaseForced caseForce; bool visible; bool changeable; bool hotspot; FontAlias font; Style(); Style(const Style &source); ~Style(); Style &operator=(const Style &source); void Clear(ColourDesired fore_, ColourDesired back_, int size_, const char *fontName_, int characterSet_, int weight_, bool italic_, bool eolFilled_, bool underline_, ecaseForced caseForce_, bool visible_, bool changeable_, bool hotspot_); void ClearTo(const Style &source); void Copy(Font &font_, const FontMeasurements &fm_); bool IsProtected() const { return !(changeable && visible);} }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/XPM.cxx0000644000175000017500000002244711717550114017621 00000000000000// Scintilla source code edit control /** @file XPM.cxx ** Define a class that holds data in the X Pixmap (XPM) format. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "XPM.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static const char *NextField(const char *s) { // In case there are leading spaces in the string while (*s && *s == ' ') { s++; } while (*s && *s != ' ') { s++; } while (*s && *s == ' ') { s++; } return s; } // Data lines in XPM can be terminated either with NUL or " static size_t MeasureLength(const char *s) { size_t i = 0; while (s[i] && (s[i] != '\"')) i++; return i; } ColourDesired XPM::ColourDesiredFromCode(int ch) const { return *colourCodeTable[ch]; } ColourDesired XPM::ColourFromCode(int ch) const { return *colourCodeTable[ch]; } void XPM::FillRun(Surface *surface, int code, int startX, int y, int x) { if ((code != codeTransparent) && (startX != x)) { PRectangle rc(startX, y, x, y+1); surface->FillRectangle(rc, ColourFromCode(code)); } } XPM::XPM(const char *textForm) : data(0), codes(0), colours(0), lines(0) { Init(textForm); } XPM::XPM(const char *const *linesForm) : data(0), codes(0), colours(0), lines(0) { Init(linesForm); } XPM::~XPM() { Clear(); } void XPM::Init(const char *textForm) { Clear(); // Test done is two parts to avoid possibility of overstepping the memory // if memcmp implemented strangely. Must be 4 bytes at least at destination. if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) { // Build the lines form out of the text form const char **linesForm = LinesFormFromTextForm(textForm); if (linesForm != 0) { Init(linesForm); delete []linesForm; } } else { // It is really in line form Init(reinterpret_cast(textForm)); } } void XPM::Init(const char *const *linesForm) { Clear(); height = 1; width = 1; nColours = 1; data = NULL; codeTransparent = ' '; codes = NULL; colours = NULL; lines = NULL; if (!linesForm) return; const char *line0 = linesForm[0]; width = atoi(line0); line0 = NextField(line0); height = atoi(line0); line0 = NextField(line0); nColours = atoi(line0); line0 = NextField(line0); if (atoi(line0) != 1) { // Only one char per pixel is supported return; } codes = new char[nColours]; colours = new ColourDesired[nColours]; int strings = 1+height+nColours; lines = new char *[strings]; size_t allocation = 0; for (int i=0; i(codes[c])] = &(colours[c]); } } void XPM::Clear() { delete []data; data = 0; delete []codes; codes = 0; delete []colours; colours = 0; delete []lines; lines = 0; } void XPM::Draw(Surface *surface, PRectangle &rc) { if (!data || !codes || !colours || !lines) { return; } // Centre the pixmap int startY = rc.top + (rc.Height() - height) / 2; int startX = rc.left + (rc.Width() - width) / 2; for (int y=0; y= width) || (y<0) || (y >= height)) { colour = 0; transparent = true; return; } int code = lines[y+nColours+1][x]; transparent = code == codeTransparent; if (transparent) { colour = 0; } else { colour = ColourDesiredFromCode(code).AsLong(); } } const char **XPM::LinesFormFromTextForm(const char *textForm) { // Build the lines form out of the text form const char **linesForm = 0; int countQuotes = 0; int strings=1; int j=0; for (; countQuotes < (2*strings) && textForm[j] != '\0'; j++) { if (textForm[j] == '\"') { if (countQuotes == 0) { // First field: width, height, number of colors, chars per pixel const char *line0 = textForm + j + 1; // Skip width line0 = NextField(line0); // Add 1 line for each pixel of height strings += atoi(line0); line0 = NextField(line0); // Add 1 line for each colour strings += atoi(line0); linesForm = new const char *[strings]; if (linesForm == 0) { break; // Memory error! } } if (countQuotes / 2 >= strings) { break; // Bad height or number of colors! } if ((countQuotes & 1) == 0) { linesForm[countQuotes / 2] = textForm + j + 1; } countQuotes++; } } if (textForm[j] == '\0' || countQuotes / 2 > strings) { // Malformed XPM! Height + number of colors too high or too low delete []linesForm; linesForm = 0; } return linesForm; } // In future, may want to minimize search time by sorting and using a binary search. XPMSet::XPMSet() : set(0), len(0), maximum(0), height(-1), width(-1) { } XPMSet::~XPMSet() { Clear(); } void XPMSet::Clear() { for (int i = 0; i < len; i++) { delete set[i]; } delete []set; set = 0; len = 0; maximum = 0; height = -1; width = -1; } void XPMSet::Add(int ident, const char *textForm) { // Invalidate cached dimensions height = -1; width = -1; // Replace if this id already present for (int i = 0; i < len; i++) { if (set[i]->GetId() == ident) { set[i]->Init(textForm); return; } } // Not present, so add to end XPM *pxpm = new XPM(textForm); if (pxpm) { pxpm->SetId(ident); if (len == maximum) { maximum += 64; XPM **setNew = new XPM *[maximum]; for (int i = 0; i < len; i++) { setNew[i] = set[i]; } delete []set; set = setNew; } set[len] = pxpm; len++; } } XPM *XPMSet::Get(int ident) { for (int i = 0; i < len; i++) { if (set[i]->GetId() == ident) { return set[i]; } } return 0; } int XPMSet::GetHeight() { if (height < 0) { for (int i = 0; i < len; i++) { if (height < set[i]->GetHeight()) { height = set[i]->GetHeight(); } } } return (height > 0) ? height : 0; } int XPMSet::GetWidth() { if (width < 0) { for (int i = 0; i < len; i++) { if (width < set[i]->GetWidth()) { width = set[i]->GetWidth(); } } } return (width > 0) ? width : 0; } RGBAImage::RGBAImage(int width_, int height_, const unsigned char *pixels_) : height(height_), width(width_) { if (pixels_) { pixelBytes.assign(pixels_, pixels_ + CountBytes()); } else { pixelBytes.resize(CountBytes()); } } RGBAImage::RGBAImage(const XPM &xpm) { height = xpm.GetHeight(); width = xpm.GetWidth(); pixelBytes.resize(CountBytes()); for (int y=0; ysecond; it->second = 0; } images.clear(); height = -1; width = -1; } /// Add an image. void RGBAImageSet::Add(int ident, RGBAImage *image) { ImageMap::iterator it=images.find(ident); if (it == images.end()) { images[ident] = image; } else { delete it->second; it->second = image; } height = -1; width = -1; } /// Get image by id. RGBAImage *RGBAImageSet::Get(int ident) { ImageMap::iterator it = images.find(ident); if (it != images.end()) { return it->second; } return NULL; } /// Give the largest height of the set. int RGBAImageSet::GetHeight() const { if (height < 0) { for (ImageMap::const_iterator it=images.begin(); it != images.end(); ++it) { if (height < it->second->GetHeight()) { height = it->second->GetHeight(); } } } return (height > 0) ? height : 0; } /// Give the largest width of the set. int RGBAImageSet::GetWidth() const { if (width < 0) { for (ImageMap::const_iterator it=images.begin(); it != images.end(); ++it) { if (width < it->second->GetWidth()) { width = it->second->GetWidth(); } } } return (width > 0) ? width : 0; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Partitioning.h0000644000175000017500000001163611615412040021237 00000000000000// Scintilla source code edit control /** @file Partitioning.h ** Data structure used to partition an interval. Used for holding line start/end positions. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PARTITIONING_H #define PARTITIONING_H /// A split vector of integers with a method for adding a value to all elements /// in a range. /// Used by the Partitioning class. class SplitVectorWithRangeAdd : public SplitVector { public: SplitVectorWithRangeAdd(int growSize_) { SetGrowSize(growSize_); ReAllocate(growSize_); } ~SplitVectorWithRangeAdd() { } void RangeAddDelta(int start, int end, int delta) { // end is 1 past end, so end-start is number of elements to change int i = 0; int rangeLength = end - start; int range1Length = rangeLength; int part1Left = part1Length - start; if (range1Length > part1Left) range1Length = part1Left; while (i < range1Length) { body[start++] += delta; i++; } start += gapLength; while (i < rangeLength) { body[start++] += delta; i++; } } }; /// Divide an interval into multiple partitions. /// Useful for breaking a document down into sections such as lines. /// A 0 length interval has a single 0 length partition, numbered 0 /// If interval not 0 length then each partition non-zero length /// When needed, positions after the interval are considered part of the last partition /// but the end of the last partition can be found with PositionFromPartition(last+1). class Partitioning { private: // To avoid calculating all the partition positions whenever any text is inserted // there may be a step somewhere in the list. int stepPartition; int stepLength; SplitVectorWithRangeAdd *body; // Move step forward void ApplyStep(int partitionUpTo) { if (stepLength != 0) { body->RangeAddDelta(stepPartition+1, partitionUpTo + 1, stepLength); } stepPartition = partitionUpTo; if (stepPartition >= body->Length()-1) { stepPartition = body->Length()-1; stepLength = 0; } } // Move step backward void BackStep(int partitionDownTo) { if (stepLength != 0) { body->RangeAddDelta(partitionDownTo+1, stepPartition+1, -stepLength); } stepPartition = partitionDownTo; } void Allocate(int growSize) { body = new SplitVectorWithRangeAdd(growSize); stepPartition = 0; stepLength = 0; body->Insert(0, 0); // This value stays 0 for ever body->Insert(1, 0); // This is the end of the first partition and will be the start of the second } public: Partitioning(int growSize) { Allocate(growSize); } ~Partitioning() { delete body; body = 0; } int Partitions() const { return body->Length()-1; } void InsertPartition(int partition, int pos) { if (stepPartition < partition) { ApplyStep(partition); } body->Insert(partition, pos); stepPartition++; } void SetPartitionStartPosition(int partition, int pos) { ApplyStep(partition+1); if ((partition < 0) || (partition > body->Length())) { return; } body->SetValueAt(partition, pos); } void InsertText(int partitionInsert, int delta) { // Point all the partitions after the insertion point further along in the buffer if (stepLength != 0) { if (partitionInsert >= stepPartition) { // Fill in up to the new insertion point ApplyStep(partitionInsert); stepLength += delta; } else if (partitionInsert >= (stepPartition - body->Length() / 10)) { // Close to step but before so move step back BackStep(partitionInsert); stepLength += delta; } else { ApplyStep(body->Length()-1); stepPartition = partitionInsert; stepLength = delta; } } else { stepPartition = partitionInsert; stepLength = delta; } } void RemovePartition(int partition) { if (partition > stepPartition) { ApplyStep(partition); stepPartition--; } else { stepPartition--; } body->Delete(partition); } int PositionFromPartition(int partition) const { PLATFORM_ASSERT(partition >= 0); PLATFORM_ASSERT(partition < body->Length()); if ((partition < 0) || (partition >= body->Length())) { return 0; } int pos = body->ValueAt(partition); if (partition > stepPartition) pos += stepLength; return pos; } /// Return value in range [0 .. Partitions() - 1] even for arguments outside interval int PartitionFromPosition(int pos) const { if (body->Length() <= 1) return 0; if (pos >= (PositionFromPartition(body->Length()-1))) return body->Length() - 1 - 1; int lower = 0; int upper = body->Length()-1; do { int middle = (upper + lower + 1) / 2; // Round high int posMiddle = body->ValueAt(middle); if (middle > stepPartition) posMiddle += stepLength; if (pos < posMiddle) { upper = middle - 1; } else { lower = middle; } } while (lower < upper); return lower; } void DeleteAll() { int growSize = body->GetGrowSize(); delete body; Allocate(growSize); } }; #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/PerLine.h0000644000175000017500000000566311640062361020136 00000000000000// Scintilla source code edit control /** @file PerLine.h ** Manages data associated with each line of the document **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PERLINE_H #define PERLINE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** * This holds the marker identifier and the marker type to display. * MarkerHandleNumbers are members of lists. */ struct MarkerHandleNumber { int handle; int number; MarkerHandleNumber *next; }; /** * A marker handle set contains any number of MarkerHandleNumbers. */ class MarkerHandleSet { MarkerHandleNumber *root; public: MarkerHandleSet(); ~MarkerHandleSet(); int Length() const; int NumberFromHandle(int handle) const; int MarkValue() const; ///< Bit set of marker numbers. bool Contains(int handle) const; bool InsertHandle(int handle, int markerNum); void RemoveHandle(int handle); bool RemoveNumber(int markerNum); void CombineWith(MarkerHandleSet *other); }; class LineMarkers : public PerLine { SplitVector markers; /// Handles are allocated sequentially and should never have to be reused as 32 bit ints are very big. int handleCurrent; public: LineMarkers() : handleCurrent(0) { } virtual ~LineMarkers(); virtual void Init(); virtual void InsertLine(int line); virtual void RemoveLine(int line); int MarkValue(int line); int MarkerNext(int lineStart, int mask) const; int AddMark(int line, int marker, int lines); void MergeMarkers(int pos); bool DeleteMark(int line, int markerNum, bool all); void DeleteMarkFromHandle(int markerHandle); int LineFromHandle(int markerHandle); }; class LineLevels : public PerLine { SplitVector levels; public: virtual ~LineLevels(); virtual void Init(); virtual void InsertLine(int line); virtual void RemoveLine(int line); void ExpandLevels(int sizeNew=-1); void ClearLevels(); int SetLevel(int line, int level, int lines); int GetLevel(int line); }; class LineState : public PerLine { SplitVector lineStates; public: LineState() { } virtual ~LineState(); virtual void Init(); virtual void InsertLine(int line); virtual void RemoveLine(int line); int SetLineState(int line, int state); int GetLineState(int line); int GetMaxLineState(); }; class LineAnnotation : public PerLine { SplitVector annotations; public: LineAnnotation() { } virtual ~LineAnnotation(); virtual void Init(); virtual void InsertLine(int line); virtual void RemoveLine(int line); bool AnySet() const; bool MultipleStyles(int line) const; int Style(int line); const char *Text(int line) const; const unsigned char *Styles(int line) const; void SetText(int line, const char *text); void ClearAll(); void SetStyle(int line, int style); void SetStyles(int line, const unsigned char *styles); int Length(int line) const; int Lines(int line) const; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/Decoration.h0000644000175000017500000000260311615412040020651 00000000000000/** @file Decoration.h ** Visual elements added over text. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DECORATION_H #define DECORATION_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class Decoration { public: Decoration *next; RunStyles rs; int indicator; Decoration(int indicator_); ~Decoration(); bool Empty(); }; class DecorationList { int currentIndicator; int currentValue; Decoration *current; int lengthDocument; Decoration *DecorationFromIndicator(int indicator); Decoration *Create(int indicator, int length); void Delete(int indicator); void DeleteAnyEmpty(); public: Decoration *root; bool clickNotified; DecorationList(); ~DecorationList(); void SetCurrentIndicator(int indicator); int GetCurrentIndicator() const { return currentIndicator; } void SetCurrentValue(int value); int GetCurrentValue() const { return currentValue; } // Returns true if some values may have changed bool FillRange(int &position, int value, int &fillLength); void InsertSpace(int position, int insertLength); void DeleteRange(int position, int deleteLength); int AllOnFor(int position); int ValueAt(int indicator, int position); int Start(int indicator, int position); int End(int indicator, int position); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/Selection.cxx0000644000175000017500000002160711615412040021067 00000000000000// Scintilla source code edit control /** @file Selection.cxx ** Classes maintaining the selection. **/ // Copyright 2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "Platform.h" #include "Scintilla.h" #include "Selection.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif void SelectionPosition::MoveForInsertDelete(bool insertion, int startChange, int length) { if (position == startChange) { virtualSpace = 0; } if (insertion) { if (position > startChange) { position += length; } } else { if (position > startChange) { int endDeletion = startChange + length; if (position > endDeletion) { position -= length; } else { position = startChange; virtualSpace = 0; } } } } bool SelectionPosition::operator <(const SelectionPosition &other) const { if (position == other.position) return virtualSpace < other.virtualSpace; else return position < other.position; } bool SelectionPosition::operator >(const SelectionPosition &other) const { if (position == other.position) return virtualSpace > other.virtualSpace; else return position > other.position; } bool SelectionPosition::operator <=(const SelectionPosition &other) const { if (position == other.position && virtualSpace == other.virtualSpace) return true; else return other > *this; } bool SelectionPosition::operator >=(const SelectionPosition &other) const { if (position == other.position && virtualSpace == other.virtualSpace) return true; else return *this > other; } int SelectionRange::Length() const { if (anchor > caret) { return anchor.Position() - caret.Position(); } else { return caret.Position() - anchor.Position(); } } bool SelectionRange::Contains(int pos) const { if (anchor > caret) return (pos >= caret.Position()) && (pos <= anchor.Position()); else return (pos >= anchor.Position()) && (pos <= caret.Position()); } bool SelectionRange::Contains(SelectionPosition sp) const { if (anchor > caret) return (sp >= caret) && (sp <= anchor); else return (sp >= anchor) && (sp <= caret); } bool SelectionRange::ContainsCharacter(int posCharacter) const { if (anchor > caret) return (posCharacter >= caret.Position()) && (posCharacter < anchor.Position()); else return (posCharacter >= anchor.Position()) && (posCharacter < caret.Position()); } SelectionSegment SelectionRange::Intersect(SelectionSegment check) const { SelectionSegment inOrder(caret, anchor); if ((inOrder.start <= check.end) || (inOrder.end >= check.start)) { SelectionSegment portion = check; if (portion.start < inOrder.start) portion.start = inOrder.start; if (portion.end > inOrder.end) portion.end = inOrder.end; if (portion.start > portion.end) return SelectionSegment(); else return portion; } else { return SelectionSegment(); } } bool SelectionRange::Trim(SelectionRange range) { SelectionPosition startRange = range.Start(); SelectionPosition endRange = range.End(); SelectionPosition start = Start(); SelectionPosition end = End(); PLATFORM_ASSERT(start <= end); PLATFORM_ASSERT(startRange <= endRange); if ((startRange <= end) && (endRange >= start)) { if ((start > startRange) && (end < endRange)) { // Completely covered by range -> empty at start end = start; } else if ((start < startRange) && (end > endRange)) { // Completely covers range -> empty at start end = start; } else if (start <= startRange) { // Trim end end = startRange; } else { // PLATFORM_ASSERT(end >= endRange); // Trim start start = endRange; } if (anchor > caret) { caret = start; anchor = end; } else { anchor = start; caret = end; } return Empty(); } else { return false; } } // If range is all virtual collapse to start of virtual space void SelectionRange::MinimizeVirtualSpace() { if (caret.Position() == anchor.Position()) { int virtualSpace = caret.VirtualSpace(); if (virtualSpace > anchor.VirtualSpace()) virtualSpace = anchor.VirtualSpace(); caret.SetVirtualSpace(virtualSpace); anchor.SetVirtualSpace(virtualSpace); } } Selection::Selection() : mainRange(0), moveExtends(false), tentativeMain(false), selType(selStream) { AddSelection(SelectionPosition(0)); } Selection::~Selection() { } bool Selection::IsRectangular() const { return (selType == selRectangle) || (selType == selThin); } int Selection::MainCaret() const { return ranges[mainRange].caret.Position(); } int Selection::MainAnchor() const { return ranges[mainRange].anchor.Position(); } SelectionRange &Selection::Rectangular() { return rangeRectangular; } SelectionSegment Selection::Limits() const { if (ranges.empty()) { return SelectionSegment(); } else { SelectionSegment sr(ranges[0].anchor, ranges[0].caret); for (size_t i=1; i ranges[i].Start().Position()) && (pos <= ranges[i].End().Position())) return i == mainRange ? 1 : 2; } return 0; } int Selection::VirtualSpaceFor(int pos) const { int virtualSpace = 0; for (size_t i=0; i= j) mainRange--; } else { j++; } } } } } void Selection::RotateMain() { mainRange = (mainRange + 1) % ranges.size(); } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Indicator.h0000644000175000017500000000135311640062361020504 00000000000000// Scintilla source code edit control /** @file Indicator.h ** Defines the style of indicators which are text decorations such as underlining. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef INDICATOR_H #define INDICATOR_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class Indicator { public: int style; bool under; ColourDesired fore; int fillAlpha; int outlineAlpha; Indicator() : style(INDIC_PLAIN), under(false), fore(ColourDesired(0,0,0)), fillAlpha(30), outlineAlpha(50) { } void Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/Editor.h0000644000175000017500000004622711763437013020035 00000000000000// Scintilla source code edit control /** @file Editor.h ** Defines the main editor class. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef EDITOR_H #define EDITOR_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class Caret { public: bool active; bool on; int period; Caret(); }; /** */ class Timer { public: bool ticking; int ticksToWait; enum {tickSize = 100}; TickerID tickerID; Timer(); }; /** */ class Idler { public: bool state; IdlerID idlerID; Idler(); }; /** * When platform has a way to generate an event before painting, * accumulate needed styling range in StyleNeeded to avoid unnecessary work. */ class StyleNeeded { public: bool active; Position upTo; StyleNeeded() : active(false), upTo(0) {} void Reset() { active = false; upTo = 0; } void NeedUpTo(Position pos) { if (upTo < pos) upTo = pos; } }; /** * Hold a piece of text selected for copying or dragging. * The text is expected to hold a terminating '\0' and this is counted in len. */ class SelectionText { public: char *s; int len; bool rectangular; bool lineCopy; int codePage; int characterSet; SelectionText() : s(0), len(0), rectangular(false), lineCopy(false), codePage(0), characterSet(0) {} ~SelectionText() { Free(); } void Free() { Set(0, 0, 0, 0, false, false); } void Set(char *s_, int len_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) { delete []s; s = s_; if (s) len = len_; else len = 0; codePage = codePage_; characterSet = characterSet_; rectangular = rectangular_; lineCopy = lineCopy_; } void Copy(const char *s_, int len_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) { delete []s; s = 0; s = new char[len_]; len = len_; for (int i = 0; i < len_; i++) { s[i] = s_[i]; } codePage = codePage_; characterSet = characterSet_; rectangular = rectangular_; lineCopy = lineCopy_; } void Copy(const SelectionText &other) { Copy(other.s, other.len, other.codePage, other.characterSet, other.rectangular, other.lineCopy); } }; /** */ class Editor : public DocWatcher { // Private so Editor objects can not be copied Editor(const Editor &); Editor &operator=(const Editor &); protected: // ScintillaBase subclass needs access to much of Editor /** On GTK+, Scintilla is a container widget holding two scroll bars * whereas on Windows there is just one window with both scroll bars turned on. */ Window wMain; ///< The Scintilla parent window /** Style resources may be expensive to allocate so are cached between uses. * When a style attribute is changed, this cache is flushed. */ bool stylesValid; ViewStyle vs; int technology; Point sizeRGBAImage; int printMagnification; int printColourMode; int printWrapState; int cursorMode; int controlCharSymbol; // Highlight current folding block HighlightDelimiter highlightDelimiter; bool hasFocus; bool hideSelection; bool inOverstrike; bool mouseDownCaptures; /** In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to * the screen. This avoids flashing but is about 30% slower. */ bool bufferedDraw; /** In twoPhaseDraw mode, drawing is performed in two phases, first the background * and then the foreground. This avoids chopping off characters that overlap the next run. */ bool twoPhaseDraw; int xOffset; ///< Horizontal scrolled amount in pixels int xCaretMargin; ///< Ensure this many pixels visible on both sides of caret bool horizontalScrollBarVisible; int scrollWidth; bool trackLineWidth; int lineWidthMaxSeen; bool verticalScrollBarVisible; bool endAtLastLine; int caretSticky; int marginOptions; bool multipleSelection; bool additionalSelectionTyping; int multiPasteMode; bool additionalCaretsBlink; bool additionalCaretsVisible; int virtualSpaceOptions; Surface *pixmapLine; Surface *pixmapSelMargin; Surface *pixmapSelPattern; Surface *pixmapIndentGuide; Surface *pixmapIndentGuideHighlight; LineLayoutCache llc; PositionCache posCache; KeyMap kmap; Caret caret; Timer timer; Timer autoScrollTimer; enum { autoScrollDelay = 200 }; Idler idler; Point lastClick; unsigned int lastClickTime; int dwellDelay; int ticksToDwell; bool dwelling; enum { selChar, selWord, selSubLine, selWholeLine } selectionType; Point ptMouseLast; enum { ddNone, ddInitial, ddDragging } inDragDrop; bool dropWentOutside; SelectionPosition posDrag; SelectionPosition posDrop; int hotSpotClickPos; int lastXChosen; int lineAnchorPos; int originalAnchorPos; int wordSelectAnchorStartPos; int wordSelectAnchorEndPos; int wordSelectInitialCaretPos; int targetStart; int targetEnd; int searchFlags; int topLine; int posTopLine; int lengthForEncode; int needUpdateUI; Position braces[2]; int bracesMatchStyle; int highlightGuideColumn; int theEdge; enum { notPainting, painting, paintAbandoned } paintState; PRectangle rcPaint; bool paintingAllText; bool willRedrawAll; StyleNeeded styleNeeded; int modEventMask; SelectionText drag; Selection sel; bool primarySelection; int caretXPolicy; int caretXSlop; ///< Ensure this many pixels visible on both sides of caret int caretYPolicy; int caretYSlop; ///< Ensure this many lines visible on both sides of caret int visiblePolicy; int visibleSlop; int searchAnchor; bool recordingMacro; int foldFlags; ContractionState cs; // Hotspot support int hsStart; int hsEnd; // Wrapping support enum { eWrapNone, eWrapWord, eWrapChar } wrapState; enum { wrapLineLarge = 0x7ffffff }; int wrapWidth; int wrapStart; int wrapEnd; int wrapVisualFlags; int wrapVisualFlagsLocation; int wrapVisualStartIndent; int wrapIndentMode; // SC_WRAPINDENT_FIXED, _SAME, _INDENT bool convertPastes; Document *pdoc; Editor(); virtual ~Editor(); virtual void Initialise() = 0; virtual void Finalise(); void InvalidateStyleData(); void InvalidateStyleRedraw(); void RefreshStyleData(); void DropGraphics(bool freeObjects); void AllocateGraphics(); virtual PRectangle GetClientRectangle(); PRectangle GetTextRectangle(); int LinesOnScreen(); int LinesToScroll(); int MaxScrollPos(); SelectionPosition ClampPositionIntoDocument(SelectionPosition sp) const; Point LocationFromPosition(SelectionPosition pos); Point LocationFromPosition(int pos); int XFromPosition(int pos); int XFromPosition(SelectionPosition sp); SelectionPosition SPositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false, bool virtualSpace=true); int PositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false); SelectionPosition SPositionFromLineX(int lineDoc, int x); int PositionFromLineX(int line, int x); int LineFromLocation(Point pt); void SetTopLine(int topLineNew); bool AbandonPaint(); void RedrawRect(PRectangle rc); void Redraw(); void RedrawSelMargin(int line=-1, bool allAfter=false); PRectangle RectangleFromRange(int start, int end); void InvalidateRange(int start, int end); bool UserVirtualSpace() const { return ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0); } int CurrentPosition(); bool SelectionEmpty(); SelectionPosition SelectionStart(); SelectionPosition SelectionEnd(); void SetRectangularRange(); void ThinRectangularRange(); void InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection=false); void SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_); void SetSelection(int currentPos_, int anchor_); void SetSelection(SelectionPosition currentPos_); void SetSelection(int currentPos_); void SetEmptySelection(SelectionPosition currentPos_); void SetEmptySelection(int currentPos_); bool RangeContainsProtected(int start, int end) const; bool SelectionContainsProtected(); int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const; SelectionPosition MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd=true) const; int MovePositionTo(SelectionPosition newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true); int MovePositionTo(int newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true); SelectionPosition MovePositionSoVisible(SelectionPosition pos, int moveDir); SelectionPosition MovePositionSoVisible(int pos, int moveDir); Point PointMainCaret(); void SetLastXChosen(); void ScrollTo(int line, bool moveThumb=true); virtual void ScrollText(int linesToMove); void HorizontalScrollTo(int xPos); void VerticalCentreCaret(); void MoveSelectedLines(int lineDelta); void MoveSelectedLinesUp(); void MoveSelectedLinesDown(); void MoveCaretInsideView(bool ensureVisible=true); int DisplayFromPosition(int pos); struct XYScrollPosition { int xOffset; int topLine; XYScrollPosition(int xOffset_, int topLine_) : xOffset(xOffset_), topLine(topLine_) {} }; XYScrollPosition XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz); void SetXYScroll(XYScrollPosition newXY); void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true); void ShowCaretAtCurrentPosition(); void DropCaret(); void InvalidateCaret(); virtual void UpdateSystemCaret(); void NeedWrapping(int docLineStart = 0, int docLineEnd = wrapLineLarge); bool WrapOneLine(Surface *surface, int lineToWrap); bool WrapLines(bool fullWrap, int priorityWrapLineStart); void LinesJoin(); void LinesSplit(int pixelWidth); int SubstituteMarkerIfEmpty(int markerCheck, int markerDefault); void PaintSelMargin(Surface *surface, PRectangle &rc); LineLayout *RetrieveLineLayout(int lineNumber); void LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width=LineLayout::wrapWidthInfinite); ColourDesired SelectionBackground(ViewStyle &vsDraw, bool main); ColourDesired TextBackground(ViewStyle &vsDraw, bool overrideBackground, ColourDesired background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll); void DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight); void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour); void DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll, int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, bool overrideBackground, ColourDesired background, bool drawWrapMark, ColourDesired wrapColour); void DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, ViewStyle &vsDraw, int xStart, PRectangle rcLine, LineLayout *ll, int subLine); void DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under); void DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine); void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, PRectangle rcLine, LineLayout *ll, int subLine); void DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour); void DrawCarets(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine); void RefreshPixMaps(Surface *surfaceWindow); void Paint(Surface *surfaceWindow, PRectangle rcArea); long FormatRange(bool draw, Sci_RangeToFormat *pfr); int TextWidth(int style, const char *text); virtual void SetVerticalScrollPos() = 0; virtual void SetHorizontalScrollPos() = 0; virtual bool ModifyScrollBars(int nMax, int nPage) = 0; virtual void ReconfigureScrollBars(); void SetScrollBars(); void ChangeSize(); void FilterSelections(); int InsertSpace(int position, unsigned int spaces); void AddChar(char ch); virtual void AddCharUTF(char *s, unsigned int len, bool treatAsDBCS=false); void InsertPaste(SelectionPosition selStart, const char *text, int len); void ClearSelection(bool retainMultipleSelections=false); void ClearAll(); void ClearDocumentStyle(); void Cut(); void PasteRectangular(SelectionPosition pos, const char *ptr, int len); virtual void Copy() = 0; virtual void CopyAllowLine(); virtual bool CanPaste(); virtual void Paste() = 0; void Clear(); void SelectAll(); void Undo(); void Redo(); void DelChar(); void DelCharBack(bool allowLineStartDeletion); virtual void ClaimSelection() = 0; virtual void NotifyChange() = 0; virtual void NotifyFocus(bool focus); virtual void SetCtrlID(int identifier); virtual int GetCtrlID() { return ctrlID; } virtual void NotifyParent(SCNotification scn) = 0; virtual void NotifyStyleToNeeded(int endStyleNeeded); void NotifyChar(int ch); void NotifySavePoint(bool isSavePoint); void NotifyModifyAttempt(); virtual void NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt); void NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt); void NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt); void NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt); void NotifyUpdateUI(); void NotifyPainted(); void NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt); bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt); void NotifyNeedShown(int pos, int len); void NotifyDwelling(Point pt, bool state); void NotifyZoom(); void NotifyModifyAttempt(Document *document, void *userData); void NotifySavePoint(Document *document, void *userData, bool atSavePoint); void CheckModificationForWrap(DocModification mh); void NotifyModified(Document *document, DocModification mh, void *userData); void NotifyDeleted(Document *document, void *userData); void NotifyStyleNeeded(Document *doc, void *userData, int endPos); void NotifyLexerChanged(Document *doc, void *userData); void NotifyErrorOccurred(Document *doc, void *userData, int status); void NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam); void ContainerNeedsUpdate(int flags); void PageMove(int direction, Selection::selTypes sel=Selection::noSel, bool stuttered = false); enum { cmSame, cmUpper, cmLower } caseMap; virtual std::string CaseMapString(const std::string &s, int caseMapping); void ChangeCaseOfSelection(int caseMapping); void LineTranspose(); void Duplicate(bool forLine); virtual void CancelModes(); void NewLine(); void CursorUpOrDown(int direction, Selection::selTypes sel=Selection::noSel); void ParaUpOrDown(int direction, Selection::selTypes sel=Selection::noSel); int StartEndDisplayLine(int pos, bool start); virtual int KeyCommand(unsigned int iMessage); virtual int KeyDefault(int /* key */, int /*modifiers*/); int KeyDownWithModifiers(int key, int modifiers, bool *consumed); int KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed=0); void Indent(bool forwards); virtual CaseFolder *CaseFolderForEncoding(); long FindText(uptr_t wParam, sptr_t lParam); void SearchAnchor(); long SearchText(unsigned int iMessage, uptr_t wParam, sptr_t lParam); long SearchInTarget(const char *text, int length); void GoToLine(int lineNo); virtual void CopyToClipboard(const SelectionText &selectedText) = 0; char *CopyRange(int start, int end); void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false); void CopyRangeToClipboard(int start, int end); void CopyText(int length, const char *text); void SetDragPosition(SelectionPosition newPos); virtual void DisplayCursor(Window::Cursor c); virtual bool DragThreshold(Point ptStart, Point ptNow); virtual void StartDrag(); void DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular); /** PositionInSelection returns true if position in selection. */ bool PositionInSelection(int pos); bool PointInSelection(Point pt); bool PointInSelMargin(Point pt); Window::Cursor GetMarginCursor(Point pt); void TrimAndSetSelection(int currentPos_, int anchor_); void LineSelection(int lineCurrentPos_, int lineAnchorPos_, bool wholeLine); void WordSelection(int pos); void DwellEnd(bool mouseMoved); void MouseLeave(); virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt); void ButtonMove(Point pt); void ButtonUp(Point pt, unsigned int curTime, bool ctrl); void Tick(); bool Idle(); virtual void SetTicking(bool on) = 0; virtual bool SetIdle(bool) { return false; } virtual void SetMouseCapture(bool on) = 0; virtual bool HaveMouseCapture() = 0; void SetFocusState(bool focusState); int PositionAfterArea(PRectangle rcArea); void StyleToPositionInView(Position pos); void IdleStyling(); virtual void QueueStyling(int upTo); virtual bool PaintContains(PRectangle rc); bool PaintContainsMargin(); void CheckForChangeOutsidePaint(Range r); void SetBraceHighlight(Position pos0, Position pos1, int matchStyle); void SetAnnotationHeights(int start, int end); void SetDocPointer(Document *document); void SetAnnotationVisible(int visible); void Expand(int &line, bool doExpand); void ToggleContraction(int line); int ContractedFoldNext(int lineStart); void EnsureLineVisible(int lineDoc, bool enforcePolicy); int GetTag(char *tagValue, int tagNumber); int ReplaceTarget(bool replacePatterns, const char *text, int length=-1); bool PositionIsHotspot(int position); bool PointIsHotspot(Point pt); void SetHotSpotRange(Point *pt); void GetHotSpotRange(int &hsStart, int &hsEnd); int CodePage() const; virtual bool ValidCodePage(int /* codePage */) const { return true; } int WrapCount(int line); void AddStyledText(char *buffer, int appendLength); virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) = 0; void StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); sptr_t StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam); static const char *StringFromEOLMode(int eolMode); static sptr_t StringResult(sptr_t lParam, const char *val); public: // Public so the COM thunks can access it. bool IsUnicodeMode() const; // Public so scintilla_send_message can use it. virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); // Public so scintilla_set_id can use it. int ctrlID; // Public so COM methods for drag and drop can set it. int errorStatus; friend class AutoSurface; friend class SelectionLineIterator; }; /** * A smart pointer class to ensure Surfaces are set up and deleted correctly. */ class AutoSurface { private: Surface *surf; public: AutoSurface(Editor *ed, int technology = -1) : surf(0) { if (ed->wMain.GetID()) { surf = Surface::Allocate(technology != -1 ? technology : ed->technology); if (surf) { surf->Init(ed->wMain.GetID()); surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); surf->SetDBCSMode(ed->CodePage()); } } } AutoSurface(SurfaceID sid, Editor *ed, int technology = -1) : surf(0) { if (ed->wMain.GetID()) { surf = Surface::Allocate(technology != -1 ? technology : ed->technology); if (surf) { surf->Init(sid, ed->wMain.GetID()); surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); surf->SetDBCSMode(ed->CodePage()); } } } ~AutoSurface() { delete surf; } Surface *operator->() const { return surf; } operator Surface *() const { return surf; } }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/PositionCache.cxx0000644000175000017500000003720311710634267021706 00000000000000// Scintilla source code edit control /** @file PositionCache.cxx ** Classes for caching layout information. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "ILexer.h" #include "Document.h" #include "Selection.h" #include "PositionCache.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsControlCharacter(int ch) { // iscntrl returns true for lots of chars > 127 which are displayable return ch >= 0 && ch < ' '; } LineLayout::LineLayout(int maxLineLength_) : lineStarts(0), lenLineStarts(0), lineNumber(-1), inCache(false), maxLineLength(-1), numCharsInLine(0), numCharsBeforeEOL(0), validity(llInvalid), xHighlightGuide(0), highlightColumn(0), psel(NULL), containsCaret(false), edgeColumn(0), chars(0), styles(0), styleBitsSet(0), indicators(0), positions(0), hsStart(0), hsEnd(0), widthLine(wrapWidthInfinite), lines(1), wrapIndent(0) { bracePreviousStyles[0] = 0; bracePreviousStyles[1] = 0; Resize(maxLineLength_); } LineLayout::~LineLayout() { Free(); } void LineLayout::Resize(int maxLineLength_) { if (maxLineLength_ > maxLineLength) { Free(); chars = new char[maxLineLength_ + 1]; styles = new unsigned char[maxLineLength_ + 1]; indicators = new char[maxLineLength_ + 1]; // Extra position allocated as sometimes the Windows // GetTextExtentExPoint API writes an extra element. positions = new XYPOSITION[maxLineLength_ + 1 + 1]; maxLineLength = maxLineLength_; } } void LineLayout::Free() { delete []chars; chars = 0; delete []styles; styles = 0; delete []indicators; indicators = 0; delete []positions; positions = 0; delete []lineStarts; lineStarts = 0; } void LineLayout::Invalidate(validLevel validity_) { if (validity > validity_) validity = validity_; } int LineLayout::LineStart(int line) const { if (line <= 0) { return 0; } else if ((line >= lines) || !lineStarts) { return numCharsInLine; } else { return lineStarts[line]; } } int LineLayout::LineLastVisible(int line) const { if (line < 0) { return 0; } else if ((line >= lines-1) || !lineStarts) { return numCharsBeforeEOL; } else { return lineStarts[line+1]; } } bool LineLayout::InLine(int offset, int line) const { return ((offset >= LineStart(line)) && (offset < LineStart(line + 1))) || ((offset == numCharsInLine) && (line == (lines-1))); } void LineLayout::SetLineStart(int line, int start) { if ((line >= lenLineStarts) && (line != 0)) { int newMaxLines = line + 20; int *newLineStarts = new int[newMaxLines]; for (int i = 0; i < newMaxLines; i++) { if (i < lenLineStarts) newLineStarts[i] = lineStarts[i]; else newLineStarts[i] = 0; } delete []lineStarts; lineStarts = newLineStarts; lenLineStarts = newMaxLines; } lineStarts[line] = start; } void LineLayout::SetBracesHighlight(Range rangeLine, Position braces[], char bracesMatchStyle, int xHighlight, bool ignoreStyle) { if (!ignoreStyle && rangeLine.ContainsCharacter(braces[0])) { int braceOffset = braces[0] - rangeLine.start; if (braceOffset < numCharsInLine) { bracePreviousStyles[0] = styles[braceOffset]; styles[braceOffset] = bracesMatchStyle; } } if (!ignoreStyle && rangeLine.ContainsCharacter(braces[1])) { int braceOffset = braces[1] - rangeLine.start; if (braceOffset < numCharsInLine) { bracePreviousStyles[1] = styles[braceOffset]; styles[braceOffset] = bracesMatchStyle; } } if ((braces[0] >= rangeLine.start && braces[1] <= rangeLine.end) || (braces[1] >= rangeLine.start && braces[0] <= rangeLine.end)) { xHighlightGuide = xHighlight; } } void LineLayout::RestoreBracesHighlight(Range rangeLine, Position braces[], bool ignoreStyle) { if (!ignoreStyle && rangeLine.ContainsCharacter(braces[0])) { int braceOffset = braces[0] - rangeLine.start; if (braceOffset < numCharsInLine) { styles[braceOffset] = bracePreviousStyles[0]; } } if (!ignoreStyle && rangeLine.ContainsCharacter(braces[1])) { int braceOffset = braces[1] - rangeLine.start; if (braceOffset < numCharsInLine) { styles[braceOffset] = bracePreviousStyles[1]; } } xHighlightGuide = 0; } int LineLayout::FindBefore(XYPOSITION x, int lower, int upper) const { do { int middle = (upper + lower + 1) / 2; // Round high XYPOSITION posMiddle = positions[middle]; if (x < posMiddle) { upper = middle - 1; } else { lower = middle; } } while (lower < upper); return lower; } int LineLayout::EndLineStyle() const { return styles[numCharsBeforeEOL > 0 ? numCharsBeforeEOL-1 : 0]; } LineLayoutCache::LineLayoutCache() : level(0), length(0), size(0), cache(0), allInvalidated(false), styleClock(-1), useCount(0) { Allocate(0); } LineLayoutCache::~LineLayoutCache() { Deallocate(); } void LineLayoutCache::Allocate(int length_) { PLATFORM_ASSERT(cache == NULL); allInvalidated = false; length = length_; size = length; if (size > 1) { size = (size / 16 + 1) * 16; } if (size > 0) { cache = new LineLayout * [size]; } for (int i = 0; i < size; i++) cache[i] = 0; } void LineLayoutCache::AllocateForLevel(int linesOnScreen, int linesInDoc) { PLATFORM_ASSERT(useCount == 0); int lengthForLevel = 0; if (level == llcCaret) { lengthForLevel = 1; } else if (level == llcPage) { lengthForLevel = linesOnScreen + 1; } else if (level == llcDocument) { lengthForLevel = linesInDoc; } if (lengthForLevel > size) { Deallocate(); Allocate(lengthForLevel); } else { if (lengthForLevel < length) { for (int i = lengthForLevel; i < length; i++) { delete cache[i]; cache[i] = 0; } } length = lengthForLevel; } PLATFORM_ASSERT(length == lengthForLevel); PLATFORM_ASSERT(cache != NULL || length == 0); } void LineLayoutCache::Deallocate() { PLATFORM_ASSERT(useCount == 0); for (int i = 0; i < length; i++) delete cache[i]; delete []cache; cache = 0; length = 0; size = 0; } void LineLayoutCache::Invalidate(LineLayout::validLevel validity_) { if (cache && !allInvalidated) { for (int i = 0; i < length; i++) { if (cache[i]) { cache[i]->Invalidate(validity_); } } if (validity_ == LineLayout::llInvalid) { allInvalidated = true; } } } void LineLayoutCache::SetLevel(int level_) { allInvalidated = false; if ((level_ != -1) && (level != level_)) { level = level_; Deallocate(); } } LineLayout *LineLayoutCache::Retrieve(int lineNumber, int lineCaret, int maxChars, int styleClock_, int linesOnScreen, int linesInDoc) { AllocateForLevel(linesOnScreen, linesInDoc); if (styleClock != styleClock_) { Invalidate(LineLayout::llCheckTextAndStyle); styleClock = styleClock_; } allInvalidated = false; int pos = -1; LineLayout *ret = 0; if (level == llcCaret) { pos = 0; } else if (level == llcPage) { if (lineNumber == lineCaret) { pos = 0; } else if (length > 1) { pos = 1 + (lineNumber % (length - 1)); } } else if (level == llcDocument) { pos = lineNumber; } if (pos >= 0) { PLATFORM_ASSERT(useCount == 0); if (cache && (pos < length)) { if (cache[pos]) { if ((cache[pos]->lineNumber != lineNumber) || (cache[pos]->maxLineLength < maxChars)) { delete cache[pos]; cache[pos] = 0; } } if (!cache[pos]) { cache[pos] = new LineLayout(maxChars); } if (cache[pos]) { cache[pos]->lineNumber = lineNumber; cache[pos]->inCache = true; ret = cache[pos]; useCount++; } } } if (!ret) { ret = new LineLayout(maxChars); ret->lineNumber = lineNumber; } return ret; } void LineLayoutCache::Dispose(LineLayout *ll) { allInvalidated = false; if (ll) { if (!ll->inCache) { delete ll; } else { useCount--; } } } void BreakFinder::Insert(int val) { // Expand if needed if (saeLen >= saeSize) { saeSize *= 2; int *selAndEdgeNew = new int[saeSize]; for (unsigned int j = 0; j= nextBreak) { for (unsigned int j = 0; jj; k--) { selAndEdge[k] = selAndEdge[k-1]; } saeLen++; selAndEdge[j] = val; return; } } // Not less than any so append selAndEdge[saeLen++] = val; } } extern bool BadUTF(const char *s, int len, int &trailBytes); static int NextBadU(const char *s, int p, int len, int &trailBytes) { while (p < len) { p++; if (BadUTF(s + p, len - p, trailBytes)) return p; } return -1; } BreakFinder::BreakFinder(LineLayout *ll_, int lineStart_, int lineEnd_, int posLineStart_, int xStart, bool breakForSelection, Document *pdoc_) : ll(ll_), lineStart(lineStart_), lineEnd(lineEnd_), posLineStart(posLineStart_), nextBreak(lineStart_), saeSize(0), saeLen(0), saeCurrentPos(0), saeNext(0), subBreak(-1), pdoc(pdoc_) { saeSize = 8; selAndEdge = new int[saeSize]; for (unsigned int j=0; j < saeSize; j++) { selAndEdge[j] = 0; } // Search for first visible break // First find the first visible character nextBreak = ll->FindBefore(xStart, lineStart, lineEnd); // Now back to a style break while ((nextBreak > lineStart) && (ll->styles[nextBreak] == ll->styles[nextBreak - 1])) { nextBreak--; } if (breakForSelection) { SelectionPosition posStart(posLineStart); SelectionPosition posEnd(posLineStart + lineEnd); SelectionSegment segmentLine(posStart, posEnd); for (size_t r=0; rpsel->Count(); r++) { SelectionSegment portion = ll->psel->Range(r).Intersect(segmentLine); if (!(portion.start == portion.end)) { if (portion.start.IsValid()) Insert(portion.start.Position() - posLineStart - 1); if (portion.end.IsValid()) Insert(portion.end.Position() - posLineStart - 1); } } } Insert(ll->edgeColumn - 1); Insert(lineEnd - 1); if (pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage)) { int trailBytes=0; for (int pos = -1;;) { pos = NextBadU(ll->chars, pos, lineEnd, trailBytes); if (pos < 0) break; Insert(pos-1); Insert(pos); } } saeNext = (saeLen > 0) ? selAndEdge[0] : -1; } BreakFinder::~BreakFinder() { delete []selAndEdge; } int BreakFinder::First() const { return nextBreak; } int BreakFinder::Next() { if (subBreak == -1) { int prev = nextBreak; while (nextBreak < lineEnd) { if ((ll->styles[nextBreak] != ll->styles[nextBreak + 1]) || (nextBreak == saeNext) || IsControlCharacter(ll->chars[nextBreak]) || IsControlCharacter(ll->chars[nextBreak + 1])) { if (nextBreak == saeNext) { saeCurrentPos++; saeNext = (saeLen > saeCurrentPos) ? selAndEdge[saeCurrentPos] : -1; } nextBreak++; if ((nextBreak - prev) < lengthStartSubdivision) { return nextBreak; } break; } nextBreak++; } if ((nextBreak - prev) < lengthStartSubdivision) { return nextBreak; } subBreak = prev; } // Splitting up a long run from prev to nextBreak in lots of approximately lengthEachSubdivision. // For very long runs add extra breaks after spaces or if no spaces before low punctuation. if ((nextBreak - subBreak) <= lengthEachSubdivision) { subBreak = -1; return nextBreak; } else { subBreak += pdoc->SafeSegment(ll->chars + subBreak, nextBreak-subBreak, lengthEachSubdivision); if (subBreak >= nextBreak) { subBreak = -1; return nextBreak; } else { return subBreak; } } } PositionCacheEntry::PositionCacheEntry() : styleNumber(0), len(0), clock(0), positions(0) { } void PositionCacheEntry::Set(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock_) { Clear(); styleNumber = styleNumber_; len = len_; clock = clock_; if (s_ && positions_) { positions = new XYPOSITION[len + (len + 1) / 2]; for (unsigned int i=0; i(positions_[i]); } memcpy(reinterpret_cast(positions + len), s_, len); } } PositionCacheEntry::~PositionCacheEntry() { Clear(); } void PositionCacheEntry::Clear() { delete []positions; positions = 0; styleNumber = 0; len = 0; clock = 0; } bool PositionCacheEntry::Retrieve(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_) const { if ((styleNumber == styleNumber_) && (len == len_) && (memcmp(reinterpret_cast(positions + len), s_, len)== 0)) { for (unsigned int i=0; i other.clock; } void PositionCacheEntry::ResetClock() { if (clock > 0) { clock = 1; } } PositionCache::PositionCache() { size = 0x400; clock = 1; pces = new PositionCacheEntry[size]; allClear = true; } PositionCache::~PositionCache() { Clear(); delete []pces; } void PositionCache::Clear() { if (!allClear) { for (size_t i=0; i 0) && (len < 30)) { // Only store short strings in the cache so it doesn't churn with // long comments with only a single comment. // Two way associative: try two probe positions. int hashValue = PositionCacheEntry::Hash(styleNumber, s, len); probe = static_cast(hashValue % size); if (pces[probe].Retrieve(styleNumber, s, len, positions)) { return; } int probe2 = static_cast((hashValue * 37) % size); if (pces[probe2].Retrieve(styleNumber, s, len, positions)) { return; } // Not found. Choose the oldest of the two slots to replace if (pces[probe].NewerThan(pces[probe2])) { probe = probe2; } } if (len > BreakFinder::lengthStartSubdivision) { // Break up into segments unsigned int startSegment = 0; XYPOSITION xStartSegment = 0; while (startSegment < len) { unsigned int lenSegment = pdoc->SafeSegment(s + startSegment, len - startSegment, BreakFinder::lengthEachSubdivision); surface->MeasureWidths(vstyle.styles[styleNumber].font, s + startSegment, lenSegment, positions + startSegment); for (unsigned int inSeg = 0; inSeg < lenSegment; inSeg++) { positions[startSegment + inSeg] += xStartSegment; } xStartSegment = positions[startSegment + lenSegment - 1]; startSegment += lenSegment; } } else { surface->MeasureWidths(vstyle.styles[styleNumber].font, s, len, positions); } if (probe >= 0) { clock++; if (clock > 60000) { // Since there are only 16 bits for the clock, wrap it round and // reset all cache entries so none get stuck with a high clock. for (size_t i=0; i // Based on the work of Ozan S. Yigit. // This file is in the public domain. #ifndef RESEARCH_H #define RESEARCH_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /* * The following defines are not meant to be changeable. * They are for readability only. */ #define MAXCHR 256 #define CHRBIT 8 #define BITBLK MAXCHR/CHRBIT class CharacterIndexer { public: virtual char CharAt(int index)=0; virtual ~CharacterIndexer() { } }; class RESearch { public: RESearch(CharClassify *charClassTable); ~RESearch(); bool GrabMatches(CharacterIndexer &ci); const char *Compile(const char *pattern, int length, bool caseSensitive, bool posix); int Execute(CharacterIndexer &ci, int lp, int endp); int Substitute(CharacterIndexer &ci, char *src, char *dst); enum { MAXTAG=10 }; enum { MAXNFA=2048 }; enum { NOTFOUND=-1 }; int bopat[MAXTAG]; int eopat[MAXTAG]; char *pat[MAXTAG]; private: void Init(); void Clear(); void ChSet(unsigned char c); void ChSetWithCase(unsigned char c, bool caseSensitive); int GetBackslashExpression(const char *pattern, int &incr); int PMatch(CharacterIndexer &ci, int lp, int endp, char *ap); int bol; int tagstk[MAXTAG]; /* subpat tag stack */ char nfa[MAXNFA]; /* automaton */ int sta; unsigned char bittab[BITBLK]; /* bit table for CCL pre-set bits */ int failure; CharClassify *charClass; bool iswordc(unsigned char x) { return charClass->IsWord(x); } }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/CellBuffer.h0000644000175000017500000001273511763437013020615 00000000000000// Scintilla source code edit control /** @file CellBuffer.h ** Manages the text of the document. **/ // Copyright 1998-2004 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CELLBUFFER_H #define CELLBUFFER_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif // Interface to per-line data that wants to see each line insertion and deletion class PerLine { public: virtual ~PerLine() {} virtual void Init()=0; virtual void InsertLine(int)=0; virtual void RemoveLine(int)=0; }; /** * The line vector contains information about each of the lines in a cell buffer. */ class LineVector { Partitioning starts; PerLine *perLine; public: LineVector(); ~LineVector(); void Init(); void SetPerLine(PerLine *pl); void InsertText(int line, int delta); void InsertLine(int line, int position, bool lineStart); void SetLineStart(int line, int position); void RemoveLine(int line); int Lines() const { return starts.Partitions(); } int LineFromPosition(int pos) const; int LineStart(int line) const { return starts.PositionFromPartition(line); } int MarkValue(int line); int AddMark(int line, int marker); void MergeMarkers(int pos); void DeleteMark(int line, int markerNum, bool all); void DeleteMarkFromHandle(int markerHandle); int LineFromHandle(int markerHandle); void ClearLevels(); int SetLevel(int line, int level); int GetLevel(int line); int SetLineState(int line, int state); int GetLineState(int line); int GetMaxLineState(); }; enum actionType { insertAction, removeAction, startAction, containerAction }; /** * Actions are used to store all the information required to perform one undo/redo step. */ class Action { public: actionType at; int position; char *data; int lenData; bool mayCoalesce; Action(); ~Action(); void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0, bool mayCoalesce_=true); void Destroy(); void Grab(Action *source); }; /** * */ class UndoHistory { Action *actions; int lenActions; int maxAction; int currentAction; int undoSequenceDepth; int savePoint; void EnsureUndoRoom(); public: UndoHistory(); ~UndoHistory(); void AppendAction(actionType at, int position, char *data, int length, bool &startSequence, bool mayCoalesce=true); void BeginUndoAction(); void EndUndoAction(); void DropUndoSequence(); void DeleteUndoHistory(); /// The save point is a marker in the undo stack where the container has stated that /// the buffer was saved. Undo and redo can move over the save point. void SetSavePoint(); bool IsSavePoint() const; /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is /// called that many times. Similarly for redo. bool CanUndo() const; int StartUndo(); const Action &GetUndoStep() const; void CompletedUndoStep(); bool CanRedo() const; int StartRedo(); const Action &GetRedoStep() const; void CompletedRedoStep(); }; /** * Holder for an expandable array of characters that supports undo and line markers. * Based on article "Data Structures in a Bit-Mapped Text Editor" * by Wilfred J. Hansen, Byte January 1987, page 183. */ class CellBuffer { private: SplitVector substance; SplitVector style; bool readOnly; bool collectingUndo; UndoHistory uh; LineVector lv; /// Actions without undo void BasicInsertString(int position, const char *s, int insertLength); void BasicDeleteChars(int position, int deleteLength); public: CellBuffer(); ~CellBuffer(); /// Retrieving positions outside the range of the buffer works and returns 0 char CharAt(int position) const; void GetCharRange(char *buffer, int position, int lengthRetrieve) const; char StyleAt(int position) const; void GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const; const char *BufferPointer(); const char *RangePointer(int position, int rangeLength); int GapPosition() const; int Length() const; void Allocate(int newSize); void SetPerLine(PerLine *pl); int Lines() const; int LineStart(int line) const; int LineFromPosition(int pos) const { return lv.LineFromPosition(pos); } void InsertLine(int line, int position, bool lineStart); void RemoveLine(int line); const char *InsertString(int position, const char *s, int insertLength, bool &startSequence); /// Setting styles for positions outside the range of the buffer is safe and has no effect. /// @return true if the style of a character is changed. bool SetStyleAt(int position, char styleValue, char mask='\377'); bool SetStyleFor(int position, int length, char styleValue, char mask); const char *DeleteChars(int position, int deleteLength, bool &startSequence); bool IsReadOnly() const; void SetReadOnly(bool set); /// The save point is a marker in the undo stack where the container has stated that /// the buffer was saved. Undo and redo can move over the save point. void SetSavePoint(); bool IsSavePoint(); bool SetUndoCollection(bool collectUndo); bool IsCollectingUndo() const; void BeginUndoAction(); void EndUndoAction(); void AddUndoAction(int token, bool mayCoalesce); void DeleteUndoHistory(); /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is /// called that many times. Similarly for redo. bool CanUndo(); int StartUndo(); const Action &GetUndoStep() const; void PerformUndoStep(); bool CanRedo(); int StartRedo(); const Action &GetRedoStep() const; void PerformRedoStep(); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/Selection.h0000644000175000017500000001207111615412040020507 00000000000000// Scintilla source code edit control /** @file Selection.h ** Classes maintaining the selection. **/ // Copyright 2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SELECTION_H #define SELECTION_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class SelectionPosition { int position; int virtualSpace; public: explicit SelectionPosition(int position_=INVALID_POSITION, int virtualSpace_=0) : position(position_), virtualSpace(virtualSpace_) { PLATFORM_ASSERT(virtualSpace < 800000); if (virtualSpace < 0) virtualSpace = 0; } void Reset() { position = 0; virtualSpace = 0; } void MoveForInsertDelete(bool insertion, int startChange, int length); bool operator ==(const SelectionPosition &other) const { return position == other.position && virtualSpace == other.virtualSpace; } bool operator <(const SelectionPosition &other) const; bool operator >(const SelectionPosition &other) const; bool operator <=(const SelectionPosition &other) const; bool operator >=(const SelectionPosition &other) const; int Position() const { return position; } void SetPosition(int position_) { position = position_; virtualSpace = 0; } int VirtualSpace() const { return virtualSpace; } void SetVirtualSpace(int virtualSpace_) { PLATFORM_ASSERT(virtualSpace_ < 800000); if (virtualSpace_ >= 0) virtualSpace = virtualSpace_; } void Add(int increment) { position = position + increment; } bool IsValid() const { return position >= 0; } }; // Ordered range to make drawing simpler struct SelectionSegment { SelectionPosition start; SelectionPosition end; SelectionSegment() : start(), end() { } SelectionSegment(SelectionPosition a, SelectionPosition b) { if (a < b) { start = a; end = b; } else { start = b; end = a; } } bool Empty() const { return start == end; } void Extend(SelectionPosition p) { if (start > p) start = p; if (end < p) end = p; } }; struct SelectionRange { SelectionPosition caret; SelectionPosition anchor; SelectionRange() : caret(), anchor() { } SelectionRange(SelectionPosition single) : caret(single), anchor(single) { } SelectionRange(int single) : caret(single), anchor(single) { } SelectionRange(SelectionPosition caret_, SelectionPosition anchor_) : caret(caret_), anchor(anchor_) { } SelectionRange(int caret_, int anchor_) : caret(caret_), anchor(anchor_) { } bool Empty() const { return anchor == caret; } int Length() const; // int Width() const; // Like Length but takes virtual space into account bool operator ==(const SelectionRange &other) const { return caret == other.caret && anchor == other.anchor; } bool operator <(const SelectionRange &other) const { return caret < other.caret || ((caret == other.caret) && (anchor < other.anchor)); } void Reset() { anchor.Reset(); caret.Reset(); } void ClearVirtualSpace() { anchor.SetVirtualSpace(0); caret.SetVirtualSpace(0); } bool Contains(int pos) const; bool Contains(SelectionPosition sp) const; bool ContainsCharacter(int posCharacter) const; SelectionSegment Intersect(SelectionSegment check) const; SelectionPosition Start() const { return (anchor < caret) ? anchor : caret; } SelectionPosition End() const { return (anchor < caret) ? caret : anchor; } bool Trim(SelectionRange range); // If range is all virtual collapse to start of virtual space void MinimizeVirtualSpace(); }; class Selection { std::vector ranges; std::vector rangesSaved; SelectionRange rangeRectangular; size_t mainRange; bool moveExtends; bool tentativeMain; public: enum selTypes { noSel, selStream, selRectangle, selLines, selThin }; selTypes selType; Selection(); ~Selection(); bool IsRectangular() const; int MainCaret() const; int MainAnchor() const; SelectionRange &Rectangular(); SelectionSegment Limits() const; // This is for when you want to move the caret in response to a // user direction command - for rectangular selections, use the range // that covers all selected text otherwise return the main selection. SelectionSegment LimitsForRectangularElseMain() const; size_t Count() const; size_t Main() const; void SetMain(size_t r); SelectionRange &Range(size_t r); SelectionRange &RangeMain(); bool MoveExtends() const; void SetMoveExtends(bool moveExtends_); bool Empty() const; SelectionPosition Last() const; int Length() const; void MovePositions(bool insertion, int startChange, int length); void TrimSelection(SelectionRange range); void SetSelection(SelectionRange range); void AddSelection(SelectionRange range); void AddSelectionWithoutTrim(SelectionRange range); void TentativeSelection(SelectionRange range); void CommitTentative(); int CharacterInSelection(int posCharacter) const; int InSelectionForEOL(int pos) const; int VirtualSpaceFor(int pos) const; void Clear(); void RemoveDuplicates(); void RotateMain(); bool Tentative() const { return tentativeMain; } std::vector RangesCopy() const { return ranges; } }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/SVector.h0000644000175000017500000000476511615412040020162 00000000000000// Scintilla source code edit control /** @file SVector.h ** A simple expandable vector. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SVECTOR_H #define SVECTOR_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** * A simple expandable integer vector. * Storage not allocated for elements until an element is used. * This makes it very lightweight unless used so is a good match for optional features. */ class SVector { enum { allocSize = 4000 }; int *v; ///< The vector unsigned int size; ///< Number of elements allocated unsigned int len; ///< Number of elements used in vector /** Internally allocate more elements than the user wants * to avoid thrashing the memory allocator. */ void SizeTo(int newSize) { if (newSize < allocSize) newSize += allocSize; else newSize = (newSize * 3) / 2; int *newv = new int[newSize]; size = newSize; unsigned int i=0; for (; i 0) { SizeTo(other.Length()); for (int i=0; i 0) { SizeTo(other.Length()); for (int i=0; i= len) { if (i >= size) { SizeTo(i); } len = i+1; } return v[i]; } /// Reset vector. void Free() { delete []v; v = 0; size = 0; len = 0; } /** @brief Grow vector size. * Doesn't allow a vector to be shrinked. */ void SetLength(unsigned int newLength) { if (newLength > len) { if (newLength >= size) { SizeTo(newLength); } } len = newLength; } /// Get the current length (number of used elements) of the vector. int Length() const { return len; } }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/LineMarker.cxx0000644000175000017500000003100611726020232021166 00000000000000// Scintilla source code edit control /** @file LineMarker.cxx ** Defines the look of a line marker in the margin . **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "Platform.h" #include "Scintilla.h" #include "XPM.h" #include "LineMarker.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif void LineMarker::SetXPM(const char *textForm) { delete pxpm; pxpm = new XPM(textForm); markType = SC_MARK_PIXMAP; } void LineMarker::SetXPM(const char *const *linesForm) { delete pxpm; pxpm = new XPM(linesForm); markType = SC_MARK_PIXMAP; } void LineMarker::SetRGBAImage(Point sizeRGBAImage, const unsigned char *pixelsRGBAImage) { delete image; image = new RGBAImage(sizeRGBAImage.x, sizeRGBAImage.y, pixelsRGBAImage); markType = SC_MARK_RGBAIMAGE; } static void DrawBox(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) { PRectangle rc; rc.left = centreX - armSize; rc.top = centreY - armSize; rc.right = centreX + armSize + 1; rc.bottom = centreY + armSize + 1; surface->RectangleDraw(rc, back, fore); } static void DrawCircle(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore, ColourDesired back) { PRectangle rcCircle; rcCircle.left = centreX - armSize; rcCircle.top = centreY - armSize; rcCircle.right = centreX + armSize + 1; rcCircle.bottom = centreY + armSize + 1; surface->Ellipse(rcCircle, back, fore); } static void DrawPlus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) { PRectangle rcV(centreX, centreY - armSize + 2, centreX + 1, centreY + armSize - 2 + 1); surface->FillRectangle(rcV, fore); PRectangle rcH(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY+1); surface->FillRectangle(rcH, fore); } static void DrawMinus(Surface *surface, int centreX, int centreY, int armSize, ColourDesired fore) { PRectangle rcH(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY+1); surface->FillRectangle(rcH, fore); } void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharacter, typeOfFold tFold, int marginStyle) { ColourDesired head = back; ColourDesired body = back; ColourDesired tail = back; switch (tFold) { case LineMarker::head : case LineMarker::headWithTail : head = backSelected; tail = backSelected; break; case LineMarker::body : head = backSelected; body = backSelected; break; case LineMarker::tail : body = backSelected; tail = backSelected; break; default : // LineMarker::undefined break; } if ((markType == SC_MARK_PIXMAP) && (pxpm)) { pxpm->Draw(surface, rcWhole); return; } if ((markType == SC_MARK_RGBAIMAGE) && (image)) { // Make rectangle just large enough to fit image centred on centre of rcWhole PRectangle rcImage; rcImage.top = static_cast(((rcWhole.top + rcWhole.bottom) - image->GetHeight()) / 2); rcImage.bottom = rcImage.top + image->GetHeight(); rcImage.left = static_cast(((rcWhole.left + rcWhole.right) - image->GetWidth()) / 2); rcImage.right = rcImage.left + image->GetWidth(); surface->DrawRGBAImage(rcImage, image->GetWidth(), image->GetHeight(), image->Pixels()); return; } // Restrict most shapes a bit PRectangle rc = rcWhole; rc.top++; rc.bottom--; int minDim = Platform::Minimum(rc.Width(), rc.Height()); minDim--; // Ensure does not go beyond edge int centreX = (rc.right + rc.left) / 2; int centreY = (rc.bottom + rc.top) / 2; int dimOn2 = minDim / 2; int dimOn4 = minDim / 4; int blobSize = dimOn2-1; int armSize = dimOn2-2; if (marginStyle == SC_MARGIN_NUMBER || marginStyle == SC_MARGIN_TEXT || marginStyle == SC_MARGIN_RTEXT) { // On textual margins move marker to the left to try to avoid overlapping the text centreX = rc.left + dimOn2 + 1; } if (markType == SC_MARK_ROUNDRECT) { PRectangle rcRounded = rc; rcRounded.left = rc.left + 1; rcRounded.right = rc.right - 1; surface->RoundedRectangle(rcRounded, fore, back); } else if (markType == SC_MARK_CIRCLE) { PRectangle rcCircle; rcCircle.left = centreX - dimOn2; rcCircle.top = centreY - dimOn2; rcCircle.right = centreX + dimOn2; rcCircle.bottom = centreY + dimOn2; surface->Ellipse(rcCircle, fore, back); } else if (markType == SC_MARK_ARROW) { Point pts[] = { Point(centreX - dimOn4, centreY - dimOn2), Point(centreX - dimOn4, centreY + dimOn2), Point(centreX + dimOn2 - dimOn4, centreY), }; surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back); } else if (markType == SC_MARK_ARROWDOWN) { Point pts[] = { Point(centreX - dimOn2, centreY - dimOn4), Point(centreX + dimOn2, centreY - dimOn4), Point(centreX, centreY + dimOn2 - dimOn4), }; surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back); } else if (markType == SC_MARK_PLUS) { Point pts[] = { Point(centreX - armSize, centreY - 1), Point(centreX - 1, centreY - 1), Point(centreX - 1, centreY - armSize), Point(centreX + 1, centreY - armSize), Point(centreX + 1, centreY - 1), Point(centreX + armSize, centreY -1), Point(centreX + armSize, centreY +1), Point(centreX + 1, centreY + 1), Point(centreX + 1, centreY + armSize), Point(centreX - 1, centreY + armSize), Point(centreX - 1, centreY + 1), Point(centreX - armSize, centreY + 1), }; surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back); } else if (markType == SC_MARK_MINUS) { Point pts[] = { Point(centreX - armSize, centreY - 1), Point(centreX + armSize, centreY -1), Point(centreX + armSize, centreY +1), Point(centreX - armSize, centreY + 1), }; surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back); } else if (markType == SC_MARK_SMALLRECT) { PRectangle rcSmall; rcSmall.left = rc.left + 1; rcSmall.top = rc.top + 2; rcSmall.right = rc.right - 1; rcSmall.bottom = rc.bottom - 2; surface->RectangleDraw(rcSmall, fore, back); } else if (markType == SC_MARK_EMPTY || markType == SC_MARK_BACKGROUND || markType == SC_MARK_UNDERLINE || markType == SC_MARK_AVAILABLE) { // An invisible marker so don't draw anything } else if (markType == SC_MARK_VLINE) { surface->PenColour(body); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, rcWhole.bottom); } else if (markType == SC_MARK_LCORNER) { surface->PenColour(tail); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY); surface->LineTo(rc.right - 1, centreY); } else if (markType == SC_MARK_TCORNER) { surface->PenColour(tail); surface->MoveTo(centreX, centreY); surface->LineTo(rc.right - 1, centreY); surface->PenColour(body); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY + 1); surface->PenColour(head); surface->LineTo(centreX, rcWhole.bottom); } else if (markType == SC_MARK_LCORNERCURVE) { surface->PenColour(tail); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY-3); surface->LineTo(centreX+3, centreY); surface->LineTo(rc.right - 1, centreY); } else if (markType == SC_MARK_TCORNERCURVE) { surface->PenColour(tail); surface->MoveTo(centreX, centreY-3); surface->LineTo(centreX+3, centreY); surface->LineTo(rc.right - 1, centreY); surface->PenColour(body); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY-2); surface->PenColour(head); surface->LineTo(centreX, rcWhole.bottom); } else if (markType == SC_MARK_BOXPLUS) { DrawBox(surface, centreX, centreY, blobSize, fore, head); DrawPlus(surface, centreX, centreY, blobSize, tail); } else if (markType == SC_MARK_BOXPLUSCONNECTED) { if (tFold == LineMarker::headWithTail) surface->PenColour(tail); else surface->PenColour(body); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, rcWhole.bottom); surface->PenColour(body); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY - blobSize); DrawBox(surface, centreX, centreY, blobSize, fore, head); DrawPlus(surface, centreX, centreY, blobSize, tail); if (tFold == LineMarker::body) { surface->PenColour(tail); surface->MoveTo(centreX + 1, centreY + blobSize); surface->LineTo(centreX + blobSize + 1, centreY + blobSize); surface->MoveTo(centreX + blobSize, centreY + blobSize); surface->LineTo(centreX + blobSize, centreY - blobSize); surface->MoveTo(centreX + 1, centreY - blobSize); surface->LineTo(centreX + blobSize + 1, centreY - blobSize); } } else if (markType == SC_MARK_BOXMINUS) { DrawBox(surface, centreX, centreY, blobSize, fore, head); DrawMinus(surface, centreX, centreY, blobSize, tail); surface->PenColour(head); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, rcWhole.bottom); } else if (markType == SC_MARK_BOXMINUSCONNECTED) { DrawBox(surface, centreX, centreY, blobSize, fore, head); DrawMinus(surface, centreX, centreY, blobSize, tail); surface->PenColour(head); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, rcWhole.bottom); surface->PenColour(body); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY - blobSize); if (tFold == LineMarker::body) { surface->PenColour(tail); surface->MoveTo(centreX + 1, centreY + blobSize); surface->LineTo(centreX + blobSize + 1, centreY + blobSize); surface->MoveTo(centreX + blobSize, centreY + blobSize); surface->LineTo(centreX + blobSize, centreY - blobSize); surface->MoveTo(centreX + 1, centreY - blobSize); surface->LineTo(centreX + blobSize + 1, centreY - blobSize); } } else if (markType == SC_MARK_CIRCLEPLUS) { DrawCircle(surface, centreX, centreY, blobSize, fore, head); DrawPlus(surface, centreX, centreY, blobSize, tail); } else if (markType == SC_MARK_CIRCLEPLUSCONNECTED) { if (tFold == LineMarker::headWithTail) surface->PenColour(tail); else surface->PenColour(body); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, rcWhole.bottom); surface->PenColour(body); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY - blobSize); DrawCircle(surface, centreX, centreY, blobSize, fore, head); DrawPlus(surface, centreX, centreY, blobSize, tail); } else if (markType == SC_MARK_CIRCLEMINUS) { DrawCircle(surface, centreX, centreY, blobSize, fore, head); DrawMinus(surface, centreX, centreY, blobSize, tail); surface->PenColour(head); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, rcWhole.bottom); } else if (markType == SC_MARK_CIRCLEMINUSCONNECTED) { DrawCircle(surface, centreX, centreY, blobSize, fore, head); DrawMinus(surface, centreX, centreY, blobSize, tail); surface->PenColour(head); surface->MoveTo(centreX, centreY + blobSize); surface->LineTo(centreX, rcWhole.bottom); surface->PenColour(body); surface->MoveTo(centreX, rcWhole.top); surface->LineTo(centreX, centreY - blobSize); } else if (markType >= SC_MARK_CHARACTER) { char character[1]; character[0] = static_cast(markType - SC_MARK_CHARACTER); XYPOSITION width = surface->WidthText(fontForCharacter, character, 1); rc.left += (rc.Width() - width) / 2; rc.right = rc.left + width; surface->DrawTextClipped(rc, fontForCharacter, rc.bottom - 2, character, 1, fore, back); } else if (markType == SC_MARK_DOTDOTDOT) { int right = centreX - 6; for (int b=0; b<3; b++) { PRectangle rcBlob(right, rc.bottom - 4, right + 2, rc.bottom-2); surface->FillRectangle(rcBlob, fore); right += 5; } } else if (markType == SC_MARK_ARROWS) { surface->PenColour(fore); int right = centreX - 2; for (int b=0; b<3; b++) { surface->MoveTo(right - 4, centreY - 4); surface->LineTo(right, centreY); surface->LineTo(right - 5, centreY + 5); right += 4; } } else if (markType == SC_MARK_SHORTARROW) { Point pts[] = { Point(centreX, centreY + dimOn2), Point(centreX + dimOn2, centreY), Point(centreX, centreY - dimOn2), Point(centreX, centreY - dimOn4), Point(centreX - dimOn4, centreY - dimOn4), Point(centreX - dimOn4, centreY + dimOn4), Point(centreX, centreY + dimOn4), Point(centreX, centreY + dimOn2), }; surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back); } else if (markType == SC_MARK_LEFTRECT) { PRectangle rcLeft = rcWhole; rcLeft.right = rcLeft.left + 4; surface->FillRectangle(rcLeft, back); } else { // SC_MARK_FULLRECT surface->FillRectangle(rcWhole, back); } } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Editor.cxx0000644000175000017500000106276611763437013020417 00000000000000// Scintilla source code edit control /** @file Editor.cxx ** Main code for the edit control. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" #include "Editor.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /* return whether this modification represents an operation that may reasonably be deferred (not done now OR [possibly] at all) */ static bool CanDeferToLastStep(const DocModification &mh) { if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) return true; // CAN skip if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO))) return false; // MUST do if (mh.modificationType & SC_MULTISTEPUNDOREDO) return true; // CAN skip return false; // PRESUMABLY must do } static bool CanEliminate(const DocModification &mh) { return (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0; } /* return whether this modification represents the FINAL step in a [possibly lengthy] multi-step Undo/Redo sequence */ static bool IsLastStep(const DocModification &mh) { return (mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0 && (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0 && (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0 && (mh.modificationType & SC_MULTILINEUNDOREDO) != 0; } Caret::Caret() : active(false), on(false), period(500) {} Timer::Timer() : ticking(false), ticksToWait(0), tickerID(0) {} Idler::Idler() : state(false), idlerID(0) {} static inline bool IsControlCharacter(int ch) { // iscntrl returns true for lots of chars > 127 which are displayable return ch >= 0 && ch < ' '; } static inline bool IsAllSpacesOrTabs(char *s, unsigned int len) { for (unsigned int i = 0; i < len; i++) { // This is safe because IsSpaceOrTab() will return false for null terminators if (!IsSpaceOrTab(s[i])) return false; } return true; } Editor::Editor() { ctrlID = 0; stylesValid = false; technology = SC_TECHNOLOGY_DEFAULT; printMagnification = 0; printColourMode = SC_PRINT_NORMAL; printWrapState = eWrapWord; cursorMode = SC_CURSORNORMAL; controlCharSymbol = 0; /* Draw the control characters */ hasFocus = false; hideSelection = false; inOverstrike = false; errorStatus = 0; mouseDownCaptures = true; bufferedDraw = true; twoPhaseDraw = true; lastClickTime = 0; dwellDelay = SC_TIME_FOREVER; ticksToDwell = SC_TIME_FOREVER; dwelling = false; ptMouseLast.x = 0; ptMouseLast.y = 0; inDragDrop = ddNone; dropWentOutside = false; posDrag = SelectionPosition(invalidPosition); posDrop = SelectionPosition(invalidPosition); hotSpotClickPos = INVALID_POSITION; selectionType = selChar; lastXChosen = 0; lineAnchorPos = 0; originalAnchorPos = 0; wordSelectAnchorStartPos = 0; wordSelectAnchorEndPos = 0; wordSelectInitialCaretPos = -1; primarySelection = true; caretXPolicy = CARET_SLOP | CARET_EVEN; caretXSlop = 50; caretYPolicy = CARET_EVEN; caretYSlop = 0; visiblePolicy = 0; visibleSlop = 0; searchAnchor = 0; xOffset = 0; xCaretMargin = 50; horizontalScrollBarVisible = true; scrollWidth = 2000; trackLineWidth = false; lineWidthMaxSeen = 0; verticalScrollBarVisible = true; endAtLastLine = true; caretSticky = SC_CARETSTICKY_OFF; marginOptions = SC_MARGINOPTION_NONE; multipleSelection = false; additionalSelectionTyping = false; multiPasteMode = SC_MULTIPASTE_ONCE; additionalCaretsBlink = true; additionalCaretsVisible = true; virtualSpaceOptions = SCVS_NONE; pixmapLine = 0; pixmapSelMargin = 0; pixmapSelPattern = 0; pixmapIndentGuide = 0; pixmapIndentGuideHighlight = 0; targetStart = 0; targetEnd = 0; searchFlags = 0; topLine = 0; posTopLine = 0; lengthForEncode = -1; needUpdateUI = 0; ContainerNeedsUpdate(SC_UPDATE_CONTENT); braces[0] = invalidPosition; braces[1] = invalidPosition; bracesMatchStyle = STYLE_BRACEBAD; highlightGuideColumn = 0; theEdge = 0; paintState = notPainting; willRedrawAll = false; modEventMask = SC_MODEVENTMASKALL; pdoc = new Document(); pdoc->AddRef(); pdoc->AddWatcher(this, 0); recordingMacro = false; foldFlags = 0; wrapState = eWrapNone; wrapWidth = LineLayout::wrapWidthInfinite; wrapStart = wrapLineLarge; wrapEnd = wrapLineLarge; wrapVisualFlags = 0; wrapVisualFlagsLocation = 0; wrapVisualStartIndent = 0; wrapIndentMode = SC_WRAPINDENT_FIXED; convertPastes = true; hsStart = -1; hsEnd = -1; llc.SetLevel(LineLayoutCache::llcCaret); posCache.SetSize(0x400); } Editor::~Editor() { pdoc->RemoveWatcher(this, 0); pdoc->Release(); pdoc = 0; DropGraphics(true); } void Editor::Finalise() { SetIdle(false); CancelModes(); } void Editor::DropGraphics(bool freeObjects) { if (freeObjects) { delete pixmapLine; pixmapLine = 0; delete pixmapSelMargin; pixmapSelMargin = 0; delete pixmapSelPattern; pixmapSelPattern = 0; delete pixmapIndentGuide; pixmapIndentGuide = 0; delete pixmapIndentGuideHighlight; pixmapIndentGuideHighlight = 0; } else { if (pixmapLine) pixmapLine->Release(); if (pixmapSelMargin) pixmapSelMargin->Release(); if (pixmapSelPattern) pixmapSelPattern->Release(); if (pixmapIndentGuide) pixmapIndentGuide->Release(); if (pixmapIndentGuideHighlight) pixmapIndentGuideHighlight->Release(); } } void Editor::AllocateGraphics() { if (!pixmapLine) pixmapLine = Surface::Allocate(technology); if (!pixmapSelMargin) pixmapSelMargin = Surface::Allocate(technology); if (!pixmapSelPattern) pixmapSelPattern = Surface::Allocate(technology); if (!pixmapIndentGuide) pixmapIndentGuide = Surface::Allocate(technology); if (!pixmapIndentGuideHighlight) pixmapIndentGuideHighlight = Surface::Allocate(technology); } void Editor::InvalidateStyleData() { stylesValid = false; vs.technology = technology; DropGraphics(false); AllocateGraphics(); llc.Invalidate(LineLayout::llInvalid); posCache.Clear(); } void Editor::InvalidateStyleRedraw() { NeedWrapping(); InvalidateStyleData(); Redraw(); } void Editor::RefreshStyleData() { if (!stylesValid) { stylesValid = true; AutoSurface surface(this); if (surface) { vs.Refresh(*surface); } SetScrollBars(); SetRectangularRange(); } } PRectangle Editor::GetClientRectangle() { return wMain.GetClientPosition(); } PRectangle Editor::GetTextRectangle() { PRectangle rc = GetClientRectangle(); rc.left += vs.fixedColumnWidth; rc.right -= vs.rightMarginWidth; return rc; } int Editor::LinesOnScreen() { PRectangle rcClient = GetClientRectangle(); int htClient = rcClient.bottom - rcClient.top; //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1); return htClient / vs.lineHeight; } int Editor::LinesToScroll() { int retVal = LinesOnScreen() - 1; if (retVal < 1) return 1; else return retVal; } int Editor::MaxScrollPos() { //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n", //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1); int retVal = cs.LinesDisplayed(); if (endAtLastLine) { retVal -= LinesOnScreen(); } else { retVal--; } if (retVal < 0) { return 0; } else { return retVal; } } const char *ControlCharacterString(unsigned char ch) { const char *reps[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; if (ch < (sizeof(reps) / sizeof(reps[0]))) { return reps[ch]; } else { return "BAD"; } } /** * Convenience class to ensure LineLayout objects are always disposed. */ class AutoLineLayout { LineLayoutCache &llc; LineLayout *ll; AutoLineLayout &operator=(const AutoLineLayout &); public: AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {} ~AutoLineLayout() { llc.Dispose(ll); ll = 0; } LineLayout *operator->() const { return ll; } operator LineLayout *() const { return ll; } void Set(LineLayout *ll_) { llc.Dispose(ll); ll = ll_; } }; SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const { if (sp.Position() < 0) { return SelectionPosition(0); } else if (sp.Position() > pdoc->Length()) { return SelectionPosition(pdoc->Length()); } else { // If not at end of line then set offset to 0 if (!pdoc->IsLineEndPosition(sp.Position())) sp.SetVirtualSpace(0); return sp; } } Point Editor::LocationFromPosition(SelectionPosition pos) { Point pt; RefreshStyleData(); if (pos.Position() == INVALID_POSITION) return pt; int line = pdoc->LineFromPosition(pos.Position()); int lineVisible = cs.DisplayFromDoc(line); //Platform::DebugPrintf("line=%d\n", line); AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); if (surface && ll) { // -1 because of adding in for visible lines in following loop. pt.y = (lineVisible - topLine - 1) * vs.lineHeight; pt.x = 0; unsigned int posLineStart = pdoc->LineStart(line); LayoutLine(line, surface, vs, ll, wrapWidth); int posInLine = pos.Position() - posLineStart; // In case of very long line put x at arbitrary large position if (posInLine > ll->maxLineLength) { pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)]; } for (int subLine = 0; subLine < ll->lines; subLine++) { if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)]; if (ll->wrapIndent != 0) { int lineStart = ll->LineStart(subLine); if (lineStart != 0) // Wrapped pt.x += ll->wrapIndent; } } if (posInLine >= ll->LineStart(subLine)) { pt.y += vs.lineHeight; } } pt.x += vs.fixedColumnWidth - xOffset; } pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; return pt; } Point Editor::LocationFromPosition(int pos) { return LocationFromPosition(SelectionPosition(pos)); } int Editor::XFromPosition(int pos) { Point pt = LocationFromPosition(pos); return pt.x - vs.fixedColumnWidth + xOffset; } int Editor::XFromPosition(SelectionPosition sp) { Point pt = LocationFromPosition(sp); return pt.x - vs.fixedColumnWidth + xOffset; } int Editor::LineFromLocation(Point pt) { return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); } void Editor::SetTopLine(int topLineNew) { if (topLine != topLineNew) { topLine = topLineNew; ContainerNeedsUpdate(SC_UPDATE_V_SCROLL); } posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine)); } SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) { RefreshStyleData(); if (canReturnInvalid) { PRectangle rcClient = GetTextRectangle(); if (!rcClient.Contains(pt)) return SelectionPosition(INVALID_POSITION); if (pt.x < vs.fixedColumnWidth) return SelectionPosition(INVALID_POSITION); if (pt.y < 0) return SelectionPosition(INVALID_POSITION); } pt.x = pt.x - vs.fixedColumnWidth + xOffset; int visibleLine = pt.y / vs.lineHeight + topLine; if (pt.y < 0) { // Division rounds towards 0 visibleLine = (static_cast(pt.y) - (vs.lineHeight - 1)) / vs.lineHeight + topLine; } if (!canReturnInvalid && (visibleLine < 0)) visibleLine = 0; int lineDoc = cs.DocFromDisplay(visibleLine); if (canReturnInvalid && (lineDoc < 0)) return SelectionPosition(INVALID_POSITION); if (lineDoc >= pdoc->LinesTotal()) return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length()); unsigned int posLineStart = pdoc->LineStart(lineDoc); SelectionPosition retVal(canReturnInvalid ? INVALID_POSITION : static_cast(posLineStart)); AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); if (surface && ll) { LayoutLine(lineDoc, surface, vs, ll, wrapWidth); int lineStartSet = cs.DisplayFromDoc(lineDoc); int subLine = visibleLine - lineStartSet; if (subLine < ll->lines) { int lineStart = ll->LineStart(subLine); int lineEnd = ll->LineLastVisible(subLine); XYPOSITION subLineStart = ll->positions[lineStart]; if (ll->wrapIndent != 0) { if (lineStart != 0) // Wrapped pt.x -= ll->wrapIndent; } int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd); while (i < lineEnd) { if (charPosition) { if ((pt.x + subLineStart) < (ll->positions[i + 1])) { return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1)); } } else { if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1)); } } i++; } if (virtualSpace) { const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; int spaceOffset = (pt.x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth; return SelectionPosition(lineEnd + posLineStart, spaceOffset); } else if (canReturnInvalid) { if (pt.x < (ll->positions[lineEnd] - subLineStart)) { return SelectionPosition(pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1)); } } else { return SelectionPosition(lineEnd + posLineStart); } } if (!canReturnInvalid) return SelectionPosition(ll->numCharsInLine + posLineStart); } return retVal; } int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) { return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position(); } /** * Find the document position corresponding to an x coordinate on a particular document line. * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. */ SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) { RefreshStyleData(); if (lineDoc >= pdoc->LinesTotal()) return SelectionPosition(pdoc->Length()); //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); int retVal = 0; if (surface && ll) { unsigned int posLineStart = pdoc->LineStart(lineDoc); LayoutLine(lineDoc, surface, vs, ll, wrapWidth); int subLine = 0; int lineStart = ll->LineStart(subLine); int lineEnd = ll->LineLastVisible(subLine); XYPOSITION subLineStart = ll->positions[lineStart]; XYPOSITION newX = x; if (ll->wrapIndent != 0) { if (lineStart != 0) // Wrapped newX -= ll->wrapIndent; } int i = ll->FindBefore(newX + subLineStart, lineStart, lineEnd); while (i < lineEnd) { if ((newX + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1); return SelectionPosition(retVal); } i++; } const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; int spaceOffset = (newX + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth; return SelectionPosition(lineEnd + posLineStart, spaceOffset); } return SelectionPosition(retVal); } int Editor::PositionFromLineX(int lineDoc, int x) { return SPositionFromLineX(lineDoc, x).Position(); } /** * If painting then abandon the painting because a wider redraw is needed. * @return true if calling code should stop drawing. */ bool Editor::AbandonPaint() { if ((paintState == painting) && !paintingAllText) { paintState = paintAbandoned; } return paintState == paintAbandoned; } void Editor::RedrawRect(PRectangle rc) { //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom); // Clip the redraw rectangle into the client area PRectangle rcClient = GetClientRectangle(); if (rc.top < rcClient.top) rc.top = rcClient.top; if (rc.bottom > rcClient.bottom) rc.bottom = rcClient.bottom; if (rc.left < rcClient.left) rc.left = rcClient.left; if (rc.right > rcClient.right) rc.right = rcClient.right; if ((rc.bottom > rc.top) && (rc.right > rc.left)) { wMain.InvalidateRectangle(rc); } } void Editor::Redraw() { //Platform::DebugPrintf("Redraw all\n"); PRectangle rcClient = GetClientRectangle(); wMain.InvalidateRectangle(rcClient); //wMain.InvalidateAll(); } void Editor::RedrawSelMargin(int line, bool allAfter) { if (!AbandonPaint()) { if (vs.maskInLine) { Redraw(); } else { PRectangle rcSelMargin = GetClientRectangle(); rcSelMargin.right = vs.fixedColumnWidth; if (line != -1) { int position = pdoc->LineStart(line); PRectangle rcLine = RectangleFromRange(position, position); // Inflate line rectangle if there are image markers with height larger than line height if (vs.largestMarkerHeight > vs.lineHeight) { int delta = (vs.largestMarkerHeight - vs.lineHeight + 1) / 2; rcLine.top -= delta; rcLine.bottom += delta; if (rcLine.top < rcSelMargin.top) rcLine.top = rcSelMargin.top; if (rcLine.bottom > rcSelMargin.bottom) rcLine.bottom = rcSelMargin.bottom; } rcSelMargin.top = rcLine.top; if (!allAfter) rcSelMargin.bottom = rcLine.bottom; } wMain.InvalidateRectangle(rcSelMargin); } } } PRectangle Editor::RectangleFromRange(int start, int end) { int minPos = start; if (minPos > end) minPos = end; int maxPos = start; if (maxPos < end) maxPos = end; int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos)); int lineDocMax = pdoc->LineFromPosition(maxPos); int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1; PRectangle rcClient = GetTextRectangle(); PRectangle rc; rc.left = vs.fixedColumnWidth; rc.top = (minLine - topLine) * vs.lineHeight; if (rc.top < 0) rc.top = 0; rc.right = rcClient.right; rc.bottom = (maxLine - topLine + 1) * vs.lineHeight; // Ensure PRectangle is within 16 bit space rc.top = Platform::Clamp(rc.top, -32000, 32000); rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000); return rc; } void Editor::InvalidateRange(int start, int end) { RedrawRect(RectangleFromRange(start, end)); } int Editor::CurrentPosition() { return sel.MainCaret(); } bool Editor::SelectionEmpty() { return sel.Empty(); } SelectionPosition Editor::SelectionStart() { return sel.RangeMain().Start(); } SelectionPosition Editor::SelectionEnd() { return sel.RangeMain().End(); } void Editor::SetRectangularRange() { if (sel.IsRectangular()) { int xAnchor = XFromPosition(sel.Rectangular().anchor); int xCaret = XFromPosition(sel.Rectangular().caret); if (sel.selType == Selection::selThin) { xCaret = xAnchor; } int lineAnchorRect = pdoc->LineFromPosition(sel.Rectangular().anchor.Position()); int lineCaret = pdoc->LineFromPosition(sel.Rectangular().caret.Position()); int increment = (lineCaret > lineAnchorRect) ? 1 : -1; for (int line=lineAnchorRect; line != lineCaret+increment; line += increment) { SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor)); if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0) range.ClearVirtualSpace(); if (line == lineAnchorRect) sel.SetSelection(range); else sel.AddSelectionWithoutTrim(range); } } } void Editor::ThinRectangularRange() { if (sel.IsRectangular()) { sel.selType = Selection::selThin; if (sel.Rectangular().caret < sel.Rectangular().anchor) { sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).caret, sel.Range(0).anchor); } else { sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).anchor, sel.Range(0).caret); } SetRectangularRange(); } } void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) { if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) { invalidateWholeSelection = true; } int firstAffected = Platform::Minimum(sel.RangeMain().Start().Position(), newMain.Start().Position()); // +1 for lastAffected ensures caret repainted int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position()); lastAffected = Platform::Maximum(lastAffected, sel.RangeMain().End().Position()); if (invalidateWholeSelection) { for (size_t r=0; rLineFromPosition(currentPos_.Position()); /* For Line selection - ensure the anchor and caret are always at the beginning and end of the region lines. */ if (sel.selType == Selection::selLines) { if (currentPos_ > anchor_) { anchor_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position()))); currentPos_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position()))); } else { currentPos_ = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position()))); anchor_ = SelectionPosition(pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position()))); } } SelectionRange rangeNew(currentPos_, anchor_); if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { InvalidateSelection(rangeNew); } sel.RangeMain() = rangeNew; SetRectangularRange(); ClaimSelection(); if (highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } } void Editor::SetSelection(int currentPos_, int anchor_) { SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_)); } // Just move the caret on the main selection void Editor::SetSelection(SelectionPosition currentPos_) { currentPos_ = ClampPositionIntoDocument(currentPos_); int currentLine = pdoc->LineFromPosition(currentPos_.Position()); if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) { InvalidateSelection(SelectionRange(currentPos_)); } if (sel.IsRectangular()) { sel.Rectangular() = SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor); SetRectangularRange(); } else { sel.RangeMain() = SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor); } ClaimSelection(); if (highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } } void Editor::SetSelection(int currentPos_) { SetSelection(SelectionPosition(currentPos_)); } void Editor::SetEmptySelection(SelectionPosition currentPos_) { int currentLine = pdoc->LineFromPosition(currentPos_.Position()); SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_)); if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { InvalidateSelection(rangeNew); } sel.Clear(); sel.RangeMain() = rangeNew; SetRectangularRange(); ClaimSelection(); if (highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } } void Editor::SetEmptySelection(int currentPos_) { SetEmptySelection(SelectionPosition(currentPos_)); } bool Editor::RangeContainsProtected(int start, int end) const { if (vs.ProtectionActive()) { if (start > end) { int t = start; start = end; end = t; } int mask = pdoc->stylingBitsMask; for (int pos = start; pos < end; pos++) { if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()) return true; } } return false; } bool Editor::SelectionContainsProtected() { for (size_t r=0; rMovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd); if (posMoved != pos.Position()) pos.SetPosition(posMoved); if (vs.ProtectionActive()) { int mask = pdoc->stylingBitsMask; if (moveDir > 0) { if ((pos.Position() > 0) && vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()) { while ((pos.Position() < pdoc->Length()) && (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected())) pos.Add(1); } } else if (moveDir < 0) { if (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()) { while ((pos.Position() > 0) && (vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected())) pos.Add(-1); } } } return pos; } int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) { bool simpleCaret = (sel.Count() == 1) && sel.Empty(); SelectionPosition spCaret = sel.Last(); int delta = newPos.Position() - sel.MainCaret(); newPos = ClampPositionIntoDocument(newPos); newPos = MovePositionOutsideChar(newPos, delta); if (!multipleSelection && sel.IsRectangular() && (selt == Selection::selStream)) { // Can't turn into multiple selection so clear additional selections InvalidateSelection(SelectionRange(newPos), true); SelectionRange rangeMain = sel.RangeMain(); sel.SetSelection(rangeMain); } if (!sel.IsRectangular() && (selt == Selection::selRectangle)) { // Switching to rectangular SelectionRange rangeMain = sel.RangeMain(); sel.Clear(); sel.Rectangular() = rangeMain; } if (selt != Selection::noSel) { sel.selType = selt; } if (selt != Selection::noSel || sel.MoveExtends()) { SetSelection(newPos); } else { SetEmptySelection(newPos); } ShowCaretAtCurrentPosition(); int currentLine = pdoc->LineFromPosition(newPos.Position()); if (ensureVisible) { // In case in need of wrapping to ensure DisplayFromDoc works. if (currentLine >= wrapStart) WrapLines(true, -1); XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true); if (simpleCaret && (newXY.xOffset == xOffset)) { // simple vertical scroll then invalidate ScrollTo(newXY.topLine); InvalidateSelection(SelectionRange(spCaret), true); } else { SetXYScroll(newXY); } } if (highlightDelimiter.NeedsDrawing(currentLine)) { RedrawSelMargin(); } return 0; } int Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) { return MovePositionTo(SelectionPosition(newPos), selt, ensureVisible); } SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) { pos = ClampPositionIntoDocument(pos); pos = MovePositionOutsideChar(pos, moveDir); int lineDoc = pdoc->LineFromPosition(pos.Position()); if (cs.GetVisible(lineDoc)) { return pos; } else { int lineDisplay = cs.DisplayFromDoc(lineDoc); if (moveDir > 0) { // lineDisplay is already line before fold as lines in fold use display line of line after fold lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed()); return SelectionPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay))); } else { lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed()); return SelectionPosition(pdoc->LineEnd(cs.DocFromDisplay(lineDisplay))); } } } SelectionPosition Editor::MovePositionSoVisible(int pos, int moveDir) { return MovePositionSoVisible(SelectionPosition(pos), moveDir); } Point Editor::PointMainCaret() { return LocationFromPosition(sel.Range(sel.Main()).caret); } /** * Choose the x position that the caret will try to stick to * as it moves up and down. */ void Editor::SetLastXChosen() { Point pt = PointMainCaret(); lastXChosen = pt.x + xOffset; } void Editor::ScrollTo(int line, bool moveThumb) { int topLineNew = Platform::Clamp(line, 0, MaxScrollPos()); if (topLineNew != topLine) { // Try to optimise small scrolls #ifndef UNDER_CE int linesToMove = topLine - topLineNew; bool performBlit = (abs(linesToMove) <= 10) && (paintState == notPainting); willRedrawAll = !performBlit; #endif SetTopLine(topLineNew); // Optimize by styling the view as this will invalidate any needed area // which could abort the initial paint if discovered later. StyleToPositionInView(PositionAfterArea(GetClientRectangle())); #ifndef UNDER_CE // Perform redraw rather than scroll if many lines would be redrawn anyway. if (performBlit) { ScrollText(linesToMove); } else { Redraw(); } willRedrawAll = false; #else Redraw(); #endif if (moveThumb) { SetVerticalScrollPos(); } } } void Editor::ScrollText(int /* linesToMove */) { //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove); Redraw(); } void Editor::HorizontalScrollTo(int xPos) { //Platform::DebugPrintf("HorizontalScroll %d\n", xPos); if (xPos < 0) xPos = 0; if ((wrapState == eWrapNone) && (xOffset != xPos)) { xOffset = xPos; ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); SetHorizontalScrollPos(); RedrawRect(GetClientRectangle()); } } void Editor::VerticalCentreCaret() { int lineDoc = pdoc->LineFromPosition(sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret()); int lineDisplay = cs.DisplayFromDoc(lineDoc); int newTop = lineDisplay - (LinesOnScreen() / 2); if (topLine != newTop) { SetTopLine(newTop > 0 ? newTop : 0); RedrawRect(GetClientRectangle()); } } // Avoid 64 bit compiler warnings. // Scintilla does not support text buffers larger than 2**31 static int istrlen(const char *s) { return static_cast(strlen(s)); } void Editor::MoveSelectedLines(int lineDelta) { // if selection doesn't start at the beginning of the line, set the new start int selectionStart = SelectionStart().Position(); int startLine = pdoc->LineFromPosition(selectionStart); int beginningOfStartLine = pdoc->LineStart(startLine); selectionStart = beginningOfStartLine; // if selection doesn't end at the beginning of a line greater than that of the start, // then set it at the beginning of the next one int selectionEnd = SelectionEnd().Position(); int endLine = pdoc->LineFromPosition(selectionEnd); int beginningOfEndLine = pdoc->LineStart(endLine); bool appendEol = false; if (selectionEnd > beginningOfEndLine || selectionStart == selectionEnd) { selectionEnd = pdoc->LineStart(endLine + 1); appendEol = (selectionEnd == pdoc->Length() && pdoc->LineFromPosition(selectionEnd) == endLine); } // if there's nowhere for the selection to move // (i.e. at the beginning going up or at the end going down), // stop it right there! if ((selectionStart == 0 && lineDelta < 0) || (selectionEnd == pdoc->Length() && lineDelta > 0) || selectionStart == selectionEnd) { return; } UndoGroup ug(pdoc); if (lineDelta > 0 && selectionEnd == pdoc->LineStart(pdoc->LinesTotal() - 1)) { SetSelection(pdoc->MovePositionOutsideChar(selectionEnd - 1, -1), selectionEnd); ClearSelection(); selectionEnd = CurrentPosition(); } SetSelection(selectionStart, selectionEnd); SelectionText selectedText; CopySelectionRange(&selectedText); int selectionLength = SelectionRange(selectionStart, selectionEnd).Length(); Point currentLocation = LocationFromPosition(CurrentPosition()); int currentLine = LineFromLocation(currentLocation); if (appendEol) SetSelection(pdoc->MovePositionOutsideChar(selectionStart - 1, -1), selectionEnd); ClearSelection(); const char *eol = StringFromEOLMode(pdoc->eolMode); if (currentLine + lineDelta >= pdoc->LinesTotal()) pdoc->InsertCString(pdoc->Length(), eol); GoToLine(currentLine + lineDelta); pdoc->InsertCString(CurrentPosition(), selectedText.s); if (appendEol) { pdoc->InsertCString(CurrentPosition() + selectionLength, eol); selectionLength += istrlen(eol); } SetSelection(CurrentPosition(), CurrentPosition() + selectionLength); } void Editor::MoveSelectedLinesUp() { MoveSelectedLines(-1); } void Editor::MoveSelectedLinesDown() { MoveSelectedLines(1); } void Editor::MoveCaretInsideView(bool ensureVisible) { PRectangle rcClient = GetTextRectangle(); Point pt = PointMainCaret(); if (pt.y < rcClient.top) { MovePositionTo(SPositionFromLocation( Point(lastXChosen - xOffset, rcClient.top), false, false, UserVirtualSpace()), Selection::noSel, ensureVisible); } else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) { int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight; MovePositionTo(SPositionFromLocation( Point(lastXChosen - xOffset, rcClient.top + yOfLastLineFullyDisplayed), false, false, UserVirtualSpace()), Selection::noSel, ensureVisible); } } int Editor::DisplayFromPosition(int pos) { int lineDoc = pdoc->LineFromPosition(pos); int lineDisplay = cs.DisplayFromDoc(lineDoc); AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); if (surface && ll) { LayoutLine(lineDoc, surface, vs, ll, wrapWidth); unsigned int posLineStart = pdoc->LineStart(lineDoc); int posInLine = pos - posLineStart; lineDisplay--; // To make up for first increment ahead. for (int subLine = 0; subLine < ll->lines; subLine++) { if (posInLine >= ll->LineStart(subLine)) { lineDisplay++; } } } return lineDisplay; } /** * Ensure the caret is reasonably visible in context. * Caret policy in SciTE If slop is set, we can define a slop value. This value defines an unwanted zone (UZ) where the caret is... unwanted. This zone is defined as a number of pixels near the vertical margins, and as a number of lines near the horizontal margins. By keeping the caret away from the edges, it is seen within its context, so it is likely that the identifier that the caret is on can be completely seen, and that the current line is seen with some of the lines following it which are often dependent on that line. If strict is set, the policy is enforced... strictly. The caret is centred on the display if slop is not set, and cannot go in the UZ if slop is set. If jumps is set, the display is moved more energetically so the caret can move in the same direction longer before the policy is applied again. '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin. If even is not set, instead of having symmetrical UZs, the left and bottom UZs are extended up to right and top UZs respectively. This way, we favour the displaying of useful information: the begining of lines, where most code reside, and the lines after the caret, eg. the body of a function. | | | | | slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of | | | | | visibility or going into the UZ) display is... -----+--------+-------+------+--------------------------------------------+-------------------------------------------------------------- 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right 0 | 0 | 0 | 1 | Yes | moved by one position 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right 0 | 0 | 1 | 1 | Yes | centred on the caret 0 | 1 | - | 0 | Caret is always on top/on right of display | - 0 | 1 | - | 1 | No, caret is always centred | - 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | - 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin */ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) { PRectangle rcClient = GetTextRectangle(); const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret; const Point pt = LocationFromPosition(posCaret); const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1); const int lineCaret = DisplayFromPosition(posCaret.Position()); XYScrollPosition newXY(xOffset, topLine); // Vertical positioning if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) { const int linesOnScreen = LinesOnScreen(); const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2; const bool bSlop = (caretYPolicy & CARET_SLOP) != 0; const bool bStrict = (caretYPolicy & CARET_STRICT) != 0; const bool bJump = (caretYPolicy & CARET_JUMPS) != 0; const bool bEven = (caretYPolicy & CARET_EVEN) != 0; // It should be possible to scroll the window to show the caret, // but this fails to remove the caret on GTK+ if (bSlop) { // A margin is defined int yMoveT, yMoveB; if (bStrict) { int yMarginT, yMarginB; if (!useMargin) { // In drag mode, avoid moves // otherwise, a double click will select several lines. yMarginT = yMarginB = 0; } else { // yMarginT must equal to caretYSlop, with a minimum of 1 and // a maximum of slightly less than half the heigth of the text area. yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen); if (bEven) { yMarginB = yMarginT; } else { yMarginB = linesOnScreen - yMarginT - 1; } } yMoveT = yMarginT; if (bEven) { if (bJump) { yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen); } yMoveB = yMoveT; } else { yMoveB = linesOnScreen - yMoveT - 1; } if (lineCaret < topLine + yMarginT) { // Caret goes too high newXY.topLine = lineCaret - yMoveT; } else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) { // Caret goes too low newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; } } else { // Not strict yMoveT = bJump ? caretYSlop * 3 : caretYSlop; yMoveT = Platform::Clamp(yMoveT, 1, halfScreen); if (bEven) { yMoveB = yMoveT; } else { yMoveB = linesOnScreen - yMoveT - 1; } if (lineCaret < topLine) { // Caret goes too high newXY.topLine = lineCaret - yMoveT; } else if (lineCaret > topLine + linesOnScreen - 1) { // Caret goes too low newXY.topLine = lineCaret - linesOnScreen + 1 + yMoveB; } } } else { // No slop if (!bStrict && !bJump) { // Minimal move if (lineCaret < topLine) { // Caret goes too high newXY.topLine = lineCaret; } else if (lineCaret > topLine + linesOnScreen - 1) { // Caret goes too low if (bEven) { newXY.topLine = lineCaret - linesOnScreen + 1; } else { newXY.topLine = lineCaret; } } } else { // Strict or going out of display if (bEven) { // Always center caret newXY.topLine = lineCaret - halfScreen; } else { // Always put caret on top of display newXY.topLine = lineCaret; } } } newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos()); } // Horizontal positioning if (horiz && (wrapState == eWrapNone)) { const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2; const bool bSlop = (caretXPolicy & CARET_SLOP) != 0; const bool bStrict = (caretXPolicy & CARET_STRICT) != 0; const bool bJump = (caretXPolicy & CARET_JUMPS) != 0; const bool bEven = (caretXPolicy & CARET_EVEN) != 0; if (bSlop) { // A margin is defined int xMoveL, xMoveR; if (bStrict) { int xMarginL, xMarginR; if (!useMargin) { // In drag mode, avoid moves unless very near of the margin // otherwise, a simple click will select text. xMarginL = xMarginR = 2; } else { // xMargin must equal to caretXSlop, with a minimum of 2 and // a maximum of slightly less than half the width of the text area. xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen); if (bEven) { xMarginL = xMarginR; } else { xMarginL = rcClient.Width() - xMarginR - 4; } } if (bJump && bEven) { // Jump is used only in even mode xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen); } else { xMoveL = xMoveR = 0; // Not used, avoid a warning } if (pt.x < rcClient.left + xMarginL) { // Caret is on the left of the display if (bJump && bEven) { newXY.xOffset -= xMoveL; } else { // Move just enough to allow to display the caret newXY.xOffset -= (rcClient.left + xMarginL) - pt.x; } } else if (pt.x >= rcClient.right - xMarginR) { // Caret is on the right of the display if (bJump && bEven) { newXY.xOffset += xMoveR; } else { // Move just enough to allow to display the caret newXY.xOffset += pt.x - (rcClient.right - xMarginR) + 1; } } } else { // Not strict xMoveR = bJump ? caretXSlop * 3 : caretXSlop; xMoveR = Platform::Clamp(xMoveR, 1, halfScreen); if (bEven) { xMoveL = xMoveR; } else { xMoveL = rcClient.Width() - xMoveR - 4; } if (pt.x < rcClient.left) { // Caret is on the left of the display newXY.xOffset -= xMoveL; } else if (pt.x >= rcClient.right) { // Caret is on the right of the display newXY.xOffset += xMoveR; } } } else { // No slop if (bStrict || (bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) { // Strict or going out of display if (bEven) { // Center caret newXY.xOffset += pt.x - rcClient.left - halfScreen; } else { // Put caret on right newXY.xOffset += pt.x - rcClient.right + 1; } } else { // Move just enough to allow to display the caret if (pt.x < rcClient.left) { // Caret is on the left of the display if (bEven) { newXY.xOffset -= rcClient.left - pt.x; } else { newXY.xOffset += pt.x - rcClient.right + 1; } } else if (pt.x >= rcClient.right) { // Caret is on the right of the display newXY.xOffset += pt.x - rcClient.right + 1; } } } // In case of a jump (find result) largely out of display, adjust the offset to display the caret if (pt.x + xOffset < rcClient.left + newXY.xOffset) { newXY.xOffset = pt.x + xOffset - rcClient.left; } else if (pt.x + xOffset >= rcClient.right + newXY.xOffset) { newXY.xOffset = pt.x + xOffset - rcClient.right + 1; if (vs.caretStyle == CARETSTYLE_BLOCK) { // Ensure we can see a good portion of the block caret newXY.xOffset += static_cast(vs.aveCharWidth); } } if (newXY.xOffset < 0) { newXY.xOffset = 0; } } return newXY; } void Editor::SetXYScroll(XYScrollPosition newXY) { if ((newXY.topLine != topLine) || (newXY.xOffset != xOffset)) { if (newXY.topLine != topLine) { SetTopLine(newXY.topLine); SetVerticalScrollPos(); } if (newXY.xOffset != xOffset) { xOffset = newXY.xOffset; ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); if (newXY.xOffset > 0) { PRectangle rcText = GetTextRectangle(); if (horizontalScrollBarVisible && rcText.Width() + xOffset > scrollWidth) { scrollWidth = xOffset + rcText.Width(); SetScrollBars(); } } SetHorizontalScrollPos(); } Redraw(); UpdateSystemCaret(); } } void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) { SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz)); } void Editor::ShowCaretAtCurrentPosition() { if (hasFocus) { caret.active = true; caret.on = true; SetTicking(true); } else { caret.active = false; caret.on = false; } InvalidateCaret(); } void Editor::DropCaret() { caret.active = false; InvalidateCaret(); } void Editor::InvalidateCaret() { if (posDrag.IsValid()) { InvalidateRange(posDrag.Position(), posDrag.Position() + 1); } else { for (size_t r=0; rLinesTotal()); if (wrapStart > docLineStart) { wrapStart = docLineStart; llc.Invalidate(LineLayout::llPositions); } if (wrapEnd < docLineEnd) { wrapEnd = docLineEnd; } wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal()); // Wrap lines during idle. if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) { SetIdle(true); } } bool Editor::WrapOneLine(Surface *surface, int lineToWrap) { AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap)); int linesWrapped = 1; if (ll) { LayoutLine(lineToWrap, surface, vs, ll, wrapWidth); linesWrapped = ll->lines; } return cs.SetHeight(lineToWrap, linesWrapped + (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0)); } // Check if wrapping needed and perform any needed wrapping. // fullwrap: if true, all lines which need wrapping will be done, // in this single call. // priorityWrapLineStart: If greater than or equal to zero, all lines starting from // here to 1 page + 100 lines past will be wrapped (even if there are // more lines under wrapping process in idle). // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be // wrapped, if there are any wrapping going on in idle. (Generally this // condition is called only from idler). // Return true if wrapping occurred. bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { // If there are any pending wraps, do them during idle if possible. int linesInOneCall = LinesOnScreen() + 100; if (priorityWrapLineStart >= 0) { // Using DocFromDisplay() here may result in chicken and egg problem in certain corner cases, // which will hopefully be handled by added 100 lines. If some lines are still missed, idle wrapping will catch on. int docLinesInOneCall = cs.DocFromDisplay(topLine + LinesOnScreen() + 100) - cs.DocFromDisplay(topLine); linesInOneCall = Platform::Maximum(linesInOneCall, docLinesInOneCall); } if (wrapState != eWrapNone) { if (wrapStart < wrapEnd) { if (!SetIdle(true)) { // Idle processing not supported so full wrap required. fullWrap = true; } } if (!fullWrap && priorityWrapLineStart >= 0 && // .. and if the paint window is outside pending wraps (((priorityWrapLineStart + linesInOneCall) < wrapStart) || (priorityWrapLineStart > wrapEnd))) { // No priority wrap pending return false; } } int goodTopLine = topLine; bool wrapOccurred = false; if (wrapStart <= pdoc->LinesTotal()) { if (wrapState == eWrapNone) { if (wrapWidth != LineLayout::wrapWidthInfinite) { wrapWidth = LineLayout::wrapWidthInfinite; for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { cs.SetHeight(lineDoc, 1 + (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); } wrapOccurred = true; } wrapStart = wrapLineLarge; wrapEnd = wrapLineLarge; } else { if (wrapEnd >= pdoc->LinesTotal()) wrapEnd = pdoc->LinesTotal(); //ElapsedTime et; int lineDocTop = cs.DocFromDisplay(topLine); int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop); PRectangle rcTextArea = GetClientRectangle(); rcTextArea.left = vs.fixedColumnWidth; rcTextArea.right -= vs.rightMarginWidth; wrapWidth = rcTextArea.Width(); RefreshStyleData(); AutoSurface surface(this); if (surface) { bool priorityWrap = false; int lastLineToWrap = wrapEnd; int lineToWrap = wrapStart; if (!fullWrap) { if (priorityWrapLineStart >= 0) { // This is a priority wrap. lineToWrap = priorityWrapLineStart; lastLineToWrap = priorityWrapLineStart + linesInOneCall; priorityWrap = true; } else { // This is idle wrap. lastLineToWrap = wrapStart + linesInOneCall; } if (lastLineToWrap >= wrapEnd) lastLineToWrap = wrapEnd; } // else do a fullWrap. // Ensure all lines being wrapped are styled. pdoc->EnsureStyledTo(pdoc->LineEnd(lastLineToWrap)); // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap); // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd); while (lineToWrap < lastLineToWrap) { if (WrapOneLine(surface, lineToWrap)) { wrapOccurred = true; } lineToWrap++; } if (!priorityWrap) wrapStart = lineToWrap; // If wrapping is done, bring it to resting position if (wrapStart >= wrapEnd) { wrapStart = wrapLineLarge; wrapEnd = wrapLineLarge; } } goodTopLine = cs.DisplayFromDoc(lineDocTop); if (subLineTop < cs.GetHeight(lineDocTop)) goodTopLine += subLineTop; else goodTopLine += cs.GetHeight(lineDocTop); //double durWrap = et.Duration(true); //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap); } } if (wrapOccurred) { SetScrollBars(); SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos())); SetVerticalScrollPos(); } return wrapOccurred; } void Editor::LinesJoin() { if (!RangeContainsProtected(targetStart, targetEnd)) { UndoGroup ug(pdoc); bool prevNonWS = true; for (int pos = targetStart; pos < targetEnd; pos++) { if (IsEOLChar(pdoc->CharAt(pos))) { targetEnd -= pdoc->LenChar(pos); pdoc->DelChar(pos); if (prevNonWS) { // Ensure at least one space separating previous lines pdoc->InsertChar(pos, ' '); targetEnd++; } } else { prevNonWS = pdoc->CharAt(pos) != ' '; } } } } const char *Editor::StringFromEOLMode(int eolMode) { if (eolMode == SC_EOL_CRLF) { return "\r\n"; } else if (eolMode == SC_EOL_CR) { return "\r"; } else { return "\n"; } } void Editor::LinesSplit(int pixelWidth) { if (!RangeContainsProtected(targetStart, targetEnd)) { if (pixelWidth == 0) { PRectangle rcText = GetTextRectangle(); pixelWidth = rcText.Width(); } int lineStart = pdoc->LineFromPosition(targetStart); int lineEnd = pdoc->LineFromPosition(targetEnd); const char *eol = StringFromEOLMode(pdoc->eolMode); UndoGroup ug(pdoc); for (int line = lineStart; line <= lineEnd; line++) { AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); if (surface && ll) { unsigned int posLineStart = pdoc->LineStart(line); LayoutLine(line, surface, vs, ll, pixelWidth); for (int subLine = 1; subLine < ll->lines; subLine++) { pdoc->InsertCString( static_cast(posLineStart + (subLine - 1) * strlen(eol) + ll->LineStart(subLine)), eol); targetEnd += static_cast(strlen(eol)); } } lineEnd = pdoc->LineFromPosition(targetEnd); } } } int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) { if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) return markerDefault; return markerCheck; } bool ValidStyledText(ViewStyle &vs, size_t styleOffset, const StyledText &st) { if (st.multipleStyles) { for (size_t iStyle=0; iStyle(styles[endSegment+1]) == style)) endSegment++; width += surface->WidthText(vs.styles[style+styleOffset].font, text + start, static_cast(endSegment - start + 1)); start = endSegment + 1; } return width; } static int WidestLineWidth(Surface *surface, ViewStyle &vs, int styleOffset, const StyledText &st) { int widthMax = 0; size_t start = 0; while (start < st.length) { size_t lenLine = st.LineLength(start); int widthSubLine; if (st.multipleStyles) { widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); } else { widthSubLine = surface->WidthText(vs.styles[styleOffset + st.style].font, st.text + start, static_cast(lenLine)); } if (widthSubLine > widthMax) widthMax = widthSubLine; start += lenLine + 1; } return widthMax; } void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent, const StyledText &st, size_t start, size_t length) { if (st.multipleStyles) { int x = rcText.left; size_t i = 0; while (i < length) { size_t end = i; int style = st.styles[i + start]; while (end < length-1 && st.styles[start+end+1] == style) end++; style += styleOffset; int width = surface->WidthText(vs.styles[style].font, st.text + start + i, static_cast(end - i + 1)); PRectangle rcSegment = rcText; rcSegment.left = x; rcSegment.right = x + width + 1; surface->DrawTextNoClip(rcSegment, vs.styles[style].font, ascent, st.text + start + i, static_cast(end - i + 1), vs.styles[style].fore, vs.styles[style].back); x += width; i = end + 1; } } else { size_t style = st.style + styleOffset; surface->DrawTextNoClip(rcText, vs.styles[style].font, rcText.top + vs.maxAscent, st.text + start, static_cast(length), vs.styles[style].fore, vs.styles[style].back); } } void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (vs.fixedColumnWidth == 0) return; PRectangle rcMargin = GetClientRectangle(); rcMargin.right = vs.fixedColumnWidth; if (!rc.Intersects(rcMargin)) return; Surface *surface; if (bufferedDraw) { surface = pixmapSelMargin; } else { surface = surfWindow; } // Clip vertically to paint area to avoid drawing line numbers if (rcMargin.bottom > rc.bottom) rcMargin.bottom = rc.bottom; if (rcMargin.top < rc.top) rcMargin.top = rc.top; PRectangle rcSelMargin = rcMargin; rcSelMargin.right = rcMargin.left; for (int margin = 0; margin < vs.margins; margin++) { if (vs.ms[margin].width > 0) { rcSelMargin.left = rcSelMargin.right; rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; if (vs.ms[margin].style != SC_MARGIN_NUMBER) { if (vs.ms[margin].mask & SC_MASK_FOLDERS) // Required because of special way brush is created for selection margin surface->FillRectangle(rcSelMargin, *pixmapSelPattern); else { ColourDesired colour; switch (vs.ms[margin].style) { case SC_MARGIN_BACK: colour = vs.styles[STYLE_DEFAULT].back; break; case SC_MARGIN_FORE: colour = vs.styles[STYLE_DEFAULT].fore; break; default: colour = vs.styles[STYLE_LINENUMBER].back; break; } surface->FillRectangle(rcSelMargin, colour); } } else { surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back); } const int lineStartPaint = rcMargin.top / vs.lineHeight; int visibleLine = topLine + lineStartPaint; int yposScreen = lineStartPaint * vs.lineHeight; // Work out whether the top line is whitespace located after a // lessening of fold level which implies a 'fold tail' but which should not // be displayed until the last of a sequence of whitespace. bool needWhiteClosure = false; if (vs.ms[margin].mask & SC_MASK_FOLDERS) { int level = pdoc->GetLevel(cs.DocFromDisplay(visibleLine)); if (level & SC_FOLDLEVELWHITEFLAG) { int lineBack = cs.DocFromDisplay(visibleLine); int levelPrev = level; while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) { lineBack--; levelPrev = pdoc->GetLevel(lineBack); } if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK)) needWhiteClosure = true; } } if (highlightDelimiter.isEnabled) { int lastLine = cs.DocFromDisplay(topLine + LinesOnScreen()) + 1; pdoc->GetHighlightDelimiters(highlightDelimiter, pdoc->LineFromPosition(CurrentPosition()), lastLine); } } // Old code does not know about new markers needed to distinguish all cases int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID, SC_MARKNUM_FOLDEROPEN); int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND, SC_MARKNUM_FOLDER); while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) { PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed()); int lineDoc = cs.DocFromDisplay(visibleLine); PLATFORM_ASSERT(cs.GetVisible(lineDoc)); bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc); bool lastSubLine = visibleLine == (cs.DisplayFromDoc(lineDoc + 1) - 1); int marks = pdoc->GetMark(lineDoc); if (!firstSubLine) marks = 0; bool headWithTail = false; if (vs.ms[margin].mask & SC_MASK_FOLDERS) { // Decide which fold indicator should be displayed int level = pdoc->GetLevel(lineDoc); int levelNext = pdoc->GetLevel(lineDoc + 1); int levelNum = level & SC_FOLDLEVELNUMBERMASK; int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK; if (level & SC_FOLDLEVELHEADERFLAG) { if (firstSubLine) { if (levelNum < levelNextNum) { if (cs.GetExpanded(lineDoc)) { if (levelNum == SC_FOLDLEVELBASE) marks |= 1 << SC_MARKNUM_FOLDEROPEN; else marks |= 1 << folderOpenMid; } else { if (levelNum == SC_FOLDLEVELBASE) marks |= 1 << SC_MARKNUM_FOLDER; else marks |= 1 << folderEnd; } } else if (levelNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } else { if (levelNum < levelNextNum) { if (cs.GetExpanded(lineDoc)) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } else if (levelNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } else if (levelNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } needWhiteClosure = false; int firstFollowupLine = cs.DocFromDisplay(cs.DisplayFromDoc(lineDoc + 1)); int firstFollowupLineLevel = pdoc->GetLevel(firstFollowupLine); int secondFollowupLineLevelNum = pdoc->GetLevel(firstFollowupLine + 1) & SC_FOLDLEVELNUMBERMASK; if (!cs.GetExpanded(lineDoc)) { if ((firstFollowupLineLevel & SC_FOLDLEVELWHITEFLAG) && (levelNum > secondFollowupLineLevelNum)) needWhiteClosure = true; if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) headWithTail = true; } } else if (level & SC_FOLDLEVELWHITEFLAG) { if (needWhiteClosure) { if (levelNext & SC_FOLDLEVELWHITEFLAG) { marks |= 1 << SC_MARKNUM_FOLDERSUB; } else if (levelNextNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; needWhiteClosure = false; } else { marks |= 1 << SC_MARKNUM_FOLDERTAIL; needWhiteClosure = false; } } else if (levelNum > SC_FOLDLEVELBASE) { if (levelNextNum < levelNum) { if (levelNextNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; } else { marks |= 1 << SC_MARKNUM_FOLDERTAIL; } } else { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } } else if (levelNum > SC_FOLDLEVELBASE) { if (levelNextNum < levelNum) { needWhiteClosure = false; if (levelNext & SC_FOLDLEVELWHITEFLAG) { marks |= 1 << SC_MARKNUM_FOLDERSUB; needWhiteClosure = true; } else if (lastSubLine) { if (levelNextNum > SC_FOLDLEVELBASE) { marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL; } else { marks |= 1 << SC_MARKNUM_FOLDERTAIL; } } else { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } else { marks |= 1 << SC_MARKNUM_FOLDERSUB; } } } marks &= vs.ms[margin].mask; PRectangle rcMarker = rcSelMargin; rcMarker.top = yposScreen; rcMarker.bottom = yposScreen + vs.lineHeight; if (vs.ms[margin].style == SC_MARGIN_NUMBER) { if (firstSubLine) { char number[100]; sprintf(number, "%d", lineDoc + 1); if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) { int lev = pdoc->GetLevel(lineDoc); sprintf(number, "%c%c %03X %03X", (lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_', (lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_', lev & SC_FOLDLEVELNUMBERMASK, lev >> 16 ); } PRectangle rcNumber = rcMarker; // Right justify XYPOSITION width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number)); XYPOSITION xpos = rcNumber.right - width - 3; rcNumber.left = xpos; surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font, rcNumber.top + vs.maxAscent, number, istrlen(number), vs.styles[STYLE_LINENUMBER].fore, vs.styles[STYLE_LINENUMBER].back); } else if (wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) { PRectangle rcWrapMarker = rcMarker; rcWrapMarker.right -= 3; rcWrapMarker.left = rcWrapMarker.right - vs.styles[STYLE_LINENUMBER].aveCharWidth; DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore); } } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) { if (firstSubLine) { const StyledText stMargin = pdoc->MarginStyledText(lineDoc); if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back); if (vs.ms[margin].style == SC_MARGIN_RTEXT) { int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); rcMarker.left = rcMarker.right - width - 3; } DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent, stMargin, 0, stMargin.length); } } } if (marks) { for (int markBit = 0; (markBit < 32) && marks; markBit++) { if (marks & 1) { LineMarker::typeOfFold tFold = LineMarker::undefined; if ((vs.ms[margin].mask & SC_MASK_FOLDERS) && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { tFold = LineMarker::body; } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { if (firstSubLine) { tFold = headWithTail ? LineMarker::headWithTail : LineMarker::head; } else { if (cs.GetExpanded(lineDoc) || headWithTail) { tFold = LineMarker::body; } else { tFold = LineMarker::undefined; } } } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { tFold = LineMarker::tail; } } vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font, tFold, vs.ms[margin].style); } marks >>= 1; } } visibleLine++; yposScreen += vs.lineHeight; } } } PRectangle rcBlankMargin = rcMargin; rcBlankMargin.left = rcSelMargin.right; surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back); if (bufferedDraw) { surfWindow->Copy(rcMargin, Point(rcMargin.left, rcMargin.top), *pixmapSelMargin); } } void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { int ydiff = (rcTab.bottom - rcTab.top) / 2; int xhead = rcTab.right - 1 - ydiff; if (xhead <= rcTab.left) { ydiff -= rcTab.left - xhead - 1; xhead = rcTab.left - 1; } if ((rcTab.left + 2) < (rcTab.right - 1)) surface->MoveTo(rcTab.left + 2, ymid); else surface->MoveTo(rcTab.right - 1, ymid); surface->LineTo(rcTab.right - 1, ymid); surface->LineTo(xhead, ymid - ydiff); surface->MoveTo(rcTab.right - 1, ymid); surface->LineTo(xhead, ymid + ydiff); } LineLayout *Editor::RetrieveLineLayout(int lineNumber) { int posLineStart = pdoc->LineStart(lineNumber); int posLineEnd = pdoc->LineStart(lineNumber + 1); PLATFORM_ASSERT(posLineEnd >= posLineStart); int lineCaret = pdoc->LineFromPosition(sel.MainCaret()); return llc.Retrieve(lineNumber, lineCaret, posLineEnd - posLineStart, pdoc->GetStyleClock(), LinesOnScreen() + 1, pdoc->LinesTotal()); } bool BadUTF(const char *s, int len, int &trailBytes) { // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 if (trailBytes) { trailBytes--; return false; } int utf8status = UTF8Classify(reinterpret_cast(s), len); if (utf8status & UTF8MaskInvalid) { return true; } else { trailBytes = (utf8status & UTF8MaskWidth) - 1; return false; } } /** * Fill in the LineLayout data for the given line. * Copy the given @a line and its styles from the document into local arrays. * Also determine the x position at which each character starts. */ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) { if (!ll) return; PLATFORM_ASSERT(line < pdoc->LinesTotal()); PLATFORM_ASSERT(ll->chars != NULL); int posLineStart = pdoc->LineStart(line); int posLineEnd = pdoc->LineStart(line + 1); // If the line is very long, limit the treatment to a length that should fit in the viewport if (posLineEnd > (posLineStart + ll->maxLineLength)) { posLineEnd = posLineStart + ll->maxLineLength; } if (ll->validity == LineLayout::llCheckTextAndStyle) { int lineLength = posLineEnd - posLineStart; if (!vstyle.viewEOL) { lineLength = pdoc->LineEnd(line) - posLineStart; } if (lineLength == ll->numCharsInLine) { // See if chars, styles, indicators, are all the same bool allSame = true; const int styleMask = pdoc->stylingBitsMask; // Check base line layout char styleByte = 0; int numCharsInLine = 0; while (numCharsInLine < lineLength) { int charInDoc = numCharsInLine + posLineStart; char chDoc = pdoc->CharAt(charInDoc); styleByte = pdoc->StyleAt(charInDoc); allSame = allSame && (ll->styles[numCharsInLine] == static_cast(styleByte & styleMask)); allSame = allSame && (ll->indicators[numCharsInLine] == static_cast(styleByte & ~styleMask)); if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) allSame = allSame && (ll->chars[numCharsInLine] == chDoc); else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) allSame = allSame && (ll->chars[numCharsInLine] == static_cast(tolower(chDoc))); else // Style::caseUpper allSame = allSame && (ll->chars[numCharsInLine] == static_cast(toupper(chDoc))); numCharsInLine++; } allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled if (allSame) { ll->validity = LineLayout::llPositions; } else { ll->validity = LineLayout::llInvalid; } } else { ll->validity = LineLayout::llInvalid; } } if (ll->validity == LineLayout::llInvalid) { ll->widthLine = LineLayout::wrapWidthInfinite; ll->lines = 1; if (vstyle.edgeState == EDGE_BACKGROUND) { ll->edgeColumn = pdoc->FindColumn(line, theEdge); if (ll->edgeColumn >= posLineStart) { ll->edgeColumn -= posLineStart; } } else { ll->edgeColumn = -1; } char styleByte; const int styleMask = pdoc->stylingBitsMask; ll->styleBitsSet = 0; // Fill base line layout const int lineLength = posLineEnd - posLineStart; pdoc->GetCharRange(ll->chars, posLineStart, lineLength); pdoc->GetStyleRange(ll->styles, posLineStart, lineLength); int numCharsBeforeEOL = pdoc->LineEnd(line) - posLineStart; const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { styleByte = ll->styles[styleInLine]; ll->styleBitsSet |= styleByte; ll->styles[styleInLine] = static_cast(styleByte & styleMask); ll->indicators[styleInLine] = static_cast(styleByte & ~styleMask); } styleByte = static_cast(((lineLength > 0) ? ll->styles[lineLength-1] : 0) & styleMask); if (vstyle.someStylesForceCase) { for (int charInLine = 0; charInLinechars[charInLine]; if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper) ll->chars[charInLine] = static_cast(toupper(chDoc)); else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower) ll->chars[charInLine] = static_cast(tolower(chDoc)); } } ll->xHighlightGuide = 0; // Extra element at the end of the line to hold end x position and act as ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character ll->styles[numCharsInLine] = styleByte; // For eolFilled ll->indicators[numCharsInLine] = 0; // Layout the line, determining the position of each character, // with an extra element at the end for the end of the line. int startseg = 0; // Start of the current segment, in char. number XYACCUMULATOR startsegx = 0; // Start of the current segment, in pixels ll->positions[0] = 0; XYPOSITION tabWidth = vstyle.spaceWidth * pdoc->tabInChars; bool lastSegItalics = false; Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font; XYPOSITION ctrlCharWidth[32] = {0}; bool isControlNext = IsControlCharacter(ll->chars[0]); int trailBytes = 0; bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes); for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) { bool isControl = isControlNext; isControlNext = IsControlCharacter(ll->chars[charInLine + 1]); bool isBadUTF = isBadUTFNext; isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes); if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) || isControl || isControlNext || isBadUTF || isBadUTFNext) { ll->positions[startseg] = 0; if (vstyle.styles[ll->styles[charInLine]].visible) { if (isControl) { if (ll->chars[charInLine] == '\t') { ll->positions[charInLine + 1] = ((static_cast((startsegx + 2) / tabWidth) + 1) * tabWidth) - startsegx; } else if (controlCharSymbol < 32) { if (ctrlCharWidth[ll->chars[charInLine]] == 0) { const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]); // +3 For a blank on front and rounded edge each side: ctrlCharWidth[ll->chars[charInLine]] = surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3; } ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]]; } else { char cc[2] = { static_cast(controlCharSymbol), '\0' }; surface->MeasureWidths(ctrlCharsFont, cc, 1, ll->positions + startseg + 1); } lastSegItalics = false; } else if (isBadUTF) { char hexits[4]; sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff); ll->positions[charInLine + 1] = surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3; } else { // Regular character int lenSeg = charInLine - startseg + 1; if ((lenSeg == 1) && (' ' == ll->chars[startseg])) { lastSegItalics = false; // Over half the segments are single characters and of these about half are space characters. ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth; } else { lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic; posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg, lenSeg, ll->positions + startseg + 1, pdoc); } } } else { // invisible for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) { ll->positions[posToZero] = 0; } } for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) { ll->positions[posToIncrease] += startsegx; } startsegx = ll->positions[charInLine + 1]; startseg = charInLine + 1; } } // Small hack to make lines that end with italics not cut off the edge of the last character if ((startseg > 0) && lastSegItalics) { ll->positions[startseg] += 2; } ll->numCharsInLine = numCharsInLine; ll->numCharsBeforeEOL = numCharsBeforeEOL; ll->validity = LineLayout::llPositions; } // Hard to cope when too narrow, so just assume there is space if (width < 20) { width = 20; } if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { ll->widthLine = width; if (width == LineLayout::wrapWidthInfinite) { ll->lines = 1; } else if (width > ll->positions[ll->numCharsInLine]) { // Simple common case where line does not need wrapping. ll->lines = 1; } else { if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) { width -= static_cast(vstyle.aveCharWidth); // take into account the space for end wrap mark } XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line if (wrapIndentMode == SC_WRAPINDENT_INDENT) { wrapAddIndent = pdoc->IndentSize() * vstyle.spaceWidth; } else if (wrapIndentMode == SC_WRAPINDENT_FIXED) { wrapAddIndent = wrapVisualStartIndent * vstyle.aveCharWidth; } ll->wrapIndent = wrapAddIndent; if (wrapIndentMode != SC_WRAPINDENT_FIXED) for (int i = 0; i < ll->numCharsInLine; i++) { if (!IsSpaceOrTab(ll->chars[i])) { ll->wrapIndent += ll->positions[i]; // Add line indent break; } } // Check for text width minimum if (ll->wrapIndent > width - static_cast(vstyle.aveCharWidth) * 15) ll->wrapIndent = wrapAddIndent; // Check for wrapIndent minimum if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth)) ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual ll->lines = 0; // Calculate line start positions based upon width. int lastGoodBreak = 0; int lastLineStart = 0; XYACCUMULATOR startOffset = 0; int p = 0; while (p < ll->numCharsInLine) { if ((ll->positions[p + 1] - startOffset) >= width) { if (lastGoodBreak == lastLineStart) { // Try moving to start of last character if (p > 0) { lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) - posLineStart; } if (lastGoodBreak == lastLineStart) { // Ensure at least one character on line. lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) - posLineStart; } } lastLineStart = lastGoodBreak; ll->lines++; ll->SetLineStart(ll->lines, lastGoodBreak); startOffset = ll->positions[lastGoodBreak]; // take into account the space for start wrap mark and indent startOffset -= ll->wrapIndent; p = lastGoodBreak + 1; continue; } if (p > 0) { if (wrapState == eWrapChar) { lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1) - posLineStart; p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; continue; } else if (ll->styles[p] != ll->styles[p - 1]) { lastGoodBreak = p; } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { lastGoodBreak = p; } } p++; } ll->lines++; } ll->validity = LineLayout::llLines; } } ColourDesired Editor::SelectionBackground(ViewStyle &vsDraw, bool main) { return main ? (primarySelection ? vsDraw.selbackground : vsDraw.selbackground2) : vsDraw.selAdditionalBackground; } ColourDesired Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground, ColourDesired background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) { if (inSelection == 1) { if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { return SelectionBackground(vsDraw, true); } } else if (inSelection == 2) { if (vsDraw.selbackset && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { return SelectionBackground(vsDraw, false); } } else { if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll->edgeColumn) && (i < ll->numCharsBeforeEOL)) return vsDraw.edgecolour; if (inHotspot && vsDraw.hotspotBackgroundSet) return vsDraw.hotspotBackground; } if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) { return background; } else { return vsDraw.styles[styleMain].back; } } void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) { Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom); surface->Copy(rcCopyArea, from, highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); } void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour) { surface->PenColour(wrapColour); enum { xa = 1 }; // gap before start int w = rcPlace.right - rcPlace.left - xa - 1; bool xStraight = isEndMarker; // x-mirrored symbol for start marker bool yStraight = true; //bool yStraight= isEndMarker; // comment in for start marker y-mirrowed int x0 = xStraight ? rcPlace.left : rcPlace.right - 1; int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1; int dy = (rcPlace.bottom - rcPlace.top) / 5; int y = (rcPlace.bottom - rcPlace.top) / 2 + dy; struct Relative { Surface *surface; int xBase; int xDir; int yBase; int yDir; void MoveTo(int xRelative, int yRelative) { surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } void LineTo(int xRelative, int yRelative) { surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } }; Relative rel = {surface, x0, xStraight ? 1 : -1, y0, yStraight ? 1 : -1}; // arrow head rel.MoveTo(xa, y); rel.LineTo(xa + 2*w / 3, y - dy); rel.MoveTo(xa, y); rel.LineTo(xa + 2*w / 3, y + dy); // arrow body rel.MoveTo(xa, y); rel.LineTo(xa + w, y); rel.LineTo(xa + w, y - 2 * dy); rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... y - 2 * dy); } static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) { if (alpha != SC_ALPHA_NOALPHA) { surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); } } void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment, const char *s, ColourDesired textBack, ColourDesired textFore, bool twoPhaseDraw) { if (!twoPhaseDraw) { surface->FillRectangle(rcSegment, textBack); } Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; int normalCharHeight = surface->Ascent(ctrlCharsFont) - surface->InternalLeading(ctrlCharsFont); PRectangle rcCChar = rcSegment; rcCChar.left = rcCChar.left + 1; rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; PRectangle rcCentral = rcCChar; rcCentral.top++; rcCentral.bottom--; surface->FillRectangle(rcCentral, textFore); PRectangle rcChar = rcCChar; rcChar.left++; rcChar.right--; surface->DrawTextClipped(rcChar, ctrlCharsFont, rcSegment.top + vsDraw.maxAscent, s, istrlen(s), textBack, textFore); } void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll, int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, bool overrideBackground, ColourDesired background, bool drawWrapMarkEnd, ColourDesired wrapColour) { const int posLineStart = pdoc->LineStart(line); const int styleMask = pdoc->stylingBitsMask; PRectangle rcSegment = rcLine; const bool lastSubLine = subLine == (ll->lines - 1); XYPOSITION virtualSpace = 0; if (lastSubLine) { const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * spaceWidth; } XYPOSITION xEol = ll->positions[lineEnd] - subLineStart; // Fill the virtual space and show selections within it if (virtualSpace) { rcSegment.left = xEol + xStart; rcSegment.right = xEol + xStart + virtualSpace; surface->FillRectangle(rcSegment, overrideBackground ? background : vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { SelectionSegment virtualSpaceRange(SelectionPosition(pdoc->LineEnd(line)), SelectionPosition(pdoc->LineEnd(line), sel.VirtualSpaceFor(pdoc->LineEnd(line)))); for (size_t r=0; rEndLineStyle()].spaceWidth; rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth; rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth; rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == sel.Main())); } } } } } int eolInSelection = 0; int alpha = SC_ALPHA_NOALPHA; if (!hideSelection) { int posAfterLineEnd = pdoc->LineStart(line + 1); eolInSelection = (subLine == (ll->lines - 1)) ? sel.InSelectionForEOL(posAfterLineEnd) : 0; alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; } // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on XYPOSITION blobsWidth = 0; if (lastSubLine) { for (int eolPos=ll->numCharsBeforeEOL; eolPosnumCharsInLine; eolPos++) { rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace; rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace; blobsWidth += rcSegment.Width(); const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]); int styleMain = ll->styles[eolPos]; ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, eolInSelection, false, styleMain, eolPos, ll); ColourDesired textFore = vsDraw.styles[styleMain].fore; if (eolInSelection && vsDraw.selforeset) { textFore = (eolInSelection == 1) ? vsDraw.selforeground : vsDraw.selAdditionalForeground; } if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) { if (alpha == SC_ALPHA_NOALPHA) { surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); } else { surface->FillRectangle(rcSegment, textBack); } } else { surface->FillRectangle(rcSegment, textBack); } DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); } } } // Draw the eol-is-selected rectangle rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); } else { if (overrideBackground) { surface->FillRectangle(rcSegment, background); } else if (line < pdoc->LinesTotal() - 1) { surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) { surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); } else { surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); } if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); } } // Fill the remainder of the line rcSegment.left = rcSegment.right; if (rcSegment.left < rcLine.left) rcSegment.left = rcLine.left; rcSegment.right = rcLine.right; if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); } else { if (overrideBackground) { surface->FillRectangle(rcSegment, background); } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) { surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back); } else { surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); } if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); } } if (drawWrapMarkEnd) { PRectangle rcPlace = rcSegment; if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { rcPlace.left = xEol + xStart + virtualSpace; rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; } else { // rcLine is clipped to text area rcPlace.right = rcLine.right; rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; } DrawWrapMarker(surface, rcPlace, true, wrapColour); } } void Editor::DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, ViewStyle &vsDraw, int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)]; PRectangle rcIndic( ll->positions[startPos] + xStart - subLineStart, rcLine.top + vsDraw.maxAscent, ll->positions[endPos] + xStart - subLineStart, rcLine.top + vsDraw.maxAscent + 3); vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine); } void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) { // Draw decorators const int posLineStart = pdoc->LineStart(line); const int lineStart = ll->LineStart(subLine); const int posLineEnd = posLineStart + lineEnd; if (!under) { // Draw indicators // foreach indicator... for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) { if (!(mask & ll->styleBitsSet)) { mask <<= 1; continue; } int startPos = -1; // foreach style pos in line... for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) { // look for starts... if (startPos < 0) { // NOT in indicator run, looking for START if (indicPos < lineEnd && (ll->indicators[indicPos] & mask)) startPos = indicPos; } // ... or ends if (startPos >= 0) { // IN indicator run, looking for END if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) { // AT end of indicator run, DRAW it! DrawIndicator(indicnum, startPos, indicPos, surface, vsDraw, xStart, rcLine, ll, subLine); // RESET control var startPos = -1; } } } mask <<= 1; } } for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) { if (under == vsDraw.indicators[deco->indicator].under) { int startPos = posLineStart + lineStart; if (!deco->rs.ValueAt(startPos)) { startPos = deco->rs.EndRun(startPos); } while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) { int endPos = deco->rs.EndRun(startPos); if (endPos > posLineEnd) endPos = posLineEnd; DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart, surface, vsDraw, xStart, rcLine, ll, subLine); startPos = deco->rs.EndRun(endPos); } } } // Use indicators to highlight matching braces if ((vs.braceHighlightIndicatorSet && (bracesMatchStyle == STYLE_BRACELIGHT)) || (vs.braceBadLightIndicatorSet && (bracesMatchStyle == STYLE_BRACEBAD))) { int braceIndicator = (bracesMatchStyle == STYLE_BRACELIGHT) ? vs.braceHighlightIndicator : vs.braceBadLightIndicator; if (under == vsDraw.indicators[braceIndicator].under) { Range rangeLine(posLineStart + lineStart, posLineEnd); if (rangeLine.ContainsCharacter(braces[0])) { int braceOffset = braces[0] - posLineStart; if (braceOffset < ll->numCharsInLine) { DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, xStart, rcLine, ll, subLine); } } if (rangeLine.ContainsCharacter(braces[1])) { int braceOffset = braces[1] - posLineStart; if (braceOffset < ll->numCharsInLine) { DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, xStart, rcLine, ll, subLine); } } } } } void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { int indent = pdoc->GetLineIndentation(line) * vsDraw.spaceWidth; PRectangle rcSegment = rcLine; int annotationLine = subLine - ll->lines; const StyledText stAnnotation = pdoc->AnnotationStyledText(line); if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { surface->FillRectangle(rcSegment, vsDraw.styles[0].back); if (vs.annotationVisible == ANNOTATION_BOXED) { // Only care about calculating width if need to draw box int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); widthAnnotation += vsDraw.spaceWidth * 2; // Margins rcSegment.left = xStart + indent; rcSegment.right = rcSegment.left + widthAnnotation; } else { rcSegment.left = xStart; } const int annotationLines = pdoc->AnnotationLines(line); size_t start = 0; size_t lengthAnnotation = stAnnotation.LineLength(start); int lineInAnnotation = 0; while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { start += lengthAnnotation + 1; lengthAnnotation = stAnnotation.LineLength(start); lineInAnnotation++; } PRectangle rcText = rcSegment; if (vs.annotationVisible == ANNOTATION_BOXED) { surface->FillRectangle(rcText, vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); rcText.left += vsDraw.spaceWidth; } DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent, stAnnotation, start, lengthAnnotation); if (vs.annotationVisible == ANNOTATION_BOXED) { surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); surface->MoveTo(rcSegment.left, rcSegment.top); surface->LineTo(rcSegment.left, rcSegment.bottom); surface->MoveTo(rcSegment.right, rcSegment.top); surface->LineTo(rcSegment.right, rcSegment.bottom); if (subLine == ll->lines) { surface->MoveTo(rcSegment.left, rcSegment.top); surface->LineTo(rcSegment.right, rcSegment.top); } if (subLine == ll->lines+annotationLines-1) { surface->MoveTo(rcSegment.left, rcSegment.bottom - 1); surface->LineTo(rcSegment.right, rcSegment.bottom - 1); } } } } void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { PRectangle rcSegment = rcLine; // Using one font for all control characters so it can be controlled independently to ensure // the box goes around the characters tightly. Seems to be no way to work out what height // is taken by an individual character - internal leading gives varying results. Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; // See if something overrides the line background color: Either if caret is on the line // and background color is set for that, or if a marker is defined that forces its background // color onto the line, or if a marker is defined but has no selection margin in which to // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order // with the earlier taking precedence. When multiple markers cause background override, // the color for the highest numbered one is used. bool overrideBackground = false; ColourDesired background; if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) { overrideBackground = true; background = vsDraw.caretLineBackground; } if (!overrideBackground) { int marks = pdoc->GetMark(line); for (int markBit = 0; (markBit < 32) && marks; markBit++) { if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) && (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { background = vsDraw.markers[markBit].back; overrideBackground = true; } marks >>= 1; } } if (!overrideBackground) { if (vsDraw.maskInLine) { int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine; if (marksMasked) { for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) { if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) && (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { overrideBackground = true; background = vsDraw.markers[markBit].back; } marksMasked >>= 1; } } } } bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) && (!overrideBackground) && (vsDraw.whitespaceBackgroundSet); bool inIndentation = subLine == 0; // Do not handle indentation except on first subline. const XYPOSITION indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth; const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues int posLineStart = pdoc->LineStart(line); int startseg = ll->LineStart(subLine); XYACCUMULATOR subLineStart = ll->positions[startseg]; if (subLine >= ll->lines) { DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine); return; // No further drawing } int lineStart = 0; int lineEnd = 0; if (subLine < ll->lines) { lineStart = ll->LineStart(subLine); lineEnd = ll->LineStart(subLine + 1); if (subLine == ll->lines - 1) { lineEnd = ll->numCharsBeforeEOL; } } ColourDesired wrapColour = vsDraw.styles[STYLE_DEFAULT].fore; if (vsDraw.whitespaceForegroundSet) wrapColour = vsDraw.whitespaceForeground; bool drawWrapMarkEnd = false; if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) { if (subLine + 1 < ll->lines) { drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; } } if (ll->wrapIndent != 0) { bool continuedWrapLine = false; if (subLine < ll->lines) { continuedWrapLine = ll->LineStart(subLine) != 0; } if (continuedWrapLine) { // draw continuation rect PRectangle rcPlace = rcSegment; rcPlace.left = ll->positions[startseg] + xStart - subLineStart; rcPlace.right = rcPlace.left + ll->wrapIndent; // default bgnd here.. surface->FillRectangle(rcSegment, overrideBackground ? background : vsDraw.styles[STYLE_DEFAULT].back); // main line style would be below but this would be inconsistent with end markers // also would possibly not be the style at wrap point //int styleMain = ll->styles[lineStart]; //surface->FillRectangle(rcPlace, vsDraw.styles[styleMain].back); if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) { if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT) rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; else rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; DrawWrapMarker(surface, rcPlace, false, wrapColour); } xStart += static_cast(ll->wrapIndent); } } bool selBackDrawn = vsDraw.selbackset && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)); // Does not take margin into account but not significant int xStartVisible = static_cast(subLineStart) - xStart; ll->psel = &sel; BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, xStartVisible, selBackDrawn, pdoc); int next = bfBack.First(); // Background drawing loop while (twoPhaseDraw && (next < lineEnd)) { startseg = next; next = bfBack.Next(); int i = next - 1; int iDoc = i + posLineStart; rcSegment.left = ll->positions[startseg] + xStart - subLineStart; rcSegment.right = ll->positions[i + 1] + xStart - subLineStart; // Only try to draw if really visible - enhances performance by not calling environment to // draw strings that are completely past the right side of the window. if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) { // Clip to line rectangle, since may have a huge position which will not work with some platforms if (rcSegment.left < rcLine.left) rcSegment.left = rcLine.left; if (rcSegment.right > rcLine.right) rcSegment.right = rcLine.right; int styleMain = ll->styles[i]; const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd); ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll); if (ll->chars[i] == '\t') { // Tab display if (drawWhitespaceBackground && (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) textBack = vsDraw.whitespaceBackground; surface->FillRectangle(rcSegment, textBack); } else if (IsControlCharacter(ll->chars[i])) { // Control character display inIndentation = false; surface->FillRectangle(rcSegment, textBack); } else { // Normal text display surface->FillRectangle(rcSegment, textBack); if (vsDraw.viewWhitespace != wsInvisible || (inIndentation && vsDraw.viewIndentationGuides == ivReal)) { for (int cpos = 0; cpos <= i - startseg; cpos++) { if (ll->chars[cpos + startseg] == ' ') { if (drawWhitespaceBackground && (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, rcSegment.top, ll->positions[cpos + startseg + 1] + xStart - subLineStart, rcSegment.bottom); surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground); } } else { inIndentation = false; } } } } } else if (rcSegment.left > rcLine.right) { break; } } if (twoPhaseDraw) { DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, xStart, subLine, subLineStart, overrideBackground, background, drawWrapMarkEnd, wrapColour); } DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true); if (vsDraw.edgeState == EDGE_LINE) { int edgeX = theEdge * vsDraw.spaceWidth; rcSegment.left = edgeX + xStart; if ((ll->wrapIndent != 0) && (lineStart != 0)) rcSegment.left -= ll->wrapIndent; rcSegment.right = rcSegment.left + 1; surface->FillRectangle(rcSegment, vsDraw.edgecolour); } // Draw underline mark as part of background if not transparent int marks = pdoc->GetMark(line); int markBit; for (markBit = 0; (markBit < 32) && marks; markBit++) { if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) && (vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) { PRectangle rcUnderline = rcLine; rcUnderline.top = rcUnderline.bottom - 2; surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back); } marks >>= 1; } inIndentation = subLine == 0; // Do not handle indentation except on first subline. // Foreground drawing loop BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, xStartVisible, ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset), pdoc); next = bfFore.First(); while (next < lineEnd) { startseg = next; next = bfFore.Next(); int i = next - 1; int iDoc = i + posLineStart; rcSegment.left = ll->positions[startseg] + xStart - subLineStart; rcSegment.right = ll->positions[i + 1] + xStart - subLineStart; // Only try to draw if really visible - enhances performance by not calling environment to // draw strings that are completely past the right side of the window. if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) { int styleMain = ll->styles[i]; ColourDesired textFore = vsDraw.styles[styleMain].fore; Font &textFont = vsDraw.styles[styleMain].font; //hotspot foreground if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) { if (vsDraw.hotspotForegroundSet) textFore = vsDraw.hotspotForeground; } const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); if (inSelection && (vsDraw.selforeset)) { textFore = (inSelection == 1) ? vsDraw.selforeground : vsDraw.selAdditionalForeground; } bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd); ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll); if (ll->chars[i] == '\t') { // Tab display if (!twoPhaseDraw) { if (drawWhitespaceBackground && (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) textBack = vsDraw.whitespaceBackground; surface->FillRectangle(rcSegment, textBack); } if ((vsDraw.viewWhitespace != wsInvisible) || (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { if (vsDraw.whitespaceForegroundSet) textFore = vsDraw.whitespaceForeground; surface->PenColour(textFore); } if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { for (int indentCount = (ll->positions[i] + epsilon) / indentWidth; indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth; indentCount++) { if (indentCount > 0) { int xIndent = indentCount * indentWidth; DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, (ll->xHighlightGuide == xIndent)); } } } if (vsDraw.viewWhitespace != wsInvisible) { if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4, rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2); } } } else if (IsControlCharacter(ll->chars[i])) { // Control character display inIndentation = false; if (controlCharSymbol < 32) { // Draw the character const char *ctrlChar = ControlCharacterString(ll->chars[i]); DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); } else { char cc[2] = { static_cast(controlCharSymbol), '\0' }; surface->DrawTextNoClip(rcSegment, ctrlCharsFont, rcSegment.top + vsDraw.maxAscent, cc, 1, textBack, textFore); } } else if ((i == startseg) && (static_cast(ll->chars[i]) >= 0x80) && IsUnicodeMode()) { // A single byte >= 0x80 in UTF-8 is a bad byte and is displayed as its hex value char hexits[4]; sprintf(hexits, "x%2X", ll->chars[i] & 0xff); DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw); } else { // Normal text display if (vsDraw.styles[styleMain].visible) { if (twoPhaseDraw) { surface->DrawTextTransparent(rcSegment, textFont, rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, i - startseg + 1, textFore); } else { surface->DrawTextNoClip(rcSegment, textFont, rcSegment.top + vsDraw.maxAscent, ll->chars + startseg, i - startseg + 1, textFore, textBack); } } if (vsDraw.viewWhitespace != wsInvisible || (inIndentation && vsDraw.viewIndentationGuides != ivNone)) { for (int cpos = 0; cpos <= i - startseg; cpos++) { if (ll->chars[cpos + startseg] == ' ') { if (vsDraw.viewWhitespace != wsInvisible) { if (vsDraw.whitespaceForegroundSet) textFore = vsDraw.whitespaceForeground; if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { XYPOSITION xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2; if (!twoPhaseDraw && drawWhitespaceBackground && (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { textBack = vsDraw.whitespaceBackground; PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart, rcSegment.top, ll->positions[cpos + startseg + 1] + xStart - subLineStart, rcSegment.bottom); surface->FillRectangle(rcSpace, textBack); } PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); rcDot.right = rcDot.left + vs.whitespaceSize; rcDot.bottom = rcDot.top + vs.whitespaceSize; surface->FillRectangle(rcDot, textFore); } } if (inIndentation && vsDraw.viewIndentationGuides == ivReal) { for (int indentCount = (ll->positions[cpos + startseg] + epsilon) / indentWidth; indentCount <= (ll->positions[cpos + startseg + 1] - epsilon) / indentWidth; indentCount++) { if (indentCount > 0) { int xIndent = indentCount * indentWidth; DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, (ll->xHighlightGuide == xIndent)); } } } } else { inIndentation = false; } } } } if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd) { PRectangle rcUL = rcSegment; rcUL.top = rcUL.top + vsDraw.maxAscent + 1; rcUL.bottom = rcUL.top + 1; if (vsDraw.hotspotForegroundSet) surface->FillRectangle(rcUL, vsDraw.hotspotForeground); else surface->FillRectangle(rcUL, textFore); } else if (vsDraw.styles[styleMain].underline) { PRectangle rcUL = rcSegment; rcUL.top = rcUL.top + vsDraw.maxAscent + 1; rcUL.bottom = rcUL.top + 1; surface->FillRectangle(rcUL, textFore); } } else if (rcSegment.left > rcLine.right) { break; } } if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth) && (subLine == 0)) { int indentSpace = pdoc->GetLineIndentation(line); int xStartText = ll->positions[pdoc->GetLineIndentPosition(line) - posLineStart]; // Find the most recent line with some text int lineLastWithText = line; while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) { lineLastWithText--; } if (lineLastWithText < line) { xStartText = 100000; // Don't limit to visible indentation on empty line // This line is empty, so use indentation of last line with text int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText); int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG; if (isFoldHeader) { // Level is one more level than parent indentLastWithText += pdoc->IndentSize(); } if (vsDraw.viewIndentationGuides == ivLookForward) { // In viLookForward mode, previous line only used if it is a fold header if (isFoldHeader) { indentSpace = Platform::Maximum(indentSpace, indentLastWithText); } } else { // viLookBoth indentSpace = Platform::Maximum(indentSpace, indentLastWithText); } } int lineNextWithText = line; while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) { lineNextWithText++; } if (lineNextWithText > line) { xStartText = 100000; // Don't limit to visible indentation on empty line // This line is empty, so use indentation of first next line with text indentSpace = Platform::Maximum(indentSpace, pdoc->GetLineIndentation(lineNextWithText)); } for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) { int xIndent = indentPos * vsDraw.spaceWidth; if (xIndent < xStartText) { DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, (ll->xHighlightGuide == xIndent)); } } } DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false); // End of the drawing of the current line if (!twoPhaseDraw) { DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd, xStart, subLine, subLineStart, overrideBackground, background, drawWrapMarkEnd, wrapColour); } if (!hideSelection && ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA))) { // For each selection draw int virtualSpaces = 0; if (subLine == (ll->lines - 1)) { virtualSpaces = sel.VirtualSpaceFor(pdoc->LineEnd(line)); } SelectionPosition posStart(posLineStart + lineStart); SelectionPosition posEnd(posLineStart + lineEnd, virtualSpaces); SelectionSegment virtualSpaceRange(posStart, posEnd); for (size_t r=0; rEndLineStyle()].spaceWidth; rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth; rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth; if ((ll->wrapIndent != 0) && (lineStart != 0)) { if ((portion.start.Position() - posLineStart) == lineStart && sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) rcSegment.left -= static_cast(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here } rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; if (rcSegment.right > rcLine.left) SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == sel.Main()), alpha); } } } } // Draw any translucent whole line states rcSegment = rcLine; if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) { SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground, vsDraw.caretLineAlpha); } marks = pdoc->GetMark(line); for (markBit = 0; (markBit < 32) && marks; markBit++) { if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) { SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); } else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) { PRectangle rcUnderline = rcSegment; rcUnderline.top = rcUnderline.bottom - 2; SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); } marks >>= 1; } if (vsDraw.maskInLine) { int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine; if (marksMasked) { for (markBit = 0; (markBit < 32) && marksMasked; markBit++) { if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) { SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back, vsDraw.markers[markBit].alpha); } marksMasked >>= 1; } } } } void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) { int lineStart = ll->LineStart(subLine); int posBefore = posCaret; int posAfter = MovePositionOutsideChar(posCaret + 1, 1); int numCharsToDraw = posAfter - posCaret; // Work out where the starting and ending offsets are. We need to // see if the previous character shares horizontal space, such as a // glyph / combining character. If so we'll need to draw that too. int offsetFirstChar = offset; int offsetLastChar = offset + (posAfter - posCaret); while ((offsetLastChar - numCharsToDraw) >= lineStart) { if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { // The char does not share horizontal space break; } // Char shares horizontal space, update the numChars to draw // Update posBefore to point to the prev char posBefore = MovePositionOutsideChar(posBefore - 1, -1); numCharsToDraw = posAfter - posBefore; offsetFirstChar = offset - (posCaret - posBefore); } // See if the next character shares horizontal space, if so we'll // need to draw that too. numCharsToDraw = offsetLastChar - offsetFirstChar; while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { // Update posAfter to point to the 2nd next char, this is where // the next character ends, and 2nd next begins. We'll need // to compare these two posBefore = posAfter; posAfter = MovePositionOutsideChar(posAfter + 1, 1); offsetLastChar = offset + (posAfter - posCaret); if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { // The char does not share horizontal space break; } // Char shares horizontal space, update the numChars to draw numCharsToDraw = offsetLastChar - offsetFirstChar; } // We now know what to draw, update the caret drawing rectangle rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart; // Adjust caret position to take into account any word wrapping symbols. if ((ll->wrapIndent != 0) && (lineStart != 0)) { XYPOSITION wordWrapCharWidth = ll->wrapIndent; rcCaret.left += wordWrapCharWidth; rcCaret.right += wordWrapCharWidth; } // This character is where the caret block is, we override the colours // (inversed) for drawing the caret here. int styleMain = ll->styles[offsetFirstChar]; surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font, rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, numCharsToDraw, vsDraw.styles[styleMain].back, caretColour); } void Editor::RefreshPixMaps(Surface *surfaceWindow) { if (!pixmapSelPattern->Initialised()) { const int patternSize = 8; pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID()); // This complex procedure is to reproduce the checkerboard dithered pattern used by windows // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half // way between the chrome colour and the chrome highlight colour making a nice transition // between the window chrome and the content area. And it works in low colour depths. PRectangle rcPattern(0, 0, patternSize, patternSize); // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. ColourDesired colourFMFill = vs.selbar; ColourDesired colourFMStripes = vs.selbarlight; if (!(vs.selbarlight == ColourDesired(0xff, 0xff, 0xff))) { // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. // (Typically, the highlight colour is white.) colourFMFill = vs.selbarlight; } if (vs.foldmarginColourSet) { // override default fold margin colour colourFMFill = vs.foldmarginColour; } if (vs.foldmarginHighlightColourSet) { // override default fold margin highlight colour colourFMStripes = vs.foldmarginHighlightColour; } pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); for (int y = 0; y < patternSize; y++) { for (int x = y % 2; x < patternSize; x+=2) { PRectangle rcPixel(x, y, x+1, y+1); pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); } } } if (!pixmapIndentGuide->Initialised()) { // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); PRectangle rcIG(0, 0, 1, vs.lineHeight); pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back); pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore); pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back); pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore); for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) { PRectangle rcPixel(0, stripe, 1, stripe+1); pixmapIndentGuide->FillRectangle(rcPixel, vs.styles[STYLE_INDENTGUIDE].fore); pixmapIndentGuideHighlight->FillRectangle(rcPixel, vs.styles[STYLE_BRACELIGHT].fore); } } if (bufferedDraw) { if (!pixmapLine->Initialised()) { PRectangle rcClient = GetClientRectangle(); pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight, surfaceWindow, wMain.GetID()); pixmapSelMargin->InitPixMap(vs.fixedColumnWidth, rcClient.Height(), surfaceWindow, wMain.GetID()); } } } void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { // When drag is active it is the only caret drawn bool drawDrag = posDrag.IsValid(); if (hideSelection && !drawDrag) return; const int posLineStart = pdoc->LineStart(lineDoc); // For each selection draw for (size_t r=0; (rEndLineStyle()].spaceWidth; const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth; if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) { XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; if (ll->wrapIndent != 0) { int lineStart = ll->LineStart(subLine); if (lineStart != 0) // Wrapped xposCaret += ll->wrapIndent; } bool caretBlinkState = (caret.active && caret.on) || (!additionalCaretsBlink && !mainCaret); bool caretVisibleState = additionalCaretsVisible || mainCaret; if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) && ((posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) { bool caretAtEOF = false; bool caretAtEOL = false; bool drawBlockCaret = false; XYPOSITION widthOverstrikeCaret; int caretWidthOffset = 0; PRectangle rcCaret = rcLine; if (posCaret.Position() == pdoc->Length()) { // At end of document caretAtEOF = true; widthOverstrikeCaret = vsDraw.aveCharWidth; } else if ((posCaret.Position() - posLineStart) >= ll->numCharsInLine) { // At end of line caretAtEOL = true; widthOverstrikeCaret = vsDraw.aveCharWidth; } else { widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset]; } if (widthOverstrikeCaret < 3) // Make sure its visible widthOverstrikeCaret = 3; if (xposCaret > 0) caretWidthOffset = 1; // Move back so overlaps both character cells. xposCaret += xStart; if (posDrag.IsValid()) { /* Dragging text, use a line caret */ rcCaret.left = xposCaret - caretWidthOffset; rcCaret.right = rcCaret.left + vsDraw.caretWidth; } else if (inOverstrike) { /* Overstrike (insert mode), use a modified bar caret */ rcCaret.top = rcCaret.bottom - 2; rcCaret.left = xposCaret + 1; rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; } else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) { /* Block caret */ rcCaret.left = xposCaret; if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { drawBlockCaret = true; rcCaret.right = xposCaret + widthOverstrikeCaret; } else { rcCaret.right = xposCaret + vsDraw.aveCharWidth; } } else { /* Line caret */ rcCaret.left = xposCaret - caretWidthOffset; rcCaret.right = rcCaret.left + vsDraw.caretWidth; } ColourDesired caretColour = mainCaret ? vsDraw.caretcolour : vsDraw.additionalCaretColour; if (drawBlockCaret) { DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); } else { surface->FillRectangle(rcCaret, caretColour); } } } if (drawDrag) break; } } void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n", // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); AllocateGraphics(); RefreshStyleData(); RefreshPixMaps(surfaceWindow); StyleToPositionInView(PositionAfterArea(rcArea)); PRectangle rcClient = GetClientRectangle(); //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n", // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); int screenLinePaintFirst = rcArea.top / vs.lineHeight; int xStart = vs.fixedColumnWidth - xOffset; int ypos = 0; if (!bufferedDraw) ypos += screenLinePaintFirst * vs.lineHeight; int yposScreen = screenLinePaintFirst * vs.lineHeight; bool paintAbandonedByStyling = paintState == paintAbandoned; if (needUpdateUI) { NotifyUpdateUI(); needUpdateUI = 0; RefreshStyleData(); RefreshPixMaps(surfaceWindow); } // Call priority lines wrap on a window of lines which are likely // to rendered with the following paint (that is wrap the visible // lines first). int startLineToWrap = cs.DocFromDisplay(topLine) - 5; if (startLineToWrap < 0) startLineToWrap = 0; if (WrapLines(false, startLineToWrap)) { // The wrapping process has changed the height of some lines so // abandon this paint for a complete repaint. if (AbandonPaint()) { return; } RefreshPixMaps(surfaceWindow); // In case pixmaps invalidated by scrollbar change } PLATFORM_ASSERT(pixmapSelPattern->Initialised()); if (!bufferedDraw) surfaceWindow->SetClip(rcArea); if (paintState != paintAbandoned) { PaintSelMargin(surfaceWindow, rcArea); PRectangle rcRightMargin = rcClient; rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth; if (rcArea.Intersects(rcRightMargin)) { surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back); } } if (paintState == paintAbandoned) { // Either styling or NotifyUpdateUI noticed that painting is needed // outside the current painting rectangle //Platform::DebugPrintf("Abandoning paint\n"); if (wrapState != eWrapNone) { if (paintAbandonedByStyling) { // Styling has spilled over a line end, such as occurs by starting a multiline // comment. The width of subsequent text may have changed, so rewrap. NeedWrapping(cs.DocFromDisplay(topLine)); } } return; } //Platform::DebugPrintf("start display %d, offset = %d\n", pdoc->Length(), xOffset); // Do the painting if (rcArea.right > vs.fixedColumnWidth) { Surface *surface = surfaceWindow; if (bufferedDraw) { surface = pixmapLine; PLATFORM_ASSERT(pixmapLine->Initialised()); } surface->SetUnicodeMode(IsUnicodeMode()); surface->SetDBCSMode(CodePage()); int visibleLine = topLine + screenLinePaintFirst; SelectionPosition posCaret = sel.RangeMain().caret; if (posDrag.IsValid()) posCaret = posDrag; int lineCaret = pdoc->LineFromPosition(posCaret.Position()); PRectangle rcTextArea = rcClient; rcTextArea.left = vs.fixedColumnWidth; rcTextArea.right -= vs.rightMarginWidth; // Remove selection margin from drawing area so text will not be drawn // on it in unbuffered mode. if (!bufferedDraw) { surfaceWindow->SetClip(rcTextArea); } // Loop on visible lines //double durLayout = 0.0; //double durPaint = 0.0; //double durCopy = 0.0; //ElapsedTime etWhole; int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times AutoLineLayout ll(llc, 0); while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) { int lineDoc = cs.DocFromDisplay(visibleLine); // Only visible lines should be handled by the code within the loop PLATFORM_ASSERT(cs.GetVisible(lineDoc)); int lineStartSet = cs.DisplayFromDoc(lineDoc); int subLine = visibleLine - lineStartSet; // Copy this line and its styles from the document into local arrays // and determine the x position at which each character starts. //ElapsedTime et; if (lineDoc != lineDocPrevious) { ll.Set(0); ll.Set(RetrieveLineLayout(lineDoc)); LayoutLine(lineDoc, surface, vs, ll, wrapWidth); lineDocPrevious = lineDoc; } //durLayout += et.Duration(true); if (ll) { ll->containsCaret = lineDoc == lineCaret; if (hideSelection) { ll->containsCaret = false; } GetHotSpotRange(ll->hsStart, ll->hsEnd); PRectangle rcLine = rcTextArea; rcLine.top = ypos; rcLine.bottom = ypos + vs.lineHeight; bool bracesIgnoreStyle = false; if ((vs.braceHighlightIndicatorSet && (bracesMatchStyle == STYLE_BRACELIGHT)) || (vs.braceBadLightIndicatorSet && (bracesMatchStyle == STYLE_BRACEBAD))) { bracesIgnoreStyle = true; } Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1)); // Highlight the current braces if any ll->SetBracesHighlight(rangeLine, braces, static_cast(bracesMatchStyle), highlightGuideColumn * vs.spaceWidth, bracesIgnoreStyle); // Draw the line DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine); //durPaint += et.Duration(true); // Restore the previous styles for the brace highlights in case layout is in cache. ll->RestoreBracesHighlight(rangeLine, braces, bracesIgnoreStyle); bool expanded = cs.GetExpanded(lineDoc); const int level = pdoc->GetLevel(lineDoc); const int levelNext = pdoc->GetLevel(lineDoc + 1); if ((level & SC_FOLDLEVELHEADERFLAG) && ((level & SC_FOLDLEVELNUMBERMASK) < (levelNext & SC_FOLDLEVELNUMBERMASK))) { // Paint the line above the fold if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED)) || (!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) { PRectangle rcFoldLine = rcLine; rcFoldLine.bottom = rcFoldLine.top + 1; surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore); } // Paint the line below the fold if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED)) || (!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) { PRectangle rcFoldLine = rcLine; rcFoldLine.top = rcFoldLine.bottom - 1; surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore); } } DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine); if (bufferedDraw) { Point from(vs.fixedColumnWidth, 0); PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen, rcClient.right - vs.rightMarginWidth, yposScreen + vs.lineHeight); surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); } lineWidthMaxSeen = Platform::Maximum( lineWidthMaxSeen, ll->positions[ll->numCharsInLine]); //durCopy += et.Duration(true); } if (!bufferedDraw) { ypos += vs.lineHeight; } yposScreen += vs.lineHeight; visibleLine++; //gdk_flush(); } ll.Set(0); //if (durPaint < 0.00000001) // durPaint = 0.00000001; // Right column limit indicator PRectangle rcBeyondEOF = rcClient; rcBeyondEOF.left = vs.fixedColumnWidth; rcBeyondEOF.right = rcBeyondEOF.right - vs.rightMarginWidth; rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight; if (rcBeyondEOF.top < rcBeyondEOF.bottom) { surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back); if (vs.edgeState == EDGE_LINE) { int edgeX = theEdge * vs.spaceWidth; rcBeyondEOF.left = edgeX + xStart; rcBeyondEOF.right = rcBeyondEOF.left + 1; surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour); } } //Platform::DebugPrintf( //"Layout:%9.6g Paint:%9.6g Ratio:%9.6g Copy:%9.6g Total:%9.6g\n", //durLayout, durPaint, durLayout / durPaint, durCopy, etWhole.Duration()); NotifyPainted(); } } // Space (3 space characters) between line numbers and text when printing. #define lineNumberPrintSpace " " ColourDesired InvertedLight(ColourDesired orig) { unsigned int r = orig.GetRed(); unsigned int g = orig.GetGreen(); unsigned int b = orig.GetBlue(); unsigned int l = (r + g + b) / 3; // There is a better calculation for this that matches human eye unsigned int il = 0xff - l; if (l == 0) return ColourDesired(0xff, 0xff, 0xff); r = r * il / l; g = g * il / l; b = b * il / l; return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff)); } // This is mostly copied from the Paint method but with some things omitted // such as the margin markers, line numbers, selection and caret // Should be merged back into a combined Draw method. long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { if (!pfr) return 0; AutoSurface surface(pfr->hdc, this, SC_TECHNOLOGY_DEFAULT); if (!surface) return 0; AutoSurface surfaceMeasure(pfr->hdcTarget, this, SC_TECHNOLOGY_DEFAULT); if (!surfaceMeasure) { return 0; } // Can't use measurements cached for screen posCache.Clear(); ViewStyle vsPrint(vs); vsPrint.technology = SC_TECHNOLOGY_DEFAULT; // Modify the view style for printing as do not normally want any of the transient features to be printed // Printing supports only the line number margin. int lineNumberIndex = -1; for (int margin = 0; margin < ViewStyle::margins; margin++) { if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) { lineNumberIndex = margin; } else { vsPrint.ms[margin].width = 0; } } vsPrint.fixedColumnWidth = 0; vsPrint.zoomLevel = printMagnification; // Don't show indentation guides // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT vsPrint.viewIndentationGuides = ivNone; // Don't show the selection when printing vsPrint.selbackset = false; vsPrint.selforeset = false; vsPrint.selAlpha = SC_ALPHA_NOALPHA; vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA; vsPrint.whitespaceBackgroundSet = false; vsPrint.whitespaceForegroundSet = false; vsPrint.showCaretLineBackground = false; // Don't highlight matching braces using indicators vsPrint.braceHighlightIndicatorSet = false; vsPrint.braceBadLightIndicatorSet = false; // Set colours for printing according to users settings for (size_t sty = 0; sty < vsPrint.stylesSize; sty++) { if (printColourMode == SC_PRINT_INVERTLIGHT) { vsPrint.styles[sty].fore = InvertedLight(vsPrint.styles[sty].fore); vsPrint.styles[sty].back = InvertedLight(vsPrint.styles[sty].back); } else if (printColourMode == SC_PRINT_BLACKONWHITE) { vsPrint.styles[sty].fore = ColourDesired(0, 0, 0); vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); } else if (printColourMode == SC_PRINT_COLOURONWHITE) { vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); } else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) { if (sty <= STYLE_DEFAULT) { vsPrint.styles[sty].back = ColourDesired(0xff, 0xff, 0xff); } } } // White background for the line numbers vsPrint.styles[STYLE_LINENUMBER].back = ColourDesired(0xff, 0xff, 0xff); // Printing uses different margins, so reset screen margins vsPrint.leftMarginWidth = 0; vsPrint.rightMarginWidth = 0; vsPrint.Refresh(*surfaceMeasure); // Determining width must hapen after fonts have been realised in Refresh int lineNumberWidth = 0; if (lineNumberIndex >= 0) { lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font, "99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace)); vsPrint.ms[lineNumberIndex].width = lineNumberWidth; vsPrint.Refresh(*surfaceMeasure); // Recalculate fixedColumnWidth } int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin); int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1; if (linePrintLast < linePrintStart) linePrintLast = linePrintStart; int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax); if (linePrintLast > linePrintMax) linePrintLast = linePrintMax; //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", // linePrintStart, linePrintLast, linePrintMax, pfr->rc.top, pfr->rc.bottom, vsPrint.lineHeight, // surfaceMeasure->Height(vsPrint.styles[STYLE_LINENUMBER].font)); int endPosPrint = pdoc->Length(); if (linePrintLast < pdoc->LinesTotal()) endPosPrint = pdoc->LineStart(linePrintLast + 1); // Ensure we are styled to where we are formatting. pdoc->EnsureStyledTo(endPosPrint); int xStart = vsPrint.fixedColumnWidth + pfr->rc.left; int ypos = pfr->rc.top; int lineDoc = linePrintStart; int nPrintPos = pfr->chrg.cpMin; int visibleLine = 0; int widthPrint = pfr->rc.right - pfr->rc.left - vsPrint.fixedColumnWidth; if (printWrapState == eWrapNone) widthPrint = LineLayout::wrapWidthInfinite; while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) { // When printing, the hdc and hdcTarget may be the same, so // changing the state of surfaceMeasure may change the underlying // state of surface. Therefore, any cached state is discarded before // using each surface. surfaceMeasure->FlushCachedState(); // Copy this line and its styles from the document into local arrays // and determine the x position at which each character starts. LineLayout ll(8000); LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint); ll.containsCaret = false; PRectangle rcLine; rcLine.left = pfr->rc.left; rcLine.top = ypos; rcLine.right = pfr->rc.right - 1; rcLine.bottom = ypos + vsPrint.lineHeight; // When document line is wrapped over multiple display lines, find where // to start printing from to ensure a particular position is on the first // line of the page. if (visibleLine == 0) { int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc); for (int iwl = 0; iwl < ll.lines - 1; iwl++) { if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) { visibleLine = -iwl; } } if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) { visibleLine = -(ll.lines - 1); } } if (draw && lineNumberWidth && (ypos + vsPrint.lineHeight <= pfr->rc.bottom) && (visibleLine >= 0)) { char number[100]; sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1); PRectangle rcNumber = rcLine; rcNumber.right = rcNumber.left + lineNumberWidth; // Right justify rcNumber.left = rcNumber.right - surfaceMeasure->WidthText( vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number)); surface->FlushCachedState(); surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font, ypos + vsPrint.maxAscent, number, istrlen(number), vsPrint.styles[STYLE_LINENUMBER].fore, vsPrint.styles[STYLE_LINENUMBER].back); } // Draw the line surface->FlushCachedState(); for (int iwl = 0; iwl < ll.lines; iwl++) { if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) { if (visibleLine >= 0) { if (draw) { rcLine.top = ypos; rcLine.bottom = ypos + vsPrint.lineHeight; DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl); } ypos += vsPrint.lineHeight; } visibleLine++; if (iwl == ll.lines - 1) nPrintPos = pdoc->LineStart(lineDoc + 1); else nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl); } } ++lineDoc; } // Clear cache so measurements are not used for screen posCache.Clear(); return nPrintPos; } int Editor::TextWidth(int style, const char *text) { RefreshStyleData(); AutoSurface surface(this); if (surface) { return surface->WidthText(vs.styles[style].font, text, istrlen(text)); } else { return 1; } } // Empty method is overridden on GTK+ to show / hide scrollbars void Editor::ReconfigureScrollBars() {} void Editor::SetScrollBars() { RefreshStyleData(); int nMax = MaxScrollPos(); int nPage = LinesOnScreen(); bool modified = ModifyScrollBars(nMax + nPage - 1, nPage); if (modified) { DwellEnd(true); } // TODO: ensure always showing as many lines as possible // May not be, if, for example, window made larger if (topLine > MaxScrollPos()) { SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } if (modified) { if (!AbandonPaint()) Redraw(); } //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage); } void Editor::ChangeSize() { DropGraphics(false); SetScrollBars(); if (wrapState != eWrapNone) { PRectangle rcTextArea = GetClientRectangle(); rcTextArea.left = vs.fixedColumnWidth; rcTextArea.right -= vs.rightMarginWidth; if (wrapWidth != rcTextArea.Width()) { NeedWrapping(); Redraw(); } } } int Editor::InsertSpace(int position, unsigned int spaces) { if (spaces > 0) { std::string spaceText(spaces, ' '); pdoc->InsertString(position, spaceText.c_str(), spaces); position += spaces; } return position; } void Editor::AddChar(char ch) { char s[2]; s[0] = ch; s[1] = '\0'; AddCharUTF(s, 1); } void Editor::FilterSelections() { if (!additionalSelectionTyping && (sel.Count() > 1)) { SelectionRange rangeOnly = sel.RangeMain(); InvalidateSelection(rangeOnly, true); sel.SetSelection(rangeOnly); } } static bool cmpSelPtrs(const SelectionRange *a, const SelectionRange *b) { return *a < *b; } // AddCharUTF inserts an array of bytes which may or may not be in UTF-8. void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { FilterSelections(); { UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike); std::vector selPtrs; for (size_t r = 0; r < sel.Count(); r++) { selPtrs.push_back(&sel.Range(r)); } std::sort(selPtrs.begin(), selPtrs.end(), cmpSelPtrs); for (std::vector::reverse_iterator rit = selPtrs.rbegin(); rit != selPtrs.rend(); ++rit) { SelectionRange *currentSel = *rit; if (!RangeContainsProtected(currentSel->Start().Position(), currentSel->End().Position())) { int positionInsert = currentSel->Start().Position(); if (!currentSel->Empty()) { if (currentSel->Length()) { pdoc->DeleteChars(positionInsert, currentSel->Length()); currentSel->ClearVirtualSpace(); } else { // Range is all virtual so collapse to start of virtual space currentSel->MinimizeVirtualSpace(); } } else if (inOverstrike) { if (positionInsert < pdoc->Length()) { if (!IsEOLChar(pdoc->CharAt(positionInsert))) { pdoc->DelChar(positionInsert); currentSel->ClearVirtualSpace(); } } } positionInsert = InsertSpace(positionInsert, currentSel->caret.VirtualSpace()); if (pdoc->InsertString(positionInsert, s, len)) { currentSel->caret.SetPosition(positionInsert + len); currentSel->anchor.SetPosition(positionInsert + len); } currentSel->ClearVirtualSpace(); // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information if (wrapState != eWrapNone) { AutoSurface surface(this); if (surface) { if (WrapOneLine(surface, pdoc->LineFromPosition(positionInsert))) { SetScrollBars(); SetVerticalScrollPos(); Redraw(); } } } } } } if (wrapState != eWrapNone) { SetScrollBars(); } ThinRectangularRange(); // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information EnsureCaretVisible(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); if ((caretSticky == SC_CARETSTICKY_OFF) || ((caretSticky == SC_CARETSTICKY_WHITESPACE) && !IsAllSpacesOrTabs(s, len))) { SetLastXChosen(); } if (treatAsDBCS) { NotifyChar((static_cast(s[0]) << 8) | static_cast(s[1])); } else { int byte = static_cast(s[0]); if ((byte < 0xC0) || (1 == len)) { // Handles UTF-8 characters between 0x01 and 0x7F and single byte // characters when not in UTF-8 mode. // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid // characters representing themselves. } else { // Unroll 1 to 3 byte UTF-8 sequences. See reference data at: // http://www.cl.cam.ac.uk/~mgk25/unicode.html // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt if (byte < 0xE0) { int byte2 = static_cast(s[1]); if ((byte2 & 0xC0) == 0x80) { // Two-byte-character lead-byte followed by a trail-byte. byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F)); } // A two-byte-character lead-byte not followed by trail-byte // represents itself. } else if (byte < 0xF0) { int byte2 = static_cast(s[1]); int byte3 = static_cast(s[2]); if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) { // Three-byte-character lead byte followed by two trail bytes. byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F)); } // A three-byte-character lead-byte not followed by two trail-bytes // represents itself. } } NotifyChar(byte); } if (recordingMacro) { NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast(s)); } } void Editor::InsertPaste(SelectionPosition selStart, const char *text, int len) { if (multiPasteMode == SC_MULTIPASTE_ONCE) { selStart = SelectionPosition(InsertSpace(selStart.Position(), selStart.VirtualSpace())); if (pdoc->InsertString(selStart.Position(), text, len)) { SetEmptySelection(selStart.Position() + len); } } else { // SC_MULTIPASTE_EACH for (size_t r=0; rDeleteChars(positionInsert, sel.Range(r).Length()); sel.Range(r).ClearVirtualSpace(); } else { // Range is all virtual so collapse to start of virtual space sel.Range(r).MinimizeVirtualSpace(); } } positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace()); if (pdoc->InsertString(positionInsert, text, len)) { sel.Range(r).caret.SetPosition(positionInsert + len); sel.Range(r).anchor.SetPosition(positionInsert + len); } sel.Range(r).ClearVirtualSpace(); } } } } void Editor::ClearSelection(bool retainMultipleSelections) { if (!sel.IsRectangular() && !retainMultipleSelections) FilterSelections(); UndoGroup ug(pdoc); for (size_t r=0; rDeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length()); sel.Range(r) = sel.Range(r).Start(); } } } ThinRectangularRange(); sel.RemoveDuplicates(); ClaimSelection(); } void Editor::ClearAll() { { UndoGroup ug(pdoc); if (0 != pdoc->Length()) { pdoc->DeleteChars(0, pdoc->Length()); } if (!pdoc->IsReadOnly()) { cs.Clear(); pdoc->AnnotationClearAll(); pdoc->MarginClearAll(); } } sel.Clear(); SetTopLine(0); SetVerticalScrollPos(); InvalidateStyleRedraw(); } void Editor::ClearDocumentStyle() { Decoration *deco = pdoc->decorations.root; while (deco) { // Save next in case deco deleted Decoration *decoNext = deco->next; if (deco->indicator < INDIC_CONTAINER) { pdoc->decorations.SetCurrentIndicator(deco->indicator); pdoc->DecorationFillRange(0, 0, pdoc->Length()); } deco = decoNext; } pdoc->StartStyling(0, '\377'); pdoc->SetStyleFor(pdoc->Length(), 0); cs.ShowAll(); pdoc->ClearLevels(); } void Editor::CopyAllowLine() { SelectionText selectedText; CopySelectionRange(&selectedText, true); CopyToClipboard(selectedText); } void Editor::Cut() { pdoc->CheckReadOnly(); if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) { Copy(); ClearSelection(); } } void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) { if (pdoc->IsReadOnly() || SelectionContainsProtected()) { return; } sel.Clear(); sel.RangeMain() = SelectionRange(pos); int line = pdoc->LineFromPosition(sel.MainCaret()); UndoGroup ug(pdoc); sel.RangeMain().caret = SelectionPosition( InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); int xInsert = XFromPosition(sel.RangeMain().caret); bool prevCr = false; while ((len > 0) && IsEOLChar(ptr[len-1])) len--; for (int i = 0; i < len; i++) { if (IsEOLChar(ptr[i])) { if ((ptr[i] == '\r') || (!prevCr)) line++; if (line >= pdoc->LinesTotal()) { if (pdoc->eolMode != SC_EOL_LF) pdoc->InsertChar(pdoc->Length(), '\r'); if (pdoc->eolMode != SC_EOL_CR) pdoc->InsertChar(pdoc->Length(), '\n'); } // Pad the end of lines with spaces if required sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert)); if ((XFromPosition(sel.MainCaret()) < xInsert) && (i + 1 < len)) { while (XFromPosition(sel.MainCaret()) < xInsert) { pdoc->InsertChar(sel.MainCaret(), ' '); sel.RangeMain().caret.Add(1); } } prevCr = ptr[i] == '\r'; } else { pdoc->InsertString(sel.MainCaret(), ptr + i, 1); sel.RangeMain().caret.Add(1); prevCr = false; } } SetEmptySelection(pos); } bool Editor::CanPaste() { return !pdoc->IsReadOnly() && !SelectionContainsProtected(); } void Editor::Clear() { // If multiple selections, don't delete EOLS if (sel.Empty()) { bool singleVirtual = false; if ((sel.Count() == 1) && !RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1) && sel.RangeMain().Start().VirtualSpace()) { singleVirtual = true; } UndoGroup ug(pdoc, (sel.Count() > 1) || singleVirtual); for (size_t r=0; rCharAt(sel.Range(r).caret.Position()))) { pdoc->DelChar(sel.Range(r).caret.Position()); sel.Range(r).ClearVirtualSpace(); } // else multiple selection so don't eat line ends } else { sel.Range(r).ClearVirtualSpace(); } } } else { ClearSelection(); } sel.RemoveDuplicates(); } void Editor::SelectAll() { sel.Clear(); SetSelection(0, pdoc->Length()); Redraw(); } void Editor::Undo() { if (pdoc->CanUndo()) { InvalidateCaret(); int newPos = pdoc->Undo(); if (newPos >= 0) SetEmptySelection(newPos); EnsureCaretVisible(); } } void Editor::Redo() { if (pdoc->CanRedo()) { int newPos = pdoc->Redo(); if (newPos >= 0) SetEmptySelection(newPos); EnsureCaretVisible(); } } void Editor::DelChar() { if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) { pdoc->DelChar(sel.MainCaret()); } // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); } void Editor::DelCharBack(bool allowLineStartDeletion) { if (!sel.IsRectangular()) FilterSelections(); if (sel.IsRectangular()) allowLineStartDeletion = false; UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty()); if (sel.Empty()) { for (size_t r=0; rLineFromPosition(sel.Range(r).caret.Position()); if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) { if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) && pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) { UndoGroup ugInner(pdoc, !ug.Needed()); int indentation = pdoc->GetLineIndentation(lineCurrentPos); int indentationStep = pdoc->IndentSize(); if (indentation % indentationStep == 0) { pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); } else { pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep)); } // SetEmptySelection sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos), pdoc->GetLineIndentPosition(lineCurrentPos)); } else { pdoc->DelCharBack(sel.Range(r).caret.Position()); } } } } else { sel.Range(r).ClearVirtualSpace(); } } } else { ClearSelection(); } sel.RemoveDuplicates(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); } void Editor::NotifyFocus(bool) {} void Editor::SetCtrlID(int identifier) { ctrlID = identifier; } void Editor::NotifyStyleToNeeded(int endStyleNeeded) { SCNotification scn = {0}; scn.nmhdr.code = SCN_STYLENEEDED; scn.position = endStyleNeeded; NotifyParent(scn); } void Editor::NotifyStyleNeeded(Document *, void *, int endStyleNeeded) { NotifyStyleToNeeded(endStyleNeeded); } void Editor::NotifyLexerChanged(Document *, void *) { } void Editor::NotifyErrorOccurred(Document *, void *, int status) { errorStatus = status; } void Editor::NotifyChar(int ch) { SCNotification scn = {0}; scn.nmhdr.code = SCN_CHARADDED; scn.ch = ch; NotifyParent(scn); } void Editor::NotifySavePoint(bool isSavePoint) { SCNotification scn = {0}; if (isSavePoint) { scn.nmhdr.code = SCN_SAVEPOINTREACHED; } else { scn.nmhdr.code = SCN_SAVEPOINTLEFT; } NotifyParent(scn); } void Editor::NotifyModifyAttempt() { SCNotification scn = {0}; scn.nmhdr.code = SCN_MODIFYATTEMPTRO; NotifyParent(scn); } void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) { SCNotification scn = {0}; scn.nmhdr.code = SCN_DOUBLECLICK; scn.line = LineFromLocation(pt); scn.position = PositionFromLocation(pt, true); scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); NotifyParent(scn); } void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) { SCNotification scn = {0}; scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK; scn.position = position; scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); NotifyParent(scn); } void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) { SCNotification scn = {0}; scn.nmhdr.code = SCN_HOTSPOTCLICK; scn.position = position; scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); NotifyParent(scn); } void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt) { SCNotification scn = {0}; scn.nmhdr.code = SCN_HOTSPOTRELEASECLICK; scn.position = position; scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); NotifyParent(scn); } void Editor::NotifyUpdateUI() { SCNotification scn = {0}; scn.nmhdr.code = SCN_UPDATEUI; scn.updated = needUpdateUI; NotifyParent(scn); } void Editor::NotifyPainted() { SCNotification scn = {0}; scn.nmhdr.code = SCN_PAINTED; NotifyParent(scn); } void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) { int mask = pdoc->decorations.AllOnFor(position); if ((click && mask) || pdoc->decorations.clickNotified) { SCNotification scn = {0}; pdoc->decorations.clickNotified = click; scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE; scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); scn.position = position; NotifyParent(scn); } } bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) { int marginClicked = -1; int x = 0; for (int margin = 0; margin < ViewStyle::margins; margin++) { if ((pt.x > x) && (pt.x < x + vs.ms[margin].width)) marginClicked = margin; x += vs.ms[margin].width; } if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) { SCNotification scn = {0}; scn.nmhdr.code = SCN_MARGINCLICK; scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); scn.position = pdoc->LineStart(LineFromLocation(pt)); scn.margin = marginClicked; NotifyParent(scn); return true; } else { return false; } } void Editor::NotifyNeedShown(int pos, int len) { SCNotification scn = {0}; scn.nmhdr.code = SCN_NEEDSHOWN; scn.position = pos; scn.length = len; NotifyParent(scn); } void Editor::NotifyDwelling(Point pt, bool state) { SCNotification scn = {0}; scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND; scn.position = PositionFromLocation(pt, true); scn.x = pt.x; scn.y = pt.y; NotifyParent(scn); } void Editor::NotifyZoom() { SCNotification scn = {0}; scn.nmhdr.code = SCN_ZOOM; NotifyParent(scn); } // Notifications from document void Editor::NotifyModifyAttempt(Document *, void *) { //Platform::DebugPrintf("** Modify Attempt\n"); NotifyModifyAttempt(); } void Editor::NotifySavePoint(Document *, void *, bool atSavePoint) { //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off"); NotifySavePoint(atSavePoint); } void Editor::CheckModificationForWrap(DocModification mh) { if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { llc.Invalidate(LineLayout::llCheckTextAndStyle); int lineDoc = pdoc->LineFromPosition(mh.position); int lines = Platform::Maximum(0, mh.linesAdded); if (wrapState != eWrapNone) { NeedWrapping(lineDoc, lineDoc + lines + 1); } RefreshStyleData(); // Fix up annotation heights SetAnnotationHeights(lineDoc, lineDoc + lines + 2); } } // Move a position so it is still after the same character as before the insertion. static inline int MovePositionForInsertion(int position, int startInsertion, int length) { if (position > startInsertion) { return position + length; } return position; } // Move a position so it is still after the same character as before the deletion if that // character is still present else after the previous surviving character. static inline int MovePositionForDeletion(int position, int startDeletion, int length) { if (position > startDeletion) { int endDeletion = startDeletion + length; if (position > endDeletion) { return position - length; } else { return startDeletion; } } else { return position; } } void Editor::NotifyModified(Document *, DocModification mh, void *) { ContainerNeedsUpdate(SC_UPDATE_CONTENT); if (paintState == painting) { CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length)); } if (mh.modificationType & SC_MOD_CHANGELINESTATE) { if (paintState == painting) { CheckForChangeOutsidePaint( Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1))); } else { // Could check that change is before last visible line. Redraw(); } } if (mh.modificationType & SC_MOD_LEXERSTATE) { if (paintState == painting) { CheckForChangeOutsidePaint( Range(mh.position, mh.position + mh.length)); } else { Redraw(); } } if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) { if (mh.modificationType & SC_MOD_CHANGESTYLE) { pdoc->IncrementStyleClock(); } if (paintState == notPainting) { if (mh.position < pdoc->LineStart(topLine)) { // Styling performed before this view Redraw(); } else { InvalidateRange(mh.position, mh.position + mh.length); } } if (mh.modificationType & SC_MOD_CHANGESTYLE) { llc.Invalidate(LineLayout::llCheckTextAndStyle); } } else { // Move selection and brace highlights if (mh.modificationType & SC_MOD_INSERTTEXT) { sel.MovePositions(true, mh.position, mh.length); braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length); braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length); } else if (mh.modificationType & SC_MOD_DELETETEXT) { sel.MovePositions(false, mh.position, mh.length); braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length); braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length); } if ((mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) && cs.HiddenLines()) { // Some lines are hidden so may need shown. // TODO: check if the modified area is hidden. if (mh.modificationType & SC_MOD_BEFOREINSERT) { int lineOfPos = pdoc->LineFromPosition(mh.position); bool insertingNewLine = false; for (int i=0; i < mh.length; i++) { if ((mh.text[i] == '\n') || (mh.text[i] == '\r')) insertingNewLine = true; } if (insertingNewLine && (mh.position != pdoc->LineStart(lineOfPos))) NotifyNeedShown(mh.position, pdoc->LineStart(lineOfPos+1) - mh.position); else NotifyNeedShown(mh.position, 0); } else if (mh.modificationType & SC_MOD_BEFOREDELETE) { NotifyNeedShown(mh.position, mh.length); } } if (mh.linesAdded != 0) { // Update contraction state for inserted and removed lines // lineOfPos should be calculated in context of state before modification, shouldn't it int lineOfPos = pdoc->LineFromPosition(mh.position); if (mh.linesAdded > 0) { cs.InsertLines(lineOfPos, mh.linesAdded); } else { cs.DeleteLines(lineOfPos, -mh.linesAdded); } } if (mh.modificationType & SC_MOD_CHANGEANNOTATION) { int lineDoc = pdoc->LineFromPosition(mh.position); if (vs.annotationVisible) { cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded); Redraw(); } } CheckModificationForWrap(mh); if (mh.linesAdded != 0) { // Avoid scrolling of display if change before current display if (mh.position < posTopLine && !CanDeferToLastStep(mh)) { int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos()); if (newTop != topLine) { SetTopLine(newTop); SetVerticalScrollPos(); } } //Platform::DebugPrintf("** %x Doc Changed\n", this); // TODO: could invalidate from mh.startModification to end of screen //InvalidateRange(mh.position, mh.position + mh.length); if (paintState == notPainting && !CanDeferToLastStep(mh)) { QueueStyling(pdoc->Length()); Redraw(); } } else { //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this, // mh.position, mh.position + mh.length); if (paintState == notPainting && mh.length && !CanEliminate(mh)) { QueueStyling(mh.position + mh.length); InvalidateRange(mh.position, mh.position + mh.length); } } } if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) { SetScrollBars(); } if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) { if ((!willRedrawAll) && ((paintState == notPainting) || !PaintContainsMargin())) { if (mh.modificationType & SC_MOD_CHANGEFOLD) { // Fold changes can affect the drawing of following lines so redraw whole margin RedrawSelMargin(highlightDelimiter.isEnabled ? -1 : mh.line-1, true); } else { RedrawSelMargin(mh.line); } } } // NOW pay the piper WRT "deferred" visual updates if (IsLastStep(mh)) { SetScrollBars(); Redraw(); } // If client wants to see this modification if (mh.modificationType & modEventMask) { if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) { // Real modification made to text of document. NotifyChange(); // Send EN_CHANGE } SCNotification scn = {0}; scn.nmhdr.code = SCN_MODIFIED; scn.position = mh.position; scn.modificationType = mh.modificationType; scn.text = mh.text; scn.length = mh.length; scn.linesAdded = mh.linesAdded; scn.line = mh.line; scn.foldLevelNow = mh.foldLevelNow; scn.foldLevelPrev = mh.foldLevelPrev; scn.token = mh.token; scn.annotationLinesAdded = mh.annotationLinesAdded; NotifyParent(scn); } } void Editor::NotifyDeleted(Document *, void *) { /* Do nothing */ } void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { // Enumerates all macroable messages switch (iMessage) { case SCI_CUT: case SCI_COPY: case SCI_PASTE: case SCI_CLEAR: case SCI_REPLACESEL: case SCI_ADDTEXT: case SCI_INSERTTEXT: case SCI_APPENDTEXT: case SCI_CLEARALL: case SCI_SELECTALL: case SCI_GOTOLINE: case SCI_GOTOPOS: case SCI_SEARCHANCHOR: case SCI_SEARCHNEXT: case SCI_SEARCHPREV: case SCI_LINEDOWN: case SCI_LINEDOWNEXTEND: case SCI_PARADOWN: case SCI_PARADOWNEXTEND: case SCI_LINEUP: case SCI_LINEUPEXTEND: case SCI_PARAUP: case SCI_PARAUPEXTEND: case SCI_CHARLEFT: case SCI_CHARLEFTEXTEND: case SCI_CHARRIGHT: case SCI_CHARRIGHTEXTEND: case SCI_WORDLEFT: case SCI_WORDLEFTEXTEND: case SCI_WORDRIGHT: case SCI_WORDRIGHTEXTEND: case SCI_WORDPARTLEFT: case SCI_WORDPARTLEFTEXTEND: case SCI_WORDPARTRIGHT: case SCI_WORDPARTRIGHTEXTEND: case SCI_WORDLEFTEND: case SCI_WORDLEFTENDEXTEND: case SCI_WORDRIGHTEND: case SCI_WORDRIGHTENDEXTEND: case SCI_HOME: case SCI_HOMEEXTEND: case SCI_LINEEND: case SCI_LINEENDEXTEND: case SCI_HOMEWRAP: case SCI_HOMEWRAPEXTEND: case SCI_LINEENDWRAP: case SCI_LINEENDWRAPEXTEND: case SCI_DOCUMENTSTART: case SCI_DOCUMENTSTARTEXTEND: case SCI_DOCUMENTEND: case SCI_DOCUMENTENDEXTEND: case SCI_STUTTEREDPAGEUP: case SCI_STUTTEREDPAGEUPEXTEND: case SCI_STUTTEREDPAGEDOWN: case SCI_STUTTEREDPAGEDOWNEXTEND: case SCI_PAGEUP: case SCI_PAGEUPEXTEND: case SCI_PAGEDOWN: case SCI_PAGEDOWNEXTEND: case SCI_EDITTOGGLEOVERTYPE: case SCI_CANCEL: case SCI_DELETEBACK: case SCI_TAB: case SCI_BACKTAB: case SCI_FORMFEED: case SCI_VCHOME: case SCI_VCHOMEEXTEND: case SCI_VCHOMEWRAP: case SCI_VCHOMEWRAPEXTEND: case SCI_DELWORDLEFT: case SCI_DELWORDRIGHT: case SCI_DELWORDRIGHTEND: case SCI_DELLINELEFT: case SCI_DELLINERIGHT: case SCI_LINECOPY: case SCI_LINECUT: case SCI_LINEDELETE: case SCI_LINETRANSPOSE: case SCI_LINEDUPLICATE: case SCI_LOWERCASE: case SCI_UPPERCASE: case SCI_LINESCROLLDOWN: case SCI_LINESCROLLUP: case SCI_DELETEBACKNOTLINE: case SCI_HOMEDISPLAY: case SCI_HOMEDISPLAYEXTEND: case SCI_LINEENDDISPLAY: case SCI_LINEENDDISPLAYEXTEND: case SCI_SETSELECTIONMODE: case SCI_LINEDOWNRECTEXTEND: case SCI_LINEUPRECTEXTEND: case SCI_CHARLEFTRECTEXTEND: case SCI_CHARRIGHTRECTEXTEND: case SCI_HOMERECTEXTEND: case SCI_VCHOMERECTEXTEND: case SCI_LINEENDRECTEXTEND: case SCI_PAGEUPRECTEXTEND: case SCI_PAGEDOWNRECTEXTEND: case SCI_SELECTIONDUPLICATE: case SCI_COPYALLOWLINE: case SCI_VERTICALCENTRECARET: case SCI_MOVESELECTEDLINESUP: case SCI_MOVESELECTEDLINESDOWN: case SCI_SCROLLTOSTART: case SCI_SCROLLTOEND: break; // Filter out all others like display changes. Also, newlines are redundant // with char insert messages. case SCI_NEWLINE: default: // printf("Filtered out %ld of macro recording\n", iMessage); return ; } // Send notification SCNotification scn = {0}; scn.nmhdr.code = SCN_MACRORECORD; scn.message = iMessage; scn.wParam = wParam; scn.lParam = lParam; NotifyParent(scn); } // Something has changed that the container should know about void Editor::ContainerNeedsUpdate(int flags) { needUpdateUI |= flags; } /** * Force scroll and keep position relative to top of window. * * If stuttered = true and not already at first/last row, move to first/last row of window. * If stuttered = true and already at first/last row, scroll as normal. */ void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) { int topLineNew; SelectionPosition newPos; int currentLine = pdoc->LineFromPosition(sel.MainCaret()); int topStutterLine = topLine + caretYSlop; int bottomStutterLine = pdoc->LineFromPosition(PositionFromLocation( Point(lastXChosen - xOffset, direction * vs.lineHeight * LinesToScroll()))) - caretYSlop - 1; if (stuttered && (direction < 0 && currentLine > topStutterLine)) { topLineNew = topLine; newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * caretYSlop), false, false, UserVirtualSpace()); } else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) { topLineNew = topLine; newPos = SPositionFromLocation(Point(lastXChosen - xOffset, vs.lineHeight * (LinesToScroll() - caretYSlop)), false, false, UserVirtualSpace()); } else { Point pt = LocationFromPosition(sel.MainCaret()); topLineNew = Platform::Clamp( topLine + direction * LinesToScroll(), 0, MaxScrollPos()); newPos = SPositionFromLocation( Point(lastXChosen - xOffset, pt.y + direction * (vs.lineHeight * LinesToScroll())), false, false, UserVirtualSpace()); } if (topLineNew != topLine) { SetTopLine(topLineNew); MovePositionTo(newPos, selt); Redraw(); SetVerticalScrollPos(); } else { MovePositionTo(newPos, selt); } } void Editor::ChangeCaseOfSelection(int caseMapping) { UndoGroup ug(pdoc); for (size_t r=0; r 0) { std::string sText(text, rangeBytes); std::string sMapped = CaseMapString(sText, caseMapping); if (sMapped != sText) { size_t firstDifference = 0; while (sMapped[firstDifference] == sText[firstDifference]) firstDifference++; size_t lastDifference = sMapped.size() - 1; while (sMapped[lastDifference] == sText[lastDifference]) lastDifference--; size_t endSame = sMapped.size() - 1 - lastDifference; pdoc->DeleteChars( static_cast(currentNoVS.Start().Position() + firstDifference), static_cast(rangeBytes - firstDifference - endSame)); pdoc->InsertString( static_cast(currentNoVS.Start().Position() + firstDifference), sMapped.c_str() + firstDifference, static_cast(lastDifference - firstDifference + 1)); // Automatic movement changes selection so reset to exactly the same as it was. sel.Range(r) = current; } } delete []text; } } void Editor::LineTranspose() { int line = pdoc->LineFromPosition(sel.MainCaret()); if (line > 0) { UndoGroup ug(pdoc); int startPrev = pdoc->LineStart(line - 1); int endPrev = pdoc->LineEnd(line - 1); int start = pdoc->LineStart(line); int end = pdoc->LineEnd(line); char *line1 = CopyRange(startPrev, endPrev); int len1 = endPrev - startPrev; char *line2 = CopyRange(start, end); int len2 = end - start; pdoc->DeleteChars(start, len2); pdoc->DeleteChars(startPrev, len1); pdoc->InsertString(startPrev, line2, len2); pdoc->InsertString(start - len1 + len2, line1, len1); MovePositionTo(SelectionPosition(start - len1 + len2)); delete []line1; delete []line2; } } void Editor::Duplicate(bool forLine) { if (sel.Empty()) { forLine = true; } UndoGroup ug(pdoc); const char *eol = ""; int eolLen = 0; if (forLine) { eol = StringFromEOLMode(pdoc->eolMode); eolLen = istrlen(eol); } for (size_t r=0; rLineFromPosition(sel.Range(r).caret.Position()); start = SelectionPosition(pdoc->LineStart(line)); end = SelectionPosition(pdoc->LineEnd(line)); } char *text = CopyRange(start.Position(), end.Position()); if (forLine) pdoc->InsertString(end.Position(), eol, eolLen); pdoc->InsertString(end.Position() + eolLen, text, SelectionRange(end, start).Length()); delete []text; } if (sel.Count() && sel.IsRectangular()) { SelectionPosition last = sel.Last(); if (forLine) { int line = pdoc->LineFromPosition(last.Position()); last = SelectionPosition(last.Position() + pdoc->LineStart(line+1) - pdoc->LineStart(line)); } if (sel.Rectangular().anchor > sel.Rectangular().caret) sel.Rectangular().anchor = last; else sel.Rectangular().caret = last; SetRectangularRange(); } } void Editor::CancelModes() { sel.SetMoveExtends(false); } void Editor::NewLine() { // Remove non-main ranges InvalidateSelection(sel.RangeMain(), true); sel.SetSelection(sel.RangeMain()); // Clear main range and insert line end bool needGroupUndo = !sel.Empty(); if (needGroupUndo) pdoc->BeginUndoAction(); if (!sel.Empty()) ClearSelection(); const char *eol = "\n"; if (pdoc->eolMode == SC_EOL_CRLF) { eol = "\r\n"; } else if (pdoc->eolMode == SC_EOL_CR) { eol = "\r"; } // else SC_EOL_LF -> "\n" already set bool inserted = pdoc->InsertCString(sel.MainCaret(), eol); // Want to end undo group before NotifyChar as applications often modify text here if (needGroupUndo) pdoc->EndUndoAction(); if (inserted) { SetEmptySelection(sel.MainCaret() + istrlen(eol)); while (*eol) { NotifyChar(*eol); if (recordingMacro) { char txt[2]; txt[0] = *eol; txt[1] = '\0'; NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast(txt)); } eol++; } } SetLastXChosen(); SetScrollBars(); EnsureCaretVisible(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); } void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { SelectionPosition caretToUse = sel.Range(sel.Main()).caret; if (sel.IsRectangular()) { if (selt == Selection::noSel) { caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start; } else { caretToUse = sel.Rectangular().caret; } } Point pt = LocationFromPosition(caretToUse); int skipLines = 0; if (vs.annotationVisible) { int lineDoc = pdoc->LineFromPosition(caretToUse.Position()); Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc)); int subLine = (pt.y - ptStartLine.y) / vs.lineHeight; if (direction < 0 && subLine == 0) { int lineDisplay = cs.DisplayFromDoc(lineDoc); if (lineDisplay > 0) { skipLines = pdoc->AnnotationLines(cs.DocFromDisplay(lineDisplay - 1)); } } else if (direction > 0 && subLine >= (cs.GetHeight(lineDoc) - 1 - pdoc->AnnotationLines(lineDoc))) { skipLines = pdoc->AnnotationLines(lineDoc); } } int newY = pt.y + (1 + skipLines) * direction * vs.lineHeight; SelectionPosition posNew = SPositionFromLocation( Point(lastXChosen - xOffset, newY), false, false, UserVirtualSpace()); if (direction < 0) { // Line wrapping may lead to a location on the same line, so // seek back if that is the case. Point ptNew = LocationFromPosition(posNew.Position()); while ((posNew.Position() > 0) && (pt.y == ptNew.y)) { posNew.Add(-1); posNew.SetVirtualSpace(0); ptNew = LocationFromPosition(posNew.Position()); } } else if (direction > 0 && posNew.Position() != pdoc->Length()) { // There is an equivalent case when moving down which skips // over a line. Point ptNew = LocationFromPosition(posNew.Position()); while ((posNew.Position() > caretToUse.Position()) && (ptNew.y > newY)) { posNew.Add(-1); posNew.SetVirtualSpace(0); ptNew = LocationFromPosition(posNew.Position()); } } MovePositionTo(MovePositionSoVisible(posNew, direction), selt); } void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) { int lineDoc, savedPos = sel.MainCaret(); do { MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt); lineDoc = pdoc->LineFromPosition(sel.MainCaret()); if (direction > 0) { if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) { if (selt == Selection::noSel) { MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos))); } break; } } } while (!cs.GetVisible(lineDoc)); } int Editor::StartEndDisplayLine(int pos, bool start) { RefreshStyleData(); int line = pdoc->LineFromPosition(pos); AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); int posRet = INVALID_POSITION; if (surface && ll) { unsigned int posLineStart = pdoc->LineStart(line); LayoutLine(line, surface, vs, ll, wrapWidth); int posInLine = pos - posLineStart; if (posInLine <= ll->maxLineLength) { for (int subLine = 0; subLine < ll->lines; subLine++) { if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { if (start) { posRet = ll->LineStart(subLine) + posLineStart; } else { if (subLine == ll->lines - 1) posRet = ll->LineStart(subLine + 1) + posLineStart; else posRet = ll->LineStart(subLine + 1) + posLineStart - 1; } } } } } if (posRet == INVALID_POSITION) { return pos; } else { return posRet; } } int Editor::KeyCommand(unsigned int iMessage) { switch (iMessage) { case SCI_LINEDOWN: CursorUpOrDown(1); break; case SCI_LINEDOWNEXTEND: CursorUpOrDown(1, Selection::selStream); break; case SCI_LINEDOWNRECTEXTEND: CursorUpOrDown(1, Selection::selRectangle); break; case SCI_PARADOWN: ParaUpOrDown(1); break; case SCI_PARADOWNEXTEND: ParaUpOrDown(1, Selection::selStream); break; case SCI_LINESCROLLDOWN: ScrollTo(topLine + 1); MoveCaretInsideView(false); break; case SCI_LINEUP: CursorUpOrDown(-1); break; case SCI_LINEUPEXTEND: CursorUpOrDown(-1, Selection::selStream); break; case SCI_LINEUPRECTEXTEND: CursorUpOrDown(-1, Selection::selRectangle); break; case SCI_PARAUP: ParaUpOrDown(-1); break; case SCI_PARAUPEXTEND: ParaUpOrDown(-1, Selection::selStream); break; case SCI_LINESCROLLUP: ScrollTo(topLine - 1); MoveCaretInsideView(false); break; case SCI_CHARLEFT: if (SelectionEmpty() || sel.MoveExtends()) { if ((sel.Count() == 1) && pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { SelectionPosition spCaret = sel.RangeMain().caret; spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); MovePositionTo(spCaret); } else { MovePositionTo(MovePositionSoVisible( SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1)); } } else { MovePositionTo(sel.LimitsForRectangularElseMain().start); } SetLastXChosen(); break; case SCI_CHARLEFTEXTEND: if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { SelectionPosition spCaret = sel.RangeMain().caret; spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); MovePositionTo(spCaret, Selection::selStream); } else { MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream); } SetLastXChosen(); break; case SCI_CHARLEFTRECTEXTEND: if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { SelectionPosition spCaret = sel.RangeMain().caret; spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); MovePositionTo(spCaret, Selection::selRectangle); } else { MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle); } SetLastXChosen(); break; case SCI_CHARRIGHT: if (SelectionEmpty() || sel.MoveExtends()) { if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { SelectionPosition spCaret = sel.RangeMain().caret; spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); MovePositionTo(spCaret); } else { MovePositionTo(MovePositionSoVisible( SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1)); } } else { MovePositionTo(sel.LimitsForRectangularElseMain().end); } SetLastXChosen(); break; case SCI_CHARRIGHTEXTEND: if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { SelectionPosition spCaret = sel.RangeMain().caret; spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); MovePositionTo(spCaret, Selection::selStream); } else { MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream); } SetLastXChosen(); break; case SCI_CHARRIGHTRECTEXTEND: if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) { SelectionPosition spCaret = sel.RangeMain().caret; spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); MovePositionTo(spCaret, Selection::selRectangle); } else { MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle); } SetLastXChosen(); break; case SCI_WORDLEFT: MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1)); SetLastXChosen(); break; case SCI_WORDLEFTEXTEND: MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream); SetLastXChosen(); break; case SCI_WORDRIGHT: MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1)); SetLastXChosen(); break; case SCI_WORDRIGHTEXTEND: MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream); SetLastXChosen(); break; case SCI_WORDLEFTEND: MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1)); SetLastXChosen(); break; case SCI_WORDLEFTENDEXTEND: MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream); SetLastXChosen(); break; case SCI_WORDRIGHTEND: MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1)); SetLastXChosen(); break; case SCI_WORDRIGHTENDEXTEND: MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream); SetLastXChosen(); break; case SCI_HOME: MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); SetLastXChosen(); break; case SCI_HOMEEXTEND: MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream); SetLastXChosen(); break; case SCI_HOMERECTEXTEND: MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle); SetLastXChosen(); break; case SCI_LINEEND: MovePositionTo(pdoc->LineEndPosition(sel.MainCaret())); SetLastXChosen(); break; case SCI_LINEENDEXTEND: MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream); SetLastXChosen(); break; case SCI_LINEENDRECTEXTEND: MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle); SetLastXChosen(); break; case SCI_HOMEWRAP: { SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); if (sel.RangeMain().caret <= homePos) homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); MovePositionTo(homePos); SetLastXChosen(); } break; case SCI_HOMEWRAPEXTEND: { SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); if (sel.RangeMain().caret <= homePos) homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); MovePositionTo(homePos, Selection::selStream); SetLastXChosen(); } break; case SCI_LINEENDWRAP: { SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret())); if (endPos > realEndPos // if moved past visible EOLs || sel.RangeMain().caret >= endPos) // if at end of display line already endPos = realEndPos; MovePositionTo(endPos); SetLastXChosen(); } break; case SCI_LINEENDWRAPEXTEND: { SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret())); if (endPos > realEndPos // if moved past visible EOLs || sel.RangeMain().caret >= endPos) // if at end of display line already endPos = realEndPos; MovePositionTo(endPos, Selection::selStream); SetLastXChosen(); } break; case SCI_DOCUMENTSTART: MovePositionTo(0); SetLastXChosen(); break; case SCI_DOCUMENTSTARTEXTEND: MovePositionTo(0, Selection::selStream); SetLastXChosen(); break; case SCI_DOCUMENTEND: MovePositionTo(pdoc->Length()); SetLastXChosen(); break; case SCI_DOCUMENTENDEXTEND: MovePositionTo(pdoc->Length(), Selection::selStream); SetLastXChosen(); break; case SCI_STUTTEREDPAGEUP: PageMove(-1, Selection::noSel, true); break; case SCI_STUTTEREDPAGEUPEXTEND: PageMove(-1, Selection::selStream, true); break; case SCI_STUTTEREDPAGEDOWN: PageMove(1, Selection::noSel, true); break; case SCI_STUTTEREDPAGEDOWNEXTEND: PageMove(1, Selection::selStream, true); break; case SCI_PAGEUP: PageMove(-1); break; case SCI_PAGEUPEXTEND: PageMove(-1, Selection::selStream); break; case SCI_PAGEUPRECTEXTEND: PageMove(-1, Selection::selRectangle); break; case SCI_PAGEDOWN: PageMove(1); break; case SCI_PAGEDOWNEXTEND: PageMove(1, Selection::selStream); break; case SCI_PAGEDOWNRECTEXTEND: PageMove(1, Selection::selRectangle); break; case SCI_EDITTOGGLEOVERTYPE: inOverstrike = !inOverstrike; DropCaret(); ShowCaretAtCurrentPosition(); ContainerNeedsUpdate(SC_UPDATE_CONTENT); NotifyUpdateUI(); break; case SCI_CANCEL: // Cancel any modes - handled in subclass // Also unselect text CancelModes(); break; case SCI_DELETEBACK: DelCharBack(true); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_DELETEBACKNOTLINE: DelCharBack(false); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_TAB: Indent(true); if (caretSticky == SC_CARETSTICKY_OFF) { SetLastXChosen(); } EnsureCaretVisible(); ShowCaretAtCurrentPosition(); // Avoid blinking break; case SCI_BACKTAB: Indent(false); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); ShowCaretAtCurrentPosition(); // Avoid blinking break; case SCI_NEWLINE: NewLine(); break; case SCI_FORMFEED: AddChar('\f'); break; case SCI_VCHOME: MovePositionTo(pdoc->VCHomePosition(sel.MainCaret())); SetLastXChosen(); break; case SCI_VCHOMEEXTEND: MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream); SetLastXChosen(); break; case SCI_VCHOMERECTEXTEND: MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle); SetLastXChosen(); break; case SCI_VCHOMEWRAP: { SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos)) homePos = viewLineStart; MovePositionTo(homePos); SetLastXChosen(); } break; case SCI_VCHOMEWRAPEXTEND: { SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos)) homePos = viewLineStart; MovePositionTo(homePos, Selection::selStream); SetLastXChosen(); } break; case SCI_ZOOMIN: if (vs.zoomLevel < 20) { vs.zoomLevel++; InvalidateStyleRedraw(); NotifyZoom(); } break; case SCI_ZOOMOUT: if (vs.zoomLevel > -10) { vs.zoomLevel--; InvalidateStyleRedraw(); NotifyZoom(); } break; case SCI_DELWORDLEFT: { int startWord = pdoc->NextWordStart(sel.MainCaret(), -1); pdoc->DeleteChars(startWord, sel.MainCaret() - startWord); sel.RangeMain().ClearVirtualSpace(); SetLastXChosen(); } break; case SCI_DELWORDRIGHT: { UndoGroup ug(pdoc); sel.RangeMain().caret = SelectionPosition( InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); sel.RangeMain().anchor = sel.RangeMain().caret; int endWord = pdoc->NextWordStart(sel.MainCaret(), 1); pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret()); } break; case SCI_DELWORDRIGHTEND: { UndoGroup ug(pdoc); sel.RangeMain().caret = SelectionPosition( InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1); pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret()); } break; case SCI_DELLINELEFT: { int line = pdoc->LineFromPosition(sel.MainCaret()); int start = pdoc->LineStart(line); pdoc->DeleteChars(start, sel.MainCaret() - start); sel.RangeMain().ClearVirtualSpace(); SetLastXChosen(); } break; case SCI_DELLINERIGHT: { int line = pdoc->LineFromPosition(sel.MainCaret()); int end = pdoc->LineEnd(line); pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret()); } break; case SCI_LINECOPY: { int lineStart = pdoc->LineFromPosition(SelectionStart().Position()); int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position()); CopyRangeToClipboard(pdoc->LineStart(lineStart), pdoc->LineStart(lineEnd + 1)); } break; case SCI_LINECUT: { int lineStart = pdoc->LineFromPosition(SelectionStart().Position()); int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position()); int start = pdoc->LineStart(lineStart); int end = pdoc->LineStart(lineEnd + 1); SetSelection(start, end); Cut(); SetLastXChosen(); } break; case SCI_LINEDELETE: { int line = pdoc->LineFromPosition(sel.MainCaret()); int start = pdoc->LineStart(line); int end = pdoc->LineStart(line + 1); pdoc->DeleteChars(start, end - start); } break; case SCI_LINETRANSPOSE: LineTranspose(); break; case SCI_LINEDUPLICATE: Duplicate(true); break; case SCI_SELECTIONDUPLICATE: Duplicate(false); break; case SCI_LOWERCASE: ChangeCaseOfSelection(cmLower); break; case SCI_UPPERCASE: ChangeCaseOfSelection(cmUpper); break; case SCI_WORDPARTLEFT: MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1)); SetLastXChosen(); break; case SCI_WORDPARTLEFTEXTEND: MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream); SetLastXChosen(); break; case SCI_WORDPARTRIGHT: MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1)); SetLastXChosen(); break; case SCI_WORDPARTRIGHTEXTEND: MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream); SetLastXChosen(); break; case SCI_HOMEDISPLAY: MovePositionTo(MovePositionSoVisible( StartEndDisplayLine(sel.MainCaret(), true), -1)); SetLastXChosen(); break; case SCI_HOMEDISPLAYEXTEND: MovePositionTo(MovePositionSoVisible( StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream); SetLastXChosen(); break; case SCI_LINEENDDISPLAY: MovePositionTo(MovePositionSoVisible( StartEndDisplayLine(sel.MainCaret(), false), 1)); SetLastXChosen(); break; case SCI_LINEENDDISPLAYEXTEND: MovePositionTo(MovePositionSoVisible( StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream); SetLastXChosen(); break; case SCI_SCROLLTOSTART: ScrollTo(0); break; case SCI_SCROLLTOEND: ScrollTo(MaxScrollPos()); break; } return 0; } int Editor::KeyDefault(int, int) { return 0; } int Editor::KeyDownWithModifiers(int key, int modifiers, bool *consumed) { DwellEnd(false); int msg = kmap.Find(key, modifiers); if (msg) { if (consumed) *consumed = true; return WndProc(msg, 0, 0); } else { if (consumed) *consumed = false; return KeyDefault(key, modifiers); } } int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) { int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0); return KeyDownWithModifiers(key, modifiers, consumed); } void Editor::Indent(bool forwards) { for (size_t r=0; rLineFromPosition(sel.Range(r).anchor.Position()); int caretPosition = sel.Range(r).caret.Position(); int lineCurrentPos = pdoc->LineFromPosition(caretPosition); if (lineOfAnchor == lineCurrentPos) { if (forwards) { UndoGroup ug(pdoc); pdoc->DeleteChars(sel.Range(r).Start().Position(), sel.Range(r).Length()); caretPosition = sel.Range(r).caret.Position(); if (pdoc->GetColumn(caretPosition) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) && pdoc->tabIndents) { int indentation = pdoc->GetLineIndentation(lineCurrentPos); int indentationStep = pdoc->IndentSize(); pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep); sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos)); } else { if (pdoc->useTabs) { pdoc->InsertChar(caretPosition, '\t'); sel.Range(r) = SelectionRange(caretPosition+1); } else { int numSpaces = (pdoc->tabInChars) - (pdoc->GetColumn(caretPosition) % (pdoc->tabInChars)); if (numSpaces < 1) numSpaces = pdoc->tabInChars; for (int i = 0; i < numSpaces; i++) { pdoc->InsertChar(caretPosition + i, ' '); } sel.Range(r) = SelectionRange(caretPosition+numSpaces); } } } else { if (pdoc->GetColumn(caretPosition) <= pdoc->GetLineIndentation(lineCurrentPos) && pdoc->tabIndents) { UndoGroup ug(pdoc); int indentation = pdoc->GetLineIndentation(lineCurrentPos); int indentationStep = pdoc->IndentSize(); pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos)); } else { int newColumn = ((pdoc->GetColumn(caretPosition) - 1) / pdoc->tabInChars) * pdoc->tabInChars; if (newColumn < 0) newColumn = 0; int newPos = caretPosition; while (pdoc->GetColumn(newPos) > newColumn) newPos--; sel.Range(r) = SelectionRange(newPos); } } } else { // Multiline int anchorPosOnLine = sel.Range(r).anchor.Position() - pdoc->LineStart(lineOfAnchor); int currentPosPosOnLine = caretPosition - pdoc->LineStart(lineCurrentPos); // Multiple lines selected so indent / dedent int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos); int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos); if (pdoc->LineStart(lineBottomSel) == sel.Range(r).anchor.Position() || pdoc->LineStart(lineBottomSel) == caretPosition) lineBottomSel--; // If not selecting any characters on a line, do not indent { UndoGroup ug(pdoc); pdoc->Indent(forwards, lineBottomSel, lineTopSel); } if (lineOfAnchor < lineCurrentPos) { if (currentPosPosOnLine == 0) sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); else sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor)); } else { if (anchorPosOnLine == 0) sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor)); else sel.Range(r) = SelectionRange(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1)); } } } } class CaseFolderASCII : public CaseFolderTable { public: CaseFolderASCII() { StandardASCII(); } ~CaseFolderASCII() { } }; CaseFolder *Editor::CaseFolderForEncoding() { // Simple default that only maps ASCII upper case to lower case. return new CaseFolderASCII(); } /** * Search of a text in the document, in the given range. * @return The position of the found text, -1 if not found. */ long Editor::FindText( uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. sptr_t lParam) { ///< @c TextToFind structure: The text to search for in the given range. Sci_TextToFind *ft = reinterpret_cast(lParam); int lengthFound = istrlen(ft->lpstrText); std::auto_ptr pcf(CaseFolderForEncoding()); int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText, (wParam & SCFIND_MATCHCASE) != 0, (wParam & SCFIND_WHOLEWORD) != 0, (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, &lengthFound, pcf.get()); if (pos != -1) { ft->chrgText.cpMin = pos; ft->chrgText.cpMax = pos + lengthFound; } return pos; } /** * Relocatable search support : Searches relative to current selection * point and sets the selection to the found text range with * each search. */ /** * Anchor following searches at current selection start: This allows * multiple incremental interactive searches to be macro recorded * while still setting the selection to found text so the find/select * operation is self-contained. */ void Editor::SearchAnchor() { searchAnchor = SelectionStart().Position(); } // Simple RAII wrapper for CaseFolder as std::auto_ptr is now deprecated class ScopedCaseFolder { CaseFolder *pcf; public: ScopedCaseFolder(CaseFolder *pcf_) : pcf(pcf_) { } ~ScopedCaseFolder() { delete pcf; pcf = 0; } CaseFolder *get() const { return pcf; } }; /** * Find text from current search anchor: Must call @c SearchAnchor first. * Used for next text and previous text requests. * @return The position of the found text, -1 if not found. */ long Editor::SearchText( unsigned int iMessage, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV. uptr_t wParam, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD, ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX. sptr_t lParam) { ///< The text to search for. const char *txt = reinterpret_cast(lParam); int pos; int lengthFound = istrlen(txt); ScopedCaseFolder pcf(CaseFolderForEncoding()); if (iMessage == SCI_SEARCHNEXT) { pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt, (wParam & SCFIND_MATCHCASE) != 0, (wParam & SCFIND_WHOLEWORD) != 0, (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, &lengthFound, pcf.get()); } else { pos = pdoc->FindText(searchAnchor, 0, txt, (wParam & SCFIND_MATCHCASE) != 0, (wParam & SCFIND_WHOLEWORD) != 0, (wParam & SCFIND_WORDSTART) != 0, (wParam & SCFIND_REGEXP) != 0, wParam, &lengthFound, pcf.get()); } if (pos != -1) { SetSelection(pos, pos + lengthFound); } return pos; } std::string Editor::CaseMapString(const std::string &s, int caseMapping) { std::string ret(s); for (size_t i=0; i= 'a' && ret[i] <= 'z') ret[i] = static_cast(ret[i] - 'a' + 'A'); break; case cmLower: if (ret[i] >= 'A' && ret[i] <= 'Z') ret[i] = static_cast(ret[i] - 'A' + 'a'); break; } } return ret; } /** * Search for text in the target range of the document. * @return The position of the found text, -1 if not found. */ long Editor::SearchInTarget(const char *text, int length) { int lengthFound = length; ScopedCaseFolder pcf(CaseFolderForEncoding()); int pos = pdoc->FindText(targetStart, targetEnd, text, (searchFlags & SCFIND_MATCHCASE) != 0, (searchFlags & SCFIND_WHOLEWORD) != 0, (searchFlags & SCFIND_WORDSTART) != 0, (searchFlags & SCFIND_REGEXP) != 0, searchFlags, &lengthFound, pcf.get()); if (pos != -1) { targetStart = pos; targetEnd = pos + lengthFound; } return pos; } void Editor::GoToLine(int lineNo) { if (lineNo > pdoc->LinesTotal()) lineNo = pdoc->LinesTotal(); if (lineNo < 0) lineNo = 0; SetEmptySelection(pdoc->LineStart(lineNo)); ShowCaretAtCurrentPosition(); EnsureCaretVisible(); } static bool Close(Point pt1, Point pt2) { if (abs(pt1.x - pt2.x) > 3) return false; if (abs(pt1.y - pt2.y) > 3) return false; return true; } char *Editor::CopyRange(int start, int end) { char *text = 0; if (start < end) { int len = end - start; text = new char[len + 1]; for (int i = 0; i < len; i++) { text[i] = pdoc->CharAt(start + i); } text[len] = '\0'; } return text; } void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) { if (sel.Empty()) { if (allowLineCopy) { int currentLine = pdoc->LineFromPosition(sel.MainCaret()); int start = pdoc->LineStart(currentLine); int end = pdoc->LineEnd(currentLine); char *text = CopyRange(start, end); size_t textLen = text ? strlen(text) : 0; // include room for \r\n\0 textLen += 3; char *textWithEndl = new char[textLen]; textWithEndl[0] = '\0'; if (text) strncat(textWithEndl, text, textLen); if (pdoc->eolMode != SC_EOL_LF) strncat(textWithEndl, "\r", textLen); if (pdoc->eolMode != SC_EOL_CR) strncat(textWithEndl, "\n", textLen); ss->Set(textWithEndl, static_cast(strlen(textWithEndl) + 1), pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true); delete []text; } } else { int delimiterLength = 0; if (sel.selType == Selection::selRectangle) { if (pdoc->eolMode == SC_EOL_CRLF) { delimiterLength = 2; } else { delimiterLength = 1; } } size_t size = sel.Length() + delimiterLength * sel.Count(); char *text = new char[size + 1]; int j = 0; std::vector rangesInOrder = sel.RangesCopy(); if (sel.selType == Selection::selRectangle) std::sort(rangesInOrder.begin(), rangesInOrder.end()); for (size_t r=0; rCharAt(i); } if (sel.selType == Selection::selRectangle) { if (pdoc->eolMode != SC_EOL_LF) { text[j++] = '\r'; } if (pdoc->eolMode != SC_EOL_CR) { text[j++] = '\n'; } } } text[size] = '\0'; ss->Set(text, static_cast(size + 1), pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines); } } void Editor::CopyRangeToClipboard(int start, int end) { start = pdoc->ClampPositionIntoDocument(start); end = pdoc->ClampPositionIntoDocument(end); SelectionText selectedText; selectedText.Set(CopyRange(start, end), end - start + 1, pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); CopyToClipboard(selectedText); } void Editor::CopyText(int length, const char *text) { SelectionText selectedText; selectedText.Copy(text, length + 1, pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); CopyToClipboard(selectedText); } void Editor::SetDragPosition(SelectionPosition newPos) { if (newPos.Position() >= 0) { newPos = MovePositionOutsideChar(newPos, 1); posDrop = newPos; } if (!(posDrag == newPos)) { caret.on = true; SetTicking(true); InvalidateCaret(); posDrag = newPos; InvalidateCaret(); } } void Editor::DisplayCursor(Window::Cursor c) { if (cursorMode == SC_CURSORNORMAL) wMain.SetCursor(c); else wMain.SetCursor(static_cast(cursorMode)); } bool Editor::DragThreshold(Point ptStart, Point ptNow) { int xMove = ptStart.x - ptNow.x; int yMove = ptStart.y - ptNow.y; int distanceSquared = xMove * xMove + yMove * yMove; return distanceSquared > 16; } void Editor::StartDrag() { // Always handled by subclasses //SetMouseCapture(true); //DisplayCursor(Window::cursorArrow); } void Editor::DropAt(SelectionPosition position, const char *value, bool moving, bool rectangular) { //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position); if (inDragDrop == ddDragging) dropWentOutside = false; bool positionWasInSelection = PositionInSelection(position.Position()); bool positionOnEdgeOfSelection = (position == SelectionStart()) || (position == SelectionEnd()); if ((inDragDrop != ddDragging) || !(positionWasInSelection) || (positionOnEdgeOfSelection && !moving)) { SelectionPosition selStart = SelectionStart(); SelectionPosition selEnd = SelectionEnd(); UndoGroup ug(pdoc); SelectionPosition positionAfterDeletion = position; if ((inDragDrop == ddDragging) && moving) { // Remove dragged out text if (rectangular || sel.selType == Selection::selLines) { for (size_t r=0; r= sel.Range(r).Start()) { if (position > sel.Range(r).End()) { positionAfterDeletion.Add(-sel.Range(r).Length()); } else { positionAfterDeletion.Add(-SelectionRange(position, sel.Range(r).Start()).Length()); } } } } else { if (position > selStart) { positionAfterDeletion.Add(-SelectionRange(selEnd, selStart).Length()); } } ClearSelection(); } position = positionAfterDeletion; if (rectangular) { PasteRectangular(position, value, istrlen(value)); // Should try to select new rectangle but it may not be a rectangle now so just select the drop position SetEmptySelection(position); } else { position = MovePositionOutsideChar(position, sel.MainCaret() - position.Position()); position = SelectionPosition(InsertSpace(position.Position(), position.VirtualSpace())); if (pdoc->InsertCString(position.Position(), value)) { SelectionPosition posAfterInsertion = position; posAfterInsertion.Add(istrlen(value)); SetSelection(posAfterInsertion, position); } } } else if (inDragDrop == ddDragging) { SetEmptySelection(position); } } /** * @return true if given position is inside the selection, */ bool Editor::PositionInSelection(int pos) { pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos); for (size_t r=0; r ptPos.x) { hit = false; } } if (hit) return true; } } return false; } bool Editor::PointInSelMargin(Point pt) { // Really means: "Point in a margin" if (vs.fixedColumnWidth > 0) { // There is a margin PRectangle rcSelMargin = GetClientRectangle(); rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth; return rcSelMargin.Contains(pt); } else { return false; } } Window::Cursor Editor::GetMarginCursor(Point pt) { int x = 0; for (int margin = 0; margin < ViewStyle::margins; margin++) { if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width)) return static_cast(vs.ms[margin].cursor); x += vs.ms[margin].width; } return Window::cursorReverseArrow; } void Editor::TrimAndSetSelection(int currentPos_, int anchor_) { sel.TrimSelection(SelectionRange(currentPos_, anchor_)); SetSelection(currentPos_, anchor_); } void Editor::LineSelection(int lineCurrentPos_, int lineAnchorPos_, bool wholeLine) { int selCurrentPos, selAnchorPos; if (wholeLine) { int lineCurrent_ = pdoc->LineFromPosition(lineCurrentPos_); int lineAnchor_ = pdoc->LineFromPosition(lineAnchorPos_); if (lineAnchorPos_ < lineCurrentPos_) { selCurrentPos = pdoc->LineStart(lineCurrent_ + 1); selAnchorPos = pdoc->LineStart(lineAnchor_); } else if (lineAnchorPos_ > lineCurrentPos_) { selCurrentPos = pdoc->LineStart(lineCurrent_); selAnchorPos = pdoc->LineStart(lineAnchor_ + 1); } else { // Same line, select it selCurrentPos = pdoc->LineStart(lineAnchor_ + 1); selAnchorPos = pdoc->LineStart(lineAnchor_); } } else { if (lineAnchorPos_ < lineCurrentPos_) { selCurrentPos = StartEndDisplayLine(lineCurrentPos_, false) + 1; selCurrentPos = pdoc->MovePositionOutsideChar(selCurrentPos, 1); selAnchorPos = StartEndDisplayLine(lineAnchorPos_, true); } else if (lineAnchorPos_ > lineCurrentPos_) { selCurrentPos = StartEndDisplayLine(lineCurrentPos_, true); selAnchorPos = StartEndDisplayLine(lineAnchorPos_, false) + 1; selAnchorPos = pdoc->MovePositionOutsideChar(selAnchorPos, 1); } else { // Same line, select it selCurrentPos = StartEndDisplayLine(lineAnchorPos_, false) + 1; selCurrentPos = pdoc->MovePositionOutsideChar(selCurrentPos, 1); selAnchorPos = StartEndDisplayLine(lineAnchorPos_, true); } } TrimAndSetSelection(selCurrentPos, selAnchorPos); } void Editor::WordSelection(int pos) { if (pos < wordSelectAnchorStartPos) { // Extend backward to the word containing pos. // Skip ExtendWordSelect if the line is empty or if pos is after the last character. // This ensures that a series of empty lines isn't counted as a single "word". if (!pdoc->IsLineEndPosition(pos)) pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos + 1, 1), -1); TrimAndSetSelection(pos, wordSelectAnchorEndPos); } else if (pos > wordSelectAnchorEndPos) { // Extend forward to the word containing the character to the left of pos. // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line. // This ensures that a series of empty lines isn't counted as a single "word". if (pos > pdoc->LineStart(pdoc->LineFromPosition(pos))) pos = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(pos - 1, -1), 1); TrimAndSetSelection(pos, wordSelectAnchorStartPos); } else { // Select only the anchored word if (pos >= originalAnchorPos) TrimAndSetSelection(wordSelectAnchorEndPos, wordSelectAnchorStartPos); else TrimAndSetSelection(wordSelectAnchorStartPos, wordSelectAnchorEndPos); } } void Editor::DwellEnd(bool mouseMoved) { if (mouseMoved) ticksToDwell = dwellDelay; else ticksToDwell = SC_TIME_FOREVER; if (dwelling && (dwellDelay < SC_TIME_FOREVER)) { dwelling = false; NotifyDwelling(ptMouseLast, dwelling); } } void Editor::MouseLeave() { SetHotSpotRange(NULL); if (!HaveMouseCapture()) { ptMouseLast = Point(-1,-1); DwellEnd(true); } } static bool AllowVirtualSpace(int virtualSpaceOptions, bool rectangular) { return (!rectangular && ((virtualSpaceOptions & SCVS_USERACCESSIBLE) != 0)) || (rectangular && ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) != 0)); } void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop); ptMouseLast = pt; SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, alt)); newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position()); inDragDrop = ddNone; sel.SetMoveExtends(false); if (NotifyMarginClick(pt, shift, ctrl, alt)) return; NotifyIndicatorClick(true, newPos.Position(), shift, ctrl, alt); bool inSelMargin = PointInSelMargin(pt); // In margin ctrl+(double)click should always select everything if (ctrl && inSelMargin) { SelectAll(); lastClickTime = curTime; lastClick = pt; return; } if (shift && !inSelMargin) { SetSelection(newPos); } if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) { //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime); SetMouseCapture(true); if (!ctrl || !multipleSelection || (selectionType != selChar && selectionType != selWord)) SetEmptySelection(newPos.Position()); bool doubleClick = false; // Stop mouse button bounce changing selection type if (!Platform::MouseButtonBounce() || curTime != lastClickTime) { if (inSelMargin) { // Inside margin selection type should be either selSubLine or selWholeLine. if (selectionType == selSubLine) { // If it is selSubLine, we're inside a *double* click and word wrap is enabled, // so we switch to selWholeLine in order to select whole line. selectionType = selWholeLine; } else if (selectionType != selSubLine && selectionType != selWholeLine) { // If it is neither, reset selection type to line selection. selectionType = ((wrapState != eWrapNone) && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; } } else { if (selectionType == selChar) { selectionType = selWord; doubleClick = true; } else if (selectionType == selWord) { // Since we ended up here, we're inside a *triple* click, which should always select // whole line irregardless of word wrap being enabled or not. selectionType = selWholeLine; } else { selectionType = selChar; originalAnchorPos = sel.MainCaret(); } } } if (selectionType == selWord) { int charPos = originalAnchorPos; if (sel.MainCaret() == originalAnchorPos) { charPos = PositionFromLocation(pt, false, true); charPos = MovePositionOutsideChar(charPos, -1); } int startWord, endWord; if ((sel.MainCaret() >= originalAnchorPos) && !pdoc->IsLineEndPosition(charPos)) { startWord = pdoc->ExtendWordSelect(pdoc->MovePositionOutsideChar(charPos + 1, 1), -1); endWord = pdoc->ExtendWordSelect(charPos, 1); } else { // Selecting backwards, or anchor beyond last character on line. In these cases, // we select the word containing the character to the *left* of the anchor. if (charPos > pdoc->LineStart(pdoc->LineFromPosition(charPos))) { startWord = pdoc->ExtendWordSelect(charPos, -1); endWord = pdoc->ExtendWordSelect(startWord, 1); } else { // Anchor at start of line; select nothing to begin with. startWord = charPos; endWord = charPos; } } wordSelectAnchorStartPos = startWord; wordSelectAnchorEndPos = endWord; wordSelectInitialCaretPos = sel.MainCaret(); WordSelection(wordSelectInitialCaretPos); } else if (selectionType == selSubLine || selectionType == selWholeLine) { lineAnchorPos = newPos.Position(); LineSelection(lineAnchorPos, lineAnchorPos, selectionType == selWholeLine); //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos); } else { SetEmptySelection(sel.MainCaret()); } //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos); if (doubleClick) { NotifyDoubleClick(pt, shift, ctrl, alt); if (PositionIsHotspot(newPos.Position())) NotifyHotSpotDoubleClicked(newPos.Position(), shift, ctrl, alt); } } else { // Single click if (inSelMargin) { sel.selType = Selection::selStream; if (!shift) { // Single click in margin: select whole line or only subline if word wrap is enabled lineAnchorPos = newPos.Position(); selectionType = ((wrapState != eWrapNone) && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; LineSelection(lineAnchorPos, lineAnchorPos, selectionType == selWholeLine); } else { // Single shift+click in margin: select from line anchor to clicked line if (sel.MainAnchor() > sel.MainCaret()) lineAnchorPos = sel.MainAnchor() - 1; else lineAnchorPos = sel.MainAnchor(); // Reset selection type if there is an empty selection. // This ensures that we don't end up stuck in previous selection mode, which is no longer valid. // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine. // This ensures that we continue selecting in the same selection mode. if (sel.Empty() || (selectionType != selSubLine && selectionType != selWholeLine)) selectionType = ((wrapState != eWrapNone) && (marginOptions & SC_MARGINOPTION_SUBLINESELECT)) ? selSubLine : selWholeLine; LineSelection(newPos.Position(), lineAnchorPos, selectionType == selWholeLine); } SetDragPosition(SelectionPosition(invalidPosition)); SetMouseCapture(true); } else { if (PointIsHotspot(pt)) { NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt); hotSpotClickPos = PositionFromLocation(pt,true,false); } if (!shift) { if (PointInSelection(pt) && !SelectionEmpty()) inDragDrop = ddInitial; else inDragDrop = ddNone; } SetMouseCapture(true); if (inDragDrop != ddInitial) { SetDragPosition(SelectionPosition(invalidPosition)); if (!shift) { if (ctrl && multipleSelection) { SelectionRange range(newPos); sel.TentativeSelection(range); InvalidateSelection(range, true); } else { InvalidateSelection(SelectionRange(newPos), true); if (sel.Count() > 1) Redraw(); if ((sel.Count() > 1) || (sel.selType != Selection::selStream)) sel.Clear(); sel.selType = alt ? Selection::selRectangle : Selection::selStream; SetSelection(newPos, newPos); } } SelectionPosition anchorCurrent = newPos; if (shift) anchorCurrent = sel.IsRectangular() ? sel.Rectangular().anchor : sel.RangeMain().anchor; sel.selType = alt ? Selection::selRectangle : Selection::selStream; selectionType = selChar; originalAnchorPos = sel.MainCaret(); sel.Rectangular() = SelectionRange(newPos, anchorCurrent); SetRectangularRange(); } } } lastClickTime = curTime; lastClick = pt; lastXChosen = pt.x + xOffset; ShowCaretAtCurrentPosition(); } bool Editor::PositionIsHotspot(int position) { return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot; } bool Editor::PointIsHotspot(Point pt) { int pos = PositionFromLocation(pt, true); if (pos == INVALID_POSITION) return false; return PositionIsHotspot(pos); } void Editor::SetHotSpotRange(Point *pt) { if (pt) { int pos = PositionFromLocation(*pt); // If we don't limit this to word characters then the // range can encompass more than the run range and then // the underline will not be drawn properly. int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine); int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine); // Only invalidate the range if the hotspot range has changed... if (hsStart_ != hsStart || hsEnd_ != hsEnd) { if (hsStart != -1) { InvalidateRange(hsStart, hsEnd); } hsStart = hsStart_; hsEnd = hsEnd_; InvalidateRange(hsStart, hsEnd); } } else { if (hsStart != -1) { int hsStart_ = hsStart; int hsEnd_ = hsEnd; hsStart = -1; hsEnd = -1; InvalidateRange(hsStart_, hsEnd_); } else { hsStart = -1; hsEnd = -1; } } } void Editor::GetHotSpotRange(int &hsStart_, int &hsEnd_) { hsStart_ = hsStart; hsEnd_ = hsEnd; } void Editor::ButtonMove(Point pt) { if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) { DwellEnd(true); } SelectionPosition movePos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular())); movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position()); if (inDragDrop == ddInitial) { if (DragThreshold(ptMouseLast, pt)) { SetMouseCapture(false); SetDragPosition(movePos); CopySelectionRange(&drag); StartDrag(); } return; } ptMouseLast = pt; //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y); if (HaveMouseCapture()) { // Slow down autoscrolling/selection autoScrollTimer.ticksToWait -= timer.tickSize; if (autoScrollTimer.ticksToWait > 0) return; autoScrollTimer.ticksToWait = autoScrollDelay; // Adjust selection if (posDrag.IsValid()) { SetDragPosition(movePos); } else { if (selectionType == selChar) { if (sel.IsRectangular()) { sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor); SetSelection(movePos, sel.RangeMain().anchor); } else if (sel.Count() > 1) { SelectionRange range(movePos, sel.RangeMain().anchor); sel.TentativeSelection(range); InvalidateSelection(range, true); } else { SetSelection(movePos, sel.RangeMain().anchor); } } else if (selectionType == selWord) { // Continue selecting by word if (movePos.Position() == wordSelectInitialCaretPos) { // Didn't move // No need to do anything. Previously this case was lumped // in with "Moved forward", but that can be harmful in this // case: a handler for the NotifyDoubleClick re-adjusts // the selection for a fancier definition of "word" (for // example, in Perl it is useful to include the leading // '$', '%' or '@' on variables for word selection). In this // the ButtonMove() called via Tick() for auto-scrolling // could result in the fancier word selection adjustment // being unmade. } else { wordSelectInitialCaretPos = -1; WordSelection(movePos.Position()); } } else { // Continue selecting by line LineSelection(movePos.Position(), lineAnchorPos, selectionType == selWholeLine); } } // Autoscroll PRectangle rcClient = GetClientRectangle(); int lineMove = DisplayFromPosition(movePos.Position()); if (pt.y > rcClient.bottom) { ScrollTo(lineMove - LinesOnScreen() + 1); Redraw(); } else if (pt.y < rcClient.top) { ScrollTo(lineMove); Redraw(); } EnsureCaretVisible(false, false, true); if (hsStart != -1 && !PositionIsHotspot(movePos.Position())) SetHotSpotRange(NULL); if (hotSpotClickPos != INVALID_POSITION && PositionFromLocation(pt,true,false) != hotSpotClickPos) { if (inDragDrop == ddNone) { DisplayCursor(Window::cursorText); } hotSpotClickPos = INVALID_POSITION; } } else { if (vs.fixedColumnWidth > 0) { // There is a margin if (PointInSelMargin(pt)) { DisplayCursor(GetMarginCursor(pt)); SetHotSpotRange(NULL); return; // No need to test for selection } } // Display regular (drag) cursor over selection if (PointInSelection(pt) && !SelectionEmpty()) { DisplayCursor(Window::cursorArrow); } else if (PointIsHotspot(pt)) { DisplayCursor(Window::cursorHand); SetHotSpotRange(&pt); } else { DisplayCursor(Window::cursorText); SetHotSpotRange(NULL); } } } void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) { //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop); SelectionPosition newPos = SPositionFromLocation(pt, false, false, AllowVirtualSpace(virtualSpaceOptions, sel.IsRectangular())); newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position()); if (inDragDrop == ddInitial) { inDragDrop = ddNone; SetEmptySelection(newPos); selectionType = selChar; originalAnchorPos = sel.MainCaret(); } if (hotSpotClickPos != INVALID_POSITION && PointIsHotspot(pt)) { hotSpotClickPos = INVALID_POSITION; NotifyHotSpotReleaseClick(newPos.Position(), false, ctrl, false); } if (HaveMouseCapture()) { if (PointInSelMargin(pt)) { DisplayCursor(GetMarginCursor(pt)); } else { DisplayCursor(Window::cursorText); SetHotSpotRange(NULL); } ptMouseLast = pt; SetMouseCapture(false); NotifyIndicatorClick(false, newPos.Position(), false, false, false); if (inDragDrop == ddDragging) { SelectionPosition selStart = SelectionStart(); SelectionPosition selEnd = SelectionEnd(); if (selStart < selEnd) { if (drag.len) { if (ctrl) { if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { SetSelection(newPos.Position(), newPos.Position() + drag.len); } } else if (newPos < selStart) { pdoc->DeleteChars(selStart.Position(), drag.len); if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { SetSelection(newPos.Position(), newPos.Position() + drag.len); } } else if (newPos > selEnd) { pdoc->DeleteChars(selStart.Position(), drag.len); newPos.Add(-drag.len); if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { SetSelection(newPos.Position(), newPos.Position() + drag.len); } } else { SetEmptySelection(newPos.Position()); } drag.Free(); } selectionType = selChar; } } else { if (selectionType == selChar) { if (sel.Count() > 1) { sel.RangeMain() = SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor); InvalidateSelection(sel.RangeMain(), true); } else { SetSelection(newPos, sel.RangeMain().anchor); } } sel.CommitTentative(); } SetRectangularRange(); lastClickTime = curTime; lastClick = pt; lastXChosen = pt.x + xOffset; if (sel.selType == Selection::selStream) { SetLastXChosen(); } inDragDrop = ddNone; EnsureCaretVisible(false); } } // Called frequently to perform background UI including // caret blinking and automatic scrolling. void Editor::Tick() { if (HaveMouseCapture()) { // Auto scroll ButtonMove(ptMouseLast); } if (caret.period > 0) { timer.ticksToWait -= timer.tickSize; if (timer.ticksToWait <= 0) { caret.on = !caret.on; timer.ticksToWait = caret.period; if (caret.active) { InvalidateCaret(); } } } if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) { scrollWidth = lineWidthMaxSeen; SetScrollBars(); } if ((dwellDelay < SC_TIME_FOREVER) && (ticksToDwell > 0) && (!HaveMouseCapture()) && (ptMouseLast.y >= 0)) { ticksToDwell -= timer.tickSize; if (ticksToDwell <= 0) { dwelling = true; NotifyDwelling(ptMouseLast, dwelling); } } } bool Editor::Idle() { bool idleDone; bool wrappingDone = wrapState == eWrapNone; if (!wrappingDone) { // Wrap lines during idle. WrapLines(false, -1); // No more wrapping if (wrapStart == wrapEnd) wrappingDone = true; } // Add more idle things to do here, but make sure idleDone is // set correctly before the function returns. returning // false will stop calling this idle funtion until SetIdle() is // called again. idleDone = wrappingDone; // && thatDone && theOtherThingDone... return !idleDone; } void Editor::SetFocusState(bool focusState) { hasFocus = focusState; NotifyFocus(hasFocus); if (hasFocus) { ShowCaretAtCurrentPosition(); } else { CancelModes(); DropCaret(); } } int Editor::PositionAfterArea(PRectangle rcArea) { // The start of the document line after the display line after the area // This often means that the line after a modification is restyled which helps // detect multiline comment additions and heals single line comments int lineAfter = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1; if (lineAfter < cs.LinesDisplayed()) return pdoc->LineStart(cs.DocFromDisplay(lineAfter) + 1); else return pdoc->Length(); } // Style to a position within the view. If this causes a change at end of last line then // affects later lines so style all the viewed text. void Editor::StyleToPositionInView(Position pos) { int endWindow = PositionAfterArea(GetClientRectangle()); if (pos > endWindow) pos = endWindow; int styleAtEnd = pdoc->StyleAt(pos-1); pdoc->EnsureStyledTo(pos); if ((endWindow > pos) && (styleAtEnd != pdoc->StyleAt(pos-1))) { // Style at end of line changed so is multi-line change like starting a comment // so require rest of window to be styled. pdoc->EnsureStyledTo(endWindow); } } void Editor::IdleStyling() { // Style the line after the modification as this allows modifications that change just the // line of the modification to heal instead of propagating to the rest of the window. StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2)); if (needUpdateUI) { NotifyUpdateUI(); needUpdateUI = 0; } styleNeeded.Reset(); } void Editor::QueueStyling(int upTo) { styleNeeded.NeedUpTo(upTo); } bool Editor::PaintContains(PRectangle rc) { if (rc.Empty()) { return true; } else { return rcPaint.Contains(rc); } } bool Editor::PaintContainsMargin() { PRectangle rcSelMargin = GetClientRectangle(); rcSelMargin.right = vs.fixedColumnWidth; return PaintContains(rcSelMargin); } void Editor::CheckForChangeOutsidePaint(Range r) { if (paintState == painting && !paintingAllText) { //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end); if (!r.Valid()) return; PRectangle rcRange = RectangleFromRange(r.start, r.end); PRectangle rcText = GetTextRectangle(); if (rcRange.top < rcText.top) { rcRange.top = rcText.top; } if (rcRange.bottom > rcText.bottom) { rcRange.bottom = rcText.bottom; } if (!PaintContains(rcRange)) { AbandonPaint(); } } } void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) { if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) { if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) { CheckForChangeOutsidePaint(Range(braces[0])); CheckForChangeOutsidePaint(Range(pos0)); braces[0] = pos0; } if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) { CheckForChangeOutsidePaint(Range(braces[1])); CheckForChangeOutsidePaint(Range(pos1)); braces[1] = pos1; } bracesMatchStyle = matchStyle; if (paintState == notPainting) { Redraw(); } } } void Editor::SetAnnotationHeights(int start, int end) { if (vs.annotationVisible) { bool changedHeight = false; for (int line=start; lineLinesTotal(); line++) { int linesWrapped = 1; if (wrapState != eWrapNone) { AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); if (surface && ll) { LayoutLine(line, surface, vs, ll, wrapWidth); linesWrapped = ll->lines; } } if (cs.SetHeight(line, pdoc->AnnotationLines(line) + linesWrapped)) changedHeight = true; } if (changedHeight) { Redraw(); } } } void Editor::SetDocPointer(Document *document) { //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document); pdoc->RemoveWatcher(this, 0); pdoc->Release(); if (document == NULL) { pdoc = new Document(); } else { pdoc = document; } pdoc->AddRef(); // Ensure all positions within document sel.Clear(); targetStart = 0; targetEnd = 0; braces[0] = invalidPosition; braces[1] = invalidPosition; // Reset the contraction state to fully shown. cs.Clear(); cs.InsertLines(0, pdoc->LinesTotal() - 1); SetAnnotationHeights(0, pdoc->LinesTotal()); llc.Deallocate(); NeedWrapping(); pdoc->AddWatcher(this, 0); SetScrollBars(); Redraw(); } void Editor::SetAnnotationVisible(int visible) { if (vs.annotationVisible != visible) { bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0)); vs.annotationVisible = visible; if (changedFromOrToHidden) { int dir = vs.annotationVisible ? 1 : -1; for (int line=0; lineLinesTotal(); line++) { int annotationLines = pdoc->AnnotationLines(line); if (annotationLines > 0) { cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir); } } } Redraw(); } } /** * Recursively expand a fold, making lines visible except where they have an unexpanded parent. */ void Editor::Expand(int &line, bool doExpand) { int lineMaxSubord = pdoc->GetLastChild(line); line++; while (line <= lineMaxSubord) { if (doExpand) cs.SetVisible(line, line, true); int level = pdoc->GetLevel(line); if (level & SC_FOLDLEVELHEADERFLAG) { if (doExpand && cs.GetExpanded(line)) { Expand(line, true); } else { Expand(line, false); } } else { line++; } } } void Editor::ToggleContraction(int line) { if (line >= 0) { if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) { line = pdoc->GetFoldParent(line); if (line < 0) return; } if (cs.GetExpanded(line)) { int lineMaxSubord = pdoc->GetLastChild(line); if (lineMaxSubord > line) { cs.SetExpanded(line, 0); cs.SetVisible(line + 1, lineMaxSubord, false); int lineCurrent = pdoc->LineFromPosition(sel.MainCaret()); if (lineCurrent > line && lineCurrent <= lineMaxSubord) { // This does not re-expand the fold EnsureCaretVisible(); } SetScrollBars(); Redraw(); } } else { if (!(cs.GetVisible(line))) { EnsureLineVisible(line, false); GoToLine(line); } cs.SetExpanded(line, 1); Expand(line, true); SetScrollBars(); Redraw(); } } } int Editor::ContractedFoldNext(int lineStart) { for (int line = lineStart; lineLinesTotal();) { if (!cs.GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG)) return line; line = cs.ContractedNext(line+1); if (line < 0) return -1; } return -1; } /** * Recurse up from this line to find any folds that prevent this line from being visible * and unfold them all. */ void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) { // In case in need of wrapping to ensure DisplayFromDoc works. if (lineDoc >= wrapStart) WrapLines(true, -1); if (!cs.GetVisible(lineDoc)) { int lookLine = lineDoc; int lookLineLevel = pdoc->GetLevel(lookLine); while ((lookLine > 0) && (lookLineLevel & SC_FOLDLEVELWHITEFLAG)) { lookLineLevel = pdoc->GetLevel(--lookLine); } int lineParent = pdoc->GetFoldParent(lookLine); if (lineParent >= 0) { if (lineDoc != lineParent) EnsureLineVisible(lineParent, enforcePolicy); if (!cs.GetExpanded(lineParent)) { cs.SetExpanded(lineParent, 1); Expand(lineParent, true); } } SetScrollBars(); Redraw(); } if (enforcePolicy) { int lineDisplay = cs.DisplayFromDoc(lineDoc); if (visiblePolicy & VISIBLE_SLOP) { if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) { SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } else if ((lineDisplay > topLine + LinesOnScreen() - 1) || ((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) { SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } } else { if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) { SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos())); SetVerticalScrollPos(); Redraw(); } } } } int Editor::GetTag(char *tagValue, int tagNumber) { char name[3] = "\\?"; const char *text = 0; int length = 0; if ((tagNumber >= 1) && (tagNumber <= 9)) { name[1] = static_cast(tagNumber + '0'); length = 2; text = pdoc->SubstituteByPosition(name, &length); } if (tagValue) { if (text) memcpy(tagValue, text, length + 1); else *tagValue = '\0'; } return length; } int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) { UndoGroup ug(pdoc); if (length == -1) length = istrlen(text); if (replacePatterns) { text = pdoc->SubstituteByPosition(text, &length); if (!text) { return 0; } } if (targetStart != targetEnd) pdoc->DeleteChars(targetStart, targetEnd - targetStart); targetEnd = targetStart; pdoc->InsertString(targetStart, text, length); targetEnd = targetStart + length; return length; } bool Editor::IsUnicodeMode() const { return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage); } int Editor::CodePage() const { if (pdoc) return pdoc->dbcsCodePage; else return 0; } int Editor::WrapCount(int line) { AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); if (surface && ll) { LayoutLine(line, surface, vs, ll, wrapWidth); return ll->lines; } else { return 1; } } void Editor::AddStyledText(char *buffer, int appendLength) { // The buffer consists of alternating character bytes and style bytes int textLength = appendLength / 2; char *text = new char[textLength]; int i; for (i = 0; i < textLength; i++) { text[i] = buffer[i*2]; } pdoc->InsertString(CurrentPosition(), text, textLength); for (i = 0; i < textLength; i++) { text[i] = buffer[i*2+1]; } pdoc->StartStyling(CurrentPosition(), static_cast(0xff)); pdoc->SetStyles(textLength, text); delete []text; SetEmptySelection(sel.MainCaret() + textLength); } static bool ValidMargin(unsigned long wParam) { return wParam < ViewStyle::margins; } static char *CharPtrFromSPtr(sptr_t lParam) { return reinterpret_cast(lParam); } void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { vs.EnsureStyle(wParam); switch (iMessage) { case SCI_STYLESETFORE: vs.styles[wParam].fore = ColourDesired(lParam); break; case SCI_STYLESETBACK: vs.styles[wParam].back = ColourDesired(lParam); break; case SCI_STYLESETBOLD: vs.styles[wParam].weight = lParam != 0 ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL; break; case SCI_STYLESETWEIGHT: vs.styles[wParam].weight = lParam; break; case SCI_STYLESETITALIC: vs.styles[wParam].italic = lParam != 0; break; case SCI_STYLESETEOLFILLED: vs.styles[wParam].eolFilled = lParam != 0; break; case SCI_STYLESETSIZE: vs.styles[wParam].size = lParam * SC_FONT_SIZE_MULTIPLIER; break; case SCI_STYLESETSIZEFRACTIONAL: vs.styles[wParam].size = lParam; break; case SCI_STYLESETFONT: if (lParam != 0) { vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam)); } break; case SCI_STYLESETUNDERLINE: vs.styles[wParam].underline = lParam != 0; break; case SCI_STYLESETCASE: vs.styles[wParam].caseForce = static_cast(lParam); break; case SCI_STYLESETCHARACTERSET: vs.styles[wParam].characterSet = lParam; break; case SCI_STYLESETVISIBLE: vs.styles[wParam].visible = lParam != 0; break; case SCI_STYLESETCHANGEABLE: vs.styles[wParam].changeable = lParam != 0; break; case SCI_STYLESETHOTSPOT: vs.styles[wParam].hotspot = lParam != 0; break; } InvalidateStyleRedraw(); } sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { vs.EnsureStyle(wParam); switch (iMessage) { case SCI_STYLEGETFORE: return vs.styles[wParam].fore.AsLong(); case SCI_STYLEGETBACK: return vs.styles[wParam].back.AsLong(); case SCI_STYLEGETBOLD: return vs.styles[wParam].weight > SC_WEIGHT_NORMAL; case SCI_STYLEGETWEIGHT: return vs.styles[wParam].weight; case SCI_STYLEGETITALIC: return vs.styles[wParam].italic ? 1 : 0; case SCI_STYLEGETEOLFILLED: return vs.styles[wParam].eolFilled ? 1 : 0; case SCI_STYLEGETSIZE: return vs.styles[wParam].size / SC_FONT_SIZE_MULTIPLIER; case SCI_STYLEGETSIZEFRACTIONAL: return vs.styles[wParam].size; case SCI_STYLEGETFONT: if (!vs.styles[wParam].fontName) return 0; if (lParam != 0) strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName); return strlen(vs.styles[wParam].fontName); case SCI_STYLEGETUNDERLINE: return vs.styles[wParam].underline ? 1 : 0; case SCI_STYLEGETCASE: return static_cast(vs.styles[wParam].caseForce); case SCI_STYLEGETCHARACTERSET: return vs.styles[wParam].characterSet; case SCI_STYLEGETVISIBLE: return vs.styles[wParam].visible ? 1 : 0; case SCI_STYLEGETCHANGEABLE: return vs.styles[wParam].changeable ? 1 : 0; case SCI_STYLEGETHOTSPOT: return vs.styles[wParam].hotspot ? 1 : 0; } return 0; } sptr_t Editor::StringResult(sptr_t lParam, const char *val) { const size_t n = strlen(val); if (lParam != 0) { char *ptr = reinterpret_cast(lParam); strcpy(ptr, val); } return n; // Not including NUL } sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam); // Optional macro recording hook if (recordingMacro) NotifyMacroRecord(iMessage, wParam, lParam); switch (iMessage) { case SCI_GETTEXT: { if (lParam == 0) return pdoc->Length() + 1; if (wParam == 0) return 0; char *ptr = CharPtrFromSPtr(lParam); unsigned int iChar = 0; for (; iChar < wParam - 1; iChar++) ptr[iChar] = pdoc->CharAt(iChar); ptr[iChar] = '\0'; return iChar; } case SCI_SETTEXT: { if (lParam == 0) return 0; UndoGroup ug(pdoc); pdoc->DeleteChars(0, pdoc->Length()); SetEmptySelection(0); pdoc->InsertCString(0, CharPtrFromSPtr(lParam)); return 1; } case SCI_GETTEXTLENGTH: return pdoc->Length(); case SCI_CUT: Cut(); SetLastXChosen(); break; case SCI_COPY: Copy(); break; case SCI_COPYALLOWLINE: CopyAllowLine(); break; case SCI_VERTICALCENTRECARET: VerticalCentreCaret(); break; case SCI_MOVESELECTEDLINESUP: MoveSelectedLinesUp(); break; case SCI_MOVESELECTEDLINESDOWN: MoveSelectedLinesDown(); break; case SCI_COPYRANGE: CopyRangeToClipboard(wParam, lParam); break; case SCI_COPYTEXT: CopyText(wParam, CharPtrFromSPtr(lParam)); break; case SCI_PASTE: Paste(); if ((caretSticky == SC_CARETSTICKY_OFF) || (caretSticky == SC_CARETSTICKY_WHITESPACE)) { SetLastXChosen(); } EnsureCaretVisible(); break; case SCI_CLEAR: Clear(); SetLastXChosen(); EnsureCaretVisible(); break; case SCI_UNDO: Undo(); SetLastXChosen(); break; case SCI_CANUNDO: return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0; case SCI_EMPTYUNDOBUFFER: pdoc->DeleteUndoHistory(); return 0; case SCI_GETFIRSTVISIBLELINE: return topLine; case SCI_SETFIRSTVISIBLELINE: ScrollTo(wParam); break; case SCI_GETLINE: { // Risk of overwriting the end of the buffer int lineStart = pdoc->LineStart(wParam); int lineEnd = pdoc->LineStart(wParam + 1); if (lParam == 0) { return lineEnd - lineStart; } char *ptr = CharPtrFromSPtr(lParam); int iPlace = 0; for (int iChar = lineStart; iChar < lineEnd; iChar++) { ptr[iPlace++] = pdoc->CharAt(iChar); } return iPlace; } case SCI_GETLINECOUNT: if (pdoc->LinesTotal() == 0) return 1; else return pdoc->LinesTotal(); case SCI_GETMODIFY: return !pdoc->IsSavePoint(); case SCI_SETSEL: { int nStart = static_cast(wParam); int nEnd = static_cast(lParam); if (nEnd < 0) nEnd = pdoc->Length(); if (nStart < 0) nStart = nEnd; // Remove selection InvalidateSelection(SelectionRange(nStart, nEnd)); sel.Clear(); sel.selType = Selection::selStream; SetSelection(nEnd, nStart); EnsureCaretVisible(); } break; case SCI_GETSELTEXT: { SelectionText selectedText; CopySelectionRange(&selectedText); if (lParam == 0) { return selectedText.len ? selectedText.len : 1; } else { char *ptr = CharPtrFromSPtr(lParam); int iChar = 0; if (selectedText.len) { for (; iChar < selectedText.len; iChar++) ptr[iChar] = selectedText.s[iChar]; } else { ptr[0] = '\0'; } return iChar; } } case SCI_LINEFROMPOSITION: if (static_cast(wParam) < 0) return 0; return pdoc->LineFromPosition(wParam); case SCI_POSITIONFROMLINE: if (static_cast(wParam) < 0) wParam = pdoc->LineFromPosition(SelectionStart().Position()); if (wParam == 0) return 0; // Even if there is no text, there is a first line that starts at 0 if (static_cast(wParam) > pdoc->LinesTotal()) return -1; //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway... // return -1; return pdoc->LineStart(wParam); // Replacement of the old Scintilla interpretation of EM_LINELENGTH case SCI_LINELENGTH: if ((static_cast(wParam) < 0) || (static_cast(wParam) > pdoc->LineFromPosition(pdoc->Length()))) return 0; return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam); case SCI_REPLACESEL: { if (lParam == 0) return 0; UndoGroup ug(pdoc); ClearSelection(); char *replacement = CharPtrFromSPtr(lParam); pdoc->InsertCString(sel.MainCaret(), replacement); SetEmptySelection(sel.MainCaret() + istrlen(replacement)); EnsureCaretVisible(); } break; case SCI_SETTARGETSTART: targetStart = wParam; break; case SCI_GETTARGETSTART: return targetStart; case SCI_SETTARGETEND: targetEnd = wParam; break; case SCI_GETTARGETEND: return targetEnd; case SCI_TARGETFROMSELECTION: if (sel.MainCaret() < sel.MainAnchor()) { targetStart = sel.MainCaret(); targetEnd = sel.MainAnchor(); } else { targetStart = sel.MainAnchor(); targetEnd = sel.MainCaret(); } break; case SCI_REPLACETARGET: PLATFORM_ASSERT(lParam); return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam); case SCI_REPLACETARGETRE: PLATFORM_ASSERT(lParam); return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam); case SCI_SEARCHINTARGET: PLATFORM_ASSERT(lParam); return SearchInTarget(CharPtrFromSPtr(lParam), wParam); case SCI_SETSEARCHFLAGS: searchFlags = wParam; break; case SCI_GETSEARCHFLAGS: return searchFlags; case SCI_GETTAG: return GetTag(CharPtrFromSPtr(lParam), wParam); case SCI_POSITIONBEFORE: return pdoc->MovePositionOutsideChar(wParam - 1, -1, true); case SCI_POSITIONAFTER: return pdoc->MovePositionOutsideChar(wParam + 1, 1, true); case SCI_LINESCROLL: ScrollTo(topLine + lParam); HorizontalScrollTo(xOffset + wParam * vs.spaceWidth); return 1; case SCI_SETXOFFSET: xOffset = wParam; ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); SetHorizontalScrollPos(); Redraw(); break; case SCI_GETXOFFSET: return xOffset; case SCI_CHOOSECARETX: SetLastXChosen(); break; case SCI_SCROLLCARET: EnsureCaretVisible(); break; case SCI_SETREADONLY: pdoc->SetReadOnly(wParam != 0); return 1; case SCI_GETREADONLY: return pdoc->IsReadOnly(); case SCI_CANPASTE: return CanPaste(); case SCI_POINTXFROMPOSITION: if (lParam < 0) { return 0; } else { Point pt = LocationFromPosition(lParam); return pt.x; } case SCI_POINTYFROMPOSITION: if (lParam < 0) { return 0; } else { Point pt = LocationFromPosition(lParam); return pt.y; } case SCI_FINDTEXT: return FindText(wParam, lParam); case SCI_GETTEXTRANGE: { if (lParam == 0) return 0; Sci_TextRange *tr = reinterpret_cast(lParam); int cpMax = tr->chrg.cpMax; if (cpMax == -1) cpMax = pdoc->Length(); PLATFORM_ASSERT(cpMax <= pdoc->Length()); int len = cpMax - tr->chrg.cpMin; // No -1 as cpMin and cpMax are referring to inter character positions pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len); // Spec says copied text is terminated with a NUL tr->lpstrText[len] = '\0'; return len; // Not including NUL } case SCI_HIDESELECTION: hideSelection = wParam != 0; Redraw(); break; case SCI_FORMATRANGE: return FormatRange(wParam != 0, reinterpret_cast(lParam)); case SCI_GETMARGINLEFT: return vs.leftMarginWidth; case SCI_GETMARGINRIGHT: return vs.rightMarginWidth; case SCI_SETMARGINLEFT: vs.leftMarginWidth = lParam; InvalidateStyleRedraw(); break; case SCI_SETMARGINRIGHT: vs.rightMarginWidth = lParam; InvalidateStyleRedraw(); break; // Control specific mesages case SCI_ADDTEXT: { if (lParam == 0) return 0; pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam); SetEmptySelection(sel.MainCaret() + wParam); return 0; } case SCI_ADDSTYLEDTEXT: if (lParam) AddStyledText(CharPtrFromSPtr(lParam), wParam); return 0; case SCI_INSERTTEXT: { if (lParam == 0) return 0; int insertPos = wParam; if (static_cast(wParam) == -1) insertPos = CurrentPosition(); int newCurrent = CurrentPosition(); char *sz = CharPtrFromSPtr(lParam); pdoc->InsertCString(insertPos, sz); if (newCurrent > insertPos) newCurrent += istrlen(sz); SetEmptySelection(newCurrent); return 0; } case SCI_APPENDTEXT: pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam); return 0; case SCI_CLEARALL: ClearAll(); return 0; case SCI_DELETERANGE: pdoc->DeleteChars(wParam, lParam); return 0; case SCI_CLEARDOCUMENTSTYLE: ClearDocumentStyle(); return 0; case SCI_SETUNDOCOLLECTION: pdoc->SetUndoCollection(wParam != 0); return 0; case SCI_GETUNDOCOLLECTION: return pdoc->IsCollectingUndo(); case SCI_BEGINUNDOACTION: pdoc->BeginUndoAction(); return 0; case SCI_ENDUNDOACTION: pdoc->EndUndoAction(); return 0; case SCI_GETCARETPERIOD: return caret.period; case SCI_SETCARETPERIOD: caret.period = wParam; break; case SCI_SETWORDCHARS: { pdoc->SetDefaultCharClasses(false); if (lParam == 0) return 0; pdoc->SetCharClasses(reinterpret_cast(lParam), CharClassify::ccWord); } break; case SCI_SETWHITESPACECHARS: { if (lParam == 0) return 0; pdoc->SetCharClasses(reinterpret_cast(lParam), CharClassify::ccSpace); } break; case SCI_SETCHARSDEFAULT: pdoc->SetDefaultCharClasses(true); break; case SCI_GETLENGTH: return pdoc->Length(); case SCI_ALLOCATE: pdoc->Allocate(wParam); break; case SCI_GETCHARAT: return pdoc->CharAt(wParam); case SCI_SETCURRENTPOS: if (sel.IsRectangular()) { sel.Rectangular().caret.SetPosition(wParam); SetRectangularRange(); Redraw(); } else { SetSelection(wParam, sel.MainAnchor()); } break; case SCI_GETCURRENTPOS: return sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret(); case SCI_SETANCHOR: if (sel.IsRectangular()) { sel.Rectangular().anchor.SetPosition(wParam); SetRectangularRange(); Redraw(); } else { SetSelection(sel.MainCaret(), wParam); } break; case SCI_GETANCHOR: return sel.IsRectangular() ? sel.Rectangular().anchor.Position() : sel.MainAnchor(); case SCI_SETSELECTIONSTART: SetSelection(Platform::Maximum(sel.MainCaret(), wParam), wParam); break; case SCI_GETSELECTIONSTART: return sel.LimitsForRectangularElseMain().start.Position(); case SCI_SETSELECTIONEND: SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam)); break; case SCI_GETSELECTIONEND: return sel.LimitsForRectangularElseMain().end.Position(); case SCI_SETEMPTYSELECTION: SetEmptySelection(wParam); break; case SCI_SETPRINTMAGNIFICATION: printMagnification = wParam; break; case SCI_GETPRINTMAGNIFICATION: return printMagnification; case SCI_SETPRINTCOLOURMODE: printColourMode = wParam; break; case SCI_GETPRINTCOLOURMODE: return printColourMode; case SCI_SETPRINTWRAPMODE: printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone; break; case SCI_GETPRINTWRAPMODE: return printWrapState; case SCI_GETSTYLEAT: if (static_cast(wParam) >= pdoc->Length()) return 0; else return pdoc->StyleAt(wParam); case SCI_REDO: Redo(); break; case SCI_SELECTALL: SelectAll(); break; case SCI_SETSAVEPOINT: pdoc->SetSavePoint(); break; case SCI_GETSTYLEDTEXT: { if (lParam == 0) return 0; Sci_TextRange *tr = reinterpret_cast(lParam); int iPlace = 0; for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) { tr->lpstrText[iPlace++] = pdoc->CharAt(iChar); tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar); } tr->lpstrText[iPlace] = '\0'; tr->lpstrText[iPlace + 1] = '\0'; return iPlace; } case SCI_CANREDO: return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0; case SCI_MARKERLINEFROMHANDLE: return pdoc->LineFromHandle(wParam); case SCI_MARKERDELETEHANDLE: pdoc->DeleteMarkFromHandle(wParam); break; case SCI_GETVIEWWS: return vs.viewWhitespace; case SCI_SETVIEWWS: vs.viewWhitespace = static_cast(wParam); Redraw(); break; case SCI_GETWHITESPACESIZE: return vs.whitespaceSize; case SCI_SETWHITESPACESIZE: vs.whitespaceSize = static_cast(wParam); Redraw(); break; case SCI_POSITIONFROMPOINT: return PositionFromLocation(Point(wParam, lParam), false, false); case SCI_POSITIONFROMPOINTCLOSE: return PositionFromLocation(Point(wParam, lParam), true, false); case SCI_CHARPOSITIONFROMPOINT: return PositionFromLocation(Point(wParam, lParam), false, true); case SCI_CHARPOSITIONFROMPOINTCLOSE: return PositionFromLocation(Point(wParam, lParam), true, true); case SCI_GOTOLINE: GoToLine(wParam); break; case SCI_GOTOPOS: SetEmptySelection(wParam); EnsureCaretVisible(); break; case SCI_GETCURLINE: { int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret()); int lineStart = pdoc->LineStart(lineCurrentPos); unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1); if (lParam == 0) { return 1 + lineEnd - lineStart; } PLATFORM_ASSERT(wParam > 0); char *ptr = CharPtrFromSPtr(lParam); unsigned int iPlace = 0; for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) { ptr[iPlace++] = pdoc->CharAt(iChar); } ptr[iPlace] = '\0'; return sel.MainCaret() - lineStart; } case SCI_GETENDSTYLED: return pdoc->GetEndStyled(); case SCI_GETEOLMODE: return pdoc->eolMode; case SCI_SETEOLMODE: pdoc->eolMode = wParam; break; case SCI_STARTSTYLING: pdoc->StartStyling(wParam, static_cast(lParam)); break; case SCI_SETSTYLING: pdoc->SetStyleFor(wParam, static_cast(lParam)); break; case SCI_SETSTYLINGEX: // Specify a complete styling buffer if (lParam == 0) return 0; pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam)); break; case SCI_SETBUFFEREDDRAW: bufferedDraw = wParam != 0; break; case SCI_GETBUFFEREDDRAW: return bufferedDraw; case SCI_GETTWOPHASEDRAW: return twoPhaseDraw; case SCI_SETTWOPHASEDRAW: twoPhaseDraw = wParam != 0; InvalidateStyleRedraw(); break; case SCI_SETFONTQUALITY: vs.extraFontFlag &= ~SC_EFF_QUALITY_MASK; vs.extraFontFlag |= (wParam & SC_EFF_QUALITY_MASK); InvalidateStyleRedraw(); break; case SCI_GETFONTQUALITY: return (vs.extraFontFlag & SC_EFF_QUALITY_MASK); case SCI_SETTABWIDTH: if (wParam > 0) { pdoc->tabInChars = wParam; if (pdoc->indentInChars == 0) pdoc->actualIndentInChars = pdoc->tabInChars; } InvalidateStyleRedraw(); break; case SCI_GETTABWIDTH: return pdoc->tabInChars; case SCI_SETINDENT: pdoc->indentInChars = wParam; if (pdoc->indentInChars != 0) pdoc->actualIndentInChars = pdoc->indentInChars; else pdoc->actualIndentInChars = pdoc->tabInChars; InvalidateStyleRedraw(); break; case SCI_GETINDENT: return pdoc->indentInChars; case SCI_SETUSETABS: pdoc->useTabs = wParam != 0; InvalidateStyleRedraw(); break; case SCI_GETUSETABS: return pdoc->useTabs; case SCI_SETLINEINDENTATION: pdoc->SetLineIndentation(wParam, lParam); break; case SCI_GETLINEINDENTATION: return pdoc->GetLineIndentation(wParam); case SCI_GETLINEINDENTPOSITION: return pdoc->GetLineIndentPosition(wParam); case SCI_SETTABINDENTS: pdoc->tabIndents = wParam != 0; break; case SCI_GETTABINDENTS: return pdoc->tabIndents; case SCI_SETBACKSPACEUNINDENTS: pdoc->backspaceUnindents = wParam != 0; break; case SCI_GETBACKSPACEUNINDENTS: return pdoc->backspaceUnindents; case SCI_SETMOUSEDWELLTIME: dwellDelay = wParam; ticksToDwell = dwellDelay; break; case SCI_GETMOUSEDWELLTIME: return dwellDelay; case SCI_WORDSTARTPOSITION: return pdoc->ExtendWordSelect(wParam, -1, lParam != 0); case SCI_WORDENDPOSITION: return pdoc->ExtendWordSelect(wParam, 1, lParam != 0); case SCI_SETWRAPMODE: switch (wParam) { case SC_WRAP_WORD: wrapState = eWrapWord; break; case SC_WRAP_CHAR: wrapState = eWrapChar; break; default: wrapState = eWrapNone; break; } xOffset = 0; ContainerNeedsUpdate(SC_UPDATE_H_SCROLL); InvalidateStyleRedraw(); ReconfigureScrollBars(); break; case SCI_GETWRAPMODE: return wrapState; case SCI_SETWRAPVISUALFLAGS: if (wrapVisualFlags != static_cast(wParam)) { wrapVisualFlags = wParam; InvalidateStyleRedraw(); ReconfigureScrollBars(); } break; case SCI_GETWRAPVISUALFLAGS: return wrapVisualFlags; case SCI_SETWRAPVISUALFLAGSLOCATION: wrapVisualFlagsLocation = wParam; InvalidateStyleRedraw(); break; case SCI_GETWRAPVISUALFLAGSLOCATION: return wrapVisualFlagsLocation; case SCI_SETWRAPSTARTINDENT: if (wrapVisualStartIndent != static_cast(wParam)) { wrapVisualStartIndent = wParam; InvalidateStyleRedraw(); ReconfigureScrollBars(); } break; case SCI_GETWRAPSTARTINDENT: return wrapVisualStartIndent; case SCI_SETWRAPINDENTMODE: if (wrapIndentMode != static_cast(wParam)) { wrapIndentMode = wParam; InvalidateStyleRedraw(); ReconfigureScrollBars(); } break; case SCI_GETWRAPINDENTMODE: return wrapIndentMode; case SCI_SETLAYOUTCACHE: llc.SetLevel(wParam); break; case SCI_GETLAYOUTCACHE: return llc.GetLevel(); case SCI_SETPOSITIONCACHE: posCache.SetSize(wParam); break; case SCI_GETPOSITIONCACHE: return posCache.GetSize(); case SCI_SETSCROLLWIDTH: PLATFORM_ASSERT(wParam > 0); if ((wParam > 0) && (wParam != static_cast(scrollWidth))) { lineWidthMaxSeen = 0; scrollWidth = wParam; SetScrollBars(); } break; case SCI_GETSCROLLWIDTH: return scrollWidth; case SCI_SETSCROLLWIDTHTRACKING: trackLineWidth = wParam != 0; break; case SCI_GETSCROLLWIDTHTRACKING: return trackLineWidth; case SCI_LINESJOIN: LinesJoin(); break; case SCI_LINESSPLIT: LinesSplit(wParam); break; case SCI_TEXTWIDTH: PLATFORM_ASSERT(wParam < vs.stylesSize); PLATFORM_ASSERT(lParam); return TextWidth(wParam, CharPtrFromSPtr(lParam)); case SCI_TEXTHEIGHT: return vs.lineHeight; case SCI_SETENDATLASTLINE: PLATFORM_ASSERT((wParam == 0) || (wParam == 1)); if (endAtLastLine != (wParam != 0)) { endAtLastLine = wParam != 0; SetScrollBars(); } break; case SCI_GETENDATLASTLINE: return endAtLastLine; case SCI_SETCARETSTICKY: PLATFORM_ASSERT(wParam <= SC_CARETSTICKY_WHITESPACE); if (wParam <= SC_CARETSTICKY_WHITESPACE) { caretSticky = wParam; } break; case SCI_GETCARETSTICKY: return caretSticky; case SCI_TOGGLECARETSTICKY: caretSticky = !caretSticky; break; case SCI_GETCOLUMN: return pdoc->GetColumn(wParam); case SCI_FINDCOLUMN: return pdoc->FindColumn(wParam, lParam); case SCI_SETHSCROLLBAR : if (horizontalScrollBarVisible != (wParam != 0)) { horizontalScrollBarVisible = wParam != 0; SetScrollBars(); ReconfigureScrollBars(); } break; case SCI_GETHSCROLLBAR: return horizontalScrollBarVisible; case SCI_SETVSCROLLBAR: if (verticalScrollBarVisible != (wParam != 0)) { verticalScrollBarVisible = wParam != 0; SetScrollBars(); ReconfigureScrollBars(); } break; case SCI_GETVSCROLLBAR: return verticalScrollBarVisible; case SCI_SETINDENTATIONGUIDES: vs.viewIndentationGuides = IndentView(wParam); Redraw(); break; case SCI_GETINDENTATIONGUIDES: return vs.viewIndentationGuides; case SCI_SETHIGHLIGHTGUIDE: if ((highlightGuideColumn != static_cast(wParam)) || (wParam > 0)) { highlightGuideColumn = wParam; Redraw(); } break; case SCI_GETHIGHLIGHTGUIDE: return highlightGuideColumn; case SCI_GETLINEENDPOSITION: return pdoc->LineEnd(wParam); case SCI_SETCODEPAGE: if (ValidCodePage(wParam)) { pdoc->dbcsCodePage = wParam; InvalidateStyleRedraw(); } break; case SCI_GETCODEPAGE: return pdoc->dbcsCodePage; #ifdef INCLUDE_DEPRECATED_FEATURES case SCI_SETUSEPALETTE: InvalidateStyleRedraw(); break; case SCI_GETUSEPALETTE: return 0; #endif // Marker definition and setting case SCI_MARKERDEFINE: if (wParam <= MARKER_MAX) { vs.markers[wParam].markType = lParam; vs.CalcLargestMarkerHeight(); } InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERSYMBOLDEFINED: if (wParam <= MARKER_MAX) return vs.markers[wParam].markType; else return 0; case SCI_MARKERSETFORE: if (wParam <= MARKER_MAX) vs.markers[wParam].fore = ColourDesired(lParam); InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERSETBACKSELECTED: if (wParam <= MARKER_MAX) vs.markers[wParam].backSelected = ColourDesired(lParam); InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERENABLEHIGHLIGHT: highlightDelimiter.isEnabled = wParam == 1; RedrawSelMargin(); break; case SCI_MARKERSETBACK: if (wParam <= MARKER_MAX) vs.markers[wParam].back = ColourDesired(lParam); InvalidateStyleData(); RedrawSelMargin(); break; case SCI_MARKERSETALPHA: if (wParam <= MARKER_MAX) vs.markers[wParam].alpha = lParam; InvalidateStyleRedraw(); break; case SCI_MARKERADD: { int markerID = pdoc->AddMark(wParam, lParam); return markerID; } case SCI_MARKERADDSET: if (lParam != 0) pdoc->AddMarkSet(wParam, lParam); break; case SCI_MARKERDELETE: pdoc->DeleteMark(wParam, lParam); break; case SCI_MARKERDELETEALL: pdoc->DeleteAllMarks(static_cast(wParam)); break; case SCI_MARKERGET: return pdoc->GetMark(wParam); case SCI_MARKERNEXT: return pdoc->MarkerNext(wParam, lParam); case SCI_MARKERPREVIOUS: { for (int iLine = wParam; iLine >= 0; iLine--) { if ((pdoc->GetMark(iLine) & lParam) != 0) return iLine; } } return -1; case SCI_MARKERDEFINEPIXMAP: if (wParam <= MARKER_MAX) { vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam)); vs.CalcLargestMarkerHeight(); }; InvalidateStyleData(); RedrawSelMargin(); break; case SCI_RGBAIMAGESETWIDTH: sizeRGBAImage.x = wParam; break; case SCI_RGBAIMAGESETHEIGHT: sizeRGBAImage.y = wParam; break; case SCI_MARKERDEFINERGBAIMAGE: if (wParam <= MARKER_MAX) { vs.markers[wParam].SetRGBAImage(sizeRGBAImage, reinterpret_cast(lParam)); vs.CalcLargestMarkerHeight(); }; InvalidateStyleData(); RedrawSelMargin(); break; case SCI_SETMARGINTYPEN: if (ValidMargin(wParam)) { vs.ms[wParam].style = lParam; InvalidateStyleRedraw(); } break; case SCI_GETMARGINTYPEN: if (ValidMargin(wParam)) return vs.ms[wParam].style; else return 0; case SCI_SETMARGINWIDTHN: if (ValidMargin(wParam)) { // Short-circuit if the width is unchanged, to avoid unnecessary redraw. if (vs.ms[wParam].width != lParam) { vs.ms[wParam].width = lParam; InvalidateStyleRedraw(); } } break; case SCI_GETMARGINWIDTHN: if (ValidMargin(wParam)) return vs.ms[wParam].width; else return 0; case SCI_SETMARGINMASKN: if (ValidMargin(wParam)) { vs.ms[wParam].mask = lParam; InvalidateStyleRedraw(); } break; case SCI_GETMARGINMASKN: if (ValidMargin(wParam)) return vs.ms[wParam].mask; else return 0; case SCI_SETMARGINSENSITIVEN: if (ValidMargin(wParam)) { vs.ms[wParam].sensitive = lParam != 0; InvalidateStyleRedraw(); } break; case SCI_GETMARGINSENSITIVEN: if (ValidMargin(wParam)) return vs.ms[wParam].sensitive ? 1 : 0; else return 0; case SCI_SETMARGINCURSORN: if (ValidMargin(wParam)) vs.ms[wParam].cursor = lParam; break; case SCI_GETMARGINCURSORN: if (ValidMargin(wParam)) return vs.ms[wParam].cursor; else return 0; case SCI_STYLECLEARALL: vs.ClearStyles(); InvalidateStyleRedraw(); break; case SCI_STYLESETFORE: case SCI_STYLESETBACK: case SCI_STYLESETBOLD: case SCI_STYLESETWEIGHT: case SCI_STYLESETITALIC: case SCI_STYLESETEOLFILLED: case SCI_STYLESETSIZE: case SCI_STYLESETSIZEFRACTIONAL: case SCI_STYLESETFONT: case SCI_STYLESETUNDERLINE: case SCI_STYLESETCASE: case SCI_STYLESETCHARACTERSET: case SCI_STYLESETVISIBLE: case SCI_STYLESETCHANGEABLE: case SCI_STYLESETHOTSPOT: StyleSetMessage(iMessage, wParam, lParam); break; case SCI_STYLEGETFORE: case SCI_STYLEGETBACK: case SCI_STYLEGETBOLD: case SCI_STYLEGETWEIGHT: case SCI_STYLEGETITALIC: case SCI_STYLEGETEOLFILLED: case SCI_STYLEGETSIZE: case SCI_STYLEGETSIZEFRACTIONAL: case SCI_STYLEGETFONT: case SCI_STYLEGETUNDERLINE: case SCI_STYLEGETCASE: case SCI_STYLEGETCHARACTERSET: case SCI_STYLEGETVISIBLE: case SCI_STYLEGETCHANGEABLE: case SCI_STYLEGETHOTSPOT: return StyleGetMessage(iMessage, wParam, lParam); case SCI_STYLERESETDEFAULT: vs.ResetDefaultStyle(); InvalidateStyleRedraw(); break; case SCI_SETSTYLEBITS: vs.EnsureStyle((1 << wParam) - 1); pdoc->SetStylingBits(wParam); break; case SCI_GETSTYLEBITS: return pdoc->stylingBits; case SCI_SETLINESTATE: return pdoc->SetLineState(wParam, lParam); case SCI_GETLINESTATE: return pdoc->GetLineState(wParam); case SCI_GETMAXLINESTATE: return pdoc->GetMaxLineState(); case SCI_GETCARETLINEVISIBLE: return vs.showCaretLineBackground; case SCI_SETCARETLINEVISIBLE: vs.showCaretLineBackground = wParam != 0; InvalidateStyleRedraw(); break; case SCI_GETCARETLINEBACK: return vs.caretLineBackground.AsLong(); case SCI_SETCARETLINEBACK: vs.caretLineBackground = wParam; InvalidateStyleRedraw(); break; case SCI_GETCARETLINEBACKALPHA: return vs.caretLineAlpha; case SCI_SETCARETLINEBACKALPHA: vs.caretLineAlpha = wParam; InvalidateStyleRedraw(); break; // Folding messages case SCI_VISIBLEFROMDOCLINE: return cs.DisplayFromDoc(wParam); case SCI_DOCLINEFROMVISIBLE: return cs.DocFromDisplay(wParam); case SCI_WRAPCOUNT: return WrapCount(wParam); case SCI_SETFOLDLEVEL: { int prev = pdoc->SetLevel(wParam, lParam); if (prev != lParam) RedrawSelMargin(); return prev; } case SCI_GETFOLDLEVEL: return pdoc->GetLevel(wParam); case SCI_GETLASTCHILD: return pdoc->GetLastChild(wParam, lParam); case SCI_GETFOLDPARENT: return pdoc->GetFoldParent(wParam); case SCI_SHOWLINES: cs.SetVisible(wParam, lParam, true); SetScrollBars(); Redraw(); break; case SCI_HIDELINES: if (wParam > 0) cs.SetVisible(wParam, lParam, false); SetScrollBars(); Redraw(); break; case SCI_GETLINEVISIBLE: return cs.GetVisible(wParam); case SCI_GETALLLINESVISIBLE: return cs.HiddenLines() ? 0 : 1; case SCI_SETFOLDEXPANDED: if (cs.SetExpanded(wParam, lParam != 0)) { RedrawSelMargin(); } break; case SCI_GETFOLDEXPANDED: return cs.GetExpanded(wParam); case SCI_SETFOLDFLAGS: foldFlags = wParam; Redraw(); break; case SCI_TOGGLEFOLD: ToggleContraction(wParam); break; case SCI_CONTRACTEDFOLDNEXT: return ContractedFoldNext(wParam); case SCI_ENSUREVISIBLE: EnsureLineVisible(wParam, false); break; case SCI_ENSUREVISIBLEENFORCEPOLICY: EnsureLineVisible(wParam, true); break; case SCI_SEARCHANCHOR: SearchAnchor(); break; case SCI_SEARCHNEXT: case SCI_SEARCHPREV: return SearchText(iMessage, wParam, lParam); case SCI_SETXCARETPOLICY: caretXPolicy = wParam; caretXSlop = lParam; break; case SCI_SETYCARETPOLICY: caretYPolicy = wParam; caretYSlop = lParam; break; case SCI_SETVISIBLEPOLICY: visiblePolicy = wParam; visibleSlop = lParam; break; case SCI_LINESONSCREEN: return LinesOnScreen(); case SCI_SETSELFORE: vs.selforeset = wParam != 0; vs.selforeground = ColourDesired(lParam); vs.selAdditionalForeground = ColourDesired(lParam); InvalidateStyleRedraw(); break; case SCI_SETSELBACK: vs.selbackset = wParam != 0; vs.selbackground = ColourDesired(lParam); vs.selAdditionalBackground = ColourDesired(lParam); InvalidateStyleRedraw(); break; case SCI_SETSELALPHA: vs.selAlpha = wParam; vs.selAdditionalAlpha = wParam; InvalidateStyleRedraw(); break; case SCI_GETSELALPHA: return vs.selAlpha; case SCI_GETSELEOLFILLED: return vs.selEOLFilled; case SCI_SETSELEOLFILLED: vs.selEOLFilled = wParam != 0; InvalidateStyleRedraw(); break; case SCI_SETWHITESPACEFORE: vs.whitespaceForegroundSet = wParam != 0; vs.whitespaceForeground = ColourDesired(lParam); InvalidateStyleRedraw(); break; case SCI_SETWHITESPACEBACK: vs.whitespaceBackgroundSet = wParam != 0; vs.whitespaceBackground = ColourDesired(lParam); InvalidateStyleRedraw(); break; case SCI_SETCARETFORE: vs.caretcolour = ColourDesired(wParam); InvalidateStyleRedraw(); break; case SCI_GETCARETFORE: return vs.caretcolour.AsLong(); case SCI_SETCARETSTYLE: if (wParam <= CARETSTYLE_BLOCK) vs.caretStyle = wParam; else /* Default to the line caret */ vs.caretStyle = CARETSTYLE_LINE; InvalidateStyleRedraw(); break; case SCI_GETCARETSTYLE: return vs.caretStyle; case SCI_SETCARETWIDTH: if (static_cast(wParam) <= 0) vs.caretWidth = 0; else if (wParam >= 3) vs.caretWidth = 3; else vs.caretWidth = wParam; InvalidateStyleRedraw(); break; case SCI_GETCARETWIDTH: return vs.caretWidth; case SCI_ASSIGNCMDKEY: kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), Platform::HighShortFromLong(wParam), lParam); break; case SCI_CLEARCMDKEY: kmap.AssignCmdKey(Platform::LowShortFromLong(wParam), Platform::HighShortFromLong(wParam), SCI_NULL); break; case SCI_CLEARALLCMDKEYS: kmap.Clear(); break; case SCI_INDICSETSTYLE: if (wParam <= INDIC_MAX) { vs.indicators[wParam].style = lParam; InvalidateStyleRedraw(); } break; case SCI_INDICGETSTYLE: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0; case SCI_INDICSETFORE: if (wParam <= INDIC_MAX) { vs.indicators[wParam].fore = ColourDesired(lParam); InvalidateStyleRedraw(); } break; case SCI_INDICGETFORE: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.AsLong() : 0; case SCI_INDICSETUNDER: if (wParam <= INDIC_MAX) { vs.indicators[wParam].under = lParam != 0; InvalidateStyleRedraw(); } break; case SCI_INDICGETUNDER: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0; case SCI_INDICSETALPHA: if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { vs.indicators[wParam].fillAlpha = lParam; InvalidateStyleRedraw(); } break; case SCI_INDICGETALPHA: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0; case SCI_INDICSETOUTLINEALPHA: if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 255) { vs.indicators[wParam].outlineAlpha = lParam; InvalidateStyleRedraw(); } break; case SCI_INDICGETOUTLINEALPHA: return (wParam <= INDIC_MAX) ? vs.indicators[wParam].outlineAlpha : 0; case SCI_SETINDICATORCURRENT: pdoc->decorations.SetCurrentIndicator(wParam); break; case SCI_GETINDICATORCURRENT: return pdoc->decorations.GetCurrentIndicator(); case SCI_SETINDICATORVALUE: pdoc->decorations.SetCurrentValue(wParam); break; case SCI_GETINDICATORVALUE: return pdoc->decorations.GetCurrentValue(); case SCI_INDICATORFILLRANGE: pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam); break; case SCI_INDICATORCLEARRANGE: pdoc->DecorationFillRange(wParam, 0, lParam); break; case SCI_INDICATORALLONFOR: return pdoc->decorations.AllOnFor(wParam); case SCI_INDICATORVALUEAT: return pdoc->decorations.ValueAt(wParam, lParam); case SCI_INDICATORSTART: return pdoc->decorations.Start(wParam, lParam); case SCI_INDICATOREND: return pdoc->decorations.End(wParam, lParam); case SCI_LINEDOWN: case SCI_LINEDOWNEXTEND: case SCI_PARADOWN: case SCI_PARADOWNEXTEND: case SCI_LINEUP: case SCI_LINEUPEXTEND: case SCI_PARAUP: case SCI_PARAUPEXTEND: case SCI_CHARLEFT: case SCI_CHARLEFTEXTEND: case SCI_CHARRIGHT: case SCI_CHARRIGHTEXTEND: case SCI_WORDLEFT: case SCI_WORDLEFTEXTEND: case SCI_WORDRIGHT: case SCI_WORDRIGHTEXTEND: case SCI_WORDLEFTEND: case SCI_WORDLEFTENDEXTEND: case SCI_WORDRIGHTEND: case SCI_WORDRIGHTENDEXTEND: case SCI_HOME: case SCI_HOMEEXTEND: case SCI_LINEEND: case SCI_LINEENDEXTEND: case SCI_HOMEWRAP: case SCI_HOMEWRAPEXTEND: case SCI_LINEENDWRAP: case SCI_LINEENDWRAPEXTEND: case SCI_DOCUMENTSTART: case SCI_DOCUMENTSTARTEXTEND: case SCI_DOCUMENTEND: case SCI_DOCUMENTENDEXTEND: case SCI_SCROLLTOSTART: case SCI_SCROLLTOEND: case SCI_STUTTEREDPAGEUP: case SCI_STUTTEREDPAGEUPEXTEND: case SCI_STUTTEREDPAGEDOWN: case SCI_STUTTEREDPAGEDOWNEXTEND: case SCI_PAGEUP: case SCI_PAGEUPEXTEND: case SCI_PAGEDOWN: case SCI_PAGEDOWNEXTEND: case SCI_EDITTOGGLEOVERTYPE: case SCI_CANCEL: case SCI_DELETEBACK: case SCI_TAB: case SCI_BACKTAB: case SCI_NEWLINE: case SCI_FORMFEED: case SCI_VCHOME: case SCI_VCHOMEEXTEND: case SCI_VCHOMEWRAP: case SCI_VCHOMEWRAPEXTEND: case SCI_ZOOMIN: case SCI_ZOOMOUT: case SCI_DELWORDLEFT: case SCI_DELWORDRIGHT: case SCI_DELWORDRIGHTEND: case SCI_DELLINELEFT: case SCI_DELLINERIGHT: case SCI_LINECOPY: case SCI_LINECUT: case SCI_LINEDELETE: case SCI_LINETRANSPOSE: case SCI_LINEDUPLICATE: case SCI_LOWERCASE: case SCI_UPPERCASE: case SCI_LINESCROLLDOWN: case SCI_LINESCROLLUP: case SCI_WORDPARTLEFT: case SCI_WORDPARTLEFTEXTEND: case SCI_WORDPARTRIGHT: case SCI_WORDPARTRIGHTEXTEND: case SCI_DELETEBACKNOTLINE: case SCI_HOMEDISPLAY: case SCI_HOMEDISPLAYEXTEND: case SCI_LINEENDDISPLAY: case SCI_LINEENDDISPLAYEXTEND: case SCI_LINEDOWNRECTEXTEND: case SCI_LINEUPRECTEXTEND: case SCI_CHARLEFTRECTEXTEND: case SCI_CHARRIGHTRECTEXTEND: case SCI_HOMERECTEXTEND: case SCI_VCHOMERECTEXTEND: case SCI_LINEENDRECTEXTEND: case SCI_PAGEUPRECTEXTEND: case SCI_PAGEDOWNRECTEXTEND: case SCI_SELECTIONDUPLICATE: return KeyCommand(iMessage); case SCI_BRACEHIGHLIGHT: SetBraceHighlight(static_cast(wParam), lParam, STYLE_BRACELIGHT); break; case SCI_BRACEHIGHLIGHTINDICATOR: if (lParam >= 0 && lParam <= INDIC_MAX) { vs.braceHighlightIndicatorSet = wParam != 0; vs.braceHighlightIndicator = lParam; } break; case SCI_BRACEBADLIGHT: SetBraceHighlight(static_cast(wParam), -1, STYLE_BRACEBAD); break; case SCI_BRACEBADLIGHTINDICATOR: if (lParam >= 0 && lParam <= INDIC_MAX) { vs.braceBadLightIndicatorSet = wParam != 0; vs.braceBadLightIndicator = lParam; } break; case SCI_BRACEMATCH: // wParam is position of char to find brace for, // lParam is maximum amount of text to restyle to find it return pdoc->BraceMatch(wParam, lParam); case SCI_GETVIEWEOL: return vs.viewEOL; case SCI_SETVIEWEOL: vs.viewEOL = wParam != 0; InvalidateStyleRedraw(); break; case SCI_SETZOOM: vs.zoomLevel = wParam; InvalidateStyleRedraw(); NotifyZoom(); break; case SCI_GETZOOM: return vs.zoomLevel; case SCI_GETEDGECOLUMN: return theEdge; case SCI_SETEDGECOLUMN: theEdge = wParam; InvalidateStyleRedraw(); break; case SCI_GETEDGEMODE: return vs.edgeState; case SCI_SETEDGEMODE: vs.edgeState = wParam; InvalidateStyleRedraw(); break; case SCI_GETEDGECOLOUR: return vs.edgecolour.AsLong(); case SCI_SETEDGECOLOUR: vs.edgecolour = ColourDesired(wParam); InvalidateStyleRedraw(); break; case SCI_GETDOCPOINTER: return reinterpret_cast(pdoc); case SCI_SETDOCPOINTER: CancelModes(); SetDocPointer(reinterpret_cast(lParam)); return 0; case SCI_CREATEDOCUMENT: { Document *doc = new Document(); if (doc) { doc->AddRef(); } return reinterpret_cast(doc); } case SCI_ADDREFDOCUMENT: (reinterpret_cast(lParam))->AddRef(); break; case SCI_RELEASEDOCUMENT: (reinterpret_cast(lParam))->Release(); break; case SCI_CREATELOADER: { Document *doc = new Document(); if (doc) { doc->AddRef(); doc->Allocate(wParam); doc->SetUndoCollection(false); } return reinterpret_cast(static_cast(doc)); } case SCI_SETMODEVENTMASK: modEventMask = wParam; return 0; case SCI_GETMODEVENTMASK: return modEventMask; case SCI_CONVERTEOLS: pdoc->ConvertLineEnds(wParam); SetSelection(sel.MainCaret(), sel.MainAnchor()); // Ensure selection inside document return 0; case SCI_SETLENGTHFORENCODE: lengthForEncode = wParam; return 0; case SCI_SELECTIONISRECTANGLE: return sel.selType == Selection::selRectangle ? 1 : 0; case SCI_SETSELECTIONMODE: { switch (wParam) { case SC_SEL_STREAM: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); sel.selType = Selection::selStream; break; case SC_SEL_RECTANGLE: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle)); sel.selType = Selection::selRectangle; break; case SC_SEL_LINES: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines)); sel.selType = Selection::selLines; break; case SC_SEL_THIN: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin)); sel.selType = Selection::selThin; break; default: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); sel.selType = Selection::selStream; } InvalidateSelection(sel.RangeMain(), true); } case SCI_GETSELECTIONMODE: switch (sel.selType) { case Selection::selStream: return SC_SEL_STREAM; case Selection::selRectangle: return SC_SEL_RECTANGLE; case Selection::selLines: return SC_SEL_LINES; case Selection::selThin: return SC_SEL_THIN; default: // ?! return SC_SEL_STREAM; } case SCI_GETLINESELSTARTPOSITION: case SCI_GETLINESELENDPOSITION: { SelectionSegment segmentLine(SelectionPosition(pdoc->LineStart(wParam)), SelectionPosition(pdoc->LineEnd(wParam))); for (size_t r=0; r(pdoc->BufferPointer()); case SCI_GETRANGEPOINTER: return reinterpret_cast(pdoc->RangePointer(wParam, lParam)); case SCI_GETGAPPOSITION: return pdoc->GapPosition(); case SCI_SETEXTRAASCENT: vs.extraAscent = wParam; InvalidateStyleRedraw(); break; case SCI_GETEXTRAASCENT: return vs.extraAscent; case SCI_SETEXTRADESCENT: vs.extraDescent = wParam; InvalidateStyleRedraw(); break; case SCI_GETEXTRADESCENT: return vs.extraDescent; case SCI_MARGINSETSTYLEOFFSET: vs.marginStyleOffset = wParam; InvalidateStyleRedraw(); break; case SCI_MARGINGETSTYLEOFFSET: return vs.marginStyleOffset; case SCI_SETMARGINOPTIONS: marginOptions = wParam; break; case SCI_GETMARGINOPTIONS: return marginOptions; case SCI_MARGINSETTEXT: pdoc->MarginSetText(wParam, CharPtrFromSPtr(lParam)); break; case SCI_MARGINGETTEXT: { const StyledText st = pdoc->MarginStyledText(wParam); if (lParam) { if (st.text) memcpy(CharPtrFromSPtr(lParam), st.text, st.length); else strcpy(CharPtrFromSPtr(lParam), ""); } return st.length; } case SCI_MARGINSETSTYLE: pdoc->MarginSetStyle(wParam, lParam); break; case SCI_MARGINGETSTYLE: { const StyledText st = pdoc->MarginStyledText(wParam); return st.style; } case SCI_MARGINSETSTYLES: pdoc->MarginSetStyles(wParam, reinterpret_cast(lParam)); break; case SCI_MARGINGETSTYLES: { const StyledText st = pdoc->MarginStyledText(wParam); if (lParam) { if (st.styles) memcpy(CharPtrFromSPtr(lParam), st.styles, st.length); else strcpy(CharPtrFromSPtr(lParam), ""); } return st.styles ? st.length : 0; } case SCI_MARGINTEXTCLEARALL: pdoc->MarginClearAll(); break; case SCI_ANNOTATIONSETTEXT: pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam)); break; case SCI_ANNOTATIONGETTEXT: { const StyledText st = pdoc->AnnotationStyledText(wParam); if (lParam) { if (st.text) memcpy(CharPtrFromSPtr(lParam), st.text, st.length); else strcpy(CharPtrFromSPtr(lParam), ""); } return st.length; } case SCI_ANNOTATIONGETSTYLE: { const StyledText st = pdoc->AnnotationStyledText(wParam); return st.style; } case SCI_ANNOTATIONSETSTYLE: pdoc->AnnotationSetStyle(wParam, lParam); break; case SCI_ANNOTATIONSETSTYLES: pdoc->AnnotationSetStyles(wParam, reinterpret_cast(lParam)); break; case SCI_ANNOTATIONGETSTYLES: { const StyledText st = pdoc->AnnotationStyledText(wParam); if (lParam) { if (st.styles) memcpy(CharPtrFromSPtr(lParam), st.styles, st.length); else strcpy(CharPtrFromSPtr(lParam), ""); } return st.styles ? st.length : 0; } case SCI_ANNOTATIONGETLINES: return pdoc->AnnotationLines(wParam); case SCI_ANNOTATIONCLEARALL: pdoc->AnnotationClearAll(); break; case SCI_ANNOTATIONSETVISIBLE: SetAnnotationVisible(wParam); break; case SCI_ANNOTATIONGETVISIBLE: return vs.annotationVisible; case SCI_ANNOTATIONSETSTYLEOFFSET: vs.annotationStyleOffset = wParam; InvalidateStyleRedraw(); break; case SCI_ANNOTATIONGETSTYLEOFFSET: return vs.annotationStyleOffset; case SCI_ADDUNDOACTION: pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE); break; case SCI_SETMULTIPLESELECTION: multipleSelection = wParam != 0; InvalidateCaret(); break; case SCI_GETMULTIPLESELECTION: return multipleSelection; case SCI_SETADDITIONALSELECTIONTYPING: additionalSelectionTyping = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALSELECTIONTYPING: return additionalSelectionTyping; case SCI_SETMULTIPASTE: multiPasteMode = wParam; break; case SCI_GETMULTIPASTE: return multiPasteMode; case SCI_SETADDITIONALCARETSBLINK: additionalCaretsBlink = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALCARETSBLINK: return additionalCaretsBlink; case SCI_SETADDITIONALCARETSVISIBLE: additionalCaretsVisible = wParam != 0; InvalidateCaret(); break; case SCI_GETADDITIONALCARETSVISIBLE: return additionalCaretsVisible; case SCI_GETSELECTIONS: return sel.Count(); case SCI_CLEARSELECTIONS: sel.Clear(); Redraw(); break; case SCI_SETSELECTION: sel.SetSelection(SelectionRange(wParam, lParam)); Redraw(); break; case SCI_ADDSELECTION: sel.AddSelection(SelectionRange(wParam, lParam)); Redraw(); break; case SCI_SETMAINSELECTION: sel.SetMain(wParam); Redraw(); break; case SCI_GETMAINSELECTION: return sel.Main(); case SCI_SETSELECTIONNCARET: sel.Range(wParam).caret.SetPosition(lParam); Redraw(); break; case SCI_GETSELECTIONNCARET: return sel.Range(wParam).caret.Position(); case SCI_SETSELECTIONNANCHOR: sel.Range(wParam).anchor.SetPosition(lParam); Redraw(); break; case SCI_GETSELECTIONNANCHOR: return sel.Range(wParam).anchor.Position(); case SCI_SETSELECTIONNCARETVIRTUALSPACE: sel.Range(wParam).caret.SetVirtualSpace(lParam); Redraw(); break; case SCI_GETSELECTIONNCARETVIRTUALSPACE: return sel.Range(wParam).caret.VirtualSpace(); case SCI_SETSELECTIONNANCHORVIRTUALSPACE: sel.Range(wParam).anchor.SetVirtualSpace(lParam); Redraw(); break; case SCI_GETSELECTIONNANCHORVIRTUALSPACE: return sel.Range(wParam).anchor.VirtualSpace(); case SCI_SETSELECTIONNSTART: sel.Range(wParam).anchor.SetPosition(lParam); Redraw(); break; case SCI_GETSELECTIONNSTART: return sel.Range(wParam).Start().Position(); case SCI_SETSELECTIONNEND: sel.Range(wParam).caret.SetPosition(lParam); Redraw(); break; case SCI_GETSELECTIONNEND: return sel.Range(wParam).End().Position(); case SCI_SETRECTANGULARSELECTIONCARET: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().caret.SetPosition(wParam); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONCARET: return sel.Rectangular().caret.Position(); case SCI_SETRECTANGULARSELECTIONANCHOR: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().anchor.SetPosition(wParam); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONANCHOR: return sel.Rectangular().anchor.Position(); case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().caret.SetVirtualSpace(wParam); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE: return sel.Rectangular().caret.VirtualSpace(); case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE: if (!sel.IsRectangular()) sel.Clear(); sel.selType = Selection::selRectangle; sel.Rectangular().anchor.SetVirtualSpace(wParam); SetRectangularRange(); Redraw(); break; case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE: return sel.Rectangular().anchor.VirtualSpace(); case SCI_SETVIRTUALSPACEOPTIONS: virtualSpaceOptions = wParam; break; case SCI_GETVIRTUALSPACEOPTIONS: return virtualSpaceOptions; case SCI_SETADDITIONALSELFORE: vs.selAdditionalForeground = ColourDesired(wParam); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELBACK: vs.selAdditionalBackground = ColourDesired(wParam); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELALPHA: vs.selAdditionalAlpha = wParam; InvalidateStyleRedraw(); break; case SCI_GETADDITIONALSELALPHA: return vs.selAdditionalAlpha; case SCI_SETADDITIONALCARETFORE: vs.additionalCaretColour = ColourDesired(wParam); InvalidateStyleRedraw(); break; case SCI_GETADDITIONALCARETFORE: return vs.additionalCaretColour.AsLong(); case SCI_ROTATESELECTION: sel.RotateMain(); InvalidateSelection(sel.RangeMain(), true); break; case SCI_SWAPMAINANCHORCARET: InvalidateSelection(sel.RangeMain()); sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret); break; case SCI_CHANGELEXERSTATE: pdoc->ChangeLexerState(wParam, lParam); break; case SCI_SETIDENTIFIER: SetCtrlID(wParam); break; case SCI_GETIDENTIFIER: return GetCtrlID(); case SCI_SETTECHNOLOGY: // No action by default break; case SCI_GETTECHNOLOGY: return technology; case SCI_COUNTCHARACTERS: return pdoc->CountCharacters(wParam, lParam); default: return DefWndProc(iMessage, wParam, lParam); } //Platform::DebugPrintf("end wnd proc\n"); return 0l; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/CellBuffer.cxx0000644000175000017500000004364711763437013021176 00000000000000// Scintilla source code edit control /** @file CellBuffer.cxx ** Manages a buffer of cells. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "CellBuffer.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif LineVector::LineVector() : starts(256), perLine(0) { Init(); } LineVector::~LineVector() { starts.DeleteAll(); } void LineVector::Init() { starts.DeleteAll(); if (perLine) { perLine->Init(); } } void LineVector::SetPerLine(PerLine *pl) { perLine = pl; } void LineVector::InsertText(int line, int delta) { starts.InsertText(line, delta); } void LineVector::InsertLine(int line, int position, bool lineStart) { starts.InsertPartition(line, position); if (perLine) { if ((line > 0) && lineStart) line--; perLine->InsertLine(line); } } void LineVector::SetLineStart(int line, int position) { starts.SetPartitionStartPosition(line, position); } void LineVector::RemoveLine(int line) { starts.RemovePartition(line); if (perLine) { perLine->RemoveLine(line); } } int LineVector::LineFromPosition(int pos) const { return starts.PartitionFromPosition(pos); } Action::Action() { at = startAction; position = 0; data = 0; lenData = 0; mayCoalesce = false; } Action::~Action() { Destroy(); } void Action::Create(actionType at_, int position_, char *data_, int lenData_, bool mayCoalesce_) { delete []data; position = position_; at = at_; data = data_; lenData = lenData_; mayCoalesce = mayCoalesce_; } void Action::Destroy() { delete []data; data = 0; } void Action::Grab(Action *source) { delete []data; position = source->position; at = source->at; data = source->data; lenData = source->lenData; mayCoalesce = source->mayCoalesce; // Ownership of source data transferred to this source->position = 0; source->at = startAction; source->data = 0; source->lenData = 0; source->mayCoalesce = true; } // The undo history stores a sequence of user operations that represent the user's view of the // commands executed on the text. // Each user operation contains a sequence of text insertion and text deletion actions. // All the user operations are stored in a list of individual actions with 'start' actions used // as delimiters between user operations. // Initially there is one start action in the history. // As each action is performed, it is recorded in the history. The action may either become // part of the current user operation or may start a new user operation. If it is to be part of the // current operation, then it overwrites the current last action. If it is to be part of a new // operation, it is appended after the current last action. // After writing the new action, a new start action is appended at the end of the history. // The decision of whether to start a new user operation is based upon two factors. If a // compound operation has been explicitly started by calling BeginUndoAction and no matching // EndUndoAction (these calls nest) has been called, then the action is coalesced into the current // operation. If there is no outstanding BeginUndoAction call then a new operation is started // unless it looks as if the new action is caused by the user typing or deleting a stream of text. // Sequences that look like typing or deletion are coalesced into a single user operation. UndoHistory::UndoHistory() { lenActions = 100; actions = new Action[lenActions]; maxAction = 0; currentAction = 0; undoSequenceDepth = 0; savePoint = 0; actions[currentAction].Create(startAction); } UndoHistory::~UndoHistory() { delete []actions; actions = 0; } void UndoHistory::EnsureUndoRoom() { // Have to test that there is room for 2 more actions in the array // as two actions may be created by the calling function if (currentAction >= (lenActions - 2)) { // Run out of undo nodes so extend the array int lenActionsNew = lenActions * 2; Action *actionsNew = new Action[lenActionsNew]; for (int act = 0; act <= currentAction; act++) actionsNew[act].Grab(&actions[act]); delete []actions; lenActions = lenActionsNew; actions = actionsNew; } } void UndoHistory::AppendAction(actionType at, int position, char *data, int lengthData, bool &startSequence, bool mayCoalesce) { EnsureUndoRoom(); //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction); //Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at, // actions[currentAction - 1].position, actions[currentAction - 1].lenData); if (currentAction < savePoint) { savePoint = -1; } int oldCurrentAction = currentAction; if (currentAction >= 1) { if (0 == undoSequenceDepth) { // Top level actions may not always be coalesced int targetAct = -1; const Action *actPrevious = &(actions[currentAction + targetAct]); // Container actions may forward the coalesce state of Scintilla Actions. while ((actPrevious->at == containerAction) && actPrevious->mayCoalesce) { targetAct--; actPrevious = &(actions[currentAction + targetAct]); } // See if current action can be coalesced into previous action // Will work if both are inserts or deletes and position is same if (currentAction == savePoint) { currentAction++; } else if (!actions[currentAction].mayCoalesce) { // Not allowed to coalesce if this set currentAction++; } else if (!mayCoalesce || !actPrevious->mayCoalesce) { currentAction++; } else if (at == containerAction || actions[currentAction].at == containerAction) { ; // A coalescible containerAction } else if ((at != actPrevious->at) && (actPrevious->at != startAction)) { currentAction++; } else if ((at == insertAction) && (position != (actPrevious->position + actPrevious->lenData))) { // Insertions must be immediately after to coalesce currentAction++; } else if (at == removeAction) { if ((lengthData == 1) || (lengthData == 2)) { if ((position + lengthData) == actPrevious->position) { ; // Backspace -> OK } else if (position == actPrevious->position) { ; // Delete -> OK } else { // Removals must be at same position to coalesce currentAction++; } } else { // Removals must be of one character to coalesce currentAction++; } } else { // Action coalesced. } } else { // Actions not at top level are always coalesced unless this is after return to top level if (!actions[currentAction].mayCoalesce) currentAction++; } } else { currentAction++; } startSequence = oldCurrentAction != currentAction; actions[currentAction].Create(at, position, data, lengthData, mayCoalesce); currentAction++; actions[currentAction].Create(startAction); maxAction = currentAction; } void UndoHistory::BeginUndoAction() { EnsureUndoRoom(); if (undoSequenceDepth == 0) { if (actions[currentAction].at != startAction) { currentAction++; actions[currentAction].Create(startAction); maxAction = currentAction; } actions[currentAction].mayCoalesce = false; } undoSequenceDepth++; } void UndoHistory::EndUndoAction() { PLATFORM_ASSERT(undoSequenceDepth > 0); EnsureUndoRoom(); undoSequenceDepth--; if (0 == undoSequenceDepth) { if (actions[currentAction].at != startAction) { currentAction++; actions[currentAction].Create(startAction); maxAction = currentAction; } actions[currentAction].mayCoalesce = false; } } void UndoHistory::DropUndoSequence() { undoSequenceDepth = 0; } void UndoHistory::DeleteUndoHistory() { for (int i = 1; i < maxAction; i++) actions[i].Destroy(); maxAction = 0; currentAction = 0; actions[currentAction].Create(startAction); savePoint = 0; } void UndoHistory::SetSavePoint() { savePoint = currentAction; } bool UndoHistory::IsSavePoint() const { return savePoint == currentAction; } bool UndoHistory::CanUndo() const { return (currentAction > 0) && (maxAction > 0); } int UndoHistory::StartUndo() { // Drop any trailing startAction if (actions[currentAction].at == startAction && currentAction > 0) currentAction--; // Count the steps in this action int act = currentAction; while (actions[act].at != startAction && act > 0) { act--; } return currentAction - act; } const Action &UndoHistory::GetUndoStep() const { return actions[currentAction]; } void UndoHistory::CompletedUndoStep() { currentAction--; } bool UndoHistory::CanRedo() const { return maxAction > currentAction; } int UndoHistory::StartRedo() { // Drop any leading startAction if (actions[currentAction].at == startAction && currentAction < maxAction) currentAction++; // Count the steps in this action int act = currentAction; while (actions[act].at != startAction && act < maxAction) { act++; } return act - currentAction; } const Action &UndoHistory::GetRedoStep() const { return actions[currentAction]; } void UndoHistory::CompletedRedoStep() { currentAction++; } CellBuffer::CellBuffer() { readOnly = false; collectingUndo = true; } CellBuffer::~CellBuffer() { } char CellBuffer::CharAt(int position) const { return substance.ValueAt(position); } void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) const { if (lengthRetrieve < 0) return; if (position < 0) return; if ((position + lengthRetrieve) > substance.Length()) { Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n", position, lengthRetrieve, substance.Length()); return; } substance.GetRange(buffer, position, lengthRetrieve); } char CellBuffer::StyleAt(int position) const { return style.ValueAt(position); } void CellBuffer::GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const { if (lengthRetrieve < 0) return; if (position < 0) return; if ((position + lengthRetrieve) > style.Length()) { Platform::DebugPrintf("Bad GetStyleRange %d for %d of %d\n", position, lengthRetrieve, style.Length()); return; } style.GetRange(reinterpret_cast(buffer), position, lengthRetrieve); } const char *CellBuffer::BufferPointer() { return substance.BufferPointer(); } const char *CellBuffer::RangePointer(int position, int rangeLength) { return substance.RangePointer(position, rangeLength); } int CellBuffer::GapPosition() const { return substance.GapPosition(); } // The char* returned is to an allocation owned by the undo history const char *CellBuffer::InsertString(int position, const char *s, int insertLength, bool &startSequence) { char *data = 0; // InsertString and DeleteChars are the bottleneck though which all changes occur if (!readOnly) { if (collectingUndo) { // Save into the undo/redo stack, but only the characters - not the formatting // This takes up about half load time data = new char[insertLength]; for (int i = 0; i < insertLength; i++) { data[i] = s[i]; } uh.AppendAction(insertAction, position, data, insertLength, startSequence); } BasicInsertString(position, s, insertLength); } return data; } bool CellBuffer::SetStyleAt(int position, char styleValue, char mask) { styleValue &= mask; char curVal = style.ValueAt(position); if ((curVal & mask) != styleValue) { style.SetValueAt(position, static_cast((curVal & ~mask) | styleValue)); return true; } else { return false; } } bool CellBuffer::SetStyleFor(int position, int lengthStyle, char styleValue, char mask) { bool changed = false; PLATFORM_ASSERT(lengthStyle == 0 || (lengthStyle > 0 && lengthStyle + position <= style.Length())); while (lengthStyle--) { char curVal = style.ValueAt(position); if ((curVal & mask) != styleValue) { style.SetValueAt(position, static_cast((curVal & ~mask) | styleValue)); changed = true; } position++; } return changed; } // The char* returned is to an allocation owned by the undo history const char *CellBuffer::DeleteChars(int position, int deleteLength, bool &startSequence) { // InsertString and DeleteChars are the bottleneck though which all changes occur PLATFORM_ASSERT(deleteLength > 0); char *data = 0; if (!readOnly) { if (collectingUndo) { // Save into the undo/redo stack, but only the characters - not the formatting data = new char[deleteLength]; for (int i = 0; i < deleteLength; i++) { data[i] = substance.ValueAt(position + i); } uh.AppendAction(removeAction, position, data, deleteLength, startSequence); } BasicDeleteChars(position, deleteLength); } return data; } int CellBuffer::Length() const { return substance.Length(); } void CellBuffer::Allocate(int newSize) { substance.ReAllocate(newSize); style.ReAllocate(newSize); } void CellBuffer::SetPerLine(PerLine *pl) { lv.SetPerLine(pl); } int CellBuffer::Lines() const { return lv.Lines(); } int CellBuffer::LineStart(int line) const { if (line < 0) return 0; else if (line >= Lines()) return Length(); else return lv.LineStart(line); } bool CellBuffer::IsReadOnly() const { return readOnly; } void CellBuffer::SetReadOnly(bool set) { readOnly = set; } void CellBuffer::SetSavePoint() { uh.SetSavePoint(); } bool CellBuffer::IsSavePoint() { return uh.IsSavePoint(); } // Without undo void CellBuffer::InsertLine(int line, int position, bool lineStart) { lv.InsertLine(line, position, lineStart); } void CellBuffer::RemoveLine(int line) { lv.RemoveLine(line); } void CellBuffer::BasicInsertString(int position, const char *s, int insertLength) { if (insertLength == 0) return; PLATFORM_ASSERT(insertLength > 0); substance.InsertFromArray(position, s, 0, insertLength); style.InsertValue(position, insertLength, 0); int lineInsert = lv.LineFromPosition(position) + 1; bool atLineStart = lv.LineStart(lineInsert-1) == position; // Point all the lines after the insertion point further along in the buffer lv.InsertText(lineInsert-1, insertLength); char chPrev = substance.ValueAt(position - 1); char chAfter = substance.ValueAt(position + insertLength); if (chPrev == '\r' && chAfter == '\n') { // Splitting up a crlf pair at position InsertLine(lineInsert, position, false); lineInsert++; } char ch = ' '; for (int i = 0; i < insertLength; i++) { ch = s[i]; if (ch == '\r') { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } else if (ch == '\n') { if (chPrev == '\r') { // Patch up what was end of line lv.SetLineStart(lineInsert - 1, (position + i) + 1); } else { InsertLine(lineInsert, (position + i) + 1, atLineStart); lineInsert++; } } chPrev = ch; } // Joining two lines where last insertion is cr and following substance starts with lf if (chAfter == '\n') { if (ch == '\r') { // End of line already in buffer so drop the newly created one RemoveLine(lineInsert - 1); } } } void CellBuffer::BasicDeleteChars(int position, int deleteLength) { if (deleteLength == 0) return; if ((position == 0) && (deleteLength == substance.Length())) { // If whole buffer is being deleted, faster to reinitialise lines data // than to delete each line. lv.Init(); } else { // Have to fix up line positions before doing deletion as looking at text in buffer // to work out which lines have been removed int lineRemove = lv.LineFromPosition(position) + 1; lv.InsertText(lineRemove-1, - (deleteLength)); char chPrev = substance.ValueAt(position - 1); char chBefore = chPrev; char chNext = substance.ValueAt(position); bool ignoreNL = false; if (chPrev == '\r' && chNext == '\n') { // Move back one lv.SetLineStart(lineRemove, position); lineRemove++; ignoreNL = true; // First \n is not real deletion } char ch = chNext; for (int i = 0; i < deleteLength; i++) { chNext = substance.ValueAt(position + i + 1); if (ch == '\r') { if (chNext != '\n') { RemoveLine(lineRemove); } } else if (ch == '\n') { if (ignoreNL) { ignoreNL = false; // Further \n are real deletions } else { RemoveLine(lineRemove); } } ch = chNext; } // May have to fix up end if last deletion causes cr to be next to lf // or removes one of a crlf pair char chAfter = substance.ValueAt(position + deleteLength); if (chBefore == '\r' && chAfter == '\n') { // Using lineRemove-1 as cr ended line before start of deletion RemoveLine(lineRemove - 1); lv.SetLineStart(lineRemove - 1, position + 1); } } substance.DeleteRange(position, deleteLength); style.DeleteRange(position, deleteLength); } bool CellBuffer::SetUndoCollection(bool collectUndo) { collectingUndo = collectUndo; uh.DropUndoSequence(); return collectingUndo; } bool CellBuffer::IsCollectingUndo() const { return collectingUndo; } void CellBuffer::BeginUndoAction() { uh.BeginUndoAction(); } void CellBuffer::EndUndoAction() { uh.EndUndoAction(); } void CellBuffer::AddUndoAction(int token, bool mayCoalesce) { bool startSequence; uh.AppendAction(containerAction, token, 0, 0, startSequence, mayCoalesce); } void CellBuffer::DeleteUndoHistory() { uh.DeleteUndoHistory(); } bool CellBuffer::CanUndo() { return uh.CanUndo(); } int CellBuffer::StartUndo() { return uh.StartUndo(); } const Action &CellBuffer::GetUndoStep() const { return uh.GetUndoStep(); } void CellBuffer::PerformUndoStep() { const Action &actionStep = uh.GetUndoStep(); if (actionStep.at == insertAction) { BasicDeleteChars(actionStep.position, actionStep.lenData); } else if (actionStep.at == removeAction) { BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData); } uh.CompletedUndoStep(); } bool CellBuffer::CanRedo() { return uh.CanRedo(); } int CellBuffer::StartRedo() { return uh.StartRedo(); } const Action &CellBuffer::GetRedoStep() const { return uh.GetRedoStep(); } void CellBuffer::PerformRedoStep() { const Action &actionStep = uh.GetRedoStep(); if (actionStep.at == insertAction) { BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData); } else if (actionStep.at == removeAction) { BasicDeleteChars(actionStep.position, actionStep.lenData); } uh.CompletedRedoStep(); } presage-0.8.8/apps/gtk/gprompter/scintilla/src/RunStyles.cxx0000644000175000017500000001440611615412040021111 00000000000000/** @file RunStyles.cxx ** Data structure used to store sparse styles. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Find the first run at a position int RunStyles::RunFromPosition(int position) const { int run = starts->PartitionFromPosition(position); // Go to first element with this position while ((run > 0) && (position == starts->PositionFromPartition(run-1))) { run--; } return run; } // If there is no run boundary at position, insert one continuing style. int RunStyles::SplitRun(int position) { int run = RunFromPosition(position); int posRun = starts->PositionFromPartition(run); if (posRun < position) { int runStyle = ValueAt(position); run++; starts->InsertPartition(run, position); styles->InsertValue(run, 1, runStyle); } return run; } void RunStyles::RemoveRun(int run) { starts->RemovePartition(run); styles->DeleteRange(run, 1); } void RunStyles::RemoveRunIfEmpty(int run) { if ((run < starts->Partitions()) && (starts->Partitions() > 1)) { if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) { RemoveRun(run); } } } void RunStyles::RemoveRunIfSameAsPrevious(int run) { if ((run > 0) && (run < starts->Partitions())) { if (styles->ValueAt(run-1) == styles->ValueAt(run)) { RemoveRun(run); } } } RunStyles::RunStyles() { starts = new Partitioning(8); styles = new SplitVector(); styles->InsertValue(0, 2, 0); } RunStyles::~RunStyles() { delete starts; starts = NULL; delete styles; styles = NULL; } int RunStyles::Length() const { return starts->PositionFromPartition(starts->Partitions()); } int RunStyles::ValueAt(int position) const { return styles->ValueAt(starts->PartitionFromPosition(position)); } int RunStyles::FindNextChange(int position, int end) { int run = starts->PartitionFromPosition(position); if (run < starts->Partitions()) { int runChange = starts->PositionFromPartition(run); if (runChange > position) return runChange; int nextChange = starts->PositionFromPartition(run + 1); if (nextChange > position) { return nextChange; } else if (position < end) { return end; } else { return end + 1; } } else { return end + 1; } } int RunStyles::StartRun(int position) { return starts->PositionFromPartition(starts->PartitionFromPosition(position)); } int RunStyles::EndRun(int position) { return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1); } bool RunStyles::FillRange(int &position, int value, int &fillLength) { int end = position + fillLength; int runEnd = RunFromPosition(end); if (styles->ValueAt(runEnd) == value) { // End already has value so trim range. end = starts->PositionFromPartition(runEnd); if (position >= end) { // Whole range is already same as value so no action return false; } fillLength = end - position; } else { runEnd = SplitRun(end); } int runStart = RunFromPosition(position); if (styles->ValueAt(runStart) == value) { // Start is in expected value so trim range. runStart++; position = starts->PositionFromPartition(runStart); fillLength = end - position; } else { if (starts->PositionFromPartition(runStart) < position) { runStart = SplitRun(position); runEnd++; } } if (runStart < runEnd) { styles->SetValueAt(runStart, value); // Remove each old run over the range for (int run=runStart+1; runPositionFromPartition(runStart) == position) { int runStyle = ValueAt(position); // Inserting at start of run so make previous longer if (runStart == 0) { // Inserting at start of document so ensure 0 if (runStyle) { styles->SetValueAt(0, 0); starts->InsertPartition(1, 0); styles->InsertValue(1, 1, runStyle); starts->InsertText(0, insertLength); } else { starts->InsertText(runStart, insertLength); } } else { if (runStyle) { starts->InsertText(runStart-1, insertLength); } else { // Insert at end of run so do not extend style starts->InsertText(runStart, insertLength); } } } else { starts->InsertText(runStart, insertLength); } } void RunStyles::DeleteAll() { delete starts; starts = NULL; delete styles; styles = NULL; starts = new Partitioning(8); styles = new SplitVector(); styles->InsertValue(0, 2, 0); } void RunStyles::DeleteRange(int position, int deleteLength) { int end = position + deleteLength; int runStart = RunFromPosition(position); int runEnd = RunFromPosition(end); if (runStart == runEnd) { // Deleting from inside one run starts->InsertText(runStart, -deleteLength); } else { runStart = SplitRun(position); runEnd = SplitRun(end); starts->InsertText(runStart, -deleteLength); // Remove each old run over the range for (int run=runStart; runPartitions(); } bool RunStyles::AllSame() const { for (int run = 1; run < starts->Partitions(); run++) { if (styles->ValueAt(run) != styles->ValueAt(run - 1)) return false; } return true; } bool RunStyles::AllSameAs(int value) const { return AllSame() && (styles->ValueAt(0) == value); } int RunStyles::Find(int value, int start) const { if (start < Length()) { int run = start ? RunFromPosition(start) : 0; if (styles->ValueAt(run) == value) return start; run++; while (run < starts->Partitions()) { if (styles->ValueAt(run) == value) return starts->PositionFromPartition(run); run++; } } return -1; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/CallTip.cxx0000644000175000017500000002514411652104216020476 00000000000000// Scintilla source code edit control /** @file CallTip.cxx ** Code for displaying call tips. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "Platform.h" #include "Scintilla.h" #include "CallTip.h" #include #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static const int insetX = 5; // text inset in x from calltip border static const int widthArrow = 14; CallTip::CallTip() { wCallTip = 0; inCallTipMode = false; posStartCallTip = 0; val = 0; rectUp = PRectangle(0,0,0,0); rectDown = PRectangle(0,0,0,0); lineHeight = 1; offsetMain = 0; startHighlight = 0; endHighlight = 0; tabSize = 0; above = false; useStyleCallTip = false; // for backwards compatibility #ifdef __APPLE__ // proper apple colours for the default colourBG = ColourDesired(0xff, 0xff, 0xc6); colourUnSel = ColourDesired(0, 0, 0); #else colourBG = ColourDesired(0xff, 0xff, 0xff); colourUnSel = ColourDesired(0x80, 0x80, 0x80); #endif colourSel = ColourDesired(0, 0, 0x80); colourShade = ColourDesired(0, 0, 0); colourLight = ColourDesired(0xc0, 0xc0, 0xc0); codePage = 0; clickPlace = 0; } CallTip::~CallTip() { font.Release(); wCallTip.Destroy(); delete []val; val = 0; } // Although this test includes 0, we should never see a \0 character. static bool IsArrowCharacter(char ch) { return (ch == 0) || (ch == '\001') || (ch == '\002'); } // We ignore tabs unless a tab width has been set. bool CallTip::IsTabCharacter(char ch) const { return (tabSize > 0) && (ch == '\t'); } int CallTip::NextTabPos(int x) { if (tabSize > 0) { // paranoia... not called unless this is true x -= insetX; // position relative to text x = (x + tabSize) / tabSize; // tab "number" return tabSize*x + insetX; // position of next tab } else { return x + 1; // arbitrary } } // Draw a section of the call tip that does not include \n in one colour. // The text may include up to numEnds tabs or arrow characters. void CallTip::DrawChunk(Surface *surface, int &x, const char *s, int posStart, int posEnd, int ytext, PRectangle rcClient, bool highlight, bool draw) { s += posStart; int len = posEnd - posStart; // Divide the text into sections that are all text, or that are // single arrows or single tab characters (if tabSize > 0). int maxEnd = 0; const int numEnds = 10; int ends[numEnds + 2]; for (int i=0; i 0) ends[maxEnd++] = i; ends[maxEnd++] = i+1; } } ends[maxEnd++] = len; int startSeg = 0; int xEnd; for (int seg = 0; seg startSeg) { if (IsArrowCharacter(s[startSeg])) { bool upArrow = s[startSeg] == '\001'; rcClient.left = x; rcClient.right = rcClient.left + widthArrow; if (draw) { const int halfWidth = widthArrow / 2 - 3; const int centreX = rcClient.left + widthArrow / 2 - 1; const int centreY = (rcClient.top + rcClient.bottom) / 2; surface->FillRectangle(rcClient, colourBG); PRectangle rcClientInner(rcClient.left + 1, rcClient.top + 1, rcClient.right - 2, rcClient.bottom - 1); surface->FillRectangle(rcClientInner, colourUnSel); if (upArrow) { // Up arrow Point pts[] = { Point(centreX - halfWidth, centreY + halfWidth / 2), Point(centreX + halfWidth, centreY + halfWidth / 2), Point(centreX, centreY - halfWidth + halfWidth / 2), }; surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), colourBG, colourBG); } else { // Down arrow Point pts[] = { Point(centreX - halfWidth, centreY - halfWidth / 2), Point(centreX + halfWidth, centreY - halfWidth / 2), Point(centreX, centreY + halfWidth - halfWidth / 2), }; surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]), colourBG, colourBG); } } xEnd = rcClient.right; offsetMain = xEnd; if (upArrow) { rectUp = rcClient; } else { rectDown = rcClient; } } else if (IsTabCharacter(s[startSeg])) { xEnd = NextTabPos(x); } else { xEnd = x + surface->WidthText(font, s + startSeg, endSeg - startSeg); if (draw) { rcClient.left = x; rcClient.right = xEnd; surface->DrawTextTransparent(rcClient, font, ytext, s+startSeg, endSeg - startSeg, highlight ? colourSel : colourUnSel); } } x = xEnd; startSeg = endSeg; } } } int CallTip::PaintContents(Surface *surfaceWindow, bool draw) { PRectangle rcClientPos = wCallTip.GetClientPosition(); PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left, rcClientPos.bottom - rcClientPos.top); PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1); // To make a nice small call tip window, it is only sized to fit most normal characters without accents int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font); // For each line... // Draw the definition in three parts: before highlight, highlighted, after highlight int ytext = rcClient.top + ascent + 1; rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1; char *chunkVal = val; bool moreChunks = true; int maxWidth = 0; while (moreChunks) { char *chunkEnd = strchr(chunkVal, '\n'); if (chunkEnd == NULL) { chunkEnd = chunkVal + strlen(chunkVal); moreChunks = false; } int chunkOffset = chunkVal - val; int chunkLength = chunkEnd - chunkVal; int chunkEndOffset = chunkOffset + chunkLength; int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset); thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset); thisStartHighlight -= chunkOffset; int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset); thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset); thisEndHighlight -= chunkOffset; rcClient.top = ytext - ascent - 1; int x = insetX; // start each line at this inset DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight, ytext, rcClient, false, draw); DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight, ytext, rcClient, true, draw); DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength, ytext, rcClient, false, draw); chunkVal = chunkEnd + 1; ytext += lineHeight; rcClient.bottom += lineHeight; maxWidth = Platform::Maximum(maxWidth, x); } return maxWidth; } void CallTip::PaintCT(Surface *surfaceWindow) { if (!val) return; PRectangle rcClientPos = wCallTip.GetClientPosition(); PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left, rcClientPos.bottom - rcClientPos.top); PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1); surfaceWindow->FillRectangle(rcClient, colourBG); offsetMain = insetX; // initial alignment assuming no arrows PaintContents(surfaceWindow, true); #ifndef __APPLE__ // OSX doesn't put borders on "help tags" // Draw a raised border around the edges of the window surfaceWindow->MoveTo(0, rcClientSize.bottom - 1); surfaceWindow->PenColour(colourShade); surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1); surfaceWindow->LineTo(rcClientSize.right - 1, 0); surfaceWindow->PenColour(colourLight); surfaceWindow->LineTo(0, 0); surfaceWindow->LineTo(0, rcClientSize.bottom - 1); #endif } void CallTip::MouseClick(Point pt) { clickPlace = 0; if (rectUp.Contains(pt)) clickPlace = 1; if (rectDown.Contains(pt)) clickPlace = 2; } PRectangle CallTip::CallTipStart(int pos, Point pt, int textHeight, const char *defn, const char *faceName, int size, int codePage_, int characterSet, int technology, Window &wParent) { clickPlace = 0; delete []val; val = 0; val = new char[strlen(defn) + 1]; strcpy(val, defn); codePage = codePage_; Surface *surfaceMeasure = Surface::Allocate(technology); if (!surfaceMeasure) return PRectangle(); surfaceMeasure->Init(wParent.GetID()); surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage); surfaceMeasure->SetDBCSMode(codePage); startHighlight = 0; endHighlight = 0; inCallTipMode = true; posStartCallTip = pos; int deviceHeight = surfaceMeasure->DeviceHeightFont(size); FontParameters fp(faceName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, SC_WEIGHT_NORMAL, false, 0, technology, characterSet); font.Create(fp); // Look for multiple lines in the text // Only support \n here - simply means container must avoid \r! int numLines = 1; const char *newline; const char *look = val; rectUp = PRectangle(0,0,0,0); rectDown = PRectangle(0,0,0,0); offsetMain = insetX; // changed to right edge of any arrows int width = PaintContents(surfaceMeasure, false) + insetX; while ((newline = strchr(look, '\n')) != NULL) { look = newline + 1; numLines++; } lineHeight = surfaceMeasure->Height(font); // Extra line for border and an empty line at top and bottom. The returned // rectangle is aligned to the right edge of the last arrow encountered in // the tip text, else to the tip text left edge. int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2; delete surfaceMeasure; if (above) { return PRectangle(pt.x - offsetMain, pt.y - 1 - height, pt.x + width - offsetMain, pt.y - 1); } else { return PRectangle(pt.x - offsetMain, pt.y + 1 + textHeight, pt.x + width - offsetMain, pt.y + 1 + textHeight + height); } } void CallTip::CallTipCancel() { inCallTipMode = false; if (wCallTip.Created()) { wCallTip.Destroy(); } } void CallTip::SetHighlight(int start, int end) { // Avoid flashing by checking something has really changed if ((start != startHighlight) || (end != endHighlight)) { startHighlight = start; endHighlight = end; if (wCallTip.Created()) { wCallTip.InvalidateAll(); } } } // Set the tab size (sizes > 0 enable the use of tabs). This also enables the // use of the STYLE_CALLTIP. void CallTip::SetTabSize(int tabSz) { tabSize = tabSz; useStyleCallTip = true; } // Set the calltip position, below the text by default or if above is false // else above the text. void CallTip::SetPosition(bool aboveText) { above = aboveText; } // It might be better to have two access functions for this and to use // them for all settings of colours. void CallTip::SetForeBack(const ColourDesired &fore, const ColourDesired &back) { colourBG = back; colourUnSel = fore; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Document.cxx0000644000175000017500000020022211763437013020723 00000000000000// Scintilla source code edit control /** @file Document.cxx ** Text document that handles notifications, DBCS, styling, words and end of line. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "CellBuffer.h" #include "PerLine.h" #include "CharClassify.h" #include "CharacterSet.h" #include "Decoration.h" #include "Document.h" #include "RESearch.h" #include "UniConversion.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // This is ASCII specific but is safe with chars >= 0x80 static inline bool isspacechar(unsigned char ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); } static inline bool IsPunctuation(char ch) { return isascii(ch) && ispunct(ch); } static inline bool IsADigit(char ch) { return isascii(ch) && isdigit(ch); } static inline bool IsLowerCase(char ch) { return isascii(ch) && islower(ch); } static inline bool IsUpperCase(char ch) { return isascii(ch) && isupper(ch); } void LexInterface::Colourise(int start, int end) { if (pdoc && instance && !performingStyle) { // Protect against reentrance, which may occur, for example, when // fold points are discovered while performing styling and the folding // code looks for child lines which may trigger styling. performingStyle = true; int lengthDoc = pdoc->Length(); if (end == -1) end = lengthDoc; int len = end - start; PLATFORM_ASSERT(len >= 0); PLATFORM_ASSERT(start + len <= lengthDoc); int styleStart = 0; if (start > 0) styleStart = pdoc->StyleAt(start - 1) & pdoc->stylingBitsMask; if (len > 0) { instance->Lex(start, len, styleStart, pdoc); instance->Fold(start, len, styleStart, pdoc); } performingStyle = false; } } Document::Document() { refCount = 0; #ifdef _WIN32 eolMode = SC_EOL_CRLF; #else eolMode = SC_EOL_LF; #endif dbcsCodePage = 0; stylingBits = 5; stylingBitsMask = 0x1F; stylingMask = 0; endStyled = 0; styleClock = 0; enteredModification = 0; enteredStyling = 0; enteredReadOnlyCount = 0; tabInChars = 8; indentInChars = 0; actualIndentInChars = 8; useTabs = true; tabIndents = true; backspaceUnindents = false; watchers = 0; lenWatchers = 0; matchesValid = false; regex = 0; UTF8BytesOfLeadInitialise(); perLineData[ldMarkers] = new LineMarkers(); perLineData[ldLevels] = new LineLevels(); perLineData[ldState] = new LineState(); perLineData[ldMargin] = new LineAnnotation(); perLineData[ldAnnotation] = new LineAnnotation(); cb.SetPerLine(this); pli = 0; } Document::~Document() { for (int i = 0; i < lenWatchers; i++) { watchers[i].watcher->NotifyDeleted(this, watchers[i].userData); } delete []watchers; for (int j=0; jInit(); } } void Document::InsertLine(int line) { for (int j=0; jInsertLine(line); } } void Document::RemoveLine(int line) { for (int j=0; jRemoveLine(line); } } // Increase reference count and return its previous value. int Document::AddRef() { return refCount++; } // Decrease reference count and return its previous value. // Delete the document if reference count reaches zero. int SCI_METHOD Document::Release() { int curRefCount = --refCount; if (curRefCount == 0) delete this; return curRefCount; } void Document::SetSavePoint() { cb.SetSavePoint(); NotifySavePoint(true); } int Document::GetMark(int line) { return static_cast(perLineData[ldMarkers])->MarkValue(line); } int Document::MarkerNext(int lineStart, int mask) const { return static_cast(perLineData[ldMarkers])->MarkerNext(lineStart, mask); } int Document::AddMark(int line, int markerNum) { if (line >= 0 && line <= LinesTotal()) { int prev = static_cast(perLineData[ldMarkers])-> AddMark(line, markerNum, LinesTotal()); DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); NotifyModified(mh); return prev; } else { return 0; } } void Document::AddMarkSet(int line, int valueSet) { if (line < 0 || line > LinesTotal()) { return; } unsigned int m = valueSet; for (int i = 0; m; i++, m >>= 1) if (m & 1) static_cast(perLineData[ldMarkers])-> AddMark(line, i, LinesTotal()); DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::DeleteMark(int line, int markerNum) { static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, false); DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::DeleteMarkFromHandle(int markerHandle) { static_cast(perLineData[ldMarkers])->DeleteMarkFromHandle(markerHandle); DocModification mh(SC_MOD_CHANGEMARKER, 0, 0, 0, 0); mh.line = -1; NotifyModified(mh); } void Document::DeleteAllMarks(int markerNum) { bool someChanges = false; for (int line = 0; line < LinesTotal(); line++) { if (static_cast(perLineData[ldMarkers])->DeleteMark(line, markerNum, true)) someChanges = true; } if (someChanges) { DocModification mh(SC_MOD_CHANGEMARKER, 0, 0, 0, 0); mh.line = -1; NotifyModified(mh); } } int Document::LineFromHandle(int markerHandle) { return static_cast(perLineData[ldMarkers])->LineFromHandle(markerHandle); } int SCI_METHOD Document::LineStart(int line) const { return cb.LineStart(line); } int Document::LineEnd(int line) const { if (line == LinesTotal() - 1) { return LineStart(line + 1); } else { int position = LineStart(line + 1) - 1; // When line terminator is CR+LF, may need to go back one more if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) { position--; } return position; } } void SCI_METHOD Document::SetErrorStatus(int status) { // Tell the watchers the lexer has changed. for (int i = 0; i < lenWatchers; i++) { watchers[i].watcher->NotifyErrorOccurred(this, watchers[i].userData, status); } } int SCI_METHOD Document::LineFromPosition(int pos) const { return cb.LineFromPosition(pos); } int Document::LineEndPosition(int position) const { return LineEnd(LineFromPosition(position)); } bool Document::IsLineEndPosition(int position) const { return LineEnd(LineFromPosition(position)) == position; } int Document::VCHomePosition(int position) const { int line = LineFromPosition(position); int startPosition = LineStart(line); int endLine = LineEnd(line); int startText = startPosition; while (startText < endLine && (cb.CharAt(startText) == ' ' || cb.CharAt(startText) == '\t')) startText++; if (position == startText) return startPosition; else return startText; } int SCI_METHOD Document::SetLevel(int line, int level) { int prev = static_cast(perLineData[ldLevels])->SetLevel(line, level, LinesTotal()); if (prev != level) { DocModification mh(SC_MOD_CHANGEFOLD | SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line); mh.foldLevelNow = level; mh.foldLevelPrev = prev; NotifyModified(mh); } return prev; } int SCI_METHOD Document::GetLevel(int line) const { return static_cast(perLineData[ldLevels])->GetLevel(line); } void Document::ClearLevels() { static_cast(perLineData[ldLevels])->ClearLevels(); } static bool IsSubordinate(int levelStart, int levelTry) { if (levelTry & SC_FOLDLEVELWHITEFLAG) return true; else return (levelStart & SC_FOLDLEVELNUMBERMASK) < (levelTry & SC_FOLDLEVELNUMBERMASK); } int Document::GetLastChild(int lineParent, int level, int lastLine) { if (level == -1) level = GetLevel(lineParent) & SC_FOLDLEVELNUMBERMASK; int maxLine = LinesTotal(); int lookLastLine = (lastLine != -1) ? Platform::Minimum(LinesTotal() - 1, lastLine) : -1; int lineMaxSubord = lineParent; while (lineMaxSubord < maxLine - 1) { EnsureStyledTo(LineStart(lineMaxSubord + 2)); if (!IsSubordinate(level, GetLevel(lineMaxSubord + 1))) break; if ((lookLastLine != -1) && (lineMaxSubord >= lookLastLine) && !(GetLevel(lineMaxSubord) & SC_FOLDLEVELWHITEFLAG)) break; lineMaxSubord++; } if (lineMaxSubord > lineParent) { if (level > (GetLevel(lineMaxSubord + 1) & SC_FOLDLEVELNUMBERMASK)) { // Have chewed up some whitespace that belongs to a parent so seek back if (GetLevel(lineMaxSubord) & SC_FOLDLEVELWHITEFLAG) { lineMaxSubord--; } } } return lineMaxSubord; } int Document::GetFoldParent(int line) { int level = GetLevel(line) & SC_FOLDLEVELNUMBERMASK; int lineLook = line - 1; while ((lineLook > 0) && ( (!(GetLevel(lineLook) & SC_FOLDLEVELHEADERFLAG)) || ((GetLevel(lineLook) & SC_FOLDLEVELNUMBERMASK) >= level)) ) { lineLook--; } if ((GetLevel(lineLook) & SC_FOLDLEVELHEADERFLAG) && ((GetLevel(lineLook) & SC_FOLDLEVELNUMBERMASK) < level)) { return lineLook; } else { return -1; } } void Document::GetHighlightDelimiters(HighlightDelimiter &highlightDelimiter, int line, int lastLine) { int level = GetLevel(line); int lookLastLine = Platform::Maximum(line, lastLine) + 1; int lookLine = line; int lookLineLevel = level; int lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; while ((lookLine > 0) && ((lookLineLevel & SC_FOLDLEVELWHITEFLAG) || ((lookLineLevel & SC_FOLDLEVELHEADERFLAG) && (lookLineLevelNum >= (GetLevel(lookLine + 1) & SC_FOLDLEVELNUMBERMASK))))) { lookLineLevel = GetLevel(--lookLine); lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; } int beginFoldBlock = (lookLineLevel & SC_FOLDLEVELHEADERFLAG) ? lookLine : GetFoldParent(lookLine); if (beginFoldBlock == -1) { highlightDelimiter.Clear(); return; } int endFoldBlock = GetLastChild(beginFoldBlock, -1, lookLastLine); int firstChangeableLineBefore = -1; if (endFoldBlock < line) { lookLine = beginFoldBlock - 1; lookLineLevel = GetLevel(lookLine); lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; while ((lookLine >= 0) && (lookLineLevelNum >= SC_FOLDLEVELBASE)) { if (lookLineLevel & SC_FOLDLEVELHEADERFLAG) { if (GetLastChild(lookLine, -1, lookLastLine) == line) { beginFoldBlock = lookLine; endFoldBlock = line; firstChangeableLineBefore = line - 1; } } if ((lookLine > 0) && (lookLineLevelNum == SC_FOLDLEVELBASE) && ((GetLevel(lookLine - 1) & SC_FOLDLEVELNUMBERMASK) > lookLineLevelNum)) break; lookLineLevel = GetLevel(--lookLine); lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; } } if (firstChangeableLineBefore == -1) { for (lookLine = line - 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; lookLine >= beginFoldBlock; lookLineLevel = GetLevel(--lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK) { if ((lookLineLevel & SC_FOLDLEVELWHITEFLAG) || (lookLineLevelNum > (level & SC_FOLDLEVELNUMBERMASK))) { firstChangeableLineBefore = lookLine; break; } } } if (firstChangeableLineBefore == -1) firstChangeableLineBefore = beginFoldBlock - 1; int firstChangeableLineAfter = -1; for (lookLine = line + 1, lookLineLevel = GetLevel(lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK; lookLine <= endFoldBlock; lookLineLevel = GetLevel(++lookLine), lookLineLevelNum = lookLineLevel & SC_FOLDLEVELNUMBERMASK) { if ((lookLineLevel & SC_FOLDLEVELHEADERFLAG) && (lookLineLevelNum < (GetLevel(lookLine + 1) & SC_FOLDLEVELNUMBERMASK))) { firstChangeableLineAfter = lookLine; break; } } if (firstChangeableLineAfter == -1) firstChangeableLineAfter = endFoldBlock + 1; highlightDelimiter.beginFoldBlock = beginFoldBlock; highlightDelimiter.endFoldBlock = endFoldBlock; highlightDelimiter.firstChangeableLineBefore = firstChangeableLineBefore; highlightDelimiter.firstChangeableLineAfter = firstChangeableLineAfter; } int Document::ClampPositionIntoDocument(int pos) { return Platform::Clamp(pos, 0, Length()); } bool Document::IsCrLf(int pos) { if (pos < 0) return false; if (pos >= (Length() - 1)) return false; return (cb.CharAt(pos) == '\r') && (cb.CharAt(pos + 1) == '\n'); } int Document::LenChar(int pos) { if (pos < 0) { return 1; } else if (IsCrLf(pos)) { return 2; } else if (SC_CP_UTF8 == dbcsCodePage) { const unsigned char leadByte = static_cast(cb.CharAt(pos)); const int widthCharBytes = UTF8BytesOfLead[leadByte]; int lengthDoc = Length(); if ((pos + widthCharBytes) > lengthDoc) return lengthDoc - pos; else return widthCharBytes; } else if (dbcsCodePage) { return IsDBCSLeadByte(cb.CharAt(pos)) ? 2 : 1; } else { return 1; } } bool Document::InGoodUTF8(int pos, int &start, int &end) const { int trail = pos; while ((trail>0) && (pos-trail < UTF8MaxBytes) && UTF8IsTrailByte(static_cast(cb.CharAt(trail-1)))) trail--; start = (trail > 0) ? trail-1 : trail; const unsigned char leadByte = static_cast(cb.CharAt(start)); const int widthCharBytes = UTF8BytesOfLead[leadByte]; if (widthCharBytes == 1) { return false; } else { int trailBytes = widthCharBytes - 1; int len = pos - start; if (len > trailBytes) // pos too far from lead return false; char charBytes[UTF8MaxBytes] = {static_cast(leadByte),0,0,0}; for (int b=1; b(start+b)); int utf8status = UTF8Classify(reinterpret_cast(charBytes), widthCharBytes); if (utf8status & UTF8MaskInvalid) return false; end = start + widthCharBytes; return true; } } // Normalise a position so that it is not halfway through a two byte character. // This can occur in two situations - // When lines are terminated with \r\n pairs which should be treated as one character. // When displaying DBCS text such as Japanese. // If moving, move the position in the indicated direction. int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { //Platform::DebugPrintf("NoCRLF %d %d\n", pos, moveDir); // If out of range, just return minimum/maximum value. if (pos <= 0) return 0; if (pos >= Length()) return Length(); // PLATFORM_ASSERT(pos > 0 && pos < Length()); if (checkLineEnd && IsCrLf(pos - 1)) { if (moveDir > 0) return pos + 1; else return pos - 1; } if (dbcsCodePage) { if (SC_CP_UTF8 == dbcsCodePage) { unsigned char ch = static_cast(cb.CharAt(pos)); // If ch is not a trail byte then pos is valid intercharacter position if (UTF8IsTrailByte(ch)) { int startUTF = pos; int endUTF = pos; if (InGoodUTF8(pos, startUTF, endUTF)) { // ch is a trail byte within a UTF-8 character if (moveDir > 0) pos = endUTF; else pos = startUTF; } // Else invalid UTF-8 so return position of isolated trail byte } } else { // Anchor DBCS calculations at start of line because start of line can // not be a DBCS trail byte. int posStartLine = LineStart(LineFromPosition(pos)); if (pos == posStartLine) return pos; // Step back until a non-lead-byte is found. int posCheck = pos; while ((posCheck > posStartLine) && IsDBCSLeadByte(cb.CharAt(posCheck-1))) posCheck--; // Check from known start of character. while (posCheck < pos) { int mbsize = IsDBCSLeadByte(cb.CharAt(posCheck)) ? 2 : 1; if (posCheck + mbsize == pos) { return pos; } else if (posCheck + mbsize > pos) { if (moveDir > 0) { return posCheck + mbsize; } else { return posCheck; } } posCheck += mbsize; } } } return pos; } // NextPosition moves between valid positions - it can not handle a position in the middle of a // multi-byte character. It is used to iterate through text more efficiently than MovePositionOutsideChar. // A \r\n pair is treated as two characters. int Document::NextPosition(int pos, int moveDir) const { // If out of range, just return minimum/maximum value. int increment = (moveDir > 0) ? 1 : -1; if (pos + increment <= 0) return 0; if (pos + increment >= Length()) return Length(); if (dbcsCodePage) { if (SC_CP_UTF8 == dbcsCodePage) { if (increment == 1) { // Simple forward movement case so can avoid some checks const unsigned char leadByte = static_cast(cb.CharAt(pos)); if (UTF8IsAscii(leadByte)) { // Single byte character or invalid pos++; } else { const int widthCharBytes = UTF8BytesOfLead[leadByte]; char charBytes[UTF8MaxBytes] = {static_cast(leadByte),0,0,0}; for (int b=1; b(pos+b)); int utf8status = UTF8Classify(reinterpret_cast(charBytes), widthCharBytes); if (utf8status & UTF8MaskInvalid) pos++; else pos += utf8status & UTF8MaskWidth; } } else { // Examine byte before position pos--; unsigned char ch = static_cast(cb.CharAt(pos)); // If ch is not a trail byte then pos is valid intercharacter position if (UTF8IsTrailByte(ch)) { // If ch is a trail byte in a valid UTF-8 character then return start of character int startUTF = pos; int endUTF = pos; if (InGoodUTF8(pos, startUTF, endUTF)) { pos = startUTF; } // Else invalid UTF-8 so return position of isolated trail byte } } } else { if (moveDir > 0) { int mbsize = IsDBCSLeadByte(cb.CharAt(pos)) ? 2 : 1; pos += mbsize; if (pos > Length()) pos = Length(); } else { // Anchor DBCS calculations at start of line because start of line can // not be a DBCS trail byte. int posStartLine = LineStart(LineFromPosition(pos)); // See http://msdn.microsoft.com/en-us/library/cc194792%28v=MSDN.10%29.aspx // http://msdn.microsoft.com/en-us/library/cc194790.aspx if ((pos - 1) <= posStartLine) { return pos - 1; } else if (IsDBCSLeadByte(cb.CharAt(pos - 1))) { // Must actually be trail byte return pos - 2; } else { // Otherwise, step back until a non-lead-byte is found. int posTemp = pos - 1; while (posStartLine <= --posTemp && IsDBCSLeadByte(cb.CharAt(posTemp))) ; // Now posTemp+1 must point to the beginning of a character, // so figure out whether we went back an even or an odd // number of bytes and go back 1 or 2 bytes, respectively. return (pos - 1 - ((pos - posTemp) & 1)); } } } } else { pos += increment; } return pos; } bool Document::NextCharacter(int &pos, int moveDir) { // Returns true if pos changed int posNext = NextPosition(pos, moveDir); if (posNext == pos) { return false; } else { pos = posNext; return true; } } int SCI_METHOD Document::CodePage() const { return dbcsCodePage; } bool SCI_METHOD Document::IsDBCSLeadByte(char ch) const { // Byte ranges found in Wikipedia articles with relevant search strings in each case unsigned char uch = static_cast(ch); switch (dbcsCodePage) { case 932: // Shift_jis return ((uch >= 0x81) && (uch <= 0x9F)) || ((uch >= 0xE0) && (uch <= 0xFC)); // Lead bytes F0 to FC may be a Microsoft addition. case 936: // GBK return (uch >= 0x81) && (uch <= 0xFE); case 949: // Korean Wansung KS C-5601-1987 return (uch >= 0x81) && (uch <= 0xFE); case 950: // Big5 return (uch >= 0x81) && (uch <= 0xFE); case 1361: // Korean Johab KS C-5601-1992 return ((uch >= 0x84) && (uch <= 0xD3)) || ((uch >= 0xD8) && (uch <= 0xDE)) || ((uch >= 0xE0) && (uch <= 0xF9)); } return false; } static inline bool IsSpaceOrTab(int ch) { return ch == ' ' || ch == '\t'; } // Need to break text into segments near lengthSegment but taking into // account the encoding to not break inside a UTF-8 or DBCS character // and also trying to avoid breaking inside a pair of combining characters. // The segment length must always be long enough (more than 4 bytes) // so that there will be at least one whole character to make a segment. // For UTF-8, text must consist only of valid whole characters. // In preference order from best to worst: // 1) Break after space // 2) Break before punctuation // 3) Break after whole character int Document::SafeSegment(const char *text, int length, int lengthSegment) { if (length <= lengthSegment) return length; int lastSpaceBreak = -1; int lastPunctuationBreak = -1; int lastEncodingAllowedBreak = -1; for (int j=0; j < lengthSegment;) { unsigned char ch = static_cast(text[j]); if (j > 0) { if (IsSpaceOrTab(text[j - 1]) && !IsSpaceOrTab(text[j])) { lastSpaceBreak = j; } if (ch < 'A') { lastPunctuationBreak = j; } } lastEncodingAllowedBreak = j; if (dbcsCodePage == SC_CP_UTF8) { j += UTF8BytesOfLead[ch]; } else if (dbcsCodePage) { j += IsDBCSLeadByte(ch) ? 2 : 1; } else { j++; } } if (lastSpaceBreak >= 0) { return lastSpaceBreak; } else if (lastPunctuationBreak >= 0) { return lastPunctuationBreak; } return lastEncodingAllowedBreak; } void Document::ModifiedAt(int pos) { if (endStyled > pos) endStyled = pos; } void Document::CheckReadOnly() { if (cb.IsReadOnly() && enteredReadOnlyCount == 0) { enteredReadOnlyCount++; NotifyModifyAttempt(); enteredReadOnlyCount--; } } // Document only modified by gateways DeleteChars, InsertString, Undo, Redo, and SetStyleAt. // SetStyleAt does not change the persistent state of a document bool Document::DeleteChars(int pos, int len) { if (len == 0) return false; if ((pos + len) > Length()) return false; CheckReadOnly(); if (enteredModification != 0) { return false; } else { enteredModification++; if (!cb.IsReadOnly()) { NotifyModified( DocModification( SC_MOD_BEFOREDELETE | SC_PERFORMED_USER, pos, len, 0, 0)); int prevLinesTotal = LinesTotal(); bool startSavePoint = cb.IsSavePoint(); bool startSequence = false; const char *text = cb.DeleteChars(pos, len, startSequence); if (startSavePoint && cb.IsCollectingUndo()) NotifySavePoint(!startSavePoint); if ((pos < Length()) || (pos == 0)) ModifiedAt(pos); else ModifiedAt(pos-1); NotifyModified( DocModification( SC_MOD_DELETETEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0), pos, len, LinesTotal() - prevLinesTotal, text)); } enteredModification--; } return !cb.IsReadOnly(); } /** * Insert a string with a length. */ bool Document::InsertString(int position, const char *s, int insertLength) { if (insertLength <= 0) { return false; } CheckReadOnly(); if (enteredModification != 0) { return false; } else { enteredModification++; if (!cb.IsReadOnly()) { NotifyModified( DocModification( SC_MOD_BEFOREINSERT | SC_PERFORMED_USER, position, insertLength, 0, s)); int prevLinesTotal = LinesTotal(); bool startSavePoint = cb.IsSavePoint(); bool startSequence = false; const char *text = cb.InsertString(position, s, insertLength, startSequence); if (startSavePoint && cb.IsCollectingUndo()) NotifySavePoint(!startSavePoint); ModifiedAt(position); NotifyModified( DocModification( SC_MOD_INSERTTEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0), position, insertLength, LinesTotal() - prevLinesTotal, text)); } enteredModification--; } return !cb.IsReadOnly(); } int SCI_METHOD Document::AddData(char *data, int length) { try { int position = Length(); InsertString(position,data, length); } catch (std::bad_alloc &) { return SC_STATUS_BADALLOC; } catch (...) { return SC_STATUS_FAILURE; } return 0; } void * SCI_METHOD Document::ConvertToDocument() { return this; } int Document::Undo() { int newPos = -1; CheckReadOnly(); if (enteredModification == 0) { enteredModification++; if (!cb.IsReadOnly()) { bool startSavePoint = cb.IsSavePoint(); bool multiLine = false; int steps = cb.StartUndo(); //Platform::DebugPrintf("Steps=%d\n", steps); for (int step = 0; step < steps; step++) { const int prevLinesTotal = LinesTotal(); const Action &action = cb.GetUndoStep(); if (action.at == removeAction) { NotifyModified(DocModification( SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action)); } else if (action.at == containerAction) { DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO); dm.token = action.position; NotifyModified(dm); } else { NotifyModified(DocModification( SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action)); } cb.PerformUndoStep(); int cellPosition = action.position; if (action.at != containerAction) { ModifiedAt(cellPosition); newPos = cellPosition; } int modFlags = SC_PERFORMED_UNDO; // With undo, an insertion action becomes a deletion notification if (action.at == removeAction) { newPos += action.lenData; modFlags |= SC_MOD_INSERTTEXT; } else if (action.at == insertAction) { modFlags |= SC_MOD_DELETETEXT; } if (steps > 1) modFlags |= SC_MULTISTEPUNDOREDO; const int linesAdded = LinesTotal() - prevLinesTotal; if (linesAdded != 0) multiLine = true; if (step == steps - 1) { modFlags |= SC_LASTSTEPINUNDOREDO; if (multiLine) modFlags |= SC_MULTILINEUNDOREDO; } NotifyModified(DocModification(modFlags, cellPosition, action.lenData, linesAdded, action.data)); } bool endSavePoint = cb.IsSavePoint(); if (startSavePoint != endSavePoint) NotifySavePoint(endSavePoint); } enteredModification--; } return newPos; } int Document::Redo() { int newPos = -1; CheckReadOnly(); if (enteredModification == 0) { enteredModification++; if (!cb.IsReadOnly()) { bool startSavePoint = cb.IsSavePoint(); bool multiLine = false; int steps = cb.StartRedo(); for (int step = 0; step < steps; step++) { const int prevLinesTotal = LinesTotal(); const Action &action = cb.GetRedoStep(); if (action.at == insertAction) { NotifyModified(DocModification( SC_MOD_BEFOREINSERT | SC_PERFORMED_REDO, action)); } else if (action.at == containerAction) { DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_REDO); dm.token = action.position; NotifyModified(dm); } else { NotifyModified(DocModification( SC_MOD_BEFOREDELETE | SC_PERFORMED_REDO, action)); } cb.PerformRedoStep(); if (action.at != containerAction) { ModifiedAt(action.position); newPos = action.position; } int modFlags = SC_PERFORMED_REDO; if (action.at == insertAction) { newPos += action.lenData; modFlags |= SC_MOD_INSERTTEXT; } else if (action.at == removeAction) { modFlags |= SC_MOD_DELETETEXT; } if (steps > 1) modFlags |= SC_MULTISTEPUNDOREDO; const int linesAdded = LinesTotal() - prevLinesTotal; if (linesAdded != 0) multiLine = true; if (step == steps - 1) { modFlags |= SC_LASTSTEPINUNDOREDO; if (multiLine) modFlags |= SC_MULTILINEUNDOREDO; } NotifyModified( DocModification(modFlags, action.position, action.lenData, linesAdded, action.data)); } bool endSavePoint = cb.IsSavePoint(); if (startSavePoint != endSavePoint) NotifySavePoint(endSavePoint); } enteredModification--; } return newPos; } /** * Insert a single character. */ bool Document::InsertChar(int pos, char ch) { char chs[1]; chs[0] = ch; return InsertString(pos, chs, 1); } /** * Insert a null terminated string. */ bool Document::InsertCString(int position, const char *s) { return InsertString(position, s, static_cast(s ? strlen(s) : 0)); } void Document::ChangeChar(int pos, char ch) { DeleteChars(pos, 1); InsertChar(pos, ch); } void Document::DelChar(int pos) { DeleteChars(pos, LenChar(pos)); } void Document::DelCharBack(int pos) { if (pos <= 0) { return; } else if (IsCrLf(pos - 2)) { DeleteChars(pos - 2, 2); } else if (dbcsCodePage) { int startChar = NextPosition(pos, -1); DeleteChars(startChar, pos - startChar); } else { DeleteChars(pos - 1, 1); } } static int NextTab(int pos, int tabSize) { return ((pos / tabSize) + 1) * tabSize; } static void CreateIndentation(char *linebuf, int length, int indent, int tabSize, bool insertSpaces) { length--; // ensure space for \0 if (!insertSpaces) { while ((indent >= tabSize) && (length > 0)) { *linebuf++ = '\t'; indent -= tabSize; length--; } } while ((indent > 0) && (length > 0)) { *linebuf++ = ' '; indent--; length--; } *linebuf = '\0'; } int SCI_METHOD Document::GetLineIndentation(int line) { int indent = 0; if ((line >= 0) && (line < LinesTotal())) { int lineStart = LineStart(line); int length = Length(); for (int i = lineStart; i < length; i++) { char ch = cb.CharAt(i); if (ch == ' ') indent++; else if (ch == '\t') indent = NextTab(indent, tabInChars); else return indent; } } return indent; } void Document::SetLineIndentation(int line, int indent) { int indentOfLine = GetLineIndentation(line); if (indent < 0) indent = 0; if (indent != indentOfLine) { char linebuf[1000]; CreateIndentation(linebuf, sizeof(linebuf), indent, tabInChars, !useTabs); int thisLineStart = LineStart(line); int indentPos = GetLineIndentPosition(line); UndoGroup ug(this); DeleteChars(thisLineStart, indentPos - thisLineStart); InsertCString(thisLineStart, linebuf); } } int Document::GetLineIndentPosition(int line) const { if (line < 0) return 0; int pos = LineStart(line); int length = Length(); while ((pos < length) && IsSpaceOrTab(cb.CharAt(pos))) { pos++; } return pos; } int Document::GetColumn(int pos) { int column = 0; int line = LineFromPosition(pos); if ((line >= 0) && (line < LinesTotal())) { for (int i = LineStart(line); i < pos;) { char ch = cb.CharAt(i); if (ch == '\t') { column = NextTab(column, tabInChars); i++; } else if (ch == '\r') { return column; } else if (ch == '\n') { return column; } else if (i >= Length()) { return column; } else { column++; i = NextPosition(i, 1); } } } return column; } int Document::CountCharacters(int startPos, int endPos) { startPos = MovePositionOutsideChar(startPos, 1, false); endPos = MovePositionOutsideChar(endPos, -1, false); int count = 0; int i = startPos; while (i < endPos) { count++; if (IsCrLf(i)) i++; i = NextPosition(i, 1); } return count; } int Document::FindColumn(int line, int column) { int position = LineStart(line); if ((line >= 0) && (line < LinesTotal())) { int columnCurrent = 0; while ((columnCurrent < column) && (position < Length())) { char ch = cb.CharAt(position); if (ch == '\t') { columnCurrent = NextTab(columnCurrent, tabInChars); if (columnCurrent > column) return position; position++; } else if (ch == '\r') { return position; } else if (ch == '\n') { return position; } else { columnCurrent++; position = NextPosition(position, 1); } } } return position; } void Document::Indent(bool forwards, int lineBottom, int lineTop) { // Dedent - suck white space off the front of the line to dedent by equivalent of a tab for (int line = lineBottom; line >= lineTop; line--) { int indentOfLine = GetLineIndentation(line); if (forwards) { if (LineStart(line) < LineEnd(line)) { SetLineIndentation(line, indentOfLine + IndentSize()); } } else { SetLineIndentation(line, indentOfLine - IndentSize()); } } } // Convert line endings for a piece of text to a particular mode. // Stop at len or when a NUL is found. // Caller must delete the returned pointer. char *Document::TransformLineEnds(int *pLenOut, const char *s, size_t len, int eolModeWanted) { char *dest = new char[2 * len + 1]; const char *sptr = s; char *dptr = dest; for (size_t i = 0; (i < len) && (*sptr != '\0'); i++) { if (*sptr == '\n' || *sptr == '\r') { if (eolModeWanted == SC_EOL_CR) { *dptr++ = '\r'; } else if (eolModeWanted == SC_EOL_LF) { *dptr++ = '\n'; } else { // eolModeWanted == SC_EOL_CRLF *dptr++ = '\r'; *dptr++ = '\n'; } if ((*sptr == '\r') && (i+1 < len) && (*(sptr+1) == '\n')) { i++; sptr++; } sptr++; } else { *dptr++ = *sptr++; } } *dptr++ = '\0'; *pLenOut = (dptr - dest) - 1; return dest; } void Document::ConvertLineEnds(int eolModeSet) { UndoGroup ug(this); for (int pos = 0; pos < Length(); pos++) { if (cb.CharAt(pos) == '\r') { if (cb.CharAt(pos + 1) == '\n') { // CRLF if (eolModeSet == SC_EOL_CR) { DeleteChars(pos + 1, 1); // Delete the LF } else if (eolModeSet == SC_EOL_LF) { DeleteChars(pos, 1); // Delete the CR } else { pos++; } } else { // CR if (eolModeSet == SC_EOL_CRLF) { InsertString(pos + 1, "\n", 1); // Insert LF pos++; } else if (eolModeSet == SC_EOL_LF) { InsertString(pos, "\n", 1); // Insert LF DeleteChars(pos + 1, 1); // Delete CR } } } else if (cb.CharAt(pos) == '\n') { // LF if (eolModeSet == SC_EOL_CRLF) { InsertString(pos, "\r", 1); // Insert CR pos++; } else if (eolModeSet == SC_EOL_CR) { InsertString(pos, "\r", 1); // Insert CR DeleteChars(pos + 1, 1); // Delete LF } } } } bool Document::IsWhiteLine(int line) const { int currentChar = LineStart(line); int endLine = LineEnd(line); while (currentChar < endLine) { if (cb.CharAt(currentChar) != ' ' && cb.CharAt(currentChar) != '\t') { return false; } ++currentChar; } return true; } int Document::ParaUp(int pos) { int line = LineFromPosition(pos); line--; while (line >= 0 && IsWhiteLine(line)) { // skip empty lines line--; } while (line >= 0 && !IsWhiteLine(line)) { // skip non-empty lines line--; } line++; return LineStart(line); } int Document::ParaDown(int pos) { int line = LineFromPosition(pos); while (line < LinesTotal() && !IsWhiteLine(line)) { // skip non-empty lines line++; } while (line < LinesTotal() && IsWhiteLine(line)) { // skip empty lines line++; } if (line < LinesTotal()) return LineStart(line); else // end of a document return LineEnd(line-1); } CharClassify::cc Document::WordCharClass(unsigned char ch) { if ((SC_CP_UTF8 == dbcsCodePage) && (!UTF8IsAscii(ch))) return CharClassify::ccWord; return charClass.GetClass(ch); } /** * Used by commmands that want to select whole words. * Finds the start of word at pos when delta < 0 or the end of the word when delta >= 0. */ int Document::ExtendWordSelect(int pos, int delta, bool onlyWordCharacters) { CharClassify::cc ccStart = CharClassify::ccWord; if (delta < 0) { if (!onlyWordCharacters) ccStart = WordCharClass(cb.CharAt(pos-1)); while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccStart)) pos--; } else { if (!onlyWordCharacters && pos < Length()) ccStart = WordCharClass(cb.CharAt(pos)); while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart)) pos++; } return MovePositionOutsideChar(pos, delta, true); } /** * Find the start of the next word in either a forward (delta >= 0) or backwards direction * (delta < 0). * This is looking for a transition between character classes although there is also some * additional movement to transit white space. * Used by cursor movement by word commands. */ int Document::NextWordStart(int pos, int delta) { if (delta < 0) { while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == CharClassify::ccSpace)) pos--; if (pos > 0) { CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos-1)); while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccStart)) { pos--; } } } else { CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos)); while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart)) pos++; while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == CharClassify::ccSpace)) pos++; } return pos; } /** * Find the end of the next word in either a forward (delta >= 0) or backwards direction * (delta < 0). * This is looking for a transition between character classes although there is also some * additional movement to transit white space. * Used by cursor movement by word commands. */ int Document::NextWordEnd(int pos, int delta) { if (delta < 0) { if (pos > 0) { CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos-1)); if (ccStart != CharClassify::ccSpace) { while (pos > 0 && WordCharClass(cb.CharAt(pos - 1)) == ccStart) { pos--; } } while (pos > 0 && WordCharClass(cb.CharAt(pos - 1)) == CharClassify::ccSpace) { pos--; } } } else { while (pos < Length() && WordCharClass(cb.CharAt(pos)) == CharClassify::ccSpace) { pos++; } if (pos < Length()) { CharClassify::cc ccStart = WordCharClass(cb.CharAt(pos)); while (pos < Length() && WordCharClass(cb.CharAt(pos)) == ccStart) { pos++; } } } return pos; } /** * Check that the character at the given position is a word or punctuation character and that * the previous character is of a different character class. */ bool Document::IsWordStartAt(int pos) { if (pos > 0) { CharClassify::cc ccPos = WordCharClass(CharAt(pos)); return (ccPos == CharClassify::ccWord || ccPos == CharClassify::ccPunctuation) && (ccPos != WordCharClass(CharAt(pos - 1))); } return true; } /** * Check that the character at the given position is a word or punctuation character and that * the next character is of a different character class. */ bool Document::IsWordEndAt(int pos) { if (pos < Length()) { CharClassify::cc ccPrev = WordCharClass(CharAt(pos-1)); return (ccPrev == CharClassify::ccWord || ccPrev == CharClassify::ccPunctuation) && (ccPrev != WordCharClass(CharAt(pos))); } return true; } /** * Check that the given range is has transitions between character classes at both * ends and where the characters on the inside are word or punctuation characters. */ bool Document::IsWordAt(int start, int end) { return IsWordStartAt(start) && IsWordEndAt(end); } static inline char MakeLowerCase(char ch) { if (ch < 'A' || ch > 'Z') return ch; else return static_cast(ch - 'A' + 'a'); } CaseFolderTable::CaseFolderTable() { for (size_t iChar=0; iChar(iChar); } } CaseFolderTable::~CaseFolderTable() { } size_t CaseFolderTable::Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { if (lenMixed > sizeFolded) { return 0; } else { for (size_t i=0; i(mixed[i])]; } return lenMixed; } } void CaseFolderTable::SetTranslation(char ch, char chTranslation) { mapping[static_cast(ch)] = chTranslation; } void CaseFolderTable::StandardASCII() { for (size_t iChar=0; iChar= 'A' && iChar <= 'Z') { mapping[iChar] = static_cast(iChar - 'A' + 'a'); } else { mapping[iChar] = static_cast(iChar); } } } bool Document::MatchesWordOptions(bool word, bool wordStart, int pos, int length) { return (!word && !wordStart) || (word && IsWordAt(pos, pos + length)) || (wordStart && IsWordStartAt(pos)); } /** * Find text in document, supporting both forward and backward * searches (just pass minPos > maxPos to do a backward search) * Has not been tested with backwards DBCS searches yet. */ long Document::FindText(int minPos, int maxPos, const char *search, bool caseSensitive, bool word, bool wordStart, bool regExp, int flags, int *length, CaseFolder *pcf) { if (*length <= 0) return minPos; if (regExp) { if (!regex) regex = CreateRegexSearch(&charClass); return regex->FindText(this, minPos, maxPos, search, caseSensitive, word, wordStart, flags, length); } else { const bool forward = minPos <= maxPos; const int increment = forward ? 1 : -1; // Range endpoints should not be inside DBCS characters, but just in case, move them. const int startPos = MovePositionOutsideChar(minPos, increment, false); const int endPos = MovePositionOutsideChar(maxPos, increment, false); // Compute actual search ranges needed const int lengthFind = *length; //Platform::DebugPrintf("Find %d %d %s %d\n", startPos, endPos, ft->lpstrText, lengthFind); const int limitPos = Platform::Maximum(startPos, endPos); int pos = startPos; if (!forward) { // Back all of a character pos = NextPosition(pos, increment); } if (caseSensitive) { const int endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos; const char charStartSearch = search[0]; while (forward ? (pos < endSearch) : (pos >= endSearch)) { if (CharAt(pos) == charStartSearch) { bool found = (pos + lengthFind) <= limitPos; for (int indexSearch = 1; (indexSearch < lengthFind) && found; indexSearch++) { found = CharAt(pos + indexSearch) == search[indexSearch]; } if (found && MatchesWordOptions(word, wordStart, pos, lengthFind)) { return pos; } } if (!NextCharacter(pos, increment)) break; } } else if (SC_CP_UTF8 == dbcsCodePage) { const size_t maxFoldingExpansion = 4; std::vector searchThing(lengthFind * UTF8MaxBytes * maxFoldingExpansion + 1); const int lenSearch = static_cast( pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind)); char bytes[UTF8MaxBytes + 1]; char folded[UTF8MaxBytes * maxFoldingExpansion + 1]; while (forward ? (pos < endPos) : (pos >= endPos)) { int widthFirstCharacter = 0; int posIndexDocument = pos; int indexSearch = 0; bool characterMatches = true; for (;;) { const unsigned char leadByte = static_cast(cb.CharAt(posIndexDocument)); bytes[0] = leadByte; int widthChar = 1; if (!UTF8IsAscii(leadByte)) { const int widthCharBytes = UTF8BytesOfLead[leadByte]; for (int b=1; b(bytes), widthCharBytes) & UTF8MaskWidth; } if (!widthFirstCharacter) widthFirstCharacter = widthChar; if ((posIndexDocument + widthChar) > limitPos) break; const int lenFlat = static_cast(pcf->Fold(folded, sizeof(folded), bytes, widthChar)); folded[lenFlat] = 0; // Does folded match the buffer characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat); if (!characterMatches) break; posIndexDocument += widthChar; indexSearch += lenFlat; if (indexSearch >= lenSearch) break; } if (characterMatches && (indexSearch == static_cast(lenSearch))) { if (MatchesWordOptions(word, wordStart, pos, posIndexDocument - pos)) { *length = posIndexDocument - pos; return pos; } } if (forward) { pos += widthFirstCharacter; } else { if (!NextCharacter(pos, increment)) break; } } } else if (dbcsCodePage) { const size_t maxBytesCharacter = 2; const size_t maxFoldingExpansion = 4; std::vector searchThing(lengthFind * maxBytesCharacter * maxFoldingExpansion + 1); const int lenSearch = static_cast( pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind)); while (forward ? (pos < endPos) : (pos >= endPos)) { int indexDocument = 0; int indexSearch = 0; bool characterMatches = true; while (characterMatches && ((pos + indexDocument) < limitPos) && (indexSearch < lenSearch)) { char bytes[maxBytesCharacter + 1]; bytes[0] = cb.CharAt(pos + indexDocument); const int widthChar = IsDBCSLeadByte(bytes[0]) ? 2 : 1; if (widthChar == 2) bytes[1] = cb.CharAt(pos + indexDocument + 1); if ((pos + indexDocument + widthChar) > limitPos) break; char folded[maxBytesCharacter * maxFoldingExpansion + 1]; const int lenFlat = static_cast(pcf->Fold(folded, sizeof(folded), bytes, widthChar)); folded[lenFlat] = 0; // Does folded match the buffer characterMatches = 0 == memcmp(folded, &searchThing[0] + indexSearch, lenFlat); indexDocument += widthChar; indexSearch += lenFlat; } if (characterMatches && (indexSearch == static_cast(lenSearch))) { if (MatchesWordOptions(word, wordStart, pos, indexDocument)) { *length = indexDocument; return pos; } } if (!NextCharacter(pos, increment)) break; } } else { const int endSearch = (startPos <= endPos) ? endPos - lengthFind + 1 : endPos; std::vector searchThing(lengthFind + 1); pcf->Fold(&searchThing[0], searchThing.size(), search, lengthFind); while (forward ? (pos < endSearch) : (pos >= endSearch)) { bool found = (pos + lengthFind) <= limitPos; for (int indexSearch = 0; (indexSearch < lengthFind) && found; indexSearch++) { char ch = CharAt(pos + indexSearch); char folded[2]; pcf->Fold(folded, sizeof(folded), &ch, 1); found = folded[0] == searchThing[indexSearch]; } if (found && MatchesWordOptions(word, wordStart, pos, lengthFind)) { return pos; } if (!NextCharacter(pos, increment)) break; } } } //Platform::DebugPrintf("Not found\n"); return -1; } const char *Document::SubstituteByPosition(const char *text, int *length) { if (regex) return regex->SubstituteByPosition(this, text, length); else return 0; } int Document::LinesTotal() const { return cb.Lines(); } void Document::ChangeCase(Range r, bool makeUpperCase) { for (int pos = r.start; pos < r.end;) { int len = LenChar(pos); if (len == 1) { char ch = CharAt(pos); if (makeUpperCase) { if (IsLowerCase(ch)) { ChangeChar(pos, static_cast(MakeUpperCase(ch))); } } else { if (IsUpperCase(ch)) { ChangeChar(pos, static_cast(MakeLowerCase(ch))); } } } pos += len; } } void Document::SetDefaultCharClasses(bool includeWordClass) { charClass.SetDefaultCharClasses(includeWordClass); } void Document::SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass) { charClass.SetCharClasses(chars, newCharClass); } void Document::SetStylingBits(int bits) { stylingBits = bits; stylingBitsMask = (1 << stylingBits) - 1; } void SCI_METHOD Document::StartStyling(int position, char mask) { stylingMask = mask; endStyled = position; } bool SCI_METHOD Document::SetStyleFor(int length, char style) { if (enteredStyling != 0) { return false; } else { enteredStyling++; style &= stylingMask; int prevEndStyled = endStyled; if (cb.SetStyleFor(endStyled, length, style, stylingMask)) { DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER, prevEndStyled, length); NotifyModified(mh); } endStyled += length; enteredStyling--; return true; } } bool SCI_METHOD Document::SetStyles(int length, const char *styles) { if (enteredStyling != 0) { return false; } else { enteredStyling++; bool didChange = false; int startMod = 0; int endMod = 0; for (int iPos = 0; iPos < length; iPos++, endStyled++) { PLATFORM_ASSERT(endStyled < Length()); if (cb.SetStyleAt(endStyled, styles[iPos], stylingMask)) { if (!didChange) { startMod = endStyled; } didChange = true; endMod = endStyled; } } if (didChange) { DocModification mh(SC_MOD_CHANGESTYLE | SC_PERFORMED_USER, startMod, endMod - startMod + 1); NotifyModified(mh); } enteredStyling--; return true; } } void Document::EnsureStyledTo(int pos) { if ((enteredStyling == 0) && (pos > GetEndStyled())) { IncrementStyleClock(); if (pli && !pli->UseContainerLexing()) { int lineEndStyled = LineFromPosition(GetEndStyled()); int endStyledTo = LineStart(lineEndStyled); pli->Colourise(endStyledTo, pos); } else { // Ask the watchers to style, and stop as soon as one responds. for (int i = 0; pos > GetEndStyled() && i < lenWatchers; i++) { watchers[i].watcher->NotifyStyleNeeded(this, watchers[i].userData, pos); } } } } void Document::LexerChanged() { // Tell the watchers the lexer has changed. for (int i = 0; i < lenWatchers; i++) { watchers[i].watcher->NotifyLexerChanged(this, watchers[i].userData); } } int SCI_METHOD Document::SetLineState(int line, int state) { int statePrevious = static_cast(perLineData[ldState])->SetLineState(line, state); if (state != statePrevious) { DocModification mh(SC_MOD_CHANGELINESTATE, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } return statePrevious; } int SCI_METHOD Document::GetLineState(int line) const { return static_cast(perLineData[ldState])->GetLineState(line); } int Document::GetMaxLineState() { return static_cast(perLineData[ldState])->GetMaxLineState(); } void SCI_METHOD Document::ChangeLexerState(int start, int end) { DocModification mh(SC_MOD_LEXERSTATE, start, end-start, 0, 0, 0); NotifyModified(mh); } StyledText Document::MarginStyledText(int line) { LineAnnotation *pla = static_cast(perLineData[ldMargin]); return StyledText(pla->Length(line), pla->Text(line), pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); } void Document::MarginSetText(int line, const char *text) { static_cast(perLineData[ldMargin])->SetText(line, text); DocModification mh(SC_MOD_CHANGEMARGIN, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::MarginSetStyle(int line, int style) { static_cast(perLineData[ldMargin])->SetStyle(line, style); } void Document::MarginSetStyles(int line, const unsigned char *styles) { static_cast(perLineData[ldMargin])->SetStyles(line, styles); } int Document::MarginLength(int line) const { return static_cast(perLineData[ldMargin])->Length(line); } void Document::MarginClearAll() { int maxEditorLine = LinesTotal(); for (int l=0; l(perLineData[ldMargin])->ClearAll(); } bool Document::AnnotationAny() const { return static_cast(perLineData[ldAnnotation])->AnySet(); } StyledText Document::AnnotationStyledText(int line) { LineAnnotation *pla = static_cast(perLineData[ldAnnotation]); return StyledText(pla->Length(line), pla->Text(line), pla->MultipleStyles(line), pla->Style(line), pla->Styles(line)); } void Document::AnnotationSetText(int line, const char *text) { if (line >= 0 && line < LinesTotal()) { const int linesBefore = AnnotationLines(line); static_cast(perLineData[ldAnnotation])->SetText(line, text); const int linesAfter = AnnotationLines(line); DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); mh.annotationLinesAdded = linesAfter - linesBefore; NotifyModified(mh); } } void Document::AnnotationSetStyle(int line, int style) { static_cast(perLineData[ldAnnotation])->SetStyle(line, style); DocModification mh(SC_MOD_CHANGEANNOTATION, LineStart(line), 0, 0, 0, line); NotifyModified(mh); } void Document::AnnotationSetStyles(int line, const unsigned char *styles) { if (line >= 0 && line < LinesTotal()) { static_cast(perLineData[ldAnnotation])->SetStyles(line, styles); } } int Document::AnnotationLength(int line) const { return static_cast(perLineData[ldAnnotation])->Length(line); } int Document::AnnotationLines(int line) const { return static_cast(perLineData[ldAnnotation])->Lines(line); } void Document::AnnotationClearAll() { int maxEditorLine = LinesTotal(); for (int l=0; l(perLineData[ldAnnotation])->ClearAll(); } void Document::IncrementStyleClock() { styleClock = (styleClock + 1) % 0x100000; } void SCI_METHOD Document::DecorationFillRange(int position, int value, int fillLength) { if (decorations.FillRange(position, value, fillLength)) { DocModification mh(SC_MOD_CHANGEINDICATOR | SC_PERFORMED_USER, position, fillLength); NotifyModified(mh); } } bool Document::AddWatcher(DocWatcher *watcher, void *userData) { for (int i = 0; i < lenWatchers; i++) { if ((watchers[i].watcher == watcher) && (watchers[i].userData == userData)) return false; } WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers + 1]; for (int j = 0; j < lenWatchers; j++) pwNew[j] = watchers[j]; pwNew[lenWatchers].watcher = watcher; pwNew[lenWatchers].userData = userData; delete []watchers; watchers = pwNew; lenWatchers++; return true; } bool Document::RemoveWatcher(DocWatcher *watcher, void *userData) { for (int i = 0; i < lenWatchers; i++) { if ((watchers[i].watcher == watcher) && (watchers[i].userData == userData)) { if (lenWatchers == 1) { delete []watchers; watchers = 0; lenWatchers = 0; } else { WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers]; for (int j = 0; j < lenWatchers - 1; j++) { pwNew[j] = (j < i) ? watchers[j] : watchers[j + 1]; } delete []watchers; watchers = pwNew; lenWatchers--; } return true; } } return false; } void Document::NotifyModifyAttempt() { for (int i = 0; i < lenWatchers; i++) { watchers[i].watcher->NotifyModifyAttempt(this, watchers[i].userData); } } void Document::NotifySavePoint(bool atSavePoint) { for (int i = 0; i < lenWatchers; i++) { watchers[i].watcher->NotifySavePoint(this, watchers[i].userData, atSavePoint); } } void Document::NotifyModified(DocModification mh) { if (mh.modificationType & SC_MOD_INSERTTEXT) { decorations.InsertSpace(mh.position, mh.length); } else if (mh.modificationType & SC_MOD_DELETETEXT) { decorations.DeleteRange(mh.position, mh.length); } for (int i = 0; i < lenWatchers; i++) { watchers[i].watcher->NotifyModified(this, mh, watchers[i].userData); } } bool Document::IsWordPartSeparator(char ch) { return (WordCharClass(ch) == CharClassify::ccWord) && IsPunctuation(ch); } int Document::WordPartLeft(int pos) { if (pos > 0) { --pos; char startChar = cb.CharAt(pos); if (IsWordPartSeparator(startChar)) { while (pos > 0 && IsWordPartSeparator(cb.CharAt(pos))) { --pos; } } if (pos > 0) { startChar = cb.CharAt(pos); --pos; if (IsLowerCase(startChar)) { while (pos > 0 && IsLowerCase(cb.CharAt(pos))) --pos; if (!IsUpperCase(cb.CharAt(pos)) && !IsLowerCase(cb.CharAt(pos))) ++pos; } else if (IsUpperCase(startChar)) { while (pos > 0 && IsUpperCase(cb.CharAt(pos))) --pos; if (!IsUpperCase(cb.CharAt(pos))) ++pos; } else if (IsADigit(startChar)) { while (pos > 0 && IsADigit(cb.CharAt(pos))) --pos; if (!IsADigit(cb.CharAt(pos))) ++pos; } else if (IsPunctuation(startChar)) { while (pos > 0 && IsPunctuation(cb.CharAt(pos))) --pos; if (!IsPunctuation(cb.CharAt(pos))) ++pos; } else if (isspacechar(startChar)) { while (pos > 0 && isspacechar(cb.CharAt(pos))) --pos; if (!isspacechar(cb.CharAt(pos))) ++pos; } else if (!isascii(startChar)) { while (pos > 0 && !isascii(cb.CharAt(pos))) --pos; if (isascii(cb.CharAt(pos))) ++pos; } else { ++pos; } } } return pos; } int Document::WordPartRight(int pos) { char startChar = cb.CharAt(pos); int length = Length(); if (IsWordPartSeparator(startChar)) { while (pos < length && IsWordPartSeparator(cb.CharAt(pos))) ++pos; startChar = cb.CharAt(pos); } if (!isascii(startChar)) { while (pos < length && !isascii(cb.CharAt(pos))) ++pos; } else if (IsLowerCase(startChar)) { while (pos < length && IsLowerCase(cb.CharAt(pos))) ++pos; } else if (IsUpperCase(startChar)) { if (IsLowerCase(cb.CharAt(pos + 1))) { ++pos; while (pos < length && IsLowerCase(cb.CharAt(pos))) ++pos; } else { while (pos < length && IsUpperCase(cb.CharAt(pos))) ++pos; } if (IsLowerCase(cb.CharAt(pos)) && IsUpperCase(cb.CharAt(pos - 1))) --pos; } else if (IsADigit(startChar)) { while (pos < length && IsADigit(cb.CharAt(pos))) ++pos; } else if (IsPunctuation(startChar)) { while (pos < length && IsPunctuation(cb.CharAt(pos))) ++pos; } else if (isspacechar(startChar)) { while (pos < length && isspacechar(cb.CharAt(pos))) ++pos; } else { ++pos; } return pos; } bool IsLineEndChar(char c) { return (c == '\n' || c == '\r'); } int Document::ExtendStyleRange(int pos, int delta, bool singleLine) { int sStart = cb.StyleAt(pos); if (delta < 0) { while (pos > 0 && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) pos--; pos++; } else { while (pos < (Length()) && (cb.StyleAt(pos) == sStart) && (!singleLine || !IsLineEndChar(cb.CharAt(pos)))) pos++; } return pos; } static char BraceOpposite(char ch) { switch (ch) { case '(': return ')'; case ')': return '('; case '[': return ']'; case ']': return '['; case '{': return '}'; case '}': return '{'; case '<': return '>'; case '>': return '<'; default: return '\0'; } } // TODO: should be able to extend styled region to find matching brace int Document::BraceMatch(int position, int /*maxReStyle*/) { char chBrace = CharAt(position); char chSeek = BraceOpposite(chBrace); if (chSeek == '\0') return - 1; char styBrace = static_cast(StyleAt(position) & stylingBitsMask); int direction = -1; if (chBrace == '(' || chBrace == '[' || chBrace == '{' || chBrace == '<') direction = 1; int depth = 1; position = NextPosition(position, direction); while ((position >= 0) && (position < Length())) { char chAtPos = CharAt(position); char styAtPos = static_cast(StyleAt(position) & stylingBitsMask); if ((position > GetEndStyled()) || (styAtPos == styBrace)) { if (chAtPos == chBrace) depth++; if (chAtPos == chSeek) depth--; if (depth == 0) return position; } int positionBeforeMove = position; position = NextPosition(position, direction); if (position == positionBeforeMove) break; } return - 1; } /** * Implementation of RegexSearchBase for the default built-in regular expression engine */ class BuiltinRegex : public RegexSearchBase { public: BuiltinRegex(CharClassify *charClassTable) : search(charClassTable), substituted(NULL) {} virtual ~BuiltinRegex() { delete substituted; } virtual long FindText(Document *doc, int minPos, int maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, int flags, int *length); virtual const char *SubstituteByPosition(Document *doc, const char *text, int *length); private: RESearch search; char *substituted; }; // Define a way for the Regular Expression code to access the document class DocumentIndexer : public CharacterIndexer { Document *pdoc; int end; public: DocumentIndexer(Document *pdoc_, int end_) : pdoc(pdoc_), end(end_) { } virtual ~DocumentIndexer() { } virtual char CharAt(int index) { if (index < 0 || index >= end) return 0; else return pdoc->CharAt(index); } }; long BuiltinRegex::FindText(Document *doc, int minPos, int maxPos, const char *s, bool caseSensitive, bool, bool, int flags, int *length) { bool posix = (flags & SCFIND_POSIX) != 0; int increment = (minPos <= maxPos) ? 1 : -1; int startPos = minPos; int endPos = maxPos; // Range endpoints should not be inside DBCS characters, but just in case, move them. startPos = doc->MovePositionOutsideChar(startPos, 1, false); endPos = doc->MovePositionOutsideChar(endPos, 1, false); const char *errmsg = search.Compile(s, *length, caseSensitive, posix); if (errmsg) { return -1; } // Find a variable in a property file: \$(\([A-Za-z0-9_.]+\)) // Replace first '.' with '-' in each property file variable reference: // Search: \$(\([A-Za-z0-9_-]+\)\.\([A-Za-z0-9_.]+\)) // Replace: $(\1-\2) int lineRangeStart = doc->LineFromPosition(startPos); int lineRangeEnd = doc->LineFromPosition(endPos); if ((increment == 1) && (startPos >= doc->LineEnd(lineRangeStart)) && (lineRangeStart < lineRangeEnd)) { // the start position is at end of line or between line end characters. lineRangeStart++; startPos = doc->LineStart(lineRangeStart); } else if ((increment == -1) && (startPos <= doc->LineStart(lineRangeStart)) && (lineRangeStart > lineRangeEnd)) { // the start position is at beginning of line. lineRangeStart--; startPos = doc->LineEnd(lineRangeStart); } int pos = -1; int lenRet = 0; char searchEnd = s[*length - 1]; char searchEndPrev = (*length > 1) ? s[*length - 2] : '\0'; int lineRangeBreak = lineRangeEnd + increment; for (int line = lineRangeStart; line != lineRangeBreak; line += increment) { int startOfLine = doc->LineStart(line); int endOfLine = doc->LineEnd(line); if (increment == 1) { if (line == lineRangeStart) { if ((startPos != startOfLine) && (s[0] == '^')) continue; // Can't match start of line if start position after start of line startOfLine = startPos; } if (line == lineRangeEnd) { if ((endPos != endOfLine) && (searchEnd == '$') && (searchEndPrev != '\\')) continue; // Can't match end of line if end position before end of line endOfLine = endPos; } } else { if (line == lineRangeEnd) { if ((endPos != startOfLine) && (s[0] == '^')) continue; // Can't match start of line if end position after start of line startOfLine = endPos; } if (line == lineRangeStart) { if ((startPos != endOfLine) && (searchEnd == '$') && (searchEndPrev != '\\')) continue; // Can't match end of line if start position before end of line endOfLine = startPos; } } DocumentIndexer di(doc, endOfLine); int success = search.Execute(di, startOfLine, endOfLine); if (success) { pos = search.bopat[0]; lenRet = search.eopat[0] - search.bopat[0]; // There can be only one start of a line, so no need to look for last match in line if ((increment == -1) && (s[0] != '^')) { // Check for the last match on this line. int repetitions = 1000; // Break out of infinite loop while (success && (search.eopat[0] <= endOfLine) && (repetitions--)) { success = search.Execute(di, pos+1, endOfLine); if (success) { if (search.eopat[0] <= minPos) { pos = search.bopat[0]; lenRet = search.eopat[0] - search.bopat[0]; } else { success = 0; } } } } break; } } *length = lenRet; return pos; } const char *BuiltinRegex::SubstituteByPosition(Document *doc, const char *text, int *length) { delete []substituted; substituted = 0; DocumentIndexer di(doc, doc->Length()); if (!search.GrabMatches(di)) return 0; unsigned int lenResult = 0; for (int i = 0; i < *length; i++) { if (text[i] == '\\') { if (text[i + 1] >= '0' && text[i + 1] <= '9') { unsigned int patNum = text[i + 1] - '0'; lenResult += search.eopat[patNum] - search.bopat[patNum]; i++; } else { switch (text[i + 1]) { case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v': case '\\': i++; } lenResult++; } } else { lenResult++; } } substituted = new char[lenResult + 1]; char *o = substituted; for (int j = 0; j < *length; j++) { if (text[j] == '\\') { if (text[j + 1] >= '0' && text[j + 1] <= '9') { unsigned int patNum = text[j + 1] - '0'; unsigned int len = search.eopat[patNum] - search.bopat[patNum]; if (search.pat[patNum]) // Will be null if try for a match that did not occur memcpy(o, search.pat[patNum], len); o += len; j++; } else { j++; switch (text[j]) { case 'a': *o++ = '\a'; break; case 'b': *o++ = '\b'; break; case 'f': *o++ = '\f'; break; case 'n': *o++ = '\n'; break; case 'r': *o++ = '\r'; break; case 't': *o++ = '\t'; break; case 'v': *o++ = '\v'; break; case '\\': *o++ = '\\'; break; default: *o++ = '\\'; j--; } } } else { *o++ = text[j]; } } *o = '\0'; *length = lenResult; return substituted; } #ifndef SCI_OWNREGEX #ifdef SCI_NAMESPACE RegexSearchBase *Scintilla::CreateRegexSearch(CharClassify *charClassTable) { return new BuiltinRegex(charClassTable); } #else RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable) { return new BuiltinRegex(charClassTable); } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/KeyMap.cxx0000644000175000017500000001320711615412040020325 00000000000000// Scintilla source code edit control /** @file KeyMap.cxx ** Defines a mapping between keystrokes and commands. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include "Platform.h" #include "Scintilla.h" #include "KeyMap.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif KeyMap::KeyMap() : kmap(0), len(0), alloc(0) { for (int i = 0; MapDefault[i].key; i++) { AssignCmdKey(MapDefault[i].key, MapDefault[i].modifiers, MapDefault[i].msg); } } KeyMap::~KeyMap() { Clear(); } void KeyMap::Clear() { delete []kmap; kmap = 0; len = 0; alloc = 0; } void KeyMap::AssignCmdKey(int key, int modifiers, unsigned int msg) { if ((len+1) >= alloc) { KeyToCommand *ktcNew = new KeyToCommand[alloc + 5]; if (!ktcNew) return; for (int k = 0; k < len; k++) ktcNew[k] = kmap[k]; alloc += 5; delete []kmap; kmap = ktcNew; } for (int keyIndex = 0; keyIndex < len; keyIndex++) { if ((key == kmap[keyIndex].key) && (modifiers == kmap[keyIndex].modifiers)) { kmap[keyIndex].msg = msg; return; } } kmap[len].key = key; kmap[len].modifiers = modifiers; kmap[len].msg = msg; len++; } unsigned int KeyMap::Find(int key, int modifiers) { for (int i = 0; i < len; i++) { if ((key == kmap[i].key) && (modifiers == kmap[i].modifiers)) { return kmap[i].msg; } } return 0; } #if PLAT_GTK_MACOSX #define OS_X_KEYS 1 #else #define OS_X_KEYS 0 #endif // Define a modifier that is exactly Ctrl key on all platforms // Most uses of Ctrl map to Cmd on OS X but some can't so use SCI_[S]CTRL_META #if OS_X_KEYS #define SCI_CTRL_META SCI_META #define SCI_SCTRL_META (SCI_META | SCI_SHIFT) #else #define SCI_CTRL_META SCI_CTRL #define SCI_SCTRL_META (SCI_CTRL | SCI_SHIFT) #endif const KeyToCommand KeyMap::MapDefault[] = { #if OS_X_KEYS {SCK_DOWN, SCI_CTRL, SCI_DOCUMENTEND}, {SCK_DOWN, SCI_CSHIFT, SCI_DOCUMENTENDEXTEND}, {SCK_UP, SCI_CTRL, SCI_DOCUMENTSTART}, {SCK_UP, SCI_CSHIFT, SCI_DOCUMENTSTARTEXTEND}, {SCK_LEFT, SCI_CTRL, SCI_VCHOME}, {SCK_LEFT, SCI_CSHIFT, SCI_VCHOMEEXTEND}, {SCK_RIGHT, SCI_CTRL, SCI_LINEEND}, {SCK_RIGHT, SCI_CSHIFT, SCI_LINEENDEXTEND}, #endif {SCK_DOWN, SCI_NORM, SCI_LINEDOWN}, {SCK_DOWN, SCI_SHIFT, SCI_LINEDOWNEXTEND}, {SCK_DOWN, SCI_CTRL_META, SCI_LINESCROLLDOWN}, {SCK_DOWN, SCI_ASHIFT, SCI_LINEDOWNRECTEXTEND}, {SCK_UP, SCI_NORM, SCI_LINEUP}, {SCK_UP, SCI_SHIFT, SCI_LINEUPEXTEND}, {SCK_UP, SCI_CTRL_META, SCI_LINESCROLLUP}, {SCK_UP, SCI_ASHIFT, SCI_LINEUPRECTEXTEND}, {'[', SCI_CTRL, SCI_PARAUP}, {'[', SCI_CSHIFT, SCI_PARAUPEXTEND}, {']', SCI_CTRL, SCI_PARADOWN}, {']', SCI_CSHIFT, SCI_PARADOWNEXTEND}, {SCK_LEFT, SCI_NORM, SCI_CHARLEFT}, {SCK_LEFT, SCI_SHIFT, SCI_CHARLEFTEXTEND}, {SCK_LEFT, SCI_CTRL_META, SCI_WORDLEFT}, {SCK_LEFT, SCI_SCTRL_META, SCI_WORDLEFTEXTEND}, {SCK_LEFT, SCI_ASHIFT, SCI_CHARLEFTRECTEXTEND}, {SCK_RIGHT, SCI_NORM, SCI_CHARRIGHT}, {SCK_RIGHT, SCI_SHIFT, SCI_CHARRIGHTEXTEND}, {SCK_RIGHT, SCI_CTRL_META, SCI_WORDRIGHT}, {SCK_RIGHT, SCI_SCTRL_META, SCI_WORDRIGHTEXTEND}, {SCK_RIGHT, SCI_ASHIFT, SCI_CHARRIGHTRECTEXTEND}, {'/', SCI_CTRL, SCI_WORDPARTLEFT}, {'/', SCI_CSHIFT, SCI_WORDPARTLEFTEXTEND}, {'\\', SCI_CTRL, SCI_WORDPARTRIGHT}, {'\\', SCI_CSHIFT, SCI_WORDPARTRIGHTEXTEND}, {SCK_HOME, SCI_NORM, SCI_VCHOME}, {SCK_HOME, SCI_SHIFT, SCI_VCHOMEEXTEND}, {SCK_HOME, SCI_CTRL, SCI_DOCUMENTSTART}, {SCK_HOME, SCI_CSHIFT, SCI_DOCUMENTSTARTEXTEND}, {SCK_HOME, SCI_ALT, SCI_HOMEDISPLAY}, {SCK_HOME, SCI_ASHIFT, SCI_VCHOMERECTEXTEND}, {SCK_END, SCI_NORM, SCI_LINEEND}, {SCK_END, SCI_SHIFT, SCI_LINEENDEXTEND}, {SCK_END, SCI_CTRL, SCI_DOCUMENTEND}, {SCK_END, SCI_CSHIFT, SCI_DOCUMENTENDEXTEND}, {SCK_END, SCI_ALT, SCI_LINEENDDISPLAY}, {SCK_END, SCI_ASHIFT, SCI_LINEENDRECTEXTEND}, {SCK_PRIOR, SCI_NORM, SCI_PAGEUP}, {SCK_PRIOR, SCI_SHIFT, SCI_PAGEUPEXTEND}, {SCK_PRIOR, SCI_ASHIFT, SCI_PAGEUPRECTEXTEND}, {SCK_NEXT, SCI_NORM, SCI_PAGEDOWN}, {SCK_NEXT, SCI_SHIFT, SCI_PAGEDOWNEXTEND}, {SCK_NEXT, SCI_ASHIFT, SCI_PAGEDOWNRECTEXTEND}, {SCK_DELETE, SCI_NORM, SCI_CLEAR}, {SCK_DELETE, SCI_SHIFT, SCI_CUT}, {SCK_DELETE, SCI_CTRL, SCI_DELWORDRIGHT}, {SCK_DELETE, SCI_CSHIFT, SCI_DELLINERIGHT}, {SCK_INSERT, SCI_NORM, SCI_EDITTOGGLEOVERTYPE}, {SCK_INSERT, SCI_SHIFT, SCI_PASTE}, {SCK_INSERT, SCI_CTRL, SCI_COPY}, {SCK_ESCAPE, SCI_NORM, SCI_CANCEL}, {SCK_BACK, SCI_NORM, SCI_DELETEBACK}, {SCK_BACK, SCI_SHIFT, SCI_DELETEBACK}, {SCK_BACK, SCI_CTRL, SCI_DELWORDLEFT}, {SCK_BACK, SCI_ALT, SCI_UNDO}, {SCK_BACK, SCI_CSHIFT, SCI_DELLINELEFT}, {'Z', SCI_CTRL, SCI_UNDO}, #if OS_X_KEYS {'Z', SCI_CSHIFT, SCI_REDO}, #else {'Y', SCI_CTRL, SCI_REDO}, #endif {'X', SCI_CTRL, SCI_CUT}, {'C', SCI_CTRL, SCI_COPY}, {'V', SCI_CTRL, SCI_PASTE}, {'A', SCI_CTRL, SCI_SELECTALL}, {SCK_TAB, SCI_NORM, SCI_TAB}, {SCK_TAB, SCI_SHIFT, SCI_BACKTAB}, {SCK_RETURN, SCI_NORM, SCI_NEWLINE}, {SCK_RETURN, SCI_SHIFT, SCI_NEWLINE}, {SCK_ADD, SCI_CTRL, SCI_ZOOMIN}, {SCK_SUBTRACT, SCI_CTRL, SCI_ZOOMOUT}, {SCK_DIVIDE, SCI_CTRL, SCI_SETZOOM}, {'L', SCI_CTRL, SCI_LINECUT}, {'L', SCI_CSHIFT, SCI_LINEDELETE}, {'T', SCI_CSHIFT, SCI_LINECOPY}, {'T', SCI_CTRL, SCI_LINETRANSPOSE}, {'D', SCI_CTRL, SCI_SELECTIONDUPLICATE}, {'U', SCI_CTRL, SCI_LOWERCASE}, {'U', SCI_CSHIFT, SCI_UPPERCASE}, {0,0,0}, }; presage-0.8.8/apps/gtk/gprompter/scintilla/src/KeyMap.h0000644000175000017500000000175011615412040017752 00000000000000// Scintilla source code edit control /** @file KeyMap.h ** Defines a mapping between keystrokes and commands. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef KEYTOCOMMAND_H #define KEYTOCOMMAND_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif #define SCI_NORM 0 #define SCI_SHIFT SCMOD_SHIFT #define SCI_CTRL SCMOD_CTRL #define SCI_ALT SCMOD_ALT #define SCI_META SCMOD_META #define SCI_CSHIFT (SCI_CTRL | SCI_SHIFT) #define SCI_ASHIFT (SCI_ALT | SCI_SHIFT) /** */ class KeyToCommand { public: int key; int modifiers; unsigned int msg; }; /** */ class KeyMap { KeyToCommand *kmap; int len; int alloc; static const KeyToCommand MapDefault[]; public: KeyMap(); ~KeyMap(); void Clear(); void AssignCmdKey(int key, int modifiers, unsigned int msg); unsigned int Find(int key, int modifiers); // 0 returned on failure }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/CharClassify.h0000644000175000017500000000162411615412040021137 00000000000000// Scintilla source code edit control /** @file CharClassify.h ** Character classifications used by Document and RESearch. **/ // Copyright 2006-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CHARCLASSIFY_H #define CHARCLASSIFY_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class CharClassify { public: CharClassify(); enum cc { ccSpace, ccNewLine, ccWord, ccPunctuation }; void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, cc newCharClass); cc GetClass(unsigned char ch) const { return static_cast(charClass[ch]);} bool IsWord(unsigned char ch) const { return static_cast(charClass[ch]) == ccWord;} private: enum { maxChar=256 }; unsigned char charClass[maxChar]; // not type cc to save space }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/SciTE.properties0000644000175000017500000000046111763437013021511 00000000000000# SciTE.properties is the per directory local options file and can be used to override # settings made in SciTEGlobal.properties command.build.directory.*.cxx=..\win32 command.build.directory.*.h=..\win32 command.build.*.cxx=nmake -f scintilla.mak QUIET=1 command.build.*.h=nmake -f scintilla.mak QUIET=1 presage-0.8.8/apps/gtk/gprompter/scintilla/src/PositionCache.h0000644000175000017500000001047311710634267021333 00000000000000// Scintilla source code edit control /** @file PositionCache.h ** Classes for caching layout information. **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef POSITIONCACHE_H #define POSITIONCACHE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif static inline bool IsEOLChar(char ch) { return (ch == '\r') || (ch == '\n'); } /** */ class LineLayout { private: friend class LineLayoutCache; int *lineStarts; int lenLineStarts; /// Drawing is only performed for @a maxLineLength characters on each line. int lineNumber; bool inCache; public: enum { wrapWidthInfinite = 0x7ffffff }; int maxLineLength; int numCharsInLine; int numCharsBeforeEOL; enum validLevel { llInvalid, llCheckTextAndStyle, llPositions, llLines } validity; int xHighlightGuide; bool highlightColumn; Selection *psel; bool containsCaret; int edgeColumn; char *chars; unsigned char *styles; int styleBitsSet; char *indicators; XYPOSITION *positions; char bracePreviousStyles[2]; // Hotspot support int hsStart; int hsEnd; // Wrapped line support int widthLine; int lines; XYPOSITION wrapIndent; // In pixels LineLayout(int maxLineLength_); virtual ~LineLayout(); void Resize(int maxLineLength_); void Free(); void Invalidate(validLevel validity_); int LineStart(int line) const; int LineLastVisible(int line) const; bool InLine(int offset, int line) const; void SetLineStart(int line, int start); void SetBracesHighlight(Range rangeLine, Position braces[], char bracesMatchStyle, int xHighlight, bool ignoreStyle); void RestoreBracesHighlight(Range rangeLine, Position braces[], bool ignoreStyle); int FindBefore(XYPOSITION x, int lower, int upper) const; int EndLineStyle() const; }; /** */ class LineLayoutCache { int level; int length; int size; LineLayout **cache; bool allInvalidated; int styleClock; int useCount; void Allocate(int length_); void AllocateForLevel(int linesOnScreen, int linesInDoc); public: LineLayoutCache(); virtual ~LineLayoutCache(); void Deallocate(); enum { llcNone=SC_CACHE_NONE, llcCaret=SC_CACHE_CARET, llcPage=SC_CACHE_PAGE, llcDocument=SC_CACHE_DOCUMENT }; void Invalidate(LineLayout::validLevel validity_); void SetLevel(int level_); int GetLevel() const { return level; } LineLayout *Retrieve(int lineNumber, int lineCaret, int maxChars, int styleClock_, int linesOnScreen, int linesInDoc); void Dispose(LineLayout *ll); }; class PositionCacheEntry { unsigned int styleNumber:8; unsigned int len:8; unsigned int clock:16; XYPOSITION *positions; public: PositionCacheEntry(); ~PositionCacheEntry(); void Set(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock); void Clear(); bool Retrieve(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_) const; static int Hash(unsigned int styleNumber_, const char *s, unsigned int len); bool NewerThan(const PositionCacheEntry &other) const; void ResetClock(); }; // Class to break a line of text into shorter runs at sensible places. class BreakFinder { LineLayout *ll; int lineStart; int lineEnd; int posLineStart; int nextBreak; int *selAndEdge; unsigned int saeSize; unsigned int saeLen; unsigned int saeCurrentPos; int saeNext; int subBreak; Document *pdoc; void Insert(int val); public: // If a whole run is longer than lengthStartSubdivision then subdivide // into smaller runs at spaces or punctuation. enum { lengthStartSubdivision = 300 }; // Try to make each subdivided run lengthEachSubdivision or shorter. enum { lengthEachSubdivision = 100 }; BreakFinder(LineLayout *ll_, int lineStart_, int lineEnd_, int posLineStart_, int xStart, bool breakForSelection, Document *pdoc_); ~BreakFinder(); int First() const; int Next(); }; class PositionCache { PositionCacheEntry *pces; size_t size; unsigned int clock; bool allClear; public: PositionCache(); ~PositionCache(); void Clear(); void SetSize(size_t size_); size_t GetSize() const { return size; } void MeasureWidths(Surface *surface, ViewStyle &vstyle, unsigned int styleNumber, const char *s, unsigned int len, XYPOSITION *positions, Document *pdoc); }; inline bool IsSpaceOrTab(int ch) { return ch == ' ' || ch == '\t'; } #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/UniConversion.cxx0000644000175000017500000001546311763437013021761 00000000000000// Scintilla source code edit control /** @file UniConversion.cxx ** Functions to handle UTF-8 and UTF-16 strings. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include "UniConversion.h" enum { SURROGATE_LEAD_FIRST = 0xD800 }; enum { SURROGATE_TRAIL_FIRST = 0xDC00 }; enum { SURROGATE_TRAIL_LAST = 0xDFFF }; unsigned int UTF8Length(const wchar_t *uptr, unsigned int tlen) { unsigned int len = 0; for (unsigned int i = 0; i < tlen && uptr[i];) { unsigned int uch = uptr[i]; if (uch < 0x80) { len++; } else if (uch < 0x800) { len += 2; } else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST)) { len += 4; i++; } else { len += 3; } i++; } return len; } void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned int len) { int k = 0; for (unsigned int i = 0; i < tlen && uptr[i];) { unsigned int uch = uptr[i]; if (uch < 0x80) { putf[k++] = static_cast(uch); } else if (uch < 0x800) { putf[k++] = static_cast(0xC0 | (uch >> 6)); putf[k++] = static_cast(0x80 | (uch & 0x3f)); } else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST)) { // Half a surrogate pair i++; unsigned int xch = 0x10000 + ((uch & 0x3ff) << 10) + (uptr[i] & 0x3ff); putf[k++] = static_cast(0xF0 | (xch >> 18)); putf[k++] = static_cast(0x80 | ((xch >> 12) & 0x3f)); putf[k++] = static_cast(0x80 | ((xch >> 6) & 0x3f)); putf[k++] = static_cast(0x80 | (xch & 0x3f)); } else { putf[k++] = static_cast(0xE0 | (uch >> 12)); putf[k++] = static_cast(0x80 | ((uch >> 6) & 0x3f)); putf[k++] = static_cast(0x80 | (uch & 0x3f)); } i++; } putf[len] = '\0'; } unsigned int UTF8CharLength(unsigned char ch) { if (ch < 0x80) { return 1; } else if (ch < 0x80 + 0x40 + 0x20) { return 2; } else if (ch < 0x80 + 0x40 + 0x20 + 0x10) { return 3; } else { return 4; } } unsigned int UTF16Length(const char *s, unsigned int len) { unsigned int ulen = 0; unsigned int charLen; for (unsigned int i=0; i(s[i]); if (ch < 0x80) { charLen = 1; } else if (ch < 0x80 + 0x40 + 0x20) { charLen = 2; } else if (ch < 0x80 + 0x40 + 0x20 + 0x10) { charLen = 3; } else { charLen = 4; ulen++; } i += charLen; ulen++; } return ulen; } unsigned int UTF16FromUTF8(const char *s, unsigned int len, wchar_t *tbuf, unsigned int tlen) { unsigned int ui=0; const unsigned char *us = reinterpret_cast(s); unsigned int i=0; while ((i((ch & 0x1F) << 6); ch = us[i++]; tbuf[ui] = static_cast(tbuf[ui] + (ch & 0x7F)); } else if (ch < 0x80 + 0x40 + 0x20 + 0x10) { tbuf[ui] = static_cast((ch & 0xF) << 12); ch = us[i++]; tbuf[ui] = static_cast(tbuf[ui] + ((ch & 0x7F) << 6)); ch = us[i++]; tbuf[ui] = static_cast(tbuf[ui] + (ch & 0x7F)); } else { // Outside the BMP so need two surrogates int val = (ch & 0x7) << 18; ch = us[i++]; val += (ch & 0x3F) << 12; ch = us[i++]; val += (ch & 0x3F) << 6; ch = us[i++]; val += (ch & 0x3F); tbuf[ui] = static_cast(((val - 0x10000) >> 10) + SURROGATE_LEAD_FIRST); ui++; tbuf[ui] = static_cast((val & 0x3ff) + SURROGATE_TRAIL_FIRST); } ui++; } return ui; } int UTF8BytesOfLead[256]; static bool initialisedBytesOfLead = false; static int BytesFromLead(int leadByte) { if (leadByte < 0xC2) { // Single byte or invalid return 1; } else if (leadByte < 0xE0) { return 2; } else if (leadByte < 0xF0) { return 3; } else if (leadByte < 0xF5) { return 4; } else { // Characters longer than 4 bytes not possible in current UTF-8 return 1; } } void UTF8BytesOfLeadInitialise() { if (!initialisedBytesOfLead) { for (int i=0;i<256;i++) { UTF8BytesOfLead[i] = BytesFromLead(i); } initialisedBytesOfLead = true; } } // Return both the width of the first character in the string and a status // saying whether it is valid or invalid. // Most invalid sequences return a width of 1 so are treated as isolated bytes but // the non-characters *FFFE, *FFFF and FDD0 .. FDEF return 3 or 4 as they can be // reasonably treated as code points in some circumstances. They will, however, // not have associated glyphs. int UTF8Classify(const unsigned char *us, int len) { // For the rules: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 if (*us < 0x80) { // Single bytes easy return 1; } else if (*us > 0xf4) { // Characters longer than 4 bytes not possible in current UTF-8 return UTF8MaskInvalid | 1; } else if (*us >= 0xf0) { // 4 bytes if (len < 4) return UTF8MaskInvalid | 1; if (UTF8IsTrailByte(us[1]) && UTF8IsTrailByte(us[2]) && UTF8IsTrailByte(us[3])) { if (((us[1] & 0xf) == 0xf) && (us[2] == 0xbf) && ((us[3] == 0xbe) || (us[3] == 0xbf))) { // *FFFE or *FFFF non-character return UTF8MaskInvalid | 4; } if (*us == 0xf4) { // Check if encoding a value beyond the last Unicode character 10FFFF if (us[1] > 0x8f) { return UTF8MaskInvalid | 1; } else if (us[1] == 0x8f) { if (us[2] > 0xbf) { return UTF8MaskInvalid | 1; } else if (us[2] == 0xbf) { if (us[3] > 0xbf) { return UTF8MaskInvalid | 1; } } } } else if ((*us == 0xf0) && ((us[1] & 0xf0) == 0x80)) { // Overlong return UTF8MaskInvalid | 1; } return 4; } else { return UTF8MaskInvalid | 1; } } else if (*us >= 0xe0) { // 3 bytes if (len < 3) return UTF8MaskInvalid | 1; if (UTF8IsTrailByte(us[1]) && UTF8IsTrailByte(us[2])) { if ((*us == 0xe0) && ((us[1] & 0xe0) == 0x80)) { // Overlong return UTF8MaskInvalid | 1; } if ((*us == 0xed) && ((us[1] & 0xe0) == 0xa0)) { // Surrogate return UTF8MaskInvalid | 1; } if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbe)) { // U+FFFE non-character - 3 bytes long return UTF8MaskInvalid | 3; } if ((*us == 0xef) && (us[1] == 0xbf) && (us[2] == 0xbf)) { // U+FFFF non-character - 3 bytes long return UTF8MaskInvalid | 3; } if ((*us == 0xef) && (us[1] == 0xb7) && (((us[2] & 0xf0) == 0x90) || ((us[2] & 0xf0) == 0xa0))) { // U+FDD0 .. U+FDEF return UTF8MaskInvalid | 3; } return 3; } else { return UTF8MaskInvalid | 1; } } else if (*us >= 0xc2) { // 2 bytes if (len < 2) return UTF8MaskInvalid | 1; if (UTF8IsTrailByte(us[1])) { return 2; } else { return UTF8MaskInvalid | 1; } } else { // 0xc0 .. 0xc1 is overlong encoding // 0x80 .. 0xbf is trail byte return UTF8MaskInvalid | 1; } } presage-0.8.8/apps/gtk/gprompter/scintilla/src/RunStyles.h0000644000175000017500000000240511615412040020532 00000000000000/** @file RunStyles.h ** Data structure used to store sparse styles. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. /// Styling buffer using one element for each run rather than using /// a filled buffer. #ifndef RUNSTYLES_H #define RUNSTYLES_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class RunStyles { private: Partitioning *starts; SplitVector *styles; int RunFromPosition(int position) const; int SplitRun(int position); void RemoveRun(int run); void RemoveRunIfEmpty(int run); void RemoveRunIfSameAsPrevious(int run); public: RunStyles(); ~RunStyles(); int Length() const; int ValueAt(int position) const; int FindNextChange(int position, int end); int StartRun(int position); int EndRun(int position); // Returns true if some values may have changed bool FillRange(int &position, int value, int &fillLength); void SetValueAt(int position, int value); void InsertSpace(int position, int insertLength); void DeleteAll(); void DeleteRange(int position, int deleteLength); int Runs() const; bool AllSame() const; bool AllSameAs(int value) const; int Find(int value, int start) const; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/Catalogue.cxx0000644000175000017500000001065411763437013021061 00000000000000// Scintilla source code edit control /** @file KeyWords.cxx ** Colourise for particular languages. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "LexerModule.h" #include "Catalogue.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static std::vector lexerCatalogue; static int nextLanguage = SCLEX_AUTOMATIC+1; const LexerModule *Catalogue::Find(int language) { Scintilla_LinkLexers(); for (std::vector::iterator it=lexerCatalogue.begin(); it != lexerCatalogue.end(); ++it) { if ((*it)->GetLanguage() == language) { return *it; } } return 0; } const LexerModule *Catalogue::Find(const char *languageName) { Scintilla_LinkLexers(); if (languageName) { for (std::vector::iterator it=lexerCatalogue.begin(); it != lexerCatalogue.end(); ++it) { if ((*it)->languageName && (0 == strcmp((*it)->languageName, languageName))) { return *it; } } } return 0; } void Catalogue::AddLexerModule(LexerModule *plm) { if (plm->GetLanguage() == SCLEX_AUTOMATIC) { plm->language = nextLanguage; nextLanguage++; } lexerCatalogue.push_back(plm); } // Alternative historical name for Scintilla_LinkLexers int wxForceScintillaLexers(void) { return Scintilla_LinkLexers(); } // To add or remove a lexer, add or remove its file and run LexGen.py. // Force a reference to all of the Scintilla lexers so that the linker will // not remove the code of the lexers. int Scintilla_LinkLexers() { static int initialised = 0; if (initialised) return 0; initialised = 1; // Shorten the code that declares a lexer and ensures it is linked in by calling a method. #define LINK_LEXER(lexer) extern LexerModule lexer; Catalogue::AddLexerModule(&lexer); //++Autogenerated -- run src/LexGen.py to regenerate //**\(\tLINK_LEXER(\*);\n\) LINK_LEXER(lmA68k); LINK_LEXER(lmAbaqus); LINK_LEXER(lmAda); LINK_LEXER(lmAns1); LINK_LEXER(lmAPDL); LINK_LEXER(lmAsm); LINK_LEXER(lmASY); LINK_LEXER(lmAU3); LINK_LEXER(lmAVE); LINK_LEXER(lmAVS); LINK_LEXER(lmBaan); LINK_LEXER(lmBash); LINK_LEXER(lmBatch); LINK_LEXER(lmBlitzBasic); LINK_LEXER(lmBullant); LINK_LEXER(lmCaml); LINK_LEXER(lmClw); LINK_LEXER(lmClwNoCase); LINK_LEXER(lmCmake); LINK_LEXER(lmCOBOL); LINK_LEXER(lmCoffeeScript); LINK_LEXER(lmConf); LINK_LEXER(lmCPP); LINK_LEXER(lmCPPNoCase); LINK_LEXER(lmCsound); LINK_LEXER(lmCss); LINK_LEXER(lmD); LINK_LEXER(lmDiff); LINK_LEXER(lmECL); LINK_LEXER(lmEiffel); LINK_LEXER(lmEiffelkw); LINK_LEXER(lmErlang); LINK_LEXER(lmErrorList); LINK_LEXER(lmESCRIPT); LINK_LEXER(lmF77); LINK_LEXER(lmFlagShip); LINK_LEXER(lmForth); LINK_LEXER(lmFortran); LINK_LEXER(lmFreeBasic); LINK_LEXER(lmGAP); LINK_LEXER(lmGui4Cli); LINK_LEXER(lmHaskell); LINK_LEXER(lmHTML); LINK_LEXER(lmInno); LINK_LEXER(lmKix); LINK_LEXER(lmLatex); LINK_LEXER(lmLISP); LINK_LEXER(lmLot); LINK_LEXER(lmLout); LINK_LEXER(lmLua); LINK_LEXER(lmMagikSF); LINK_LEXER(lmMake); LINK_LEXER(lmMarkdown); LINK_LEXER(lmMatlab); LINK_LEXER(lmMETAPOST); LINK_LEXER(lmMMIXAL); LINK_LEXER(lmModula); LINK_LEXER(lmMSSQL); LINK_LEXER(lmMySQL); LINK_LEXER(lmNimrod); LINK_LEXER(lmNncrontab); LINK_LEXER(lmNsis); LINK_LEXER(lmNull); LINK_LEXER(lmOctave); LINK_LEXER(lmOpal); LINK_LEXER(lmOScript); LINK_LEXER(lmPascal); LINK_LEXER(lmPB); LINK_LEXER(lmPerl); LINK_LEXER(lmPHPSCRIPT); LINK_LEXER(lmPLM); LINK_LEXER(lmPo); LINK_LEXER(lmPOV); LINK_LEXER(lmPowerPro); LINK_LEXER(lmPowerShell); LINK_LEXER(lmProgress); LINK_LEXER(lmProps); LINK_LEXER(lmPS); LINK_LEXER(lmPureBasic); LINK_LEXER(lmPython); LINK_LEXER(lmR); LINK_LEXER(lmREBOL); LINK_LEXER(lmRuby); LINK_LEXER(lmScriptol); LINK_LEXER(lmSmalltalk); LINK_LEXER(lmSML); LINK_LEXER(lmSorc); LINK_LEXER(lmSpecman); LINK_LEXER(lmSpice); LINK_LEXER(lmSQL); LINK_LEXER(lmTACL); LINK_LEXER(lmTADS3); LINK_LEXER(lmTAL); LINK_LEXER(lmTCL); LINK_LEXER(lmTCMD); LINK_LEXER(lmTeX); LINK_LEXER(lmTxt2tags); LINK_LEXER(lmVB); LINK_LEXER(lmVBScript); LINK_LEXER(lmVerilog); LINK_LEXER(lmVHDL); LINK_LEXER(lmVisualProlog); LINK_LEXER(lmXML); LINK_LEXER(lmYAML); //--Autogenerated -- end of automatically generated section return 1; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/CharClassify.cxx0000644000175000017500000000232711615412040021513 00000000000000// Scintilla source code edit control /** @file CharClassify.cxx ** Character classifications used by Document and RESearch. **/ // Copyright 2006 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "CharClassify.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER #pragma warning(disable: 4514) #endif CharClassify::CharClassify() { SetDefaultCharClasses(true); } void CharClassify::SetDefaultCharClasses(bool includeWordClass) { // Initialize all char classes to default values for (int ch = 0; ch < 256; ch++) { if (ch == '\r' || ch == '\n') charClass[ch] = ccNewLine; else if (ch < 0x20 || ch == ' ') charClass[ch] = ccSpace; else if (includeWordClass && (ch >= 0x80 || isalnum(ch) || ch == '_')) charClass[ch] = ccWord; else charClass[ch] = ccPunctuation; } } void CharClassify::SetCharClasses(const unsigned char *chars, cc newCharClass) { // Apply the newCharClass to the specifed chars if (chars) { while (*chars) { charClass[*chars] = static_cast(newCharClass); chars++; } } } presage-0.8.8/apps/gtk/gprompter/scintilla/src/CallTip.h0000644000175000017500000000501111652104216020112 00000000000000// Scintilla source code edit control /** @file CallTip.h ** Interface to the call tip control. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CALLTIP_H #define CALLTIP_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class CallTip { int startHighlight; // character offset to start and... int endHighlight; // ...end of highlighted text char *val; Font font; PRectangle rectUp; // rectangle of last up angle in the tip PRectangle rectDown; // rectangle of last down arrow in the tip int lineHeight; // vertical line spacing int offsetMain; // The alignment point of the call tip int tabSize; // Tab size in pixels, <=0 no TAB expand bool useStyleCallTip; // if true, STYLE_CALLTIP should be used bool above; // if true, display calltip above text // Private so CallTip objects can not be copied CallTip(const CallTip &); CallTip &operator=(const CallTip &); void DrawChunk(Surface *surface, int &x, const char *s, int posStart, int posEnd, int ytext, PRectangle rcClient, bool highlight, bool draw); int PaintContents(Surface *surfaceWindow, bool draw); bool IsTabCharacter(char c) const; int NextTabPos(int x); public: Window wCallTip; Window wDraw; bool inCallTipMode; int posStartCallTip; ColourDesired colourBG; ColourDesired colourUnSel; ColourDesired colourSel; ColourDesired colourShade; ColourDesired colourLight; int codePage; int clickPlace; CallTip(); ~CallTip(); void PaintCT(Surface *surfaceWindow); void MouseClick(Point pt); /// Setup the calltip and return a rectangle of the area required. PRectangle CallTipStart(int pos, Point pt, int textHeight, const char *defn, const char *faceName, int size, int codePage_, int characterSet, int technology, Window &wParent); void CallTipCancel(); /// Set a range of characters to be displayed in a highlight style. /// Commonly used to highlight the current parameter. void SetHighlight(int start, int end); /// Set the tab size in pixels for the call tip. 0 or -ve means no tab expand. void SetTabSize(int tabSz); /// Set calltip position. void SetPosition(bool aboveText); /// Used to determine which STYLE_xxxx to use for call tip information bool UseStyleCallTip() const { return useStyleCallTip;} // Modify foreground and background colours void SetForeBack(const ColourDesired &fore, const ColourDesired &back); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/PerLine.cxx0000644000175000017500000003033111763437013020505 00000000000000// Scintilla source code edit control /** @file PerLine.cxx ** Manages data associated with each line of the document **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include "Platform.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "CellBuffer.h" #include "PerLine.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif MarkerHandleSet::MarkerHandleSet() { root = 0; } MarkerHandleSet::~MarkerHandleSet() { MarkerHandleNumber *mhn = root; while (mhn) { MarkerHandleNumber *mhnToFree = mhn; mhn = mhn->next; delete mhnToFree; } root = 0; } int MarkerHandleSet::Length() const { int c = 0; MarkerHandleNumber *mhn = root; while (mhn) { c++; mhn = mhn->next; } return c; } int MarkerHandleSet::NumberFromHandle(int handle) const { MarkerHandleNumber *mhn = root; while (mhn) { if (mhn->handle == handle) { return mhn->number; } mhn = mhn->next; } return - 1; } int MarkerHandleSet::MarkValue() const { unsigned int m = 0; MarkerHandleNumber *mhn = root; while (mhn) { m |= (1 << mhn->number); mhn = mhn->next; } return m; } bool MarkerHandleSet::Contains(int handle) const { MarkerHandleNumber *mhn = root; while (mhn) { if (mhn->handle == handle) { return true; } mhn = mhn->next; } return false; } bool MarkerHandleSet::InsertHandle(int handle, int markerNum) { MarkerHandleNumber *mhn = new MarkerHandleNumber; if (!mhn) return false; mhn->handle = handle; mhn->number = markerNum; mhn->next = root; root = mhn; return true; } void MarkerHandleSet::RemoveHandle(int handle) { MarkerHandleNumber **pmhn = &root; while (*pmhn) { MarkerHandleNumber *mhn = *pmhn; if (mhn->handle == handle) { *pmhn = mhn->next; delete mhn; return; } pmhn = &((*pmhn)->next); } } bool MarkerHandleSet::RemoveNumber(int markerNum) { bool performedDeletion = false; MarkerHandleNumber **pmhn = &root; while (*pmhn) { MarkerHandleNumber *mhn = *pmhn; if (mhn->number == markerNum) { *pmhn = mhn->next; delete mhn; performedDeletion = true; } else { pmhn = &((*pmhn)->next); } } return performedDeletion; } void MarkerHandleSet::CombineWith(MarkerHandleSet *other) { MarkerHandleNumber **pmhn = &root; while (*pmhn) { pmhn = &((*pmhn)->next); } *pmhn = other->root; other->root = 0; } LineMarkers::~LineMarkers() { Init(); } void LineMarkers::Init() { for (int line = 0; line < markers.Length(); line++) { delete markers[line]; markers[line] = 0; } markers.DeleteAll(); } void LineMarkers::InsertLine(int line) { if (markers.Length()) { markers.Insert(line, 0); } } void LineMarkers::RemoveLine(int line) { // Retain the markers from the deleted line by oring them into the previous line if (markers.Length()) { if (line > 0) { MergeMarkers(line - 1); } markers.Delete(line); } } int LineMarkers::LineFromHandle(int markerHandle) { if (markers.Length()) { for (int line = 0; line < markers.Length(); line++) { if (markers[line]) { if (markers[line]->Contains(markerHandle)) { return line; } } } } return -1; } void LineMarkers::MergeMarkers(int pos) { if (markers[pos + 1] != NULL) { if (markers[pos] == NULL) markers[pos] = new MarkerHandleSet; markers[pos]->CombineWith(markers[pos + 1]); delete markers[pos + 1]; markers[pos + 1] = NULL; } } int LineMarkers::MarkValue(int line) { if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) return markers[line]->MarkValue(); else return 0; } int LineMarkers::MarkerNext(int lineStart, int mask) const { if (lineStart < 0) lineStart = 0; int length = markers.Length(); for (int iLine = lineStart; iLine < length; iLine++) { MarkerHandleSet *onLine = markers[iLine]; if (onLine && ((onLine->MarkValue() & mask) != 0)) //if ((pdoc->GetMark(iLine) & lParam) != 0) return iLine; } return -1; } int LineMarkers::AddMark(int line, int markerNum, int lines) { handleCurrent++; if (!markers.Length()) { // No existing markers so allocate one element per line markers.InsertValue(0, lines, 0); } if (line >= markers.Length()) { return -1; } if (!markers[line]) { // Need new structure to hold marker handle markers[line] = new MarkerHandleSet(); if (!markers[line]) return -1; } markers[line]->InsertHandle(handleCurrent, markerNum); return handleCurrent; } bool LineMarkers::DeleteMark(int line, int markerNum, bool all) { bool someChanges = false; if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) { if (markerNum == -1) { someChanges = true; delete markers[line]; markers[line] = NULL; } else { bool performedDeletion = markers[line]->RemoveNumber(markerNum); someChanges = someChanges || performedDeletion; while (all && performedDeletion) { performedDeletion = markers[line]->RemoveNumber(markerNum); someChanges = someChanges || performedDeletion; } if (markers[line]->Length() == 0) { delete markers[line]; markers[line] = NULL; } } } return someChanges; } void LineMarkers::DeleteMarkFromHandle(int markerHandle) { int line = LineFromHandle(markerHandle); if (line >= 0) { markers[line]->RemoveHandle(markerHandle); if (markers[line]->Length() == 0) { delete markers[line]; markers[line] = NULL; } } } LineLevels::~LineLevels() { } void LineLevels::Init() { levels.DeleteAll(); } void LineLevels::InsertLine(int line) { if (levels.Length()) { int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE; levels.InsertValue(line, 1, level); } } void LineLevels::RemoveLine(int line) { if (levels.Length()) { // Move up following lines but merge header flag from this line // to line before to avoid a temporary disappearence causing expansion. int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG; levels.Delete(line); if (line == levels.Length()-1) // Last line loses the header flag levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG; else if (line > 0) levels[line-1] |= firstHeader; } } void LineLevels::ExpandLevels(int sizeNew) { levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE); } void LineLevels::ClearLevels() { levels.DeleteAll(); } int LineLevels::SetLevel(int line, int level, int lines) { int prev = 0; if ((line >= 0) && (line < lines)) { if (!levels.Length()) { ExpandLevels(lines + 1); } prev = levels[line]; if (prev != level) { levels[line] = level; } } return prev; } int LineLevels::GetLevel(int line) { if (levels.Length() && (line >= 0) && (line < levels.Length())) { return levels[line]; } else { return SC_FOLDLEVELBASE; } } LineState::~LineState() { } void LineState::Init() { lineStates.DeleteAll(); } void LineState::InsertLine(int line) { if (lineStates.Length()) { lineStates.EnsureLength(line); int val = (line < lineStates.Length()) ? lineStates[line] : 0; lineStates.Insert(line, val); } } void LineState::RemoveLine(int line) { if (lineStates.Length() > line) { lineStates.Delete(line); } } int LineState::SetLineState(int line, int state) { lineStates.EnsureLength(line + 1); int stateOld = lineStates[line]; lineStates[line] = state; return stateOld; } int LineState::GetLineState(int line) { if (line < 0) return 0; lineStates.EnsureLength(line + 1); return lineStates[line]; } int LineState::GetMaxLineState() { return lineStates.Length(); } static int NumberLines(const char *text) { if (text) { int newLines = 0; while (*text) { if (*text == '\n') newLines++; text++; } return newLines+1; } else { return 0; } } // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader // and then has text and optional styles. static const int IndividualStyles = 0x100; struct AnnotationHeader { short style; // Style IndividualStyles implies array of styles short lines; int length; }; LineAnnotation::~LineAnnotation() { ClearAll(); } void LineAnnotation::Init() { ClearAll(); } void LineAnnotation::InsertLine(int line) { if (annotations.Length()) { annotations.EnsureLength(line); annotations.Insert(line, 0); } } void LineAnnotation::RemoveLine(int line) { if (annotations.Length() && (line < annotations.Length())) { delete []annotations[line]; annotations.Delete(line); } } bool LineAnnotation::AnySet() const { return annotations.Length() > 0; } bool LineAnnotation::MultipleStyles(int line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line])->style == IndividualStyles; else return 0; } int LineAnnotation::Style(int line) { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line])->style; else return 0; } const char *LineAnnotation::Text(int line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return annotations[line]+sizeof(AnnotationHeader); else return 0; } const unsigned char *LineAnnotation::Styles(int line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line)) return reinterpret_cast(annotations[line] + sizeof(AnnotationHeader) + Length(line)); else return 0; } static char *AllocateAnnotation(int length, int style) { size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0); char *ret = new char[len]; memset(ret, 0, len); return ret; } void LineAnnotation::SetText(int line, const char *text) { if (text && (line >= 0)) { annotations.EnsureLength(line+1); int style = Style(line); if (annotations[line]) { delete []annotations[line]; } annotations[line] = AllocateAnnotation(static_cast(strlen(text)), style); AnnotationHeader *pah = reinterpret_cast(annotations[line]); pah->style = static_cast(style); pah->length = static_cast(strlen(text)); pah->lines = static_cast(NumberLines(text)); memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length); } else { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) { delete []annotations[line]; annotations[line] = 0; } } } void LineAnnotation::ClearAll() { for (int line = 0; line < annotations.Length(); line++) { delete []annotations[line]; annotations[line] = 0; } annotations.DeleteAll(); } void LineAnnotation::SetStyle(int line, int style) { annotations.EnsureLength(line+1); if (!annotations[line]) { annotations[line] = AllocateAnnotation(0, style); } reinterpret_cast(annotations[line])->style = static_cast(style); } void LineAnnotation::SetStyles(int line, const unsigned char *styles) { if (line >= 0) { annotations.EnsureLength(line+1); if (!annotations[line]) { annotations[line] = AllocateAnnotation(0, IndividualStyles); } else { AnnotationHeader *pahSource = reinterpret_cast(annotations[line]); if (pahSource->style != IndividualStyles) { char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles); AnnotationHeader *pahAlloc = reinterpret_cast(allocation); pahAlloc->length = pahSource->length; pahAlloc->lines = pahSource->lines; memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length); delete []annotations[line]; annotations[line] = allocation; } } AnnotationHeader *pah = reinterpret_cast(annotations[line]); pah->style = IndividualStyles; memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length); } } int LineAnnotation::Length(int line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line])->length; else return 0; } int LineAnnotation::Lines(int line) const { if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) return reinterpret_cast(annotations[line])->lines; else return 0; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Document.h0000644000175000017500000003636211763437013020364 00000000000000// Scintilla source code edit control /** @file Document.h ** Text document that handles notifications, DBCS, styling, words and end of line. **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef DOCUMENT_H #define DOCUMENT_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** * A Position is a position within a document between two characters or at the beginning or end. * Sometimes used as a character index where it identifies the character after the position. */ typedef int Position; const Position invalidPosition = -1; /** * The range class represents a range of text in a document. * The two values are not sorted as one end may be more significant than the other * as is the case for the selection where the end position is the position of the caret. * If either position is invalidPosition then the range is invalid and most operations will fail. */ class Range { public: Position start; Position end; Range(Position pos=0) : start(pos), end(pos) { } Range(Position start_, Position end_) : start(start_), end(end_) { } bool Valid() const { return (start != invalidPosition) && (end != invalidPosition); } // Is the position within the range? bool Contains(Position pos) const { if (start < end) { return (pos >= start && pos <= end); } else { return (pos <= start && pos >= end); } } // Is the character after pos within the range? bool ContainsCharacter(Position pos) const { if (start < end) { return (pos >= start && pos < end); } else { return (pos < start && pos >= end); } } bool Contains(Range other) const { return Contains(other.start) && Contains(other.end); } bool Overlaps(Range other) const { return Contains(other.start) || Contains(other.end) || other.Contains(start) || other.Contains(end); } }; class DocWatcher; class DocModification; class Document; /** * Interface class for regular expression searching */ class RegexSearchBase { public: virtual ~RegexSearchBase() {} virtual long FindText(Document *doc, int minPos, int maxPos, const char *s, bool caseSensitive, bool word, bool wordStart, int flags, int *length) = 0; ///@return String with the substitutions, must remain valid until the next call or destruction virtual const char *SubstituteByPosition(Document *doc, const char *text, int *length) = 0; }; /// Factory function for RegexSearchBase extern RegexSearchBase *CreateRegexSearch(CharClassify *charClassTable); struct StyledText { size_t length; const char *text; bool multipleStyles; size_t style; const unsigned char *styles; StyledText(size_t length_, const char *text_, bool multipleStyles_, int style_, const unsigned char *styles_) : length(length_), text(text_), multipleStyles(multipleStyles_), style(style_), styles(styles_) { } // Return number of bytes from start to before '\n' or end of text. // Return 1 when start is outside text size_t LineLength(size_t start) const { size_t cur = start; while ((cur < length) && (text[cur] != '\n')) cur++; return cur-start; } size_t StyleAt(size_t i) const { return multipleStyles ? styles[i] : style; } }; class HighlightDelimiter { public: HighlightDelimiter() : isEnabled(false) { Clear(); } void Clear() { beginFoldBlock = -1; endFoldBlock = -1; firstChangeableLineBefore = -1; firstChangeableLineAfter = -1; } bool NeedsDrawing(int line) { return isEnabled && (line <= firstChangeableLineBefore || line >= firstChangeableLineAfter); } bool IsFoldBlockHighlighted(int line) { return isEnabled && beginFoldBlock != -1 && beginFoldBlock <= line && line <= endFoldBlock; } bool IsHeadOfFoldBlock(int line) { return beginFoldBlock == line && line < endFoldBlock; } bool IsBodyOfFoldBlock(int line) { return beginFoldBlock != -1 && beginFoldBlock < line && line < endFoldBlock; } bool IsTailOfFoldBlock(int line) { return beginFoldBlock != -1 && beginFoldBlock < line && line == endFoldBlock; } int beginFoldBlock; // Begin of current fold block int endFoldBlock; // End of current fold block int firstChangeableLineBefore; // First line that triggers repaint before starting line that determined current fold block int firstChangeableLineAfter; // First line that triggers repaint after starting line that determined current fold block bool isEnabled; }; class CaseFolder { public: virtual ~CaseFolder() { } virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) = 0; }; class CaseFolderTable : public CaseFolder { protected: char mapping[256]; public: CaseFolderTable(); virtual ~CaseFolderTable(); virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed); void SetTranslation(char ch, char chTranslation); void StandardASCII(); }; class Document; class LexInterface { protected: Document *pdoc; ILexer *instance; bool performingStyle; ///< Prevent reentrance public: LexInterface(Document *pdoc_) : pdoc(pdoc_), instance(0), performingStyle(false) { } virtual ~LexInterface() { } void Colourise(int start, int end); bool UseContainerLexing() const { return instance == 0; } }; /** */ class Document : PerLine, public IDocument, public ILoader { public: /** Used to pair watcher pointer with user data. */ class WatcherWithUserData { public: DocWatcher *watcher; void *userData; WatcherWithUserData() { watcher = 0; userData = 0; } }; enum charClassification { ccSpace, ccNewLine, ccWord, ccPunctuation }; private: int refCount; CellBuffer cb; CharClassify charClass; char stylingMask; int endStyled; int styleClock; int enteredModification; int enteredStyling; int enteredReadOnlyCount; WatcherWithUserData *watchers; int lenWatchers; // ldSize is not real data - it is for dimensions and loops enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize }; PerLine *perLineData[ldSize]; bool matchesValid; RegexSearchBase *regex; public: LexInterface *pli; int stylingBits; int stylingBitsMask; int eolMode; /// Can also be SC_CP_UTF8 to enable UTF-8 mode int dbcsCodePage; int tabInChars; int indentInChars; int actualIndentInChars; bool useTabs; bool tabIndents; bool backspaceUnindents; DecorationList decorations; Document(); virtual ~Document(); int AddRef(); int SCI_METHOD Release(); virtual void Init(); virtual void InsertLine(int line); virtual void RemoveLine(int line); int SCI_METHOD Version() const { return dvOriginal; } void SCI_METHOD SetErrorStatus(int status); int SCI_METHOD LineFromPosition(int pos) const; int ClampPositionIntoDocument(int pos); bool IsCrLf(int pos); int LenChar(int pos); bool InGoodUTF8(int pos, int &start, int &end) const; int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); int NextPosition(int pos, int moveDir) const; bool NextCharacter(int &pos, int moveDir); // Returns true if pos changed int SCI_METHOD CodePage() const; bool SCI_METHOD IsDBCSLeadByte(char ch) const; int SafeSegment(const char *text, int length, int lengthSegment); // Gateways to modifying document void ModifiedAt(int pos); void CheckReadOnly(); bool DeleteChars(int pos, int len); bool InsertString(int position, const char *s, int insertLength); int SCI_METHOD AddData(char *data, int length); void * SCI_METHOD ConvertToDocument(); int Undo(); int Redo(); bool CanUndo() { return cb.CanUndo(); } bool CanRedo() { return cb.CanRedo(); } void DeleteUndoHistory() { cb.DeleteUndoHistory(); } bool SetUndoCollection(bool collectUndo) { return cb.SetUndoCollection(collectUndo); } bool IsCollectingUndo() { return cb.IsCollectingUndo(); } void BeginUndoAction() { cb.BeginUndoAction(); } void EndUndoAction() { cb.EndUndoAction(); } void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); } void SetSavePoint(); bool IsSavePoint() { return cb.IsSavePoint(); } const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); } const char *RangePointer(int position, int rangeLength) { return cb.RangePointer(position, rangeLength); } int GapPosition() const { return cb.GapPosition(); } int SCI_METHOD GetLineIndentation(int line); void SetLineIndentation(int line, int indent); int GetLineIndentPosition(int line) const; int GetColumn(int position); int CountCharacters(int startPos, int endPos); int FindColumn(int line, int column); void Indent(bool forwards, int lineBottom, int lineTop); static char *TransformLineEnds(int *pLenOut, const char *s, size_t len, int eolModeWanted); void ConvertLineEnds(int eolModeSet); void SetReadOnly(bool set) { cb.SetReadOnly(set); } bool IsReadOnly() { return cb.IsReadOnly(); } bool InsertChar(int pos, char ch); bool InsertCString(int position, const char *s); void ChangeChar(int pos, char ch); void DelChar(int pos); void DelCharBack(int pos); char CharAt(int position) { return cb.CharAt(position); } void SCI_METHOD GetCharRange(char *buffer, int position, int lengthRetrieve) const { cb.GetCharRange(buffer, position, lengthRetrieve); } char SCI_METHOD StyleAt(int position) const { return cb.StyleAt(position); } void GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const { cb.GetStyleRange(buffer, position, lengthRetrieve); } int GetMark(int line); int MarkerNext(int lineStart, int mask) const; int AddMark(int line, int markerNum); void AddMarkSet(int line, int valueSet); void DeleteMark(int line, int markerNum); void DeleteMarkFromHandle(int markerHandle); void DeleteAllMarks(int markerNum); int LineFromHandle(int markerHandle); int SCI_METHOD LineStart(int line) const; int LineEnd(int line) const; int LineEndPosition(int position) const; bool IsLineEndPosition(int position) const; int VCHomePosition(int position) const; int SCI_METHOD SetLevel(int line, int level); int SCI_METHOD GetLevel(int line) const; void ClearLevels(); int GetLastChild(int lineParent, int level=-1, int lastLine=-1); int GetFoldParent(int line); void GetHighlightDelimiters(HighlightDelimiter &hDelimiter, int line, int lastLine); void Indent(bool forwards); int ExtendWordSelect(int pos, int delta, bool onlyWordCharacters=false); int NextWordStart(int pos, int delta); int NextWordEnd(int pos, int delta); int SCI_METHOD Length() const { return cb.Length(); } void Allocate(int newSize) { cb.Allocate(newSize); } bool MatchesWordOptions(bool word, bool wordStart, int pos, int length); long FindText(int minPos, int maxPos, const char *search, bool caseSensitive, bool word, bool wordStart, bool regExp, int flags, int *length, CaseFolder *pcf); const char *SubstituteByPosition(const char *text, int *length); int LinesTotal() const; void ChangeCase(Range r, bool makeUpperCase); void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass); void SetStylingBits(int bits); void SCI_METHOD StartStyling(int position, char mask); bool SCI_METHOD SetStyleFor(int length, char style); bool SCI_METHOD SetStyles(int length, const char *styles); int GetEndStyled() { return endStyled; } void EnsureStyledTo(int pos); void LexerChanged(); int GetStyleClock() { return styleClock; } void IncrementStyleClock(); void SCI_METHOD DecorationSetCurrentIndicator(int indicator) { decorations.SetCurrentIndicator(indicator); } void SCI_METHOD DecorationFillRange(int position, int value, int fillLength); int SCI_METHOD SetLineState(int line, int state); int SCI_METHOD GetLineState(int line) const; int GetMaxLineState(); void SCI_METHOD ChangeLexerState(int start, int end); StyledText MarginStyledText(int line); void MarginSetStyle(int line, int style); void MarginSetStyles(int line, const unsigned char *styles); void MarginSetText(int line, const char *text); int MarginLength(int line) const; void MarginClearAll(); bool AnnotationAny() const; StyledText AnnotationStyledText(int line); void AnnotationSetText(int line, const char *text); void AnnotationSetStyle(int line, int style); void AnnotationSetStyles(int line, const unsigned char *styles); int AnnotationLength(int line) const; int AnnotationLines(int line) const; void AnnotationClearAll(); bool AddWatcher(DocWatcher *watcher, void *userData); bool RemoveWatcher(DocWatcher *watcher, void *userData); const WatcherWithUserData *GetWatchers() const { return watchers; } int GetLenWatchers() const { return lenWatchers; } CharClassify::cc WordCharClass(unsigned char ch); bool IsWordPartSeparator(char ch); int WordPartLeft(int pos); int WordPartRight(int pos); int ExtendStyleRange(int pos, int delta, bool singleLine = false); bool IsWhiteLine(int line) const; int ParaUp(int pos); int ParaDown(int pos); int IndentSize() { return actualIndentInChars; } int BraceMatch(int position, int maxReStyle); private: bool IsWordStartAt(int pos); bool IsWordEndAt(int pos); bool IsWordAt(int start, int end); void NotifyModifyAttempt(); void NotifySavePoint(bool atSavePoint); void NotifyModified(DocModification mh); }; class UndoGroup { Document *pdoc; bool groupNeeded; public: UndoGroup(Document *pdoc_, bool groupNeeded_=true) : pdoc(pdoc_), groupNeeded(groupNeeded_) { if (groupNeeded) { pdoc->BeginUndoAction(); } } ~UndoGroup() { if (groupNeeded) { pdoc->EndUndoAction(); } } bool Needed() const { return groupNeeded; } }; /** * To optimise processing of document modifications by DocWatchers, a hint is passed indicating the * scope of the change. * If the DocWatcher is a document view then this can be used to optimise screen updating. */ class DocModification { public: int modificationType; int position; int length; int linesAdded; /**< Negative if lines deleted. */ const char *text; /**< Only valid for changes to text, not for changes to style. */ int line; int foldLevelNow; int foldLevelPrev; int annotationLinesAdded; int token; DocModification(int modificationType_, int position_=0, int length_=0, int linesAdded_=0, const char *text_=0, int line_=0) : modificationType(modificationType_), position(position_), length(length_), linesAdded(linesAdded_), text(text_), line(line_), foldLevelNow(0), foldLevelPrev(0), annotationLinesAdded(0), token(0) {} DocModification(int modificationType_, const Action &act, int linesAdded_=0) : modificationType(modificationType_), position(act.position), length(act.lenData), linesAdded(linesAdded_), text(act.data), line(0), foldLevelNow(0), foldLevelPrev(0), annotationLinesAdded(0), token(0) {} }; /** * A class that wants to receive notifications from a Document must be derived from DocWatcher * and implement the notification methods. It can then be added to the watcher list with AddWatcher. */ class DocWatcher { public: virtual ~DocWatcher() {} virtual void NotifyModifyAttempt(Document *doc, void *userData) = 0; virtual void NotifySavePoint(Document *doc, void *userData, bool atSavePoint) = 0; virtual void NotifyModified(Document *doc, DocModification mh, void *userData) = 0; virtual void NotifyDeleted(Document *doc, void *userData) = 0; virtual void NotifyStyleNeeded(Document *doc, void *userData, int endPos) = 0; virtual void NotifyLexerChanged(Document *doc, void *userData) = 0; virtual void NotifyErrorOccurred(Document *doc, void *userData, int status) = 0; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/ExternalLexer.cxx0000644000175000017500000001007311615412040021717 00000000000000// Scintilla source code edit control /** @file ExternalLexer.cxx ** Support external lexers in DLLs. **/ // Copyright 2001 Simon Steele , portions copyright Neil Hodgson. // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "LexerModule.h" #include "Catalogue.h" #include "ExternalLexer.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif LexerManager *LexerManager::theInstance = NULL; //------------------------------------------ // // ExternalLexerModule // //------------------------------------------ void ExternalLexerModule::SetExternal(GetLexerFactoryFunction fFactory, int index) { fneFactory = fFactory; fnFactory = fFactory(index); } //------------------------------------------ // // LexerLibrary // //------------------------------------------ LexerLibrary::LexerLibrary(const char *ModuleName) { // Initialise some members... first = NULL; last = NULL; // Load the DLL lib = DynamicLibrary::Load(ModuleName); if (lib->IsValid()) { m_sModuleName = ModuleName; //Cannot use reinterpret_cast because: ANSI C++ forbids casting between pointers to functions and objects GetLexerCountFn GetLexerCount = (GetLexerCountFn)(sptr_t)lib->FindFunction("GetLexerCount"); if (GetLexerCount) { ExternalLexerModule *lex; LexerMinder *lm; // Find functions in the DLL GetLexerNameFn GetLexerName = (GetLexerNameFn)(sptr_t)lib->FindFunction("GetLexerName"); GetLexerFactoryFunction fnFactory = (GetLexerFactoryFunction)(sptr_t)lib->FindFunction("GetLexerFactory"); // Assign a buffer for the lexer name. char lexname[100]; strcpy(lexname, ""); int nl = GetLexerCount(); for (int i = 0; i < nl; i++) { GetLexerName(i, lexname, 100); lex = new ExternalLexerModule(SCLEX_AUTOMATIC, NULL, lexname, NULL); Catalogue::AddLexerModule(lex); // Create a LexerMinder so we don't leak the ExternalLexerModule... lm = new LexerMinder; lm->self = lex; lm->next = NULL; if (first != NULL) { last->next = lm; last = lm; } else { first = lm; last = lm; } // The external lexer needs to know how to call into its DLL to // do its lexing and folding, we tell it here. lex->SetExternal(fnFactory, i); } } } next = NULL; } LexerLibrary::~LexerLibrary() { Release(); delete lib; } void LexerLibrary::Release() { LexerMinder *lm; LexerMinder *lmNext; lm = first; while (NULL != lm) { lmNext = lm->next; delete lm->self; delete lm; lm = lmNext; } first = NULL; last = NULL; } //------------------------------------------ // // LexerManager // //------------------------------------------ /// Return the single LexerManager instance... LexerManager *LexerManager::GetInstance() { if (!theInstance) theInstance = new LexerManager; return theInstance; } /// Delete any LexerManager instance... void LexerManager::DeleteInstance() { delete theInstance; theInstance = NULL; } /// protected constructor - this is a singleton... LexerManager::LexerManager() { first = NULL; last = NULL; } LexerManager::~LexerManager() { Clear(); } void LexerManager::Load(const char *path) { LoadLexerLibrary(path); } void LexerManager::LoadLexerLibrary(const char *module) { for (LexerLibrary *ll = first; ll; ll= ll->next) { if (strcmp(ll->m_sModuleName.c_str(), module) == 0) return; } LexerLibrary *lib = new LexerLibrary(module); if (NULL != first) { last->next = lib; last = lib; } else { first = lib; last = lib; } } void LexerManager::Clear() { if (NULL != first) { LexerLibrary *cur = first; LexerLibrary *next; while (cur) { next = cur->next; delete cur; cur = next; } first = NULL; last = NULL; } } //------------------------------------------ // // LexerManager // //------------------------------------------ LMMinder::~LMMinder() { LexerManager::DeleteInstance(); } LMMinder minder; presage-0.8.8/apps/gtk/gprompter/scintilla/src/ViewStyle.cxx0000644000175000017500000003154211763437013021107 00000000000000// Scintilla source code edit control /** @file ViewStyle.cxx ** Store information on how the document is to be viewed. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "Platform.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif MarginStyle::MarginStyle() : style(SC_MARGIN_SYMBOL), width(0), mask(0), sensitive(false), cursor(SC_CURSORREVERSEARROW) { } // A list of the fontnames - avoids wasting space in each style FontNames::FontNames() { size = 8; names = new char *[size]; max = 0; } FontNames::~FontNames() { Clear(); delete []names; names = 0; } void FontNames::Clear() { for (int i=0; i= size) { // Grow array int sizeNew = size * 2; char **namesNew = new char *[sizeNew]; for (int j=0; jRealise(surface, zoomLevel, technology); } } FontRealised *FontRealised::Find(const FontSpecification &fs) { if (!fs.fontName) return this; FontRealised *fr = this; while (fr) { if (fr->EqualTo(fs)) return fr; fr = fr->frNext; } return 0; } void FontRealised::FindMaxAscentDescent(unsigned int &maxAscent, unsigned int &maxDescent) { FontRealised *fr = this; while (fr) { if (maxAscent < fr->ascent) maxAscent = fr->ascent; if (maxDescent < fr->descent) maxDescent = fr->descent; fr = fr->frNext; } } ViewStyle::ViewStyle() { Init(); } ViewStyle::ViewStyle(const ViewStyle &source) { frFirst = NULL; Init(source.stylesSize); for (unsigned int sty=0; sty 0) maskInLine &= ~ms[margin].mask; } zoomLevel = 0; viewWhitespace = wsInvisible; whitespaceSize = 1; viewIndentationGuides = ivNone; viewEOL = false; extraFontFlag = 0; extraAscent = 0; extraDescent = 0; marginStyleOffset = 0; annotationVisible = ANNOTATION_HIDDEN; annotationStyleOffset = 0; braceHighlightIndicatorSet = false; braceHighlightIndicator = 0; braceBadLightIndicatorSet = false; braceBadLightIndicator = 0; } void ViewStyle::CreateFont(const FontSpecification &fs) { if (fs.fontName) { for (FontRealised *cur=frFirst; cur; cur=cur->frNext) { if (cur->EqualTo(fs)) return; if (!cur->frNext) { cur->frNext = new FontRealised(fs); return; } } frFirst = new FontRealised(fs); } } void ViewStyle::Refresh(Surface &surface) { delete frFirst; frFirst = NULL; selbar = Platform::Chrome(); selbarlight = Platform::ChromeHighlight(); for (unsigned int i=0; iRealise(surface, zoomLevel, technology); for (unsigned int k=0; kFind(styles[k]); styles[k].Copy(fr->font, *fr); } maxAscent = 1; maxDescent = 1; frFirst->FindMaxAscentDescent(maxAscent, maxDescent); maxAscent += extraAscent; maxDescent += extraDescent; lineHeight = maxAscent + maxDescent; someStylesProtected = false; someStylesForceCase = false; for (unsigned int l=0; l 0) maskInLine &= ~ms[margin].mask; } } void ViewStyle::AllocStyles(size_t sizeNew) { Style *stylesNew = new Style[sizeNew]; size_t i=0; for (; i STYLE_DEFAULT) { for (; i= stylesSize) { size_t sizeNew = stylesSize * 2; while (sizeNew <= index) sizeNew *= 2; AllocStyles(sizeNew); } } void ViewStyle::ResetDefaultStyle() { styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0), ColourDesired(0xff,0xff,0xff), Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()), SC_CHARSET_DEFAULT, SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false); } void ViewStyle::ClearStyles() { // Reset all styles to be like the default style for (unsigned int i=0; iGetHeight() > largestMarkerHeight) largestMarkerHeight = markers[m].pxpm->GetHeight(); break; case SC_MARK_RGBAIMAGE: if (markers[m].image->GetHeight() > largestMarkerHeight) largestMarkerHeight = markers[m].image->GetHeight(); break; } } } presage-0.8.8/apps/gtk/gprompter/scintilla/src/AutoComplete.h0000644000175000017500000000406111763437013021176 00000000000000// Scintilla source code edit control /** @file AutoComplete.h ** Defines the auto completion list box. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef AUTOCOMPLETE_H #define AUTOCOMPLETE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class AutoComplete { bool active; char stopChars[256]; char fillUpChars[256]; char separator; char typesep; // Type seperator public: bool ignoreCase; bool chooseSingle; ListBox *lb; int posStart; int startLen; /// Should autocompletion be canceled if editor's currentPos <= startPos? bool cancelAtStartPos; bool autoHide; bool dropRestOfWord; unsigned int ignoreCaseBehaviour; AutoComplete(); ~AutoComplete(); /// Is the auto completion list displayed? bool Active() const; /// Display the auto completion list positioned to be near a character position void Start(Window &parent, int ctrlID, int position, Point location, int startLen_, int lineHeight, bool unicodeMode, int technology); /// The stop chars are characters which, when typed, cause the auto completion list to disappear void SetStopChars(const char *stopChars_); bool IsStopChar(char ch); /// The fillup chars are characters which, when typed, fill up the selected word void SetFillUpChars(const char *fillUpChars_); bool IsFillUpChar(char ch); /// The separator character is used when interpreting the list in SetList void SetSeparator(char separator_); char GetSeparator() const; /// The typesep character is used for seperating the word from the type void SetTypesep(char separator_); char GetTypesep() const; /// The list string contains a sequence of words separated by the separator character void SetList(const char *list); void Show(bool show); void Cancel(); /// Move the current list element by delta, scrolling appropriately void Move(int delta); /// Select a list element that starts with word as the current element void Select(const char *word); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/UniConversion.h0000644000175000017500000000170511763437013021400 00000000000000// Scintilla source code edit control /** @file UniConversion.h ** Functions to handle UTF-8 and UTF-16 strings. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. const int UTF8MaxBytes = 4; unsigned int UTF8Length(const wchar_t *uptr, unsigned int tlen); void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned int len); unsigned int UTF8CharLength(unsigned char ch); unsigned int UTF16Length(const char *s, unsigned int len); unsigned int UTF16FromUTF8(const char *s, unsigned int len, wchar_t *tbuf, unsigned int tlen); extern int UTF8BytesOfLead[256]; void UTF8BytesOfLeadInitialise(); inline bool UTF8IsTrailByte(int ch) { return (ch >= 0x80) && (ch < 0xc0); } inline bool UTF8IsAscii(int ch) { return ch < 0x80; } enum { UTF8MaskWidth=0x7, UTF8MaskInvalid=0x8 }; int UTF8Classify(const unsigned char *us, int len); presage-0.8.8/apps/gtk/gprompter/scintilla/src/AutoComplete.cxx0000644000175000017500000000771711763437013021564 00000000000000// Scintilla source code edit control /** @file AutoComplete.cxx ** Defines the auto completion list box. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "CharacterSet.h" #include "AutoComplete.h" #include "Scintilla.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif AutoComplete::AutoComplete() : active(false), separator(' '), typesep('?'), ignoreCase(false), chooseSingle(false), lb(0), posStart(0), startLen(0), cancelAtStartPos(true), autoHide(true), dropRestOfWord(false), ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) { lb = ListBox::Allocate(); stopChars[0] = '\0'; fillUpChars[0] = '\0'; } AutoComplete::~AutoComplete() { if (lb) { lb->Destroy(); delete lb; lb = 0; } } bool AutoComplete::Active() const { return active; } void AutoComplete::Start(Window &parent, int ctrlID, int position, Point location, int startLen_, int lineHeight, bool unicodeMode, int technology) { if (active) { Cancel(); } lb->Create(parent, ctrlID, location, lineHeight, unicodeMode, technology); lb->Clear(); active = true; startLen = startLen_; posStart = position; } void AutoComplete::SetStopChars(const char *stopChars_) { strncpy(stopChars, stopChars_, sizeof(stopChars)); stopChars[sizeof(stopChars) - 1] = '\0'; } bool AutoComplete::IsStopChar(char ch) { return ch && strchr(stopChars, ch); } void AutoComplete::SetFillUpChars(const char *fillUpChars_) { strncpy(fillUpChars, fillUpChars_, sizeof(fillUpChars)); fillUpChars[sizeof(fillUpChars) - 1] = '\0'; } bool AutoComplete::IsFillUpChar(char ch) { return ch && strchr(fillUpChars, ch); } void AutoComplete::SetSeparator(char separator_) { separator = separator_; } char AutoComplete::GetSeparator() const { return separator; } void AutoComplete::SetTypesep(char separator_) { typesep = separator_; } char AutoComplete::GetTypesep() const { return typesep; } void AutoComplete::SetList(const char *list) { lb->SetList(list, separator, typesep); } void AutoComplete::Show(bool show) { lb->Show(show); if (show) lb->Select(0); } void AutoComplete::Cancel() { if (lb->Created()) { lb->Clear(); lb->Destroy(); active = false; } } void AutoComplete::Move(int delta) { int count = lb->Length(); int current = lb->GetSelection(); current += delta; if (current >= count) current = count - 1; if (current < 0) current = 0; lb->Select(current); } void AutoComplete::Select(const char *word) { size_t lenWord = strlen(word); int location = -1; const int maxItemLen=1000; int start = 0; // lower bound of the api array block to search int end = lb->Length() - 1; // upper bound of the api array block to search while ((start <= end) && (location == -1)) { // Binary searching loop int pivot = (start + end) / 2; char item[maxItemLen]; lb->GetValue(pivot, item, maxItemLen); int cond; if (ignoreCase) cond = CompareNCaseInsensitive(word, item, lenWord); else cond = strncmp(word, item, lenWord); if (!cond) { // Find first match while (pivot > start) { lb->GetValue(pivot-1, item, maxItemLen); if (ignoreCase) cond = CompareNCaseInsensitive(word, item, lenWord); else cond = strncmp(word, item, lenWord); if (0 != cond) break; --pivot; } location = pivot; if (ignoreCase && ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) { // Check for exact-case match for (; pivot <= end; pivot++) { lb->GetValue(pivot, item, maxItemLen); if (!strncmp(word, item, lenWord)) { location = pivot; break; } if (CompareNCaseInsensitive(word, item, lenWord)) break; } } } else if (cond < 0) { end = pivot - 1; } else if (cond > 0) { start = pivot + 1; } } if (location == -1 && autoHide) Cancel(); else lb->Select(location); } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Catalogue.h0000644000175000017500000000106111615412040020463 00000000000000// Scintilla source code edit control /** @file Catalogue.h ** Lexer infrastructure. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CATALOGUE_H #define CATALOGUE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class Catalogue { public: static const LexerModule *Find(int language); static const LexerModule *Find(const char *languageName); static void AddLexerModule(LexerModule *plm); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/ContractionState.h0000644000175000017500000000303411615412040022045 00000000000000// Scintilla source code edit control /** @file ContractionState.h ** Manages visibility of lines for folding and wrapping. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CONTRACTIONSTATE_H #define CONTRACTIONSTATE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class ContractionState { // These contain 1 element for every document line. RunStyles *visible; RunStyles *expanded; RunStyles *heights; Partitioning *displayLines; int linesInDocument; void EnsureData(); bool OneToOne() const { // True when each document line is exactly one display line so need for // complex data structures. return visible == 0; } public: ContractionState(); virtual ~ContractionState(); void Clear(); int LinesInDoc() const; int LinesDisplayed() const; int DisplayFromDoc(int lineDoc) const; int DocFromDisplay(int lineDisplay) const; void InsertLine(int lineDoc); void InsertLines(int lineDoc, int lineCount); void DeleteLine(int lineDoc); void DeleteLines(int lineDoc, int lineCount); bool GetVisible(int lineDoc) const; bool SetVisible(int lineDocStart, int lineDocEnd, bool visible); bool HiddenLines() const; bool GetExpanded(int lineDoc) const; bool SetExpanded(int lineDoc, bool expanded); int ContractedNext(int lineDocStart) const; int GetHeight(int lineDoc) const; bool SetHeight(int lineDoc, int height); void ShowAll(); void Check() const; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/Decoration.cxx0000644000175000017500000001035711717550114021241 00000000000000/** @file Decoration.cxx ** Visual elements added over text. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "Decoration.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif Decoration::Decoration(int indicator_) : next(0), indicator(indicator_) { } Decoration::~Decoration() { } bool Decoration::Empty() { return (rs.Runs() == 1) && (rs.AllSameAs(0)); } DecorationList::DecorationList() : currentIndicator(0), currentValue(1), current(0), lengthDocument(0), root(0), clickNotified(false) { } DecorationList::~DecorationList() { Decoration *deco = root; while (deco) { Decoration *decoNext = deco->next; delete deco; deco = decoNext; } root = 0; current = 0; } Decoration *DecorationList::DecorationFromIndicator(int indicator) { for (Decoration *deco=root; deco; deco = deco->next) { if (deco->indicator == indicator) { return deco; } } return 0; } Decoration *DecorationList::Create(int indicator, int length) { currentIndicator = indicator; Decoration *decoNew = new Decoration(indicator); decoNew->rs.InsertSpace(0, length); Decoration *decoPrev = 0; Decoration *deco = root; while (deco && (deco->indicator < indicator)) { decoPrev = deco; deco = deco->next; } if (decoPrev == 0) { decoNew->next = root; root = decoNew; } else { decoNew->next = deco; decoPrev->next = decoNew; } return decoNew; } void DecorationList::Delete(int indicator) { Decoration *decoToDelete = 0; if (root) { if (root->indicator == indicator) { decoToDelete = root; root = root->next; } else { Decoration *deco=root; while (deco->next && !decoToDelete) { if (deco->next && deco->next->indicator == indicator) { decoToDelete = deco->next; deco->next = decoToDelete->next; } else { deco = deco->next; } } } } if (decoToDelete) { delete decoToDelete; current = 0; } } void DecorationList::SetCurrentIndicator(int indicator) { currentIndicator = indicator; current = DecorationFromIndicator(indicator); currentValue = 1; } void DecorationList::SetCurrentValue(int value) { currentValue = value ? value : 1; } bool DecorationList::FillRange(int &position, int value, int &fillLength) { if (!current) { current = DecorationFromIndicator(currentIndicator); if (!current) { current = Create(currentIndicator, lengthDocument); } } bool changed = current->rs.FillRange(position, value, fillLength); if (current->Empty()) { Delete(currentIndicator); } return changed; } void DecorationList::InsertSpace(int position, int insertLength) { const bool atEnd = position == lengthDocument; lengthDocument += insertLength; for (Decoration *deco=root; deco; deco = deco->next) { deco->rs.InsertSpace(position, insertLength); if (atEnd) { deco->rs.FillRange(position, 0, insertLength); } } } void DecorationList::DeleteRange(int position, int deleteLength) { lengthDocument -= deleteLength; Decoration *deco; for (deco=root; deco; deco = deco->next) { deco->rs.DeleteRange(position, deleteLength); } DeleteAnyEmpty(); } void DecorationList::DeleteAnyEmpty() { Decoration *deco = root; while (deco) { if ((lengthDocument == 0) || deco->Empty()) { Delete(deco->indicator); deco = root; } else { deco = deco->next; } } } int DecorationList::AllOnFor(int position) { int mask = 0; for (Decoration *deco=root; deco; deco = deco->next) { if (deco->rs.ValueAt(position)) { mask |= 1 << deco->indicator; } } return mask; } int DecorationList::ValueAt(int indicator, int position) { Decoration *deco = DecorationFromIndicator(indicator); if (deco) { return deco->rs.ValueAt(position); } return 0; } int DecorationList::Start(int indicator, int position) { Decoration *deco = DecorationFromIndicator(indicator); if (deco) { return deco->rs.StartRun(position); } return 0; } int DecorationList::End(int indicator, int position) { Decoration *deco = DecorationFromIndicator(indicator); if (deco) { return deco->rs.EndRun(position); } return 0; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/XPM.h0000644000175000017500000000632611640062361017241 00000000000000// Scintilla source code edit control /** @file XPM.h ** Define a class that holds data in the X Pixmap (XPM) format. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef XPM_H #define XPM_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** * Hold a pixmap in XPM format. */ class XPM { int pid; // Assigned by container int height; int width; int nColours; char *data; char codeTransparent; char *codes; ColourDesired *colours; ColourDesired ColourDesiredFromCode(int ch) const; ColourDesired ColourFromCode(int ch) const; void FillRun(Surface *surface, int code, int startX, int y, int x); char **lines; ColourDesired *colourCodeTable[256]; public: XPM(const char *textForm); XPM(const char *const *linesForm); ~XPM(); void Init(const char *textForm); void Init(const char *const *linesForm); void Clear(); /// Decompose image into runs and use FillRectangle for each run void Draw(Surface *surface, PRectangle &rc); char **InLinesForm() { return lines; } void SetId(int pid_) { pid = pid_; } int GetId() const { return pid; } int GetHeight() const { return height; } int GetWidth() const { return width; } void PixelAt(int x, int y, ColourDesired &colour, bool &transparent) const; static const char **LinesFormFromTextForm(const char *textForm); }; /** * A collection of pixmaps indexed by integer id. */ class XPMSet { XPM **set; ///< The stored XPMs. int len; ///< Current number of XPMs. int maximum; ///< Current maximum number of XPMs, increased by steps if reached. int height; ///< Memorize largest height of the set. int width; ///< Memorize largest width of the set. public: XPMSet(); ~XPMSet(); /// Remove all XPMs. void Clear(); /// Add a XPM. void Add(int ident, const char *textForm); /// Get XPM by id. XPM *Get(int ident); /// Give the largest height of the set. int GetHeight(); /// Give the largest width of the set. int GetWidth(); }; /** * An translucent image stoed as a sequence of RGBA bytes. */ class RGBAImage { // Private so RGBAImage objects can not be copied RGBAImage(const RGBAImage &); RGBAImage &operator=(const RGBAImage &); int height; int width; std::vector pixelBytes; public: RGBAImage(int width_, int height_, const unsigned char *pixels_); RGBAImage(const XPM &xpm); virtual ~RGBAImage(); int GetHeight() const { return height; } int GetWidth() const { return width; } int CountBytes() const; const unsigned char *Pixels() const; void SetPixel(int x, int y, ColourDesired colour, int alpha=0xff); }; /** * A collection of RGBAImage pixmaps indexed by integer id. */ class RGBAImageSet { typedef std::map ImageMap; ImageMap images; mutable int height; ///< Memorize largest height of the set. mutable int width; ///< Memorize largest width of the set. public: RGBAImageSet(); ~RGBAImageSet(); /// Remove all images. void Clear(); /// Add an image. void Add(int ident, RGBAImage *image); /// Get image by id. RGBAImage *Get(int ident); /// Give the largest height of the set. int GetHeight() const; /// Give the largest width of the set. int GetWidth() const; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/Indicator.cxx0000644000175000017500000000745711660423551021076 00000000000000// Scintilla source code edit control /** @file Indicator.cxx ** Defines the style of indicators which are text decorations such as underlining. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include "Platform.h" #include "Scintilla.h" #include "XPM.h" #include "Indicator.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif void Indicator::Draw(Surface *surface, const PRectangle &rc, const PRectangle &rcLine) { surface->PenColour(fore); int ymid = (rc.bottom + rc.top) / 2; if (style == INDIC_SQUIGGLE) { surface->MoveTo(rc.left, rc.top); int x = rc.left + 2; int y = 2; while (x < rc.right) { surface->LineTo(x, rc.top + y); x += 2; y = 2 - y; } surface->LineTo(rc.right, rc.top + y); // Finish the line } else if (style == INDIC_SQUIGGLELOW) { surface->MoveTo(rc.left, rc.top); int x = rc.left + 3; int y = 0; while (x < rc.right) { surface->LineTo(x-1, rc.top + y); y = 1 - y; surface->LineTo(x, rc.top + y); x += 3; } surface->LineTo(rc.right, rc.top + y); // Finish the line } else if (style == INDIC_TT) { surface->MoveTo(rc.left, ymid); int x = rc.left + 5; while (x < rc.right) { surface->LineTo(x, ymid); surface->MoveTo(x-3, ymid); surface->LineTo(x-3, ymid+2); x++; surface->MoveTo(x, ymid); x += 5; } surface->LineTo(rc.right, ymid); // Finish the line if (x - 3 <= rc.right) { surface->MoveTo(x-3, ymid); surface->LineTo(x-3, ymid+2); } } else if (style == INDIC_DIAGONAL) { int x = rc.left; while (x < rc.right) { surface->MoveTo(x, rc.top+2); int endX = x+3; int endY = rc.top - 1; if (endX > rc.right) { endY += endX - rc.right; endX = rc.right; } surface->LineTo(endX, endY); x += 4; } } else if (style == INDIC_STRIKE) { surface->MoveTo(rc.left, rc.top - 4); surface->LineTo(rc.right, rc.top - 4); } else if (style == INDIC_HIDDEN) { // Draw nothing } else if (style == INDIC_BOX) { surface->MoveTo(rc.left, ymid+1); surface->LineTo(rc.right, ymid+1); surface->LineTo(rc.right, rcLine.top+1); surface->LineTo(rc.left, rcLine.top+1); surface->LineTo(rc.left, ymid+1); } else if (style == INDIC_ROUNDBOX || style == INDIC_STRAIGHTBOX) { PRectangle rcBox = rcLine; rcBox.top = rcLine.top + 1; rcBox.left = rc.left; rcBox.right = rc.right; surface->AlphaRectangle(rcBox, (style == INDIC_ROUNDBOX) ? 1 : 0, fore, fillAlpha, fore, outlineAlpha, 0); } else if (style == INDIC_DOTBOX) { PRectangle rcBox = rcLine; rcBox.top = rcLine.top + 1; rcBox.left = rc.left; rcBox.right = rc.right; // Cap width at 4000 to avoid large allocations when mistakes made int width = Platform::Minimum(rcBox.Width(), 4000); RGBAImage image(width, rcBox.Height(), 0); // Draw horizontal lines top and bottom for (int x=0; xDrawRGBAImage(rcBox, image.GetWidth(), image.GetHeight(), image.Pixels()); } else if (style == INDIC_DASH) { int x = rc.left; while (x < rc.right) { surface->MoveTo(x, ymid); surface->LineTo(Platform::Minimum(x + 4, rc.right), ymid); x += 7; } } else if (style == INDIC_DOTS) { int x = rc.left; while (x < rc.right) { PRectangle rcDot(x, ymid, x+1, ymid+1); surface->FillRectangle(rcDot, fore); x += 2; } } else { // Either INDIC_PLAIN or unknown surface->MoveTo(rc.left, ymid); surface->LineTo(rc.right, ymid); } } presage-0.8.8/apps/gtk/gprompter/scintilla/src/ViewStyle.h0000644000175000017500000000762711763437013020543 00000000000000// Scintilla source code edit control /** @file ViewStyle.h ** Store information on how the document is to be viewed. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef VIEWSTYLE_H #define VIEWSTYLE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class MarginStyle { public: int style; int width; int mask; bool sensitive; int cursor; MarginStyle(); }; /** */ class FontNames { private: char **names; int size; int max; public: FontNames(); ~FontNames(); void Clear(); const char *Save(const char *name); }; class FontRealised : public FontSpecification, public FontMeasurements { // Private so FontRealised objects can not be copied FontRealised(const FontRealised &); FontRealised &operator=(const FontRealised &); public: Font font; FontRealised *frNext; FontRealised(const FontSpecification &fs); virtual ~FontRealised(); void Realise(Surface &surface, int zoomLevel, int technology); FontRealised *Find(const FontSpecification &fs); void FindMaxAscentDescent(unsigned int &maxAscent, unsigned int &maxDescent); }; enum IndentView {ivNone, ivReal, ivLookForward, ivLookBoth}; enum WhiteSpaceVisibility {wsInvisible=0, wsVisibleAlways=1, wsVisibleAfterIndent=2}; /** */ class ViewStyle { public: FontNames fontNames; FontRealised *frFirst; size_t stylesSize; Style *styles; LineMarker markers[MARKER_MAX + 1]; int largestMarkerHeight; Indicator indicators[INDIC_MAX + 1]; int technology; int lineHeight; unsigned int maxAscent; unsigned int maxDescent; XYPOSITION aveCharWidth; XYPOSITION spaceWidth; bool selforeset; ColourDesired selforeground; ColourDesired selAdditionalForeground; bool selbackset; ColourDesired selbackground; ColourDesired selAdditionalBackground; ColourDesired selbackground2; int selAlpha; int selAdditionalAlpha; bool selEOLFilled; bool whitespaceForegroundSet; ColourDesired whitespaceForeground; bool whitespaceBackgroundSet; ColourDesired whitespaceBackground; ColourDesired selbar; ColourDesired selbarlight; bool foldmarginColourSet; ColourDesired foldmarginColour; bool foldmarginHighlightColourSet; ColourDesired foldmarginHighlightColour; bool hotspotForegroundSet; ColourDesired hotspotForeground; bool hotspotBackgroundSet; ColourDesired hotspotBackground; bool hotspotUnderline; bool hotspotSingleLine; /// Margins are ordered: Line Numbers, Selection Margin, Spacing Margin enum { margins=5 }; int leftMarginWidth; ///< Spacing margin on left of text int rightMarginWidth; ///< Spacing margin on left of text int maskInLine; ///< Mask for markers to be put into text because there is nowhere for them to go in margin MarginStyle ms[margins]; int fixedColumnWidth; int zoomLevel; WhiteSpaceVisibility viewWhitespace; int whitespaceSize; IndentView viewIndentationGuides; bool viewEOL; ColourDesired caretcolour; ColourDesired additionalCaretColour; bool showCaretLineBackground; ColourDesired caretLineBackground; int caretLineAlpha; ColourDesired edgecolour; int edgeState; int caretStyle; int caretWidth; bool someStylesProtected; bool someStylesForceCase; int extraFontFlag; int extraAscent; int extraDescent; int marginStyleOffset; int annotationVisible; int annotationStyleOffset; bool braceHighlightIndicatorSet; int braceHighlightIndicator; bool braceBadLightIndicatorSet; int braceBadLightIndicator; ViewStyle(); ViewStyle(const ViewStyle &source); ~ViewStyle(); void Init(size_t stylesSize_=64); void CreateFont(const FontSpecification &fs); void Refresh(Surface &surface); void AllocStyles(size_t sizeNew); void EnsureStyle(size_t index); void ResetDefaultStyle(); void ClearStyles(); void SetStyleFontName(int styleIndex, const char *name); bool ProtectionActive() const; bool ValidStyle(size_t styleIndex) const; void CalcLargestMarkerHeight(); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/SplitVector.h0000644000175000017500000001617111763437013021060 00000000000000// Scintilla source code edit control /** @file SplitVector.h ** Main data structure for holding arrays that handle insertions ** and deletions efficiently. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SPLITVECTOR_H #define SPLITVECTOR_H template class SplitVector { protected: T *body; int size; int lengthBody; int part1Length; int gapLength; /// invariant: gapLength == size - lengthBody int growSize; /// Move the gap to a particular position so that insertion and /// deletion at that point will not require much copying and /// hence be fast. void GapTo(int position) { if (position != part1Length) { if (position < part1Length) { memmove( body + position + gapLength, body + position, sizeof(T) * (part1Length - position)); } else { // position > part1Length memmove( body + part1Length, body + part1Length + gapLength, sizeof(T) * (position - part1Length)); } part1Length = position; } } /// Check that there is room in the buffer for an insertion, /// reallocating if more space needed. void RoomFor(int insertionLength) { if (gapLength <= insertionLength) { while (growSize < size / 6) growSize *= 2; ReAllocate(size + insertionLength + growSize); } } void Init() { body = NULL; growSize = 8; size = 0; lengthBody = 0; part1Length = 0; gapLength = 0; } public: /// Construct a split buffer. SplitVector() { Init(); } ~SplitVector() { delete []body; body = 0; } int GetGrowSize() const { return growSize; } void SetGrowSize(int growSize_) { growSize = growSize_; } /// Reallocate the storage for the buffer to be newSize and /// copy exisiting contents to the new buffer. /// Must not be used to decrease the size of the buffer. void ReAllocate(int newSize) { if (newSize > size) { // Move the gap to the end GapTo(lengthBody); T *newBody = new T[newSize]; if ((size != 0) && (body != 0)) { memmove(newBody, body, sizeof(T) * lengthBody); delete []body; } body = newBody; gapLength += newSize - size; size = newSize; } } /// Retrieve the character at a particular position. /// Retrieving positions outside the range of the buffer returns 0. /// The assertions here are disabled since calling code can be /// simpler if out of range access works and returns 0. T ValueAt(int position) const { if (position < part1Length) { //PLATFORM_ASSERT(position >= 0); if (position < 0) { return 0; } else { return body[position]; } } else { //PLATFORM_ASSERT(position < lengthBody); if (position >= lengthBody) { return 0; } else { return body[gapLength + position]; } } } void SetValueAt(int position, T v) { if (position < part1Length) { PLATFORM_ASSERT(position >= 0); if (position < 0) { ; } else { body[position] = v; } } else { PLATFORM_ASSERT(position < lengthBody); if (position >= lengthBody) { ; } else { body[gapLength + position] = v; } } } T &operator[](int position) const { PLATFORM_ASSERT(position >= 0 && position < lengthBody); if (position < part1Length) { return body[position]; } else { return body[gapLength + position]; } } /// Retrieve the length of the buffer. int Length() const { return lengthBody; } /// Insert a single value into the buffer. /// Inserting at positions outside the current range fails. void Insert(int position, T v) { PLATFORM_ASSERT((position >= 0) && (position <= lengthBody)); if ((position < 0) || (position > lengthBody)) { return; } RoomFor(1); GapTo(position); body[part1Length] = v; lengthBody++; part1Length++; gapLength--; } /// Insert a number of elements into the buffer setting their value. /// Inserting at positions outside the current range fails. void InsertValue(int position, int insertLength, T v) { PLATFORM_ASSERT((position >= 0) && (position <= lengthBody)); if (insertLength > 0) { if ((position < 0) || (position > lengthBody)) { return; } RoomFor(insertLength); GapTo(position); for (int i = 0; i < insertLength; i++) body[part1Length + i] = v; lengthBody += insertLength; part1Length += insertLength; gapLength -= insertLength; } } /// Ensure at least length elements allocated, /// appending zero valued elements if needed. void EnsureLength(int wantedLength) { if (Length() < wantedLength) { InsertValue(Length(), wantedLength - Length(), 0); } } /// Insert text into the buffer from an array. void InsertFromArray(int positionToInsert, const T s[], int positionFrom, int insertLength) { PLATFORM_ASSERT((positionToInsert >= 0) && (positionToInsert <= lengthBody)); if (insertLength > 0) { if ((positionToInsert < 0) || (positionToInsert > lengthBody)) { return; } RoomFor(insertLength); GapTo(positionToInsert); memmove(body + part1Length, s + positionFrom, sizeof(T) * insertLength); lengthBody += insertLength; part1Length += insertLength; gapLength -= insertLength; } } /// Delete one element from the buffer. void Delete(int position) { PLATFORM_ASSERT((position >= 0) && (position < lengthBody)); if ((position < 0) || (position >= lengthBody)) { return; } DeleteRange(position, 1); } /// Delete a range from the buffer. /// Deleting positions outside the current range fails. void DeleteRange(int position, int deleteLength) { PLATFORM_ASSERT((position >= 0) && (position + deleteLength <= lengthBody)); if ((position < 0) || ((position + deleteLength) > lengthBody)) { return; } if ((position == 0) && (deleteLength == lengthBody)) { // Full deallocation returns storage and is faster delete []body; Init(); } else if (deleteLength > 0) { GapTo(position); lengthBody -= deleteLength; gapLength += deleteLength; } } /// Delete all the buffer contents. void DeleteAll() { DeleteRange(0, lengthBody); } // Retrieve a range of elements into an array void GetRange(T *buffer, int position, int retrieveLength) const { // Split into up to 2 ranges, before and after the split then use memcpy on each. int range1Length = 0; if (position < part1Length) { int part1AfterPosition = part1Length - position; range1Length = retrieveLength; if (range1Length > part1AfterPosition) range1Length = part1AfterPosition; } memcpy(buffer, body + position, range1Length * sizeof(T)); buffer += range1Length; position = position + range1Length + gapLength; int range2Length = retrieveLength - range1Length; memcpy(buffer, body + position, range2Length * sizeof(T)); } T *BufferPointer() { RoomFor(1); GapTo(lengthBody); body[lengthBody] = 0; return body; } T *RangePointer(int position, int rangeLength) { if (position < part1Length) { if ((position + rangeLength) > part1Length) { // Range overlaps gap, so move gap to start of range. GapTo(position); return body + position + gapLength; } else { return body + position ; } } else { return body + position + gapLength; } } int GapPosition() const { return part1Length; } }; #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/ContractionState.cxx0000644000175000017500000001440111615412040022420 00000000000000// Scintilla source code edit control /** @file ContractionState.cxx ** Manages visibility of lines for folding and wrapping. **/ // Copyright 1998-2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include "Platform.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif ContractionState::ContractionState() : visible(0), expanded(0), heights(0), displayLines(0), linesInDocument(1) { //InsertLine(0); } ContractionState::~ContractionState() { Clear(); } void ContractionState::EnsureData() { if (OneToOne()) { visible = new RunStyles(); expanded = new RunStyles(); heights = new RunStyles(); displayLines = new Partitioning(4); InsertLines(0, linesInDocument); } } void ContractionState::Clear() { delete visible; visible = 0; delete expanded; expanded = 0; delete heights; heights = 0; delete displayLines; displayLines = 0; linesInDocument = 1; } int ContractionState::LinesInDoc() const { if (OneToOne()) { return linesInDocument; } else { return displayLines->Partitions() - 1; } } int ContractionState::LinesDisplayed() const { if (OneToOne()) { return linesInDocument; } else { return displayLines->PositionFromPartition(LinesInDoc()); } } int ContractionState::DisplayFromDoc(int lineDoc) const { if (OneToOne()) { return lineDoc; } else { if (lineDoc > displayLines->Partitions()) lineDoc = displayLines->Partitions(); return displayLines->PositionFromPartition(lineDoc); } } int ContractionState::DocFromDisplay(int lineDisplay) const { if (OneToOne()) { return lineDisplay; } else { if (lineDisplay <= 0) { return 0; } if (lineDisplay > LinesDisplayed()) { return displayLines->PartitionFromPosition(LinesDisplayed()); } int lineDoc = displayLines->PartitionFromPosition(lineDisplay); PLATFORM_ASSERT(GetVisible(lineDoc)); return lineDoc; } } void ContractionState::InsertLine(int lineDoc) { if (OneToOne()) { linesInDocument++; } else { visible->InsertSpace(lineDoc, 1); visible->SetValueAt(lineDoc, 1); expanded->InsertSpace(lineDoc, 1); expanded->SetValueAt(lineDoc, 1); heights->InsertSpace(lineDoc, 1); heights->SetValueAt(lineDoc, 1); int lineDisplay = DisplayFromDoc(lineDoc); displayLines->InsertPartition(lineDoc, lineDisplay); displayLines->InsertText(lineDoc, 1); } } void ContractionState::InsertLines(int lineDoc, int lineCount) { for (int l = 0; l < lineCount; l++) { InsertLine(lineDoc + l); } Check(); } void ContractionState::DeleteLine(int lineDoc) { if (OneToOne()) { linesInDocument--; } else { if (GetVisible(lineDoc)) { displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc)); } displayLines->RemovePartition(lineDoc); visible->DeleteRange(lineDoc, 1); expanded->DeleteRange(lineDoc, 1); heights->DeleteRange(lineDoc, 1); } } void ContractionState::DeleteLines(int lineDoc, int lineCount) { for (int l = 0; l < lineCount; l++) { DeleteLine(lineDoc); } Check(); } bool ContractionState::GetVisible(int lineDoc) const { if (OneToOne()) { return true; } else { if (lineDoc >= visible->Length()) return true; return visible->ValueAt(lineDoc) == 1; } } bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) { if (OneToOne() && visible_) { return false; } else { EnsureData(); int delta = 0; Check(); if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) { for (int line = lineDocStart; line <= lineDocEnd; line++) { if (GetVisible(line) != visible_) { int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line); visible->SetValueAt(line, visible_ ? 1 : 0); displayLines->InsertText(line, difference); delta += difference; } } } else { return false; } Check(); return delta != 0; } } bool ContractionState::HiddenLines() const { if (OneToOne()) { return false; } else { return !visible->AllSameAs(1); } } bool ContractionState::GetExpanded(int lineDoc) const { if (OneToOne()) { return true; } else { Check(); return expanded->ValueAt(lineDoc) == 1; } } bool ContractionState::SetExpanded(int lineDoc, bool expanded_) { if (OneToOne() && expanded_) { return false; } else { EnsureData(); if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) { expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0); Check(); return true; } else { Check(); return false; } } } int ContractionState::ContractedNext(int lineDocStart) const { if (OneToOne()) { return -1; } else { Check(); if (!expanded->ValueAt(lineDocStart)) { return lineDocStart; } else { int lineDocNextChange = expanded->EndRun(lineDocStart); if (lineDocNextChange < LinesInDoc()) return lineDocNextChange; else return -1; } } } int ContractionState::GetHeight(int lineDoc) const { if (OneToOne()) { return 1; } else { return heights->ValueAt(lineDoc); } } // Set the number of display lines needed for this line. // Return true if this is a change. bool ContractionState::SetHeight(int lineDoc, int height) { if (OneToOne() && (height == 1)) { return false; } else if (lineDoc < LinesInDoc()) { EnsureData(); if (GetHeight(lineDoc) != height) { if (GetVisible(lineDoc)) { displayLines->InsertText(lineDoc, height - GetHeight(lineDoc)); } heights->SetValueAt(lineDoc, height); Check(); return true; } else { Check(); return false; } } else { return false; } } void ContractionState::ShowAll() { int lines = LinesInDoc(); Clear(); linesInDocument = lines; } // Debugging checks void ContractionState::Check() const { #ifdef CHECK_CORRECTNESS for (int vline = 0; vline < LinesDisplayed(); vline++) { const int lineDoc = DocFromDisplay(vline); PLATFORM_ASSERT(GetVisible(lineDoc)); } for (int lineDoc = 0; lineDoc < LinesInDoc(); lineDoc++) { const int displayThis = DisplayFromDoc(lineDoc); const int displayNext = DisplayFromDoc(lineDoc + 1); const int height = displayNext - displayThis; PLATFORM_ASSERT(height >= 0); if (GetVisible(lineDoc)) { PLATFORM_ASSERT(GetHeight(lineDoc) == height); } else { PLATFORM_ASSERT(0 == height); } } #endif } presage-0.8.8/apps/gtk/gprompter/scintilla/src/Style.cxx0000644000175000017500000000710711726020232020242 00000000000000// Scintilla source code edit control /** @file Style.cxx ** Defines the font and colour style for a class of text. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include "Platform.h" #include "Scintilla.h" #include "Style.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif FontAlias::FontAlias() { } FontAlias::~FontAlias() { SetID(0); // ~Font will not release the actual font resource sine it is now 0 } void FontAlias::MakeAlias(Font &fontOrigin) { SetID(fontOrigin.GetID()); } void FontAlias::ClearFont() { SetID(0); } bool FontSpecification::EqualTo(const FontSpecification &other) const { return weight == other.weight && italic == other.italic && size == other.size && characterSet == other.characterSet && fontName == other.fontName; } FontMeasurements::FontMeasurements() { Clear(); } void FontMeasurements::Clear() { ascent = 1; descent = 1; aveCharWidth = 1; spaceWidth = 1; sizeZoomed = 2; } Style::Style() : FontSpecification() { Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, 0, SC_CHARSET_DEFAULT, SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false); } Style::Style(const Style &source) : FontSpecification(), FontMeasurements() { Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), 0, 0, 0, SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false); fore = source.fore; back = source.back; characterSet = source.characterSet; weight = source.weight; italic = source.italic; size = source.size; eolFilled = source.eolFilled; underline = source.underline; caseForce = source.caseForce; visible = source.visible; changeable = source.changeable; hotspot = source.hotspot; } Style::~Style() { } Style &Style::operator=(const Style &source) { if (this == &source) return * this; Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), 0, 0, SC_CHARSET_DEFAULT, SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false); fore = source.fore; back = source.back; characterSet = source.characterSet; weight = source.weight; italic = source.italic; size = source.size; eolFilled = source.eolFilled; underline = source.underline; caseForce = source.caseForce; visible = source.visible; changeable = source.changeable; return *this; } void Style::Clear(ColourDesired fore_, ColourDesired back_, int size_, const char *fontName_, int characterSet_, int weight_, bool italic_, bool eolFilled_, bool underline_, ecaseForced caseForce_, bool visible_, bool changeable_, bool hotspot_) { fore = fore_; back = back_; characterSet = characterSet_; weight = weight_; italic = italic_; size = size_; fontName = fontName_; eolFilled = eolFilled_; underline = underline_; caseForce = caseForce_; visible = visible_; changeable = changeable_; hotspot = hotspot_; font.ClearFont(); FontMeasurements::Clear(); } void Style::ClearTo(const Style &source) { Clear( source.fore, source.back, source.size, source.fontName, source.characterSet, source.weight, source.italic, source.eolFilled, source.underline, source.caseForce, source.visible, source.changeable, source.hotspot); } void Style::Copy(Font &font_, const FontMeasurements &fm_) { font.MakeAlias(font_); #if PLAT_WX font.SetAscent(fm_.ascent); #endif (FontMeasurements &)(*this) = fm_; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/RESearch.cxx0000644000175000017500000006563011615412040020602 00000000000000// Scintilla source code edit control /** @file RESearch.cxx ** Regular expression search library. **/ /* * regex - Regular expression pattern matching and replacement * * By: Ozan S. Yigit (oz) * Dept. of Computer Science * York University * * Original code available from http://www.cs.yorku.ca/~oz/ * Translation to C++ by Neil Hodgson neilh@scintilla.org * Removed all use of register. * Converted to modern function prototypes. * Put all global/static variables into an object so this code can be * used from multiple threads, etc. * Some extensions by Philippe Lhoste PhiLho(a)GMX.net * '?' extensions by Michael Mullin masmullin@gmail.com * * These routines are the PUBLIC DOMAIN equivalents of regex * routines as found in 4.nBSD UN*X, with minor extensions. * * These routines are derived from various implementations found * in software tools books, and Conroy's grep. They are NOT derived * from licensed/restricted software. * For more interesting/academic/complicated implementations, * see Henry Spencer's regexp routines, or GNU Emacs pattern * matching module. * * Modification history removed. * * Interfaces: * RESearch::Compile: compile a regular expression into a NFA. * * const char *RESearch::Compile(const char *pattern, int length, * bool caseSensitive, bool posix) * * Returns a short error string if they fail. * * RESearch::Execute: execute the NFA to match a pattern. * * int RESearch::Execute(characterIndexer &ci, int lp, int endp) * * RESearch::Substitute: substitute the matched portions in a new string. * * int RESearch::Substitute(CharacterIndexer &ci, char *src, char *dst) * * re_fail: failure routine for RESearch::Execute. (no longer used) * * void re_fail(char *msg, char op) * * Regular Expressions: * * [1] char matches itself, unless it is a special * character (metachar): . \ [ ] * + ? ^ $ * and ( ) if posix option. * * [2] . matches any character. * * [3] \ matches the character following it, except: * - \a, \b, \f, \n, \r, \t, \v match the corresponding C * escape char, respectively BEL, BS, FF, LF, CR, TAB and VT; * Note that \r and \n are never matched because Scintilla * regex searches are made line per line * (stripped of end-of-line chars). * - if not in posix mode, when followed by a * left or right round bracket (see [8]); * - when followed by a digit 1 to 9 (see [9]); * - when followed by a left or right angle bracket * (see [10]); * - when followed by d, D, s, S, w or W (see [11]); * - when followed by x and two hexa digits (see [12]. * Backslash is used as an escape character for all * other meta-characters, and itself. * * [4] [set] matches one of the characters in the set. * If the first character in the set is "^", * it matches the characters NOT in the set, i.e. * complements the set. A shorthand S-E (start dash end) * is used to specify a set of characters S up to * E, inclusive. S and E must be characters, otherwise * the dash is taken literally (eg. in expression [\d-a]). * The special characters "]" and "-" have no special * meaning if they appear as the first chars in the set. * To include both, put - first: [-]A-Z] * (or just backslash them). * examples: match: * * [-]|] matches these 3 chars, * * []-|] matches from ] to | chars * * [a-z] any lowercase alpha * * [^-]] any char except - and ] * * [^A-Z] any char except uppercase * alpha * * [a-zA-Z] any alpha * * [5] * any regular expression form [1] to [4] * (except [8], [9] and [10] forms of [3]), * followed by closure char (*) * matches zero or more matches of that form. * * [6] + same as [5], except it matches one or more. * * [5-6] Both [5] and [6] are greedy (they match as much as possible). * Unless they are followed by the 'lazy' quantifier (?) * In which case both [5] and [6] try to match as little as possible * * [7] ? same as [5] except it matches zero or one. * * [8] a regular expression in the form [1] to [13], enclosed * as \(form\) (or (form) with posix flag) matches what * form matches. The enclosure creates a set of tags, * used for [9] and for pattern substitution. * The tagged forms are numbered starting from 1. * * [9] a \ followed by a digit 1 to 9 matches whatever a * previously tagged regular expression ([8]) matched. * * [10] \< a regular expression starting with a \< construct * \> and/or ending with a \> construct, restricts the * pattern matching to the beginning of a word, and/or * the end of a word. A word is defined to be a character * string beginning and/or ending with the characters * A-Z a-z 0-9 and _. Scintilla extends this definition * by user setting. The word must also be preceded and/or * followed by any character outside those mentioned. * * [11] \l a backslash followed by d, D, s, S, w or W, * becomes a character class (both inside and * outside sets []). * d: decimal digits * D: any char except decimal digits * s: whitespace (space, \t \n \r \f \v) * S: any char except whitespace (see above) * w: alphanumeric & underscore (changed by user setting) * W: any char except alphanumeric & underscore (see above) * * [12] \xHH a backslash followed by x and two hexa digits, * becomes the character whose Ascii code is equal * to these digits. If not followed by two digits, * it is 'x' char itself. * * [13] a composite regular expression xy where x and y * are in the form [1] to [12] matches the longest * match of x followed by a match for y. * * [14] ^ a regular expression starting with a ^ character * $ and/or ending with a $ character, restricts the * pattern matching to the beginning of the line, * or the end of line. [anchors] Elsewhere in the * pattern, ^ and $ are treated as ordinary characters. * * * Acknowledgements: * * HCR's Hugh Redelmeier has been most helpful in various * stages of development. He convinced me to include BOW * and EOW constructs, originally invented by Rob Pike at * the University of Toronto. * * References: * Software tools Kernighan & Plauger * Software tools in Pascal Kernighan & Plauger * Grep [rsx-11 C dist] David Conroy * ed - text editor Un*x Programmer's Manual * Advanced editing on Un*x B. W. Kernighan * RegExp routines Henry Spencer * * Notes: * * This implementation uses a bit-set representation for character * classes for speed and compactness. Each character is represented * by one bit in a 256-bit block. Thus, CCL always takes a * constant 32 bytes in the internal nfa, and RESearch::Execute does a single * bit comparison to locate the character in the set. * * Examples: * * pattern: foo*.* * compile: CHR f CHR o CLO CHR o END CLO ANY END END * matches: fo foo fooo foobar fobar foxx ... * * pattern: fo[ob]a[rz] * compile: CHR f CHR o CCL bitset CHR a CCL bitset END * matches: fobar fooar fobaz fooaz * * pattern: foo\\+ * compile: CHR f CHR o CHR o CHR \ CLO CHR \ END END * matches: foo\ foo\\ foo\\\ ... * * pattern: \(foo\)[1-3]\1 (same as foo[1-3]foo) * compile: BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END * matches: foo1foo foo2foo foo3foo * * pattern: \(fo.*\)-\1 * compile: BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END * matches: foo-foo fo-fo fob-fob foobar-foobar ... */ #include #include "CharClassify.h" #include "RESearch.h" // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER #pragma warning(disable: 4514) #endif #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #define OKP 1 #define NOP 0 #define CHR 1 #define ANY 2 #define CCL 3 #define BOL 4 #define EOL 5 #define BOT 6 #define EOT 7 #define BOW 8 #define EOW 9 #define REF 10 #define CLO 11 #define CLQ 12 /* 0 to 1 closure */ #define LCLO 13 /* lazy closure */ #define END 0 /* * The following defines are not meant to be changeable. * They are for readability only. */ #define BLKIND 0370 #define BITIND 07 const char bitarr[] = { 1, 2, 4, 8, 16, 32, 64, '\200' }; #define badpat(x) (*nfa = END, x) /* * Character classification table for word boundary operators BOW * and EOW is passed in by the creator of this object (Scintilla * Document). The Document default state is that word chars are: * 0-9, a-z, A-Z and _ */ RESearch::RESearch(CharClassify *charClassTable) { failure = 0; charClass = charClassTable; Init(); } RESearch::~RESearch() { Clear(); } void RESearch::Init() { sta = NOP; /* status of lastpat */ bol = 0; for (int i = 0; i < MAXTAG; i++) pat[i] = 0; for (int j = 0; j < BITBLK; j++) bittab[j] = 0; } void RESearch::Clear() { for (int i = 0; i < MAXTAG; i++) { delete []pat[i]; pat[i] = 0; bopat[i] = NOTFOUND; eopat[i] = NOTFOUND; } } bool RESearch::GrabMatches(CharacterIndexer &ci) { bool success = true; for (unsigned int i = 0; i < MAXTAG; i++) { if ((bopat[i] != NOTFOUND) && (eopat[i] != NOTFOUND)) { unsigned int len = eopat[i] - bopat[i]; pat[i] = new char[len + 1]; if (pat[i]) { for (unsigned int j = 0; j < len; j++) pat[i][j] = ci.CharAt(bopat[i] + j); pat[i][len] = '\0'; } else { success = false; } } } return success; } void RESearch::ChSet(unsigned char c) { bittab[((c) & BLKIND) >> 3] |= bitarr[(c) & BITIND]; } void RESearch::ChSetWithCase(unsigned char c, bool caseSensitive) { if (caseSensitive) { ChSet(c); } else { if ((c >= 'a') && (c <= 'z')) { ChSet(c); ChSet(static_cast(c - 'a' + 'A')); } else if ((c >= 'A') && (c <= 'Z')) { ChSet(c); ChSet(static_cast(c - 'A' + 'a')); } else { ChSet(c); } } } unsigned char escapeValue(unsigned char ch) { switch (ch) { case 'a': return '\a'; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'v': return '\v'; } return 0; } static int GetHexaChar(unsigned char hd1, unsigned char hd2) { int hexValue = 0; if (hd1 >= '0' && hd1 <= '9') { hexValue += 16 * (hd1 - '0'); } else if (hd1 >= 'A' && hd1 <= 'F') { hexValue += 16 * (hd1 - 'A' + 10); } else if (hd1 >= 'a' && hd1 <= 'f') { hexValue += 16 * (hd1 - 'a' + 10); } else return -1; if (hd2 >= '0' && hd2 <= '9') { hexValue += hd2 - '0'; } else if (hd2 >= 'A' && hd2 <= 'F') { hexValue += hd2 - 'A' + 10; } else if (hd2 >= 'a' && hd2 <= 'f') { hexValue += hd2 - 'a' + 10; } else return -1; return hexValue; } /** * Called when the parser finds a backslash not followed * by a valid expression (like \( in non-Posix mode). * @param pattern: pointer on the char after the backslash. * @param incr: (out) number of chars to skip after expression evaluation. * @return the char if it resolves to a simple char, * or -1 for a char class. In this case, bittab is changed. */ int RESearch::GetBackslashExpression( const char *pattern, int &incr) { // Since error reporting is primitive and messages are not used anyway, // I choose to interpret unexpected syntax in a logical way instead // of reporting errors. Otherwise, we can stick on, eg., PCRE behavior. incr = 0; // Most of the time, will skip the char "naturally". int c; int result = -1; unsigned char bsc = *pattern; if (!bsc) { // Avoid overrun result = '\\'; // \ at end of pattern, take it literally return result; } switch (bsc) { case 'a': case 'b': case 'n': case 'f': case 'r': case 't': case 'v': result = escapeValue(bsc); break; case 'x': { unsigned char hd1 = *(pattern + 1); unsigned char hd2 = *(pattern + 2); int hexValue = GetHexaChar(hd1, hd2); if (hexValue >= 0) { result = hexValue; incr = 2; // Must skip the digits } else { result = 'x'; // \x without 2 digits: see it as 'x' } } break; case 'd': for (c = '0'; c <= '9'; c++) { ChSet(static_cast(c)); } break; case 'D': for (c = 0; c < MAXCHR; c++) { if (c < '0' || c > '9') { ChSet(static_cast(c)); } } break; case 's': ChSet(' '); ChSet('\t'); ChSet('\n'); ChSet('\r'); ChSet('\f'); ChSet('\v'); break; case 'S': for (c = 0; c < MAXCHR; c++) { if (c != ' ' && !(c >= 0x09 && c <= 0x0D)) { ChSet(static_cast(c)); } } break; case 'w': for (c = 0; c < MAXCHR; c++) { if (iswordc(static_cast(c))) { ChSet(static_cast(c)); } } break; case 'W': for (c = 0; c < MAXCHR; c++) { if (!iswordc(static_cast(c))) { ChSet(static_cast(c)); } } break; default: result = bsc; } return result; } const char *RESearch::Compile(const char *pattern, int length, bool caseSensitive, bool posix) { char *mp=nfa; /* nfa pointer */ char *lp; /* saved pointer */ char *sp=nfa; /* another one */ char *mpMax = mp + MAXNFA - BITBLK - 10; int tagi = 0; /* tag stack index */ int tagc = 1; /* actual tag count */ int n; char mask; /* xor mask -CCL/NCL */ int c1, c2, prevChar; if (!pattern || !length) { if (sta) return 0; else return badpat("No previous regular expression"); } sta = NOP; const char *p=pattern; /* pattern pointer */ for (int i=0; i mpMax) return badpat("Pattern too long"); lp = mp; switch (*p) { case '.': /* match any char */ *mp++ = ANY; break; case '^': /* match beginning */ if (p == pattern) *mp++ = BOL; else { *mp++ = CHR; *mp++ = *p; } break; case '$': /* match endofline */ if (!*(p+1)) *mp++ = EOL; else { *mp++ = CHR; *mp++ = *p; } break; case '[': /* match char class */ *mp++ = CCL; prevChar = 0; i++; if (*++p == '^') { mask = '\377'; i++; p++; } else mask = 0; if (*p == '-') { /* real dash */ i++; prevChar = *p; ChSet(*p++); } if (*p == ']') { /* real brace */ i++; prevChar = *p; ChSet(*p++); } while (*p && *p != ']') { if (*p == '-') { if (prevChar < 0) { // Previous def. was a char class like \d, take dash literally prevChar = *p; ChSet(*p); } else if (*(p+1)) { if (*(p+1) != ']') { c1 = prevChar + 1; i++; c2 = static_cast(*++p); if (c2 == '\\') { if (!*(p+1)) // End of RE return badpat("Missing ]"); else { i++; p++; int incr; c2 = GetBackslashExpression(p, incr); i += incr; p += incr; if (c2 >= 0) { // Convention: \c (c is any char) is case sensitive, whatever the option ChSet(static_cast(c2)); prevChar = c2; } else { // bittab is already changed prevChar = -1; } } } if (prevChar < 0) { // Char after dash is char class like \d, take dash literally prevChar = '-'; ChSet('-'); } else { // Put all chars between c1 and c2 included in the char set while (c1 <= c2) { ChSetWithCase(static_cast(c1++), caseSensitive); } } } else { // Dash before the ], take it literally prevChar = *p; ChSet(*p); } } else { return badpat("Missing ]"); } } else if (*p == '\\' && *(p+1)) { i++; p++; int incr; int c = GetBackslashExpression(p, incr); i += incr; p += incr; if (c >= 0) { // Convention: \c (c is any char) is case sensitive, whatever the option ChSet(static_cast(c)); prevChar = c; } else { // bittab is already changed prevChar = -1; } } else { prevChar = static_cast(*p); ChSetWithCase(*p, caseSensitive); } i++; p++; } if (!*p) return badpat("Missing ]"); for (n = 0; n < BITBLK; bittab[n++] = 0) *mp++ = static_cast(mask ^ bittab[n]); break; case '*': /* match 0 or more... */ case '+': /* match 1 or more... */ case '?': if (p == pattern) return badpat("Empty closure"); lp = sp; /* previous opcode */ if (*lp == CLO || *lp == LCLO) /* equivalence... */ break; switch (*lp) { case BOL: case BOT: case EOT: case BOW: case EOW: case REF: return badpat("Illegal closure"); default: break; } if (*p == '+') for (sp = mp; lp < sp; lp++) *mp++ = *lp; *mp++ = END; *mp++ = END; sp = mp; while (--mp > lp) *mp = mp[-1]; if (*p == '?') *mp = CLQ; else if (*(p+1) == '?') *mp = LCLO; else *mp = CLO; mp = sp; break; case '\\': /* tags, backrefs... */ i++; switch (*++p) { case '<': *mp++ = BOW; break; case '>': if (*sp == BOW) return badpat("Null pattern inside \\<\\>"); *mp++ = EOW; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = *p-'0'; if (tagi > 0 && tagstk[tagi] == n) return badpat("Cyclical reference"); if (tagc > n) { *mp++ = static_cast(REF); *mp++ = static_cast(n); } else return badpat("Undetermined reference"); break; default: if (!posix && *p == '(') { if (tagc < MAXTAG) { tagstk[++tagi] = tagc; *mp++ = BOT; *mp++ = static_cast(tagc++); } else return badpat("Too many \\(\\) pairs"); } else if (!posix && *p == ')') { if (*sp == BOT) return badpat("Null pattern inside \\(\\)"); if (tagi > 0) { *mp++ = static_cast(EOT); *mp++ = static_cast(tagstk[tagi--]); } else return badpat("Unmatched \\)"); } else { int incr; int c = GetBackslashExpression(p, incr); i += incr; p += incr; if (c >= 0) { *mp++ = CHR; *mp++ = static_cast(c); } else { *mp++ = CCL; mask = 0; for (n = 0; n < BITBLK; bittab[n++] = 0) *mp++ = static_cast(mask ^ bittab[n]); } } } break; default : /* an ordinary char */ if (posix && *p == '(') { if (tagc < MAXTAG) { tagstk[++tagi] = tagc; *mp++ = BOT; *mp++ = static_cast(tagc++); } else return badpat("Too many () pairs"); } else if (posix && *p == ')') { if (*sp == BOT) return badpat("Null pattern inside ()"); if (tagi > 0) { *mp++ = static_cast(EOT); *mp++ = static_cast(tagstk[tagi--]); } else return badpat("Unmatched )"); } else { unsigned char c = *p; if (!c) // End of RE c = '\\'; // We take it as raw backslash if (caseSensitive || !iswordc(c)) { *mp++ = CHR; *mp++ = c; } else { *mp++ = CCL; mask = 0; ChSetWithCase(c, false); for (n = 0; n < BITBLK; bittab[n++] = 0) *mp++ = static_cast(mask ^ bittab[n]); } } break; } sp = lp; } if (tagi > 0) return badpat((posix ? "Unmatched (" : "Unmatched \\(")); *mp = END; sta = OKP; return 0; } /* * RESearch::Execute: * execute nfa to find a match. * * special cases: (nfa[0]) * BOL * Match only once, starting from the * beginning. * CHR * First locate the character without * calling PMatch, and if found, call * PMatch for the remaining string. * END * RESearch::Compile failed, poor luser did not * check for it. Fail fast. * * If a match is found, bopat[0] and eopat[0] are set * to the beginning and the end of the matched fragment, * respectively. * */ int RESearch::Execute(CharacterIndexer &ci, int lp, int endp) { unsigned char c; int ep = NOTFOUND; char *ap = nfa; bol = lp; failure = 0; Clear(); switch (*ap) { case BOL: /* anchored: match from BOL only */ ep = PMatch(ci, lp, endp, ap); break; case EOL: /* just searching for end of line normal path doesn't work */ if (*(ap+1) == END) { lp = endp; ep = lp; break; } else { return 0; } case CHR: /* ordinary char: locate it fast */ c = *(ap+1); while ((lp < endp) && (ci.CharAt(lp) != c)) lp++; if (lp >= endp) /* if EOS, fail, else fall thru. */ return 0; default: /* regular matching all the way. */ while (lp < endp) { ep = PMatch(ci, lp, endp, ap); if (ep != NOTFOUND) break; lp++; } break; case END: /* munged automaton. fail always */ return 0; } if (ep == NOTFOUND) return 0; bopat[0] = lp; eopat[0] = ep; return 1; } /* * PMatch: internal routine for the hard part * * This code is partly snarfed from an early grep written by * David Conroy. The backref and tag stuff, and various other * innovations are by oz. * * special case optimizations: (nfa[n], nfa[n+1]) * CLO ANY * We KNOW .* will match everything upto the * end of line. Thus, directly go to the end of * line, without recursive PMatch calls. As in * the other closure cases, the remaining pattern * must be matched by moving backwards on the * string recursively, to find a match for xy * (x is ".*" and y is the remaining pattern) * where the match satisfies the LONGEST match for * x followed by a match for y. * CLO CHR * We can again scan the string forward for the * single char and at the point of failure, we * execute the remaining nfa recursively, same as * above. * * At the end of a successful match, bopat[n] and eopat[n] * are set to the beginning and end of subpatterns matched * by tagged expressions (n = 1 to 9). */ extern void re_fail(char *,char); #define isinset(x,y) ((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND]) /* * skip values for CLO XXX to skip past the closure */ #define ANYSKIP 2 /* [CLO] ANY END */ #define CHRSKIP 3 /* [CLO] CHR chr END */ #define CCLSKIP 34 /* [CLO] CCL 32 bytes END */ int RESearch::PMatch(CharacterIndexer &ci, int lp, int endp, char *ap) { int op, c, n; int e; /* extra pointer for CLO */ int bp; /* beginning of subpat... */ int ep; /* ending of subpat... */ int are; /* to save the line ptr. */ int llp; /* lazy lp for LCLO */ while ((op = *ap++) != END) switch (op) { case CHR: if (ci.CharAt(lp++) != *ap++) return NOTFOUND; break; case ANY: if (lp++ >= endp) return NOTFOUND; break; case CCL: if (lp >= endp) return NOTFOUND; c = ci.CharAt(lp++); if (!isinset(ap,c)) return NOTFOUND; ap += BITBLK; break; case BOL: if (lp != bol) return NOTFOUND; break; case EOL: if (lp < endp) return NOTFOUND; break; case BOT: bopat[static_cast(*ap++)] = lp; break; case EOT: eopat[static_cast(*ap++)] = lp; break; case BOW: if ((lp!=bol && iswordc(ci.CharAt(lp-1))) || !iswordc(ci.CharAt(lp))) return NOTFOUND; break; case EOW: if (lp==bol || !iswordc(ci.CharAt(lp-1)) || iswordc(ci.CharAt(lp))) return NOTFOUND; break; case REF: n = *ap++; bp = bopat[n]; ep = eopat[n]; while (bp < ep) if (ci.CharAt(bp++) != ci.CharAt(lp++)) return NOTFOUND; break; case LCLO: case CLQ: case CLO: are = lp; switch (*ap) { case ANY: if (op == CLO || op == LCLO) while (lp < endp) lp++; else if (lp < endp) lp++; n = ANYSKIP; break; case CHR: c = *(ap+1); if (op == CLO || op == LCLO) while ((lp < endp) && (c == ci.CharAt(lp))) lp++; else if ((lp < endp) && (c == ci.CharAt(lp))) lp++; n = CHRSKIP; break; case CCL: while ((lp < endp) && isinset(ap+1,ci.CharAt(lp))) lp++; n = CCLSKIP; break; default: failure = true; //re_fail("closure: bad nfa.", *ap); return NOTFOUND; } ap += n; llp = lp; e = NOTFOUND; while (llp >= are) { int q; if ((q = PMatch(ci, llp, endp, ap)) != NOTFOUND) { e = q; lp = llp; if (op != LCLO) return e; } if (*ap == END) return e; --llp; } if (*ap == EOT) PMatch(ci, lp, endp, ap); return e; default: //re_fail("RESearch::Execute: bad nfa.", static_cast(op)); return NOTFOUND; } return lp; } /* * RESearch::Substitute: * substitute the matched portions of the src in dst. * * & substitute the entire matched pattern. * * \digit substitute a subpattern, with the given tag number. * Tags are numbered from 1 to 9. If the particular * tagged subpattern does not exist, null is substituted. */ int RESearch::Substitute(CharacterIndexer &ci, char *src, char *dst) { unsigned char c; int pin; int bp; int ep; if (!*src || !bopat[0]) return 0; while ((c = *src++) != 0) { switch (c) { case '&': pin = 0; break; case '\\': c = *src++; if (c >= '0' && c <= '9') { pin = c - '0'; break; } default: *dst++ = c; continue; } if ((bp = bopat[pin]) != 0 && (ep = eopat[pin]) != 0) { while (ci.CharAt(bp) && bp < ep) *dst++ = ci.CharAt(bp++); if (bp < ep) return 0; } } *dst = '\0'; return 1; } presage-0.8.8/apps/gtk/gprompter/scintilla/src/ExternalLexer.h0000644000175000017500000000427311615412040021351 00000000000000// Scintilla source code edit control /** @file ExternalLexer.h ** Support external lexers in DLLs. **/ // Copyright 2001 Simon Steele , portions copyright Neil Hodgson. // The License.txt file describes the conditions under which this software may be distributed. #ifndef EXTERNALLEXER_H #define EXTERNALLEXER_H #if PLAT_WIN #define EXT_LEXER_DECL __stdcall #else #define EXT_LEXER_DECL #endif #ifdef SCI_NAMESPACE namespace Scintilla { #endif typedef void*(EXT_LEXER_DECL *GetLexerFunction)(unsigned int Index); typedef int (EXT_LEXER_DECL *GetLexerCountFn)(); typedef void (EXT_LEXER_DECL *GetLexerNameFn)(unsigned int Index, char *name, int buflength); typedef LexerFactoryFunction(EXT_LEXER_DECL *GetLexerFactoryFunction)(unsigned int Index); /// Sub-class of LexerModule to use an external lexer. class ExternalLexerModule : public LexerModule { protected: GetLexerFactoryFunction fneFactory; char name[100]; public: ExternalLexerModule(int language_, LexerFunction fnLexer_, const char *languageName_=0, LexerFunction fnFolder_=0) : LexerModule(language_, fnLexer_, 0, fnFolder_), fneFactory(0) { strncpy(name, languageName_, sizeof(name)); name[sizeof(name)-1] = '\0'; languageName = name; } virtual void SetExternal(GetLexerFactoryFunction fFactory, int index); }; /// LexerMinder points to an ExternalLexerModule - so we don't leak them. class LexerMinder { public: ExternalLexerModule *self; LexerMinder *next; }; /// LexerLibrary exists for every External Lexer DLL, contains LexerMinders. class LexerLibrary { DynamicLibrary *lib; LexerMinder *first; LexerMinder *last; public: LexerLibrary(const char *ModuleName); ~LexerLibrary(); void Release(); LexerLibrary *next; std::string m_sModuleName; }; /// LexerManager manages external lexers, contains LexerLibrarys. class LexerManager { public: ~LexerManager(); static LexerManager *GetInstance(); static void DeleteInstance(); void Load(const char *path); void Clear(); private: LexerManager(); static LexerManager *theInstance; void LoadLexerLibrary(const char *module); LexerLibrary *first; LexerLibrary *last; }; class LMMinder { public: ~LMMinder(); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/src/LineMarker.h0000644000175000017500000000362711763437013020635 00000000000000// Scintilla source code edit control /** @file LineMarker.h ** Defines the look of a line marker in the margin . **/ // Copyright 1998-2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LINEMARKER_H #define LINEMARKER_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class LineMarker { public: enum typeOfFold { undefined, head, body, tail, headWithTail }; int markType; ColourDesired fore; ColourDesired back; ColourDesired backSelected; int alpha; XPM *pxpm; RGBAImage *image; LineMarker() { markType = SC_MARK_CIRCLE; fore = ColourDesired(0,0,0); back = ColourDesired(0xff,0xff,0xff); backSelected = ColourDesired(0xff,0x00,0x00); alpha = SC_ALPHA_NOALPHA; pxpm = NULL; image = NULL; } LineMarker(const LineMarker &) { // Defined to avoid pxpm being blindly copied, not as a complete copy constructor markType = SC_MARK_CIRCLE; fore = ColourDesired(0,0,0); back = ColourDesired(0xff,0xff,0xff); backSelected = ColourDesired(0xff,0x00,0x00); alpha = SC_ALPHA_NOALPHA; pxpm = NULL; image = NULL; } ~LineMarker() { delete pxpm; delete image; } LineMarker &operator=(const LineMarker &other) { // Defined to avoid pxpm being blindly copied, not as a complete assignment operator if (this != &other) { markType = SC_MARK_CIRCLE; fore = ColourDesired(0,0,0); back = ColourDesired(0xff,0xff,0xff); backSelected = ColourDesired(0xff,0x00,0x00); alpha = SC_ALPHA_NOALPHA; delete pxpm; pxpm = NULL; delete image; image = NULL; } return *this; } void SetXPM(const char *textForm); void SetXPM(const char *const *linesForm); void SetRGBAImage(Point sizeRGBAImage, const unsigned char *pixelsRGBAImage); void Draw(Surface *surface, PRectangle &rc, Font &fontForCharacter, typeOfFold tFold, int marginStyle); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/gtk/0000755000175000017500000000000011764714757016517 500000000000000presage-0.8.8/apps/gtk/gprompter/scintilla/gtk/scintilla-marshal.h0000644000175000017500000000141011615412040022162 00000000000000 #ifndef __scintilla_marshal_MARSHAL_H__ #define __scintilla_marshal_MARSHAL_H__ #include G_BEGIN_DECLS /* NONE:INT,POINTER (scintilla-marshal.list:1) */ extern void scintilla_marshal_VOID__INT_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); #define scintilla_marshal_NONE__INT_POINTER scintilla_marshal_VOID__INT_POINTER G_END_DECLS #endif /* __scintilla_marshal_MARSHAL_H__ */ presage-0.8.8/apps/gtk/gprompter/scintilla/gtk/ScintillaGTK.cxx0000644000175000017500000026747111763437013021456 00000000000000// Scintilla source code edit control // ScintillaGTK.cxx - GTK+ specific subclass of ScintillaBase // Copyright 1998-2004 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #if PLAT_GTK_WIN32 #include #endif #include "ILexer.h" #include "Scintilla.h" #include "ScintillaWidget.h" #ifdef SCI_LEXER #include "SciLexer.h" #endif #include "SVector.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "CallTip.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "AutoComplete.h" #include "ViewStyle.h" #include "Decoration.h" #include "CharClassify.h" #include "Document.h" #include "Selection.h" #include "PositionCache.h" #include "Editor.h" #include "ScintillaBase.h" #include "UniConversion.h" #include "scintilla-marshal.h" #ifdef SCI_LEXER #include #include #include "LexerModule.h" #include "ExternalLexer.h" #endif #include "Converter.h" #if defined(__clang__) // Clang 3.0 incorrectly displays sentinel warnings. Fixed by clang 3.1. #pragma GCC diagnostic ignored "-Wsentinel" #endif #if GTK_CHECK_VERSION(2,20,0) #define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w))) #define IS_WIDGET_MAPPED(w) (gtk_widget_get_mapped(GTK_WIDGET(w))) #define IS_WIDGET_VISIBLE(w) (gtk_widget_get_visible(GTK_WIDGET(w))) #else #define IS_WIDGET_REALIZED(w) (GTK_WIDGET_REALIZED(w)) #define IS_WIDGET_MAPPED(w) (GTK_WIDGET_MAPPED(w)) #define IS_WIDGET_VISIBLE(w) (GTK_WIDGET_VISIBLE(w)) #endif static GdkWindow *WindowFromWidget(GtkWidget *w) { #if GTK_CHECK_VERSION(3,0,0) return gtk_widget_get_window(w); #else return w->window; #endif } static GdkWindow *PWindow(const Window &w) { GtkWidget *widget = reinterpret_cast(w.GetID()); #if GTK_CHECK_VERSION(3,0,0) return gtk_widget_get_window(widget); #else return widget->window; #endif } #ifdef _MSC_VER // Constant conditional expressions are because of GTK+ headers #pragma warning(disable: 4127) // Ignore unreferenced local functions in GTK+ headers #pragma warning(disable: 4505) #endif #define OBJECT_CLASS GObjectClass #ifdef SCI_NAMESPACE using namespace Scintilla; #endif extern char *UTF8FromLatin1(const char *s, int &len); class ScintillaGTK : public ScintillaBase { _ScintillaObject *sci; Window wText; Window scrollbarv; Window scrollbarh; GtkAdjustment *adjustmentv; GtkAdjustment *adjustmenth; int scrollBarWidth; int scrollBarHeight; SelectionText primary; GdkEventButton evbtn; bool capturedMouse; bool dragWasDropped; int lastKey; int rectangularSelectionModifier; GtkWidgetClass *parentClass; static GdkAtom atomClipboard; static GdkAtom atomUTF8; static GdkAtom atomString; static GdkAtom atomUriList; static GdkAtom atomDROPFILES_DND; GdkAtom atomSought; #if PLAT_GTK_WIN32 CLIPFORMAT cfColumnSelect; #endif Window wPreedit; Window wPreeditDraw; GtkIMContext *im_context; // Wheel mouse support unsigned int linesPerScroll; GTimeVal lastWheelMouseTime; gint lastWheelMouseDirection; gint wheelMouseIntensity; #if GTK_CHECK_VERSION(3,0,0) cairo_rectangle_list_t *rgnUpdate; #else GdkRegion *rgnUpdate; #endif // Private so ScintillaGTK objects can not be copied ScintillaGTK(const ScintillaGTK &); ScintillaGTK &operator=(const ScintillaGTK &); public: ScintillaGTK(_ScintillaObject *sci_); virtual ~ScintillaGTK(); static void ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class); private: virtual void Initialise(); virtual void Finalise(); virtual void DisplayCursor(Window::Cursor c); virtual bool DragThreshold(Point ptStart, Point ptNow); virtual void StartDrag(); int TargetAsUTF8(char *text); int EncodedFromUTF8(char *utf8, char *encoded); virtual bool ValidCodePage(int codePage) const; public: // Public for scintilla_send_message virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); private: virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); virtual void SetTicking(bool on); virtual bool SetIdle(bool on); virtual void SetMouseCapture(bool on); virtual bool HaveMouseCapture(); virtual bool PaintContains(PRectangle rc); void FullPaint(); virtual PRectangle GetClientRectangle(); void SyncPaint(PRectangle rc); virtual void ScrollText(int linesToMove); virtual void SetVerticalScrollPos(); virtual void SetHorizontalScrollPos(); virtual bool ModifyScrollBars(int nMax, int nPage); void ReconfigureScrollBars(); virtual void NotifyChange(); virtual void NotifyFocus(bool focus); virtual void NotifyParent(SCNotification scn); void NotifyKey(int key, int modifiers); void NotifyURIDropped(const char *list); const char *CharacterSetID() const; virtual CaseFolder *CaseFolderForEncoding(); virtual std::string CaseMapString(const std::string &s, int caseMapping); virtual int KeyDefault(int key, int modifiers); virtual void CopyToClipboard(const SelectionText &selectedText); virtual void Copy(); virtual void Paste(); virtual void CreateCallTipWindow(PRectangle rc); virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true); bool OwnPrimarySelection(); virtual void ClaimSelection(); void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText); void ReceivedSelection(GtkSelectionData *selection_data); void ReceivedDrop(GtkSelectionData *selection_data); static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *selected); void StoreOnClipboard(SelectionText *clipText); static void ClipboardGetSelection(GtkClipboard* clip, GtkSelectionData *selection_data, guint info, void *data); static void ClipboardClearSelection(GtkClipboard* clip, void *data); void UnclaimSelection(GdkEventSelection *selection_event); void Resize(int width, int height); // Callback functions void RealizeThis(GtkWidget *widget); static void Realize(GtkWidget *widget); void UnRealizeThis(GtkWidget *widget); static void UnRealize(GtkWidget *widget); void MapThis(); static void Map(GtkWidget *widget); void UnMapThis(); static void UnMap(GtkWidget *widget); gint FocusInThis(GtkWidget *widget); static gint FocusIn(GtkWidget *widget, GdkEventFocus *event); gint FocusOutThis(GtkWidget *widget); static gint FocusOut(GtkWidget *widget, GdkEventFocus *event); static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition); static void GetPreferredWidth(GtkWidget *widget, gint *minimalWidth, gint *naturalWidth); static void GetPreferredHeight(GtkWidget *widget, gint *minimalHeight, gint *naturalHeight); static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation); #if GTK_CHECK_VERSION(3,0,0) gboolean DrawTextThis(cairo_t *cr); static gboolean DrawText(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis); gboolean DrawThis(cairo_t *cr); static gboolean DrawMain(GtkWidget *widget, cairo_t *cr); #else gboolean ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose); static gboolean ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis); gboolean Expose(GtkWidget *widget, GdkEventExpose *ose); static gboolean ExposeMain(GtkWidget *widget, GdkEventExpose *ose); #endif static void Draw(GtkWidget *widget, GdkRectangle *area); void ForAll(GtkCallback callback, gpointer callback_data); static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis); static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis); gint PressThis(GdkEventButton *event); static gint Press(GtkWidget *widget, GdkEventButton *event); static gint MouseRelease(GtkWidget *widget, GdkEventButton *event); static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event); static gint Motion(GtkWidget *widget, GdkEventMotion *event); gboolean KeyThis(GdkEventKey *event); static gboolean KeyPress(GtkWidget *widget, GdkEventKey *event); static gboolean KeyRelease(GtkWidget *widget, GdkEventKey *event); #if GTK_CHECK_VERSION(3,0,0) gboolean DrawPreeditThis(GtkWidget *widget, cairo_t *cr); static gboolean DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis); #else gboolean ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose); static gboolean ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis); #endif void CommitThis(char *str); static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis); void PreeditChangedThis(); static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis); static void StyleSetText(GtkWidget *widget, GtkStyle *previous, void*); static void RealizeText(GtkWidget *widget, void*); static void Destroy(GObject *object); static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data, guint time); static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time); static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event); static void DragBegin(GtkWidget *widget, GdkDragContext *context); gboolean DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime); static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint dragtime); static void DragLeave(GtkWidget *widget, GdkDragContext *context, guint time); static void DragEnd(GtkWidget *widget, GdkDragContext *context); static gboolean Drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time); static void DragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time); static void DragDataGet(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time); static gboolean TimeOut(ScintillaGTK *sciThis); static gboolean IdleCallback(ScintillaGTK *sciThis); static gboolean StyleIdle(ScintillaGTK *sciThis); virtual void QueueStyling(int upTo); static void PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis); #if GTK_CHECK_VERSION(3,0,0) static gboolean DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip); #else static gboolean ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ct); #endif static gboolean PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis); static sptr_t DirectFunction(ScintillaGTK *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam); }; enum { COMMAND_SIGNAL, NOTIFY_SIGNAL, LAST_SIGNAL }; static gint scintilla_signals[LAST_SIGNAL] = { 0 }; enum { TARGET_STRING, TARGET_TEXT, TARGET_COMPOUND_TEXT, TARGET_UTF8_STRING, TARGET_URI }; GdkAtom ScintillaGTK::atomClipboard = 0; GdkAtom ScintillaGTK::atomUTF8 = 0; GdkAtom ScintillaGTK::atomString = 0; GdkAtom ScintillaGTK::atomUriList = 0; GdkAtom ScintillaGTK::atomDROPFILES_DND = 0; static const GtkTargetEntry clipboardCopyTargets[] = { { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING }, { (gchar *) "STRING", 0, TARGET_STRING }, }; static const gint nClipboardCopyTargets = sizeof(clipboardCopyTargets) / sizeof(clipboardCopyTargets[0]); static const GtkTargetEntry clipboardPasteTargets[] = { { (gchar *) "text/uri-list", 0, TARGET_URI }, { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING }, { (gchar *) "STRING", 0, TARGET_STRING }, }; static const gint nClipboardPasteTargets = sizeof(clipboardPasteTargets) / sizeof(clipboardPasteTargets[0]); static GtkWidget *PWidget(Window &w) { return reinterpret_cast(w.GetID()); } static ScintillaGTK *ScintillaFromWidget(GtkWidget *widget) { ScintillaObject *scio = reinterpret_cast(widget); return reinterpret_cast(scio->pscin); } ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) : adjustmentv(0), adjustmenth(0), scrollBarWidth(30), scrollBarHeight(30), capturedMouse(false), dragWasDropped(false), lastKey(0), rectangularSelectionModifier(SCMOD_CTRL), parentClass(0), im_context(NULL), lastWheelMouseDirection(0), wheelMouseIntensity(0), rgnUpdate(0) { sci = sci_; wMain = GTK_WIDGET(sci); #if PLAT_GTK_WIN32 rectangularSelectionModifier = SCMOD_ALT; #else rectangularSelectionModifier = SCMOD_CTRL; #endif #if PLAT_GTK_WIN32 // There does not seem to be a real standard for indicating that the clipboard // contains a rectangular selection, so copy Developer Studio. cfColumnSelect = static_cast( ::RegisterClipboardFormat("MSDEVColumnSelect")); // Get intellimouse parameters when running on win32; otherwise use // reasonable default #ifndef SPI_GETWHEELSCROLLLINES #define SPI_GETWHEELSCROLLLINES 104 #endif ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0); #else linesPerScroll = 4; #endif lastWheelMouseTime.tv_sec = 0; lastWheelMouseTime.tv_usec = 0; Initialise(); } ScintillaGTK::~ScintillaGTK() { g_idle_remove_by_data(this); } static void UnRefCursor(GdkCursor *cursor) { #if GTK_CHECK_VERSION(3,0,0) g_object_unref(cursor); #else gdk_cursor_unref(cursor); #endif } void ScintillaGTK::RealizeThis(GtkWidget *widget) { //Platform::DebugPrintf("ScintillaGTK::realize this\n"); #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_realized(widget, TRUE); #else GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); #endif GdkWindowAttr attrs; attrs.window_type = GDK_WINDOW_CHILD; GtkAllocation allocation; #if GTK_CHECK_VERSION(3,0,0) gtk_widget_get_allocation(widget, &allocation); #else allocation = widget->allocation; #endif attrs.x = allocation.x; attrs.y = allocation.y; attrs.width = allocation.width; attrs.height = allocation.height; attrs.wclass = GDK_INPUT_OUTPUT; attrs.visual = gtk_widget_get_visual(widget); #if !GTK_CHECK_VERSION(3,0,0) attrs.colormap = gtk_widget_get_colormap(widget); #endif attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK; GdkCursor *cursor = gdk_cursor_new(GDK_XTERM); attrs.cursor = cursor; #if GTK_CHECK_VERSION(3,0,0) gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attrs, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_CURSOR)); gdk_window_set_user_data(gtk_widget_get_window(widget), widget); GtkStyleContext *styleContext = gtk_widget_get_style_context(widget); if (styleContext) { GdkRGBA colourBackWidget; gtk_style_context_get_background_color(styleContext, GTK_STATE_FLAG_NORMAL, &colourBackWidget); gdk_window_set_background_rgba(gtk_widget_get_window(widget), &colourBackWidget); } gdk_window_show(gtk_widget_get_window(widget)); UnRefCursor(cursor); #else widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR); gdk_window_set_user_data(widget->window, widget); widget->style = gtk_style_attach(widget->style, widget->window); gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]); gdk_window_show(widget->window); UnRefCursor(cursor); #endif wPreedit = gtk_window_new(GTK_WINDOW_POPUP); wPreeditDraw = gtk_drawing_area_new(); GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro #if GTK_CHECK_VERSION(3,0,0) g_signal_connect(G_OBJECT(predrw), "draw", G_CALLBACK(DrawPreedit), this); #else g_signal_connect(G_OBJECT(predrw), "expose_event", G_CALLBACK(ExposePreedit), this); #endif gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw); gtk_widget_realize(PWidget(wPreedit)); gtk_widget_realize(predrw); gtk_widget_show(predrw); im_context = gtk_im_multicontext_new(); g_signal_connect(G_OBJECT(im_context), "commit", G_CALLBACK(Commit), this); g_signal_connect(G_OBJECT(im_context), "preedit_changed", G_CALLBACK(PreeditChanged), this); gtk_im_context_set_client_window(im_context, WindowFromWidget(widget)); GtkWidget *widtxt = PWidget(wText); // // No code inside the G_OBJECT macro g_signal_connect_after(G_OBJECT(widtxt), "style_set", G_CALLBACK(ScintillaGTK::StyleSetText), NULL); g_signal_connect_after(G_OBJECT(widtxt), "realize", G_CALLBACK(ScintillaGTK::RealizeText), NULL); gtk_widget_realize(widtxt); gtk_widget_realize(PWidget(scrollbarv)); gtk_widget_realize(PWidget(scrollbarh)); cursor = gdk_cursor_new(GDK_XTERM); gdk_window_set_cursor(PWindow(wText), cursor); UnRefCursor(cursor); cursor = gdk_cursor_new(GDK_LEFT_PTR); gdk_window_set_cursor(PWindow(scrollbarv), cursor); UnRefCursor(cursor); cursor = gdk_cursor_new(GDK_LEFT_PTR); gdk_window_set_cursor(PWindow(scrollbarh), cursor); UnRefCursor(cursor); gtk_selection_add_targets(widget, GDK_SELECTION_PRIMARY, clipboardCopyTargets, nClipboardCopyTargets); } void ScintillaGTK::Realize(GtkWidget *widget) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); sciThis->RealizeThis(widget); } void ScintillaGTK::UnRealizeThis(GtkWidget *widget) { try { gtk_selection_clear_targets(widget, GDK_SELECTION_PRIMARY); if (IS_WIDGET_MAPPED(widget)) { gtk_widget_unmap(widget); } #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_realized(widget, FALSE); #else GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED); #endif gtk_widget_unrealize(PWidget(wText)); gtk_widget_unrealize(PWidget(scrollbarv)); gtk_widget_unrealize(PWidget(scrollbarh)); gtk_widget_unrealize(PWidget(wPreedit)); gtk_widget_unrealize(PWidget(wPreeditDraw)); g_object_unref(im_context); im_context = NULL; if (GTK_WIDGET_CLASS(parentClass)->unrealize) GTK_WIDGET_CLASS(parentClass)->unrealize(widget); Finalise(); } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::UnRealize(GtkWidget *widget) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); sciThis->UnRealizeThis(widget); } static void MapWidget(GtkWidget *widget) { if (widget && IS_WIDGET_VISIBLE(widget) && !IS_WIDGET_MAPPED(widget)) { gtk_widget_map(widget); } } void ScintillaGTK::MapThis() { try { //Platform::DebugPrintf("ScintillaGTK::map this\n"); #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_mapped(PWidget(wMain), TRUE); #else GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_MAPPED); #endif MapWidget(PWidget(wText)); MapWidget(PWidget(scrollbarh)); MapWidget(PWidget(scrollbarv)); wMain.SetCursor(Window::cursorArrow); scrollbarv.SetCursor(Window::cursorArrow); scrollbarh.SetCursor(Window::cursorArrow); ChangeSize(); gdk_window_show(PWindow(wMain)); } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::Map(GtkWidget *widget) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); sciThis->MapThis(); } void ScintillaGTK::UnMapThis() { try { //Platform::DebugPrintf("ScintillaGTK::unmap this\n"); #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_mapped(PWidget(wMain), FALSE); #else GTK_WIDGET_UNSET_FLAGS(PWidget(wMain), GTK_MAPPED); #endif DropGraphics(false); gdk_window_hide(PWindow(wMain)); gtk_widget_unmap(PWidget(wText)); gtk_widget_unmap(PWidget(scrollbarh)); gtk_widget_unmap(PWidget(scrollbarv)); } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::UnMap(GtkWidget *widget) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); sciThis->UnMapThis(); } void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) { try { (*callback) (PWidget(wText), callback_data); (*callback) (PWidget(scrollbarv), callback_data); (*callback) (PWidget(scrollbarh), callback_data); } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { ScintillaGTK *sciThis = ScintillaFromWidget((GtkWidget *)container); if (callback != NULL && include_internals) { sciThis->ForAll(callback, callback_data); } } gint ScintillaGTK::FocusInThis(GtkWidget *widget) { try { SetFocusState(true); if (im_context != NULL) { gchar *str = NULL; gint cursor_pos; gtk_im_context_get_preedit_string(im_context, &str, NULL, &cursor_pos); if (PWidget(wPreedit) != NULL) { if (strlen(str) > 0) { gtk_widget_show(PWidget(wPreedit)); } else { gtk_widget_hide(PWidget(wPreedit)); } } g_free(str); gtk_im_context_focus_in(im_context); } } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); return sciThis->FocusInThis(widget); } gint ScintillaGTK::FocusOutThis(GtkWidget *widget) { try { SetFocusState(false); if (PWidget(wPreedit) != NULL) gtk_widget_hide(PWidget(wPreedit)); if (im_context != NULL) gtk_im_context_focus_out(im_context); } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); return sciThis->FocusOutThis(widget); } void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); requisition->width = 1; requisition->height = 1; GtkRequisition child_requisition; #if GTK_CHECK_VERSION(3,0,0) gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarh), NULL, &child_requisition); gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarv), NULL, &child_requisition); #else gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition); gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition); #endif } void ScintillaGTK::GetPreferredWidth(GtkWidget *widget, gint *minimalWidth, gint *naturalWidth) { GtkRequisition requisition; SizeRequest(widget, &requisition); *minimalWidth = *naturalWidth = requisition.width; } void ScintillaGTK::GetPreferredHeight(GtkWidget *widget, gint *minimalHeight, gint *naturalHeight) { GtkRequisition requisition; SizeRequest(widget, &requisition); *minimalHeight = *naturalHeight = requisition.height; } void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_allocation(widget, allocation); #else widget->allocation = *allocation; #endif if (IS_WIDGET_REALIZED(widget)) gdk_window_move_resize(WindowFromWidget(widget), allocation->x, allocation->y, allocation->width, allocation->height); sciThis->Resize(allocation->width, allocation->height); } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::Initialise() { //Platform::DebugPrintf("ScintillaGTK::Initialise\n"); parentClass = reinterpret_cast( g_type_class_ref(gtk_container_get_type())); #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_can_focus(PWidget(wMain), TRUE); gtk_widget_set_sensitive(PWidget(wMain), TRUE); #else GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_CAN_FOCUS); GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain)), GTK_SENSITIVE); #endif gtk_widget_set_events(PWidget(wMain), GDK_EXPOSURE_MASK | GDK_SCROLL_MASK | GDK_STRUCTURE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); wText = gtk_drawing_area_new(); gtk_widget_set_parent(PWidget(wText), PWidget(wMain)); GtkWidget *widtxt = PWidget(wText); // No code inside the G_OBJECT macro gtk_widget_show(widtxt); #if GTK_CHECK_VERSION(3,0,0) g_signal_connect(G_OBJECT(widtxt), "draw", G_CALLBACK(ScintillaGTK::DrawText), this); #else g_signal_connect(G_OBJECT(widtxt), "expose_event", G_CALLBACK(ScintillaGTK::ExposeText), this); #endif gtk_widget_set_events(widtxt, GDK_EXPOSURE_MASK); // Avoid background drawing flash gtk_widget_set_double_buffered(widtxt, FALSE); gtk_widget_set_size_request(widtxt, 100, 100); adjustmentv = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0)); #if GTK_CHECK_VERSION(3,0,0) scrollbarv = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT(adjustmentv)); #else scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv)); #endif #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_can_focus(PWidget(scrollbarv), FALSE); #else GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv), GTK_CAN_FOCUS); #endif g_signal_connect(G_OBJECT(adjustmentv), "value_changed", G_CALLBACK(ScrollSignal), this); gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain)); gtk_widget_show(PWidget(scrollbarv)); adjustmenth = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0)); #if GTK_CHECK_VERSION(3,0,0) scrollbarh = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT(adjustmenth)); #else scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth)); #endif #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_can_focus(PWidget(scrollbarh), FALSE); #else GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh), GTK_CAN_FOCUS); #endif g_signal_connect(G_OBJECT(adjustmenth), "value_changed", G_CALLBACK(ScrollHSignal), this); gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain)); gtk_widget_show(PWidget(scrollbarh)); gtk_widget_grab_focus(PWidget(wMain)); gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)), GTK_DEST_DEFAULT_ALL, clipboardPasteTargets, nClipboardPasteTargets, static_cast(GDK_ACTION_COPY | GDK_ACTION_MOVE)); // Set caret period based on GTK settings gboolean blinkOn = false; if (g_object_class_find_property(G_OBJECT_GET_CLASS( G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) { g_object_get(G_OBJECT( gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn, NULL); } if (blinkOn && g_object_class_find_property(G_OBJECT_GET_CLASS( G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) { gint value; g_object_get(G_OBJECT( gtk_settings_get_default()), "gtk-cursor-blink-time", &value, NULL); caret.period = gint(value / 1.75); } else { caret.period = 0; } SetTicking(true); } void ScintillaGTK::Finalise() { SetTicking(false); ScintillaBase::Finalise(); } void ScintillaGTK::DisplayCursor(Window::Cursor c) { if (cursorMode == SC_CURSORNORMAL) wText.SetCursor(c); else wText.SetCursor(static_cast(cursorMode)); } bool ScintillaGTK::DragThreshold(Point ptStart, Point ptNow) { return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain)), ptStart.x, ptStart.y, ptNow.x, ptNow.y); } void ScintillaGTK::StartDrag() { dragWasDropped = false; inDragDrop = ddDragging; GtkTargetList *tl = gtk_target_list_new(clipboardCopyTargets, nClipboardCopyTargets); gtk_drag_begin(GTK_WIDGET(PWidget(wMain)), tl, static_cast(GDK_ACTION_COPY | GDK_ACTION_MOVE), evbtn.button, reinterpret_cast(&evbtn)); } static char *ConvertText(int *lenResult, char *s, size_t len, const char *charSetDest, const char *charSetSource, bool transliterations, bool silent=false) { // s is not const because of different versions of iconv disagreeing about const *lenResult = 0; char *destForm = 0; Converter conv(charSetDest, charSetSource, transliterations); if (conv) { destForm = new char[len*3+1]; char *pin = s; size_t inLeft = len; char *pout = destForm; size_t outLeft = len*3+1; size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); if (conversions == ((size_t)(-1))) { if (!silent) fprintf(stderr, "iconv %s->%s failed for %s\n", charSetSource, charSetDest, static_cast(s)); delete []destForm; destForm = 0; } else { //fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm); *pout = '\0'; *lenResult = pout - destForm; } } else { fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource); } if (!destForm) { destForm = new char[1]; destForm[0] = '\0'; *lenResult = 0; } return destForm; } // Returns the target converted to UTF8. // Return the length in bytes. int ScintillaGTK::TargetAsUTF8(char *text) { int targetLength = targetEnd - targetStart; if (IsUnicodeMode()) { if (text) { pdoc->GetCharRange(text, targetStart, targetLength); } } else { // Need to convert const char *charSetBuffer = CharacterSetID(); if (*charSetBuffer) { //~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd); char *s = new char[targetLength]; if (s) { pdoc->GetCharRange(s, targetStart, targetLength); //~ fprintf(stderr, " \"%s\"\n", s); if (text) { char *tmputf = ConvertText(&targetLength, s, targetLength, "UTF-8", charSetBuffer, false); memcpy(text, tmputf, targetLength); delete []tmputf; //~ fprintf(stderr, " \"%s\"\n", text); } delete []s; } } else { if (text) { pdoc->GetCharRange(text, targetStart, targetLength); } } } //~ fprintf(stderr, "Length = %d bytes\n", targetLength); return targetLength; } // Translates a nul terminated UTF8 string into the document encoding. // Return the length of the result in bytes. int ScintillaGTK::EncodedFromUTF8(char *utf8, char *encoded) { int inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8); if (IsUnicodeMode()) { if (encoded) { memcpy(encoded, utf8, inputLength); } return inputLength; } else { // Need to convert const char *charSetBuffer = CharacterSetID(); if (*charSetBuffer) { int outLength = 0; char *tmpEncoded = ConvertText(&outLength, utf8, inputLength, charSetBuffer, "UTF-8", true); if (tmpEncoded) { if (encoded) { memcpy(encoded, tmpEncoded, outLength); } delete []tmpEncoded; } return outLength; } else { if (encoded) { memcpy(encoded, utf8, inputLength); } return inputLength; } } // Fail return 0; } bool ScintillaGTK::ValidCodePage(int codePage) const { return codePage == 0 || codePage == SC_CP_UTF8 || codePage == 932 || codePage == 936 || codePage == 949 || codePage == 950 || codePage == 1361; } sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { try { switch (iMessage) { case SCI_GRABFOCUS: gtk_widget_grab_focus(PWidget(wMain)); break; case SCI_GETDIRECTFUNCTION: return reinterpret_cast(DirectFunction); case SCI_GETDIRECTPOINTER: return reinterpret_cast(this); #ifdef SCI_LEXER case SCI_LOADLEXERLIBRARY: LexerManager::GetInstance()->Load(reinterpret_cast(lParam)); break; #endif case SCI_TARGETASUTF8: return TargetAsUTF8(reinterpret_cast(lParam)); case SCI_ENCODEDFROMUTF8: return EncodedFromUTF8(reinterpret_cast(wParam), reinterpret_cast(lParam)); case SCI_SETRECTANGULARSELECTIONMODIFIER: rectangularSelectionModifier = wParam; break; case SCI_GETRECTANGULARSELECTIONMODIFIER: return rectangularSelectionModifier; default: return ScintillaBase::WndProc(iMessage, wParam, lParam); } } catch (std::bad_alloc&) { errorStatus = SC_STATUS_BADALLOC; } catch (...) { errorStatus = SC_STATUS_FAILURE; } return 0l; } sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) { return 0; } void ScintillaGTK::SetTicking(bool on) { if (timer.ticking != on) { timer.ticking = on; if (timer.ticking) { timer.tickerID = reinterpret_cast(g_timeout_add(timer.tickSize, reinterpret_cast(TimeOut), this)); } else { g_source_remove(GPOINTER_TO_UINT(timer.tickerID)); } } timer.ticksToWait = caret.period; } bool ScintillaGTK::SetIdle(bool on) { if (on) { // Start idler, if it's not running. if (!idler.state) { idler.state = true; idler.idlerID = reinterpret_cast( g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, reinterpret_cast(IdleCallback), this, NULL)); } } else { // Stop idler, if it's running if (idler.state) { idler.state = false; g_source_remove(GPOINTER_TO_UINT(idler.idlerID)); } } return true; } void ScintillaGTK::SetMouseCapture(bool on) { if (mouseDownCaptures) { if (on) { gtk_grab_add(GTK_WIDGET(PWidget(wMain))); } else { gtk_grab_remove(GTK_WIDGET(PWidget(wMain))); } } capturedMouse = on; } bool ScintillaGTK::HaveMouseCapture() { return capturedMouse; } #if GTK_CHECK_VERSION(3,0,0) // Is crcTest completely in crcContainer? static bool CRectContains(const cairo_rectangle_t &crcContainer, const cairo_rectangle_t &crcTest) { return (crcTest.x >= crcContainer.x) && ((crcTest.x + crcTest.width) <= (crcContainer.x + crcContainer.width)) && (crcTest.y >= crcContainer.y) && ((crcTest.y + crcTest.height) <= (crcContainer.y + crcContainer.height)); } // Is crcTest completely in crcListContainer? // May incorrectly return false if complex shape static bool CRectListContains(const cairo_rectangle_list_t *crcListContainer, const cairo_rectangle_t &crcTest) { for (int r=0; rnum_rectangles; r++) { if (CRectContains(crcListContainer->rectangles[r], crcTest)) return true; } return false; } #endif bool ScintillaGTK::PaintContains(PRectangle rc) { // This allows optimization when a rectangle is completely in the update region. // It is OK to return false when too difficult to determine as that just performs extra drawing bool contains = true; if (paintState == painting) { if (!rcPaint.Contains(rc)) { contains = false; } else if (rgnUpdate) { #if GTK_CHECK_VERSION(3,0,0) cairo_rectangle_t grc = {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}; contains = CRectListContains(rgnUpdate, grc); #else GdkRectangle grc = {static_cast(rc.left), static_cast(rc.top), static_cast(rc.right - rc.left), static_cast(rc.bottom - rc.top)}; if (gdk_region_rect_in(rgnUpdate, &grc) != GDK_OVERLAP_RECTANGLE_IN) { contains = false; } #endif } } return contains; } // Redraw all of text area. This paint will not be abandoned. void ScintillaGTK::FullPaint() { wText.InvalidateAll(); } PRectangle ScintillaGTK::GetClientRectangle() { PRectangle rc = wMain.GetClientPosition(); if (verticalScrollBarVisible) rc.right -= scrollBarWidth; if (horizontalScrollBarVisible && (wrapState == eWrapNone)) rc.bottom -= scrollBarHeight; // Move to origin rc.right -= rc.left; rc.bottom -= rc.top; rc.left = 0; rc.top = 0; return rc; } // Synchronously paint a rectangle of the window. void ScintillaGTK::SyncPaint(PRectangle rc) { paintState = painting; rcPaint = rc; PRectangle rcClient = GetClientRectangle(); paintingAllText = rcPaint.Contains(rcClient); if (PWindow(wText)) { Surface *sw = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (sw) { cairo_t *cr = gdk_cairo_create(PWindow(wText)); sw->Init(cr, PWidget(wText)); Paint(sw, rc); sw->Release(); delete sw; cairo_destroy(cr); } } if (paintState == paintAbandoned) { // Painting area was insufficient to cover new styling or brace highlight positions FullPaint(); } paintState = notPainting; } void ScintillaGTK::ScrollText(int linesToMove) { int diff = vs.lineHeight * -linesToMove; //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff, // rc.left, rc.top, rc.right, rc.bottom); GtkWidget *wi = PWidget(wText); if (IS_WIDGET_REALIZED(wi)) { gdk_window_scroll(WindowFromWidget(wi), 0, -diff); gdk_window_process_updates(WindowFromWidget(wi), FALSE); } } void ScintillaGTK::SetVerticalScrollPos() { DwellEnd(true); gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine); } void ScintillaGTK::SetHorizontalScrollPos() { DwellEnd(true); gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset / 2); } bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) { bool modified = false; int pageScroll = LinesToScroll(); #if GTK_CHECK_VERSION(3,0,0) if (gtk_adjustment_get_upper(adjustmentv) != (nMax + 1) || gtk_adjustment_get_page_size(adjustmentv) != nPage || gtk_adjustment_get_page_increment(adjustmentv) != pageScroll) { gtk_adjustment_set_upper(adjustmentv, nMax + 1); gtk_adjustment_set_page_size(adjustmentv, nPage); gtk_adjustment_set_page_increment(adjustmentv, pageScroll); gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv)); modified = true; } #else if (GTK_ADJUSTMENT(adjustmentv)->upper != (nMax + 1) || GTK_ADJUSTMENT(adjustmentv)->page_size != nPage || GTK_ADJUSTMENT(adjustmentv)->page_increment != pageScroll) { GTK_ADJUSTMENT(adjustmentv)->upper = nMax + 1; GTK_ADJUSTMENT(adjustmentv)->page_size = nPage; GTK_ADJUSTMENT(adjustmentv)->page_increment = pageScroll; gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv)); modified = true; } #endif PRectangle rcText = GetTextRectangle(); int horizEndPreferred = scrollWidth; if (horizEndPreferred < 0) horizEndPreferred = 0; unsigned int pageWidth = rcText.Width(); unsigned int pageIncrement = pageWidth / 3; unsigned int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth; #if GTK_CHECK_VERSION(3,0,0) if (gtk_adjustment_get_upper(adjustmenth) != horizEndPreferred || gtk_adjustment_get_page_size(adjustmenth) != pageWidth || gtk_adjustment_get_page_increment(adjustmenth) != pageIncrement || gtk_adjustment_get_step_increment(adjustmenth) != charWidth) { gtk_adjustment_set_upper(adjustmenth, horizEndPreferred); gtk_adjustment_set_page_size(adjustmenth, pageWidth); gtk_adjustment_set_page_increment(adjustmenth, pageIncrement); gtk_adjustment_set_step_increment(adjustmenth, charWidth); gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth)); modified = true; } #else if (GTK_ADJUSTMENT(adjustmenth)->upper != horizEndPreferred || GTK_ADJUSTMENT(adjustmenth)->page_size != pageWidth || GTK_ADJUSTMENT(adjustmenth)->page_increment != pageIncrement || GTK_ADJUSTMENT(adjustmenth)->step_increment != charWidth) { GTK_ADJUSTMENT(adjustmenth)->upper = horizEndPreferred; GTK_ADJUSTMENT(adjustmenth)->step_increment = charWidth; GTK_ADJUSTMENT(adjustmenth)->page_size = pageWidth; GTK_ADJUSTMENT(adjustmenth)->page_increment = pageIncrement; gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth)); modified = true; } #endif return modified; } void ScintillaGTK::ReconfigureScrollBars() { PRectangle rc = wMain.GetClientPosition(); Resize(rc.Width(), rc.Height()); } void ScintillaGTK::NotifyChange() { g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0, Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain)); } void ScintillaGTK::NotifyFocus(bool focus) { g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0, Platform::LongFromTwoShorts (GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS), PWidget(wMain)); } void ScintillaGTK::NotifyParent(SCNotification scn) { scn.nmhdr.hwndFrom = PWidget(wMain); scn.nmhdr.idFrom = GetCtrlID(); g_signal_emit(G_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL], 0, GetCtrlID(), &scn); } void ScintillaGTK::NotifyKey(int key, int modifiers) { SCNotification scn = {0}; scn.nmhdr.code = SCN_KEY; scn.ch = key; scn.modifiers = modifiers; NotifyParent(scn); } void ScintillaGTK::NotifyURIDropped(const char *list) { SCNotification scn = {0}; scn.nmhdr.code = SCN_URIDROPPED; scn.text = list; NotifyParent(scn); } const char *CharacterSetID(int characterSet); const char *ScintillaGTK::CharacterSetID() const { return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet); } class CaseFolderUTF8 : public CaseFolderTable { public: CaseFolderUTF8() { StandardASCII(); } virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { if ((lenMixed == 1) && (sizeFolded > 0)) { folded[0] = mapping[static_cast(mixed[0])]; return 1; } else { gchar *mapped = g_utf8_casefold(mixed, lenMixed); size_t lenMapped = strlen(mapped); if (lenMapped < sizeFolded) { memcpy(folded, mapped, lenMapped); } else { lenMapped = 0; } g_free(mapped); return lenMapped; } } }; class CaseFolderDBCS : public CaseFolderTable { const char *charSet; public: CaseFolderDBCS(const char *charSet_) : charSet(charSet_) { StandardASCII(); } virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) { if ((lenMixed == 1) && (sizeFolded > 0)) { folded[0] = mapping[static_cast(mixed[0])]; return 1; } else if (*charSet) { int convertedLength = lenMixed; char *sUTF8 = ConvertText(&convertedLength, const_cast(mixed), lenMixed, "UTF-8", charSet, false); if (sUTF8) { gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8)); size_t lenMapped = strlen(mapped); if (lenMapped < sizeFolded) { memcpy(folded, mapped, lenMapped); } else { folded[0] = '\0'; lenMapped = 1; } g_free(mapped); delete []sUTF8; return lenMapped; } } // Something failed so return a single NUL byte folded[0] = '\0'; return 1; } }; CaseFolder *ScintillaGTK::CaseFolderForEncoding() { if (pdoc->dbcsCodePage == SC_CP_UTF8) { return new CaseFolderUTF8(); } else { const char *charSetBuffer = CharacterSetID(); if (charSetBuffer) { if (pdoc->dbcsCodePage == 0) { CaseFolderTable *pcf = new CaseFolderTable(); pcf->StandardASCII(); // Only for single byte encodings for (int i=0x80; i<0x100; i++) { char sCharacter[2] = "A"; sCharacter[0] = i; int convertedLength = 1; const char *sUTF8 = ConvertText(&convertedLength, sCharacter, 1, "UTF-8", charSetBuffer, false); if (sUTF8) { gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8)); if (mapped) { int mappedLength = strlen(mapped); const char *mappedBack = ConvertText(&mappedLength, mapped, mappedLength, charSetBuffer, "UTF-8", false, true); if (mappedBack && (strlen(mappedBack) == 1) && (mappedBack[0] != sCharacter[0])) { pcf->SetTranslation(sCharacter[0], mappedBack[0]); } delete []mappedBack; g_free(mapped); } } delete []sUTF8; } return pcf; } else { return new CaseFolderDBCS(charSetBuffer); } } return 0; } } std::string ScintillaGTK::CaseMapString(const std::string &s, int caseMapping) { if (s.size() == 0) return std::string(); if (caseMapping == cmSame) return s; const char *needsFree1 = 0; // Must be freed with delete [] const char *charSetBuffer = CharacterSetID(); const char *sUTF8 = s.c_str(); int rangeBytes = s.size(); int convertedLength = rangeBytes; // Change text to UTF-8 if (!IsUnicodeMode()) { // Need to convert if (*charSetBuffer) { sUTF8 = ConvertText(&convertedLength, const_cast(s.c_str()), rangeBytes, "UTF-8", charSetBuffer, false); needsFree1 = sUTF8; } } gchar *mapped; // Must be freed with g_free if (caseMapping == cmUpper) { mapped = g_utf8_strup(sUTF8, convertedLength); } else { mapped = g_utf8_strdown(sUTF8, convertedLength); } int mappedLength = strlen(mapped); char *mappedBack = mapped; char *needsFree2 = 0; // Must be freed with delete [] if (!IsUnicodeMode()) { if (*charSetBuffer) { mappedBack = ConvertText(&mappedLength, mapped, mappedLength, charSetBuffer, "UTF-8", false); needsFree2 = mappedBack; } } std::string ret(mappedBack, mappedLength); g_free(mapped); delete []needsFree1; delete []needsFree2; return ret; } int ScintillaGTK::KeyDefault(int key, int modifiers) { // Pass up to container in case it is an accelerator NotifyKey(key, modifiers); return 0; } void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) { SelectionText *clipText = new SelectionText(); clipText->Copy(selectedText); StoreOnClipboard(clipText); } void ScintillaGTK::Copy() { if (!sel.Empty()) { SelectionText *clipText = new SelectionText(); CopySelectionRange(clipText); StoreOnClipboard(clipText); #if PLAT_GTK_WIN32 if (sel.IsRectangular()) { ::OpenClipboard(NULL); ::SetClipboardData(cfColumnSelect, 0); ::CloseClipboard(); } #endif } } void ScintillaGTK::Paste() { atomSought = atomUTF8; gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), atomClipboard, atomSought, GDK_CURRENT_TIME); } void ScintillaGTK::CreateCallTipWindow(PRectangle rc) { if (!ct.wCallTip.Created()) { ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP); ct.wDraw = gtk_drawing_area_new(); GtkWidget *widcdrw = PWidget(ct.wDraw); // // No code inside the G_OBJECT macro gtk_container_add(GTK_CONTAINER(PWidget(ct.wCallTip)), widcdrw); #if GTK_CHECK_VERSION(3,0,0) g_signal_connect(G_OBJECT(widcdrw), "draw", G_CALLBACK(ScintillaGTK::DrawCT), &ct); #else g_signal_connect(G_OBJECT(widcdrw), "expose_event", G_CALLBACK(ScintillaGTK::ExposeCT), &ct); #endif g_signal_connect(G_OBJECT(widcdrw), "button_press_event", G_CALLBACK(ScintillaGTK::PressCT), static_cast(this)); gtk_widget_set_events(widcdrw, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); } gtk_widget_set_size_request(PWidget(ct.wDraw), rc.Width(), rc.Height()); ct.wDraw.Show(); if (PWindow(ct.wCallTip)) { gdk_window_resize(PWindow(ct.wCallTip), rc.Width(), rc.Height()); } } void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) { GtkWidget *menuItem; if (label[0]) menuItem = gtk_menu_item_new_with_label(label); else menuItem = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(popup.GetID()), menuItem); g_object_set_data(G_OBJECT(menuItem), "CmdNum", reinterpret_cast(cmd)); g_signal_connect(G_OBJECT(menuItem),"activate", G_CALLBACK(PopUpCB), this); if (cmd) { if (menuItem) gtk_widget_set_sensitive(menuItem, enabled); } } bool ScintillaGTK::OwnPrimarySelection() { return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY) == PWindow(wMain)) && (PWindow(wMain) != NULL)); } void ScintillaGTK::ClaimSelection() { // X Windows has a 'primary selection' as well as the clipboard. // Whenever the user selects some text, we become the primary selection if (!sel.Empty() && IS_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain)))) { primarySelection = true; gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); primary.Free(); } else if (OwnPrimarySelection()) { primarySelection = true; if (primary.s == NULL) gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); } else { primarySelection = false; primary.Free(); } } #if GTK_CHECK_VERSION(3,0,0) static const guchar *DataOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_data(sd); } static gint LengthOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_length(sd); } static GdkAtom TypeOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_data_type(sd); } static GdkAtom SelectionOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_selection(sd); } #else static const guchar *DataOfGSD(GtkSelectionData *sd) { return sd->data; } static gint LengthOfGSD(GtkSelectionData *sd) { return sd->length; } static GdkAtom TypeOfGSD(GtkSelectionData *sd) { return sd->type; } static GdkAtom SelectionOfGSD(GtkSelectionData *sd) { return sd->selection; } #endif // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) { const char *data = reinterpret_cast(DataOfGSD(selectionData)); int len = LengthOfGSD(selectionData); GdkAtom selectionTypeData = TypeOfGSD(selectionData); // Return empty string if selection is not a string if ((selectionTypeData != GDK_TARGET_STRING) && (selectionTypeData != atomUTF8)) { char *empty = new char[1]; empty[0] = '\0'; selText.Set(empty, 0, SC_CP_UTF8, 0, false, false); return; } // Check for "\n\0" ending to string indicating that selection is rectangular bool isRectangular; #if PLAT_GTK_WIN32 isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0; #else isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n')); if (isRectangular) len--; // Forget the extra '\0' #endif char *dest; if (selectionTypeData == GDK_TARGET_STRING) { dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode); if (IsUnicodeMode()) { // Unknown encoding so assume in Latin1 char *destPrevious = dest; dest = UTF8FromLatin1(dest, len); selText.Set(dest, len, SC_CP_UTF8, 0, selText.rectangular, false); delete []destPrevious; } else { // Assume buffer is in same encoding as selection selText.Set(dest, len, pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false); } } else { // UTF-8 dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode); selText.Set(dest, len, SC_CP_UTF8, 0, isRectangular, false); const char *charSetBuffer = CharacterSetID(); if (!IsUnicodeMode() && *charSetBuffer) { // Convert to locale dest = ConvertText(&len, selText.s, selText.len, charSetBuffer, "UTF-8", true); selText.Set(dest, len, pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, selText.rectangular, false); } } } void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) { try { if ((SelectionOfGSD(selection_data) == atomClipboard) || (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY)) { if ((atomSought == atomUTF8) && (LengthOfGSD(selection_data) <= 0)) { atomSought = atomString; gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), SelectionOfGSD(selection_data), atomSought, GDK_CURRENT_TIME); } else if ((LengthOfGSD(selection_data) > 0) && ((TypeOfGSD(selection_data) == GDK_TARGET_STRING) || (TypeOfGSD(selection_data) == atomUTF8))) { SelectionText selText; GetGtkSelectionText(selection_data, selText); UndoGroup ug(pdoc); if (SelectionOfGSD(selection_data) != GDK_SELECTION_PRIMARY) { ClearSelection(multiPasteMode == SC_MULTIPASTE_EACH); } SelectionPosition selStart = sel.IsRectangular() ? sel.Rectangular().Start() : sel.Range(sel.Main()).Start(); if (selText.rectangular) { PasteRectangular(selStart, selText.s, selText.len); } else { InsertPaste(selStart, selText.s, selText.len); } EnsureCaretVisible(); } } // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type), // (int)(atomUTF8)); Redraw(); } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) { dragWasDropped = true; if (TypeOfGSD(selection_data) == atomUriList || TypeOfGSD(selection_data) == atomDROPFILES_DND) { char *ptr = new char[LengthOfGSD(selection_data) + 1]; ptr[LengthOfGSD(selection_data)] = '\0'; memcpy(ptr, DataOfGSD(selection_data), LengthOfGSD(selection_data)); NotifyURIDropped(ptr); delete []ptr; } else if ((TypeOfGSD(selection_data) == GDK_TARGET_STRING) || (TypeOfGSD(selection_data) == atomUTF8)) { if (TypeOfGSD(selection_data) > 0) { SelectionText selText; GetGtkSelectionText(selection_data, selText); DropAt(posDrop, selText.s, false, selText.rectangular); } } else if (LengthOfGSD(selection_data) > 0) { //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast(selection_data->type)); } Redraw(); } void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) { #if PLAT_GTK_WIN32 // GDK on Win32 expands any \n into \r\n, so make a copy of // the clip text now with newlines converted to \n. Use { } to hide symbols // from code below SelectionText *newline_normalized = NULL; { int tmpstr_len; char *tmpstr = Document::TransformLineEnds(&tmpstr_len, text->s, text->len, SC_EOL_LF); newline_normalized = new SelectionText(); newline_normalized->Set(tmpstr, tmpstr_len, SC_CP_UTF8, 0, text->rectangular, false); text = newline_normalized; } #endif // Convert text to utf8 if it isn't already SelectionText *converted = 0; if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) { const char *charSet = ::CharacterSetID(text->characterSet); if (*charSet) { int new_len; char* tmputf = ConvertText(&new_len, text->s, text->len, "UTF-8", charSet, false); converted = new SelectionText(); converted->Set(tmputf, new_len, SC_CP_UTF8, 0, text->rectangular, false); text = converted; } } // Here is a somewhat evil kludge. // As I can not work out how to store data on the clipboard in multiple formats // and need some way to mark the clipping as being stream or rectangular, // the terminating \0 is included in the length for rectangular clippings. // All other tested aplications behave benignly by ignoring the \0. // The #if is here because on Windows cfColumnSelect clip entry is used // instead as standard indicator of rectangularness (so no need to kludge) const char *textData = text->s ? text->s : ""; int len = strlen(textData); #if PLAT_GTK_WIN32 == 0 if (text->rectangular) len++; #endif if (info == TARGET_UTF8_STRING) { gtk_selection_data_set_text(selection_data, textData, len); } else { gtk_selection_data_set(selection_data, static_cast(GDK_SELECTION_TYPE_STRING), 8, reinterpret_cast(textData), len); } delete converted; #if PLAT_GTK_WIN32 delete newline_normalized; #endif } void ScintillaGTK::StoreOnClipboard(SelectionText *clipText) { GtkClipboard *clipBoard = gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard); if (clipBoard == NULL) // Occurs if widget isn't in a toplevel return; if (gtk_clipboard_set_with_data(clipBoard, clipboardCopyTargets, nClipboardCopyTargets, ClipboardGetSelection, ClipboardClearSelection, clipText)) { gtk_clipboard_set_can_store(clipBoard, clipboardCopyTargets, nClipboardCopyTargets); } } void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) { GetSelection(selection_data, info, static_cast(data)); } void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) { SelectionText *obj = static_cast(data); delete obj; } void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) { try { //Platform::DebugPrintf("UnclaimSelection\n"); if (selection_event->selection == GDK_SELECTION_PRIMARY) { //Platform::DebugPrintf("UnclaimPrimarySelection\n"); if (!OwnPrimarySelection()) { primary.Free(); primarySelection = false; FullPaint(); } } } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::Resize(int width, int height) { //Platform::DebugPrintf("Resize %d %d\n", width, height); //printf("Resize %d %d\n", width, height); // Not always needed, but some themes can have different sizes of scrollbars #if GTK_CHECK_VERSION(3,0,0) GtkRequisition requisition; gtk_widget_get_requisition(PWidget(scrollbarv), &requisition); scrollBarWidth = requisition.width; gtk_widget_get_requisition(PWidget(scrollbarh), &requisition); scrollBarHeight = requisition.height; #else scrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width; scrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height; #endif // These allocations should never produce negative sizes as they would wrap around to huge // unsigned numbers inside GTK+ causing warnings. bool showSBHorizontal = horizontalScrollBarVisible && (wrapState == eWrapNone); int horizontalScrollBarHeight = scrollBarHeight; if (!showSBHorizontal) horizontalScrollBarHeight = 0; GtkAllocation alloc; if (showSBHorizontal) { gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh))); alloc.x = 0; alloc.y = height - scrollBarHeight; alloc.width = Platform::Maximum(1, width - scrollBarWidth); alloc.height = horizontalScrollBarHeight; gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc); } else { gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh))); } if (verticalScrollBarVisible) { gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv))); alloc.x = width - scrollBarWidth; alloc.y = 0; alloc.width = scrollBarWidth; alloc.height = Platform::Maximum(1, height - scrollBarHeight); if (!showSBHorizontal) alloc.height += scrollBarWidth-1; gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc); } else { gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv))); } if (IS_WIDGET_MAPPED(PWidget(wMain))) { ChangeSize(); } alloc.x = 0; alloc.y = 0; alloc.width = Platform::Maximum(1, width - scrollBarWidth); alloc.height = Platform::Maximum(1, height - scrollBarHeight); if (!showSBHorizontal) alloc.height += scrollBarHeight; if (!verticalScrollBarVisible) alloc.width += scrollBarWidth; gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc); } static void SetAdjustmentValue(GtkAdjustment *object, int value) { GtkAdjustment *adjustment = GTK_ADJUSTMENT(object); #if GTK_CHECK_VERSION(3,0,0) int maxValue = static_cast( gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment)); #else int maxValue = static_cast( adjustment->upper - adjustment->page_size); #endif if (value > maxValue) value = maxValue; if (value < 0) value = 0; gtk_adjustment_set_value(adjustment, value); } static int modifierTranslated(int sciModifier) { switch (sciModifier) { case SCMOD_SHIFT: return GDK_SHIFT_MASK; case SCMOD_CTRL: return GDK_CONTROL_MASK; case SCMOD_ALT: return GDK_MOD1_MASK; case SCMOD_SUPER: return GDK_MOD4_MASK; default: return 0; } } gint ScintillaGTK::PressThis(GdkEventButton *event) { try { //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button); // Do not use GTK+ double click events as Scintilla has its own double click detection if (event->type != GDK_BUTTON_PRESS) return FALSE; evbtn = *event; Point pt; pt.x = int(event->x); pt.y = int(event->y); PRectangle rcClient = GetClientRectangle(); //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n", // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); if ((pt.x > rcClient.right) || (pt.y > rcClient.bottom)) { Platform::DebugPrintf("Bad location\n"); return FALSE; } bool ctrl = (event->state & GDK_CONTROL_MASK) != 0; gtk_widget_grab_focus(PWidget(wMain)); if (event->button == 1) { // On X, instead of sending literal modifiers use the user specified // modifier, defaulting to control instead of alt. // This is because most X window managers grab alt + click for moving ButtonDown(pt, event->time, (event->state & GDK_SHIFT_MASK) != 0, (event->state & GDK_CONTROL_MASK) != 0, (event->state & modifierTranslated(rectangularSelectionModifier)) != 0); } else if (event->button == 2) { // Grab the primary selection if it exists SelectionPosition pos = SPositionFromLocation(pt, false, false, UserVirtualSpace()); if (OwnPrimarySelection() && primary.s == NULL) CopySelectionRange(&primary); sel.Clear(); SetSelection(pos, pos); atomSought = atomUTF8; gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY, atomSought, event->time); } else if (event->button == 3) { if (!PointInSelection(pt)) SetEmptySelection(PositionFromLocation(pt)); if (displayPopupMenu) { // PopUp menu // Convert to screen int ox = 0; int oy = 0; gdk_window_get_origin(PWindow(wMain), &ox, &oy); ContextMenu(Point(pt.x + ox, pt.y + oy)); } else { return FALSE; } } else if (event->button == 4) { // Wheel scrolling up (only GTK 1.x does it this way) if (ctrl) SetAdjustmentValue(adjustmenth, (xOffset / 2) - 6); else SetAdjustmentValue(adjustmentv, topLine - 3); } else if (event->button == 5) { // Wheel scrolling down (only GTK 1.x does it this way) if (ctrl) SetAdjustmentValue(adjustmenth, (xOffset / 2) + 6); else SetAdjustmentValue(adjustmentv, topLine + 3); } } catch (...) { errorStatus = SC_STATUS_FAILURE; } return TRUE; } gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) { if (event->window != WindowFromWidget(widget)) return FALSE; ScintillaGTK *sciThis = ScintillaFromWidget(widget); return sciThis->PressThis(event); } gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state); if (!sciThis->HaveMouseCapture()) return FALSE; if (event->button == 1) { Point pt; pt.x = int(event->x); pt.y = int(event->y); //Platform::DebugPrintf("Up %x %x %d %d %d\n", // sciThis,event->window,event->time, pt.x, pt.y); if (event->window != PWindow(sciThis->wMain)) // If mouse released on scroll bar then the position is relative to the // scrollbar, not the drawing window so just repeat the most recent point. pt = sciThis->ptMouseLast; sciThis->ButtonUp(pt, event->time, (event->state & 4) != 0); } } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } return FALSE; } // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the // button4/5/6/7 events to the GTK app gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { if (widget == NULL || event == NULL) return FALSE; // Compute amount and direction to scroll (even tho on win32 there is // intensity of scrolling info in the native message, gtk doesn't // support this so we simulate similarly adaptive scrolling) // Note that this is disabled on OS X (Darwin) where the X11 server already has // and adaptive scrolling algorithm that fights with this one int cLineScroll; #if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__) cLineScroll = sciThis->linesPerScroll; if (cLineScroll == 0) cLineScroll = 4; sciThis->wheelMouseIntensity = cLineScroll; #else int timeDelta = 1000000; GTimeVal curTime; g_get_current_time(&curTime); if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec) timeDelta = curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec; else if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec + 1) timeDelta = 1000000 + (curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec); if ((event->direction == sciThis->lastWheelMouseDirection) && (timeDelta < 250000)) { if (sciThis->wheelMouseIntensity < 12) sciThis->wheelMouseIntensity++; cLineScroll = sciThis->wheelMouseIntensity; } else { cLineScroll = sciThis->linesPerScroll; if (cLineScroll == 0) cLineScroll = 4; sciThis->wheelMouseIntensity = cLineScroll; } #endif if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT) { cLineScroll *= -1; } g_get_current_time(&sciThis->lastWheelMouseTime); sciThis->lastWheelMouseDirection = event->direction; // Note: Unpatched versions of win32gtk don't set the 'state' value so // only regular scrolling is supported there. Also, unpatched win32gtk // issues spurious button 2 mouse events during wheeling, which can cause // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001) // Data zoom not supported if (event->state & GDK_SHIFT_MASK) { return FALSE; } #if GTK_CHECK_VERSION(3,4,0) // Smooth scrolling not supported if (event->direction == GDK_SCROLL_SMOOTH) { return FALSE; } #endif // Horizontal scrolling if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) { sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll); // Text font size zoom } else if (event->state & GDK_CONTROL_MASK) { if (cLineScroll < 0) { sciThis->KeyCommand(SCI_ZOOMIN); } else { sciThis->KeyCommand(SCI_ZOOMOUT); } // Regular scrolling } else { sciThis->ScrollTo(sciThis->topLine + cLineScroll); } return TRUE; } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } return FALSE; } gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time); if (event->window != WindowFromWidget(widget)) return FALSE; int x = 0; int y = 0; GdkModifierType state; if (event->is_hint) { #if GTK_CHECK_VERSION(3,0,0) gdk_window_get_device_position(event->window, event->device, &x, &y, &state); #else gdk_window_get_pointer(event->window, &x, &y, &state); #endif } else { x = static_cast(event->x); y = static_cast(event->y); state = static_cast(event->state); } //Platform::DebugPrintf("Move %x %x %d %c %d %d\n", // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y); Point pt(x, y); sciThis->ButtonMove(pt); } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } return FALSE; } // Map the keypad keys to their equivalent functions static int KeyTranslate(int keyIn) { switch (keyIn) { #if GTK_CHECK_VERSION(3,0,0) case GDK_KEY_ISO_Left_Tab: return SCK_TAB; case GDK_KEY_KP_Down: return SCK_DOWN; case GDK_KEY_KP_Up: return SCK_UP; case GDK_KEY_KP_Left: return SCK_LEFT; case GDK_KEY_KP_Right: return SCK_RIGHT; case GDK_KEY_KP_Home: return SCK_HOME; case GDK_KEY_KP_End: return SCK_END; case GDK_KEY_KP_Page_Up: return SCK_PRIOR; case GDK_KEY_KP_Page_Down: return SCK_NEXT; case GDK_KEY_KP_Delete: return SCK_DELETE; case GDK_KEY_KP_Insert: return SCK_INSERT; case GDK_KEY_KP_Enter: return SCK_RETURN; case GDK_KEY_Down: return SCK_DOWN; case GDK_KEY_Up: return SCK_UP; case GDK_KEY_Left: return SCK_LEFT; case GDK_KEY_Right: return SCK_RIGHT; case GDK_KEY_Home: return SCK_HOME; case GDK_KEY_End: return SCK_END; case GDK_KEY_Page_Up: return SCK_PRIOR; case GDK_KEY_Page_Down: return SCK_NEXT; case GDK_KEY_Delete: return SCK_DELETE; case GDK_KEY_Insert: return SCK_INSERT; case GDK_KEY_Escape: return SCK_ESCAPE; case GDK_KEY_BackSpace: return SCK_BACK; case GDK_KEY_Tab: return SCK_TAB; case GDK_KEY_Return: return SCK_RETURN; case GDK_KEY_KP_Add: return SCK_ADD; case GDK_KEY_KP_Subtract: return SCK_SUBTRACT; case GDK_KEY_KP_Divide: return SCK_DIVIDE; case GDK_KEY_Super_L: return SCK_WIN; case GDK_KEY_Super_R: return SCK_RWIN; case GDK_KEY_Menu: return SCK_MENU; #else case GDK_ISO_Left_Tab: return SCK_TAB; case GDK_KP_Down: return SCK_DOWN; case GDK_KP_Up: return SCK_UP; case GDK_KP_Left: return SCK_LEFT; case GDK_KP_Right: return SCK_RIGHT; case GDK_KP_Home: return SCK_HOME; case GDK_KP_End: return SCK_END; case GDK_KP_Page_Up: return SCK_PRIOR; case GDK_KP_Page_Down: return SCK_NEXT; case GDK_KP_Delete: return SCK_DELETE; case GDK_KP_Insert: return SCK_INSERT; case GDK_KP_Enter: return SCK_RETURN; case GDK_Down: return SCK_DOWN; case GDK_Up: return SCK_UP; case GDK_Left: return SCK_LEFT; case GDK_Right: return SCK_RIGHT; case GDK_Home: return SCK_HOME; case GDK_End: return SCK_END; case GDK_Page_Up: return SCK_PRIOR; case GDK_Page_Down: return SCK_NEXT; case GDK_Delete: return SCK_DELETE; case GDK_Insert: return SCK_INSERT; case GDK_Escape: return SCK_ESCAPE; case GDK_BackSpace: return SCK_BACK; case GDK_Tab: return SCK_TAB; case GDK_Return: return SCK_RETURN; case GDK_KP_Add: return SCK_ADD; case GDK_KP_Subtract: return SCK_SUBTRACT; case GDK_KP_Divide: return SCK_DIVIDE; case GDK_Super_L: return SCK_WIN; case GDK_Super_R: return SCK_RWIN; case GDK_Menu: return SCK_MENU; #endif default: return keyIn; } } gboolean ScintillaGTK::KeyThis(GdkEventKey *event) { try { //fprintf(stderr, "SC-key: %d %x [%s]\n", // event->keyval, event->state, (event->length > 0) ? event->string : "empty"); if (gtk_im_context_filter_keypress(im_context, event)) { return 1; } if (!event->keyval) { return true; } bool shift = (event->state & GDK_SHIFT_MASK) != 0; bool ctrl = (event->state & GDK_CONTROL_MASK) != 0; bool alt = (event->state & GDK_MOD1_MASK) != 0; guint key = event->keyval; if ((ctrl || alt) && (key < 128)) key = toupper(key); #if GTK_CHECK_VERSION(3,0,0) else if (!ctrl && (key >= GDK_KEY_KP_Multiply && key <= GDK_KEY_KP_9)) #else else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9)) #endif key &= 0x7F; // Hack for keys over 256 and below command keys but makes Hungarian work. // This will have to change for Unicode else if (key >= 0xFE00) key = KeyTranslate(key); bool consumed = false; #if !(PLAT_GTK_MACOSX) bool added = KeyDown(key, shift, ctrl, alt, &consumed) != 0; #else bool meta = ctrl; ctrl = (event->state & GDK_META_MASK) != 0; bool added = KeyDownWithModifiers(key, (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0) | (meta ? SCI_META : 0), &consumed) != 0; #endif if (!consumed) consumed = added; //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed); if (event->keyval == 0xffffff && event->length > 0) { ClearSelection(); if (pdoc->InsertCString(CurrentPosition(), event->string)) { MovePositionTo(CurrentPosition() + event->length); } } return consumed; } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } gboolean ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); return sciThis->KeyThis(event); } gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) { //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string); ScintillaGTK *sciThis = ScintillaFromWidget(widget); if (gtk_im_context_filter_keypress(sciThis->im_context, event)) { return TRUE; } return FALSE; } #if GTK_CHECK_VERSION(3,0,0) gboolean ScintillaGTK::DrawPreeditThis(GtkWidget *widget, cairo_t *cr) { try { gchar *str; gint cursor_pos; PangoAttrList *attrs; gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); pango_layout_set_attributes(layout, attrs); cairo_move_to(cr, 0, 0); pango_cairo_show_layout(cr, layout); g_free(str); pango_attr_list_unref(attrs); g_object_unref(layout); } catch (...) { errorStatus = SC_STATUS_FAILURE; } return TRUE; } gboolean ScintillaGTK::DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis) { return sciThis->DrawPreeditThis(widget, cr); } #else gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) { try { gchar *str; gint cursor_pos; PangoAttrList *attrs; gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); pango_layout_set_attributes(layout, attrs); cairo_t *context = gdk_cairo_create(reinterpret_cast(WindowFromWidget(widget))); cairo_move_to(context, 0, 0); pango_cairo_show_layout(context, layout); cairo_destroy(context); g_free(str); pango_attr_list_unref(attrs); g_object_unref(layout); } catch (...) { errorStatus = SC_STATUS_FAILURE; } return TRUE; } gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) { return sciThis->ExposePreeditThis(widget, ose); } #endif void ScintillaGTK::CommitThis(char *utfVal) { try { //~ fprintf(stderr, "Commit '%s'\n", utfVal); if (IsUnicodeMode()) { AddCharUTF(utfVal, strlen(utfVal)); } else { const char *source = CharacterSetID(); if (*source) { Converter conv(source, "UTF-8", true); if (conv) { char localeVal[4] = "\0\0\0"; char *pin = utfVal; size_t inLeft = strlen(utfVal); char *pout = localeVal; size_t outLeft = sizeof(localeVal); size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); if (conversions != ((size_t)(-1))) { *pout = '\0'; for (int i = 0; localeVal[i]; i++) { AddChar(localeVal[i]); } } else { fprintf(stderr, "Conversion failed '%s'\n", utfVal); } } } } } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) { sciThis->CommitThis(str); } void ScintillaGTK::PreeditChangedThis() { try { gchar *str; PangoAttrList *attrs; gint cursor_pos; gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); if (strlen(str) > 0) { PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); pango_layout_set_attributes(layout, attrs); gint w, h; pango_layout_get_pixel_size(layout, &w, &h); g_object_unref(layout); gint x, y; gdk_window_get_origin(PWindow(wText), &x, &y); Point pt = PointMainCaret(); if (pt.x < 0) pt.x = 0; if (pt.y < 0) pt.y = 0; gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y); gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h); gtk_widget_show(PWidget(wPreedit)); gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h); } else { gtk_widget_hide(PWidget(wPreedit)); } g_free(str); pango_attr_list_unref(attrs); } catch (...) { errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) { sciThis->PreeditChangedThis(); } void ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void*) { RealizeText(widget, NULL); } void ScintillaGTK::RealizeText(GtkWidget *widget, void*) { // Set NULL background to avoid automatic clearing so Scintilla responsible for all drawing if (WindowFromWidget(widget)) { #if GTK_CHECK_VERSION(3,0,0) gdk_window_set_background_pattern(WindowFromWidget(widget), NULL); #else gdk_window_set_back_pixmap(WindowFromWidget(widget), NULL, FALSE); #endif } } void ScintillaGTK::Destroy(GObject *object) { try { ScintillaObject *scio = reinterpret_cast(object); // This avoids a double destruction if (!scio->pscin) return; ScintillaGTK *sciThis = reinterpret_cast(scio->pscin); //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object); sciThis->Finalise(); delete sciThis; scio->pscin = 0; } catch (...) { // Its dead so nowhere to save the status } } #if GTK_CHECK_VERSION(3,0,0) gboolean ScintillaGTK::DrawTextThis(cairo_t *cr) { try { paintState = painting; rcPaint = GetClientRectangle(); PLATFORM_ASSERT(rgnUpdate == NULL); rgnUpdate = cairo_copy_clip_rectangle_list(cr); if (rgnUpdate && rgnUpdate->status != CAIRO_STATUS_SUCCESS) { // If not successful then ignore fprintf(stderr, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate->status, rgnUpdate->num_rectangles); cairo_rectangle_list_destroy(rgnUpdate); rgnUpdate = 0; } double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); rcPaint.left = x1; rcPaint.top = y1; rcPaint.right = x2; rcPaint.bottom = y2; PRectangle rcClient = GetClientRectangle(); paintingAllText = rcPaint.Contains(rcClient); Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceWindow) { surfaceWindow->Init(cr, PWidget(wText)); Paint(surfaceWindow, rcPaint); surfaceWindow->Release(); delete surfaceWindow; } if (paintState == paintAbandoned) { // Painting area was insufficient to cover new styling or brace highlight positions FullPaint(); } paintState = notPainting; if (rgnUpdate) { cairo_rectangle_list_destroy(rgnUpdate); } rgnUpdate = 0; paintState = notPainting; } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } gboolean ScintillaGTK::DrawText(GtkWidget *, cairo_t *cr, ScintillaGTK *sciThis) { return sciThis->DrawTextThis(cr); } gboolean ScintillaGTK::DrawThis(cairo_t *cr) { try { gtk_container_propagate_draw( GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), cr); gtk_container_propagate_draw( GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), cr); } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } gboolean ScintillaGTK::DrawMain(GtkWidget *widget, cairo_t *cr) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); return sciThis->DrawThis(cr); } #else gboolean ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) { try { paintState = painting; rcPaint.left = ose->area.x; rcPaint.top = ose->area.y; rcPaint.right = ose->area.x + ose->area.width; rcPaint.bottom = ose->area.y + ose->area.height; PLATFORM_ASSERT(rgnUpdate == NULL); rgnUpdate = gdk_region_copy(ose->region); PRectangle rcClient = GetClientRectangle(); paintingAllText = rcPaint.Contains(rcClient); Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceWindow) { cairo_t *cr = gdk_cairo_create(PWindow(wText)); surfaceWindow->Init(cr, PWidget(wText)); Paint(surfaceWindow, rcPaint); surfaceWindow->Release(); delete surfaceWindow; cairo_destroy(cr); } if (paintState == paintAbandoned) { // Painting area was insufficient to cover new styling or brace highlight positions FullPaint(); } paintState = notPainting; if (rgnUpdate) { gdk_region_destroy(rgnUpdate); } rgnUpdate = 0; } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } gboolean ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) { return sciThis->ExposeTextThis(widget, ose); } gboolean ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n", //ose->area.x, ose->area.y, ose->area.width, ose->area.height); return sciThis->Expose(widget, ose); } gboolean ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) { try { //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n", //ose->area.x, ose->area.y, ose->area.width, ose->area.height); // The text is painted in ExposeText gtk_container_propagate_expose( GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose); gtk_container_propagate_expose( GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose); } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } #endif void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) { try { #if GTK_CHECK_VERSION(3,0,0) sciThis->ScrollTo(static_cast(gtk_adjustment_get_value(adj)), false); #else sciThis->ScrollTo(static_cast(adj->value), false); #endif } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) { try { #if GTK_CHECK_VERSION(3,0,0) sciThis->HorizontalScrollTo(static_cast(gtk_adjustment_get_value(adj) * 2)); #else sciThis->HorizontalScrollTo(static_cast(adj->value * 2)); #endif } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data, guint) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); //Platform::DebugPrintf("Selection received\n"); sciThis->ReceivedSelection(selection_data); } void ScintillaGTK::SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { //Platform::DebugPrintf("Selection get\n"); if (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY) { if (sciThis->primary.s == NULL) { sciThis->CopySelectionRange(&sciThis->primary); } sciThis->GetSelection(selection_data, info, &sciThis->primary); } } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); //Platform::DebugPrintf("Selection clear\n"); sciThis->UnclaimSelection(selection_event); if (GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event) { return GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event(widget, selection_event); } return TRUE; } void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *) { //Platform::DebugPrintf("DragBegin\n"); } gboolean ScintillaGTK::DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime) { try { Point npt(x, y); SetDragPosition(SPositionFromLocation(npt, false, false, UserVirtualSpace())); #if GTK_CHECK_VERSION(3,0,0) GdkDragAction preferredAction = gdk_drag_context_get_suggested_action(context); GdkDragAction actions = gdk_drag_context_get_actions(context); #else GdkDragAction preferredAction = context->suggested_action; GdkDragAction actions = context->actions; #endif SelectionPosition pos = SPositionFromLocation(npt); if ((inDragDrop == ddDragging) && (PositionInSelection(pos.Position()))) { // Avoid dragging selection onto itself as that produces a move // with no real effect but which creates undo actions. preferredAction = static_cast(0); } else if (actions == static_cast (GDK_ACTION_COPY | GDK_ACTION_MOVE)) { preferredAction = GDK_ACTION_MOVE; } gdk_drag_status(context, preferredAction, dragtime); } catch (...) { errorStatus = SC_STATUS_FAILURE; } return FALSE; } gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint dragtime) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); return sciThis->DragMotionThis(context, x, y, dragtime); } void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { sciThis->SetDragPosition(SelectionPosition(invalidPosition)); //Platform::DebugPrintf("DragLeave %x\n", sciThis); } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { // If drag did not result in drop here or elsewhere if (!sciThis->dragWasDropped) sciThis->SetEmptySelection(sciThis->posDrag); sciThis->SetDragPosition(SelectionPosition(invalidPosition)); //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped); sciThis->inDragDrop = ddNone; } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/, gint, gint, guint) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { //Platform::DebugPrintf("Drop %x\n", sciThis); sciThis->SetDragPosition(SelectionPosition(invalidPosition)); } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } return FALSE; } void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/, gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { sciThis->ReceivedDrop(selection_data); sciThis->SetDragPosition(SelectionPosition(invalidPosition)); } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint) { ScintillaGTK *sciThis = ScintillaFromWidget(widget); try { sciThis->dragWasDropped = true; if (!sciThis->sel.Empty()) { sciThis->GetSelection(selection_data, info, &sciThis->drag); } #if GTK_CHECK_VERSION(3,0,0) GdkDragAction action = gdk_drag_context_get_selected_action(context); #else GdkDragAction action = context->action; #endif if (action == GDK_ACTION_MOVE) { for (size_t r=0; rsel.Count(); r++) { if (sciThis->posDrop >= sciThis->sel.Range(r).Start()) { if (sciThis->posDrop > sciThis->sel.Range(r).End()) { sciThis->posDrop.Add(-sciThis->sel.Range(r).Length()); } else { sciThis->posDrop.Add(-SelectionRange(sciThis->posDrop, sciThis->sel.Range(r).Start()).Length()); } } } sciThis->ClearSelection(); } sciThis->SetDragPosition(SelectionPosition(invalidPosition)); } catch (...) { sciThis->errorStatus = SC_STATUS_FAILURE; } } int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) { sciThis->Tick(); return 1; } gboolean ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) { // Idler will be automatically stopped, if there is nothing // to do while idle. gdk_threads_enter(); bool ret = sciThis->Idle(); if (ret == false) { // FIXME: This will remove the idler from GTK, we don't want to // remove it as it is removed automatically when this function // returns false (although, it should be harmless). sciThis->SetIdle(false); } gdk_threads_leave(); return ret; } gboolean ScintillaGTK::StyleIdle(ScintillaGTK *sciThis) { gdk_threads_enter(); sciThis->IdleStyling(); gdk_threads_leave(); // Idler will be automatically stopped return FALSE; } void ScintillaGTK::QueueStyling(int upTo) { Editor::QueueStyling(upTo); if (!styleNeeded.active) { // Only allow one style needed to be queued styleNeeded.active = true; g_idle_add_full(G_PRIORITY_HIGH_IDLE, reinterpret_cast(StyleIdle), this, NULL); } } void ScintillaGTK::PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis) { guint action = (sptr_t)(g_object_get_data(G_OBJECT(menuItem), "CmdNum")); if (action) { sciThis->Command(action); } } gboolean ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) { try { if (event->window != WindowFromWidget(widget)) return FALSE; if (event->type != GDK_BUTTON_PRESS) return FALSE; Point pt; pt.x = int(event->x); pt.y = int(event->y); sciThis->ct.MouseClick(pt); sciThis->CallTipClick(); } catch (...) { } return TRUE; } #if GTK_CHECK_VERSION(3,0,0) gboolean ScintillaGTK::DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip) { try { Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceWindow) { surfaceWindow->Init(cr, widget); surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage); surfaceWindow->SetDBCSMode(ctip->codePage); ctip->PaintCT(surfaceWindow); surfaceWindow->Release(); delete surfaceWindow; } } catch (...) { // No pointer back to Scintilla to save status } return TRUE; } #else gboolean ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) { try { Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceWindow) { cairo_t *cr = gdk_cairo_create(WindowFromWidget(widget)); surfaceWindow->Init(cr, widget); surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage); surfaceWindow->SetDBCSMode(ctip->codePage); ctip->PaintCT(surfaceWindow); surfaceWindow->Release(); delete surfaceWindow; cairo_destroy(cr); } } catch (...) { // No pointer back to Scintilla to save status } return TRUE; } #endif sptr_t ScintillaGTK::DirectFunction( ScintillaGTK *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return sciThis->WndProc(iMessage, wParam, lParam); } sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) { ScintillaGTK *psci = reinterpret_cast(sci->pscin); return psci->WndProc(iMessage, wParam, lParam); } static void scintilla_class_init(ScintillaClass *klass); static void scintilla_init(ScintillaObject *sci); extern void Platform_Initialise(); extern void Platform_Finalise(); GType scintilla_get_type() { static GType scintilla_type = 0; try { if (!scintilla_type) { scintilla_type = g_type_from_name("Scintilla"); if (!scintilla_type) { static GTypeInfo scintilla_info = { (guint16) sizeof (ScintillaClass), NULL, //(GBaseInitFunc) NULL, //(GBaseFinalizeFunc) (GClassInitFunc) scintilla_class_init, NULL, //(GClassFinalizeFunc) NULL, //gconstpointer data (guint16) sizeof (ScintillaObject), 0, //n_preallocs (GInstanceInitFunc) scintilla_init, NULL //(GTypeValueTable*) }; scintilla_type = g_type_register_static( GTK_TYPE_CONTAINER, "Scintilla", &scintilla_info, (GTypeFlags) 0); } } } catch (...) { } return scintilla_type; } void ScintillaGTK::ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) { Platform_Initialise(); #ifdef SCI_LEXER Scintilla_LinkLexers(); #endif atomClipboard = gdk_atom_intern("CLIPBOARD", FALSE); atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE); atomString = GDK_SELECTION_TYPE_STRING; atomUriList = gdk_atom_intern("text/uri-list", FALSE); atomDROPFILES_DND = gdk_atom_intern("DROPFILES_DND", FALSE); // Define default signal handlers for the class: Could move more // of the signal handlers here (those that currently attached to wDraw // in Initialise() may require coordinate translation?) object_class->finalize = Destroy; #if GTK_CHECK_VERSION(3,0,0) widget_class->get_preferred_width = GetPreferredWidth; widget_class->get_preferred_height = GetPreferredHeight; #else widget_class->size_request = SizeRequest; #endif widget_class->size_allocate = SizeAllocate; #if GTK_CHECK_VERSION(3,0,0) widget_class->draw = DrawMain; #else widget_class->expose_event = ExposeMain; #endif widget_class->motion_notify_event = Motion; widget_class->button_press_event = Press; widget_class->button_release_event = MouseRelease; widget_class->scroll_event = ScrollEvent; widget_class->key_press_event = KeyPress; widget_class->key_release_event = KeyRelease; widget_class->focus_in_event = FocusIn; widget_class->focus_out_event = FocusOut; widget_class->selection_received = SelectionReceived; widget_class->selection_get = SelectionGet; widget_class->selection_clear_event = SelectionClear; widget_class->drag_data_received = DragDataReceived; widget_class->drag_motion = DragMotion; widget_class->drag_leave = DragLeave; widget_class->drag_end = DragEnd; widget_class->drag_drop = Drop; widget_class->drag_data_get = DragDataGet; widget_class->realize = Realize; widget_class->unrealize = UnRealize; widget_class->map = Map; widget_class->unmap = UnMap; container_class->forall = MainForAll; } #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER #define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER static void scintilla_class_init(ScintillaClass *klass) { try { OBJECT_CLASS *object_class = (OBJECT_CLASS*) klass; GtkWidgetClass *widget_class = (GtkWidgetClass*) klass; GtkContainerClass *container_class = (GtkContainerClass*) klass; GSignalFlags sigflags = GSignalFlags(G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST); scintilla_signals[COMMAND_SIGNAL] = g_signal_new( "command", G_TYPE_FROM_CLASS(object_class), sigflags, G_STRUCT_OFFSET(ScintillaClass, command), NULL, //(GSignalAccumulator) NULL, //(gpointer) SIG_MARSHAL, G_TYPE_NONE, 2, MARSHAL_ARGUMENTS); scintilla_signals[NOTIFY_SIGNAL] = g_signal_new( SCINTILLA_NOTIFY, G_TYPE_FROM_CLASS(object_class), sigflags, G_STRUCT_OFFSET(ScintillaClass, notify), NULL, NULL, SIG_MARSHAL, G_TYPE_NONE, 2, MARSHAL_ARGUMENTS); klass->command = NULL; klass->notify = NULL; ScintillaGTK::ClassInit(object_class, widget_class, container_class); } catch (...) { } } static void scintilla_init(ScintillaObject *sci) { try { #if GTK_CHECK_VERSION(2,20,0) gtk_widget_set_can_focus(GTK_WIDGET(sci), TRUE); #else GTK_WIDGET_SET_FLAGS(sci, GTK_CAN_FOCUS); #endif sci->pscin = new ScintillaGTK(sci); } catch (...) { } } GtkWidget* scintilla_new() { return GTK_WIDGET(g_object_new(scintilla_get_type(), NULL)); } void scintilla_set_id(ScintillaObject *sci, uptr_t id) { ScintillaGTK *psci = reinterpret_cast(sci->pscin); psci->ctrlID = id; } void scintilla_release_resources(void) { try { Platform_Finalise(); } catch (...) { } } presage-0.8.8/apps/gtk/gprompter/scintilla/gtk/scintilla-marshal.c0000644000175000017500000000756511615412040022176 00000000000000 #include #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) #define g_marshal_value_peek_char(v) g_value_get_char (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) #define g_marshal_value_peek_long(v) g_value_get_long (v) #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) #define g_marshal_value_peek_int64(v) g_value_get_int64 (v) #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) #define g_marshal_value_peek_enum(v) g_value_get_enum (v) #define g_marshal_value_peek_flags(v) g_value_get_flags (v) #define g_marshal_value_peek_float(v) g_value_get_float (v) #define g_marshal_value_peek_double(v) g_value_get_double (v) #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) #define g_marshal_value_peek_param(v) g_value_get_param (v) #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) #define g_marshal_value_peek_object(v) g_value_get_object (v) #else /* !G_ENABLE_DEBUG */ /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. * Do not access GValues directly in your code. Instead, use the * g_value_get_*() functions */ #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int #define g_marshal_value_peek_char(v) (v)->data[0].v_int #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint #define g_marshal_value_peek_int(v) (v)->data[0].v_int #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint #define g_marshal_value_peek_long(v) (v)->data[0].v_long #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 #define g_marshal_value_peek_enum(v) (v)->data[0].v_int #define g_marshal_value_peek_flags(v) (v)->data[0].v_uint #define g_marshal_value_peek_float(v) (v)->data[0].v_float #define g_marshal_value_peek_double(v) (v)->data[0].v_double #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer #endif /* !G_ENABLE_DEBUG */ /* NONE:INT,POINTER (scintilla-marshal.list:1) */ void scintilla_marshal_VOID__INT_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__INT_POINTER) (gpointer data1, gint arg_1, gpointer arg_2, gpointer data2); register GMarshalFunc_VOID__INT_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__INT_POINTER) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_int (param_values + 1), g_marshal_value_peek_pointer (param_values + 2), data2); } presage-0.8.8/apps/gtk/gprompter/scintilla/gtk/Converter.h0000644000175000017500000000414311615412040020530 00000000000000// Scintilla source code edit control // Converter.h - Encapsulation of iconv // Copyright 2004 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. typedef GIConv ConverterHandle; const ConverterHandle iconvhBad = (ConverterHandle)(-1); // Since various versions of iconv can not agree on whether the src argument // is char ** or const char ** provide a templatised adaptor. template size_t iconv_adaptor(size_t(*f_iconv)(ConverterHandle, T, size_t *, char **, size_t *), ConverterHandle cd, char** src, size_t *srcleft, char **dst, size_t *dstleft) { return f_iconv(cd, (T)src, srcleft, dst, dstleft); } /** * Encapsulate iconv safely and avoid iconv_adaptor complexity in client code. */ class Converter { ConverterHandle iconvh; void OpenHandle(const char *fullDestination, const char *charSetSource) { iconvh = g_iconv_open(fullDestination, charSetSource); } bool Succeeded() const { return iconvh != iconvhBad; } public: Converter() { iconvh = iconvhBad; } Converter(const char *charSetDestination, const char *charSetSource, bool transliterations) { iconvh = iconvhBad; Open(charSetDestination, charSetSource, transliterations); } ~Converter() { Close(); } operator bool() const { return Succeeded(); } void Open(const char *charSetDestination, const char *charSetSource, bool transliterations=true) { Close(); if (*charSetSource) { // Try allowing approximate transliterations if (transliterations) { char fullDest[200]; strcpy(fullDest, charSetDestination); strcat(fullDest, "//TRANSLIT"); OpenHandle(fullDest, charSetSource); } if (!Succeeded()) { // Transliterations failed so try basic name OpenHandle(charSetDestination, charSetSource); } } } void Close() { if (Succeeded()) { g_iconv_close(iconvh); iconvh = iconvhBad; } } size_t Convert(char** src, size_t *srcleft, char **dst, size_t *dstleft) const { if (!Succeeded()) { return (size_t)(-1); } else { return iconv_adaptor(g_iconv, iconvh, src, srcleft, dst, dstleft); } } }; presage-0.8.8/apps/gtk/gprompter/scintilla/gtk/PlatGTK.cxx0000644000175000017500000016674111763437013020432 00000000000000// Scintilla source code edit control // PlatGTK.cxx - implementation of platform facilities on GTK+/Linux // Copyright 1998-2004 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "Scintilla.h" #include "ScintillaWidget.h" #include "UniConversion.h" #include "XPM.h" #if defined(__clang__) // Clang 3.0 incorrectly displays sentinel warnings. Fixed by clang 3.1. #pragma GCC diagnostic ignored "-Wsentinel" #endif /* GLIB must be compiled with thread support, otherwise we will bail on trying to use locks, and that could lead to problems for someone. `glib-config --libs gthread` needs to be used to get the glib libraries for linking, otherwise g_thread_init will fail */ #define USE_LOCK defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE) #include "Converter.h" #if GTK_CHECK_VERSION(2,20,0) #define IS_WIDGET_FOCUSSED(w) (gtk_widget_has_focus(GTK_WIDGET(w))) #else #define IS_WIDGET_FOCUSSED(w) (GTK_WIDGET_HAS_FOCUS(w)) #endif // The Pango version guard for pango_units_from_double and pango_units_to_double // is more complex than simply implementing these here. static int pangoUnitsFromDouble(double d) { return static_cast(d * PANGO_SCALE + 0.5); } static double doubleFromPangoUnits(int pu) { return static_cast(pu) / PANGO_SCALE; } static cairo_surface_t *CreateSimilarSurface(GdkWindow *window, cairo_content_t content, int width, int height) { #if GTK_CHECK_VERSION(2,22,0) return gdk_window_create_similar_surface(window, content, width, height); #else cairo_surface_t *window_surface, *surface; g_return_val_if_fail(GDK_IS_WINDOW(window), NULL); window_surface = GDK_DRAWABLE_GET_CLASS(window)->ref_cairo_surface(window); surface = cairo_surface_create_similar(window_surface, content, width, height); cairo_surface_destroy(window_surface); return surface; #endif } static GdkWindow *WindowFromWidget(GtkWidget *w) { #if GTK_CHECK_VERSION(3,0,0) return gtk_widget_get_window(w); #else return w->window; #endif } #ifdef _MSC_VER // Ignore unreferenced local functions in GTK+ headers #pragma warning(disable: 4505) #endif #ifdef SCI_NAMESPACE using namespace Scintilla; #endif enum encodingType { singleByte, UTF8, dbcs}; struct LOGFONT { int size; int weight; bool italic; int characterSet; char faceName[300]; }; #if USE_LOCK static GMutex *fontMutex = NULL; static void InitializeGLIBThreads() { if (!g_thread_supported()) { g_thread_init(NULL); } } #endif static void FontMutexAllocate() { #if USE_LOCK if (!fontMutex) { InitializeGLIBThreads(); fontMutex = g_mutex_new(); } #endif } static void FontMutexFree() { #if USE_LOCK if (fontMutex) { g_mutex_free(fontMutex); fontMutex = NULL; } #endif } static void FontMutexLock() { #if USE_LOCK g_mutex_lock(fontMutex); #endif } static void FontMutexUnlock() { #if USE_LOCK if (fontMutex) { g_mutex_unlock(fontMutex); } #endif } // On GTK+ 1.x holds a GdkFont* but on GTK+ 2.x can hold a GdkFont* or a // PangoFontDescription*. class FontHandle { XYPOSITION width[128]; encodingType et; public: int ascent; PangoFontDescription *pfd; int characterSet; FontHandle() : et(singleByte), ascent(0), pfd(0), characterSet(-1) { ResetWidths(et); } FontHandle(PangoFontDescription *pfd_, int characterSet_) { et = singleByte; ascent = 0; pfd = pfd_; characterSet = characterSet_; ResetWidths(et); } ~FontHandle() { if (pfd) pango_font_description_free(pfd); pfd = 0; } void ResetWidths(encodingType et_) { et = et_; for (int i=0; i<=127; i++) { width[i] = 0; } } XYPOSITION CharWidth(unsigned char ch, encodingType et_) { XYPOSITION w = 0; FontMutexLock(); if ((ch <= 127) && (et == et_)) { w = width[ch]; } FontMutexUnlock(); return w; } void SetCharWidth(unsigned char ch, XYPOSITION w, encodingType et_) { if (ch <= 127) { FontMutexLock(); if (et != et_) { ResetWidths(et_); } width[ch] = w; FontMutexUnlock(); } } }; // X has a 16 bit coordinate space, so stop drawing here to avoid wrapping static const int maxCoordinate = 32000; static FontHandle *PFont(Font &f) { return reinterpret_cast(f.GetID()); } static GtkWidget *PWidget(WindowID wid) { return reinterpret_cast(wid); } Point Point::FromLong(long lpoint) { return Point( Platform::LowShortFromLong(lpoint), Platform::HighShortFromLong(lpoint)); } static void SetLogFont(LOGFONT &lf, const char *faceName, int characterSet, float size, int weight, bool italic) { memset(&lf, 0, sizeof(lf)); lf.size = size; lf.weight = weight; lf.italic = italic; lf.characterSet = characterSet; strncpy(lf.faceName, faceName, sizeof(lf.faceName) - 1); } /** * Create a hash from the parameters for a font to allow easy checking for identity. * If one font is the same as another, its hash will be the same, but if the hash is the * same then they may still be different. */ static int HashFont(const FontParameters &fp) { return static_cast(fp.size+0.5) ^ (fp.characterSet << 10) ^ ((fp.weight / 100) << 12) ^ (fp.italic ? 0x20000000 : 0) ^ fp.faceName[0]; } class FontCached : Font { FontCached *next; int usage; LOGFONT lf; int hash; FontCached(const FontParameters &fp); ~FontCached() {} bool SameAs(const FontParameters &fp); virtual void Release(); static FontID CreateNewFont(const FontParameters &fp); static FontCached *first; public: static FontID FindOrCreate(const FontParameters &fp); static void ReleaseId(FontID fid_); }; FontCached *FontCached::first = 0; FontCached::FontCached(const FontParameters &fp) : next(0), usage(0), hash(0) { ::SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic); hash = HashFont(fp); fid = CreateNewFont(fp); usage = 1; } bool FontCached::SameAs(const FontParameters &fp) { return lf.size == fp.size && lf.weight == fp.weight && lf.italic == fp.italic && lf.characterSet == fp.characterSet && 0 == strcmp(lf.faceName, fp.faceName); } void FontCached::Release() { if (fid) delete PFont(*this); fid = 0; } FontID FontCached::FindOrCreate(const FontParameters &fp) { FontID ret = 0; FontMutexLock(); int hashFind = HashFont(fp); for (FontCached *cur = first; cur; cur = cur->next) { if ((cur->hash == hashFind) && cur->SameAs(fp)) { cur->usage++; ret = cur->fid; } } if (ret == 0) { FontCached *fc = new FontCached(fp); if (fc) { fc->next = first; first = fc; ret = fc->fid; } } FontMutexUnlock(); return ret; } void FontCached::ReleaseId(FontID fid_) { FontMutexLock(); FontCached **pcur = &first; for (FontCached *cur = first; cur; cur = cur->next) { if (cur->fid == fid_) { cur->usage--; if (cur->usage == 0) { *pcur = cur->next; cur->Release(); cur->next = 0; delete cur; } break; } pcur = &cur->next; } FontMutexUnlock(); } FontID FontCached::CreateNewFont(const FontParameters &fp) { PangoFontDescription *pfd = pango_font_description_new(); if (pfd) { pango_font_description_set_family(pfd, (fp.faceName[0] == '!') ? fp.faceName+1 : fp.faceName); pango_font_description_set_size(pfd, pangoUnitsFromDouble(fp.size)); pango_font_description_set_weight(pfd, static_cast(fp.weight)); pango_font_description_set_style(pfd, fp.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); return new FontHandle(pfd, fp.characterSet); } return new FontHandle(); } Font::Font() : fid(0) {} Font::~Font() {} void Font::Create(const FontParameters &fp) { Release(); fid = FontCached::FindOrCreate(fp); } void Font::Release() { if (fid) FontCached::ReleaseId(fid); fid = 0; } // Required on OS X #ifdef SCI_NAMESPACE namespace Scintilla { #endif // SurfaceID is a cairo_t* class SurfaceImpl : public Surface { encodingType et; cairo_t *context; cairo_surface_t *psurf; int x; int y; bool inited; bool createdGC; PangoContext *pcontext; PangoLayout *layout; Converter conv; int characterSet; void SetConverter(int characterSet_); public: SurfaceImpl(); virtual ~SurfaceImpl(); void Init(WindowID wid); void Init(SurfaceID sid, WindowID wid); void InitPixMap(int width, int height, Surface *surface_, WindowID wid); void Release(); bool Initialised(); void PenColour(ColourDesired fore); int LogPixelsY(); int DeviceHeightFont(int points); void MoveTo(int x_, int y_); void LineTo(int x_, int y_); void Polygon(Point *pts, int npts, ColourDesired fore, ColourDesired back); void RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back); void FillRectangle(PRectangle rc, ColourDesired back); void FillRectangle(PRectangle rc, Surface &surfacePattern); void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back); void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, ColourDesired outline, int alphaOutline, int flags); void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage); void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back); void Copy(PRectangle rc, Point from, Surface &surfaceSource); void DrawTextBase(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore); void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back); void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back); void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore); void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); XYPOSITION WidthText(Font &font_, const char *s, int len); XYPOSITION WidthChar(Font &font_, char ch); XYPOSITION Ascent(Font &font_); XYPOSITION Descent(Font &font_); XYPOSITION InternalLeading(Font &font_); XYPOSITION ExternalLeading(Font &font_); XYPOSITION Height(Font &font_); XYPOSITION AverageCharWidth(Font &font_); void SetClip(PRectangle rc); void FlushCachedState(); void SetUnicodeMode(bool unicodeMode_); void SetDBCSMode(int codePage); }; #ifdef SCI_NAMESPACE } #endif const char *CharacterSetID(int characterSet) { switch (characterSet) { case SC_CHARSET_ANSI: return ""; case SC_CHARSET_DEFAULT: return "ISO-8859-1"; case SC_CHARSET_BALTIC: return "ISO-8859-13"; case SC_CHARSET_CHINESEBIG5: return "BIG-5"; case SC_CHARSET_EASTEUROPE: return "ISO-8859-2"; case SC_CHARSET_GB2312: return "CP936"; case SC_CHARSET_GREEK: return "ISO-8859-7"; case SC_CHARSET_HANGUL: return "CP949"; case SC_CHARSET_MAC: return "MACINTOSH"; case SC_CHARSET_OEM: return "ASCII"; case SC_CHARSET_RUSSIAN: return "KOI8-R"; case SC_CHARSET_CYRILLIC: return "CP1251"; case SC_CHARSET_SHIFTJIS: return "SHIFT-JIS"; case SC_CHARSET_SYMBOL: return ""; case SC_CHARSET_TURKISH: return "ISO-8859-9"; case SC_CHARSET_JOHAB: return "CP1361"; case SC_CHARSET_HEBREW: return "ISO-8859-8"; case SC_CHARSET_ARABIC: return "ISO-8859-6"; case SC_CHARSET_VIETNAMESE: return ""; case SC_CHARSET_THAI: return "ISO-8859-11"; case SC_CHARSET_8859_15: return "ISO-8859-15"; default: return ""; } } void SurfaceImpl::SetConverter(int characterSet_) { if (characterSet != characterSet_) { characterSet = characterSet_; conv.Open("UTF-8", CharacterSetID(characterSet), false); } } SurfaceImpl::SurfaceImpl() : et(singleByte), context(0), psurf(0), x(0), y(0), inited(false), createdGC(false) , pcontext(0), layout(0), characterSet(-1) { } SurfaceImpl::~SurfaceImpl() { Release(); } void SurfaceImpl::Release() { et = singleByte; if (createdGC) { createdGC = false; cairo_destroy(context); } context = 0; if (psurf) cairo_surface_destroy(psurf); psurf = 0; if (layout) g_object_unref(layout); layout = 0; if (pcontext) g_object_unref(pcontext); pcontext = 0; conv.Close(); characterSet = -1; x = 0; y = 0; inited = false; createdGC = false; } bool SurfaceImpl::Initialised() { return inited; } void SurfaceImpl::Init(WindowID wid) { Release(); PLATFORM_ASSERT(wid); #if GTK_CHECK_VERSION(3,0,0) GdkWindow *drawable_ = gtk_widget_get_window(PWidget(wid)); #else GdkDrawable *drawable_ = GDK_DRAWABLE(PWidget(wid)->window); #endif if (drawable_) { context = gdk_cairo_create(drawable_); PLATFORM_ASSERT(context); } else { // Shouldn't happen with valid window but may when calls made before // window completely allocated and mapped. psurf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 1, 1); context = cairo_create(psurf); } createdGC = true; pcontext = gtk_widget_create_pango_context(PWidget(wid)); PLATFORM_ASSERT(pcontext); layout = pango_layout_new(pcontext); PLATFORM_ASSERT(layout); inited = true; } void SurfaceImpl::Init(SurfaceID sid, WindowID wid) { PLATFORM_ASSERT(sid); Release(); PLATFORM_ASSERT(wid); context = cairo_reference(reinterpret_cast(sid)); pcontext = gtk_widget_create_pango_context(PWidget(wid)); layout = pango_layout_new(pcontext); cairo_set_line_width(context, 1); createdGC = true; inited = true; } void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID wid) { PLATFORM_ASSERT(surface_); Release(); SurfaceImpl *surfImpl = static_cast(surface_); PLATFORM_ASSERT(wid); context = cairo_reference(surfImpl->context); pcontext = gtk_widget_create_pango_context(PWidget(wid)); PLATFORM_ASSERT(pcontext); layout = pango_layout_new(pcontext); PLATFORM_ASSERT(layout); if (height > 0 && width > 0) psurf = CreateSimilarSurface( WindowFromWidget(PWidget(wid)), CAIRO_CONTENT_COLOR_ALPHA, width, height); cairo_destroy(context); context = cairo_create(psurf); cairo_rectangle(context, 0, 0, width, height); cairo_set_source_rgb(context, 1.0, 0, 0); cairo_fill(context); // This produces sharp drawing more similar to GDK: //cairo_set_antialias(context, CAIRO_ANTIALIAS_NONE); cairo_set_line_width(context, 1); createdGC = true; inited = true; } void SurfaceImpl::PenColour(ColourDesired fore) { if (context) { ColourDesired cdFore(fore.AsLong()); cairo_set_source_rgb(context, cdFore.GetRed() / 255.0, cdFore.GetGreen() / 255.0, cdFore.GetBlue() / 255.0); } } int SurfaceImpl::LogPixelsY() { return 72; } int SurfaceImpl::DeviceHeightFont(int points) { int logPix = LogPixelsY(); return (points * logPix + logPix / 2) / 72; } void SurfaceImpl::MoveTo(int x_, int y_) { x = x_; y = y_; } static int Delta(int difference) { if (difference < 0) return -1; else if (difference > 0) return 1; else return 0; } void SurfaceImpl::LineTo(int x_, int y_) { // cairo_line_to draws the end position, unlike Win32 or GDK with GDK_CAP_NOT_LAST. // For simple cases, move back one pixel from end. if (context) { int xDiff = x_ - x; int xDelta = Delta(xDiff); int yDiff = y_ - y; int yDelta = Delta(yDiff); if ((xDiff == 0) || (yDiff == 0)) { // Horizontal or vertical lines can be more precisely drawn as a filled rectangle int xEnd = x_ - xDelta; int left = Platform::Minimum(x, xEnd); int width = abs(x - xEnd) + 1; int yEnd = y_ - yDelta; int top = Platform::Minimum(y, yEnd); int height = abs(y - yEnd) + 1; cairo_rectangle(context, left, top, width, height); cairo_fill(context); } else if ((abs(xDiff) == abs(yDiff))) { // 45 degree slope cairo_move_to(context, x + 0.5, y + 0.5); cairo_line_to(context, x_ + 0.5 - xDelta, y_ + 0.5 - yDelta); } else { // Line has a different slope so difficult to avoid last pixel cairo_move_to(context, x + 0.5, y + 0.5); cairo_line_to(context, x_ + 0.5, y_ + 0.5); } cairo_stroke(context); } x = x_; y = y_; } void SurfaceImpl::Polygon(Point *pts, int npts, ColourDesired fore, ColourDesired back) { PenColour(back); cairo_move_to(context, pts[0].x + 0.5, pts[0].y + 0.5); for (int i = 1;i < npts;i++) { cairo_line_to(context, pts[i].x + 0.5, pts[i].y + 0.5); } cairo_close_path(context); cairo_fill_preserve(context); PenColour(fore); cairo_stroke(context); } void SurfaceImpl::RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back) { if (context) { cairo_rectangle(context, rc.left + 0.5, rc.top + 0.5, rc.right - rc.left - 1, rc.bottom - rc.top - 1); PenColour(back); cairo_fill_preserve(context); PenColour(fore); cairo_stroke(context); } } void SurfaceImpl::FillRectangle(PRectangle rc, ColourDesired back) { PenColour(back); if (context && (rc.left < maxCoordinate)) { // Protect against out of range rc.left = lround(rc.left); rc.right = lround(rc.right); cairo_rectangle(context, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); cairo_fill(context); } } void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { SurfaceImpl &surfi = static_cast(surfacePattern); bool canDraw = surfi.psurf; if (canDraw) { // Tile pattern over rectangle // Currently assumes 8x8 pattern int widthPat = 8; int heightPat = 8; for (int xTile = rc.left; xTile < rc.right; xTile += widthPat) { int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat; for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) { int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat; cairo_set_source_surface(context, surfi.psurf, xTile, yTile); cairo_rectangle(context, xTile, yTile, widthx, heighty); cairo_fill(context); } } } else { // Something is wrong so try to show anyway // Shows up black because colour not allocated FillRectangle(rc, ColourDesired(0)); } } void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) { if (((rc.right - rc.left) > 4) && ((rc.bottom - rc.top) > 4)) { // Approximate a round rect with some cut off corners Point pts[] = { Point(rc.left + 2, rc.top), Point(rc.right - 2, rc.top), Point(rc.right, rc.top + 2), Point(rc.right, rc.bottom - 2), Point(rc.right - 2, rc.bottom), Point(rc.left + 2, rc.bottom), Point(rc.left, rc.bottom - 2), Point(rc.left, rc.top + 2), }; Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back); } else { RectangleDraw(rc, fore, back); } } static void PathRoundRectangle(cairo_t *context, double left, double top, double width, double height, int radius) { double degrees = M_PI / 180.0; #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 2, 0) cairo_new_sub_path(context); #else // First arc is in the top-right corner and starts from a point on the top line cairo_move_to(context, left + width - radius, top); #endif cairo_arc(context, left + width - radius, top + radius, radius, -90 * degrees, 0 * degrees); cairo_arc(context, left + width - radius, top + height - radius, radius, 0 * degrees, 90 * degrees); cairo_arc(context, left + radius, top + height - radius, radius, 90 * degrees, 180 * degrees); cairo_arc(context, left + radius, top + radius, radius, 180 * degrees, 270 * degrees); cairo_close_path(context); } void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, ColourDesired outline, int alphaOutline, int flags) { if (context && rc.Width() > 0) { ColourDesired cdFill(fill.AsLong()); cairo_set_source_rgba(context, cdFill.GetRed() / 255.0, cdFill.GetGreen() / 255.0, cdFill.GetBlue() / 255.0, alphaFill / 255.0); if (cornerSize > 0) PathRoundRectangle(context, rc.left + 1.0, rc.top + 1.0, rc.right - rc.left - 2.0, rc.bottom - rc.top - 2.0, cornerSize); else cairo_rectangle(context, rc.left + 1.0, rc.top + 1.0, rc.right - rc.left - 2.0, rc.bottom - rc.top - 2.0); cairo_fill(context); ColourDesired cdOutline(outline.AsLong()); cairo_set_source_rgba(context, cdOutline.GetRed() / 255.0, cdOutline.GetGreen() / 255.0, cdOutline.GetBlue() / 255.0, alphaOutline / 255.0); if (cornerSize > 0) PathRoundRectangle(context, rc.left + 0.5, rc.top + 0.5, rc.right - rc.left - 1, rc.bottom - rc.top - 1, cornerSize); else cairo_rectangle(context, rc.left + 0.5, rc.top + 0.5, rc.right - rc.left - 1, rc.bottom - rc.top - 1); cairo_stroke(context); } } void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { if (rc.Width() > width) rc.left += (rc.Width() - width) / 2; rc.right = rc.left + width; if (rc.Height() > height) rc.top += (rc.Height() - height) / 2; rc.bottom = rc.top + height; #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,6,0) int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); #else int stride = width * 4; #endif int ucs = stride * height; std::vector image(ucs); for (int y=0; y(surfaceSource); bool canDraw = surfi.psurf; if (canDraw) { cairo_set_source_surface(context, surfi.psurf, rc.left - from.x, rc.top - from.y); cairo_rectangle(context, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); cairo_fill(context); } } char *UTF8FromLatin1(const char *s, int &len) { char *utfForm = new char[len*2+1]; size_t lenU = 0; for (int i=0;i(s[i]); if (uch < 0x80) { utfForm[lenU++] = uch; } else { utfForm[lenU++] = static_cast(0xC0 | (uch >> 6)); utfForm[lenU++] = static_cast(0x80 | (uch & 0x3f)); } } utfForm[lenU] = '\0'; len = lenU; return utfForm; } static char *UTF8FromIconv(const Converter &conv, const char *s, int &len) { if (conv) { char *utfForm = new char[len*3+1]; char *pin = const_cast(s); size_t inLeft = len; char *pout = utfForm; size_t outLeft = len*3+1; size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); if (conversions != ((size_t)(-1))) { *pout = '\0'; len = pout - utfForm; return utfForm; } delete []utfForm; } return 0; } // Work out how many bytes are in a character by trying to convert using iconv, // returning the first length that succeeds. static size_t MultiByteLenFromIconv(const Converter &conv, const char *s, size_t len) { for (size_t lenMB=1; (lenMB<4) && (lenMB <= len); lenMB++) { char wcForm[2]; char *pin = const_cast(s); size_t inLeft = lenMB; char *pout = wcForm; size_t outLeft = 2; size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); if (conversions != ((size_t)(-1))) { return lenMB; } } return 1; } static size_t UTF8CharLength(const char *s) { const unsigned char *us = reinterpret_cast(s); unsigned char ch = *us; if (ch < 0x80) { return 1; } else if (ch < 0x80 + 0x40 + 0x20) { return 2; } else { return 3; } } void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore) { PenColour(fore); if (context) { XYPOSITION xText = rc.left; if (PFont(font_)->pfd) { char *utfForm = 0; if (et == UTF8) { pango_layout_set_text(layout, s, len); } else { if (!utfForm) { SetConverter(PFont(font_)->characterSet); utfForm = UTF8FromIconv(conv, s, len); } if (!utfForm) { // iconv failed so treat as Latin1 utfForm = UTF8FromLatin1(s, len); } pango_layout_set_text(layout, utfForm, len); } pango_layout_set_font_description(layout, PFont(font_)->pfd); pango_cairo_update_layout(context, layout); #ifdef PANGO_VERSION PangoLayoutLine *pll = pango_layout_get_line_readonly(layout,0); #else PangoLayoutLine *pll = pango_layout_get_line(layout,0); #endif cairo_move_to(context, xText, ybase); pango_cairo_show_layout_line(context, pll); delete []utfForm; } } } void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) { FillRectangle(rc, back); DrawTextBase(rc, font_, ybase, s, len, fore); } // On GTK+, exactly same as DrawTextNoClip void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) { FillRectangle(rc, back); DrawTextBase(rc, font_, ybase, s, len, fore); } void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore) { // Avoid drawing spaces in transparent mode for (int i=0;ipfd) { if (len == 1) { int width = PFont(font_)->CharWidth(*s, et); if (width) { positions[0] = width; return; } } pango_layout_set_font_description(layout, PFont(font_)->pfd); if (et == UTF8) { // Simple and direct as UTF-8 is native Pango encoding int i = 0; pango_layout_set_text(layout, s, len); ClusterIterator iti(layout, lenPositions); while (!iti.finished) { iti.Next(); int places = iti.curIndex - i; while (i < iti.curIndex) { // Evenly distribute space among bytes of this cluster. // Would be better to find number of characters and then // divide evenly between characters with each byte of a character // being at the same position. positions[i] = iti.position - (iti.curIndex - 1 - i) * iti.distance / places; i++; } } PLATFORM_ASSERT(i == lenPositions); } else { int positionsCalculated = 0; if (et == dbcs) { SetConverter(PFont(font_)->characterSet); char *utfForm = UTF8FromIconv(conv, s, len); if (utfForm) { // Convert to UTF-8 so can ask Pango for widths, then // Loop through UTF-8 and DBCS forms, taking account of different // character byte lengths. Converter convMeasure("UCS-2", CharacterSetID(characterSet), false); pango_layout_set_text(layout, utfForm, strlen(utfForm)); int i = 0; int clusterStart = 0; ClusterIterator iti(layout, strlen(utfForm)); while (!iti.finished) { iti.Next(); int clusterEnd = iti.curIndex; int places = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart); int place = 1; while (clusterStart < clusterEnd) { size_t lenChar = MultiByteLenFromIconv(convMeasure, s+i, len-i); while (lenChar--) { positions[i++] = iti.position - (places - place) * iti.distance / places; positionsCalculated++; } clusterStart += UTF8CharLength(utfForm+clusterStart); place++; } } delete []utfForm; PLATFORM_ASSERT(i == lenPositions); } } if (positionsCalculated < 1 ) { // Either Latin1 or DBCS conversion failed so treat as Latin1. SetConverter(PFont(font_)->characterSet); char *utfForm = UTF8FromIconv(conv, s, len); if (!utfForm) { utfForm = UTF8FromLatin1(s, len); } pango_layout_set_text(layout, utfForm, len); int i = 0; int clusterStart = 0; // Each Latin1 input character may take 1 or 2 bytes in UTF-8 // and groups of up to 3 may be represented as ligatures. ClusterIterator iti(layout, strlen(utfForm)); while (!iti.finished) { iti.Next(); int clusterEnd = iti.curIndex; int ligatureLength = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart); PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3); for (int charInLig=0; charInLigSetCharWidth(*s, positions[0], et); } return; } } else { // No font so return an ascending range of values for (int i = 0; i < len; i++) { positions[i] = i + 1; } } } XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) { if (font_.GetID()) { if (PFont(font_)->pfd) { char *utfForm = 0; pango_layout_set_font_description(layout, PFont(font_)->pfd); PangoRectangle pos; if (et == UTF8) { pango_layout_set_text(layout, s, len); } else { if (!utfForm) { // use iconv SetConverter(PFont(font_)->characterSet); utfForm = UTF8FromIconv(conv, s, len); } if (!utfForm) { // iconv failed so treat as Latin1 utfForm = UTF8FromLatin1(s, len); } pango_layout_set_text(layout, utfForm, len); } #ifdef PANGO_VERSION PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout,0); #else PangoLayoutLine *pangoLine = pango_layout_get_line(layout,0); #endif pango_layout_line_get_extents(pangoLine, NULL, &pos); delete []utfForm; return doubleFromPangoUnits(pos.width); } return 1; } else { return 1; } } XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) { if (font_.GetID()) { if (PFont(font_)->pfd) { return WidthText(font_, &ch, 1); } return 1; } else { return 1; } } // Ascent and descent determined by Pango font metrics. XYPOSITION SurfaceImpl::Ascent(Font &font_) { if (!(font_.GetID())) return 1; FontMutexLock(); int ascent = PFont(font_)->ascent; if ((ascent == 0) && (PFont(font_)->pfd)) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, PFont(font_)->pfd, pango_context_get_language(pcontext)); PFont(font_)->ascent = doubleFromPangoUnits(pango_font_metrics_get_ascent(metrics)); pango_font_metrics_unref(metrics); ascent = PFont(font_)->ascent; } if (ascent == 0) { ascent = 1; } FontMutexUnlock(); return ascent; } XYPOSITION SurfaceImpl::Descent(Font &font_) { if (!(font_.GetID())) return 1; if (PFont(font_)->pfd) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, PFont(font_)->pfd, pango_context_get_language(pcontext)); int descent = doubleFromPangoUnits(pango_font_metrics_get_descent(metrics)); pango_font_metrics_unref(metrics); return descent; } return 0; } XYPOSITION SurfaceImpl::InternalLeading(Font &) { return 0; } XYPOSITION SurfaceImpl::ExternalLeading(Font &) { return 0; } XYPOSITION SurfaceImpl::Height(Font &font_) { return Ascent(font_) + Descent(font_); } XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { return WidthChar(font_, 'n'); } void SurfaceImpl::SetClip(PRectangle rc) { cairo_rectangle(context, rc.left, rc.top, rc.right, rc.bottom); cairo_clip(context); } void SurfaceImpl::FlushCachedState() {} void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) { if (unicodeMode_) et = UTF8; } void SurfaceImpl::SetDBCSMode(int codePage) { if (codePage && (codePage != SC_CP_UTF8)) et = dbcs; } Surface *Surface::Allocate(int) { return new SurfaceImpl(); } Window::~Window() {} void Window::Destroy() { if (wid) gtk_widget_destroy(GTK_WIDGET(wid)); wid = 0; } bool Window::HasFocus() { return IS_WIDGET_FOCUSSED(wid); } PRectangle Window::GetPosition() { // Before any size allocated pretend its 1000 wide so not scrolled PRectangle rc(0, 0, 1000, 1000); if (wid) { GtkAllocation allocation; #if GTK_CHECK_VERSION(3,0,0) gtk_widget_get_allocation(PWidget(wid), &allocation); #else allocation = PWidget(wid)->allocation; #endif rc.left = allocation.x; rc.top = allocation.y; if (allocation.width > 20) { rc.right = rc.left + allocation.width; rc.bottom = rc.top + allocation.height; } } return rc; } void Window::SetPosition(PRectangle rc) { GtkAllocation alloc; alloc.x = rc.left; alloc.y = rc.top; alloc.width = rc.Width(); alloc.height = rc.Height(); gtk_widget_size_allocate(PWidget(wid), &alloc); } void Window::SetPositionRelative(PRectangle rc, Window relativeTo) { int ox = 0; int oy = 0; gdk_window_get_origin(WindowFromWidget(PWidget(relativeTo.wid)), &ox, &oy); ox += rc.left; if (ox < 0) ox = 0; oy += rc.top; if (oy < 0) oy = 0; /* do some corrections to fit into screen */ int sizex = rc.right - rc.left; int sizey = rc.bottom - rc.top; int screenWidth = gdk_screen_width(); int screenHeight = gdk_screen_height(); if (sizex > screenWidth) ox = 0; /* the best we can do */ else if (ox + sizex > screenWidth) ox = screenWidth - sizex; if (oy + sizey > screenHeight) oy = screenHeight - sizey; gtk_window_move(GTK_WINDOW(PWidget(wid)), ox, oy); gtk_widget_set_size_request(PWidget(wid), sizex, sizey); } PRectangle Window::GetClientPosition() { // On GTK+, the client position is the window position return GetPosition(); } void Window::Show(bool show) { if (show) gtk_widget_show(PWidget(wid)); } void Window::InvalidateAll() { if (wid) { gtk_widget_queue_draw(PWidget(wid)); } } void Window::InvalidateRectangle(PRectangle rc) { if (wid) { gtk_widget_queue_draw_area(PWidget(wid), rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); } } void Window::SetFont(Font &) { // Can not be done generically but only needed for ListBox } void Window::SetCursor(Cursor curs) { // We don't set the cursor to same value numerous times under gtk because // it stores the cursor in the window once it's set if (curs == cursorLast) return; cursorLast = curs; GdkCursor *gdkCurs; switch (curs) { case cursorText: gdkCurs = gdk_cursor_new(GDK_XTERM); break; case cursorArrow: gdkCurs = gdk_cursor_new(GDK_LEFT_PTR); break; case cursorUp: gdkCurs = gdk_cursor_new(GDK_CENTER_PTR); break; case cursorWait: gdkCurs = gdk_cursor_new(GDK_WATCH); break; case cursorHand: gdkCurs = gdk_cursor_new(GDK_HAND2); break; case cursorReverseArrow: gdkCurs = gdk_cursor_new(GDK_RIGHT_PTR); break; default: gdkCurs = gdk_cursor_new(GDK_LEFT_PTR); cursorLast = cursorArrow; break; } if (WindowFromWidget(PWidget(wid))) gdk_window_set_cursor(WindowFromWidget(PWidget(wid)), gdkCurs); #if GTK_CHECK_VERSION(3,0,0) g_object_unref(gdkCurs); #else gdk_cursor_unref(gdkCurs); #endif } void Window::SetTitle(const char *s) { gtk_window_set_title(GTK_WINDOW(wid), s); } /* Returns rectangle of monitor pt is on, both rect and pt are in Window's gdk window coordinates */ PRectangle Window::GetMonitorRect(Point pt) { gint x_offset, y_offset; gdk_window_get_origin(WindowFromWidget(PWidget(wid)), &x_offset, &y_offset); GdkScreen* screen; gint monitor_num; GdkRectangle rect; screen = gtk_widget_get_screen(PWidget(wid)); monitor_num = gdk_screen_get_monitor_at_point(screen, pt.x + x_offset, pt.y + y_offset); gdk_screen_get_monitor_geometry(screen, monitor_num, &rect); rect.x -= x_offset; rect.y -= y_offset; return PRectangle(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); } typedef std::map ImageMap; struct ListImage { const RGBAImage *rgba_data; GdkPixbuf *pixbuf; }; static void list_image_free(gpointer, gpointer value, gpointer) { ListImage *list_image = static_cast(value); if (list_image->pixbuf) g_object_unref(list_image->pixbuf); g_free(list_image); } ListBox::ListBox() { } ListBox::~ListBox() { } enum { PIXBUF_COLUMN, TEXT_COLUMN, N_COLUMNS }; class ListBoxX : public ListBox { WindowID list; WindowID scroller; void *pixhash; GtkCellRenderer* pixbuf_renderer; RGBAImageSet images; int desiredVisibleRows; unsigned int maxItemCharacters; unsigned int aveCharWidth; public: CallBackAction doubleClickAction; void *doubleClickActionData; ListBoxX() : list(0), scroller(0), pixhash(NULL), pixbuf_renderer(0), desiredVisibleRows(5), maxItemCharacters(0), aveCharWidth(1), doubleClickAction(NULL), doubleClickActionData(NULL) { } virtual ~ListBoxX() { if (pixhash) { g_hash_table_foreach((GHashTable *) pixhash, list_image_free, NULL); g_hash_table_destroy((GHashTable *) pixhash); } } virtual void SetFont(Font &font); virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, int technology_); virtual void SetAverageCharWidth(int width); virtual void SetVisibleRows(int rows); virtual int GetVisibleRows() const; virtual PRectangle GetDesiredRect(); virtual int CaretFromEdge(); virtual void Clear(); virtual void Append(char *s, int type = -1); virtual int Length(); virtual void Select(int n); virtual int GetSelection(); virtual int Find(const char *prefix); virtual void GetValue(int n, char *value, int len); void RegisterRGBA(int type, RGBAImage *image); virtual void RegisterImage(int type, const char *xpm_data); virtual void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage); virtual void ClearRegisteredImages(); virtual void SetDoubleClickAction(CallBackAction action, void *data) { doubleClickAction = action; doubleClickActionData = data; } virtual void SetList(const char *listText, char separator, char typesep); }; ListBox *ListBox::Allocate() { ListBoxX *lb = new ListBoxX(); return lb; } static gboolean ButtonPress(GtkWidget *, GdkEventButton* ev, gpointer p) { try { ListBoxX* lb = reinterpret_cast(p); if (ev->type == GDK_2BUTTON_PRESS && lb->doubleClickAction != NULL) { lb->doubleClickAction(lb->doubleClickActionData); return TRUE; } } catch (...) { // No pointer back to Scintilla to save status } return FALSE; } /* Change the active color to the selected color so the listbox uses the color scheme that it would use if it had the focus. */ static void StyleSet(GtkWidget *w, GtkStyle*, void*) { g_return_if_fail(w != NULL); /* Copy the selected color to active. Note that the modify calls will cause recursive calls to this function after the value is updated and w->style to be set to a new object */ #if GTK_CHECK_VERSION(3,0,0) GtkStyleContext *styleContext = gtk_widget_get_style_context(w); if (styleContext == NULL) return; GdkRGBA colourForeSelected; gtk_style_context_get_color(styleContext, GTK_STATE_FLAG_SELECTED, &colourForeSelected); GdkRGBA colourForeActive; gtk_style_context_get_color(styleContext, GTK_STATE_FLAG_ACTIVE, &colourForeActive); if (!gdk_rgba_equal(&colourForeSelected, &colourForeActive)) gtk_widget_override_color(w, GTK_STATE_FLAG_ACTIVE, &colourForeSelected); styleContext = gtk_widget_get_style_context(w); if (styleContext == NULL) return; GdkRGBA colourBaseSelected; gtk_style_context_get_background_color(styleContext, GTK_STATE_FLAG_SELECTED, &colourBaseSelected); GdkRGBA colourBaseActive; gtk_style_context_get_background_color(styleContext, GTK_STATE_FLAG_ACTIVE, &colourBaseActive); if (!gdk_rgba_equal(&colourBaseSelected, &colourBaseActive)) gtk_widget_override_background_color(w, GTK_STATE_FLAG_ACTIVE, &colourBaseSelected); #else GtkStyle *style = gtk_widget_get_style(w); if (style == NULL) return; if (!gdk_color_equal(&style->base[GTK_STATE_SELECTED], &style->base[GTK_STATE_ACTIVE])) gtk_widget_modify_base(w, GTK_STATE_ACTIVE, &style->base[GTK_STATE_SELECTED]); style = gtk_widget_get_style(w); if (style == NULL) return; if (!gdk_color_equal(&style->text[GTK_STATE_SELECTED], &style->text[GTK_STATE_ACTIVE])) gtk_widget_modify_text(w, GTK_STATE_ACTIVE, &style->text[GTK_STATE_SELECTED]); #endif } void ListBoxX::Create(Window &, int, Point, int, bool, int) { wid = gtk_window_new(GTK_WINDOW_POPUP); GtkWidget *frame = gtk_frame_new(NULL); gtk_widget_show(frame); gtk_container_add(GTK_CONTAINER(GetID()), frame); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); gtk_container_set_border_width(GTK_CONTAINER(frame), 0); scroller = gtk_scrolled_window_new(NULL, NULL); gtk_container_set_border_width(GTK_CONTAINER(scroller), 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(frame), PWidget(scroller)); gtk_widget_show(PWidget(scroller)); /* Tree and its model */ GtkListStore *store = gtk_list_store_new(N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING); list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_signal_connect(G_OBJECT(list), "style-set", G_CALLBACK(StyleSet), NULL); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE); gtk_tree_view_set_reorderable(GTK_TREE_VIEW(list), FALSE); /* Columns */ GtkTreeViewColumn *column = gtk_tree_view_column_new(); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_title(column, "Autocomplete"); pixbuf_renderer = gtk_cell_renderer_pixbuf_new(); gtk_cell_renderer_set_fixed_size(pixbuf_renderer, 0, -1); gtk_tree_view_column_pack_start(column, pixbuf_renderer, FALSE); gtk_tree_view_column_add_attribute(column, pixbuf_renderer, "pixbuf", PIXBUF_COLUMN); GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", TEXT_COLUMN); gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); if (g_object_class_find_property(G_OBJECT_GET_CLASS(list), "fixed-height-mode")) g_object_set(G_OBJECT(list), "fixed-height-mode", TRUE, NULL); GtkWidget *wid = PWidget(list); // No code inside the G_OBJECT macro gtk_container_add(GTK_CONTAINER(PWidget(scroller)), wid); gtk_widget_show(wid); g_signal_connect(G_OBJECT(wid), "button_press_event", G_CALLBACK(ButtonPress), this); gtk_widget_realize(PWidget(wid)); } void ListBoxX::SetFont(Font &scint_font) { // Only do for Pango font as there have been crashes for GDK fonts if (Created() && PFont(scint_font)->pfd) { // Current font is Pango font #if GTK_CHECK_VERSION(3,0,0) gtk_widget_override_font(PWidget(list), PFont(scint_font)->pfd); #else gtk_widget_modify_font(PWidget(list), PFont(scint_font)->pfd); #endif } } void ListBoxX::SetAverageCharWidth(int width) { aveCharWidth = width; } void ListBoxX::SetVisibleRows(int rows) { desiredVisibleRows = rows; } int ListBoxX::GetVisibleRows() const { return desiredVisibleRows; } PRectangle ListBoxX::GetDesiredRect() { // Before any size allocated pretend its 100 wide so not scrolled PRectangle rc(0, 0, 100, 100); if (wid) { int rows = Length(); if ((rows == 0) || (rows > desiredVisibleRows)) rows = desiredVisibleRows; GtkRequisition req; #if GTK_CHECK_VERSION(3,0,0) // This, apparently unnecessary call, ensures gtk_tree_view_column_cell_get_size // returns reasonable values. gtk_widget_get_preferred_size(GTK_WIDGET(scroller), NULL, &req); #endif int height; // First calculate height of the clist for our desired visible // row count otherwise it tries to expand to the total # of rows // Get cell height int row_width=0; int row_height=0; GtkTreeViewColumn * column = gtk_tree_view_get_column(GTK_TREE_VIEW(list), 0); gtk_tree_view_column_cell_get_size(column, NULL, NULL, NULL, &row_width, &row_height); #if GTK_CHECK_VERSION(3,0,0) GtkStyleContext *styleContextList = gtk_widget_get_style_context(PWidget(list)); GtkBorder padding; gtk_style_context_get_padding(styleContextList, GTK_STATE_FLAG_NORMAL, &padding); height = (rows * row_height + padding.top + padding.bottom + 2 * (gtk_container_get_border_width(GTK_CONTAINER(PWidget(list))) + 1)); #else int ythickness = PWidget(list)->style->ythickness; height = (rows * row_height + 2 * (ythickness + GTK_CONTAINER(PWidget(list))->border_width + 1)); #endif gtk_widget_set_size_request(GTK_WIDGET(PWidget(list)), -1, height); // Get the size of the scroller because we set usize on the window #if GTK_CHECK_VERSION(3,0,0) gtk_widget_get_preferred_size(GTK_WIDGET(scroller), NULL, &req); #else gtk_widget_size_request(GTK_WIDGET(scroller), &req); #endif rc.right = req.width; rc.bottom = Platform::Maximum(height, req.height); gtk_widget_set_size_request(GTK_WIDGET(list), -1, -1); int width = maxItemCharacters; if (width < 12) width = 12; rc.right = width * (aveCharWidth + aveCharWidth / 3); if (Length() > rows) rc.right = rc.right + 16; } return rc; } int ListBoxX::CaretFromEdge() { gint renderer_width, renderer_height; gtk_cell_renderer_get_fixed_size(pixbuf_renderer, &renderer_width, &renderer_height); return 4 + renderer_width; } void ListBoxX::Clear() { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list)); gtk_list_store_clear(GTK_LIST_STORE(model)); maxItemCharacters = 0; } static void init_pixmap(ListImage *list_image) { if (list_image->rgba_data) { // Drop any existing pixmap/bitmap as data may have changed if (list_image->pixbuf) g_object_unref(list_image->pixbuf); list_image->pixbuf = gdk_pixbuf_new_from_data(list_image->rgba_data->Pixels(), GDK_COLORSPACE_RGB, TRUE, 8, list_image->rgba_data->GetWidth(), list_image->rgba_data->GetHeight(), list_image->rgba_data->GetWidth() * 4, NULL, NULL); } } #define SPACING 5 void ListBoxX::Append(char *s, int type) { ListImage *list_image = NULL; if ((type >= 0) && pixhash) { list_image = static_cast(g_hash_table_lookup((GHashTable *) pixhash , (gconstpointer) GINT_TO_POINTER(type))); } GtkTreeIter iter; GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list))); gtk_list_store_append(GTK_LIST_STORE(store), &iter); if (list_image) { if (NULL == list_image->pixbuf) init_pixmap(list_image); if (list_image->pixbuf) { gtk_list_store_set(GTK_LIST_STORE(store), &iter, PIXBUF_COLUMN, list_image->pixbuf, TEXT_COLUMN, s, -1); gint pixbuf_width = gdk_pixbuf_get_width(list_image->pixbuf); gint renderer_height, renderer_width; gtk_cell_renderer_get_fixed_size(pixbuf_renderer, &renderer_width, &renderer_height); if (pixbuf_width > renderer_width) gtk_cell_renderer_set_fixed_size(pixbuf_renderer, pixbuf_width, -1); } else { gtk_list_store_set(GTK_LIST_STORE(store), &iter, TEXT_COLUMN, s, -1); } } else { gtk_list_store_set(GTK_LIST_STORE(store), &iter, TEXT_COLUMN, s, -1); } size_t len = strlen(s); if (maxItemCharacters < len) maxItemCharacters = len; } int ListBoxX::Length() { if (wid) return gtk_tree_model_iter_n_children(gtk_tree_view_get_model (GTK_TREE_VIEW(list)), NULL); return 0; } void ListBoxX::Select(int n) { GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list)); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); if (n < 0) { gtk_tree_selection_unselect_all(selection); return; } bool valid = gtk_tree_model_iter_nth_child(model, &iter, NULL, n) != FALSE; if (valid) { gtk_tree_selection_select_iter(selection, &iter); // Move the scrollbar to show the selection. int total = Length(); #if GTK_CHECK_VERSION(3,0,0) GtkAdjustment *adj = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(list)); gfloat value = ((gfloat)n / total) * (gtk_adjustment_get_upper(adj) - gtk_adjustment_get_lower(adj)) + gtk_adjustment_get_lower(adj) - gtk_adjustment_get_page_size(adj) / 2; #else GtkAdjustment *adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(list)); gfloat value = ((gfloat)n / total) * (adj->upper - adj->lower) + adj->lower - adj->page_size / 2; #endif // Get cell height int row_width; int row_height; GtkTreeViewColumn * column = gtk_tree_view_get_column(GTK_TREE_VIEW(list), 0); gtk_tree_view_column_cell_get_size(column, NULL, NULL, NULL, &row_width, &row_height); int rows = Length(); if ((rows == 0) || (rows > desiredVisibleRows)) rows = desiredVisibleRows; if (rows & 0x1) { // Odd rows to display -- We are now in the middle. // Align it so that we don't chop off rows. value += (gfloat)row_height / 2.0; } // Clamp it. value = (value < 0)? 0 : value; #if GTK_CHECK_VERSION(3,0,0) value = (value > (gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj)))? (gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj)) : value; #else value = (value > (adj->upper - adj->page_size))? (adj->upper - adj->page_size) : value; #endif // Set it. gtk_adjustment_set_value(adj, value); } else { gtk_tree_selection_unselect_all(selection); } } int ListBoxX::GetSelection() { GtkTreeIter iter; GtkTreeModel *model; GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { GtkTreePath *path = gtk_tree_model_get_path(model, &iter); int *indices = gtk_tree_path_get_indices(path); // Don't free indices. if (indices) return indices[0]; } return -1; } int ListBoxX::Find(const char *prefix) { GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list)); bool valid = gtk_tree_model_get_iter_first(model, &iter) != FALSE; int i = 0; while(valid) { gchar *s; gtk_tree_model_get(model, &iter, TEXT_COLUMN, &s, -1); if (s && (0 == strncmp(prefix, s, strlen(prefix)))) { g_free(s); return i; } g_free(s); valid = gtk_tree_model_iter_next(model, &iter) != FALSE; i++; } return -1; } void ListBoxX::GetValue(int n, char *value, int len) { char *text = NULL; GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list)); bool valid = gtk_tree_model_iter_nth_child(model, &iter, NULL, n) != FALSE; if (valid) { gtk_tree_model_get(model, &iter, TEXT_COLUMN, &text, -1); } if (text && len > 0) { strncpy(value, text, len); value[len - 1] = '\0'; } else { value[0] = '\0'; } g_free(text); } // g_return_if_fail causes unnecessary compiler warning in release compile. #ifdef _MSC_VER #pragma warning(disable: 4127) #endif void ListBoxX::RegisterRGBA(int type, RGBAImage *image) { images.Add(type, image); if (!pixhash) { pixhash = g_hash_table_new(g_direct_hash, g_direct_equal); } ListImage *list_image = static_cast(g_hash_table_lookup((GHashTable *) pixhash, (gconstpointer) GINT_TO_POINTER(type))); if (list_image) { // Drop icon already registered if (list_image->pixbuf) g_object_unref(list_image->pixbuf); list_image->pixbuf = NULL; list_image->rgba_data = image; } else { list_image = g_new0(ListImage, 1); list_image->rgba_data = image; g_hash_table_insert((GHashTable *) pixhash, GINT_TO_POINTER(type), (gpointer) list_image); } } void ListBoxX::RegisterImage(int type, const char *xpm_data) { g_return_if_fail(xpm_data); XPM xpmImage(xpm_data); RegisterRGBA(type, new RGBAImage(xpmImage)); } void ListBoxX::RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) { RegisterRGBA(type, new RGBAImage(width, height, pixelsImage)); } void ListBoxX::ClearRegisteredImages() { images.Clear(); } void ListBoxX::SetList(const char *listText, char separator, char typesep) { Clear(); int count = strlen(listText) + 1; char *words = new char[count]; if (words) { memcpy(words, listText, count); char *startword = words; char *numword = NULL; int i = 0; for (; words[i]; i++) { if (words[i] == separator) { words[i] = '\0'; if (numword) *numword = '\0'; Append(startword, numword?atoi(numword + 1):-1); startword = words + i + 1; numword = NULL; } else if (words[i] == typesep) { numword = words + i; } } if (startword) { if (numword) *numword = '\0'; Append(startword, numword?atoi(numword + 1):-1); } delete []words; } } Menu::Menu() : mid(0) {} void Menu::CreatePopUp() { Destroy(); mid = gtk_menu_new(); #if GLIB_CHECK_VERSION(2,10,0) g_object_ref_sink(G_OBJECT(mid)); #else g_object_ref(G_OBJECT(mid)); gtk_object_sink(GTK_OBJECT(G_OBJECT(mid))); #endif } void Menu::Destroy() { if (mid) g_object_unref(G_OBJECT(mid)); mid = 0; } static void MenuPositionFunc(GtkMenu *, gint *x, gint *y, gboolean *, gpointer userData) { sptr_t intFromPointer = reinterpret_cast(userData); *x = intFromPointer & 0xffff; *y = intFromPointer >> 16; } void Menu::Show(Point pt, Window &) { int screenHeight = gdk_screen_height(); int screenWidth = gdk_screen_width(); GtkMenu *widget = reinterpret_cast(mid); gtk_widget_show_all(GTK_WIDGET(widget)); GtkRequisition requisition; #if GTK_CHECK_VERSION(3,0,0) gtk_widget_get_preferred_size(GTK_WIDGET(widget), NULL, &requisition); #else gtk_widget_size_request(GTK_WIDGET(widget), &requisition); #endif if ((pt.x + requisition.width) > screenWidth) { pt.x = screenWidth - requisition.width; } if ((pt.y + requisition.height) > screenHeight) { pt.y = screenHeight - requisition.height; } gtk_menu_popup(widget, NULL, NULL, MenuPositionFunc, reinterpret_cast((static_cast(pt.y) << 16) | static_cast(pt.x)), 0, gtk_get_current_event_time()); } ElapsedTime::ElapsedTime() { GTimeVal curTime; g_get_current_time(&curTime); bigBit = curTime.tv_sec; littleBit = curTime.tv_usec; } class DynamicLibraryImpl : public DynamicLibrary { protected: GModule* m; public: DynamicLibraryImpl(const char *modulePath) { m = g_module_open(modulePath, G_MODULE_BIND_LAZY); } virtual ~DynamicLibraryImpl() { if (m != NULL) g_module_close(m); } // Use g_module_symbol to get a pointer to the relevant function. virtual Function FindFunction(const char *name) { if (m != NULL) { gpointer fn_address = NULL; gboolean status = g_module_symbol(m, name, &fn_address); if (status) return static_cast(fn_address); else return NULL; } else return NULL; } virtual bool IsValid() { return m != NULL; } }; DynamicLibrary *DynamicLibrary::Load(const char *modulePath) { return static_cast( new DynamicLibraryImpl(modulePath) ); } double ElapsedTime::Duration(bool reset) { GTimeVal curTime; g_get_current_time(&curTime); long endBigBit = curTime.tv_sec; long endLittleBit = curTime.tv_usec; double result = 1000000.0 * (endBigBit - bigBit); result += endLittleBit - littleBit; result /= 1000000.0; if (reset) { bigBit = endBigBit; littleBit = endLittleBit; } return result; } ColourDesired Platform::Chrome() { return ColourDesired(0xe0, 0xe0, 0xe0); } ColourDesired Platform::ChromeHighlight() { return ColourDesired(0xff, 0xff, 0xff); } const char *Platform::DefaultFont() { #ifdef G_OS_WIN32 return "Lucida Console"; #else return "!Sans"; #endif } int Platform::DefaultFontSize() { #ifdef G_OS_WIN32 return 10; #else return 12; #endif } unsigned int Platform::DoubleClickTime() { return 500; // Half a second } bool Platform::MouseButtonBounce() { return true; } void Platform::DebugDisplay(const char *s) { fprintf(stderr, "%s", s); } bool Platform::IsKeyDown(int) { // TODO: discover state of keys in GTK+/X return false; } long Platform::SendScintilla( WindowID w, unsigned int msg, unsigned long wParam, long lParam) { return scintilla_send_message(SCINTILLA(w), msg, wParam, lParam); } long Platform::SendScintillaPointer( WindowID w, unsigned int msg, unsigned long wParam, void *lParam) { return scintilla_send_message(SCINTILLA(w), msg, wParam, reinterpret_cast(lParam)); } bool Platform::IsDBCSLeadByte(int codePage, char ch) { // Byte ranges found in Wikipedia articles with relevant search strings in each case unsigned char uch = static_cast(ch); switch (codePage) { case 932: // Shift_jis return ((uch >= 0x81) && (uch <= 0x9F)) || ((uch >= 0xE0) && (uch <= 0xFC)); // Lead bytes F0 to FC may be a Microsoft addition. case 936: // GBK return (uch >= 0x81) && (uch <= 0xFE); case 950: // Big5 return (uch >= 0x81) && (uch <= 0xFE); // Korean EUC-KR may be code page 949. } return false; } int Platform::DBCSCharLength(int codePage, const char *s) { if (codePage == 932 || codePage == 936 || codePage == 950) { return IsDBCSLeadByte(codePage, s[0]) ? 2 : 1; } else { int bytes = mblen(s, MB_CUR_MAX); if (bytes >= 1) return bytes; else return 1; } } int Platform::DBCSCharMaxLength() { return MB_CUR_MAX; //return 2; } // These are utility functions not really tied to a platform int Platform::Minimum(int a, int b) { if (a < b) return a; else return b; } int Platform::Maximum(int a, int b) { if (a > b) return a; else return b; } //#define TRACE #ifdef TRACE void Platform::DebugPrintf(const char *format, ...) { char buffer[2000]; va_list pArguments; va_start(pArguments, format); vsprintf(buffer, format, pArguments); va_end(pArguments); Platform::DebugDisplay(buffer); } #else void Platform::DebugPrintf(const char *, ...) {} #endif // Not supported for GTK+ static bool assertionPopUps = true; bool Platform::ShowAssertionPopUps(bool assertionPopUps_) { bool ret = assertionPopUps; assertionPopUps = assertionPopUps_; return ret; } void Platform::Assert(const char *c, const char *file, int line) { char buffer[2000]; sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line); strcat(buffer, "\r\n"); Platform::DebugDisplay(buffer); abort(); } int Platform::Clamp(int val, int minVal, int maxVal) { if (val > maxVal) val = maxVal; if (val < minVal) val = minVal; return val; } void Platform_Initialise() { FontMutexAllocate(); } void Platform_Finalise() { FontMutexFree(); } presage-0.8.8/apps/gtk/gprompter/scintilla/version.txt0000644000175000017500000000000411763437013020054 00000000000000320 presage-0.8.8/apps/gtk/gprompter/scintilla/include/0000755000175000017500000000000011764714757017355 500000000000000presage-0.8.8/apps/gtk/gprompter/scintilla/include/SciLexer.h0000644000175000017500000013124311763437013021152 00000000000000/* Scintilla source code edit control */ /** @file SciLexer.h ** Interface to the added lexer functions in the SciLexer version of the edit control. **/ /* Copyright 1998-2002 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ /* Most of this file is automatically generated from the Scintilla.iface interface definition * file which contains any comments about the definitions. HFacer.py does the generation. */ #ifndef SCILEXER_H #define SCILEXER_H /* SciLexer features - not in standard Scintilla */ /* ++Autogenerated -- start of section automatically generated from Scintilla.iface */ #define SCLEX_CONTAINER 0 #define SCLEX_NULL 1 #define SCLEX_PYTHON 2 #define SCLEX_CPP 3 #define SCLEX_HTML 4 #define SCLEX_XML 5 #define SCLEX_PERL 6 #define SCLEX_SQL 7 #define SCLEX_VB 8 #define SCLEX_PROPERTIES 9 #define SCLEX_ERRORLIST 10 #define SCLEX_MAKEFILE 11 #define SCLEX_BATCH 12 #define SCLEX_XCODE 13 #define SCLEX_LATEX 14 #define SCLEX_LUA 15 #define SCLEX_DIFF 16 #define SCLEX_CONF 17 #define SCLEX_PASCAL 18 #define SCLEX_AVE 19 #define SCLEX_ADA 20 #define SCLEX_LISP 21 #define SCLEX_RUBY 22 #define SCLEX_EIFFEL 23 #define SCLEX_EIFFELKW 24 #define SCLEX_TCL 25 #define SCLEX_NNCRONTAB 26 #define SCLEX_BULLANT 27 #define SCLEX_VBSCRIPT 28 #define SCLEX_BAAN 31 #define SCLEX_MATLAB 32 #define SCLEX_SCRIPTOL 33 #define SCLEX_ASM 34 #define SCLEX_CPPNOCASE 35 #define SCLEX_FORTRAN 36 #define SCLEX_F77 37 #define SCLEX_CSS 38 #define SCLEX_POV 39 #define SCLEX_LOUT 40 #define SCLEX_ESCRIPT 41 #define SCLEX_PS 42 #define SCLEX_NSIS 43 #define SCLEX_MMIXAL 44 #define SCLEX_CLW 45 #define SCLEX_CLWNOCASE 46 #define SCLEX_LOT 47 #define SCLEX_YAML 48 #define SCLEX_TEX 49 #define SCLEX_METAPOST 50 #define SCLEX_POWERBASIC 51 #define SCLEX_FORTH 52 #define SCLEX_ERLANG 53 #define SCLEX_OCTAVE 54 #define SCLEX_MSSQL 55 #define SCLEX_VERILOG 56 #define SCLEX_KIX 57 #define SCLEX_GUI4CLI 58 #define SCLEX_SPECMAN 59 #define SCLEX_AU3 60 #define SCLEX_APDL 61 #define SCLEX_BASH 62 #define SCLEX_ASN1 63 #define SCLEX_VHDL 64 #define SCLEX_CAML 65 #define SCLEX_BLITZBASIC 66 #define SCLEX_PUREBASIC 67 #define SCLEX_HASKELL 68 #define SCLEX_PHPSCRIPT 69 #define SCLEX_TADS3 70 #define SCLEX_REBOL 71 #define SCLEX_SMALLTALK 72 #define SCLEX_FLAGSHIP 73 #define SCLEX_CSOUND 74 #define SCLEX_FREEBASIC 75 #define SCLEX_INNOSETUP 76 #define SCLEX_OPAL 77 #define SCLEX_SPICE 78 #define SCLEX_D 79 #define SCLEX_CMAKE 80 #define SCLEX_GAP 81 #define SCLEX_PLM 82 #define SCLEX_PROGRESS 83 #define SCLEX_ABAQUS 84 #define SCLEX_ASYMPTOTE 85 #define SCLEX_R 86 #define SCLEX_MAGIK 87 #define SCLEX_POWERSHELL 88 #define SCLEX_MYSQL 89 #define SCLEX_PO 90 #define SCLEX_TAL 91 #define SCLEX_COBOL 92 #define SCLEX_TACL 93 #define SCLEX_SORCUS 94 #define SCLEX_POWERPRO 95 #define SCLEX_NIMROD 96 #define SCLEX_SML 97 #define SCLEX_MARKDOWN 98 #define SCLEX_TXT2TAGS 99 #define SCLEX_A68K 100 #define SCLEX_MODULA 101 #define SCLEX_COFFEESCRIPT 102 #define SCLEX_TCMD 103 #define SCLEX_AVS 104 #define SCLEX_ECL 105 #define SCLEX_OSCRIPT 106 #define SCLEX_VISUALPROLOG 107 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 #define SCE_P_NUMBER 2 #define SCE_P_STRING 3 #define SCE_P_CHARACTER 4 #define SCE_P_WORD 5 #define SCE_P_TRIPLE 6 #define SCE_P_TRIPLEDOUBLE 7 #define SCE_P_CLASSNAME 8 #define SCE_P_DEFNAME 9 #define SCE_P_OPERATOR 10 #define SCE_P_IDENTIFIER 11 #define SCE_P_COMMENTBLOCK 12 #define SCE_P_STRINGEOL 13 #define SCE_P_WORD2 14 #define SCE_P_DECORATOR 15 #define SCE_C_DEFAULT 0 #define SCE_C_COMMENT 1 #define SCE_C_COMMENTLINE 2 #define SCE_C_COMMENTDOC 3 #define SCE_C_NUMBER 4 #define SCE_C_WORD 5 #define SCE_C_STRING 6 #define SCE_C_CHARACTER 7 #define SCE_C_UUID 8 #define SCE_C_PREPROCESSOR 9 #define SCE_C_OPERATOR 10 #define SCE_C_IDENTIFIER 11 #define SCE_C_STRINGEOL 12 #define SCE_C_VERBATIM 13 #define SCE_C_REGEX 14 #define SCE_C_COMMENTLINEDOC 15 #define SCE_C_WORD2 16 #define SCE_C_COMMENTDOCKEYWORD 17 #define SCE_C_COMMENTDOCKEYWORDERROR 18 #define SCE_C_GLOBALCLASS 19 #define SCE_C_STRINGRAW 20 #define SCE_C_TRIPLEVERBATIM 21 #define SCE_C_HASHQUOTEDSTRING 22 #define SCE_D_DEFAULT 0 #define SCE_D_COMMENT 1 #define SCE_D_COMMENTLINE 2 #define SCE_D_COMMENTDOC 3 #define SCE_D_COMMENTNESTED 4 #define SCE_D_NUMBER 5 #define SCE_D_WORD 6 #define SCE_D_WORD2 7 #define SCE_D_WORD3 8 #define SCE_D_TYPEDEF 9 #define SCE_D_STRING 10 #define SCE_D_STRINGEOL 11 #define SCE_D_CHARACTER 12 #define SCE_D_OPERATOR 13 #define SCE_D_IDENTIFIER 14 #define SCE_D_COMMENTLINEDOC 15 #define SCE_D_COMMENTDOCKEYWORD 16 #define SCE_D_COMMENTDOCKEYWORDERROR 17 #define SCE_D_STRINGB 18 #define SCE_D_STRINGR 19 #define SCE_D_WORD5 20 #define SCE_D_WORD6 21 #define SCE_D_WORD7 22 #define SCE_TCL_DEFAULT 0 #define SCE_TCL_COMMENT 1 #define SCE_TCL_COMMENTLINE 2 #define SCE_TCL_NUMBER 3 #define SCE_TCL_WORD_IN_QUOTE 4 #define SCE_TCL_IN_QUOTE 5 #define SCE_TCL_OPERATOR 6 #define SCE_TCL_IDENTIFIER 7 #define SCE_TCL_SUBSTITUTION 8 #define SCE_TCL_SUB_BRACE 9 #define SCE_TCL_MODIFIER 10 #define SCE_TCL_EXPAND 11 #define SCE_TCL_WORD 12 #define SCE_TCL_WORD2 13 #define SCE_TCL_WORD3 14 #define SCE_TCL_WORD4 15 #define SCE_TCL_WORD5 16 #define SCE_TCL_WORD6 17 #define SCE_TCL_WORD7 18 #define SCE_TCL_WORD8 19 #define SCE_TCL_COMMENT_BOX 20 #define SCE_TCL_BLOCK_COMMENT 21 #define SCE_H_DEFAULT 0 #define SCE_H_TAG 1 #define SCE_H_TAGUNKNOWN 2 #define SCE_H_ATTRIBUTE 3 #define SCE_H_ATTRIBUTEUNKNOWN 4 #define SCE_H_NUMBER 5 #define SCE_H_DOUBLESTRING 6 #define SCE_H_SINGLESTRING 7 #define SCE_H_OTHER 8 #define SCE_H_COMMENT 9 #define SCE_H_ENTITY 10 #define SCE_H_TAGEND 11 #define SCE_H_XMLSTART 12 #define SCE_H_XMLEND 13 #define SCE_H_SCRIPT 14 #define SCE_H_ASP 15 #define SCE_H_ASPAT 16 #define SCE_H_CDATA 17 #define SCE_H_QUESTION 18 #define SCE_H_VALUE 19 #define SCE_H_XCCOMMENT 20 #define SCE_H_SGML_DEFAULT 21 #define SCE_H_SGML_COMMAND 22 #define SCE_H_SGML_1ST_PARAM 23 #define SCE_H_SGML_DOUBLESTRING 24 #define SCE_H_SGML_SIMPLESTRING 25 #define SCE_H_SGML_ERROR 26 #define SCE_H_SGML_SPECIAL 27 #define SCE_H_SGML_ENTITY 28 #define SCE_H_SGML_COMMENT 29 #define SCE_H_SGML_1ST_PARAM_COMMENT 30 #define SCE_H_SGML_BLOCK_DEFAULT 31 #define SCE_HJ_START 40 #define SCE_HJ_DEFAULT 41 #define SCE_HJ_COMMENT 42 #define SCE_HJ_COMMENTLINE 43 #define SCE_HJ_COMMENTDOC 44 #define SCE_HJ_NUMBER 45 #define SCE_HJ_WORD 46 #define SCE_HJ_KEYWORD 47 #define SCE_HJ_DOUBLESTRING 48 #define SCE_HJ_SINGLESTRING 49 #define SCE_HJ_SYMBOLS 50 #define SCE_HJ_STRINGEOL 51 #define SCE_HJ_REGEX 52 #define SCE_HJA_START 55 #define SCE_HJA_DEFAULT 56 #define SCE_HJA_COMMENT 57 #define SCE_HJA_COMMENTLINE 58 #define SCE_HJA_COMMENTDOC 59 #define SCE_HJA_NUMBER 60 #define SCE_HJA_WORD 61 #define SCE_HJA_KEYWORD 62 #define SCE_HJA_DOUBLESTRING 63 #define SCE_HJA_SINGLESTRING 64 #define SCE_HJA_SYMBOLS 65 #define SCE_HJA_STRINGEOL 66 #define SCE_HJA_REGEX 67 #define SCE_HB_START 70 #define SCE_HB_DEFAULT 71 #define SCE_HB_COMMENTLINE 72 #define SCE_HB_NUMBER 73 #define SCE_HB_WORD 74 #define SCE_HB_STRING 75 #define SCE_HB_IDENTIFIER 76 #define SCE_HB_STRINGEOL 77 #define SCE_HBA_START 80 #define SCE_HBA_DEFAULT 81 #define SCE_HBA_COMMENTLINE 82 #define SCE_HBA_NUMBER 83 #define SCE_HBA_WORD 84 #define SCE_HBA_STRING 85 #define SCE_HBA_IDENTIFIER 86 #define SCE_HBA_STRINGEOL 87 #define SCE_HP_START 90 #define SCE_HP_DEFAULT 91 #define SCE_HP_COMMENTLINE 92 #define SCE_HP_NUMBER 93 #define SCE_HP_STRING 94 #define SCE_HP_CHARACTER 95 #define SCE_HP_WORD 96 #define SCE_HP_TRIPLE 97 #define SCE_HP_TRIPLEDOUBLE 98 #define SCE_HP_CLASSNAME 99 #define SCE_HP_DEFNAME 100 #define SCE_HP_OPERATOR 101 #define SCE_HP_IDENTIFIER 102 #define SCE_HPHP_COMPLEX_VARIABLE 104 #define SCE_HPA_START 105 #define SCE_HPA_DEFAULT 106 #define SCE_HPA_COMMENTLINE 107 #define SCE_HPA_NUMBER 108 #define SCE_HPA_STRING 109 #define SCE_HPA_CHARACTER 110 #define SCE_HPA_WORD 111 #define SCE_HPA_TRIPLE 112 #define SCE_HPA_TRIPLEDOUBLE 113 #define SCE_HPA_CLASSNAME 114 #define SCE_HPA_DEFNAME 115 #define SCE_HPA_OPERATOR 116 #define SCE_HPA_IDENTIFIER 117 #define SCE_HPHP_DEFAULT 118 #define SCE_HPHP_HSTRING 119 #define SCE_HPHP_SIMPLESTRING 120 #define SCE_HPHP_WORD 121 #define SCE_HPHP_NUMBER 122 #define SCE_HPHP_VARIABLE 123 #define SCE_HPHP_COMMENT 124 #define SCE_HPHP_COMMENTLINE 125 #define SCE_HPHP_HSTRING_VARIABLE 126 #define SCE_HPHP_OPERATOR 127 #define SCE_PL_DEFAULT 0 #define SCE_PL_ERROR 1 #define SCE_PL_COMMENTLINE 2 #define SCE_PL_POD 3 #define SCE_PL_NUMBER 4 #define SCE_PL_WORD 5 #define SCE_PL_STRING 6 #define SCE_PL_CHARACTER 7 #define SCE_PL_PUNCTUATION 8 #define SCE_PL_PREPROCESSOR 9 #define SCE_PL_OPERATOR 10 #define SCE_PL_IDENTIFIER 11 #define SCE_PL_SCALAR 12 #define SCE_PL_ARRAY 13 #define SCE_PL_HASH 14 #define SCE_PL_SYMBOLTABLE 15 #define SCE_PL_VARIABLE_INDEXER 16 #define SCE_PL_REGEX 17 #define SCE_PL_REGSUBST 18 #define SCE_PL_LONGQUOTE 19 #define SCE_PL_BACKTICKS 20 #define SCE_PL_DATASECTION 21 #define SCE_PL_HERE_DELIM 22 #define SCE_PL_HERE_Q 23 #define SCE_PL_HERE_QQ 24 #define SCE_PL_HERE_QX 25 #define SCE_PL_STRING_Q 26 #define SCE_PL_STRING_QQ 27 #define SCE_PL_STRING_QX 28 #define SCE_PL_STRING_QR 29 #define SCE_PL_STRING_QW 30 #define SCE_PL_POD_VERB 31 #define SCE_PL_SUB_PROTOTYPE 40 #define SCE_PL_FORMAT_IDENT 41 #define SCE_PL_FORMAT 42 #define SCE_PL_STRING_VAR 43 #define SCE_PL_XLAT 44 #define SCE_PL_REGEX_VAR 54 #define SCE_PL_REGSUBST_VAR 55 #define SCE_PL_BACKTICKS_VAR 57 #define SCE_PL_HERE_QQ_VAR 61 #define SCE_PL_HERE_QX_VAR 62 #define SCE_PL_STRING_QQ_VAR 64 #define SCE_PL_STRING_QX_VAR 65 #define SCE_PL_STRING_QR_VAR 66 #define SCE_RB_DEFAULT 0 #define SCE_RB_ERROR 1 #define SCE_RB_COMMENTLINE 2 #define SCE_RB_POD 3 #define SCE_RB_NUMBER 4 #define SCE_RB_WORD 5 #define SCE_RB_STRING 6 #define SCE_RB_CHARACTER 7 #define SCE_RB_CLASSNAME 8 #define SCE_RB_DEFNAME 9 #define SCE_RB_OPERATOR 10 #define SCE_RB_IDENTIFIER 11 #define SCE_RB_REGEX 12 #define SCE_RB_GLOBAL 13 #define SCE_RB_SYMBOL 14 #define SCE_RB_MODULE_NAME 15 #define SCE_RB_INSTANCE_VAR 16 #define SCE_RB_CLASS_VAR 17 #define SCE_RB_BACKTICKS 18 #define SCE_RB_DATASECTION 19 #define SCE_RB_HERE_DELIM 20 #define SCE_RB_HERE_Q 21 #define SCE_RB_HERE_QQ 22 #define SCE_RB_HERE_QX 23 #define SCE_RB_STRING_Q 24 #define SCE_RB_STRING_QQ 25 #define SCE_RB_STRING_QX 26 #define SCE_RB_STRING_QR 27 #define SCE_RB_STRING_QW 28 #define SCE_RB_WORD_DEMOTED 29 #define SCE_RB_STDIN 30 #define SCE_RB_STDOUT 31 #define SCE_RB_STDERR 40 #define SCE_RB_UPPER_BOUND 41 #define SCE_B_DEFAULT 0 #define SCE_B_COMMENT 1 #define SCE_B_NUMBER 2 #define SCE_B_KEYWORD 3 #define SCE_B_STRING 4 #define SCE_B_PREPROCESSOR 5 #define SCE_B_OPERATOR 6 #define SCE_B_IDENTIFIER 7 #define SCE_B_DATE 8 #define SCE_B_STRINGEOL 9 #define SCE_B_KEYWORD2 10 #define SCE_B_KEYWORD3 11 #define SCE_B_KEYWORD4 12 #define SCE_B_CONSTANT 13 #define SCE_B_ASM 14 #define SCE_B_LABEL 15 #define SCE_B_ERROR 16 #define SCE_B_HEXNUMBER 17 #define SCE_B_BINNUMBER 18 #define SCE_PROPS_DEFAULT 0 #define SCE_PROPS_COMMENT 1 #define SCE_PROPS_SECTION 2 #define SCE_PROPS_ASSIGNMENT 3 #define SCE_PROPS_DEFVAL 4 #define SCE_PROPS_KEY 5 #define SCE_L_DEFAULT 0 #define SCE_L_COMMAND 1 #define SCE_L_TAG 2 #define SCE_L_MATH 3 #define SCE_L_COMMENT 4 #define SCE_L_TAG2 5 #define SCE_L_MATH2 6 #define SCE_L_COMMENT2 7 #define SCE_L_VERBATIM 8 #define SCE_L_SHORTCMD 9 #define SCE_L_SPECIAL 10 #define SCE_L_CMDOPT 11 #define SCE_L_ERROR 12 #define SCE_LUA_DEFAULT 0 #define SCE_LUA_COMMENT 1 #define SCE_LUA_COMMENTLINE 2 #define SCE_LUA_COMMENTDOC 3 #define SCE_LUA_NUMBER 4 #define SCE_LUA_WORD 5 #define SCE_LUA_STRING 6 #define SCE_LUA_CHARACTER 7 #define SCE_LUA_LITERALSTRING 8 #define SCE_LUA_PREPROCESSOR 9 #define SCE_LUA_OPERATOR 10 #define SCE_LUA_IDENTIFIER 11 #define SCE_LUA_STRINGEOL 12 #define SCE_LUA_WORD2 13 #define SCE_LUA_WORD3 14 #define SCE_LUA_WORD4 15 #define SCE_LUA_WORD5 16 #define SCE_LUA_WORD6 17 #define SCE_LUA_WORD7 18 #define SCE_LUA_WORD8 19 #define SCE_LUA_LABEL 20 #define SCE_ERR_DEFAULT 0 #define SCE_ERR_PYTHON 1 #define SCE_ERR_GCC 2 #define SCE_ERR_MS 3 #define SCE_ERR_CMD 4 #define SCE_ERR_BORLAND 5 #define SCE_ERR_PERL 6 #define SCE_ERR_NET 7 #define SCE_ERR_LUA 8 #define SCE_ERR_CTAG 9 #define SCE_ERR_DIFF_CHANGED 10 #define SCE_ERR_DIFF_ADDITION 11 #define SCE_ERR_DIFF_DELETION 12 #define SCE_ERR_DIFF_MESSAGE 13 #define SCE_ERR_PHP 14 #define SCE_ERR_ELF 15 #define SCE_ERR_IFC 16 #define SCE_ERR_IFORT 17 #define SCE_ERR_ABSF 18 #define SCE_ERR_TIDY 19 #define SCE_ERR_JAVA_STACK 20 #define SCE_ERR_VALUE 21 #define SCE_BAT_DEFAULT 0 #define SCE_BAT_COMMENT 1 #define SCE_BAT_WORD 2 #define SCE_BAT_LABEL 3 #define SCE_BAT_HIDE 4 #define SCE_BAT_COMMAND 5 #define SCE_BAT_IDENTIFIER 6 #define SCE_BAT_OPERATOR 7 #define SCE_TCMD_DEFAULT 0 #define SCE_TCMD_COMMENT 1 #define SCE_TCMD_WORD 2 #define SCE_TCMD_LABEL 3 #define SCE_TCMD_HIDE 4 #define SCE_TCMD_COMMAND 5 #define SCE_TCMD_IDENTIFIER 6 #define SCE_TCMD_OPERATOR 7 #define SCE_TCMD_ENVIRONMENT 8 #define SCE_TCMD_EXPANSION 9 #define SCE_TCMD_CLABEL 10 #define SCE_MAKE_DEFAULT 0 #define SCE_MAKE_COMMENT 1 #define SCE_MAKE_PREPROCESSOR 2 #define SCE_MAKE_IDENTIFIER 3 #define SCE_MAKE_OPERATOR 4 #define SCE_MAKE_TARGET 5 #define SCE_MAKE_IDEOL 9 #define SCE_DIFF_DEFAULT 0 #define SCE_DIFF_COMMENT 1 #define SCE_DIFF_COMMAND 2 #define SCE_DIFF_HEADER 3 #define SCE_DIFF_POSITION 4 #define SCE_DIFF_DELETED 5 #define SCE_DIFF_ADDED 6 #define SCE_DIFF_CHANGED 7 #define SCE_CONF_DEFAULT 0 #define SCE_CONF_COMMENT 1 #define SCE_CONF_NUMBER 2 #define SCE_CONF_IDENTIFIER 3 #define SCE_CONF_EXTENSION 4 #define SCE_CONF_PARAMETER 5 #define SCE_CONF_STRING 6 #define SCE_CONF_OPERATOR 7 #define SCE_CONF_IP 8 #define SCE_CONF_DIRECTIVE 9 #define SCE_AVE_DEFAULT 0 #define SCE_AVE_COMMENT 1 #define SCE_AVE_NUMBER 2 #define SCE_AVE_WORD 3 #define SCE_AVE_STRING 6 #define SCE_AVE_ENUM 7 #define SCE_AVE_STRINGEOL 8 #define SCE_AVE_IDENTIFIER 9 #define SCE_AVE_OPERATOR 10 #define SCE_AVE_WORD1 11 #define SCE_AVE_WORD2 12 #define SCE_AVE_WORD3 13 #define SCE_AVE_WORD4 14 #define SCE_AVE_WORD5 15 #define SCE_AVE_WORD6 16 #define SCE_ADA_DEFAULT 0 #define SCE_ADA_WORD 1 #define SCE_ADA_IDENTIFIER 2 #define SCE_ADA_NUMBER 3 #define SCE_ADA_DELIMITER 4 #define SCE_ADA_CHARACTER 5 #define SCE_ADA_CHARACTEREOL 6 #define SCE_ADA_STRING 7 #define SCE_ADA_STRINGEOL 8 #define SCE_ADA_LABEL 9 #define SCE_ADA_COMMENTLINE 10 #define SCE_ADA_ILLEGAL 11 #define SCE_BAAN_DEFAULT 0 #define SCE_BAAN_COMMENT 1 #define SCE_BAAN_COMMENTDOC 2 #define SCE_BAAN_NUMBER 3 #define SCE_BAAN_WORD 4 #define SCE_BAAN_STRING 5 #define SCE_BAAN_PREPROCESSOR 6 #define SCE_BAAN_OPERATOR 7 #define SCE_BAAN_IDENTIFIER 8 #define SCE_BAAN_STRINGEOL 9 #define SCE_BAAN_WORD2 10 #define SCE_LISP_DEFAULT 0 #define SCE_LISP_COMMENT 1 #define SCE_LISP_NUMBER 2 #define SCE_LISP_KEYWORD 3 #define SCE_LISP_KEYWORD_KW 4 #define SCE_LISP_SYMBOL 5 #define SCE_LISP_STRING 6 #define SCE_LISP_STRINGEOL 8 #define SCE_LISP_IDENTIFIER 9 #define SCE_LISP_OPERATOR 10 #define SCE_LISP_SPECIAL 11 #define SCE_LISP_MULTI_COMMENT 12 #define SCE_EIFFEL_DEFAULT 0 #define SCE_EIFFEL_COMMENTLINE 1 #define SCE_EIFFEL_NUMBER 2 #define SCE_EIFFEL_WORD 3 #define SCE_EIFFEL_STRING 4 #define SCE_EIFFEL_CHARACTER 5 #define SCE_EIFFEL_OPERATOR 6 #define SCE_EIFFEL_IDENTIFIER 7 #define SCE_EIFFEL_STRINGEOL 8 #define SCE_NNCRONTAB_DEFAULT 0 #define SCE_NNCRONTAB_COMMENT 1 #define SCE_NNCRONTAB_TASK 2 #define SCE_NNCRONTAB_SECTION 3 #define SCE_NNCRONTAB_KEYWORD 4 #define SCE_NNCRONTAB_MODIFIER 5 #define SCE_NNCRONTAB_ASTERISK 6 #define SCE_NNCRONTAB_NUMBER 7 #define SCE_NNCRONTAB_STRING 8 #define SCE_NNCRONTAB_ENVIRONMENT 9 #define SCE_NNCRONTAB_IDENTIFIER 10 #define SCE_FORTH_DEFAULT 0 #define SCE_FORTH_COMMENT 1 #define SCE_FORTH_COMMENT_ML 2 #define SCE_FORTH_IDENTIFIER 3 #define SCE_FORTH_CONTROL 4 #define SCE_FORTH_KEYWORD 5 #define SCE_FORTH_DEFWORD 6 #define SCE_FORTH_PREWORD1 7 #define SCE_FORTH_PREWORD2 8 #define SCE_FORTH_NUMBER 9 #define SCE_FORTH_STRING 10 #define SCE_FORTH_LOCALE 11 #define SCE_MATLAB_DEFAULT 0 #define SCE_MATLAB_COMMENT 1 #define SCE_MATLAB_COMMAND 2 #define SCE_MATLAB_NUMBER 3 #define SCE_MATLAB_KEYWORD 4 #define SCE_MATLAB_STRING 5 #define SCE_MATLAB_OPERATOR 6 #define SCE_MATLAB_IDENTIFIER 7 #define SCE_MATLAB_DOUBLEQUOTESTRING 8 #define SCE_SCRIPTOL_DEFAULT 0 #define SCE_SCRIPTOL_WHITE 1 #define SCE_SCRIPTOL_COMMENTLINE 2 #define SCE_SCRIPTOL_PERSISTENT 3 #define SCE_SCRIPTOL_CSTYLE 4 #define SCE_SCRIPTOL_COMMENTBLOCK 5 #define SCE_SCRIPTOL_NUMBER 6 #define SCE_SCRIPTOL_STRING 7 #define SCE_SCRIPTOL_CHARACTER 8 #define SCE_SCRIPTOL_STRINGEOL 9 #define SCE_SCRIPTOL_KEYWORD 10 #define SCE_SCRIPTOL_OPERATOR 11 #define SCE_SCRIPTOL_IDENTIFIER 12 #define SCE_SCRIPTOL_TRIPLE 13 #define SCE_SCRIPTOL_CLASSNAME 14 #define SCE_SCRIPTOL_PREPROCESSOR 15 #define SCE_ASM_DEFAULT 0 #define SCE_ASM_COMMENT 1 #define SCE_ASM_NUMBER 2 #define SCE_ASM_STRING 3 #define SCE_ASM_OPERATOR 4 #define SCE_ASM_IDENTIFIER 5 #define SCE_ASM_CPUINSTRUCTION 6 #define SCE_ASM_MATHINSTRUCTION 7 #define SCE_ASM_REGISTER 8 #define SCE_ASM_DIRECTIVE 9 #define SCE_ASM_DIRECTIVEOPERAND 10 #define SCE_ASM_COMMENTBLOCK 11 #define SCE_ASM_CHARACTER 12 #define SCE_ASM_STRINGEOL 13 #define SCE_ASM_EXTINSTRUCTION 14 #define SCE_ASM_COMMENTDIRECTIVE 15 #define SCE_F_DEFAULT 0 #define SCE_F_COMMENT 1 #define SCE_F_NUMBER 2 #define SCE_F_STRING1 3 #define SCE_F_STRING2 4 #define SCE_F_STRINGEOL 5 #define SCE_F_OPERATOR 6 #define SCE_F_IDENTIFIER 7 #define SCE_F_WORD 8 #define SCE_F_WORD2 9 #define SCE_F_WORD3 10 #define SCE_F_PREPROCESSOR 11 #define SCE_F_OPERATOR2 12 #define SCE_F_LABEL 13 #define SCE_F_CONTINUATION 14 #define SCE_CSS_DEFAULT 0 #define SCE_CSS_TAG 1 #define SCE_CSS_CLASS 2 #define SCE_CSS_PSEUDOCLASS 3 #define SCE_CSS_UNKNOWN_PSEUDOCLASS 4 #define SCE_CSS_OPERATOR 5 #define SCE_CSS_IDENTIFIER 6 #define SCE_CSS_UNKNOWN_IDENTIFIER 7 #define SCE_CSS_VALUE 8 #define SCE_CSS_COMMENT 9 #define SCE_CSS_ID 10 #define SCE_CSS_IMPORTANT 11 #define SCE_CSS_DIRECTIVE 12 #define SCE_CSS_DOUBLESTRING 13 #define SCE_CSS_SINGLESTRING 14 #define SCE_CSS_IDENTIFIER2 15 #define SCE_CSS_ATTRIBUTE 16 #define SCE_CSS_IDENTIFIER3 17 #define SCE_CSS_PSEUDOELEMENT 18 #define SCE_CSS_EXTENDED_IDENTIFIER 19 #define SCE_CSS_EXTENDED_PSEUDOCLASS 20 #define SCE_CSS_EXTENDED_PSEUDOELEMENT 21 #define SCE_CSS_MEDIA 22 #define SCE_CSS_VARIABLE 23 #define SCE_POV_DEFAULT 0 #define SCE_POV_COMMENT 1 #define SCE_POV_COMMENTLINE 2 #define SCE_POV_NUMBER 3 #define SCE_POV_OPERATOR 4 #define SCE_POV_IDENTIFIER 5 #define SCE_POV_STRING 6 #define SCE_POV_STRINGEOL 7 #define SCE_POV_DIRECTIVE 8 #define SCE_POV_BADDIRECTIVE 9 #define SCE_POV_WORD2 10 #define SCE_POV_WORD3 11 #define SCE_POV_WORD4 12 #define SCE_POV_WORD5 13 #define SCE_POV_WORD6 14 #define SCE_POV_WORD7 15 #define SCE_POV_WORD8 16 #define SCE_LOUT_DEFAULT 0 #define SCE_LOUT_COMMENT 1 #define SCE_LOUT_NUMBER 2 #define SCE_LOUT_WORD 3 #define SCE_LOUT_WORD2 4 #define SCE_LOUT_WORD3 5 #define SCE_LOUT_WORD4 6 #define SCE_LOUT_STRING 7 #define SCE_LOUT_OPERATOR 8 #define SCE_LOUT_IDENTIFIER 9 #define SCE_LOUT_STRINGEOL 10 #define SCE_ESCRIPT_DEFAULT 0 #define SCE_ESCRIPT_COMMENT 1 #define SCE_ESCRIPT_COMMENTLINE 2 #define SCE_ESCRIPT_COMMENTDOC 3 #define SCE_ESCRIPT_NUMBER 4 #define SCE_ESCRIPT_WORD 5 #define SCE_ESCRIPT_STRING 6 #define SCE_ESCRIPT_OPERATOR 7 #define SCE_ESCRIPT_IDENTIFIER 8 #define SCE_ESCRIPT_BRACE 9 #define SCE_ESCRIPT_WORD2 10 #define SCE_ESCRIPT_WORD3 11 #define SCE_PS_DEFAULT 0 #define SCE_PS_COMMENT 1 #define SCE_PS_DSC_COMMENT 2 #define SCE_PS_DSC_VALUE 3 #define SCE_PS_NUMBER 4 #define SCE_PS_NAME 5 #define SCE_PS_KEYWORD 6 #define SCE_PS_LITERAL 7 #define SCE_PS_IMMEVAL 8 #define SCE_PS_PAREN_ARRAY 9 #define SCE_PS_PAREN_DICT 10 #define SCE_PS_PAREN_PROC 11 #define SCE_PS_TEXT 12 #define SCE_PS_HEXSTRING 13 #define SCE_PS_BASE85STRING 14 #define SCE_PS_BADSTRINGCHAR 15 #define SCE_NSIS_DEFAULT 0 #define SCE_NSIS_COMMENT 1 #define SCE_NSIS_STRINGDQ 2 #define SCE_NSIS_STRINGLQ 3 #define SCE_NSIS_STRINGRQ 4 #define SCE_NSIS_FUNCTION 5 #define SCE_NSIS_VARIABLE 6 #define SCE_NSIS_LABEL 7 #define SCE_NSIS_USERDEFINED 8 #define SCE_NSIS_SECTIONDEF 9 #define SCE_NSIS_SUBSECTIONDEF 10 #define SCE_NSIS_IFDEFINEDEF 11 #define SCE_NSIS_MACRODEF 12 #define SCE_NSIS_STRINGVAR 13 #define SCE_NSIS_NUMBER 14 #define SCE_NSIS_SECTIONGROUP 15 #define SCE_NSIS_PAGEEX 16 #define SCE_NSIS_FUNCTIONDEF 17 #define SCE_NSIS_COMMENTBOX 18 #define SCE_MMIXAL_LEADWS 0 #define SCE_MMIXAL_COMMENT 1 #define SCE_MMIXAL_LABEL 2 #define SCE_MMIXAL_OPCODE 3 #define SCE_MMIXAL_OPCODE_PRE 4 #define SCE_MMIXAL_OPCODE_VALID 5 #define SCE_MMIXAL_OPCODE_UNKNOWN 6 #define SCE_MMIXAL_OPCODE_POST 7 #define SCE_MMIXAL_OPERANDS 8 #define SCE_MMIXAL_NUMBER 9 #define SCE_MMIXAL_REF 10 #define SCE_MMIXAL_CHAR 11 #define SCE_MMIXAL_STRING 12 #define SCE_MMIXAL_REGISTER 13 #define SCE_MMIXAL_HEX 14 #define SCE_MMIXAL_OPERATOR 15 #define SCE_MMIXAL_SYMBOL 16 #define SCE_MMIXAL_INCLUDE 17 #define SCE_CLW_DEFAULT 0 #define SCE_CLW_LABEL 1 #define SCE_CLW_COMMENT 2 #define SCE_CLW_STRING 3 #define SCE_CLW_USER_IDENTIFIER 4 #define SCE_CLW_INTEGER_CONSTANT 5 #define SCE_CLW_REAL_CONSTANT 6 #define SCE_CLW_PICTURE_STRING 7 #define SCE_CLW_KEYWORD 8 #define SCE_CLW_COMPILER_DIRECTIVE 9 #define SCE_CLW_RUNTIME_EXPRESSIONS 10 #define SCE_CLW_BUILTIN_PROCEDURES_FUNCTION 11 #define SCE_CLW_STRUCTURE_DATA_TYPE 12 #define SCE_CLW_ATTRIBUTE 13 #define SCE_CLW_STANDARD_EQUATE 14 #define SCE_CLW_ERROR 15 #define SCE_CLW_DEPRECATED 16 #define SCE_LOT_DEFAULT 0 #define SCE_LOT_HEADER 1 #define SCE_LOT_BREAK 2 #define SCE_LOT_SET 3 #define SCE_LOT_PASS 4 #define SCE_LOT_FAIL 5 #define SCE_LOT_ABORT 6 #define SCE_YAML_DEFAULT 0 #define SCE_YAML_COMMENT 1 #define SCE_YAML_IDENTIFIER 2 #define SCE_YAML_KEYWORD 3 #define SCE_YAML_NUMBER 4 #define SCE_YAML_REFERENCE 5 #define SCE_YAML_DOCUMENT 6 #define SCE_YAML_TEXT 7 #define SCE_YAML_ERROR 8 #define SCE_YAML_OPERATOR 9 #define SCE_TEX_DEFAULT 0 #define SCE_TEX_SPECIAL 1 #define SCE_TEX_GROUP 2 #define SCE_TEX_SYMBOL 3 #define SCE_TEX_COMMAND 4 #define SCE_TEX_TEXT 5 #define SCE_METAPOST_DEFAULT 0 #define SCE_METAPOST_SPECIAL 1 #define SCE_METAPOST_GROUP 2 #define SCE_METAPOST_SYMBOL 3 #define SCE_METAPOST_COMMAND 4 #define SCE_METAPOST_TEXT 5 #define SCE_METAPOST_EXTRA 6 #define SCE_ERLANG_DEFAULT 0 #define SCE_ERLANG_COMMENT 1 #define SCE_ERLANG_VARIABLE 2 #define SCE_ERLANG_NUMBER 3 #define SCE_ERLANG_KEYWORD 4 #define SCE_ERLANG_STRING 5 #define SCE_ERLANG_OPERATOR 6 #define SCE_ERLANG_ATOM 7 #define SCE_ERLANG_FUNCTION_NAME 8 #define SCE_ERLANG_CHARACTER 9 #define SCE_ERLANG_MACRO 10 #define SCE_ERLANG_RECORD 11 #define SCE_ERLANG_PREPROC 12 #define SCE_ERLANG_NODE_NAME 13 #define SCE_ERLANG_COMMENT_FUNCTION 14 #define SCE_ERLANG_COMMENT_MODULE 15 #define SCE_ERLANG_COMMENT_DOC 16 #define SCE_ERLANG_COMMENT_DOC_MACRO 17 #define SCE_ERLANG_ATOM_QUOTED 18 #define SCE_ERLANG_MACRO_QUOTED 19 #define SCE_ERLANG_RECORD_QUOTED 20 #define SCE_ERLANG_NODE_NAME_QUOTED 21 #define SCE_ERLANG_BIFS 22 #define SCE_ERLANG_MODULES 23 #define SCE_ERLANG_MODULES_ATT 24 #define SCE_ERLANG_UNKNOWN 31 #define SCE_MSSQL_DEFAULT 0 #define SCE_MSSQL_COMMENT 1 #define SCE_MSSQL_LINE_COMMENT 2 #define SCE_MSSQL_NUMBER 3 #define SCE_MSSQL_STRING 4 #define SCE_MSSQL_OPERATOR 5 #define SCE_MSSQL_IDENTIFIER 6 #define SCE_MSSQL_VARIABLE 7 #define SCE_MSSQL_COLUMN_NAME 8 #define SCE_MSSQL_STATEMENT 9 #define SCE_MSSQL_DATATYPE 10 #define SCE_MSSQL_SYSTABLE 11 #define SCE_MSSQL_GLOBAL_VARIABLE 12 #define SCE_MSSQL_FUNCTION 13 #define SCE_MSSQL_STORED_PROCEDURE 14 #define SCE_MSSQL_DEFAULT_PREF_DATATYPE 15 #define SCE_MSSQL_COLUMN_NAME_2 16 #define SCE_V_DEFAULT 0 #define SCE_V_COMMENT 1 #define SCE_V_COMMENTLINE 2 #define SCE_V_COMMENTLINEBANG 3 #define SCE_V_NUMBER 4 #define SCE_V_WORD 5 #define SCE_V_STRING 6 #define SCE_V_WORD2 7 #define SCE_V_WORD3 8 #define SCE_V_PREPROCESSOR 9 #define SCE_V_OPERATOR 10 #define SCE_V_IDENTIFIER 11 #define SCE_V_STRINGEOL 12 #define SCE_V_USER 19 #define SCE_KIX_DEFAULT 0 #define SCE_KIX_COMMENT 1 #define SCE_KIX_STRING1 2 #define SCE_KIX_STRING2 3 #define SCE_KIX_NUMBER 4 #define SCE_KIX_VAR 5 #define SCE_KIX_MACRO 6 #define SCE_KIX_KEYWORD 7 #define SCE_KIX_FUNCTIONS 8 #define SCE_KIX_OPERATOR 9 #define SCE_KIX_IDENTIFIER 31 #define SCE_GC_DEFAULT 0 #define SCE_GC_COMMENTLINE 1 #define SCE_GC_COMMENTBLOCK 2 #define SCE_GC_GLOBAL 3 #define SCE_GC_EVENT 4 #define SCE_GC_ATTRIBUTE 5 #define SCE_GC_CONTROL 6 #define SCE_GC_COMMAND 7 #define SCE_GC_STRING 8 #define SCE_GC_OPERATOR 9 #define SCE_SN_DEFAULT 0 #define SCE_SN_CODE 1 #define SCE_SN_COMMENTLINE 2 #define SCE_SN_COMMENTLINEBANG 3 #define SCE_SN_NUMBER 4 #define SCE_SN_WORD 5 #define SCE_SN_STRING 6 #define SCE_SN_WORD2 7 #define SCE_SN_WORD3 8 #define SCE_SN_PREPROCESSOR 9 #define SCE_SN_OPERATOR 10 #define SCE_SN_IDENTIFIER 11 #define SCE_SN_STRINGEOL 12 #define SCE_SN_REGEXTAG 13 #define SCE_SN_SIGNAL 14 #define SCE_SN_USER 19 #define SCE_AU3_DEFAULT 0 #define SCE_AU3_COMMENT 1 #define SCE_AU3_COMMENTBLOCK 2 #define SCE_AU3_NUMBER 3 #define SCE_AU3_FUNCTION 4 #define SCE_AU3_KEYWORD 5 #define SCE_AU3_MACRO 6 #define SCE_AU3_STRING 7 #define SCE_AU3_OPERATOR 8 #define SCE_AU3_VARIABLE 9 #define SCE_AU3_SENT 10 #define SCE_AU3_PREPROCESSOR 11 #define SCE_AU3_SPECIAL 12 #define SCE_AU3_EXPAND 13 #define SCE_AU3_COMOBJ 14 #define SCE_AU3_UDF 15 #define SCE_APDL_DEFAULT 0 #define SCE_APDL_COMMENT 1 #define SCE_APDL_COMMENTBLOCK 2 #define SCE_APDL_NUMBER 3 #define SCE_APDL_STRING 4 #define SCE_APDL_OPERATOR 5 #define SCE_APDL_WORD 6 #define SCE_APDL_PROCESSOR 7 #define SCE_APDL_COMMAND 8 #define SCE_APDL_SLASHCOMMAND 9 #define SCE_APDL_STARCOMMAND 10 #define SCE_APDL_ARGUMENT 11 #define SCE_APDL_FUNCTION 12 #define SCE_SH_DEFAULT 0 #define SCE_SH_ERROR 1 #define SCE_SH_COMMENTLINE 2 #define SCE_SH_NUMBER 3 #define SCE_SH_WORD 4 #define SCE_SH_STRING 5 #define SCE_SH_CHARACTER 6 #define SCE_SH_OPERATOR 7 #define SCE_SH_IDENTIFIER 8 #define SCE_SH_SCALAR 9 #define SCE_SH_PARAM 10 #define SCE_SH_BACKTICKS 11 #define SCE_SH_HERE_DELIM 12 #define SCE_SH_HERE_Q 13 #define SCE_ASN1_DEFAULT 0 #define SCE_ASN1_COMMENT 1 #define SCE_ASN1_IDENTIFIER 2 #define SCE_ASN1_STRING 3 #define SCE_ASN1_OID 4 #define SCE_ASN1_SCALAR 5 #define SCE_ASN1_KEYWORD 6 #define SCE_ASN1_ATTRIBUTE 7 #define SCE_ASN1_DESCRIPTOR 8 #define SCE_ASN1_TYPE 9 #define SCE_ASN1_OPERATOR 10 #define SCE_VHDL_DEFAULT 0 #define SCE_VHDL_COMMENT 1 #define SCE_VHDL_COMMENTLINEBANG 2 #define SCE_VHDL_NUMBER 3 #define SCE_VHDL_STRING 4 #define SCE_VHDL_OPERATOR 5 #define SCE_VHDL_IDENTIFIER 6 #define SCE_VHDL_STRINGEOL 7 #define SCE_VHDL_KEYWORD 8 #define SCE_VHDL_STDOPERATOR 9 #define SCE_VHDL_ATTRIBUTE 10 #define SCE_VHDL_STDFUNCTION 11 #define SCE_VHDL_STDPACKAGE 12 #define SCE_VHDL_STDTYPE 13 #define SCE_VHDL_USERWORD 14 #define SCE_CAML_DEFAULT 0 #define SCE_CAML_IDENTIFIER 1 #define SCE_CAML_TAGNAME 2 #define SCE_CAML_KEYWORD 3 #define SCE_CAML_KEYWORD2 4 #define SCE_CAML_KEYWORD3 5 #define SCE_CAML_LINENUM 6 #define SCE_CAML_OPERATOR 7 #define SCE_CAML_NUMBER 8 #define SCE_CAML_CHAR 9 #define SCE_CAML_WHITE 10 #define SCE_CAML_STRING 11 #define SCE_CAML_COMMENT 12 #define SCE_CAML_COMMENT1 13 #define SCE_CAML_COMMENT2 14 #define SCE_CAML_COMMENT3 15 #define SCE_HA_DEFAULT 0 #define SCE_HA_IDENTIFIER 1 #define SCE_HA_KEYWORD 2 #define SCE_HA_NUMBER 3 #define SCE_HA_STRING 4 #define SCE_HA_CHARACTER 5 #define SCE_HA_CLASS 6 #define SCE_HA_MODULE 7 #define SCE_HA_CAPITAL 8 #define SCE_HA_DATA 9 #define SCE_HA_IMPORT 10 #define SCE_HA_OPERATOR 11 #define SCE_HA_INSTANCE 12 #define SCE_HA_COMMENTLINE 13 #define SCE_HA_COMMENTBLOCK 14 #define SCE_HA_COMMENTBLOCK2 15 #define SCE_HA_COMMENTBLOCK3 16 #define SCE_T3_DEFAULT 0 #define SCE_T3_X_DEFAULT 1 #define SCE_T3_PREPROCESSOR 2 #define SCE_T3_BLOCK_COMMENT 3 #define SCE_T3_LINE_COMMENT 4 #define SCE_T3_OPERATOR 5 #define SCE_T3_KEYWORD 6 #define SCE_T3_NUMBER 7 #define SCE_T3_IDENTIFIER 8 #define SCE_T3_S_STRING 9 #define SCE_T3_D_STRING 10 #define SCE_T3_X_STRING 11 #define SCE_T3_LIB_DIRECTIVE 12 #define SCE_T3_MSG_PARAM 13 #define SCE_T3_HTML_TAG 14 #define SCE_T3_HTML_DEFAULT 15 #define SCE_T3_HTML_STRING 16 #define SCE_T3_USER1 17 #define SCE_T3_USER2 18 #define SCE_T3_USER3 19 #define SCE_T3_BRACE 20 #define SCE_REBOL_DEFAULT 0 #define SCE_REBOL_COMMENTLINE 1 #define SCE_REBOL_COMMENTBLOCK 2 #define SCE_REBOL_PREFACE 3 #define SCE_REBOL_OPERATOR 4 #define SCE_REBOL_CHARACTER 5 #define SCE_REBOL_QUOTEDSTRING 6 #define SCE_REBOL_BRACEDSTRING 7 #define SCE_REBOL_NUMBER 8 #define SCE_REBOL_PAIR 9 #define SCE_REBOL_TUPLE 10 #define SCE_REBOL_BINARY 11 #define SCE_REBOL_MONEY 12 #define SCE_REBOL_ISSUE 13 #define SCE_REBOL_TAG 14 #define SCE_REBOL_FILE 15 #define SCE_REBOL_EMAIL 16 #define SCE_REBOL_URL 17 #define SCE_REBOL_DATE 18 #define SCE_REBOL_TIME 19 #define SCE_REBOL_IDENTIFIER 20 #define SCE_REBOL_WORD 21 #define SCE_REBOL_WORD2 22 #define SCE_REBOL_WORD3 23 #define SCE_REBOL_WORD4 24 #define SCE_REBOL_WORD5 25 #define SCE_REBOL_WORD6 26 #define SCE_REBOL_WORD7 27 #define SCE_REBOL_WORD8 28 #define SCE_SQL_DEFAULT 0 #define SCE_SQL_COMMENT 1 #define SCE_SQL_COMMENTLINE 2 #define SCE_SQL_COMMENTDOC 3 #define SCE_SQL_NUMBER 4 #define SCE_SQL_WORD 5 #define SCE_SQL_STRING 6 #define SCE_SQL_CHARACTER 7 #define SCE_SQL_SQLPLUS 8 #define SCE_SQL_SQLPLUS_PROMPT 9 #define SCE_SQL_OPERATOR 10 #define SCE_SQL_IDENTIFIER 11 #define SCE_SQL_SQLPLUS_COMMENT 13 #define SCE_SQL_COMMENTLINEDOC 15 #define SCE_SQL_WORD2 16 #define SCE_SQL_COMMENTDOCKEYWORD 17 #define SCE_SQL_COMMENTDOCKEYWORDERROR 18 #define SCE_SQL_USER1 19 #define SCE_SQL_USER2 20 #define SCE_SQL_USER3 21 #define SCE_SQL_USER4 22 #define SCE_SQL_QUOTEDIDENTIFIER 23 #define SCE_ST_DEFAULT 0 #define SCE_ST_STRING 1 #define SCE_ST_NUMBER 2 #define SCE_ST_COMMENT 3 #define SCE_ST_SYMBOL 4 #define SCE_ST_BINARY 5 #define SCE_ST_BOOL 6 #define SCE_ST_SELF 7 #define SCE_ST_SUPER 8 #define SCE_ST_NIL 9 #define SCE_ST_GLOBAL 10 #define SCE_ST_RETURN 11 #define SCE_ST_SPECIAL 12 #define SCE_ST_KWSEND 13 #define SCE_ST_ASSIGN 14 #define SCE_ST_CHARACTER 15 #define SCE_ST_SPEC_SEL 16 #define SCE_FS_DEFAULT 0 #define SCE_FS_COMMENT 1 #define SCE_FS_COMMENTLINE 2 #define SCE_FS_COMMENTDOC 3 #define SCE_FS_COMMENTLINEDOC 4 #define SCE_FS_COMMENTDOCKEYWORD 5 #define SCE_FS_COMMENTDOCKEYWORDERROR 6 #define SCE_FS_KEYWORD 7 #define SCE_FS_KEYWORD2 8 #define SCE_FS_KEYWORD3 9 #define SCE_FS_KEYWORD4 10 #define SCE_FS_NUMBER 11 #define SCE_FS_STRING 12 #define SCE_FS_PREPROCESSOR 13 #define SCE_FS_OPERATOR 14 #define SCE_FS_IDENTIFIER 15 #define SCE_FS_DATE 16 #define SCE_FS_STRINGEOL 17 #define SCE_FS_CONSTANT 18 #define SCE_FS_WORDOPERATOR 19 #define SCE_FS_DISABLEDCODE 20 #define SCE_FS_DEFAULT_C 21 #define SCE_FS_COMMENTDOC_C 22 #define SCE_FS_COMMENTLINEDOC_C 23 #define SCE_FS_KEYWORD_C 24 #define SCE_FS_KEYWORD2_C 25 #define SCE_FS_NUMBER_C 26 #define SCE_FS_STRING_C 27 #define SCE_FS_PREPROCESSOR_C 28 #define SCE_FS_OPERATOR_C 29 #define SCE_FS_IDENTIFIER_C 30 #define SCE_FS_STRINGEOL_C 31 #define SCE_CSOUND_DEFAULT 0 #define SCE_CSOUND_COMMENT 1 #define SCE_CSOUND_NUMBER 2 #define SCE_CSOUND_OPERATOR 3 #define SCE_CSOUND_INSTR 4 #define SCE_CSOUND_IDENTIFIER 5 #define SCE_CSOUND_OPCODE 6 #define SCE_CSOUND_HEADERSTMT 7 #define SCE_CSOUND_USERKEYWORD 8 #define SCE_CSOUND_COMMENTBLOCK 9 #define SCE_CSOUND_PARAM 10 #define SCE_CSOUND_ARATE_VAR 11 #define SCE_CSOUND_KRATE_VAR 12 #define SCE_CSOUND_IRATE_VAR 13 #define SCE_CSOUND_GLOBAL_VAR 14 #define SCE_CSOUND_STRINGEOL 15 #define SCE_INNO_DEFAULT 0 #define SCE_INNO_COMMENT 1 #define SCE_INNO_KEYWORD 2 #define SCE_INNO_PARAMETER 3 #define SCE_INNO_SECTION 4 #define SCE_INNO_PREPROC 5 #define SCE_INNO_INLINE_EXPANSION 6 #define SCE_INNO_COMMENT_PASCAL 7 #define SCE_INNO_KEYWORD_PASCAL 8 #define SCE_INNO_KEYWORD_USER 9 #define SCE_INNO_STRING_DOUBLE 10 #define SCE_INNO_STRING_SINGLE 11 #define SCE_INNO_IDENTIFIER 12 #define SCE_OPAL_SPACE 0 #define SCE_OPAL_COMMENT_BLOCK 1 #define SCE_OPAL_COMMENT_LINE 2 #define SCE_OPAL_INTEGER 3 #define SCE_OPAL_KEYWORD 4 #define SCE_OPAL_SORT 5 #define SCE_OPAL_STRING 6 #define SCE_OPAL_PAR 7 #define SCE_OPAL_BOOL_CONST 8 #define SCE_OPAL_DEFAULT 32 #define SCE_SPICE_DEFAULT 0 #define SCE_SPICE_IDENTIFIER 1 #define SCE_SPICE_KEYWORD 2 #define SCE_SPICE_KEYWORD2 3 #define SCE_SPICE_KEYWORD3 4 #define SCE_SPICE_NUMBER 5 #define SCE_SPICE_DELIMITER 6 #define SCE_SPICE_VALUE 7 #define SCE_SPICE_COMMENTLINE 8 #define SCE_CMAKE_DEFAULT 0 #define SCE_CMAKE_COMMENT 1 #define SCE_CMAKE_STRINGDQ 2 #define SCE_CMAKE_STRINGLQ 3 #define SCE_CMAKE_STRINGRQ 4 #define SCE_CMAKE_COMMANDS 5 #define SCE_CMAKE_PARAMETERS 6 #define SCE_CMAKE_VARIABLE 7 #define SCE_CMAKE_USERDEFINED 8 #define SCE_CMAKE_WHILEDEF 9 #define SCE_CMAKE_FOREACHDEF 10 #define SCE_CMAKE_IFDEFINEDEF 11 #define SCE_CMAKE_MACRODEF 12 #define SCE_CMAKE_STRINGVAR 13 #define SCE_CMAKE_NUMBER 14 #define SCE_GAP_DEFAULT 0 #define SCE_GAP_IDENTIFIER 1 #define SCE_GAP_KEYWORD 2 #define SCE_GAP_KEYWORD2 3 #define SCE_GAP_KEYWORD3 4 #define SCE_GAP_KEYWORD4 5 #define SCE_GAP_STRING 6 #define SCE_GAP_CHAR 7 #define SCE_GAP_OPERATOR 8 #define SCE_GAP_COMMENT 9 #define SCE_GAP_NUMBER 10 #define SCE_GAP_STRINGEOL 11 #define SCE_PLM_DEFAULT 0 #define SCE_PLM_COMMENT 1 #define SCE_PLM_STRING 2 #define SCE_PLM_NUMBER 3 #define SCE_PLM_IDENTIFIER 4 #define SCE_PLM_OPERATOR 5 #define SCE_PLM_CONTROL 6 #define SCE_PLM_KEYWORD 7 #define SCE_4GL_DEFAULT 0 #define SCE_4GL_NUMBER 1 #define SCE_4GL_WORD 2 #define SCE_4GL_STRING 3 #define SCE_4GL_CHARACTER 4 #define SCE_4GL_PREPROCESSOR 5 #define SCE_4GL_OPERATOR 6 #define SCE_4GL_IDENTIFIER 7 #define SCE_4GL_BLOCK 8 #define SCE_4GL_END 9 #define SCE_4GL_COMMENT1 10 #define SCE_4GL_COMMENT2 11 #define SCE_4GL_COMMENT3 12 #define SCE_4GL_COMMENT4 13 #define SCE_4GL_COMMENT5 14 #define SCE_4GL_COMMENT6 15 #define SCE_4GL_DEFAULT_ 16 #define SCE_4GL_NUMBER_ 17 #define SCE_4GL_WORD_ 18 #define SCE_4GL_STRING_ 19 #define SCE_4GL_CHARACTER_ 20 #define SCE_4GL_PREPROCESSOR_ 21 #define SCE_4GL_OPERATOR_ 22 #define SCE_4GL_IDENTIFIER_ 23 #define SCE_4GL_BLOCK_ 24 #define SCE_4GL_END_ 25 #define SCE_4GL_COMMENT1_ 26 #define SCE_4GL_COMMENT2_ 27 #define SCE_4GL_COMMENT3_ 28 #define SCE_4GL_COMMENT4_ 29 #define SCE_4GL_COMMENT5_ 30 #define SCE_4GL_COMMENT6_ 31 #define SCE_ABAQUS_DEFAULT 0 #define SCE_ABAQUS_COMMENT 1 #define SCE_ABAQUS_COMMENTBLOCK 2 #define SCE_ABAQUS_NUMBER 3 #define SCE_ABAQUS_STRING 4 #define SCE_ABAQUS_OPERATOR 5 #define SCE_ABAQUS_WORD 6 #define SCE_ABAQUS_PROCESSOR 7 #define SCE_ABAQUS_COMMAND 8 #define SCE_ABAQUS_SLASHCOMMAND 9 #define SCE_ABAQUS_STARCOMMAND 10 #define SCE_ABAQUS_ARGUMENT 11 #define SCE_ABAQUS_FUNCTION 12 #define SCE_ASY_DEFAULT 0 #define SCE_ASY_COMMENT 1 #define SCE_ASY_COMMENTLINE 2 #define SCE_ASY_NUMBER 3 #define SCE_ASY_WORD 4 #define SCE_ASY_STRING 5 #define SCE_ASY_CHARACTER 6 #define SCE_ASY_OPERATOR 7 #define SCE_ASY_IDENTIFIER 8 #define SCE_ASY_STRINGEOL 9 #define SCE_ASY_COMMENTLINEDOC 10 #define SCE_ASY_WORD2 11 #define SCE_R_DEFAULT 0 #define SCE_R_COMMENT 1 #define SCE_R_KWORD 2 #define SCE_R_BASEKWORD 3 #define SCE_R_OTHERKWORD 4 #define SCE_R_NUMBER 5 #define SCE_R_STRING 6 #define SCE_R_STRING2 7 #define SCE_R_OPERATOR 8 #define SCE_R_IDENTIFIER 9 #define SCE_R_INFIX 10 #define SCE_R_INFIXEOL 11 #define SCE_MAGIK_DEFAULT 0 #define SCE_MAGIK_COMMENT 1 #define SCE_MAGIK_HYPER_COMMENT 16 #define SCE_MAGIK_STRING 2 #define SCE_MAGIK_CHARACTER 3 #define SCE_MAGIK_NUMBER 4 #define SCE_MAGIK_IDENTIFIER 5 #define SCE_MAGIK_OPERATOR 6 #define SCE_MAGIK_FLOW 7 #define SCE_MAGIK_CONTAINER 8 #define SCE_MAGIK_BRACKET_BLOCK 9 #define SCE_MAGIK_BRACE_BLOCK 10 #define SCE_MAGIK_SQBRACKET_BLOCK 11 #define SCE_MAGIK_UNKNOWN_KEYWORD 12 #define SCE_MAGIK_KEYWORD 13 #define SCE_MAGIK_PRAGMA 14 #define SCE_MAGIK_SYMBOL 15 #define SCE_POWERSHELL_DEFAULT 0 #define SCE_POWERSHELL_COMMENT 1 #define SCE_POWERSHELL_STRING 2 #define SCE_POWERSHELL_CHARACTER 3 #define SCE_POWERSHELL_NUMBER 4 #define SCE_POWERSHELL_VARIABLE 5 #define SCE_POWERSHELL_OPERATOR 6 #define SCE_POWERSHELL_IDENTIFIER 7 #define SCE_POWERSHELL_KEYWORD 8 #define SCE_POWERSHELL_CMDLET 9 #define SCE_POWERSHELL_ALIAS 10 #define SCE_POWERSHELL_FUNCTION 11 #define SCE_POWERSHELL_USER1 12 #define SCE_POWERSHELL_COMMENTSTREAM 13 #define SCE_MYSQL_DEFAULT 0 #define SCE_MYSQL_COMMENT 1 #define SCE_MYSQL_COMMENTLINE 2 #define SCE_MYSQL_VARIABLE 3 #define SCE_MYSQL_SYSTEMVARIABLE 4 #define SCE_MYSQL_KNOWNSYSTEMVARIABLE 5 #define SCE_MYSQL_NUMBER 6 #define SCE_MYSQL_MAJORKEYWORD 7 #define SCE_MYSQL_KEYWORD 8 #define SCE_MYSQL_DATABASEOBJECT 9 #define SCE_MYSQL_PROCEDUREKEYWORD 10 #define SCE_MYSQL_STRING 11 #define SCE_MYSQL_SQSTRING 12 #define SCE_MYSQL_DQSTRING 13 #define SCE_MYSQL_OPERATOR 14 #define SCE_MYSQL_FUNCTION 15 #define SCE_MYSQL_IDENTIFIER 16 #define SCE_MYSQL_QUOTEDIDENTIFIER 17 #define SCE_MYSQL_USER1 18 #define SCE_MYSQL_USER2 19 #define SCE_MYSQL_USER3 20 #define SCE_MYSQL_HIDDENCOMMAND 21 #define SCE_PO_DEFAULT 0 #define SCE_PO_COMMENT 1 #define SCE_PO_MSGID 2 #define SCE_PO_MSGID_TEXT 3 #define SCE_PO_MSGSTR 4 #define SCE_PO_MSGSTR_TEXT 5 #define SCE_PO_MSGCTXT 6 #define SCE_PO_MSGCTXT_TEXT 7 #define SCE_PO_FUZZY 8 #define SCE_PAS_DEFAULT 0 #define SCE_PAS_IDENTIFIER 1 #define SCE_PAS_COMMENT 2 #define SCE_PAS_COMMENT2 3 #define SCE_PAS_COMMENTLINE 4 #define SCE_PAS_PREPROCESSOR 5 #define SCE_PAS_PREPROCESSOR2 6 #define SCE_PAS_NUMBER 7 #define SCE_PAS_HEXNUMBER 8 #define SCE_PAS_WORD 9 #define SCE_PAS_STRING 10 #define SCE_PAS_STRINGEOL 11 #define SCE_PAS_CHARACTER 12 #define SCE_PAS_OPERATOR 13 #define SCE_PAS_ASM 14 #define SCE_SORCUS_DEFAULT 0 #define SCE_SORCUS_COMMAND 1 #define SCE_SORCUS_PARAMETER 2 #define SCE_SORCUS_COMMENTLINE 3 #define SCE_SORCUS_STRING 4 #define SCE_SORCUS_STRINGEOL 5 #define SCE_SORCUS_IDENTIFIER 6 #define SCE_SORCUS_OPERATOR 7 #define SCE_SORCUS_NUMBER 8 #define SCE_SORCUS_CONSTANT 9 #define SCE_POWERPRO_DEFAULT 0 #define SCE_POWERPRO_COMMENTBLOCK 1 #define SCE_POWERPRO_COMMENTLINE 2 #define SCE_POWERPRO_NUMBER 3 #define SCE_POWERPRO_WORD 4 #define SCE_POWERPRO_WORD2 5 #define SCE_POWERPRO_WORD3 6 #define SCE_POWERPRO_WORD4 7 #define SCE_POWERPRO_DOUBLEQUOTEDSTRING 8 #define SCE_POWERPRO_SINGLEQUOTEDSTRING 9 #define SCE_POWERPRO_LINECONTINUE 10 #define SCE_POWERPRO_OPERATOR 11 #define SCE_POWERPRO_IDENTIFIER 12 #define SCE_POWERPRO_STRINGEOL 13 #define SCE_POWERPRO_VERBATIM 14 #define SCE_POWERPRO_ALTQUOTE 15 #define SCE_POWERPRO_FUNCTION 16 #define SCE_SML_DEFAULT 0 #define SCE_SML_IDENTIFIER 1 #define SCE_SML_TAGNAME 2 #define SCE_SML_KEYWORD 3 #define SCE_SML_KEYWORD2 4 #define SCE_SML_KEYWORD3 5 #define SCE_SML_LINENUM 6 #define SCE_SML_OPERATOR 7 #define SCE_SML_NUMBER 8 #define SCE_SML_CHAR 9 #define SCE_SML_STRING 11 #define SCE_SML_COMMENT 12 #define SCE_SML_COMMENT1 13 #define SCE_SML_COMMENT2 14 #define SCE_SML_COMMENT3 15 #define SCE_MARKDOWN_DEFAULT 0 #define SCE_MARKDOWN_LINE_BEGIN 1 #define SCE_MARKDOWN_STRONG1 2 #define SCE_MARKDOWN_STRONG2 3 #define SCE_MARKDOWN_EM1 4 #define SCE_MARKDOWN_EM2 5 #define SCE_MARKDOWN_HEADER1 6 #define SCE_MARKDOWN_HEADER2 7 #define SCE_MARKDOWN_HEADER3 8 #define SCE_MARKDOWN_HEADER4 9 #define SCE_MARKDOWN_HEADER5 10 #define SCE_MARKDOWN_HEADER6 11 #define SCE_MARKDOWN_PRECHAR 12 #define SCE_MARKDOWN_ULIST_ITEM 13 #define SCE_MARKDOWN_OLIST_ITEM 14 #define SCE_MARKDOWN_BLOCKQUOTE 15 #define SCE_MARKDOWN_STRIKEOUT 16 #define SCE_MARKDOWN_HRULE 17 #define SCE_MARKDOWN_LINK 18 #define SCE_MARKDOWN_CODE 19 #define SCE_MARKDOWN_CODE2 20 #define SCE_MARKDOWN_CODEBK 21 #define SCE_TXT2TAGS_DEFAULT 0 #define SCE_TXT2TAGS_LINE_BEGIN 1 #define SCE_TXT2TAGS_STRONG1 2 #define SCE_TXT2TAGS_STRONG2 3 #define SCE_TXT2TAGS_EM1 4 #define SCE_TXT2TAGS_EM2 5 #define SCE_TXT2TAGS_HEADER1 6 #define SCE_TXT2TAGS_HEADER2 7 #define SCE_TXT2TAGS_HEADER3 8 #define SCE_TXT2TAGS_HEADER4 9 #define SCE_TXT2TAGS_HEADER5 10 #define SCE_TXT2TAGS_HEADER6 11 #define SCE_TXT2TAGS_PRECHAR 12 #define SCE_TXT2TAGS_ULIST_ITEM 13 #define SCE_TXT2TAGS_OLIST_ITEM 14 #define SCE_TXT2TAGS_BLOCKQUOTE 15 #define SCE_TXT2TAGS_STRIKEOUT 16 #define SCE_TXT2TAGS_HRULE 17 #define SCE_TXT2TAGS_LINK 18 #define SCE_TXT2TAGS_CODE 19 #define SCE_TXT2TAGS_CODE2 20 #define SCE_TXT2TAGS_CODEBK 21 #define SCE_TXT2TAGS_COMMENT 22 #define SCE_TXT2TAGS_OPTION 23 #define SCE_TXT2TAGS_PREPROC 24 #define SCE_TXT2TAGS_POSTPROC 25 #define SCE_A68K_DEFAULT 0 #define SCE_A68K_COMMENT 1 #define SCE_A68K_NUMBER_DEC 2 #define SCE_A68K_NUMBER_BIN 3 #define SCE_A68K_NUMBER_HEX 4 #define SCE_A68K_STRING1 5 #define SCE_A68K_OPERATOR 6 #define SCE_A68K_CPUINSTRUCTION 7 #define SCE_A68K_EXTINSTRUCTION 8 #define SCE_A68K_REGISTER 9 #define SCE_A68K_DIRECTIVE 10 #define SCE_A68K_MACRO_ARG 11 #define SCE_A68K_LABEL 12 #define SCE_A68K_STRING2 13 #define SCE_A68K_IDENTIFIER 14 #define SCE_A68K_MACRO_DECLARATION 15 #define SCE_A68K_COMMENT_WORD 16 #define SCE_A68K_COMMENT_SPECIAL 17 #define SCE_A68K_COMMENT_DOXYGEN 18 #define SCE_MODULA_DEFAULT 0 #define SCE_MODULA_COMMENT 1 #define SCE_MODULA_DOXYCOMM 2 #define SCE_MODULA_DOXYKEY 3 #define SCE_MODULA_KEYWORD 4 #define SCE_MODULA_RESERVED 5 #define SCE_MODULA_NUMBER 6 #define SCE_MODULA_BASENUM 7 #define SCE_MODULA_FLOAT 8 #define SCE_MODULA_STRING 9 #define SCE_MODULA_STRSPEC 10 #define SCE_MODULA_CHAR 11 #define SCE_MODULA_CHARSPEC 12 #define SCE_MODULA_PROC 13 #define SCE_MODULA_PRAGMA 14 #define SCE_MODULA_PRGKEY 15 #define SCE_MODULA_OPERATOR 16 #define SCE_MODULA_BADSTR 17 #define SCE_COFFEESCRIPT_DEFAULT 0 #define SCE_COFFEESCRIPT_COMMENT 1 #define SCE_COFFEESCRIPT_COMMENTLINE 2 #define SCE_COFFEESCRIPT_COMMENTDOC 3 #define SCE_COFFEESCRIPT_NUMBER 4 #define SCE_COFFEESCRIPT_WORD 5 #define SCE_COFFEESCRIPT_STRING 6 #define SCE_COFFEESCRIPT_CHARACTER 7 #define SCE_COFFEESCRIPT_UUID 8 #define SCE_COFFEESCRIPT_PREPROCESSOR 9 #define SCE_COFFEESCRIPT_OPERATOR 10 #define SCE_COFFEESCRIPT_IDENTIFIER 11 #define SCE_COFFEESCRIPT_STRINGEOL 12 #define SCE_COFFEESCRIPT_VERBATIM 13 #define SCE_COFFEESCRIPT_REGEX 14 #define SCE_COFFEESCRIPT_COMMENTLINEDOC 15 #define SCE_COFFEESCRIPT_WORD2 16 #define SCE_COFFEESCRIPT_COMMENTDOCKEYWORD 17 #define SCE_COFFEESCRIPT_COMMENTDOCKEYWORDERROR 18 #define SCE_COFFEESCRIPT_GLOBALCLASS 19 #define SCE_COFFEESCRIPT_STRINGRAW 20 #define SCE_COFFEESCRIPT_TRIPLEVERBATIM 21 #define SCE_COFFEESCRIPT_HASHQUOTEDSTRING 22 #define SCE_COFFEESCRIPT_COMMENTBLOCK 22 #define SCE_COFFEESCRIPT_VERBOSE_REGEX 23 #define SCE_COFFEESCRIPT_VERBOSE_REGEX_COMMENT 24 #define SCE_AVS_DEFAULT 0 #define SCE_AVS_COMMENTBLOCK 1 #define SCE_AVS_COMMENTBLOCKN 2 #define SCE_AVS_COMMENTLINE 3 #define SCE_AVS_NUMBER 4 #define SCE_AVS_OPERATOR 5 #define SCE_AVS_IDENTIFIER 6 #define SCE_AVS_STRING 7 #define SCE_AVS_TRIPLESTRING 8 #define SCE_AVS_KEYWORD 9 #define SCE_AVS_FILTER 10 #define SCE_AVS_PLUGIN 11 #define SCE_AVS_FUNCTION 12 #define SCE_AVS_CLIPPROP 13 #define SCE_AVS_USERDFN 14 #define SCE_ECL_DEFAULT 0 #define SCE_ECL_COMMENT 1 #define SCE_ECL_COMMENTLINE 2 #define SCE_ECL_NUMBER 3 #define SCE_ECL_STRING 4 #define SCE_ECL_WORD0 5 #define SCE_ECL_OPERATOR 6 #define SCE_ECL_CHARACTER 7 #define SCE_ECL_UUID 8 #define SCE_ECL_PREPROCESSOR 9 #define SCE_ECL_UNKNOWN 10 #define SCE_ECL_IDENTIFIER 11 #define SCE_ECL_STRINGEOL 12 #define SCE_ECL_VERBATIM 13 #define SCE_ECL_REGEX 14 #define SCE_ECL_COMMENTLINEDOC 15 #define SCE_ECL_WORD1 16 #define SCE_ECL_COMMENTDOCKEYWORD 17 #define SCE_ECL_COMMENTDOCKEYWORDERROR 18 #define SCE_ECL_WORD2 19 #define SCE_ECL_WORD3 20 #define SCE_ECL_WORD4 21 #define SCE_ECL_WORD5 22 #define SCE_ECL_COMMENTDOC 23 #define SCE_ECL_ADDED 24 #define SCE_ECL_DELETED 25 #define SCE_ECL_CHANGED 26 #define SCE_ECL_MOVED 27 #define SCE_OSCRIPT_DEFAULT 0 #define SCE_OSCRIPT_LINE_COMMENT 1 #define SCE_OSCRIPT_BLOCK_COMMENT 2 #define SCE_OSCRIPT_DOC_COMMENT 3 #define SCE_OSCRIPT_PREPROCESSOR 4 #define SCE_OSCRIPT_NUMBER 5 #define SCE_OSCRIPT_SINGLEQUOTE_STRING 6 #define SCE_OSCRIPT_DOUBLEQUOTE_STRING 7 #define SCE_OSCRIPT_CONSTANT 8 #define SCE_OSCRIPT_IDENTIFIER 9 #define SCE_OSCRIPT_GLOBAL 10 #define SCE_OSCRIPT_KEYWORD 11 #define SCE_OSCRIPT_OPERATOR 12 #define SCE_OSCRIPT_LABEL 13 #define SCE_OSCRIPT_TYPE 14 #define SCE_OSCRIPT_FUNCTION 15 #define SCE_OSCRIPT_OBJECT 16 #define SCE_OSCRIPT_PROPERTY 17 #define SCE_OSCRIPT_METHOD 18 #define SCE_VISUALPROLOG_DEFAULT 0 #define SCE_VISUALPROLOG_KEY_MAJOR 1 #define SCE_VISUALPROLOG_KEY_MINOR 2 #define SCE_VISUALPROLOG_KEY_DIRECTIVE 3 #define SCE_VISUALPROLOG_COMMENT_BLOCK 4 #define SCE_VISUALPROLOG_COMMENT_LINE 5 #define SCE_VISUALPROLOG_COMMENT_KEY 6 #define SCE_VISUALPROLOG_COMMENT_KEY_ERROR 7 #define SCE_VISUALPROLOG_IDENTIFIER 8 #define SCE_VISUALPROLOG_VARIABLE 9 #define SCE_VISUALPROLOG_ANONYMOUS 10 #define SCE_VISUALPROLOG_NUMBER 11 #define SCE_VISUALPROLOG_OPERATOR 12 #define SCE_VISUALPROLOG_CHARACTER 13 #define SCE_VISUALPROLOG_CHARACTER_TOO_MANY 14 #define SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR 15 #define SCE_VISUALPROLOG_STRING 16 #define SCE_VISUALPROLOG_STRING_ESCAPE 17 #define SCE_VISUALPROLOG_STRING_ESCAPE_ERROR 18 #define SCE_VISUALPROLOG_STRING_EOL_OPEN 19 #define SCE_VISUALPROLOG_STRING_VERBATIM 20 #define SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL 21 #define SCE_VISUALPROLOG_STRING_VERBATIM_EOL 22 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif presage-0.8.8/apps/gtk/gprompter/scintilla/include/Scintilla.h0000644000175000017500000010026111763437013021352 00000000000000/* Scintilla source code edit control */ /** @file Scintilla.h ** Interface to the edit control. **/ /* Copyright 1998-2003 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ /* Most of this file is automatically generated from the Scintilla.iface interface definition * file which contains any comments about the definitions. HFacer.py does the generation. */ #ifndef SCINTILLA_H #define SCINTILLA_H #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) /* Return false on failure: */ int Scintilla_RegisterClasses(void *hInstance); int Scintilla_ReleaseResources(); #endif int Scintilla_LinkLexers(); #ifdef __cplusplus } #endif /* Here should be placed typedefs for uptr_t, an unsigned integer type large enough to * hold a pointer and sptr_t, a signed integer large enough to hold a pointer. * May need to be changed for 64 bit platforms. */ #if defined(_WIN32) #include #endif #ifdef MAXULONG_PTR typedef ULONG_PTR uptr_t; typedef LONG_PTR sptr_t; #else typedef unsigned long uptr_t; typedef long sptr_t; #endif typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam); /* ++Autogenerated -- start of section automatically generated from Scintilla.iface */ #define INVALID_POSITION -1 #define SCI_START 2000 #define SCI_OPTIONAL_START 3000 #define SCI_LEXER_START 4000 #define SCI_ADDTEXT 2001 #define SCI_ADDSTYLEDTEXT 2002 #define SCI_INSERTTEXT 2003 #define SCI_CLEARALL 2004 #define SCI_DELETERANGE 2645 #define SCI_CLEARDOCUMENTSTYLE 2005 #define SCI_GETLENGTH 2006 #define SCI_GETCHARAT 2007 #define SCI_GETCURRENTPOS 2008 #define SCI_GETANCHOR 2009 #define SCI_GETSTYLEAT 2010 #define SCI_REDO 2011 #define SCI_SETUNDOCOLLECTION 2012 #define SCI_SELECTALL 2013 #define SCI_SETSAVEPOINT 2014 #define SCI_GETSTYLEDTEXT 2015 #define SCI_CANREDO 2016 #define SCI_MARKERLINEFROMHANDLE 2017 #define SCI_MARKERDELETEHANDLE 2018 #define SCI_GETUNDOCOLLECTION 2019 #define SCWS_INVISIBLE 0 #define SCWS_VISIBLEALWAYS 1 #define SCWS_VISIBLEAFTERINDENT 2 #define SCI_GETVIEWWS 2020 #define SCI_SETVIEWWS 2021 #define SCI_POSITIONFROMPOINT 2022 #define SCI_POSITIONFROMPOINTCLOSE 2023 #define SCI_GOTOLINE 2024 #define SCI_GOTOPOS 2025 #define SCI_SETANCHOR 2026 #define SCI_GETCURLINE 2027 #define SCI_GETENDSTYLED 2028 #define SC_EOL_CRLF 0 #define SC_EOL_CR 1 #define SC_EOL_LF 2 #define SCI_CONVERTEOLS 2029 #define SCI_GETEOLMODE 2030 #define SCI_SETEOLMODE 2031 #define SCI_STARTSTYLING 2032 #define SCI_SETSTYLING 2033 #define SCI_GETBUFFEREDDRAW 2034 #define SCI_SETBUFFEREDDRAW 2035 #define SCI_SETTABWIDTH 2036 #define SCI_GETTABWIDTH 2121 #define SC_CP_UTF8 65001 #define SCI_SETCODEPAGE 2037 #define MARKER_MAX 31 #define SC_MARK_CIRCLE 0 #define SC_MARK_ROUNDRECT 1 #define SC_MARK_ARROW 2 #define SC_MARK_SMALLRECT 3 #define SC_MARK_SHORTARROW 4 #define SC_MARK_EMPTY 5 #define SC_MARK_ARROWDOWN 6 #define SC_MARK_MINUS 7 #define SC_MARK_PLUS 8 #define SC_MARK_VLINE 9 #define SC_MARK_LCORNER 10 #define SC_MARK_TCORNER 11 #define SC_MARK_BOXPLUS 12 #define SC_MARK_BOXPLUSCONNECTED 13 #define SC_MARK_BOXMINUS 14 #define SC_MARK_BOXMINUSCONNECTED 15 #define SC_MARK_LCORNERCURVE 16 #define SC_MARK_TCORNERCURVE 17 #define SC_MARK_CIRCLEPLUS 18 #define SC_MARK_CIRCLEPLUSCONNECTED 19 #define SC_MARK_CIRCLEMINUS 20 #define SC_MARK_CIRCLEMINUSCONNECTED 21 #define SC_MARK_BACKGROUND 22 #define SC_MARK_DOTDOTDOT 23 #define SC_MARK_ARROWS 24 #define SC_MARK_PIXMAP 25 #define SC_MARK_FULLRECT 26 #define SC_MARK_LEFTRECT 27 #define SC_MARK_AVAILABLE 28 #define SC_MARK_UNDERLINE 29 #define SC_MARK_RGBAIMAGE 30 #define SC_MARK_CHARACTER 10000 #define SC_MARKNUM_FOLDEREND 25 #define SC_MARKNUM_FOLDEROPENMID 26 #define SC_MARKNUM_FOLDERMIDTAIL 27 #define SC_MARKNUM_FOLDERTAIL 28 #define SC_MARKNUM_FOLDERSUB 29 #define SC_MARKNUM_FOLDER 30 #define SC_MARKNUM_FOLDEROPEN 31 #define SC_MASK_FOLDERS 0xFE000000 #define SCI_MARKERDEFINE 2040 #define SCI_MARKERSETFORE 2041 #define SCI_MARKERSETBACK 2042 #define SCI_MARKERSETBACKSELECTED 2292 #define SCI_MARKERENABLEHIGHLIGHT 2293 #define SCI_MARKERADD 2043 #define SCI_MARKERDELETE 2044 #define SCI_MARKERDELETEALL 2045 #define SCI_MARKERGET 2046 #define SCI_MARKERNEXT 2047 #define SCI_MARKERPREVIOUS 2048 #define SCI_MARKERDEFINEPIXMAP 2049 #define SCI_MARKERADDSET 2466 #define SCI_MARKERSETALPHA 2476 #define SC_MARGIN_SYMBOL 0 #define SC_MARGIN_NUMBER 1 #define SC_MARGIN_BACK 2 #define SC_MARGIN_FORE 3 #define SC_MARGIN_TEXT 4 #define SC_MARGIN_RTEXT 5 #define SCI_SETMARGINTYPEN 2240 #define SCI_GETMARGINTYPEN 2241 #define SCI_SETMARGINWIDTHN 2242 #define SCI_GETMARGINWIDTHN 2243 #define SCI_SETMARGINMASKN 2244 #define SCI_GETMARGINMASKN 2245 #define SCI_SETMARGINSENSITIVEN 2246 #define SCI_GETMARGINSENSITIVEN 2247 #define SCI_SETMARGINCURSORN 2248 #define SCI_GETMARGINCURSORN 2249 #define STYLE_DEFAULT 32 #define STYLE_LINENUMBER 33 #define STYLE_BRACELIGHT 34 #define STYLE_BRACEBAD 35 #define STYLE_CONTROLCHAR 36 #define STYLE_INDENTGUIDE 37 #define STYLE_CALLTIP 38 #define STYLE_LASTPREDEFINED 39 #define STYLE_MAX 255 #define SC_CHARSET_ANSI 0 #define SC_CHARSET_DEFAULT 1 #define SC_CHARSET_BALTIC 186 #define SC_CHARSET_CHINESEBIG5 136 #define SC_CHARSET_EASTEUROPE 238 #define SC_CHARSET_GB2312 134 #define SC_CHARSET_GREEK 161 #define SC_CHARSET_HANGUL 129 #define SC_CHARSET_MAC 77 #define SC_CHARSET_OEM 255 #define SC_CHARSET_RUSSIAN 204 #define SC_CHARSET_CYRILLIC 1251 #define SC_CHARSET_SHIFTJIS 128 #define SC_CHARSET_SYMBOL 2 #define SC_CHARSET_TURKISH 162 #define SC_CHARSET_JOHAB 130 #define SC_CHARSET_HEBREW 177 #define SC_CHARSET_ARABIC 178 #define SC_CHARSET_VIETNAMESE 163 #define SC_CHARSET_THAI 222 #define SC_CHARSET_8859_15 1000 #define SCI_STYLECLEARALL 2050 #define SCI_STYLESETFORE 2051 #define SCI_STYLESETBACK 2052 #define SCI_STYLESETBOLD 2053 #define SCI_STYLESETITALIC 2054 #define SCI_STYLESETSIZE 2055 #define SCI_STYLESETFONT 2056 #define SCI_STYLESETEOLFILLED 2057 #define SCI_STYLERESETDEFAULT 2058 #define SCI_STYLESETUNDERLINE 2059 #define SC_CASE_MIXED 0 #define SC_CASE_UPPER 1 #define SC_CASE_LOWER 2 #define SCI_STYLEGETFORE 2481 #define SCI_STYLEGETBACK 2482 #define SCI_STYLEGETBOLD 2483 #define SCI_STYLEGETITALIC 2484 #define SCI_STYLEGETSIZE 2485 #define SCI_STYLEGETFONT 2486 #define SCI_STYLEGETEOLFILLED 2487 #define SCI_STYLEGETUNDERLINE 2488 #define SCI_STYLEGETCASE 2489 #define SCI_STYLEGETCHARACTERSET 2490 #define SCI_STYLEGETVISIBLE 2491 #define SCI_STYLEGETCHANGEABLE 2492 #define SCI_STYLEGETHOTSPOT 2493 #define SCI_STYLESETCASE 2060 #define SC_FONT_SIZE_MULTIPLIER 100 #define SCI_STYLESETSIZEFRACTIONAL 2061 #define SCI_STYLEGETSIZEFRACTIONAL 2062 #define SC_WEIGHT_NORMAL 400 #define SC_WEIGHT_SEMIBOLD 600 #define SC_WEIGHT_BOLD 700 #define SCI_STYLESETWEIGHT 2063 #define SCI_STYLEGETWEIGHT 2064 #define SCI_STYLESETCHARACTERSET 2066 #define SCI_STYLESETHOTSPOT 2409 #define SCI_SETSELFORE 2067 #define SCI_SETSELBACK 2068 #define SCI_GETSELALPHA 2477 #define SCI_SETSELALPHA 2478 #define SCI_GETSELEOLFILLED 2479 #define SCI_SETSELEOLFILLED 2480 #define SCI_SETCARETFORE 2069 #define SCI_ASSIGNCMDKEY 2070 #define SCI_CLEARCMDKEY 2071 #define SCI_CLEARALLCMDKEYS 2072 #define SCI_SETSTYLINGEX 2073 #define SCI_STYLESETVISIBLE 2074 #define SCI_GETCARETPERIOD 2075 #define SCI_SETCARETPERIOD 2076 #define SCI_SETWORDCHARS 2077 #define SCI_BEGINUNDOACTION 2078 #define SCI_ENDUNDOACTION 2079 #define INDIC_PLAIN 0 #define INDIC_SQUIGGLE 1 #define INDIC_TT 2 #define INDIC_DIAGONAL 3 #define INDIC_STRIKE 4 #define INDIC_HIDDEN 5 #define INDIC_BOX 6 #define INDIC_ROUNDBOX 7 #define INDIC_STRAIGHTBOX 8 #define INDIC_DASH 9 #define INDIC_DOTS 10 #define INDIC_SQUIGGLELOW 11 #define INDIC_DOTBOX 12 #define INDIC_MAX 31 #define INDIC_CONTAINER 8 #define INDIC0_MASK 0x20 #define INDIC1_MASK 0x40 #define INDIC2_MASK 0x80 #define INDICS_MASK 0xE0 #define SCI_INDICSETSTYLE 2080 #define SCI_INDICGETSTYLE 2081 #define SCI_INDICSETFORE 2082 #define SCI_INDICGETFORE 2083 #define SCI_INDICSETUNDER 2510 #define SCI_INDICGETUNDER 2511 #define SCI_SETWHITESPACEFORE 2084 #define SCI_SETWHITESPACEBACK 2085 #define SCI_SETWHITESPACESIZE 2086 #define SCI_GETWHITESPACESIZE 2087 #define SCI_SETSTYLEBITS 2090 #define SCI_GETSTYLEBITS 2091 #define SCI_SETLINESTATE 2092 #define SCI_GETLINESTATE 2093 #define SCI_GETMAXLINESTATE 2094 #define SCI_GETCARETLINEVISIBLE 2095 #define SCI_SETCARETLINEVISIBLE 2096 #define SCI_GETCARETLINEBACK 2097 #define SCI_SETCARETLINEBACK 2098 #define SCI_STYLESETCHANGEABLE 2099 #define SCI_AUTOCSHOW 2100 #define SCI_AUTOCCANCEL 2101 #define SCI_AUTOCACTIVE 2102 #define SCI_AUTOCPOSSTART 2103 #define SCI_AUTOCCOMPLETE 2104 #define SCI_AUTOCSTOPS 2105 #define SCI_AUTOCSETSEPARATOR 2106 #define SCI_AUTOCGETSEPARATOR 2107 #define SCI_AUTOCSELECT 2108 #define SCI_AUTOCSETCANCELATSTART 2110 #define SCI_AUTOCGETCANCELATSTART 2111 #define SCI_AUTOCSETFILLUPS 2112 #define SCI_AUTOCSETCHOOSESINGLE 2113 #define SCI_AUTOCGETCHOOSESINGLE 2114 #define SCI_AUTOCSETIGNORECASE 2115 #define SCI_AUTOCGETIGNORECASE 2116 #define SCI_USERLISTSHOW 2117 #define SCI_AUTOCSETAUTOHIDE 2118 #define SCI_AUTOCGETAUTOHIDE 2119 #define SCI_AUTOCSETDROPRESTOFWORD 2270 #define SCI_AUTOCGETDROPRESTOFWORD 2271 #define SCI_REGISTERIMAGE 2405 #define SCI_CLEARREGISTEREDIMAGES 2408 #define SCI_AUTOCGETTYPESEPARATOR 2285 #define SCI_AUTOCSETTYPESEPARATOR 2286 #define SCI_AUTOCSETMAXWIDTH 2208 #define SCI_AUTOCGETMAXWIDTH 2209 #define SCI_AUTOCSETMAXHEIGHT 2210 #define SCI_AUTOCGETMAXHEIGHT 2211 #define SCI_SETINDENT 2122 #define SCI_GETINDENT 2123 #define SCI_SETUSETABS 2124 #define SCI_GETUSETABS 2125 #define SCI_SETLINEINDENTATION 2126 #define SCI_GETLINEINDENTATION 2127 #define SCI_GETLINEINDENTPOSITION 2128 #define SCI_GETCOLUMN 2129 #define SCI_COUNTCHARACTERS 2633 #define SCI_SETHSCROLLBAR 2130 #define SCI_GETHSCROLLBAR 2131 #define SC_IV_NONE 0 #define SC_IV_REAL 1 #define SC_IV_LOOKFORWARD 2 #define SC_IV_LOOKBOTH 3 #define SCI_SETINDENTATIONGUIDES 2132 #define SCI_GETINDENTATIONGUIDES 2133 #define SCI_SETHIGHLIGHTGUIDE 2134 #define SCI_GETHIGHLIGHTGUIDE 2135 #define SCI_GETLINEENDPOSITION 2136 #define SCI_GETCODEPAGE 2137 #define SCI_GETCARETFORE 2138 #define SCI_GETREADONLY 2140 #define SCI_SETCURRENTPOS 2141 #define SCI_SETSELECTIONSTART 2142 #define SCI_GETSELECTIONSTART 2143 #define SCI_SETSELECTIONEND 2144 #define SCI_GETSELECTIONEND 2145 #define SCI_SETEMPTYSELECTION 2556 #define SCI_SETPRINTMAGNIFICATION 2146 #define SCI_GETPRINTMAGNIFICATION 2147 #define SC_PRINT_NORMAL 0 #define SC_PRINT_INVERTLIGHT 1 #define SC_PRINT_BLACKONWHITE 2 #define SC_PRINT_COLOURONWHITE 3 #define SC_PRINT_COLOURONWHITEDEFAULTBG 4 #define SCI_SETPRINTCOLOURMODE 2148 #define SCI_GETPRINTCOLOURMODE 2149 #define SCFIND_WHOLEWORD 2 #define SCFIND_MATCHCASE 4 #define SCFIND_WORDSTART 0x00100000 #define SCFIND_REGEXP 0x00200000 #define SCFIND_POSIX 0x00400000 #define SCI_FINDTEXT 2150 #define SCI_FORMATRANGE 2151 #define SCI_GETFIRSTVISIBLELINE 2152 #define SCI_GETLINE 2153 #define SCI_GETLINECOUNT 2154 #define SCI_SETMARGINLEFT 2155 #define SCI_GETMARGINLEFT 2156 #define SCI_SETMARGINRIGHT 2157 #define SCI_GETMARGINRIGHT 2158 #define SCI_GETMODIFY 2159 #define SCI_SETSEL 2160 #define SCI_GETSELTEXT 2161 #define SCI_GETTEXTRANGE 2162 #define SCI_HIDESELECTION 2163 #define SCI_POINTXFROMPOSITION 2164 #define SCI_POINTYFROMPOSITION 2165 #define SCI_LINEFROMPOSITION 2166 #define SCI_POSITIONFROMLINE 2167 #define SCI_LINESCROLL 2168 #define SCI_SCROLLCARET 2169 #define SCI_REPLACESEL 2170 #define SCI_SETREADONLY 2171 #define SCI_NULL 2172 #define SCI_CANPASTE 2173 #define SCI_CANUNDO 2174 #define SCI_EMPTYUNDOBUFFER 2175 #define SCI_UNDO 2176 #define SCI_CUT 2177 #define SCI_COPY 2178 #define SCI_PASTE 2179 #define SCI_CLEAR 2180 #define SCI_SETTEXT 2181 #define SCI_GETTEXT 2182 #define SCI_GETTEXTLENGTH 2183 #define SCI_GETDIRECTFUNCTION 2184 #define SCI_GETDIRECTPOINTER 2185 #define SCI_SETOVERTYPE 2186 #define SCI_GETOVERTYPE 2187 #define SCI_SETCARETWIDTH 2188 #define SCI_GETCARETWIDTH 2189 #define SCI_SETTARGETSTART 2190 #define SCI_GETTARGETSTART 2191 #define SCI_SETTARGETEND 2192 #define SCI_GETTARGETEND 2193 #define SCI_REPLACETARGET 2194 #define SCI_REPLACETARGETRE 2195 #define SCI_SEARCHINTARGET 2197 #define SCI_SETSEARCHFLAGS 2198 #define SCI_GETSEARCHFLAGS 2199 #define SCI_CALLTIPSHOW 2200 #define SCI_CALLTIPCANCEL 2201 #define SCI_CALLTIPACTIVE 2202 #define SCI_CALLTIPPOSSTART 2203 #define SCI_CALLTIPSETHLT 2204 #define SCI_CALLTIPSETBACK 2205 #define SCI_CALLTIPSETFORE 2206 #define SCI_CALLTIPSETFOREHLT 2207 #define SCI_CALLTIPUSESTYLE 2212 #define SCI_CALLTIPSETPOSITION 2213 #define SCI_VISIBLEFROMDOCLINE 2220 #define SCI_DOCLINEFROMVISIBLE 2221 #define SCI_WRAPCOUNT 2235 #define SC_FOLDLEVELBASE 0x400 #define SC_FOLDLEVELWHITEFLAG 0x1000 #define SC_FOLDLEVELHEADERFLAG 0x2000 #define SC_FOLDLEVELNUMBERMASK 0x0FFF #define SCI_SETFOLDLEVEL 2222 #define SCI_GETFOLDLEVEL 2223 #define SCI_GETLASTCHILD 2224 #define SCI_GETFOLDPARENT 2225 #define SCI_SHOWLINES 2226 #define SCI_HIDELINES 2227 #define SCI_GETLINEVISIBLE 2228 #define SCI_GETALLLINESVISIBLE 2236 #define SCI_SETFOLDEXPANDED 2229 #define SCI_GETFOLDEXPANDED 2230 #define SCI_TOGGLEFOLD 2231 #define SCI_ENSUREVISIBLE 2232 #define SC_FOLDFLAG_LINEBEFORE_EXPANDED 0x0002 #define SC_FOLDFLAG_LINEBEFORE_CONTRACTED 0x0004 #define SC_FOLDFLAG_LINEAFTER_EXPANDED 0x0008 #define SC_FOLDFLAG_LINEAFTER_CONTRACTED 0x0010 #define SC_FOLDFLAG_LEVELNUMBERS 0x0040 #define SCI_SETFOLDFLAGS 2233 #define SCI_ENSUREVISIBLEENFORCEPOLICY 2234 #define SCI_SETTABINDENTS 2260 #define SCI_GETTABINDENTS 2261 #define SCI_SETBACKSPACEUNINDENTS 2262 #define SCI_GETBACKSPACEUNINDENTS 2263 #define SC_TIME_FOREVER 10000000 #define SCI_SETMOUSEDWELLTIME 2264 #define SCI_GETMOUSEDWELLTIME 2265 #define SCI_WORDSTARTPOSITION 2266 #define SCI_WORDENDPOSITION 2267 #define SC_WRAP_NONE 0 #define SC_WRAP_WORD 1 #define SC_WRAP_CHAR 2 #define SCI_SETWRAPMODE 2268 #define SCI_GETWRAPMODE 2269 #define SC_WRAPVISUALFLAG_NONE 0x0000 #define SC_WRAPVISUALFLAG_END 0x0001 #define SC_WRAPVISUALFLAG_START 0x0002 #define SC_WRAPVISUALFLAG_MARGIN 0x0004 #define SCI_SETWRAPVISUALFLAGS 2460 #define SCI_GETWRAPVISUALFLAGS 2461 #define SC_WRAPVISUALFLAGLOC_DEFAULT 0x0000 #define SC_WRAPVISUALFLAGLOC_END_BY_TEXT 0x0001 #define SC_WRAPVISUALFLAGLOC_START_BY_TEXT 0x0002 #define SCI_SETWRAPVISUALFLAGSLOCATION 2462 #define SCI_GETWRAPVISUALFLAGSLOCATION 2463 #define SCI_SETWRAPSTARTINDENT 2464 #define SCI_GETWRAPSTARTINDENT 2465 #define SC_WRAPINDENT_FIXED 0 #define SC_WRAPINDENT_SAME 1 #define SC_WRAPINDENT_INDENT 2 #define SCI_SETWRAPINDENTMODE 2472 #define SCI_GETWRAPINDENTMODE 2473 #define SC_CACHE_NONE 0 #define SC_CACHE_CARET 1 #define SC_CACHE_PAGE 2 #define SC_CACHE_DOCUMENT 3 #define SCI_SETLAYOUTCACHE 2272 #define SCI_GETLAYOUTCACHE 2273 #define SCI_SETSCROLLWIDTH 2274 #define SCI_GETSCROLLWIDTH 2275 #define SCI_SETSCROLLWIDTHTRACKING 2516 #define SCI_GETSCROLLWIDTHTRACKING 2517 #define SCI_TEXTWIDTH 2276 #define SCI_SETENDATLASTLINE 2277 #define SCI_GETENDATLASTLINE 2278 #define SCI_TEXTHEIGHT 2279 #define SCI_SETVSCROLLBAR 2280 #define SCI_GETVSCROLLBAR 2281 #define SCI_APPENDTEXT 2282 #define SCI_GETTWOPHASEDRAW 2283 #define SCI_SETTWOPHASEDRAW 2284 #define SC_EFF_QUALITY_MASK 0xF #define SC_EFF_QUALITY_DEFAULT 0 #define SC_EFF_QUALITY_NON_ANTIALIASED 1 #define SC_EFF_QUALITY_ANTIALIASED 2 #define SC_EFF_QUALITY_LCD_OPTIMIZED 3 #define SCI_SETFONTQUALITY 2611 #define SCI_GETFONTQUALITY 2612 #define SCI_SETFIRSTVISIBLELINE 2613 #define SC_MULTIPASTE_ONCE 0 #define SC_MULTIPASTE_EACH 1 #define SCI_SETMULTIPASTE 2614 #define SCI_GETMULTIPASTE 2615 #define SCI_GETTAG 2616 #define SCI_TARGETFROMSELECTION 2287 #define SCI_LINESJOIN 2288 #define SCI_LINESSPLIT 2289 #define SCI_SETFOLDMARGINCOLOUR 2290 #define SCI_SETFOLDMARGINHICOLOUR 2291 #define SCI_LINEDOWN 2300 #define SCI_LINEDOWNEXTEND 2301 #define SCI_LINEUP 2302 #define SCI_LINEUPEXTEND 2303 #define SCI_CHARLEFT 2304 #define SCI_CHARLEFTEXTEND 2305 #define SCI_CHARRIGHT 2306 #define SCI_CHARRIGHTEXTEND 2307 #define SCI_WORDLEFT 2308 #define SCI_WORDLEFTEXTEND 2309 #define SCI_WORDRIGHT 2310 #define SCI_WORDRIGHTEXTEND 2311 #define SCI_HOME 2312 #define SCI_HOMEEXTEND 2313 #define SCI_LINEEND 2314 #define SCI_LINEENDEXTEND 2315 #define SCI_DOCUMENTSTART 2316 #define SCI_DOCUMENTSTARTEXTEND 2317 #define SCI_DOCUMENTEND 2318 #define SCI_DOCUMENTENDEXTEND 2319 #define SCI_PAGEUP 2320 #define SCI_PAGEUPEXTEND 2321 #define SCI_PAGEDOWN 2322 #define SCI_PAGEDOWNEXTEND 2323 #define SCI_EDITTOGGLEOVERTYPE 2324 #define SCI_CANCEL 2325 #define SCI_DELETEBACK 2326 #define SCI_TAB 2327 #define SCI_BACKTAB 2328 #define SCI_NEWLINE 2329 #define SCI_FORMFEED 2330 #define SCI_VCHOME 2331 #define SCI_VCHOMEEXTEND 2332 #define SCI_ZOOMIN 2333 #define SCI_ZOOMOUT 2334 #define SCI_DELWORDLEFT 2335 #define SCI_DELWORDRIGHT 2336 #define SCI_DELWORDRIGHTEND 2518 #define SCI_LINECUT 2337 #define SCI_LINEDELETE 2338 #define SCI_LINETRANSPOSE 2339 #define SCI_LINEDUPLICATE 2404 #define SCI_LOWERCASE 2340 #define SCI_UPPERCASE 2341 #define SCI_LINESCROLLDOWN 2342 #define SCI_LINESCROLLUP 2343 #define SCI_DELETEBACKNOTLINE 2344 #define SCI_HOMEDISPLAY 2345 #define SCI_HOMEDISPLAYEXTEND 2346 #define SCI_LINEENDDISPLAY 2347 #define SCI_LINEENDDISPLAYEXTEND 2348 #define SCI_HOMEWRAP 2349 #define SCI_HOMEWRAPEXTEND 2450 #define SCI_LINEENDWRAP 2451 #define SCI_LINEENDWRAPEXTEND 2452 #define SCI_VCHOMEWRAP 2453 #define SCI_VCHOMEWRAPEXTEND 2454 #define SCI_LINECOPY 2455 #define SCI_MOVECARETINSIDEVIEW 2401 #define SCI_LINELENGTH 2350 #define SCI_BRACEHIGHLIGHT 2351 #define SCI_BRACEHIGHLIGHTINDICATOR 2498 #define SCI_BRACEBADLIGHT 2352 #define SCI_BRACEBADLIGHTINDICATOR 2499 #define SCI_BRACEMATCH 2353 #define SCI_GETVIEWEOL 2355 #define SCI_SETVIEWEOL 2356 #define SCI_GETDOCPOINTER 2357 #define SCI_SETDOCPOINTER 2358 #define SCI_SETMODEVENTMASK 2359 #define EDGE_NONE 0 #define EDGE_LINE 1 #define EDGE_BACKGROUND 2 #define SCI_GETEDGECOLUMN 2360 #define SCI_SETEDGECOLUMN 2361 #define SCI_GETEDGEMODE 2362 #define SCI_SETEDGEMODE 2363 #define SCI_GETEDGECOLOUR 2364 #define SCI_SETEDGECOLOUR 2365 #define SCI_SEARCHANCHOR 2366 #define SCI_SEARCHNEXT 2367 #define SCI_SEARCHPREV 2368 #define SCI_LINESONSCREEN 2370 #define SCI_USEPOPUP 2371 #define SCI_SELECTIONISRECTANGLE 2372 #define SCI_SETZOOM 2373 #define SCI_GETZOOM 2374 #define SCI_CREATEDOCUMENT 2375 #define SCI_ADDREFDOCUMENT 2376 #define SCI_RELEASEDOCUMENT 2377 #define SCI_GETMODEVENTMASK 2378 #define SCI_SETFOCUS 2380 #define SCI_GETFOCUS 2381 #define SC_STATUS_OK 0 #define SC_STATUS_FAILURE 1 #define SC_STATUS_BADALLOC 2 #define SCI_SETSTATUS 2382 #define SCI_GETSTATUS 2383 #define SCI_SETMOUSEDOWNCAPTURES 2384 #define SCI_GETMOUSEDOWNCAPTURES 2385 #define SC_CURSORNORMAL -1 #define SC_CURSORARROW 2 #define SC_CURSORWAIT 4 #define SC_CURSORREVERSEARROW 7 #define SCI_SETCURSOR 2386 #define SCI_GETCURSOR 2387 #define SCI_SETCONTROLCHARSYMBOL 2388 #define SCI_GETCONTROLCHARSYMBOL 2389 #define SCI_WORDPARTLEFT 2390 #define SCI_WORDPARTLEFTEXTEND 2391 #define SCI_WORDPARTRIGHT 2392 #define SCI_WORDPARTRIGHTEXTEND 2393 #define VISIBLE_SLOP 0x01 #define VISIBLE_STRICT 0x04 #define SCI_SETVISIBLEPOLICY 2394 #define SCI_DELLINELEFT 2395 #define SCI_DELLINERIGHT 2396 #define SCI_SETXOFFSET 2397 #define SCI_GETXOFFSET 2398 #define SCI_CHOOSECARETX 2399 #define SCI_GRABFOCUS 2400 #define CARET_SLOP 0x01 #define CARET_STRICT 0x04 #define CARET_JUMPS 0x10 #define CARET_EVEN 0x08 #define SCI_SETXCARETPOLICY 2402 #define SCI_SETYCARETPOLICY 2403 #define SCI_SETPRINTWRAPMODE 2406 #define SCI_GETPRINTWRAPMODE 2407 #define SCI_SETHOTSPOTACTIVEFORE 2410 #define SCI_GETHOTSPOTACTIVEFORE 2494 #define SCI_SETHOTSPOTACTIVEBACK 2411 #define SCI_GETHOTSPOTACTIVEBACK 2495 #define SCI_SETHOTSPOTACTIVEUNDERLINE 2412 #define SCI_GETHOTSPOTACTIVEUNDERLINE 2496 #define SCI_SETHOTSPOTSINGLELINE 2421 #define SCI_GETHOTSPOTSINGLELINE 2497 #define SCI_PARADOWN 2413 #define SCI_PARADOWNEXTEND 2414 #define SCI_PARAUP 2415 #define SCI_PARAUPEXTEND 2416 #define SCI_POSITIONBEFORE 2417 #define SCI_POSITIONAFTER 2418 #define SCI_COPYRANGE 2419 #define SCI_COPYTEXT 2420 #define SC_SEL_STREAM 0 #define SC_SEL_RECTANGLE 1 #define SC_SEL_LINES 2 #define SC_SEL_THIN 3 #define SCI_SETSELECTIONMODE 2422 #define SCI_GETSELECTIONMODE 2423 #define SCI_GETLINESELSTARTPOSITION 2424 #define SCI_GETLINESELENDPOSITION 2425 #define SCI_LINEDOWNRECTEXTEND 2426 #define SCI_LINEUPRECTEXTEND 2427 #define SCI_CHARLEFTRECTEXTEND 2428 #define SCI_CHARRIGHTRECTEXTEND 2429 #define SCI_HOMERECTEXTEND 2430 #define SCI_VCHOMERECTEXTEND 2431 #define SCI_LINEENDRECTEXTEND 2432 #define SCI_PAGEUPRECTEXTEND 2433 #define SCI_PAGEDOWNRECTEXTEND 2434 #define SCI_STUTTEREDPAGEUP 2435 #define SCI_STUTTEREDPAGEUPEXTEND 2436 #define SCI_STUTTEREDPAGEDOWN 2437 #define SCI_STUTTEREDPAGEDOWNEXTEND 2438 #define SCI_WORDLEFTEND 2439 #define SCI_WORDLEFTENDEXTEND 2440 #define SCI_WORDRIGHTEND 2441 #define SCI_WORDRIGHTENDEXTEND 2442 #define SCI_SETWHITESPACECHARS 2443 #define SCI_SETCHARSDEFAULT 2444 #define SCI_AUTOCGETCURRENT 2445 #define SCI_AUTOCGETCURRENTTEXT 2610 #define SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE 0 #define SC_CASEINSENSITIVEBEHAVIOUR_IGNORECASE 1 #define SCI_AUTOCSETCASEINSENSITIVEBEHAVIOUR 2634 #define SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR 2635 #define SCI_ALLOCATE 2446 #define SCI_TARGETASUTF8 2447 #define SCI_SETLENGTHFORENCODE 2448 #define SCI_ENCODEDFROMUTF8 2449 #define SCI_FINDCOLUMN 2456 #define SCI_GETCARETSTICKY 2457 #define SCI_SETCARETSTICKY 2458 #define SC_CARETSTICKY_OFF 0 #define SC_CARETSTICKY_ON 1 #define SC_CARETSTICKY_WHITESPACE 2 #define SCI_TOGGLECARETSTICKY 2459 #define SCI_SETPASTECONVERTENDINGS 2467 #define SCI_GETPASTECONVERTENDINGS 2468 #define SCI_SELECTIONDUPLICATE 2469 #define SC_ALPHA_TRANSPARENT 0 #define SC_ALPHA_OPAQUE 255 #define SC_ALPHA_NOALPHA 256 #define SCI_SETCARETLINEBACKALPHA 2470 #define SCI_GETCARETLINEBACKALPHA 2471 #define CARETSTYLE_INVISIBLE 0 #define CARETSTYLE_LINE 1 #define CARETSTYLE_BLOCK 2 #define SCI_SETCARETSTYLE 2512 #define SCI_GETCARETSTYLE 2513 #define SCI_SETINDICATORCURRENT 2500 #define SCI_GETINDICATORCURRENT 2501 #define SCI_SETINDICATORVALUE 2502 #define SCI_GETINDICATORVALUE 2503 #define SCI_INDICATORFILLRANGE 2504 #define SCI_INDICATORCLEARRANGE 2505 #define SCI_INDICATORALLONFOR 2506 #define SCI_INDICATORVALUEAT 2507 #define SCI_INDICATORSTART 2508 #define SCI_INDICATOREND 2509 #define SCI_SETPOSITIONCACHE 2514 #define SCI_GETPOSITIONCACHE 2515 #define SCI_COPYALLOWLINE 2519 #define SCI_GETCHARACTERPOINTER 2520 #define SCI_GETRANGEPOINTER 2643 #define SCI_GETGAPPOSITION 2644 #define SCI_SETKEYSUNICODE 2521 #define SCI_GETKEYSUNICODE 2522 #define SCI_INDICSETALPHA 2523 #define SCI_INDICGETALPHA 2524 #define SCI_INDICSETOUTLINEALPHA 2558 #define SCI_INDICGETOUTLINEALPHA 2559 #define SCI_SETEXTRAASCENT 2525 #define SCI_GETEXTRAASCENT 2526 #define SCI_SETEXTRADESCENT 2527 #define SCI_GETEXTRADESCENT 2528 #define SCI_MARKERSYMBOLDEFINED 2529 #define SCI_MARGINSETTEXT 2530 #define SCI_MARGINGETTEXT 2531 #define SCI_MARGINSETSTYLE 2532 #define SCI_MARGINGETSTYLE 2533 #define SCI_MARGINSETSTYLES 2534 #define SCI_MARGINGETSTYLES 2535 #define SCI_MARGINTEXTCLEARALL 2536 #define SCI_MARGINSETSTYLEOFFSET 2537 #define SCI_MARGINGETSTYLEOFFSET 2538 #define SC_MARGINOPTION_NONE 0 #define SC_MARGINOPTION_SUBLINESELECT 1 #define SCI_SETMARGINOPTIONS 2539 #define SCI_GETMARGINOPTIONS 2557 #define SCI_ANNOTATIONSETTEXT 2540 #define SCI_ANNOTATIONGETTEXT 2541 #define SCI_ANNOTATIONSETSTYLE 2542 #define SCI_ANNOTATIONGETSTYLE 2543 #define SCI_ANNOTATIONSETSTYLES 2544 #define SCI_ANNOTATIONGETSTYLES 2545 #define SCI_ANNOTATIONGETLINES 2546 #define SCI_ANNOTATIONCLEARALL 2547 #define ANNOTATION_HIDDEN 0 #define ANNOTATION_STANDARD 1 #define ANNOTATION_BOXED 2 #define SCI_ANNOTATIONSETVISIBLE 2548 #define SCI_ANNOTATIONGETVISIBLE 2549 #define SCI_ANNOTATIONSETSTYLEOFFSET 2550 #define SCI_ANNOTATIONGETSTYLEOFFSET 2551 #define UNDO_MAY_COALESCE 1 #define SCI_ADDUNDOACTION 2560 #define SCI_CHARPOSITIONFROMPOINT 2561 #define SCI_CHARPOSITIONFROMPOINTCLOSE 2562 #define SCI_SETMULTIPLESELECTION 2563 #define SCI_GETMULTIPLESELECTION 2564 #define SCI_SETADDITIONALSELECTIONTYPING 2565 #define SCI_GETADDITIONALSELECTIONTYPING 2566 #define SCI_SETADDITIONALCARETSBLINK 2567 #define SCI_GETADDITIONALCARETSBLINK 2568 #define SCI_SETADDITIONALCARETSVISIBLE 2608 #define SCI_GETADDITIONALCARETSVISIBLE 2609 #define SCI_GETSELECTIONS 2570 #define SCI_CLEARSELECTIONS 2571 #define SCI_SETSELECTION 2572 #define SCI_ADDSELECTION 2573 #define SCI_SETMAINSELECTION 2574 #define SCI_GETMAINSELECTION 2575 #define SCI_SETSELECTIONNCARET 2576 #define SCI_GETSELECTIONNCARET 2577 #define SCI_SETSELECTIONNANCHOR 2578 #define SCI_GETSELECTIONNANCHOR 2579 #define SCI_SETSELECTIONNCARETVIRTUALSPACE 2580 #define SCI_GETSELECTIONNCARETVIRTUALSPACE 2581 #define SCI_SETSELECTIONNANCHORVIRTUALSPACE 2582 #define SCI_GETSELECTIONNANCHORVIRTUALSPACE 2583 #define SCI_SETSELECTIONNSTART 2584 #define SCI_GETSELECTIONNSTART 2585 #define SCI_SETSELECTIONNEND 2586 #define SCI_GETSELECTIONNEND 2587 #define SCI_SETRECTANGULARSELECTIONCARET 2588 #define SCI_GETRECTANGULARSELECTIONCARET 2589 #define SCI_SETRECTANGULARSELECTIONANCHOR 2590 #define SCI_GETRECTANGULARSELECTIONANCHOR 2591 #define SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE 2592 #define SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE 2593 #define SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE 2594 #define SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE 2595 #define SCVS_NONE 0 #define SCVS_RECTANGULARSELECTION 1 #define SCVS_USERACCESSIBLE 2 #define SCI_SETVIRTUALSPACEOPTIONS 2596 #define SCI_GETVIRTUALSPACEOPTIONS 2597 #define SCI_SETRECTANGULARSELECTIONMODIFIER 2598 #define SCI_GETRECTANGULARSELECTIONMODIFIER 2599 #define SCI_SETADDITIONALSELFORE 2600 #define SCI_SETADDITIONALSELBACK 2601 #define SCI_SETADDITIONALSELALPHA 2602 #define SCI_GETADDITIONALSELALPHA 2603 #define SCI_SETADDITIONALCARETFORE 2604 #define SCI_GETADDITIONALCARETFORE 2605 #define SCI_ROTATESELECTION 2606 #define SCI_SWAPMAINANCHORCARET 2607 #define SCI_CHANGELEXERSTATE 2617 #define SCI_CONTRACTEDFOLDNEXT 2618 #define SCI_VERTICALCENTRECARET 2619 #define SCI_MOVESELECTEDLINESUP 2620 #define SCI_MOVESELECTEDLINESDOWN 2621 #define SCI_SETIDENTIFIER 2622 #define SCI_GETIDENTIFIER 2623 #define SCI_RGBAIMAGESETWIDTH 2624 #define SCI_RGBAIMAGESETHEIGHT 2625 #define SCI_MARKERDEFINERGBAIMAGE 2626 #define SCI_REGISTERRGBAIMAGE 2627 #define SCI_SCROLLTOSTART 2628 #define SCI_SCROLLTOEND 2629 #define SC_TECHNOLOGY_DEFAULT 0 #define SC_TECHNOLOGY_DIRECTWRITE 1 #define SCI_SETTECHNOLOGY 2630 #define SCI_GETTECHNOLOGY 2631 #define SCI_CREATELOADER 2632 #define SCI_FINDINDICATORSHOW 2640 #define SCI_FINDINDICATORFLASH 2641 #define SCI_FINDINDICATORHIDE 2642 #define SCI_STARTRECORD 3001 #define SCI_STOPRECORD 3002 #define SCI_SETLEXER 4001 #define SCI_GETLEXER 4002 #define SCI_COLOURISE 4003 #define SCI_SETPROPERTY 4004 #define KEYWORDSET_MAX 8 #define SCI_SETKEYWORDS 4005 #define SCI_SETLEXERLANGUAGE 4006 #define SCI_LOADLEXERLIBRARY 4007 #define SCI_GETPROPERTY 4008 #define SCI_GETPROPERTYEXPANDED 4009 #define SCI_GETPROPERTYINT 4010 #define SCI_GETSTYLEBITSNEEDED 4011 #define SCI_GETLEXERLANGUAGE 4012 #define SCI_PRIVATELEXERCALL 4013 #define SCI_PROPERTYNAMES 4014 #define SC_TYPE_BOOLEAN 0 #define SC_TYPE_INTEGER 1 #define SC_TYPE_STRING 2 #define SCI_PROPERTYTYPE 4015 #define SCI_DESCRIBEPROPERTY 4016 #define SCI_DESCRIBEKEYWORDSETS 4017 #define SC_MOD_INSERTTEXT 0x1 #define SC_MOD_DELETETEXT 0x2 #define SC_MOD_CHANGESTYLE 0x4 #define SC_MOD_CHANGEFOLD 0x8 #define SC_PERFORMED_USER 0x10 #define SC_PERFORMED_UNDO 0x20 #define SC_PERFORMED_REDO 0x40 #define SC_MULTISTEPUNDOREDO 0x80 #define SC_LASTSTEPINUNDOREDO 0x100 #define SC_MOD_CHANGEMARKER 0x200 #define SC_MOD_BEFOREINSERT 0x400 #define SC_MOD_BEFOREDELETE 0x800 #define SC_MULTILINEUNDOREDO 0x1000 #define SC_STARTACTION 0x2000 #define SC_MOD_CHANGEINDICATOR 0x4000 #define SC_MOD_CHANGELINESTATE 0x8000 #define SC_MOD_CHANGEMARGIN 0x10000 #define SC_MOD_CHANGEANNOTATION 0x20000 #define SC_MOD_CONTAINER 0x40000 #define SC_MOD_LEXERSTATE 0x80000 #define SC_MODEVENTMASKALL 0xFFFFF #define SC_UPDATE_CONTENT 0x1 #define SC_UPDATE_SELECTION 0x2 #define SC_UPDATE_V_SCROLL 0x4 #define SC_UPDATE_H_SCROLL 0x8 #define SCEN_CHANGE 768 #define SCEN_SETFOCUS 512 #define SCEN_KILLFOCUS 256 #define SCK_DOWN 300 #define SCK_UP 301 #define SCK_LEFT 302 #define SCK_RIGHT 303 #define SCK_HOME 304 #define SCK_END 305 #define SCK_PRIOR 306 #define SCK_NEXT 307 #define SCK_DELETE 308 #define SCK_INSERT 309 #define SCK_ESCAPE 7 #define SCK_BACK 8 #define SCK_TAB 9 #define SCK_RETURN 13 #define SCK_ADD 310 #define SCK_SUBTRACT 311 #define SCK_DIVIDE 312 #define SCK_WIN 313 #define SCK_RWIN 314 #define SCK_MENU 315 #define SCMOD_NORM 0 #define SCMOD_SHIFT 1 #define SCMOD_CTRL 2 #define SCMOD_ALT 4 #define SCMOD_SUPER 8 #define SCMOD_META 16 #define SCN_STYLENEEDED 2000 #define SCN_CHARADDED 2001 #define SCN_SAVEPOINTREACHED 2002 #define SCN_SAVEPOINTLEFT 2003 #define SCN_MODIFYATTEMPTRO 2004 #define SCN_KEY 2005 #define SCN_DOUBLECLICK 2006 #define SCN_UPDATEUI 2007 #define SCN_MODIFIED 2008 #define SCN_MACRORECORD 2009 #define SCN_MARGINCLICK 2010 #define SCN_NEEDSHOWN 2011 #define SCN_PAINTED 2013 #define SCN_USERLISTSELECTION 2014 #define SCN_URIDROPPED 2015 #define SCN_DWELLSTART 2016 #define SCN_DWELLEND 2017 #define SCN_ZOOM 2018 #define SCN_HOTSPOTCLICK 2019 #define SCN_HOTSPOTDOUBLECLICK 2020 #define SCN_CALLTIPCLICK 2021 #define SCN_AUTOCSELECTION 2022 #define SCN_INDICATORCLICK 2023 #define SCN_INDICATORRELEASE 2024 #define SCN_AUTOCCANCELLED 2025 #define SCN_AUTOCCHARDELETED 2026 #define SCN_HOTSPOTRELEASECLICK 2027 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ /* These structures are defined to be exactly the same shape as the Win32 * CHARRANGE, TEXTRANGE, FINDTEXTEX, FORMATRANGE, and NMHDR structs. * So older code that treats Scintilla as a RichEdit will work. */ #ifdef SCI_NAMESPACE namespace Scintilla { #endif struct Sci_CharacterRange { long cpMin; long cpMax; }; struct Sci_TextRange { struct Sci_CharacterRange chrg; char *lpstrText; }; struct Sci_TextToFind { struct Sci_CharacterRange chrg; char *lpstrText; struct Sci_CharacterRange chrgText; }; #define CharacterRange Sci_CharacterRange #define TextRange Sci_TextRange #define TextToFind Sci_TextToFind typedef void *Sci_SurfaceID; struct Sci_Rectangle { int left; int top; int right; int bottom; }; /* This structure is used in printing and requires some of the graphics types * from Platform.h. Not needed by most client code. */ struct Sci_RangeToFormat { Sci_SurfaceID hdc; Sci_SurfaceID hdcTarget; struct Sci_Rectangle rc; struct Sci_Rectangle rcPage; struct Sci_CharacterRange chrg; }; #define RangeToFormat Sci_RangeToFormat struct Sci_NotifyHeader { /* Compatible with Windows NMHDR. * hwndFrom is really an environment specific window handle or pointer * but most clients of Scintilla.h do not have this type visible. */ void *hwndFrom; uptr_t idFrom; unsigned int code; }; #define NotifyHeader Sci_NotifyHeader struct SCNotification { struct Sci_NotifyHeader nmhdr; int position; /* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */ /* SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, SCN_CALLTIPCLICK, */ /* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */ /* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */ /* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */ int ch; /* SCN_CHARADDED, SCN_KEY */ int modifiers; /* SCN_KEY, SCN_DOUBLECLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */ /* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */ int modificationType; /* SCN_MODIFIED */ const char *text; /* SCN_MODIFIED, SCN_USERLISTSELECTION, SCN_AUTOCSELECTION, SCN_URIDROPPED */ int length; /* SCN_MODIFIED */ int linesAdded; /* SCN_MODIFIED */ int message; /* SCN_MACRORECORD */ uptr_t wParam; /* SCN_MACRORECORD */ sptr_t lParam; /* SCN_MACRORECORD */ int line; /* SCN_MODIFIED */ int foldLevelNow; /* SCN_MODIFIED */ int foldLevelPrev; /* SCN_MODIFIED */ int margin; /* SCN_MARGINCLICK */ int listType; /* SCN_USERLISTSELECTION */ int x; /* SCN_DWELLSTART, SCN_DWELLEND */ int y; /* SCN_DWELLSTART, SCN_DWELLEND */ int token; /* SCN_MODIFIED with SC_MOD_CONTAINER */ int annotationLinesAdded; /* SCN_MODIFIED with SC_MOD_CHANGEANNOTATION */ int updated; /* SCN_UPDATEUI */ }; #ifdef SCI_NAMESPACE } #endif #ifdef INCLUDE_DEPRECATED_FEATURES #define SC_CP_DBCS 1 #define SCI_SETUSEPALETTE 2039 #define SCI_GETUSEPALETTE 2139 #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/include/ScintillaWidget.h0000644000175000017500000000257311615412040022512 00000000000000/* Scintilla source code edit control */ /** @file ScintillaWidget.h ** Definition of Scintilla widget for GTK+. ** Only needed by GTK+ code but is harmless on other platforms. **/ /* Copyright 1998-2001 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ #ifndef SCINTILLAWIDGET_H #define SCINTILLAWIDGET_H #if defined(GTK) #ifdef __cplusplus extern "C" { #endif #define SCINTILLA(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, scintilla_get_type (), ScintillaObject) #define SCINTILLA_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, scintilla_get_type (), ScintillaClass) #define IS_SCINTILLA(obj) GTK_CHECK_TYPE (obj, scintilla_get_type ()) typedef struct _ScintillaObject ScintillaObject; typedef struct _ScintillaClass ScintillaClass; struct _ScintillaObject { GtkContainer cont; void *pscin; }; struct _ScintillaClass { GtkContainerClass parent_class; void (* command) (ScintillaObject *ttt); void (* notify) (ScintillaObject *ttt); }; GType scintilla_get_type (void); GtkWidget* scintilla_new (void); void scintilla_set_id (ScintillaObject *sci, uptr_t id); sptr_t scintilla_send_message (ScintillaObject *sci,unsigned int iMessage, uptr_t wParam, sptr_t lParam); void scintilla_release_resources(void); #define SCINTILLA_NOTIFY "sci-notify" #ifdef __cplusplus } #endif #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/include/Platform.h0000644000175000017500000003361211763437013021221 00000000000000// Scintilla source code edit control /** @file Platform.h ** Interface to platform facilities. Also includes some basic utilities. ** Implemented in PlatGTK.cxx for GTK+/Linux, PlatWin.cxx for Windows, and PlatWX.cxx for wxWindows. **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PLATFORM_H #define PLATFORM_H // PLAT_GTK = GTK+ on Linux or Win32 // PLAT_GTK_WIN32 is defined additionally when running PLAT_GTK under Win32 // PLAT_WIN = Win32 API on Win32 OS // PLAT_WX is wxWindows on any supported platform #define PLAT_GTK 0 #define PLAT_GTK_WIN32 0 #define PLAT_GTK_MACOSX 0 #define PLAT_MACOSX 0 #define PLAT_WIN 0 #define PLAT_WX 0 #define PLAT_QT 0 #define PLAT_FOX 0 #if defined(FOX) #undef PLAT_FOX #define PLAT_FOX 1 #elif defined(__WX__) #undef PLAT_WX #define PLAT_WX 1 #elif defined(GTK) #undef PLAT_GTK #define PLAT_GTK 1 #elif defined(SCINTILLA_QT) #undef PLAT_QT #define PLAT_QT 1 #if defined(__WIN32__) || defined(_MSC_VER) #undef PLAT_GTK_WIN32 #define PLAT_GTK_WIN32 1 #endif #if defined(__APPLE__) #undef PLAT_GTK_MACOSX #define PLAT_GTK_MACOSX 1 #endif #elif defined(__APPLE__) #undef PLAT_MACOSX #define PLAT_MACOSX 1 #else #undef PLAT_WIN #define PLAT_WIN 1 #endif #ifdef SCI_NAMESPACE namespace Scintilla { #endif typedef float XYPOSITION; typedef double XYACCUMULATOR; //#define XYPOSITION int // Underlying the implementation of the platform classes are platform specific types. // Sometimes these need to be passed around by client code so they are defined here typedef void *FontID; typedef void *SurfaceID; typedef void *WindowID; typedef void *MenuID; typedef void *TickerID; typedef void *Function; typedef void *IdlerID; /** * A geometric point class. * Point is exactly the same as the Win32 POINT and GTK+ GdkPoint so can be used interchangeably. */ class Point { public: XYPOSITION x; XYPOSITION y; explicit Point(XYPOSITION x_=0, XYPOSITION y_=0) : x(x_), y(y_) { } // Other automatically defined methods (assignment, copy constructor, destructor) are fine static Point FromLong(long lpoint); }; /** * A geometric rectangle class. * PRectangle is exactly the same as the Win32 RECT so can be used interchangeably. * PRectangles contain their top and left sides, but not their right and bottom sides. */ class PRectangle { public: XYPOSITION left; XYPOSITION top; XYPOSITION right; XYPOSITION bottom; PRectangle(XYPOSITION left_=0, XYPOSITION top_=0, XYPOSITION right_=0, XYPOSITION bottom_ = 0) : left(left_), top(top_), right(right_), bottom(bottom_) { } // Other automatically defined methods (assignment, copy constructor, destructor) are fine bool operator==(PRectangle &rc) { return (rc.left == left) && (rc.right == right) && (rc.top == top) && (rc.bottom == bottom); } bool Contains(Point pt) { return (pt.x >= left) && (pt.x <= right) && (pt.y >= top) && (pt.y <= bottom); } bool Contains(PRectangle rc) { return (rc.left >= left) && (rc.right <= right) && (rc.top >= top) && (rc.bottom <= bottom); } bool Intersects(PRectangle other) { return (right > other.left) && (left < other.right) && (bottom > other.top) && (top < other.bottom); } void Move(XYPOSITION xDelta, XYPOSITION yDelta) { left += xDelta; top += yDelta; right += xDelta; bottom += yDelta; } XYPOSITION Width() { return right - left; } XYPOSITION Height() { return bottom - top; } bool Empty() { return (Height() <= 0) || (Width() <= 0); } }; /** * Holds a desired RGB colour. */ class ColourDesired { long co; public: ColourDesired(long lcol=0) { co = lcol; } ColourDesired(unsigned int red, unsigned int green, unsigned int blue) { Set(red, green, blue); } bool operator==(const ColourDesired &other) const { return co == other.co; } void Set(long lcol) { co = lcol; } void Set(unsigned int red, unsigned int green, unsigned int blue) { co = red | (green << 8) | (blue << 16); } static inline unsigned int ValueOfHex(const char ch) { if (ch >= '0' && ch <= '9') return ch - '0'; else if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; else if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; else return 0; } void Set(const char *val) { if (*val == '#') { val++; } unsigned int r = ValueOfHex(val[0]) * 16 + ValueOfHex(val[1]); unsigned int g = ValueOfHex(val[2]) * 16 + ValueOfHex(val[3]); unsigned int b = ValueOfHex(val[4]) * 16 + ValueOfHex(val[5]); Set(r, g, b); } long AsLong() const { return co; } unsigned int GetRed() { return co & 0xff; } unsigned int GetGreen() { return (co >> 8) & 0xff; } unsigned int GetBlue() { return (co >> 16) & 0xff; } }; /** * Font management. */ struct FontParameters { const char *faceName; float size; int weight; bool italic; int extraFontFlag; int technology; int characterSet; FontParameters( const char *faceName_, float size_=10, int weight_=400, bool italic_=false, int extraFontFlag_=0, int technology_=0, int characterSet_=0) : faceName(faceName_), size(size_), weight(weight_), italic(italic_), extraFontFlag(extraFontFlag_), technology(technology_), characterSet(characterSet_) { } }; class Font { protected: FontID fid; #if PLAT_WX int ascent; #endif // Private so Font objects can not be copied Font(const Font &); Font &operator=(const Font &); public: Font(); virtual ~Font(); virtual void Create(const FontParameters &fp); virtual void Release(); FontID GetID() { return fid; } // Alias another font - caller guarantees not to Release void SetID(FontID fid_) { fid = fid_; } #if PLAT_WX void SetAscent(int ascent_) { ascent = ascent_; } #endif friend class Surface; friend class SurfaceImpl; }; /** * A surface abstracts a place to draw. */ class Surface { private: // Private so Surface objects can not be copied Surface(const Surface &) {} Surface &operator=(const Surface &) { return *this; } public: Surface() {} virtual ~Surface() {} static Surface *Allocate(int technology); virtual void Init(WindowID wid)=0; virtual void Init(SurfaceID sid, WindowID wid)=0; virtual void InitPixMap(int width, int height, Surface *surface_, WindowID wid)=0; virtual void Release()=0; virtual bool Initialised()=0; virtual void PenColour(ColourDesired fore)=0; virtual int LogPixelsY()=0; virtual int DeviceHeightFont(int points)=0; virtual void MoveTo(int x_, int y_)=0; virtual void LineTo(int x_, int y_)=0; virtual void Polygon(Point *pts, int npts, ColourDesired fore, ColourDesired back)=0; virtual void RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back)=0; virtual void FillRectangle(PRectangle rc, ColourDesired back)=0; virtual void FillRectangle(PRectangle rc, Surface &surfacePattern)=0; virtual void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back)=0; virtual void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill, ColourDesired outline, int alphaOutline, int flags)=0; virtual void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) = 0; virtual void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back)=0; virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0; virtual void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0; virtual void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0; virtual void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore)=0; virtual void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions)=0; virtual XYPOSITION WidthText(Font &font_, const char *s, int len)=0; virtual XYPOSITION WidthChar(Font &font_, char ch)=0; virtual XYPOSITION Ascent(Font &font_)=0; virtual XYPOSITION Descent(Font &font_)=0; virtual XYPOSITION InternalLeading(Font &font_)=0; virtual XYPOSITION ExternalLeading(Font &font_)=0; virtual XYPOSITION Height(Font &font_)=0; virtual XYPOSITION AverageCharWidth(Font &font_)=0; virtual void SetClip(PRectangle rc)=0; virtual void FlushCachedState()=0; virtual void SetUnicodeMode(bool unicodeMode_)=0; virtual void SetDBCSMode(int codePage)=0; }; /** * A simple callback action passing one piece of untyped user data. */ typedef void (*CallBackAction)(void*); /** * Class to hide the details of window manipulation. * Does not own the window which will normally have a longer life than this object. */ class Window { protected: WindowID wid; #if PLAT_MACOSX void *windowRef; void *control; #endif public: Window() : wid(0), cursorLast(cursorInvalid) { #if PLAT_MACOSX windowRef = 0; control = 0; #endif } Window(const Window &source) : wid(source.wid), cursorLast(cursorInvalid) { #if PLAT_MACOSX windowRef = 0; control = 0; #endif } virtual ~Window(); Window &operator=(WindowID wid_) { wid = wid_; return *this; } WindowID GetID() const { return wid; } bool Created() const { return wid != 0; } void Destroy(); bool HasFocus(); PRectangle GetPosition(); void SetPosition(PRectangle rc); void SetPositionRelative(PRectangle rc, Window relativeTo); PRectangle GetClientPosition(); void Show(bool show=true); void InvalidateAll(); void InvalidateRectangle(PRectangle rc); virtual void SetFont(Font &font); enum Cursor { cursorInvalid, cursorText, cursorArrow, cursorUp, cursorWait, cursorHoriz, cursorVert, cursorReverseArrow, cursorHand }; void SetCursor(Cursor curs); void SetTitle(const char *s); PRectangle GetMonitorRect(Point pt); #if PLAT_MACOSX void SetWindow(void *ref) { windowRef = ref; } void SetControl(void *_control) { control = _control; } #endif private: Cursor cursorLast; }; /** * Listbox management. */ class ListBox : public Window { public: ListBox(); virtual ~ListBox(); static ListBox *Allocate(); virtual void SetFont(Font &font)=0; virtual void Create(Window &parent, int ctrlID, Point location, int lineHeight_, bool unicodeMode_, int technology_)=0; virtual void SetAverageCharWidth(int width)=0; virtual void SetVisibleRows(int rows)=0; virtual int GetVisibleRows() const=0; virtual PRectangle GetDesiredRect()=0; virtual int CaretFromEdge()=0; virtual void Clear()=0; virtual void Append(char *s, int type = -1)=0; virtual int Length()=0; virtual void Select(int n)=0; virtual int GetSelection()=0; virtual int Find(const char *prefix)=0; virtual void GetValue(int n, char *value, int len)=0; virtual void RegisterImage(int type, const char *xpm_data)=0; virtual void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) = 0; virtual void ClearRegisteredImages()=0; virtual void SetDoubleClickAction(CallBackAction, void *)=0; virtual void SetList(const char* list, char separator, char typesep)=0; }; /** * Menu management. */ class Menu { MenuID mid; public: Menu(); MenuID GetID() { return mid; } void CreatePopUp(); void Destroy(); void Show(Point pt, Window &w); }; class ElapsedTime { long bigBit; long littleBit; public: ElapsedTime(); double Duration(bool reset=false); }; /** * Dynamic Library (DLL/SO/...) loading */ class DynamicLibrary { public: virtual ~DynamicLibrary() {} /// @return Pointer to function "name", or NULL on failure. virtual Function FindFunction(const char *name) = 0; /// @return true if the library was loaded successfully. virtual bool IsValid() = 0; /// @return An instance of a DynamicLibrary subclass with "modulePath" loaded. static DynamicLibrary *Load(const char *modulePath); }; /** * Platform class used to retrieve system wide parameters such as double click speed * and chrome colour. Not a creatable object, more of a module with several functions. */ class Platform { // Private so Platform objects can not be copied Platform(const Platform &) {} Platform &operator=(const Platform &) { return *this; } public: // Should be private because no new Platforms are ever created // but gcc warns about this Platform() {} ~Platform() {} static ColourDesired Chrome(); static ColourDesired ChromeHighlight(); static const char *DefaultFont(); static int DefaultFontSize(); static unsigned int DoubleClickTime(); static bool MouseButtonBounce(); static void DebugDisplay(const char *s); static bool IsKeyDown(int key); static long SendScintilla( WindowID w, unsigned int msg, unsigned long wParam=0, long lParam=0); static long SendScintillaPointer( WindowID w, unsigned int msg, unsigned long wParam=0, void *lParam=0); static bool IsDBCSLeadByte(int codePage, char ch); static int DBCSCharLength(int codePage, const char *s); static int DBCSCharMaxLength(); // These are utility functions not really tied to a platform static int Minimum(int a, int b); static int Maximum(int a, int b); // Next three assume 16 bit shorts and 32 bit longs static long LongFromTwoShorts(short a,short b) { return (a) | ((b) << 16); } static short HighShortFromLong(long x) { return static_cast(x >> 16); } static short LowShortFromLong(long x) { return static_cast(x & 0xffff); } static void DebugPrintf(const char *format, ...); static bool ShowAssertionPopUps(bool assertionPopUps_); static void Assert(const char *c, const char *file, int line); static int Clamp(int val, int minVal, int maxVal); }; #ifdef NDEBUG #define PLATFORM_ASSERT(c) ((void)0) #else #ifdef SCI_NAMESPACE #define PLATFORM_ASSERT(c) ((c) ? (void)(0) : Scintilla::Platform::Assert(#c, __FILE__, __LINE__)) #else #define PLATFORM_ASSERT(c) ((c) ? (void)(0) : Platform::Assert(#c, __FILE__, __LINE__)) #endif #endif #ifdef SCI_NAMESPACE } #endif // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER #pragma warning(disable: 4244 4309 4514 4710) #endif #if defined(__GNUC__) && defined(SCINTILLA_QT) #pragma GCC diagnostic ignored "-Wmissing-braces" #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #pragma GCC diagnostic ignored "-Wchar-subscripts" #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/include/ILexer.h0000644000175000017500000000546311652104216020621 00000000000000// Scintilla source code edit control /** @file ILexer.h ** Interface between Scintilla and lexers. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef ILEXER_H #define ILEXER_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif #ifdef _WIN32 #define SCI_METHOD __stdcall #else #define SCI_METHOD #endif enum { dvOriginal=0 }; class IDocument { public: virtual int SCI_METHOD Version() const = 0; virtual void SCI_METHOD SetErrorStatus(int status) = 0; virtual int SCI_METHOD Length() const = 0; virtual void SCI_METHOD GetCharRange(char *buffer, int position, int lengthRetrieve) const = 0; virtual char SCI_METHOD StyleAt(int position) const = 0; virtual int SCI_METHOD LineFromPosition(int position) const = 0; virtual int SCI_METHOD LineStart(int line) const = 0; virtual int SCI_METHOD GetLevel(int line) const = 0; virtual int SCI_METHOD SetLevel(int line, int level) = 0; virtual int SCI_METHOD GetLineState(int line) const = 0; virtual int SCI_METHOD SetLineState(int line, int state) = 0; virtual void SCI_METHOD StartStyling(int position, char mask) = 0; virtual bool SCI_METHOD SetStyleFor(int length, char style) = 0; virtual bool SCI_METHOD SetStyles(int length, const char *styles) = 0; virtual void SCI_METHOD DecorationSetCurrentIndicator(int indicator) = 0; virtual void SCI_METHOD DecorationFillRange(int position, int value, int fillLength) = 0; virtual void SCI_METHOD ChangeLexerState(int start, int end) = 0; virtual int SCI_METHOD CodePage() const = 0; virtual bool SCI_METHOD IsDBCSLeadByte(char ch) const = 0; virtual const char * SCI_METHOD BufferPointer() = 0; virtual int SCI_METHOD GetLineIndentation(int line) = 0; }; enum { lvOriginal=0 }; class ILexer { public: virtual int SCI_METHOD Version() const = 0; virtual void SCI_METHOD Release() = 0; virtual const char * SCI_METHOD PropertyNames() = 0; virtual int SCI_METHOD PropertyType(const char *name) = 0; virtual const char * SCI_METHOD DescribeProperty(const char *name) = 0; virtual int SCI_METHOD PropertySet(const char *key, const char *val) = 0; virtual const char * SCI_METHOD DescribeWordListSets() = 0; virtual int SCI_METHOD WordListSet(int n, const char *wl) = 0; virtual void SCI_METHOD Lex(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess) = 0; virtual void SCI_METHOD Fold(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess) = 0; virtual void * SCI_METHOD PrivateCall(int operation, void *pointer) = 0; }; class ILoader { public: virtual int SCI_METHOD Release() = 0; // Returns a status code from SC_STATUS_* virtual int SCI_METHOD AddData(char *data, int length) = 0; virtual void * SCI_METHOD ConvertToDocument() = 0; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/License.txt0000644000175000017500000000154411615412040017750 00000000000000License for Scintilla and SciTE Copyright 1998-2003 by Neil Hodgson All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/0000755000175000017500000000000011764714760017203 500000000000000presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/Accessor.h0000644000175000017500000000153111615412040021013 00000000000000// Scintilla source code edit control /** @file Accessor.h ** Interfaces between Scintilla and lexers. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef ACCESSOR_H #define ACCESSOR_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif enum { wsSpace = 1, wsTab = 2, wsSpaceTab = 4, wsInconsistent=8}; class Accessor; class WordList; class PropSetSimple; typedef bool (*PFNIsCommentLeader)(Accessor &styler, int pos, int len); class Accessor : public LexAccessor { public: PropSetSimple *pprops; Accessor(IDocument *pAccess_, PropSetSimple *pprops_); int GetPropertyInt(const char *, int defaultValue=0); int IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader = 0); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerBase.h0000644000175000017500000000234311615412040021125 00000000000000// Scintilla source code edit control /** @file LexerBase.h ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXERBASE_H #define LEXERBASE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif // A simple lexer with no state class LexerBase : public ILexer { protected: PropSetSimple props; enum {numWordLists=KEYWORDSET_MAX+1}; WordList *keyWordLists[numWordLists+1]; public: LexerBase(); virtual ~LexerBase(); void SCI_METHOD Release(); int SCI_METHOD Version() const; const char * SCI_METHOD PropertyNames(); int SCI_METHOD PropertyType(const char *name); const char * SCI_METHOD DescribeProperty(const char *name); int SCI_METHOD PropertySet(const char *key, const char *val); const char * SCI_METHOD DescribeWordListSets(); int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess) = 0; void SCI_METHOD Fold(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess) = 0; void * SCI_METHOD PrivateCall(int operation, void *pointer); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerNoExceptions.cxx0000644000175000017500000000374511615412040023253 00000000000000// Scintilla source code edit control /** @file LexerNoExceptions.cxx ** A simple lexer with no state which does not throw exceptions so can be used in an external lexer. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" #include "LexerNoExceptions.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif int SCI_METHOD LexerNoExceptions::PropertySet(const char *key, const char *val) { try { return LexerBase::PropertySet(key, val); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options } return -1; } int SCI_METHOD LexerNoExceptions::WordListSet(int n, const char *wl) { try { return LexerBase::WordListSet(n, wl); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options } return -1; } void SCI_METHOD LexerNoExceptions::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { try { Accessor astyler(pAccess, &props); Lexer(startPos, length, initStyle, pAccess, astyler); astyler.Flush(); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options pAccess->SetErrorStatus(SC_STATUS_FAILURE); } } void SCI_METHOD LexerNoExceptions::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { try { Accessor astyler(pAccess, &props); Folder(startPos, length, initStyle, pAccess, astyler); astyler.Flush(); } catch (...) { // Should not throw into caller as may be compiled with different compiler or options pAccess->SetErrorStatus(SC_STATUS_FAILURE); } } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/StyleContext.cxx0000644000175000017500000000232611615412040022274 00000000000000// Scintilla source code edit control /** @file StyleContext.cxx ** Lexer infrastructure. **/ // Copyright 1998-2004 by Neil Hodgson // This file is in the public domain. #include #include #include #include #include #include "ILexer.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static void getRange(unsigned int start, unsigned int end, LexAccessor &styler, char *s, unsigned int len) { unsigned int i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = styler[start + i]; i++; } s[i] = '\0'; } void StyleContext::GetCurrent(char *s, unsigned int len) { getRange(styler.GetStartSegment(), currentPos - 1, styler, s, len); } static void getRangeLowered(unsigned int start, unsigned int end, LexAccessor &styler, char *s, unsigned int len) { unsigned int i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = static_cast(tolower(styler[start + i])); i++; } s[i] = '\0'; } void StyleContext::GetCurrentLowered(char *s, unsigned int len) { getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len); } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/OptionSet.h0000644000175000017500000000664311615412040021206 00000000000000// Scintilla source code edit control /** @file OptionSet.h ** Manage descriptive information about an options struct for a lexer. ** Hold the names, positions, and descriptions of boolean, integer and string options and ** allow setting options and retrieving metadata about the options. **/ // Copyright 2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef OPTIONSET_H #define OPTIONSET_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif template class OptionSet { typedef T Target; typedef bool T::*plcob; typedef int T::*plcoi; typedef std::string T::*plcos; struct Option { int opType; union { plcob pb; plcoi pi; plcos ps; }; std::string description; Option() : opType(SC_TYPE_BOOLEAN), pb(0), description("") { } Option(plcob pb_, std::string description_="") : opType(SC_TYPE_BOOLEAN), pb(pb_), description(description_) { } Option(plcoi pi_, std::string description_) : opType(SC_TYPE_INTEGER), pi(pi_), description(description_) { } Option(plcos ps_, std::string description_) : opType(SC_TYPE_STRING), ps(ps_), description(description_) { } bool Set(T *base, const char *val) { switch (opType) { case SC_TYPE_BOOLEAN: { bool option = atoi(val) != 0; if ((*base).*pb != option) { (*base).*pb = option; return true; } break; } case SC_TYPE_INTEGER: { int option = atoi(val); if ((*base).*pi != option) { (*base).*pi = option; return true; } break; } case SC_TYPE_STRING: { if ((*base).*ps != val) { (*base).*ps = val; return true; } break; } } return false; } }; typedef std::map OptionMap; OptionMap nameToDef; std::string names; std::string wordLists; void AppendName(const char *name) { if (!names.empty()) names += "\n"; names += name; } public: virtual ~OptionSet() { } void DefineProperty(const char *name, plcob pb, std::string description="") { nameToDef[name] = Option(pb, description); AppendName(name); } void DefineProperty(const char *name, plcoi pi, std::string description="") { nameToDef[name] = Option(pi, description); AppendName(name); } void DefineProperty(const char *name, plcos ps, std::string description="") { nameToDef[name] = Option(ps, description); AppendName(name); } const char *PropertyNames() { return names.c_str(); } int PropertyType(const char *name) { typename OptionMap::iterator it = nameToDef.find(name); if (it != nameToDef.end()) { return it->second.opType; } return SC_TYPE_BOOLEAN; } const char *DescribeProperty(const char *name) { typename OptionMap::iterator it = nameToDef.find(name); if (it != nameToDef.end()) { return it->second.description.c_str(); } return ""; } bool PropertySet(T *base, const char *name, const char *val) { typename OptionMap::iterator it = nameToDef.find(name); if (it != nameToDef.end()) { return it->second.Set(base, val); } return false; } void DefineWordListSets(const char * const wordListDescriptions[]) { if (wordListDescriptions) { for (size_t wl = 0; wordListDescriptions[wl]; wl++) { if (!wordLists.empty()) wordLists += "\n"; wordLists += wordListDescriptions[wl]; } } } const char *DescribeWordListSets() { return wordLists.c_str(); } }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/StyleContext.h0000644000175000017500000001034211615412040021716 00000000000000// Scintilla source code edit control /** @file StyleContext.cxx ** Lexer infrastructure. **/ // Copyright 1998-2004 by Neil Hodgson // This file is in the public domain. #ifndef STYLECONTEXT_H #define STYLECONTEXT_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif static inline int MakeLowerCase(int ch) { if (ch < 'A' || ch > 'Z') return ch; else return ch - 'A' + 'a'; } // All languages handled so far can treat all characters >= 0x80 as one class // which just continues the current token or starts an identifier if in default. // DBCS treated specially as the second character can be < 0x80 and hence // syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80 class StyleContext { LexAccessor &styler; unsigned int endPos; StyleContext &operator=(const StyleContext &); void GetNextChar(unsigned int pos) { chNext = static_cast(styler.SafeGetCharAt(pos+1)); if (styler.IsLeadByte(static_cast(chNext))) { chNext = chNext << 8; chNext |= static_cast(styler.SafeGetCharAt(pos+2)); } // End of line? // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) // or on LF alone (Unix). Avoid triggering two times on Dos/Win. atLineEnd = (ch == '\r' && chNext != '\n') || (ch == '\n') || (currentPos >= endPos); } public: unsigned int currentPos; bool atLineStart; bool atLineEnd; int state; int chPrev; int ch; int chNext; StyleContext(unsigned int startPos, unsigned int length, int initStyle, LexAccessor &styler_, char chMask=31) : styler(styler_), endPos(startPos + length), currentPos(startPos), atLineEnd(false), state(initStyle & chMask), // Mask off all bits which aren't in the chMask. chPrev(0), ch(0), chNext(0) { styler.StartAt(startPos, chMask); styler.StartSegment(startPos); atLineStart = static_cast(styler.LineStart(styler.GetLine(startPos))) == startPos; unsigned int pos = currentPos; ch = static_cast(styler.SafeGetCharAt(pos)); if (styler.IsLeadByte(static_cast(ch))) { pos++; ch = ch << 8; ch |= static_cast(styler.SafeGetCharAt(pos)); } GetNextChar(pos); } void Complete() { styler.ColourTo(currentPos - 1, state); styler.Flush(); } bool More() const { return currentPos < endPos; } void Forward() { if (currentPos < endPos) { atLineStart = atLineEnd; chPrev = ch; currentPos++; if (ch >= 0x100) currentPos++; ch = chNext; GetNextChar(currentPos + ((ch >= 0x100) ? 1 : 0)); } else { atLineStart = false; chPrev = ' '; ch = ' '; chNext = ' '; atLineEnd = true; } } void Forward(int nb) { for (int i = 0; i < nb; i++) { Forward(); } } void ChangeState(int state_) { state = state_; } void SetState(int state_) { styler.ColourTo(currentPos - 1, state); state = state_; } void ForwardSetState(int state_) { Forward(); styler.ColourTo(currentPos - 1, state); state = state_; } int LengthCurrent() { return currentPos - styler.GetStartSegment(); } int GetRelative(int n) { return static_cast(styler.SafeGetCharAt(currentPos+n)); } bool Match(char ch0) const { return ch == static_cast(ch0); } bool Match(char ch0, char ch1) const { return (ch == static_cast(ch0)) && (chNext == static_cast(ch1)); } bool Match(const char *s) { if (ch != static_cast(*s)) return false; s++; if (!*s) return true; if (chNext != static_cast(*s)) return false; s++; for (int n=2; *s; n++) { if (*s != styler.SafeGetCharAt(currentPos+n)) return false; s++; } return true; } bool MatchIgnoreCase(const char *s) { if (MakeLowerCase(ch) != static_cast(*s)) return false; s++; if (MakeLowerCase(chNext) != static_cast(*s)) return false; s++; for (int n=2; *s; n++) { if (static_cast(*s) != MakeLowerCase(static_cast(styler.SafeGetCharAt(currentPos+n)))) return false; s++; } return true; } // Non-inline void GetCurrent(char *s, unsigned int len); void GetCurrentLowered(char *s, unsigned int len); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerBase.cxx0000644000175000017500000000352611615412040021504 00000000000000// Scintilla source code edit control /** @file LexerSimple.cxx ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif LexerBase::LexerBase() { for (int wl = 0; wl < numWordLists; wl++) keyWordLists[wl] = new WordList; keyWordLists[numWordLists] = 0; } LexerBase::~LexerBase() { for (int wl = 0; wl < numWordLists; wl++) { delete keyWordLists[wl]; keyWordLists[wl] = 0; } keyWordLists[numWordLists] = 0; } void SCI_METHOD LexerBase::Release() { delete this; } int SCI_METHOD LexerBase::Version() const { return lvOriginal; } const char * SCI_METHOD LexerBase::PropertyNames() { return ""; } int SCI_METHOD LexerBase::PropertyType(const char *) { return SC_TYPE_BOOLEAN; } const char * SCI_METHOD LexerBase::DescribeProperty(const char *) { return ""; } int SCI_METHOD LexerBase::PropertySet(const char *key, const char *val) { const char *valOld = props.Get(key); if (strcmp(val, valOld) != 0) { props.Set(key, val); return 0; } else { return -1; } } const char * SCI_METHOD LexerBase::DescribeWordListSets() { return ""; } int SCI_METHOD LexerBase::WordListSet(int n, const char *wl) { if (n < numWordLists) { WordList wlNew; wlNew.Set(wl); if (*keyWordLists[n] != wlNew) { keyWordLists[n]->Set(wl); return 0; } } return -1; } void * SCI_METHOD LexerBase::PrivateCall(int, void *) { return 0; } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/CharacterSet.h0000644000175000017500000000665511615412040021635 00000000000000// Scintilla source code edit control /** @file CharacterSet.h ** Encapsulates a set of characters. Used to test if a character is within a set. **/ // Copyright 2007 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef CHARACTERSET_H #define CHARACTERSET_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class CharacterSet { int size; bool valueAfter; bool *bset; public: enum setBase { setNone=0, setLower=1, setUpper=2, setDigits=4, setAlpha=setLower|setUpper, setAlphaNum=setAlpha|setDigits }; CharacterSet(setBase base=setNone, const char *initialSet="", int size_=0x80, bool valueAfter_=false) { size = size_; valueAfter = valueAfter_; bset = new bool[size]; for (int i=0; i < size; i++) { bset[i] = false; } AddString(initialSet); if (base & setLower) AddString("abcdefghijklmnopqrstuvwxyz"); if (base & setUpper) AddString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); if (base & setDigits) AddString("0123456789"); } ~CharacterSet() { delete []bset; bset = 0; size = 0; } void Add(int val) { assert(val >= 0); assert(val < size); bset[val] = true; } void AddString(const char *setToAdd) { for (const char *cp=setToAdd; *cp; cp++) { int val = static_cast(*cp); assert(val >= 0); assert(val < size); bset[val] = true; } } bool Contains(int val) const { assert(val >= 0); if (val < 0) return false; return (val < size) ? bset[val] : valueAfter; } }; // Functions for classifying characters inline bool IsASpace(int ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); } inline bool IsASpaceOrTab(int ch) { return (ch == ' ') || (ch == '\t'); } inline bool IsADigit(int ch) { return (ch >= '0') && (ch <= '9'); } inline bool IsADigit(int ch, int base) { if (base <= 10) { return (ch >= '0') && (ch < '0' + base); } else { return ((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch < 'A' + base - 10)) || ((ch >= 'a') && (ch < 'a' + base - 10)); } } inline bool IsASCII(int ch) { return ch < 0x80; } inline bool IsAlphaNumeric(int ch) { return ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')); } /** * Check if a character is a space. * This is ASCII specific but is safe with chars >= 0x80. */ inline bool isspacechar(int ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); } inline bool iswordchar(int ch) { return IsASCII(ch) && (IsAlphaNumeric(ch) || ch == '.' || ch == '_'); } inline bool iswordstart(int ch) { return IsASCII(ch) && (IsAlphaNumeric(ch) || ch == '_'); } inline bool isoperator(int ch) { if (IsASCII(ch) && IsAlphaNumeric(ch)) return false; if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || ch == '(' || ch == ')' || ch == '-' || ch == '+' || ch == '=' || ch == '|' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == ':' || ch == ';' || ch == '<' || ch == '>' || ch == ',' || ch == '/' || ch == '?' || ch == '!' || ch == '.' || ch == '~') return true; return false; } // Simple case functions for ASCII. inline char MakeUpperCase(char ch) { if (ch < 'a' || ch > 'z') return ch; else return static_cast(ch - 'a' + 'A'); } int CompareCaseInsensitive(const char *a, const char *b); int CompareNCaseInsensitive(const char *a, const char *b, size_t len); #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerModule.cxx0000644000175000017500000000550011615412040022051 00000000000000// Scintilla source code edit control /** @file LexerModule.cxx ** Colourise for particular languages. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" #include "LexerSimple.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif LexerModule::LexerModule(int language_, LexerFunction fnLexer_, const char *languageName_, LexerFunction fnFolder_, const char *const wordListDescriptions_[], int styleBits_) : language(language_), fnLexer(fnLexer_), fnFolder(fnFolder_), fnFactory(0), wordListDescriptions(wordListDescriptions_), styleBits(styleBits_), languageName(languageName_) { } LexerModule::LexerModule(int language_, LexerFactoryFunction fnFactory_, const char *languageName_, const char * const wordListDescriptions_[], int styleBits_) : language(language_), fnLexer(0), fnFolder(0), fnFactory(fnFactory_), wordListDescriptions(wordListDescriptions_), styleBits(styleBits_), languageName(languageName_) { } int LexerModule::GetNumWordLists() const { if (wordListDescriptions == NULL) { return -1; } else { int numWordLists = 0; while (wordListDescriptions[numWordLists]) { ++numWordLists; } return numWordLists; } } const char *LexerModule::GetWordListDescription(int index) const { static const char *emptyStr = ""; assert(index < GetNumWordLists()); if (index >= GetNumWordLists()) { return emptyStr; } else { return wordListDescriptions[index]; } } int LexerModule::GetStyleBitsNeeded() const { return styleBits; } ILexer *LexerModule::Create() const { if (fnFactory) return fnFactory(); else return new LexerSimple(this); } void LexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const { if (fnLexer) fnLexer(startPos, lengthDoc, initStyle, keywordlists, styler); } void LexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler) const { if (fnFolder) { int lineCurrent = styler.GetLine(startPos); // Move back one line in case deletion wrecked current line fold state if (lineCurrent > 0) { lineCurrent--; int newStartPos = styler.LineStart(lineCurrent); lengthDoc += startPos - newStartPos; startPos = newStartPos; initStyle = 0; if (startPos > 0) { initStyle = styler.StyleAt(startPos - 1); } } fnFolder(startPos, lengthDoc, initStyle, keywordlists, styler); } } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerSimple.h0000644000175000017500000000145111615412040021503 00000000000000// Scintilla source code edit control /** @file LexerSimple.h ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXERSIMPLE_H #define LEXERSIMPLE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif // A simple lexer with no state class LexerSimple : public LexerBase { const LexerModule *module; std::string wordLists; public: LexerSimple(const LexerModule *module_); const char * SCI_METHOD DescribeWordListSets(); void SCI_METHOD Lex(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess); }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/WordList.cxx0000644000175000017500000001142711634611460021410 00000000000000// Scintilla source code edit control /** @file KeyWords.cxx ** Colourise for particular languages. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "WordList.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /** * Creates an array that points into each word in the string and puts \0 terminators * after each word. */ static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) { int prev = '\n'; int words = 0; // For rapid determination of whether a character is a separator, build // a look up table. bool wordSeparator[256]; for (int i=0; i<256; i++) { wordSeparator[i] = false; } wordSeparator['\r'] = true; wordSeparator['\n'] = true; if (!onlyLineEnds) { wordSeparator[' '] = true; wordSeparator['\t'] = true; } for (int j = 0; wordlist[j]; j++) { int curr = static_cast(wordlist[j]); if (!wordSeparator[curr] && wordSeparator[prev]) words++; prev = curr; } char **keywords = new char *[words + 1]; if (keywords) { words = 0; prev = '\0'; size_t slen = strlen(wordlist); for (size_t k = 0; k < slen; k++) { if (!wordSeparator[static_cast(wordlist[k])]) { if (!prev) { keywords[words] = &wordlist[k]; words++; } } else { wordlist[k] = '\0'; } prev = wordlist[k]; } keywords[words] = &wordlist[slen]; *len = words; } else { *len = 0; } return keywords; } bool WordList::operator!=(const WordList &other) const { if (len != other.len) return true; for (int i=0; i(a), *static_cast(b)); } static void SortWordList(char **words, unsigned int len) { qsort(reinterpret_cast(words), len, sizeof(*words), cmpWords); } #endif void WordList::Set(const char *s) { Clear(); list = new char[strlen(s) + 1]; strcpy(list, s); words = ArrayFromWordList(list, &len, onlyLineEnds); #ifdef _MSC_VER std::sort(words, words + len, cmpWords); #else SortWordList(words, len); #endif for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++) starts[k] = -1; for (int l = len - 1; l >= 0; l--) { unsigned char indexChar = words[l][0]; starts[indexChar] = l; } } /** Check whether a string is in the list. * List elements are either exact matches or prefixes. * Prefix elements start with '^' and match all strings that start with the rest of the element * so '^GTK_' matches 'GTK_X', 'GTK_MAJOR_VERSION', and 'GTK_'. */ bool WordList::InList(const char *s) const { if (0 == words) return false; unsigned char firstChar = s[0]; int j = starts[firstChar]; if (j >= 0) { while (static_cast(words[j][0]) == firstChar) { if (s[1] == words[j][1]) { const char *a = words[j] + 1; const char *b = s + 1; while (*a && *a == *b) { a++; b++; } if (!*a && !*b) return true; } j++; } } j = starts['^']; if (j >= 0) { while (words[j][0] == '^') { const char *a = words[j] + 1; const char *b = s; while (*a && *a == *b) { a++; b++; } if (!*a) return true; j++; } } return false; } /** similar to InList, but word s can be a substring of keyword. * eg. the keyword define is defined as def~ine. This means the word must start * with def to be a keyword, but also defi, defin and define are valid. * The marker is ~ in this case. */ bool WordList::InListAbbreviated(const char *s, const char marker) const { if (0 == words) return false; unsigned char firstChar = s[0]; int j = starts[firstChar]; if (j >= 0) { while (static_cast(words[j][0]) == firstChar) { bool isSubword = false; int start = 1; if (words[j][1] == marker) { isSubword = true; start++; } if (s[1] == words[j][start]) { const char *a = words[j] + start; const char *b = s + 1; while (*a && *a == *b) { a++; if (*a == marker) { isSubword = true; a++; } b++; } if ((!*a || isSubword) && !*b) return true; } j++; } } j = starts['^']; if (j >= 0) { while (words[j][0] == '^') { const char *a = words[j] + 1; const char *b = s; while (*a && *a == *b) { a++; b++; } if (!*a) return true; j++; } } return false; } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/SparseState.h0000644000175000017500000000563111634611460021524 00000000000000// Scintilla source code edit control /** @file SparseState.h ** Hold lexer state that may change rarely. ** This is often per-line state such as whether a particular type of section has been entered. ** A state continues until it is changed. **/ // Copyright 2011 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef SPARSESTATE_H #define SPARSESTATE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif template class SparseState { struct State { int position; T value; State(int position_, T value_) : position(position_), value(value_) { } inline bool operator<(const State &other) const { return position < other.position; } inline bool operator==(const State &other) const { return (position == other.position) && (value == other.value); } }; int positionFirst; typedef std::vector stateVector; stateVector states; typename stateVector::iterator Find(int position) { State searchValue(position, T()); return std::lower_bound(states.begin(), states.end(), searchValue); } public: SparseState(int positionFirst_=-1) { positionFirst = positionFirst_; } void Set(int position, T value) { Delete(position); if (states.empty() || (value != states[states.size()-1].value)) { states.push_back(State(position, value)); } } T ValueAt(int position) { if (states.empty()) return T(); if (position < states[0].position) return T(); typename stateVector::iterator low = Find(position); if (low == states.end()) { return states[states.size()-1].value; } else { if (low->position > position) { --low; } return low->value; } } bool Delete(int position) { typename stateVector::iterator low = Find(position); if (low != states.end()) { states.erase(low, states.end()); return true; } return false; } size_t size() const { return states.size(); } // Returns true if Merge caused a significant change bool Merge(const SparseState &other, int ignoreAfter) { // Changes caused beyond ignoreAfter are not significant Delete(ignoreAfter+1); bool different = true; bool changed = false; typename stateVector::iterator low = Find(other.positionFirst); if (static_cast(states.end() - low) == other.states.size()) { // Same number in other as after positionFirst in this different = !std::equal(low, states.end(), other.states.begin()); } if (different) { if (low != states.end()) { states.erase(low, states.end()); changed = true; } typename stateVector::const_iterator startOther = other.states.begin(); if (!states.empty() && !other.states.empty() && states.back().value == startOther->value) ++startOther; if (startOther != other.states.end()) { states.insert(states.end(), startOther, other.states.end()); changed = true; } } return changed; } }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexAccessor.h0000644000175000017500000001057611763437013021510 00000000000000// Scintilla source code edit control /** @file LexAccessor.h ** Interfaces between Scintilla and lexers. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXACCESSOR_H #define LEXACCESSOR_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class LexAccessor { private: IDocument *pAccess; enum {extremePosition=0x7FFFFFFF}; /** @a bufferSize is a trade off between time taken to copy the characters * and retrieval overhead. * @a slopSize positions the buffer before the desired position * in case there is some backtracking. */ enum {bufferSize=4000, slopSize=bufferSize/8}; char buf[bufferSize+1]; int startPos; int endPos; int codePage; int lenDoc; int mask; char styleBuf[bufferSize]; int validLen; char chFlags; char chWhile; unsigned int startSeg; int startPosStyling; void Fill(int position) { startPos = position - slopSize; if (startPos + bufferSize > lenDoc) startPos = lenDoc - bufferSize; if (startPos < 0) startPos = 0; endPos = startPos + bufferSize; if (endPos > lenDoc) endPos = lenDoc; pAccess->GetCharRange(buf, startPos, endPos-startPos); buf[endPos-startPos] = '\0'; } public: LexAccessor(IDocument *pAccess_) : pAccess(pAccess_), startPos(extremePosition), endPos(0), codePage(pAccess->CodePage()), lenDoc(pAccess->Length()), mask(127), validLen(0), chFlags(0), chWhile(0), startSeg(0), startPosStyling(0) { } char operator[](int position) { if (position < startPos || position >= endPos) { Fill(position); } return buf[position - startPos]; } /** Safe version of operator[], returning a defined value for invalid position. */ char SafeGetCharAt(int position, char chDefault=' ') { if (position < startPos || position >= endPos) { Fill(position); if (position < startPos || position >= endPos) { // Position is outside range of document return chDefault; } } return buf[position - startPos]; } bool IsLeadByte(char ch) { return pAccess->IsDBCSLeadByte(ch); } bool Match(int pos, const char *s) { for (int i=0; *s; i++) { if (*s != SafeGetCharAt(pos+i)) return false; s++; } return true; } char StyleAt(int position) { return static_cast(pAccess->StyleAt(position) & mask); } int GetLine(int position) { return pAccess->LineFromPosition(position); } int LineStart(int line) { return pAccess->LineStart(line); } int LevelAt(int line) { return pAccess->GetLevel(line); } int Length() const { return lenDoc; } void Flush() { startPos = extremePosition; if (validLen > 0) { pAccess->SetStyles(validLen, styleBuf); startPosStyling += validLen; validLen = 0; } } int GetLineState(int line) { return pAccess->GetLineState(line); } int SetLineState(int line, int state) { return pAccess->SetLineState(line, state); } // Style setting void StartAt(unsigned int start, char chMask=31) { // Store the mask specified for use with StyleAt. mask = chMask; pAccess->StartStyling(start, chMask); startPosStyling = start; } void SetFlags(char chFlags_, char chWhile_) { chFlags = chFlags_; chWhile = chWhile_; } unsigned int GetStartSegment() const { return startSeg; } void StartSegment(unsigned int pos) { startSeg = pos; } void ColourTo(unsigned int pos, int chAttr) { // Only perform styling if non empty range if (pos != startSeg - 1) { assert(pos >= startSeg); if (pos < startSeg) { return; } if (validLen + (pos - startSeg + 1) >= bufferSize) Flush(); if (validLen + (pos - startSeg + 1) >= bufferSize) { // Too big for buffer so send directly pAccess->SetStyleFor(pos - startSeg + 1, static_cast(chAttr)); } else { if (chAttr != chWhile) chFlags = 0; chAttr = static_cast(chAttr | chFlags); for (unsigned int i = startSeg; i <= pos; i++) { assert((startPosStyling + validLen) < Length()); styleBuf[validLen++] = static_cast(chAttr); } } } startSeg = pos+1; } void SetLevel(int line, int level) { pAccess->SetLevel(line, level); } void IndicatorFill(int start, int end, int indicator, int value) { pAccess->DecorationSetCurrentIndicator(indicator); pAccess->DecorationFillRange(start, value, end - start); } void ChangeLexerState(int start, int end) { pAccess->ChangeLexerState(start, end); } }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/Accessor.cxx0000644000175000017500000000426211615412040021372 00000000000000// Scintilla source code edit control /** @file KeyWords.cxx ** Colourise for particular languages. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif Accessor::Accessor(IDocument *pAccess_, PropSetSimple *pprops_) : LexAccessor(pAccess_), pprops(pprops_) { } int Accessor::GetPropertyInt(const char *key, int defaultValue) { return pprops->GetInt(key, defaultValue); } int Accessor::IndentAmount(int line, int *flags, PFNIsCommentLeader pfnIsCommentLeader) { int end = Length(); int spaceFlags = 0; // Determines the indentation level of the current line and also checks for consistent // indentation compared to the previous line. // Indentation is judged consistent when the indentation whitespace of each line lines // the same or the indentation of one line is a prefix of the other. int pos = LineStart(line); char ch = (*this)[pos]; int indent = 0; bool inPrevPrefix = line > 0; int posPrev = inPrevPrefix ? LineStart(line-1) : 0; while ((ch == ' ' || ch == '\t') && (pos < end)) { if (inPrevPrefix) { char chPrev = (*this)[posPrev++]; if (chPrev == ' ' || chPrev == '\t') { if (chPrev != ch) spaceFlags |= wsInconsistent; } else { inPrevPrefix = false; } } if (ch == ' ') { spaceFlags |= wsSpace; indent++; } else { // Tab spaceFlags |= wsTab; if (spaceFlags & wsSpace) spaceFlags |= wsSpaceTab; indent = (indent / 8 + 1) * 8; } ch = (*this)[++pos]; } *flags = spaceFlags; indent += SC_FOLDLEVELBASE; // if completely empty line or the start of a comment... if ((LineStart(line) == Length()) || (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') || (pfnIsCommentLeader && (*pfnIsCommentLeader)(*this, pos, end-pos))) return indent | SC_FOLDLEVELWHITEFLAG; else return indent; } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/PropSetSimple.cxx0000644000175000017500000001125411660423551022406 00000000000000// SciTE - Scintilla based Text Editor /** @file PropSetSimple.cxx ** A Java style properties file module. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. // Maintain a dictionary of properties #include #include #include #ifdef _MSC_VER // Visual C++ doesn't like unreachable code in its own headers. #pragma warning(disable: 4018 4100 4245 4511 4512 4663 4702) #endif #include #include #include "PropSetSimple.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif typedef std::map mapss; PropSetSimple::PropSetSimple() { mapss *props = new mapss; impl = static_cast(props); } PropSetSimple::~PropSetSimple() { mapss *props = static_cast(impl); delete props; impl = 0; } void PropSetSimple::Set(const char *key, const char *val, int lenKey, int lenVal) { mapss *props = static_cast(impl); if (!*key) // Empty keys are not supported return; if (lenKey == -1) lenKey = static_cast(strlen(key)); if (lenVal == -1) lenVal = static_cast(strlen(val)); (*props)[std::string(key, lenKey)] = std::string(val, lenVal); } static bool IsASpaceCharacter(unsigned int ch) { return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d)); } void PropSetSimple::Set(const char *keyVal) { while (IsASpaceCharacter(*keyVal)) keyVal++; const char *endVal = keyVal; while (*endVal && (*endVal != '\n')) endVal++; const char *eqAt = strchr(keyVal, '='); if (eqAt) { Set(keyVal, eqAt + 1, static_cast(eqAt-keyVal), static_cast(endVal - eqAt - 1)); } else if (*keyVal) { // No '=' so assume '=1' Set(keyVal, "1", static_cast(endVal-keyVal), 1); } } void PropSetSimple::SetMultiple(const char *s) { const char *eol = strchr(s, '\n'); while (eol) { Set(s); s = eol + 1; eol = strchr(s, '\n'); } Set(s); } const char *PropSetSimple::Get(const char *key) const { mapss *props = static_cast(impl); mapss::const_iterator keyPos = props->find(std::string(key)); if (keyPos != props->end()) { return keyPos->second.c_str(); } else { return ""; } } // There is some inconsistency between GetExpanded("foo") and Expand("$(foo)"). // A solution is to keep a stack of variables that have been expanded, so that // recursive expansions can be skipped. For now I'll just use the C++ stack // for that, through a recursive function and a simple chain of pointers. struct VarChain { VarChain(const char *var_=NULL, const VarChain *link_=NULL): var(var_), link(link_) {} bool contains(const char *testVar) const { return (var && (0 == strcmp(var, testVar))) || (link && link->contains(testVar)); } const char *var; const VarChain *link; }; static int ExpandAllInPlace(const PropSetSimple &props, std::string &withVars, int maxExpands, const VarChain &blankVars) { size_t varStart = withVars.find("$("); while ((varStart != std::string::npos) && (maxExpands > 0)) { size_t varEnd = withVars.find(")", varStart+2); if (varEnd == std::string::npos) { break; } // For consistency, when we see '$(ab$(cde))', expand the inner variable first, // regardless whether there is actually a degenerate variable named 'ab$(cde'. size_t innerVarStart = withVars.find("$(", varStart+2); while ((innerVarStart != std::string::npos) && (innerVarStart > varStart) && (innerVarStart < varEnd)) { varStart = innerVarStart; innerVarStart = withVars.find("$(", varStart+2); } std::string var(withVars.c_str(), varStart + 2, varEnd - varStart - 2); std::string val = props.Get(var.c_str()); if (blankVars.contains(var.c_str())) { val = ""; // treat blankVar as an empty string (e.g. to block self-reference) } if (--maxExpands >= 0) { maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars)); } withVars.erase(varStart, varEnd-varStart+1); withVars.insert(varStart, val.c_str(), val.length()); varStart = withVars.find("$("); } return maxExpands; } char *PropSetSimple::Expanded(const char *key) const { std::string val = Get(key); ExpandAllInPlace(*this, val, 100, VarChain(key)); char *ret = new char [val.size() + 1]; strcpy(ret, val.c_str()); return ret; } int PropSetSimple::GetExpanded(const char *key, char *result) const { char *val = Expanded(key); const int n = static_cast(strlen(val)); if (result) { strcpy(result, val); } delete []val; return n; // Not including NUL } int PropSetSimple::GetInt(const char *key, int defaultValue) const { char *val = Expanded(key); if (val) { int retVal = val[0] ? atoi(val) : defaultValue; delete []val; return retVal; } return defaultValue; } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/PropSetSimple.h0000644000175000017500000000146511615412040022025 00000000000000// Scintilla source code edit control /** @file PropSetSimple.h ** A basic string to string map. **/ // Copyright 1998-2009 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef PROPSETSIMPLE_H #define PROPSETSIMPLE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class PropSetSimple { void *impl; void Set(const char *keyVal); public: PropSetSimple(); virtual ~PropSetSimple(); void Set(const char *key, const char *val, int lenKey=-1, int lenVal=-1); void SetMultiple(const char *); const char *Get(const char *key) const; char *Expanded(const char *key) const; int GetExpanded(const char *key, char *result) const; int GetInt(const char *key, int defaultValue=0) const; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerSimple.cxx0000644000175000017500000000276211615412040022064 00000000000000// Scintilla source code edit control /** @file LexerSimple.cxx ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "LexerModule.h" #include "LexerBase.h" #include "LexerSimple.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif LexerSimple::LexerSimple(const LexerModule *module_) : module(module_) { for (int wl = 0; wl < module->GetNumWordLists(); wl++) { if (!wordLists.empty()) wordLists += "\n"; wordLists += module->GetWordListDescription(wl); } } const char * SCI_METHOD LexerSimple::DescribeWordListSets() { return wordLists.c_str(); } void SCI_METHOD LexerSimple::Lex(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess) { Accessor astyler(pAccess, &props); module->Lex(startPos, lengthDoc, initStyle, keyWordLists, astyler); astyler.Flush(); } void SCI_METHOD LexerSimple::Fold(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess) { if (props.GetInt("fold")) { Accessor astyler(pAccess, &props); module->Fold(startPos, lengthDoc, initStyle, keyWordLists, astyler); astyler.Flush(); } } presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerModule.h0000644000175000017500000000417211615412040021502 00000000000000// Scintilla source code edit control /** @file LexerModule.h ** Colourise for particular languages. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LEXERMODULE_H #define LEXERMODULE_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif class Accessor; class WordList; typedef void (*LexerFunction)(unsigned int startPos, int lengthDoc, int initStyle, WordList *keywordlists[], Accessor &styler); typedef ILexer *(*LexerFactoryFunction)(); /** * A LexerModule is responsible for lexing and folding a particular language. * The class maintains a list of LexerModules which can be searched to find a * module appropriate to a particular language. */ class LexerModule { protected: int language; LexerFunction fnLexer; LexerFunction fnFolder; LexerFactoryFunction fnFactory; const char * const * wordListDescriptions; int styleBits; public: const char *languageName; LexerModule(int language_, LexerFunction fnLexer_, const char *languageName_=0, LexerFunction fnFolder_=0, const char * const wordListDescriptions_[] = NULL, int styleBits_=5); LexerModule(int language_, LexerFactoryFunction fnFactory_, const char *languageName_, const char * const wordListDescriptions_[] = NULL, int styleBits_=8); virtual ~LexerModule() { } int GetLanguage() const { return language; } // -1 is returned if no WordList information is available int GetNumWordLists() const; const char *GetWordListDescription(int index) const; int GetStyleBitsNeeded() const; ILexer *Create() const; virtual void Lex(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) const; virtual void Fold(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) const; friend class Catalogue; }; inline int Maximum(int a, int b) { return (a > b) ? a : b; } // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER #pragma warning(disable: 4244 4309 4514 4710) #endif #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/WordList.h0000644000175000017500000000175011615412040021023 00000000000000// Scintilla source code edit control /** @file WordList.h ** Hold a list of words. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef WORDLIST_H #define WORDLIST_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif /** */ class WordList { public: // Each word contains at least one character - a empty word acts as sentinel at the end. char **words; char *list; int len; bool onlyLineEnds; ///< Delimited by any white space or only line ends int starts[256]; WordList(bool onlyLineEnds_ = false) : words(0), list(0), len(0), onlyLineEnds(onlyLineEnds_) {} ~WordList() { Clear(); } operator bool() const { return len ? true : false; } bool operator!=(const WordList &other) const; void Clear(); void Set(const char *s); bool InList(const char *s) const; bool InListAbbreviated(const char *s, const char marker) const; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/LexerNoExceptions.h0000644000175000017500000000211111615412040022662 00000000000000// Scintilla source code edit control /** @file LexerNoExceptions.h ** A simple lexer with no state. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #ifndef LexerNoExceptions_H #define LexerNoExceptions_H #ifdef SCI_NAMESPACE namespace Scintilla { #endif // A simple lexer with no state class LexerNoExceptions : public LexerBase { public: // TODO Also need to prevent exceptions in constructor and destructor int SCI_METHOD PropertySet(const char *key, const char *val); int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int lengthDoc, int initStyle, IDocument *); virtual void Lexer(unsigned int startPos, int length, int initStyle, IDocument *pAccess, Accessor &styler) = 0; virtual void Folder(unsigned int startPos, int length, int initStyle, IDocument *pAccess, Accessor &styler) = 0; }; #ifdef SCI_NAMESPACE } #endif #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexlib/CharacterSet.cxx0000644000175000017500000000225511615412040022200 00000000000000// Scintilla source code edit control /** @file CharacterSet.cxx ** Simple case functions for ASCII. ** Lexer infrastructure. **/ // Copyright 1998-2010 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "CharacterSet.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #ifdef SCI_NAMESPACE namespace Scintilla { #endif int CompareCaseInsensitive(const char *a, const char *b) { while (*a && *b) { if (*a != *b) { char upperA = MakeUpperCase(*a); char upperB = MakeUpperCase(*b); if (upperA != upperB) return upperA - upperB; } a++; b++; } // Either *a or *b is nul return *a - *b; } int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { while (*a && *b && len) { if (*a != *b) { char upperA = MakeUpperCase(*a); char upperB = MakeUpperCase(*b); if (upperA != upperB) return upperA - upperB; } a++; b++; len--; } if (len == 0) return 0; else // Either *a or *b is nul return *a - *b; } #ifdef SCI_NAMESPACE } #endif presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/0000755000175000017500000000000011764714757017234 500000000000000presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexScriptol.cxx0000644000175000017500000003071411652104216022130 00000000000000// Scintilla source code edit control /** @file LexScriptol.cxx ** Lexer for Scriptol. **/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static void ClassifyWordSol(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord) { char s[100]; bool wordIsNumber = isdigit(styler[start]) != 0; for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { s[i] = styler[start + i]; s[i + 1] = '\0'; } char chAttr = SCE_SCRIPTOL_IDENTIFIER; if (0 == strcmp(prevWord, "class")) chAttr = SCE_SCRIPTOL_CLASSNAME; else if (wordIsNumber) chAttr = SCE_SCRIPTOL_NUMBER; else if (keywords.InList(s)) chAttr = SCE_SCRIPTOL_KEYWORD; else for (unsigned int i = 0; i < end - start + 1; i++) // test dotted idents { if (styler[start + i] == '.') { styler.ColourTo(start + i - 1, chAttr); styler.ColourTo(start + i, SCE_SCRIPTOL_OPERATOR); } } styler.ColourTo(end, chAttr); strcpy(prevWord, s); } static bool IsSolComment(Accessor &styler, int pos, int len) { if(len > 0) { char c = styler[pos]; if(c == '`') return true; if(len > 1) { if(c == '/') { c = styler[pos + 1]; if(c == '/') return true; if(c == '*') return true; } } } return false; } static bool IsSolStringStart(char ch) { if (ch == '\'' || ch == '"') return true; return false; } static bool IsSolWordStart(char ch) { return (iswordchar(ch) && !IsSolStringStart(ch)); } static int GetSolStringState(Accessor &styler, int i, int *nextIndex) { char ch = styler.SafeGetCharAt(i); char chNext = styler.SafeGetCharAt(i + 1); if (ch != '\"' && ch != '\'') { *nextIndex = i + 1; return SCE_SCRIPTOL_DEFAULT; } // ch is either single or double quotes in string // code below seem non-sense but is here for future extensions if (ch == chNext && ch == styler.SafeGetCharAt(i + 2)) { *nextIndex = i + 3; if(ch == '\"') return SCE_SCRIPTOL_TRIPLE; if(ch == '\'') return SCE_SCRIPTOL_TRIPLE; return SCE_SCRIPTOL_STRING; } else { *nextIndex = i + 1; if (ch == '"') return SCE_SCRIPTOL_STRING; else return SCE_SCRIPTOL_STRING; } } static void ColouriseSolDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { int lengthDoc = startPos + length; char stringType = '\"'; if (startPos > 0) { int lineCurrent = styler.GetLine(startPos); if (lineCurrent > 0) { startPos = styler.LineStart(lineCurrent-1); if (startPos == 0) initStyle = SCE_SCRIPTOL_DEFAULT; else initStyle = styler.StyleAt(startPos-1); } } styler.StartAt(startPos, 127); WordList &keywords = *keywordlists[0]; int whingeLevel = styler.GetPropertyInt("tab.timmy.whinge.level"); char prevWord[200]; prevWord[0] = '\0'; if (length == 0) return; int state = initStyle & 31; int nextIndex = 0; char chPrev = ' '; char chPrev2 = ' '; char chNext = styler[startPos]; styler.StartSegment(startPos); bool atStartLine = true; int spaceFlags = 0; for (int i = startPos; i < lengthDoc; i++) { if (atStartLine) { char chBad = static_cast(64); char chGood = static_cast(0); char chFlags = chGood; if (whingeLevel == 1) { chFlags = (spaceFlags & wsInconsistent) ? chBad : chGood; } else if (whingeLevel == 2) { chFlags = (spaceFlags & wsSpaceTab) ? chBad : chGood; } else if (whingeLevel == 3) { chFlags = (spaceFlags & wsSpace) ? chBad : chGood; } else if (whingeLevel == 4) { chFlags = (spaceFlags & wsTab) ? chBad : chGood; } styler.SetFlags(chFlags, static_cast(state)); atStartLine = false; } char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) { if ((state == SCE_SCRIPTOL_DEFAULT) || (state == SCE_SCRIPTOL_TRIPLE) || (state == SCE_SCRIPTOL_COMMENTBLOCK)) { styler.ColourTo(i, state); } atStartLine = true; } if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); chPrev = ' '; chPrev2 = ' '; i += 1; continue; } if (state == SCE_SCRIPTOL_STRINGEOL) { if (ch != '\r' && ch != '\n') { styler.ColourTo(i - 1, state); state = SCE_SCRIPTOL_DEFAULT; } } if (state == SCE_SCRIPTOL_DEFAULT) { if (IsSolWordStart(ch)) { styler.ColourTo(i - 1, state); state = SCE_SCRIPTOL_KEYWORD; } else if (ch == '`') { styler.ColourTo(i - 1, state); state = SCE_SCRIPTOL_COMMENTLINE; } else if (ch == '/') { styler.ColourTo(i - 1, state); if(chNext == '/') state = SCE_SCRIPTOL_CSTYLE; if(chNext == '*') state = SCE_SCRIPTOL_COMMENTBLOCK; } else if (IsSolStringStart(ch)) { styler.ColourTo(i - 1, state); state = GetSolStringState(styler, i, &nextIndex); if(state == SCE_SCRIPTOL_STRING) { stringType = ch; } if (nextIndex != i + 1) { i = nextIndex - 1; ch = ' '; chPrev = ' '; chNext = styler.SafeGetCharAt(i + 1); } } else if (isoperator(ch)) { styler.ColourTo(i - 1, state); styler.ColourTo(i, SCE_SCRIPTOL_OPERATOR); } } else if (state == SCE_SCRIPTOL_KEYWORD) { if (!iswordchar(ch)) { ClassifyWordSol(styler.GetStartSegment(), i - 1, keywords, styler, prevWord); state = SCE_SCRIPTOL_DEFAULT; if (ch == '`') { state = chNext == '`' ? SCE_SCRIPTOL_PERSISTENT : SCE_SCRIPTOL_COMMENTLINE; } else if (IsSolStringStart(ch)) { styler.ColourTo(i - 1, state); state = GetSolStringState(styler, i, &nextIndex); if (nextIndex != i + 1) { i = nextIndex - 1; ch = ' '; chPrev = ' '; chNext = styler.SafeGetCharAt(i + 1); } } else if (isoperator(ch)) { styler.ColourTo(i, SCE_SCRIPTOL_OPERATOR); } } } else { if (state == SCE_SCRIPTOL_COMMENTLINE || state == SCE_SCRIPTOL_PERSISTENT || state == SCE_SCRIPTOL_CSTYLE) { if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, state); state = SCE_SCRIPTOL_DEFAULT; } } else if(state == SCE_SCRIPTOL_COMMENTBLOCK) { if(chPrev == '*' && ch == '/') { styler.ColourTo(i, state); state = SCE_SCRIPTOL_DEFAULT; } } else if ((state == SCE_SCRIPTOL_STRING) || (state == SCE_SCRIPTOL_CHARACTER)) { if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { styler.ColourTo(i - 1, state); state = SCE_SCRIPTOL_STRINGEOL; } else if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; ch = chNext; chNext = styler.SafeGetCharAt(i + 1); } } else if ((ch == '\"') || (ch == '\'')) { // must match the entered quote type if(ch == stringType) { styler.ColourTo(i, state); state = SCE_SCRIPTOL_DEFAULT; } } } else if (state == SCE_SCRIPTOL_TRIPLE) { if ((ch == '\'' && chPrev == '\'' && chPrev2 == '\'') || (ch == '\"' && chPrev == '\"' && chPrev2 == '\"')) { styler.ColourTo(i, state); state = SCE_SCRIPTOL_DEFAULT; } } } chPrev2 = chPrev; chPrev = ch; } if (state == SCE_SCRIPTOL_KEYWORD) { ClassifyWordSol(styler.GetStartSegment(), lengthDoc-1, keywords, styler, prevWord); } else { styler.ColourTo(lengthDoc-1, state); } } static void FoldSolDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { int lengthDoc = startPos + length; int lineCurrent = styler.GetLine(startPos); if (startPos > 0) { if (lineCurrent > 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); if (startPos == 0) initStyle = SCE_SCRIPTOL_DEFAULT; else initStyle = styler.StyleAt(startPos-1); } } int state = initStyle & 31; int spaceFlags = 0; int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsSolComment); if (state == SCE_SCRIPTOL_TRIPLE) indentCurrent |= SC_FOLDLEVELWHITEFLAG; char chNext = styler[startPos]; for (int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styler.StyleAt(i) & 31; if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) { int lev = indentCurrent; int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsSolComment); if (style == SCE_SCRIPTOL_TRIPLE) indentNext |= SC_FOLDLEVELWHITEFLAG; if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { // Only non whitespace lines can be headers if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } else if (indentNext & SC_FOLDLEVELWHITEFLAG) { // Line after is blank so check the next - maybe should continue further? int spaceFlags2 = 0; int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsSolComment); if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } } } indentCurrent = indentNext; styler.SetLevel(lineCurrent, lev); lineCurrent++; } } } LexerModule lmScriptol(SCLEX_SCRIPTOL, ColouriseSolDoc, "scriptol", FoldSolDoc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexCrontab.cxx0000644000175000017500000001605211615412040021714 00000000000000// Scintilla source code edit control /** @file LexCrontab.cxx ** Lexer to use with extended crontab files used by a powerful ** Windows scheduler/event monitor/automation manager nnCron. ** (http://nemtsev.eserv.ru/) **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static void ColouriseNncrontabDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler) { int state = SCE_NNCRONTAB_DEFAULT; char chNext = styler[startPos]; int lengthDoc = startPos + length; // create a buffer large enough to take the largest chunk... char *buffer = new char[length]; int bufferCount = 0; // used when highliting environment variables inside quoted string: bool insideString = false; // this assumes that we have 3 keyword list in conf.properties WordList §ion = *keywordLists[0]; WordList &keyword = *keywordLists[1]; WordList &modifier = *keywordLists[2]; // go through all provided text segment // using the hand-written state machine shown below styler.StartAt(startPos); styler.StartSegment(startPos); for (int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); i++; continue; } switch(state) { case SCE_NNCRONTAB_DEFAULT: if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') { // whitespace is simply ignored here... styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT); break; } else if( ch == '#' && styler.SafeGetCharAt(i+1) == '(') { // signals the start of a task... state = SCE_NNCRONTAB_TASK; styler.ColourTo(i,SCE_NNCRONTAB_TASK); } else if( ch == '\\' && (styler.SafeGetCharAt(i+1) == ' ' || styler.SafeGetCharAt(i+1) == '\t')) { // signals the start of an extended comment... state = SCE_NNCRONTAB_COMMENT; styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); } else if( ch == '#' ) { // signals the start of a plain comment... state = SCE_NNCRONTAB_COMMENT; styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); } else if( ch == ')' && styler.SafeGetCharAt(i+1) == '#') { // signals the end of a task... state = SCE_NNCRONTAB_TASK; styler.ColourTo(i,SCE_NNCRONTAB_TASK); } else if( ch == '"') { state = SCE_NNCRONTAB_STRING; styler.ColourTo(i,SCE_NNCRONTAB_STRING); } else if( ch == '%') { // signals environment variables state = SCE_NNCRONTAB_ENVIRONMENT; styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); } else if( ch == '<' && styler.SafeGetCharAt(i+1) == '%') { // signals environment variables state = SCE_NNCRONTAB_ENVIRONMENT; styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); } else if( ch == '*' ) { // signals an asterisk // no state jump necessary for this simple case... styler.ColourTo(i,SCE_NNCRONTAB_ASTERISK); } else if( (isascii(ch) && isalpha(ch)) || ch == '<' ) { // signals the start of an identifier bufferCount = 0; buffer[bufferCount++] = ch; state = SCE_NNCRONTAB_IDENTIFIER; } else if( isascii(ch) && isdigit(ch) ) { // signals the start of a number bufferCount = 0; buffer[bufferCount++] = ch; state = SCE_NNCRONTAB_NUMBER; } else { // style it the default style.. styler.ColourTo(i,SCE_NNCRONTAB_DEFAULT); } break; case SCE_NNCRONTAB_COMMENT: // if we find a newline here, // we simply go to default state // else continue to work on it... if( ch == '\n' || ch == '\r' ) { state = SCE_NNCRONTAB_DEFAULT; } else { styler.ColourTo(i,SCE_NNCRONTAB_COMMENT); } break; case SCE_NNCRONTAB_TASK: // if we find a newline here, // we simply go to default state // else continue to work on it... if( ch == '\n' || ch == '\r' ) { state = SCE_NNCRONTAB_DEFAULT; } else { styler.ColourTo(i,SCE_NNCRONTAB_TASK); } break; case SCE_NNCRONTAB_STRING: if( ch == '%' ) { state = SCE_NNCRONTAB_ENVIRONMENT; insideString = true; styler.ColourTo(i-1,SCE_NNCRONTAB_STRING); break; } // if we find the end of a string char, we simply go to default state // else we're still dealing with an string... if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') || (ch == '\n') || (ch == '\r') ) { state = SCE_NNCRONTAB_DEFAULT; } styler.ColourTo(i,SCE_NNCRONTAB_STRING); break; case SCE_NNCRONTAB_ENVIRONMENT: // if we find the end of a string char, we simply go to default state // else we're still dealing with an string... if( ch == '%' && insideString ) { state = SCE_NNCRONTAB_STRING; insideString = false; break; } if( (ch == '%' && styler.SafeGetCharAt(i-1)!='\\') || (ch == '\n') || (ch == '\r') || (ch == '>') ) { state = SCE_NNCRONTAB_DEFAULT; styler.ColourTo(i,SCE_NNCRONTAB_ENVIRONMENT); break; } styler.ColourTo(i+1,SCE_NNCRONTAB_ENVIRONMENT); break; case SCE_NNCRONTAB_IDENTIFIER: // stay in CONF_IDENTIFIER state until we find a non-alphanumeric if( (isascii(ch) && isalnum(ch)) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '<') || (ch == '>') || (ch == '@') ) { buffer[bufferCount++] = ch; } else { state = SCE_NNCRONTAB_DEFAULT; buffer[bufferCount] = '\0'; // check if the buffer contains a keyword, // and highlight it if it is a keyword... if(section.InList(buffer)) { styler.ColourTo(i,SCE_NNCRONTAB_SECTION ); } else if(keyword.InList(buffer)) { styler.ColourTo(i-1,SCE_NNCRONTAB_KEYWORD ); } // else if(strchr(buffer,'/') || strchr(buffer,'.')) { // styler.ColourTo(i-1,SCE_NNCRONTAB_EXTENSION); // } else if(modifier.InList(buffer)) { styler.ColourTo(i-1,SCE_NNCRONTAB_MODIFIER ); } else { styler.ColourTo(i-1,SCE_NNCRONTAB_DEFAULT); } // push back the faulty character chNext = styler[i--]; } break; case SCE_NNCRONTAB_NUMBER: // stay in CONF_NUMBER state until we find a non-numeric if( isascii(ch) && isdigit(ch) /* || ch == '.' */ ) { buffer[bufferCount++] = ch; } else { state = SCE_NNCRONTAB_DEFAULT; buffer[bufferCount] = '\0'; // Colourize here... (normal number) styler.ColourTo(i-1,SCE_NNCRONTAB_NUMBER); // push back a character chNext = styler[i--]; } break; } } delete []buffer; } static const char * const cronWordListDesc[] = { "Section keywords and Forth words", "nnCrontab keywords", "Modifiers", 0 }; LexerModule lmNncrontab(SCLEX_NNCRONTAB, ColouriseNncrontabDoc, "nncrontab", 0, cronWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexTADS3.cxx0000644000175000017500000011111311726020232021135 00000000000000// Scintilla source code edit control /** @file LexTADS3.cxx ** Lexer for TADS3. **/ // Copyright 1998-2006 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. /* * TADS3 is a language designed by Michael J. Roberts for the writing of text * based games. TADS comes from Text Adventure Development System. It has good * support for the processing and outputting of formatted text and much of a * TADS program listing consists of strings. * * TADS has two types of strings, those enclosed in single quotes (') and those * enclosed in double quotes ("). These strings have different symantics and * can be given different highlighting if desired. * * There can be embedded within both types of strings html tags * ( ), library directives ( <.directive> ), and message * parameters ( {The doctor's/his} ). * * Double quoted strings can also contain interpolated expressions * ( << rug.moved ? ' and a hole in the floor. ' : nil >> ). These expressions * may themselves contain single or double quoted strings, although the double * quoted strings may not contain interpolated expressions. * * These embedded constructs influence the output and formatting and are an * important part of a program and require highlighting. * * LINKS * http://www.tads.org/ */ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static const int T3_SINGLE_QUOTE = 1; static const int T3_INT_EXPRESSION = 2; static const int T3_INT_EXPRESSION_IN_TAG = 4; static const int T3_HTML_SQUOTE = 8; static inline bool IsEOL(const int ch, const int chNext) { return (ch == '\r' && chNext != '\n') || (ch == '\n'); } /* * Test the current character to see if it's the START of an EOL sequence; * if so, skip ahead to the last character of the sequence and return true, * and if not just return false. There are a few places where we want to * check to see if a newline sequence occurs at a particular point, but * where a caller expects a subroutine to stop only upon reaching the END * of a newline sequence (in particular, CR-LF on Windows). That's why * IsEOL() above only returns true on CR if the CR isn't followed by an LF * - it doesn't want to admit that there's a newline until reaching the END * of the sequence. We meet both needs by saying that there's a newline * when we see the CR in a CR-LF, but skipping the CR before returning so * that the caller's caller will see that we've stopped at the LF. */ static inline bool IsEOLSkip(StyleContext &sc) { /* test for CR-LF */ if (sc.ch == '\r' && sc.chNext == '\n') { /* got CR-LF - skip the CR and indicate that we're at a newline */ sc.Forward(); return true; } /* * in other cases, we have at most a 1-character newline, so do the * normal IsEOL test */ return IsEOL(sc.ch, sc.chNext); } static inline bool IsATADS3Operator(const int ch) { return ch == '=' || ch == '{' || ch == '}' || ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == ',' || ch == ':' || ch == ';' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '?' || ch == '!' || ch == '<' || ch == '>' || ch == '|' || ch == '@' || ch == '&' || ch == '~'; } static inline bool IsAWordChar(const int ch) { return isalnum(ch) || ch == '_'; } static inline bool IsAWordStart(const int ch) { return isalpha(ch) || ch == '_'; } static inline bool IsAHexDigit(const int ch) { int lch = tolower(ch); return isdigit(lch) || lch == 'a' || lch == 'b' || lch == 'c' || lch == 'd' || lch == 'e' || lch == 'f'; } static inline bool IsAnHTMLChar(int ch) { return isalnum(ch) || ch == '-' || ch == '_' || ch == '.'; } static inline bool IsADirectiveChar(int ch) { return isalnum(ch) || isspace(ch) || ch == '-' || ch == '/'; } static inline bool IsANumberStart(StyleContext &sc) { return isdigit(sc.ch) || (!isdigit(sc.chPrev) && sc.ch == '.' && isdigit(sc.chNext)); } inline static void ColouriseTADS3Operator(StyleContext &sc) { int initState = sc.state; int c = sc.ch; sc.SetState(c == '{' || c == '}' ? SCE_T3_BRACE : SCE_T3_OPERATOR); sc.ForwardSetState(initState); } static void ColouriseTADSHTMLString(StyleContext &sc, int &lineState) { int endState = sc.state; int chQuote = sc.ch; int chString = (lineState & T3_SINGLE_QUOTE) ? '\'' : '"'; if (endState == SCE_T3_HTML_STRING) { if (lineState&T3_SINGLE_QUOTE) { endState = SCE_T3_S_STRING; chString = '\''; } else if (lineState&T3_INT_EXPRESSION) { endState = SCE_T3_X_STRING; chString = '"'; } else { endState = SCE_T3_HTML_DEFAULT; chString = '"'; } chQuote = (lineState & T3_HTML_SQUOTE) ? '\'' : '"'; } else { sc.SetState(SCE_T3_HTML_STRING); sc.Forward(); } if (chQuote == '"') lineState &= ~T3_HTML_SQUOTE; else lineState |= T3_HTML_SQUOTE; while (sc.More()) { if (IsEOL(sc.ch, sc.chNext)) { return; } if (sc.ch == chQuote) { sc.ForwardSetState(endState); return; } if (sc.Match('\\', static_cast(chQuote))) { sc.Forward(2); sc.SetState(endState); return; } if (sc.ch == chString) { sc.SetState(SCE_T3_DEFAULT); return; } if (sc.Match('<', '<')) { lineState |= T3_INT_EXPRESSION | T3_INT_EXPRESSION_IN_TAG; sc.SetState(SCE_T3_X_DEFAULT); sc.Forward(2); return; } if (sc.Match('\\', static_cast(chQuote)) || sc.Match('\\', static_cast(chString)) || sc.Match('\\', '\\')) { sc.Forward(2); } else { sc.Forward(); } } } static void ColouriseTADS3HTMLTagStart(StyleContext &sc) { sc.SetState(SCE_T3_HTML_TAG); sc.Forward(); if (sc.ch == '/') { sc.Forward(); } while (IsAnHTMLChar(sc.ch)) { sc.Forward(); } } static void ColouriseTADS3HTMLTag(StyleContext &sc, int &lineState) { int endState = sc.state; int chQuote = '"'; int chString = '\''; switch (endState) { case SCE_T3_S_STRING: ColouriseTADS3HTMLTagStart(sc); sc.SetState(SCE_T3_HTML_DEFAULT); chQuote = '\''; chString = '"'; break; case SCE_T3_D_STRING: case SCE_T3_X_STRING: ColouriseTADS3HTMLTagStart(sc); sc.SetState(SCE_T3_HTML_DEFAULT); break; case SCE_T3_HTML_DEFAULT: if (lineState&T3_SINGLE_QUOTE) { endState = SCE_T3_S_STRING; chQuote = '\''; chString = '"'; } else if (lineState&T3_INT_EXPRESSION) { endState = SCE_T3_X_STRING; } else { endState = SCE_T3_D_STRING; } break; } while (sc.More()) { if (IsEOL(sc.ch, sc.chNext)) { return; } if (sc.Match('/', '>')) { sc.SetState(SCE_T3_HTML_TAG); sc.Forward(2); sc.SetState(endState); return; } if (sc.ch == '>') { sc.SetState(SCE_T3_HTML_TAG); sc.ForwardSetState(endState); return; } if (sc.ch == chQuote) { sc.SetState(endState); return; } if (sc.Match('\\', static_cast(chQuote))) { sc.Forward(); ColouriseTADSHTMLString(sc, lineState); if (sc.state == SCE_T3_X_DEFAULT) break; } else if (sc.ch == chString) { ColouriseTADSHTMLString(sc, lineState); } else if (sc.ch == '=') { ColouriseTADS3Operator(sc); } else { sc.Forward(); } } } static void ColouriseTADS3Keyword(StyleContext &sc, WordList *keywordlists[], unsigned int endPos) { char s[250]; WordList &keywords = *keywordlists[0]; WordList &userwords1 = *keywordlists[1]; WordList &userwords2 = *keywordlists[2]; WordList &userwords3 = *keywordlists[3]; int initState = sc.state; sc.SetState(SCE_T3_IDENTIFIER); while (sc.More() && (IsAWordChar(sc.ch))) { sc.Forward(); } sc.GetCurrent(s, sizeof(s)); if ( strcmp(s, "is") == 0 || strcmp(s, "not") == 0) { // have to find if "in" is next int n = 1; while (n + sc.currentPos < endPos && IsASpaceOrTab(sc.GetRelative(n))) n++; if (sc.GetRelative(n) == 'i' && sc.GetRelative(n+1) == 'n') { sc.Forward(n+2); sc.ChangeState(SCE_T3_KEYWORD); } } else if (keywords.InList(s)) { sc.ChangeState(SCE_T3_KEYWORD); } else if (userwords3.InList(s)) { sc.ChangeState(SCE_T3_USER3); } else if (userwords2.InList(s)) { sc.ChangeState(SCE_T3_USER2); } else if (userwords1.InList(s)) { sc.ChangeState(SCE_T3_USER1); } sc.SetState(initState); } static void ColouriseTADS3MsgParam(StyleContext &sc, int &lineState) { int endState = sc.state; int chQuote = '"'; switch (endState) { case SCE_T3_S_STRING: sc.SetState(SCE_T3_MSG_PARAM); sc.Forward(); chQuote = '\''; break; case SCE_T3_D_STRING: case SCE_T3_X_STRING: sc.SetState(SCE_T3_MSG_PARAM); sc.Forward(); break; case SCE_T3_MSG_PARAM: if (lineState&T3_SINGLE_QUOTE) { endState = SCE_T3_S_STRING; chQuote = '\''; } else if (lineState&T3_INT_EXPRESSION) { endState = SCE_T3_X_STRING; } else { endState = SCE_T3_D_STRING; } break; } while (sc.More() && sc.ch != '}' && sc.ch != chQuote) { if (IsEOL(sc.ch, sc.chNext)) { return; } if (sc.ch == '\\') { sc.Forward(); } sc.Forward(); } if (sc.ch == chQuote) { sc.SetState(endState); } else { sc.ForwardSetState(endState); } } static void ColouriseTADS3LibDirective(StyleContext &sc, int &lineState) { int initState = sc.state; int chQuote = '"'; switch (initState) { case SCE_T3_S_STRING: sc.SetState(SCE_T3_LIB_DIRECTIVE); sc.Forward(2); chQuote = '\''; break; case SCE_T3_D_STRING: sc.SetState(SCE_T3_LIB_DIRECTIVE); sc.Forward(2); break; case SCE_T3_LIB_DIRECTIVE: if (lineState&T3_SINGLE_QUOTE) { initState = SCE_T3_S_STRING; chQuote = '\''; } else { initState = SCE_T3_D_STRING; } break; } while (sc.More() && IsADirectiveChar(sc.ch)) { if (IsEOL(sc.ch, sc.chNext)) { return; } sc.Forward(); }; if (sc.ch == '>' || !sc.More()) { sc.ForwardSetState(initState); } else if (sc.ch == chQuote) { sc.SetState(initState); } else { sc.ChangeState(initState); sc.Forward(); } } static void ColouriseTADS3String(StyleContext &sc, int &lineState) { int chQuote = sc.ch; int endState = sc.state; switch (sc.state) { case SCE_T3_DEFAULT: case SCE_T3_X_DEFAULT: if (chQuote == '"') { if (sc.state == SCE_T3_DEFAULT) { sc.SetState(SCE_T3_D_STRING); } else { sc.SetState(SCE_T3_X_STRING); } lineState &= ~T3_SINGLE_QUOTE; } else { sc.SetState(SCE_T3_S_STRING); lineState |= T3_SINGLE_QUOTE; } sc.Forward(); break; case SCE_T3_S_STRING: chQuote = '\''; endState = lineState&T3_INT_EXPRESSION ? SCE_T3_X_DEFAULT : SCE_T3_DEFAULT; break; case SCE_T3_D_STRING: chQuote = '"'; endState = SCE_T3_DEFAULT; break; case SCE_T3_X_STRING: chQuote = '"'; endState = SCE_T3_X_DEFAULT; break; } while (sc.More()) { if (IsEOL(sc.ch, sc.chNext)) { return; } if (sc.ch == chQuote) { sc.ForwardSetState(endState); return; } if (sc.state == SCE_T3_D_STRING && sc.Match('<', '<')) { lineState |= T3_INT_EXPRESSION; sc.SetState(SCE_T3_X_DEFAULT); sc.Forward(2); return; } if (sc.Match('\\', static_cast(chQuote)) || sc.Match('\\', '\\')) { sc.Forward(2); } else if (sc.ch == '{') { ColouriseTADS3MsgParam(sc, lineState); } else if (sc.Match('<', '.')) { ColouriseTADS3LibDirective(sc, lineState); } else if (sc.ch == '<') { ColouriseTADS3HTMLTag(sc, lineState); if (sc.state == SCE_T3_X_DEFAULT) return; } else { sc.Forward(); } } } static void ColouriseTADS3Comment(StyleContext &sc, int endState) { sc.SetState(SCE_T3_BLOCK_COMMENT); while (sc.More()) { if (IsEOL(sc.ch, sc.chNext)) { return; } if (sc.Match('*', '/')) { sc.Forward(2); sc.SetState(endState); return; } sc.Forward(); } } static void ColouriseToEndOfLine(StyleContext &sc, int initState, int endState) { sc.SetState(initState); while (sc.More()) { if (sc.ch == '\\') { sc.Forward(); if (IsEOLSkip(sc)) { return; } } if (IsEOL(sc.ch, sc.chNext)) { sc.SetState(endState); return; } sc.Forward(); } } static void ColouriseTADS3Number(StyleContext &sc) { int endState = sc.state; bool inHexNumber = false; bool seenE = false; bool seenDot = sc.ch == '.'; sc.SetState(SCE_T3_NUMBER); if (sc.More()) { sc.Forward(); } if (sc.chPrev == '0' && tolower(sc.ch) == 'x') { inHexNumber = true; sc.Forward(); } while (sc.More()) { if (inHexNumber) { if (!IsAHexDigit(sc.ch)) { break; } } else if (!isdigit(sc.ch)) { if (!seenE && tolower(sc.ch) == 'e') { seenE = true; seenDot = true; if (sc.chNext == '+' || sc.chNext == '-') { sc.Forward(); } } else if (!seenDot && sc.ch == '.') { seenDot = true; } else { break; } } sc.Forward(); } sc.SetState(endState); } static void ColouriseTADS3Doc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { int visibleChars = 0; int bracketLevel = 0; int lineState = 0; unsigned int endPos = startPos + length; int lineCurrent = styler.GetLine(startPos); if (lineCurrent > 0) { lineState = styler.GetLineState(lineCurrent-1); } StyleContext sc(startPos, length, initStyle, styler); while (sc.More()) { if (IsEOL(sc.ch, sc.chNext)) { styler.SetLineState(lineCurrent, lineState); lineCurrent++; visibleChars = 0; sc.Forward(); if (sc.ch == '\n') { sc.Forward(); } } switch(sc.state) { case SCE_T3_PREPROCESSOR: case SCE_T3_LINE_COMMENT: ColouriseToEndOfLine(sc, sc.state, lineState&T3_INT_EXPRESSION ? SCE_T3_X_DEFAULT : SCE_T3_DEFAULT); break; case SCE_T3_S_STRING: case SCE_T3_D_STRING: case SCE_T3_X_STRING: ColouriseTADS3String(sc, lineState); visibleChars++; break; case SCE_T3_MSG_PARAM: ColouriseTADS3MsgParam(sc, lineState); break; case SCE_T3_LIB_DIRECTIVE: ColouriseTADS3LibDirective(sc, lineState); break; case SCE_T3_HTML_DEFAULT: ColouriseTADS3HTMLTag(sc, lineState); break; case SCE_T3_HTML_STRING: ColouriseTADSHTMLString(sc, lineState); break; case SCE_T3_BLOCK_COMMENT: ColouriseTADS3Comment(sc, lineState&T3_INT_EXPRESSION ? SCE_T3_X_DEFAULT : SCE_T3_DEFAULT); break; case SCE_T3_DEFAULT: case SCE_T3_X_DEFAULT: if (IsASpaceOrTab(sc.ch)) { sc.Forward(); } else if (sc.ch == '#' && visibleChars == 0) { ColouriseToEndOfLine(sc, SCE_T3_PREPROCESSOR, sc.state); } else if (sc.Match('/', '*')) { ColouriseTADS3Comment(sc, sc.state); visibleChars++; } else if (sc.Match('/', '/')) { ColouriseToEndOfLine(sc, SCE_T3_LINE_COMMENT, sc.state); } else if (sc.ch == '"') { bracketLevel = 0; ColouriseTADS3String(sc, lineState); visibleChars++; } else if (sc.ch == '\'') { ColouriseTADS3String(sc, lineState); visibleChars++; } else if (sc.state == SCE_T3_X_DEFAULT && bracketLevel == 0 && sc.Match('>', '>')) { sc.Forward(2); sc.SetState(SCE_T3_D_STRING); if (lineState & T3_INT_EXPRESSION_IN_TAG) sc.SetState(SCE_T3_HTML_STRING); lineState &= ~(T3_SINGLE_QUOTE|T3_INT_EXPRESSION |T3_INT_EXPRESSION_IN_TAG); } else if (IsATADS3Operator(sc.ch)) { if (sc.state == SCE_T3_X_DEFAULT) { if (sc.ch == '(') { bracketLevel++; } else if (sc.ch == ')' && bracketLevel > 0) { bracketLevel--; } } ColouriseTADS3Operator(sc); visibleChars++; } else if (IsANumberStart(sc)) { ColouriseTADS3Number(sc); visibleChars++; } else if (IsAWordStart(sc.ch)) { ColouriseTADS3Keyword(sc, keywordlists, endPos); visibleChars++; } else if (sc.Match("...")) { sc.SetState(SCE_T3_IDENTIFIER); sc.Forward(3); sc.SetState(SCE_T3_DEFAULT); } else { sc.Forward(); visibleChars++; } break; default: sc.SetState(SCE_T3_DEFAULT); sc.Forward(); } } sc.Complete(); } /* TADS3 has two styles of top level block (TLB). Eg // default style silverKey : Key 'small silver key' 'small silver key' "A small key glints in the sunlight. " ; and silverKey : Key { 'small silver key' 'small silver key' "A small key glints in the sunlight. " } Some constructs mandate one or the other, but usually the author has may choose either. T3_SEENSTART is used to indicate that a braceless TLB has been (potentially) seen and is also used to match the closing ';' of the default style. T3_EXPECTINGIDENTIFIER and T3_EXPECTINGPUNCTUATION are used to keep track of what characters may be seen without incrementing the block level. The general pattern is identifier identifier, acceptable punctuation characters are ':', ',', '(' and ')'. No attempt is made to ensure that punctuation characters are syntactically correct, eg parentheses match. A ')' always signifies the start of a block. We just need to check if it is followed by a '{', in which case we let the brace handling code handle the folding level. expectingIdentifier == false && expectingIdentifier == false Before the start of a TLB. expectingIdentifier == true && expectingIdentifier == true Currently in an identifier. Will accept identifier or punctuation. expectingIdentifier == true && expectingIdentifier == false Just seen a punctuation character & now waiting for an identifier to start. expectingIdentifier == false && expectingIdentifier == truee We were in an identifier and have seen space. Now waiting to see a punctuation character Space, comments & preprocessor directives are always acceptable and are equivalent. */ static const int T3_SEENSTART = 1 << 12; static const int T3_EXPECTINGIDENTIFIER = 1 << 13; static const int T3_EXPECTINGPUNCTUATION = 1 << 14; static inline bool IsStringTransition(int s1, int s2) { return s1 != s2 && (s1 == SCE_T3_S_STRING || s1 == SCE_T3_X_STRING || (s1 == SCE_T3_D_STRING && s2 != SCE_T3_X_DEFAULT)) && s2 != SCE_T3_LIB_DIRECTIVE && s2 != SCE_T3_MSG_PARAM && s2 != SCE_T3_HTML_TAG && s2 != SCE_T3_HTML_STRING; } static inline bool IsATADS3Punctuation(const int ch) { return ch == ':' || ch == ',' || ch == '(' || ch == ')'; } static inline bool IsAnIdentifier(const int style) { return style == SCE_T3_IDENTIFIER || style == SCE_T3_USER1 || style == SCE_T3_USER2 || style == SCE_T3_USER3; } static inline bool IsAnOperator(const int style) { return style == SCE_T3_OPERATOR || style == SCE_T3_BRACE; } static inline bool IsSpaceEquivalent(const int ch, const int style) { return isspace(ch) || style == SCE_T3_BLOCK_COMMENT || style == SCE_T3_LINE_COMMENT || style == SCE_T3_PREPROCESSOR; } static char peekAhead(unsigned int startPos, unsigned int endPos, Accessor &styler) { for (unsigned int i = startPos; i < endPos; i++) { int style = styler.StyleAt(i); char ch = styler[i]; if (!IsSpaceEquivalent(ch, style)) { if (IsAnIdentifier(style)) { return 'a'; } if (IsATADS3Punctuation(ch)) { return ':'; } if (ch == '{') { return '{'; } return '*'; } } return ' '; } static void FoldTADS3Doc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { unsigned int endPos = startPos + length; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int seenStart = levelCurrent & T3_SEENSTART; int expectingIdentifier = levelCurrent & T3_EXPECTINGIDENTIFIER; int expectingPunctuation = levelCurrent & T3_EXPECTINGPUNCTUATION; levelCurrent &= SC_FOLDLEVELNUMBERMASK; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; char ch = chNext; int stylePrev = style; bool redo = false; for (unsigned int i = startPos; i < endPos; i++) { if (redo) { redo = false; i--; } else { ch = chNext; chNext = styler.SafeGetCharAt(i + 1); stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); } bool atEOL = IsEOL(ch, chNext); if (levelNext == SC_FOLDLEVELBASE) { if (IsSpaceEquivalent(ch, style)) { if (expectingPunctuation) { expectingIdentifier = 0; } if (style == SCE_T3_BLOCK_COMMENT) { levelNext++; } } else if (ch == '{') { levelNext++; seenStart = 0; } else if (ch == '\'' || ch == '"' || ch == '[') { levelNext++; if (seenStart) { redo = true; } } else if (ch == ';') { seenStart = 0; expectingIdentifier = 0; expectingPunctuation = 0; } else if (expectingIdentifier && expectingPunctuation) { if (IsATADS3Punctuation(ch)) { if (ch == ')' && peekAhead(i+1, endPos, styler) != '{') { levelNext++; } else { expectingPunctuation = 0; } } else if (!IsAnIdentifier(style)) { levelNext++; } } else if (expectingIdentifier && !expectingPunctuation) { if (!IsAnIdentifier(style)) { levelNext++; } else { expectingPunctuation = T3_EXPECTINGPUNCTUATION; } } else if (!expectingIdentifier && expectingPunctuation) { if (!IsATADS3Punctuation(ch)) { levelNext++; } else { if (ch == ')' && peekAhead(i+1, endPos, styler) != '{') { levelNext++; } else { expectingIdentifier = T3_EXPECTINGIDENTIFIER; expectingPunctuation = 0; } } } else if (!expectingIdentifier && !expectingPunctuation) { if (IsAnIdentifier(style)) { seenStart = T3_SEENSTART; expectingIdentifier = T3_EXPECTINGIDENTIFIER; expectingPunctuation = T3_EXPECTINGPUNCTUATION; } } if (levelNext != SC_FOLDLEVELBASE && style != SCE_T3_BLOCK_COMMENT) { expectingIdentifier = 0; expectingPunctuation = 0; } } else if (levelNext == SC_FOLDLEVELBASE+1 && seenStart && ch == ';' && IsAnOperator(style)) { levelNext--; seenStart = 0; } else if (style == SCE_T3_BLOCK_COMMENT) { if (stylePrev != SCE_T3_BLOCK_COMMENT) { levelNext++; } else if (styleNext != SCE_T3_BLOCK_COMMENT && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelNext--; } } else if (ch == '\'' || ch == '"') { if (IsStringTransition(style, stylePrev)) { if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (IsStringTransition(style, styleNext)) { levelNext--; } } else if (IsAnOperator(style)) { if (ch == '{' || ch == '[') { // Measure the minimum before a '{' to allow // folding on "} else {" if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (ch == '}' || ch == ']') { levelNext--; } } if (atEOL) { if (seenStart && levelNext == SC_FOLDLEVELBASE) { switch (peekAhead(i+1, endPos, styler)) { case ' ': case '{': break; case '*': levelNext++; break; case 'a': if (expectingPunctuation) { levelNext++; } break; case ':': if (expectingIdentifier) { levelNext++; } break; } if (levelNext != SC_FOLDLEVELBASE) { expectingIdentifier = 0; expectingPunctuation = 0; } } int lev = levelMinCurrent | (levelNext | expectingIdentifier | expectingPunctuation | seenStart) << 16; if (levelMinCurrent < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; } } } static const char * const tads3WordList[] = { "TADS3 Keywords", "User defined 1", "User defined 2", "User defined 3", 0 }; LexerModule lmTADS3(SCLEX_TADS3, ColouriseTADS3Doc, "tads3", FoldTADS3Doc, tads3WordList); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexTAL.cxx0000644000175000017500000002556511615412040020755 00000000000000// Scintilla source code edit control /** @file LexTAL.cxx ** Lexer for TAL ** Based on LexPascal.cxx ** Written by Laurent le Tynevez ** Updated by Simon Steele September 2002 ** Updated by Mathias Rauen May 2003 (Delphi adjustments) ** Updated by Rod Falck, Aug 2006 Converted to TAL **/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif inline bool isTALoperator(char ch) { return ch == '\'' || ch == '@' || ch == '#' || isoperator(ch); } inline bool isTALwordchar(char ch) { return ch == '$' || ch == '^' || iswordchar(ch); } inline bool isTALwordstart(char ch) { return ch == '$' || ch == '^' || iswordstart(ch); } static void getRange(unsigned int start, unsigned int end, Accessor &styler, char *s, unsigned int len) { unsigned int i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = static_cast(tolower(styler[start + i])); i++; } s[i] = '\0'; } static bool IsStreamCommentStyle(int style) { return style == SCE_C_COMMENT || style == SCE_C_COMMENTDOC || style == SCE_C_COMMENTDOCKEYWORD || style == SCE_C_COMMENTDOCKEYWORDERROR; } static void ColourTo(Accessor &styler, unsigned int end, unsigned int attr, bool bInAsm) { if ((bInAsm) && (attr == SCE_C_OPERATOR || attr == SCE_C_NUMBER || attr == SCE_C_DEFAULT || attr == SCE_C_WORD || attr == SCE_C_IDENTIFIER)) { styler.ColourTo(end, SCE_C_REGEX); } else styler.ColourTo(end, attr); } // returns 1 if the item starts a class definition, and -1 if the word is "end", and 2 if the word is "asm" static int classifyWordTAL(unsigned int start, unsigned int end, /*WordList &keywords*/WordList *keywordlists[], Accessor &styler, bool bInAsm) { int ret = 0; WordList& keywords = *keywordlists[0]; WordList& builtins = *keywordlists[1]; WordList& nonreserved_keywords = *keywordlists[2]; char s[100]; getRange(start, end, styler, s, sizeof(s)); char chAttr = SCE_C_IDENTIFIER; if (isdigit(s[0]) || (s[0] == '.')) { chAttr = SCE_C_NUMBER; } else { if (keywords.InList(s)) { chAttr = SCE_C_WORD; if (strcmp(s, "asm") == 0) { ret = 2; } else if (strcmp(s, "end") == 0) { ret = -1; } } else if (s[0] == '$' || builtins.InList(s)) { chAttr = SCE_C_WORD2; } else if (nonreserved_keywords.InList(s)) { chAttr = SCE_C_UUID; } } ColourTo(styler, end, chAttr, (bInAsm && ret != -1)); return ret; } static int classifyFoldPointTAL(const char* s) { int lev = 0; if (!(isdigit(s[0]) || (s[0] == '.'))) { if (strcmp(s, "begin") == 0 || strcmp(s, "block") == 0) { lev=1; } else if (strcmp(s, "end") == 0) { lev=-1; } } return lev; } static void ColouriseTALDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos); int state = initStyle; if (state == SCE_C_CHARACTER) // Does not leak onto next line state = SCE_C_DEFAULT; char chPrev = ' '; char chNext = styler[startPos]; unsigned int lengthDoc = startPos + length; bool bInClassDefinition; int currentLine = styler.GetLine(startPos); if (currentLine > 0) { styler.SetLineState(currentLine, styler.GetLineState(currentLine-1)); bInClassDefinition = (styler.GetLineState(currentLine) == 1); } else { styler.SetLineState(currentLine, 0); bInClassDefinition = false; } bool bInAsm = (state == SCE_C_REGEX); if (bInAsm) state = SCE_C_DEFAULT; styler.StartSegment(startPos); int visibleChars = 0; for (unsigned int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) // Avoid triggering two times on Dos/Win // End of line if (state == SCE_C_CHARACTER) { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } visibleChars = 0; currentLine++; styler.SetLineState(currentLine, (bInClassDefinition ? 1 : 0)); } if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); chPrev = ' '; i += 1; continue; } if (state == SCE_C_DEFAULT) { if (isTALwordstart(ch)) { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_IDENTIFIER; } else if (ch == '!' && chNext != '*') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENT; } else if (ch == '!' && chNext == '*') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENTDOC; } else if (ch == '-' && chNext == '-') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENTLINE; } else if (ch == '"') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_STRING; } else if (ch == '?' && visibleChars == 0) { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_PREPROCESSOR; } else if (isTALoperator(ch)) { ColourTo(styler, i-1, state, bInAsm); ColourTo(styler, i, SCE_C_OPERATOR, bInAsm); } } else if (state == SCE_C_IDENTIFIER) { if (!isTALwordchar(ch)) { int lStateChange = classifyWordTAL(styler.GetStartSegment(), i - 1, keywordlists, styler, bInAsm); if(lStateChange == 1) { styler.SetLineState(currentLine, 1); bInClassDefinition = true; } else if(lStateChange == 2) { bInAsm = true; } else if(lStateChange == -1) { styler.SetLineState(currentLine, 0); bInClassDefinition = false; bInAsm = false; } state = SCE_C_DEFAULT; chNext = styler.SafeGetCharAt(i + 1); if (ch == '!' && chNext != '*') { state = SCE_C_COMMENT; } else if (ch == '!' && chNext == '*') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENTDOC; } else if (ch == '-' && chNext == '-') { state = SCE_C_COMMENTLINE; } else if (ch == '"') { state = SCE_C_STRING; } else if (isTALoperator(ch)) { ColourTo(styler, i, SCE_C_OPERATOR, bInAsm); } } } else { if (state == SCE_C_PREPROCESSOR) { if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_DEFAULT; } } else if (state == SCE_C_COMMENT) { if (ch == '!' || (ch == '\r' || ch == '\n') ) { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } } else if (state == SCE_C_COMMENTDOC) { if (ch == '!' || (ch == '\r' || ch == '\n')) { if (((i > styler.GetStartSegment() + 2) || ( (initStyle == SCE_C_COMMENTDOC) && (styler.GetStartSegment() == static_cast(startPos))))) { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } } } else if (state == SCE_C_COMMENTLINE) { if (ch == '\r' || ch == '\n') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_DEFAULT; } } else if (state == SCE_C_STRING) { if (ch == '"') { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } } } if (!isspacechar(ch)) visibleChars++; chPrev = ch; } ColourTo(styler, lengthDoc - 1, state, bInAsm); } static void FoldTALDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; bool was_end = false; bool section = false; int lastStart = 0; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (stylePrev == SCE_C_DEFAULT && (style == SCE_C_WORD || style == SCE_C_UUID || style == SCE_C_PREPROCESSOR)) { // Store last word start point. lastStart = i; } if (stylePrev == SCE_C_WORD || style == SCE_C_UUID || stylePrev == SCE_C_PREPROCESSOR) { if(isTALwordchar(ch) && !isTALwordchar(chNext)) { char s[100]; getRange(lastStart, i, styler, s, sizeof(s)); if (stylePrev == SCE_C_PREPROCESSOR && strcmp(s, "?section") == 0) { section = true; levelCurrent = 1; levelPrev = 0; } else if (stylePrev == SCE_C_WORD || stylePrev == SCE_C_UUID) { if (strcmp(s, "block") == 0) { // block keyword is ignored immediately after end keyword if (!was_end) levelCurrent++; } else levelCurrent += classifyFoldPointTAL(s); if (strcmp(s, "end") == 0) { was_end = true; } else { was_end = false; } } } } if (foldComment && (style == SCE_C_COMMENTLINE)) { if ((ch == '/') && (chNext == '/')) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelCurrent++; } else if (chNext2 == '}') { levelCurrent--; } } } if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { if (ch == '{' && chNext == '$') { unsigned int j=i+2; // skip {$ while ((j levelPrev || section) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; section = false; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const TALWordListDesc[] = { "Keywords", "Builtins", 0 }; LexerModule lmTAL(SCLEX_TAL, ColouriseTALDoc, "TAL", FoldTALDoc, TALWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexBash.cxx0000644000175000017500000005013211763437013021211 00000000000000// Scintilla source code edit control /** @file LexBash.cxx ** Lexer for Bash. **/ // Copyright 2004-2010 by Neil Hodgson // Adapted from LexPerl by Kein-Hong Man 2004 // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #define HERE_DELIM_MAX 256 // define this if you want 'invalid octals' to be marked as errors // usually, this is not a good idea, permissive lexing is better #undef PEDANTIC_OCTAL #define BASH_BASE_ERROR 65 #define BASH_BASE_DECIMAL 66 #define BASH_BASE_HEX 67 #ifdef PEDANTIC_OCTAL #define BASH_BASE_OCTAL 68 #define BASH_BASE_OCTAL_ERROR 69 #endif // state constants for parts of a bash command segment #define BASH_CMD_BODY 0 #define BASH_CMD_START 1 #define BASH_CMD_WORD 2 #define BASH_CMD_TEST 3 #define BASH_CMD_ARITH 4 #define BASH_CMD_DELIM 5 static inline int translateBashDigit(int ch) { if (ch >= '0' && ch <= '9') { return ch - '0'; } else if (ch >= 'a' && ch <= 'z') { return ch - 'a' + 10; } else if (ch >= 'A' && ch <= 'Z') { return ch - 'A' + 36; } else if (ch == '@') { return 62; } else if (ch == '_') { return 63; } return BASH_BASE_ERROR; } static inline int getBashNumberBase(char *s) { int i = 0; int base = 0; while (*s) { base = base * 10 + (*s++ - '0'); i++; } if (base > 64 || i > 2) { return BASH_BASE_ERROR; } return base; } static int opposite(int ch) { if (ch == '(') return ')'; if (ch == '[') return ']'; if (ch == '{') return '}'; if (ch == '<') return '>'; return ch; } static void ColouriseBashDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList cmdDelimiter, bashStruct, bashStruct_in; cmdDelimiter.Set("| || |& & && ; ;; ( ) { }"); bashStruct.Set("if elif fi while until else then do done esac eval"); bashStruct_in.Set("for case select"); CharacterSet setWordStart(CharacterSet::setAlpha, "_"); // note that [+-] are often parts of identifiers in shell scripts CharacterSet setWord(CharacterSet::setAlphaNum, "._+-"); CharacterSet setBashOperator(CharacterSet::setNone, "^&%()-+=|{}[]:;>,*/(ch); Delimiter[DelimiterLength] = '\0'; } ~HereDocCls() { delete []Delimiter; } }; HereDocCls HereDoc; class QuoteCls { // Class to manage quote pairs (simplified vs LexPerl) public: int Count; int Up, Down; QuoteCls() { Count = 0; Up = '\0'; Down = '\0'; } void Open(int u) { Count++; Up = u; Down = opposite(Up); } void Start(int u) { Count = 0; Open(u); } }; QuoteCls Quote; int numBase = 0; int digit; unsigned int endPos = startPos + length; int cmdState = BASH_CMD_START; int testExprType = 0; // Always backtracks to the start of a line that is not a continuation // of the previous line (i.e. start of a bash command segment) int ln = styler.GetLine(startPos); for (;;) { startPos = styler.LineStart(ln); if (ln == 0 || styler.GetLineState(ln) == BASH_CMD_START) break; ln--; } initStyle = SCE_SH_DEFAULT; StyleContext sc(startPos, endPos - startPos, initStyle, styler); for (; sc.More(); sc.Forward()) { // handle line continuation, updates per-line stored state if (sc.atLineStart) { ln = styler.GetLine(sc.currentPos); if (sc.state == SCE_SH_STRING || sc.state == SCE_SH_BACKTICKS || sc.state == SCE_SH_CHARACTER || sc.state == SCE_SH_HERE_Q || sc.state == SCE_SH_COMMENTLINE || sc.state == SCE_SH_PARAM) { // force backtrack while retaining cmdState styler.SetLineState(ln, BASH_CMD_BODY); } else { if (ln > 0) { if ((sc.GetRelative(-3) == '\\' && sc.GetRelative(-2) == '\r' && sc.chPrev == '\n') || sc.GetRelative(-2) == '\\') { // handle '\' line continuation // retain last line's state } else cmdState = BASH_CMD_START; } styler.SetLineState(ln, cmdState); } } // controls change of cmdState at the end of a non-whitespace element // states BODY|TEST|ARITH persist until the end of a command segment // state WORD persist, but ends with 'in' or 'do' construct keywords int cmdStateNew = BASH_CMD_BODY; if (cmdState == BASH_CMD_TEST || cmdState == BASH_CMD_ARITH || cmdState == BASH_CMD_WORD) cmdStateNew = cmdState; int stylePrev = sc.state; // Determine if the current state should terminate. switch (sc.state) { case SCE_SH_OPERATOR: sc.SetState(SCE_SH_DEFAULT); if (cmdState == BASH_CMD_DELIM) // if command delimiter, start new command cmdStateNew = BASH_CMD_START; else if (sc.chPrev == '\\') // propagate command state if line continued cmdStateNew = cmdState; break; case SCE_SH_WORD: // "." never used in Bash variable names but used in file names if (!setWord.Contains(sc.ch)) { char s[500]; char s2[10]; sc.GetCurrent(s, sizeof(s)); // allow keywords ending in a whitespace or command delimiter s2[0] = static_cast(sc.ch); s2[1] = '\0'; bool keywordEnds = IsASpace(sc.ch) || cmdDelimiter.InList(s2); // 'in' or 'do' may be construct keywords if (cmdState == BASH_CMD_WORD) { if (strcmp(s, "in") == 0 && keywordEnds) cmdStateNew = BASH_CMD_BODY; else if (strcmp(s, "do") == 0 && keywordEnds) cmdStateNew = BASH_CMD_START; else sc.ChangeState(SCE_SH_IDENTIFIER); sc.SetState(SCE_SH_DEFAULT); break; } // a 'test' keyword starts a test expression if (strcmp(s, "test") == 0) { if (cmdState == BASH_CMD_START && keywordEnds) { cmdStateNew = BASH_CMD_TEST; testExprType = 0; } else sc.ChangeState(SCE_SH_IDENTIFIER); } // detect bash construct keywords else if (bashStruct.InList(s)) { if (cmdState == BASH_CMD_START && keywordEnds) cmdStateNew = BASH_CMD_START; else sc.ChangeState(SCE_SH_IDENTIFIER); } // 'for'|'case'|'select' needs 'in'|'do' to be highlighted later else if (bashStruct_in.InList(s)) { if (cmdState == BASH_CMD_START && keywordEnds) cmdStateNew = BASH_CMD_WORD; else sc.ChangeState(SCE_SH_IDENTIFIER); } // disambiguate option items and file test operators else if (s[0] == '-') { if (cmdState != BASH_CMD_TEST) sc.ChangeState(SCE_SH_IDENTIFIER); } // disambiguate keywords and identifiers else if (cmdState != BASH_CMD_START || !(keywords.InList(s) && keywordEnds)) { sc.ChangeState(SCE_SH_IDENTIFIER); } sc.SetState(SCE_SH_DEFAULT); } break; case SCE_SH_IDENTIFIER: if (sc.chPrev == '\\') { // for escaped chars sc.ForwardSetState(SCE_SH_DEFAULT); } else if (!setWord.Contains(sc.ch)) { sc.SetState(SCE_SH_DEFAULT); } break; case SCE_SH_NUMBER: digit = translateBashDigit(sc.ch); if (numBase == BASH_BASE_DECIMAL) { if (sc.ch == '#') { char s[10]; sc.GetCurrent(s, sizeof(s)); numBase = getBashNumberBase(s); if (numBase != BASH_BASE_ERROR) break; } else if (IsADigit(sc.ch)) break; } else if (numBase == BASH_BASE_HEX) { if (IsADigit(sc.ch, 16)) break; #ifdef PEDANTIC_OCTAL } else if (numBase == BASH_BASE_OCTAL || numBase == BASH_BASE_OCTAL_ERROR) { if (digit <= 7) break; if (digit <= 9) { numBase = BASH_BASE_OCTAL_ERROR; break; } #endif } else if (numBase == BASH_BASE_ERROR) { if (digit <= 9) break; } else { // DD#DDDD number style handling if (digit != BASH_BASE_ERROR) { if (numBase <= 36) { // case-insensitive if base<=36 if (digit >= 36) digit -= 26; } if (digit < numBase) break; if (digit <= 9) { numBase = BASH_BASE_ERROR; break; } } } // fallthrough when number is at an end or error if (numBase == BASH_BASE_ERROR #ifdef PEDANTIC_OCTAL || numBase == BASH_BASE_OCTAL_ERROR #endif ) { sc.ChangeState(SCE_SH_ERROR); } sc.SetState(SCE_SH_DEFAULT); break; case SCE_SH_COMMENTLINE: if (sc.atLineEnd && sc.chPrev != '\\') { sc.SetState(SCE_SH_DEFAULT); } break; case SCE_SH_HERE_DELIM: // From Bash info: // --------------- // Specifier format is: <<[-]WORD // Optional '-' is for removal of leading tabs from here-doc. // Whitespace acceptable after <<[-] operator // if (HereDoc.State == 0) { // '<<' encountered HereDoc.Quote = sc.chNext; HereDoc.Quoted = false; HereDoc.DelimiterLength = 0; HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; if (sc.chNext == '\'' || sc.chNext == '\"') { // a quoted here-doc delimiter (' or ") sc.Forward(); HereDoc.Quoted = true; HereDoc.State = 1; } else if (!HereDoc.Indent && sc.chNext == '-') { // <<- indent case HereDoc.Indent = true; } else if (setHereDoc.Contains(sc.chNext)) { // an unquoted here-doc delimiter, no special handling // TODO check what exactly bash considers part of the delim HereDoc.State = 1; } else if (sc.chNext == '<') { // HERE string <<< sc.Forward(); sc.ForwardSetState(SCE_SH_DEFAULT); } else if (IsASpace(sc.chNext)) { // eat whitespace } else if (setLeftShift.Contains(sc.chNext)) { // left shift << or <<= operator cases sc.ChangeState(SCE_SH_OPERATOR); sc.ForwardSetState(SCE_SH_DEFAULT); } else { // symbols terminates; deprecated zero-length delimiter HereDoc.State = 1; } } else if (HereDoc.State == 1) { // collect the delimiter if (setHereDoc2.Contains(sc.ch) || sc.chPrev == '\\') { HereDoc.Append(sc.ch); } else if (HereDoc.Quoted && sc.ch == HereDoc.Quote) { // closing quote => end of delimiter sc.ForwardSetState(SCE_SH_DEFAULT); } else if (sc.ch == '\\') { // skip escape prefix } else { sc.SetState(SCE_SH_DEFAULT); } if (HereDoc.DelimiterLength >= HERE_DELIM_MAX - 1) { // force blowup sc.SetState(SCE_SH_ERROR); HereDoc.State = 0; } } break; case SCE_SH_HERE_Q: // HereDoc.State == 2 if (sc.atLineStart) { sc.SetState(SCE_SH_HERE_Q); int prefixws = 0; while (IsASpace(sc.ch) && !sc.atLineEnd) { // whitespace prefix sc.Forward(); prefixws++; } if (prefixws > 0) sc.SetState(SCE_SH_HERE_Q); while (!sc.atLineEnd) { sc.Forward(); } char s[HERE_DELIM_MAX]; sc.GetCurrent(s, sizeof(s)); if (sc.LengthCurrent() == 0) break; if (s[strlen(s) - 1] == '\r') s[strlen(s) - 1] = '\0'; if (strcmp(HereDoc.Delimiter, s) == 0) { if ((prefixws == 0) || // indentation rule (prefixws > 0 && HereDoc.Indent)) { sc.SetState(SCE_SH_DEFAULT); break; } } } break; case SCE_SH_SCALAR: // variable names if (!setParam.Contains(sc.ch)) { if (sc.LengthCurrent() == 1) { // Special variable: $(, $_ etc. sc.ForwardSetState(SCE_SH_DEFAULT); } else { sc.SetState(SCE_SH_DEFAULT); } } break; case SCE_SH_STRING: // delimited styles case SCE_SH_BACKTICKS: case SCE_SH_PARAM: if (sc.ch == '\\' && Quote.Up != '\\') { sc.Forward(); } else if (sc.ch == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { sc.ForwardSetState(SCE_SH_DEFAULT); } } else if (sc.ch == Quote.Up) { Quote.Count++; } break; case SCE_SH_CHARACTER: // singly-quoted strings if (sc.ch == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { sc.ForwardSetState(SCE_SH_DEFAULT); } } break; } // Must check end of HereDoc state 1 before default state is handled if (HereDoc.State == 1 && sc.atLineEnd) { // Begin of here-doc (the line after the here-doc delimiter): // Lexically, the here-doc starts from the next line after the >>, but the // first line of here-doc seem to follow the style of the last EOL sequence HereDoc.State = 2; if (HereDoc.Quoted) { if (sc.state == SCE_SH_HERE_DELIM) { // Missing quote at end of string! We are stricter than bash. // Colour here-doc anyway while marking this bit as an error. sc.ChangeState(SCE_SH_ERROR); } // HereDoc.Quote always == '\'' } sc.SetState(SCE_SH_HERE_Q); } // update cmdState about the current command segment if (stylePrev != SCE_SH_DEFAULT && sc.state == SCE_SH_DEFAULT) { cmdState = cmdStateNew; } // Determine if a new state should be entered. if (sc.state == SCE_SH_DEFAULT) { if (sc.ch == '\\') { // Bash can escape any non-newline as a literal sc.SetState(SCE_SH_IDENTIFIER); if (sc.chNext == '\r' || sc.chNext == '\n') sc.SetState(SCE_SH_OPERATOR); } else if (IsADigit(sc.ch)) { sc.SetState(SCE_SH_NUMBER); numBase = BASH_BASE_DECIMAL; if (sc.ch == '0') { // hex,octal if (sc.chNext == 'x' || sc.chNext == 'X') { numBase = BASH_BASE_HEX; sc.Forward(); } else if (IsADigit(sc.chNext)) { #ifdef PEDANTIC_OCTAL numBase = BASH_BASE_OCTAL; #else numBase = BASH_BASE_HEX; #endif } } } else if (setWordStart.Contains(sc.ch)) { sc.SetState(SCE_SH_WORD); } else if (sc.ch == '#') { sc.SetState(SCE_SH_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_SH_STRING); Quote.Start(sc.ch); } else if (sc.ch == '\'') { sc.SetState(SCE_SH_CHARACTER); Quote.Start(sc.ch); } else if (sc.ch == '`') { sc.SetState(SCE_SH_BACKTICKS); Quote.Start(sc.ch); } else if (sc.ch == '$') { if (sc.Match("$((")) { sc.SetState(SCE_SH_OPERATOR); // handle '((' later continue; } sc.SetState(SCE_SH_SCALAR); sc.Forward(); if (sc.ch == '{') { sc.ChangeState(SCE_SH_PARAM); } else if (sc.ch == '\'') { sc.ChangeState(SCE_SH_STRING); } else if (sc.ch == '"') { sc.ChangeState(SCE_SH_STRING); } else if (sc.ch == '(' || sc.ch == '`') { sc.ChangeState(SCE_SH_BACKTICKS); } else { continue; // scalar has no delimiter pair } // fallthrough, open delim for $[{'"(`] Quote.Start(sc.ch); } else if (sc.Match('<', '<')) { sc.SetState(SCE_SH_HERE_DELIM); HereDoc.State = 0; HereDoc.Indent = false; } else if (sc.ch == '-' && // one-char file test operators setSingleCharOp.Contains(sc.chNext) && !setWord.Contains(sc.GetRelative(2)) && IsASpace(sc.chPrev)) { sc.SetState(SCE_SH_WORD); sc.Forward(); } else if (setBashOperator.Contains(sc.ch)) { char s[10]; bool isCmdDelim = false; sc.SetState(SCE_SH_OPERATOR); // handle opening delimiters for test/arithmetic expressions - ((,[[,[ if (cmdState == BASH_CMD_START || cmdState == BASH_CMD_BODY) { if (sc.Match('(', '(')) { cmdState = BASH_CMD_ARITH; sc.Forward(); } else if (sc.Match('[', '[') && IsASpace(sc.GetRelative(2))) { cmdState = BASH_CMD_TEST; testExprType = 1; sc.Forward(); } else if (sc.ch == '[' && IsASpace(sc.chNext)) { cmdState = BASH_CMD_TEST; testExprType = 2; } } // special state -- for ((x;y;z)) in ... looping if (cmdState == BASH_CMD_WORD && sc.Match('(', '(')) { cmdState = BASH_CMD_ARITH; sc.Forward(); continue; } // handle command delimiters in command START|BODY|WORD state, also TEST if 'test' if (cmdState == BASH_CMD_START || cmdState == BASH_CMD_BODY || cmdState == BASH_CMD_WORD || (cmdState == BASH_CMD_TEST && testExprType == 0)) { s[0] = static_cast(sc.ch); if (setBashOperator.Contains(sc.chNext)) { s[1] = static_cast(sc.chNext); s[2] = '\0'; isCmdDelim = cmdDelimiter.InList(s); if (isCmdDelim) sc.Forward(); } if (!isCmdDelim) { s[1] = '\0'; isCmdDelim = cmdDelimiter.InList(s); } if (isCmdDelim) { cmdState = BASH_CMD_DELIM; continue; } } // handle closing delimiters for test/arithmetic expressions - )),]],] if (cmdState == BASH_CMD_ARITH && sc.Match(')', ')')) { cmdState = BASH_CMD_BODY; sc.Forward(); } else if (cmdState == BASH_CMD_TEST && IsASpace(sc.chPrev)) { if (sc.Match(']', ']') && testExprType == 1) { sc.Forward(); cmdState = BASH_CMD_BODY; } else if (sc.ch == ']' && testExprType == 2) { cmdState = BASH_CMD_BODY; } } } }// sc.state } sc.Complete(); } static bool IsCommentLine(int line, Accessor &styler) { int pos = styler.LineStart(line); int eol_pos = styler.LineStart(line + 1) - 1; for (int i = pos; i < eol_pos; i++) { char ch = styler[i]; if (ch == '#') return true; else if (ch != ' ' && ch != '\t') return false; } return false; } static void FoldBashDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); // Comment folding if (foldComment && atEOL && IsCommentLine(lineCurrent, styler)) { if (!IsCommentLine(lineCurrent - 1, styler) && IsCommentLine(lineCurrent + 1, styler)) levelCurrent++; else if (IsCommentLine(lineCurrent - 1, styler) && !IsCommentLine(lineCurrent + 1, styler)) levelCurrent--; } if (style == SCE_SH_OPERATOR) { if (ch == '{') { levelCurrent++; } else if (ch == '}') { levelCurrent--; } } // Here Document folding if (style == SCE_SH_HERE_DELIM) { if (ch == '<' && chNext == '<') { levelCurrent++; } } else if (style == SCE_SH_HERE_Q && styler.StyleAt(i+1) == SCE_PL_DEFAULT) { levelCurrent--; } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const bashWordListDesc[] = { "Keywords", 0 }; LexerModule lmBash(SCLEX_BASH, ColouriseBashDoc, "bash", FoldBashDoc, bashWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexPowerPro.cxx0000644000175000017500000004757311634611460022125 00000000000000// Scintilla source code edit control // @file LexPowerPro.cxx // PowerPro utility, written by Bruce Switzer, is available from http://powerpro.webeddie.com // PowerPro lexer is written by Christopher Bean (cbean@cb-software.net) // // Lexer code heavily borrowed from: // LexAU3.cxx by Jos van der Zande // LexCPP.cxx by Neil Hodgson // LexVB.cxx by Neil Hodgson // // Changes: // 2008-10-25 - Initial release // 2008-10-26 - Changed how is hilighted in 'function ' so that // local isFunction = "" and local functions = "" don't get falsely highlighted // 2008-12-14 - Added bounds checking for szFirstWord and szDo // - Replaced SetOfCharacters with CharacterSet // - Made sure that CharacterSet::Contains is passed only positive values // - Made sure that the return value of Accessor::SafeGetCharAt is positive before // passing to functions that require positive values like isspacechar() // - Removed unused visibleChars processing from ColourisePowerProDoc() // - Fixed bug with folding logic where line continuations didn't end where // they were supposed to // - Moved all helper functions to the top of the file // 2010-06-03 - Added onlySpaces variable to allow the @function and ;comment styles to be indented // - Modified HasFunction function to be a bit more robust // - Renamed HasFunction function to IsFunction // - Cleanup // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsStreamCommentStyle(int style) { return style == SCE_POWERPRO_COMMENTBLOCK; } static inline bool IsLineEndChar(unsigned char ch) { return ch == 0x0a //LF || ch == 0x0c //FF || ch == 0x0d; //CR } static bool IsContinuationLine(unsigned int szLine, Accessor &styler) { int startPos = styler.LineStart(szLine); int endPos = styler.LineStart(szLine + 1) - 2; while (startPos < endPos) { char stylech = styler.StyleAt(startPos); if (!(stylech == SCE_POWERPRO_COMMENTBLOCK)) { char ch = styler.SafeGetCharAt(endPos); char chPrev = styler.SafeGetCharAt(endPos - 1); char chPrevPrev = styler.SafeGetCharAt(endPos - 2); if (ch > 0 && chPrev > 0 && chPrevPrev > 0 && !isspacechar(ch) && !isspacechar(chPrev) && !isspacechar(chPrevPrev) ) return (chPrevPrev == ';' && chPrev == ';' && ch == '+'); } endPos--; // skip to next char } return false; } // Routine to find first none space on the current line and return its Style // needed for comment lines not starting on pos 1 static int GetStyleFirstWord(int szLine, Accessor &styler) { int startPos = styler.LineStart(szLine); int endPos = styler.LineStart(szLine + 1) - 1; char ch = styler.SafeGetCharAt(startPos); while (ch > 0 && isspacechar(ch) && startPos < endPos) { startPos++; // skip to next char ch = styler.SafeGetCharAt(startPos); } return styler.StyleAt(startPos); } //returns true if there is a function to highlight //used to highlight in 'function ' //note: // sample line (without quotes): "\tfunction asdf() // currentPos will be the position of 'a' static bool IsFunction(Accessor &styler, unsigned int currentPos) { const char function[10] = "function "; //10 includes \0 unsigned int numberOfCharacters = sizeof(function) - 1; unsigned int position = currentPos - numberOfCharacters; //compare each character with the letters in the function array //return false if ALL don't match for (unsigned int i = 0; i < numberOfCharacters; i++) { char c = styler.SafeGetCharAt(position++); if (c != function[i]) return false; } //make sure that there are only spaces (or tabs) between the beginning //of the line and the function declaration position = currentPos - numberOfCharacters - 1; //-1 to move to char before 'function' for (unsigned int j = 0; j < 16; j++) { //check up to 16 preceeding characters char c = styler.SafeGetCharAt(position--, '\0'); //if can't read char, return NUL (past beginning of document) if (c <= 0) //reached beginning of document return true; if (c > 0 && IsLineEndChar(c)) return true; else if (c > 0 && !IsASpaceOrTab(c)) return false; } //fall-through return false; } static void ColourisePowerProDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler, bool caseSensitive) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; //define the character sets CharacterSet setWordStart(CharacterSet::setAlpha, "_@", 0x80, true); CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true); StyleContext sc(startPos, length, initStyle, styler); char s_save[100]; //for last line highlighting //are there only spaces between the first letter of the line and the beginning of the line bool onlySpaces = true; for (; sc.More(); sc.Forward()) { // save the total current word for eof processing char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if ((sc.ch > 0) && setWord.Contains(sc.ch)) { strcpy(s_save,s); int tp = static_cast(strlen(s_save)); if (tp < 99) { s_save[tp] = static_cast(tolower(sc.ch)); s_save[tp+1] = '\0'; } } if (sc.atLineStart) { if (sc.state == SCE_POWERPRO_DOUBLEQUOTEDSTRING) { // Prevent SCE_POWERPRO_STRINGEOL from leaking back to previous line which // ends with a line continuation by locking in the state upto this position. sc.SetState(SCE_POWERPRO_DOUBLEQUOTEDSTRING); } } // Determine if the current state should terminate. switch (sc.state) { case SCE_POWERPRO_OPERATOR: sc.SetState(SCE_POWERPRO_DEFAULT); break; case SCE_POWERPRO_NUMBER: if (!IsADigit(sc.ch)) sc.SetState(SCE_POWERPRO_DEFAULT); break; case SCE_POWERPRO_IDENTIFIER: //if ((sc.ch > 0) && !setWord.Contains(sc.ch) || (sc.ch == '.')) { // use this line if don't want to match keywords with . in them. ie: win.debug will match both win and debug so win debug will also be colorized if ((sc.ch > 0) && !setWord.Contains(sc.ch)){ // || (sc.ch == '.')) { // use this line if you want to match keywords with a . ie: win.debug will only match win.debug neither win nor debug will be colorized separately char s[1000]; if (caseSensitive) { sc.GetCurrent(s, sizeof(s)); } else { sc.GetCurrentLowered(s, sizeof(s)); } if (keywords.InList(s)) { sc.ChangeState(SCE_POWERPRO_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_POWERPRO_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_POWERPRO_WORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_POWERPRO_WORD4); } sc.SetState(SCE_POWERPRO_DEFAULT); } break; case SCE_POWERPRO_LINECONTINUE: if (sc.atLineStart) { sc.SetState(SCE_POWERPRO_DEFAULT); } else if (sc.Match('/', '*') || sc.Match('/', '/')) { sc.SetState(SCE_POWERPRO_DEFAULT); } break; case SCE_POWERPRO_COMMENTBLOCK: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_POWERPRO_DEFAULT); } break; case SCE_POWERPRO_COMMENTLINE: if (sc.atLineStart) { sc.SetState(SCE_POWERPRO_DEFAULT); } break; case SCE_POWERPRO_DOUBLEQUOTEDSTRING: if (sc.atLineEnd) { sc.ChangeState(SCE_POWERPRO_STRINGEOL); } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_POWERPRO_DEFAULT); } break; case SCE_POWERPRO_SINGLEQUOTEDSTRING: if (sc.atLineEnd) { sc.ChangeState(SCE_POWERPRO_STRINGEOL); } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_POWERPRO_DEFAULT); } break; case SCE_POWERPRO_STRINGEOL: if (sc.atLineStart) { sc.SetState(SCE_POWERPRO_DEFAULT); } break; case SCE_POWERPRO_VERBATIM: if (sc.ch == '\"') { if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_POWERPRO_DEFAULT); } } break; case SCE_POWERPRO_ALTQUOTE: if (sc.ch == '#') { if (sc.chNext == '#') { sc.Forward(); } else { sc.ForwardSetState(SCE_POWERPRO_DEFAULT); } } break; case SCE_POWERPRO_FUNCTION: if (isspacechar(sc.ch) || sc.ch == '(') { sc.SetState(SCE_POWERPRO_DEFAULT); } break; } // Determine if a new state should be entered. if (sc.state == SCE_POWERPRO_DEFAULT) { if (sc.Match('?', '\"')) { sc.SetState(SCE_POWERPRO_VERBATIM); sc.Forward(); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_POWERPRO_NUMBER); }else if (sc.Match('?','#')) { if (sc.ch == '?' && sc.chNext == '#') { sc.SetState(SCE_POWERPRO_ALTQUOTE); sc.Forward(); } } else if (IsFunction(styler, sc.currentPos)) { //highlight in 'function ' sc.SetState(SCE_POWERPRO_FUNCTION); } else if (onlySpaces && sc.ch == '@') { //alternate function definition [label] sc.SetState(SCE_POWERPRO_FUNCTION); } else if ((sc.ch > 0) && (setWordStart.Contains(sc.ch) || (sc.ch == '?'))) { sc.SetState(SCE_POWERPRO_IDENTIFIER); } else if (sc.Match(";;+")) { sc.SetState(SCE_POWERPRO_LINECONTINUE); } else if (sc.Match('/', '*')) { sc.SetState(SCE_POWERPRO_COMMENTBLOCK); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { sc.SetState(SCE_POWERPRO_COMMENTLINE); } else if (onlySpaces && sc.ch == ';') { //legacy comment that can only have blank space in front of it sc.SetState(SCE_POWERPRO_COMMENTLINE); } else if (sc.Match(";;")) { sc.SetState(SCE_POWERPRO_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_POWERPRO_DOUBLEQUOTEDSTRING); } else if (sc.ch == '\'') { sc.SetState(SCE_POWERPRO_SINGLEQUOTEDSTRING); } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_POWERPRO_OPERATOR); } } //maintain a record of whether or not all the preceding characters on //a line are space characters if (onlySpaces && !IsASpaceOrTab(sc.ch)) onlySpaces = false; //reset when starting a new line if (sc.atLineEnd) onlySpaces = true; } //************************************* // Colourize the last word correctly //************************************* if (sc.state == SCE_POWERPRO_IDENTIFIER) { if (keywords.InList(s_save)) { sc.ChangeState(SCE_POWERPRO_WORD); sc.SetState(SCE_POWERPRO_DEFAULT); } else if (keywords2.InList(s_save)) { sc.ChangeState(SCE_POWERPRO_WORD2); sc.SetState(SCE_POWERPRO_DEFAULT); } else if (keywords3.InList(s_save)) { sc.ChangeState(SCE_POWERPRO_WORD3); sc.SetState(SCE_POWERPRO_DEFAULT); } else if (keywords4.InList(s_save)) { sc.ChangeState(SCE_POWERPRO_WORD4); sc.SetState(SCE_POWERPRO_DEFAULT); } else { sc.SetState(SCE_POWERPRO_DEFAULT); } } sc.Complete(); } static void FoldPowerProDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { //define the character sets CharacterSet setWordStart(CharacterSet::setAlpha, "_@", 0x80, true); CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true); //used to tell if we're recursively folding the whole document, or just a small piece (ie: if statement or 1 function) bool isFoldingAll = true; int endPos = startPos + length; int lastLine = styler.GetLine(styler.Length()); //used to help fold the last line correctly // get settings from the config files for folding comments and preprocessor lines bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldInComment = styler.GetPropertyInt("fold.comment") == 2; bool foldCompact = true; // Backtrack to previous line in case need to fix its fold status int lineCurrent = styler.GetLine(startPos); if (startPos > 0) { isFoldingAll = false; if (lineCurrent > 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); } } // vars for style of previous/current/next lines int style = GetStyleFirstWord(lineCurrent,styler); int stylePrev = 0; // find the first previous line without continuation character at the end while ((lineCurrent > 0 && IsContinuationLine(lineCurrent, styler)) || (lineCurrent > 1 && IsContinuationLine(lineCurrent - 1, styler))) { lineCurrent--; startPos = styler.LineStart(lineCurrent); } if (lineCurrent > 0) { stylePrev = GetStyleFirstWord(lineCurrent-1,styler); } // vars for getting first word to check for keywords bool isFirstWordStarted = false; bool isFirstWordEnded = false; const unsigned int FIRST_WORD_MAX_LEN = 10; char szFirstWord[FIRST_WORD_MAX_LEN] = ""; unsigned int firstWordLen = 0; char szDo[3]=""; int szDolen = 0; bool isDoLastWord = false; // var for indentlevel int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelNext = levelCurrent; int visibleChars = 0; int functionCount = 0; char chNext = styler.SafeGetCharAt(startPos); char chPrev = '\0'; char chPrevPrev = '\0'; char chPrevPrevPrev = '\0'; for (int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch > 0) && setWord.Contains(ch)) visibleChars++; // get the syle for the current character neede to check in comment int stylech = styler.StyleAt(i); // start the capture of the first word if (!isFirstWordStarted && (ch > 0)) { if (setWord.Contains(ch) || setWordStart.Contains(ch) || ch == ';' || ch == '/') { isFirstWordStarted = true; if (firstWordLen < FIRST_WORD_MAX_LEN - 1) { szFirstWord[firstWordLen++] = static_cast(tolower(ch)); szFirstWord[firstWordLen] = '\0'; } } } // continue capture of the first word on the line else if (isFirstWordStarted && !isFirstWordEnded && (ch > 0)) { if (!setWord.Contains(ch)) { isFirstWordEnded = true; } else if (firstWordLen < (FIRST_WORD_MAX_LEN - 1)) { szFirstWord[firstWordLen++] = static_cast(tolower(ch)); szFirstWord[firstWordLen] = '\0'; } } if (stylech != SCE_POWERPRO_COMMENTLINE) { //reset isDoLastWord if we find a character(ignoring spaces) after 'do' if (isDoLastWord && (ch > 0) && setWord.Contains(ch)) isDoLastWord = false; // --find out if the word "do" is the last on a "if" line-- // collect each letter and put it into a buffer 2 chars long // if we end up with "do" in the buffer when we reach the end of // the line, "do" was the last word on the line if ((ch > 0) && isFirstWordEnded && strcmp(szFirstWord, "if") == 0) { if (szDolen == 2) { szDo[0] = szDo[1]; szDo[1] = static_cast(tolower(ch)); szDo[2] = '\0'; if (strcmp(szDo, "do") == 0) isDoLastWord = true; } else if (szDolen < 2) { szDo[szDolen++] = static_cast(tolower(ch)); szDo[szDolen] = '\0'; } } } // End of Line found so process the information if ((ch == '\r' && chNext != '\n') // \r\n || ch == '\n' // \n || i == endPos) { // end of selection // ************************** // Folding logic for Keywords // ************************** // if a keyword is found on the current line and the line doesn't end with ;;+ (continuation) // and we are not inside a commentblock. if (firstWordLen > 0 && chPrev != '+' && chPrevPrev != ';' && chPrevPrevPrev !=';' && (!IsStreamCommentStyle(style) || foldInComment) ) { // only fold "if" last keyword is "then" (else its a one line if) if (strcmp(szFirstWord, "if") == 0 && isDoLastWord) levelNext++; // create new fold for these words if (strcmp(szFirstWord, "for") == 0) levelNext++; //handle folding for functions/labels //Note: Functions and labels don't have an explicit end like [end function] // 1. functions/labels end at the start of another function // 2. functions/labels end at the end of the file if ((strcmp(szFirstWord, "function") == 0) || (firstWordLen > 0 && szFirstWord[0] == '@')) { if (isFoldingAll) { //if we're folding the whole document (recursivly by lua script) if (functionCount > 0) { levelCurrent--; } else { levelNext++; } functionCount++; } else { //if just folding a small piece (by clicking on the minus sign next to the word) levelCurrent--; } } // end the fold for these words before the current line if (strcmp(szFirstWord, "endif") == 0 || strcmp(szFirstWord, "endfor") == 0) { levelNext--; levelCurrent--; } // end the fold for these words before the current line and Start new fold if (strcmp(szFirstWord, "else") == 0 || strcmp(szFirstWord, "elseif") == 0 ) levelCurrent--; } // Preprocessor and Comment folding int styleNext = GetStyleFirstWord(lineCurrent + 1,styler); // ********************************* // Folding logic for Comment blocks // ********************************* if (foldComment && IsStreamCommentStyle(style)) { // Start of a comment block if (stylePrev != style && IsStreamCommentStyle(styleNext) && styleNext == style) { levelNext++; } // fold till the last line for normal comment lines else if (IsStreamCommentStyle(stylePrev) && styleNext != SCE_POWERPRO_COMMENTLINE && stylePrev == SCE_POWERPRO_COMMENTLINE && style == SCE_POWERPRO_COMMENTLINE) { levelNext--; } // fold till the one but last line for Blockcomment lines else if (IsStreamCommentStyle(stylePrev) && styleNext != SCE_POWERPRO_COMMENTBLOCK && style == SCE_POWERPRO_COMMENTBLOCK) { levelNext--; levelCurrent--; } } int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); // reset values for the next line lineCurrent++; stylePrev = style; style = styleNext; levelCurrent = levelNext; visibleChars = 0; // if the last characters are ;;+ then don't reset since the line continues on the next line. if (chPrev != '+' && chPrevPrev != ';' && chPrevPrevPrev != ';') { firstWordLen = 0; szDolen = 0; isFirstWordStarted = false; isFirstWordEnded = false; isDoLastWord = false; //blank out first word for (unsigned int i = 0; i < FIRST_WORD_MAX_LEN; i++) szFirstWord[i] = '\0'; } } // save the last processed characters if ((ch > 0) && !isspacechar(ch)) { chPrevPrevPrev = chPrevPrev; chPrevPrev = chPrev; chPrev = ch; } } //close folds on the last line - without this a 'phantom' //fold can appear when an open fold is on the last line //this can occur because functions and labels don't have an explicit end if (lineCurrent >= lastLine) { int lev = 0; lev |= SC_FOLDLEVELWHITEFLAG; styler.SetLevel(lineCurrent, lev); } } static const char * const powerProWordLists[] = { "Keyword list 1", "Keyword list 2", "Keyword list 3", "Keyword list 4", 0, }; static void ColourisePowerProDocWrapper(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColourisePowerProDoc(startPos, length, initStyle, keywordlists, styler, false); } LexerModule lmPowerPro(SCLEX_POWERPRO, ColourisePowerProDocWrapper, "powerpro", FoldPowerProDoc, powerProWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexTCMD.cxx0000644000175000017500000004064611710634267021076 00000000000000// Scintilla\ source code edit control /** @file LexTCMD.cxx ** Lexer for Take Command / TCC batch scripts (.bat, .btm, .cmd). **/ // Written by Rex Conn (rconn [at] jpsoft [dot] com) // based on the CMD lexer // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static bool IsAlphabetic(int ch) { return isascii(ch) && isalpha(ch); } static inline bool AtEOL(Accessor &styler, unsigned int i) { return (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')); } // Tests for BATCH Operators static bool IsBOperator(char ch) { return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') || (ch == '|') || (ch == '&') || (ch == '!') || (ch == '?') || (ch == '*') || (ch == '(') || (ch == ')'); } // Tests for BATCH Separators static bool IsBSeparator(char ch) { return (ch == '\\') || (ch == '.') || (ch == ';') || (ch == ' ') || (ch == '\t') || (ch == '[') || (ch == ']') || (ch == '\"') || (ch == '\'') || (ch == '/'); } // Tests for Environment Variable symbol static inline bool IsEnvironmentVar(char ch) { return isalpha(ch) || isdigit(ch) || (ch == '_') || (ch == '$'); } // Find length of CMD FOR variable with modifier (%~...) or return 0 static unsigned int GetBatchVarLen( char *wordBuffer ) { int nLength = 0; if ( wordBuffer[0] == '%' ) { if ( wordBuffer[1] == '~' ) nLength = 2; else if (( wordBuffer[1] == '%' ) && ( wordBuffer[2] == '~' )) nLength++; else return 0; for ( ; ( wordBuffer[nLength] ); nLength++ ) { switch ( toupper(wordBuffer[nLength]) ) { case 'A': // file attributes case 'D': // drive letter only case 'F': // fully qualified path name case 'N': // filename only case 'P': // path only case 'S': // short name case 'T': // date / time of file case 'X': // file extension only case 'Z': // file size break; default: return nLength; } } } return nLength; } static void ColouriseTCMDLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, WordList *keywordlists[], Accessor &styler) { unsigned int offset = 0; // Line Buffer Offset char wordBuffer[260]; // Word Buffer - large to catch long paths unsigned int wbl; // Word Buffer Length unsigned int wbo; // Word Buffer Offset - also Special Keyword Buffer Length WordList &keywords = *keywordlists[0]; // Internal Commands // WordList &keywords2 = *keywordlists[1]; // Aliases (optional) bool isDelayedExpansion = 1; // !var! bool continueProcessing = true; // Used to toggle Regular Keyword Checking // Special Keywords are those that allow certain characters without whitespace after the command // Examples are: cd. cd\ echo: echo. path= bool inString = false; // Used for processing while "" // Special Keyword Buffer used to determine if the first n characters is a Keyword char sKeywordBuffer[260]; // Special Keyword Buffer bool sKeywordFound; // Exit Special Keyword for-loop if found // Skip leading whitespace while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { offset++; } // Colorize Default Text styler.ColourTo(startLine + offset - 1, SCE_TCMD_DEFAULT); if ( offset >= lengthLine ) return; // Check for Fake Label (Comment) or Real Label - return if found if (lineBuffer[offset] == ':') { if (lineBuffer[offset + 1] == ':') { // Colorize Fake Label (Comment) - :: is the same as REM styler.ColourTo(endPos, SCE_TCMD_COMMENT); } else { // Colorize Real Label styler.ColourTo(endPos, SCE_TCMD_LABEL); } return; // Check for Comment - return if found } else if (( CompareNCaseInsensitive(lineBuffer+offset, "rem", 3) == 0 ) && (( lineBuffer[offset+3] == 0 ) || ( isspace(lineBuffer[offset+3] )))) { styler.ColourTo(endPos, SCE_TCMD_COMMENT); return; // Check for Drive Change (Drive Change is internal command) - return if found } else if ((IsAlphabetic(lineBuffer[offset])) && (lineBuffer[offset + 1] == ':') && ((isspacechar(lineBuffer[offset + 2])) || (((lineBuffer[offset + 2] == '\\')) && (isspacechar(lineBuffer[offset + 3]))))) { // Colorize Regular Keyword styler.ColourTo(endPos, SCE_TCMD_WORD); return; } // Check for Hide Command (@ECHO OFF/ON) if (lineBuffer[offset] == '@') { styler.ColourTo(startLine + offset, SCE_TCMD_HIDE); offset++; } // Skip whitespace while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { offset++; } // Read remainder of line word-at-a-time or remainder-of-word-at-a-time while (offset < lengthLine) { if (offset > startLine) { // Colorize Default Text styler.ColourTo(startLine + offset - 1, SCE_TCMD_DEFAULT); } // Copy word from Line Buffer into Word Buffer wbl = 0; for (; offset < lengthLine && ( wbl < 260 ) && !isspacechar(lineBuffer[offset]); wbl++, offset++) { wordBuffer[wbl] = static_cast(tolower(lineBuffer[offset])); } wordBuffer[wbl] = '\0'; wbo = 0; // Check for Separator if (IsBSeparator(wordBuffer[0])) { // Reset Offset to re-process remainder of word offset -= (wbl - 1); // Colorize Default Text styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); if (wordBuffer[0] == '"') inString = !inString; // Check for Regular expression } else if (( wordBuffer[0] == ':' ) && ( wordBuffer[1] == ':' ) && (continueProcessing)) { // Colorize Regular exoressuin styler.ColourTo(startLine + offset - 1, SCE_TCMD_DEFAULT); // No need to Reset Offset // Check for Labels in text (... :label) } else if (wordBuffer[0] == ':' && isspacechar(lineBuffer[offset - wbl - 1])) { // Colorize Default Text styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT); // Colorize Label styler.ColourTo(startLine + offset - 1, SCE_TCMD_CLABEL); // No need to Reset Offset // Check for delayed expansion Variable (!x...!) } else if (isDelayedExpansion && wordBuffer[0] == '!') { // Colorize Default Text styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT); wbo++; // Search to end of word for second ! while ((wbo < wbl) && (wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } if (wordBuffer[wbo] == '!') { wbo++; // Colorize Environment Variable styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_EXPANSION); } else { wbo = 1; // Colorize Symbol styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_DEFAULT); } // Reset Offset to re-process remainder of word offset -= (wbl - wbo); // Check for Regular Keyword in list } else if ((keywords.InList(wordBuffer)) && (!inString) && (continueProcessing)) { // ECHO, PATH, and PROMPT require no further Regular Keyword Checking if ((CompareCaseInsensitive(wordBuffer, "echo") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "echos") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "echoerr") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "echoserr") == 0) || (CompareCaseInsensitive(wordBuffer, "path") == 0) || (CompareCaseInsensitive(wordBuffer, "prompt") == 0)) { continueProcessing = false; } // Colorize Regular keyword styler.ColourTo(startLine + offset - 1, SCE_TCMD_WORD); // No need to Reset Offset } else if ((wordBuffer[0] != '%') && (wordBuffer[0] != '!') && (!IsBOperator(wordBuffer[0])) && (!inString) && (continueProcessing)) { // a few commands accept "illegal" syntax -- cd\, echo., etc. sscanf( wordBuffer, "%[^.<>|&=\\/]", sKeywordBuffer ); sKeywordFound = false; if ((CompareCaseInsensitive(sKeywordBuffer, "echo") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "echos") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "echoerr") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "echoserr") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "cd") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "path") == 0) || (CompareCaseInsensitive(sKeywordBuffer, "prompt") == 0)) { // no further Regular Keyword Checking continueProcessing = false; sKeywordFound = true; wbo = (unsigned int)strlen( sKeywordBuffer ); // Colorize Special Keyword as Regular Keyword styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_WORD); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); } // Check for Default Text if (!sKeywordFound) { wbo = 0; // Read up to %, Operator or Separator while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (!isDelayedExpansion || wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } // Colorize Default Text styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_DEFAULT); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); } // Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a) } else if (wordBuffer[0] == '%') { unsigned int varlen; unsigned int n = 1; // Colorize Default Text styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT); wbo++; // check for %[nn] syntax if ( wordBuffer[1] == '[' ) { n++; while ((n < wbl) && (wordBuffer[n] != ']')) { n++; } if ( wordBuffer[n] == ']' ) n++; goto ColorizeArg; } // Search to end of word for second % or to the first terminator (can be a long path) while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } // Check for Argument (%n) or (%*) if (((isdigit(wordBuffer[1])) || (wordBuffer[1] == '*')) && (wordBuffer[wbo] != '%')) { while (( wordBuffer[n] ) && ( strchr( "%0123456789*#$", wordBuffer[n] ) != NULL )) n++; ColorizeArg: // Colorize Argument styler.ColourTo(startLine + offset - 1 - (wbl - n), SCE_TCMD_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - n); // Check for Variable with modifiers (%~...) } else if ((varlen = GetBatchVarLen(wordBuffer)) != 0) { // Colorize Variable styler.ColourTo(startLine + offset - 1 - (wbl - varlen), SCE_TCMD_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - varlen); // Check for Environment Variable (%x...%) } else if (( wordBuffer[1] ) && ( wordBuffer[1] != '%')) { if ( wordBuffer[wbo] == '%' ) wbo++; // Colorize Environment Variable styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_ENVIRONMENT); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); // Check for Local Variable (%%a) } else if ( (wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] != '%') && (!IsBOperator(wordBuffer[2])) && (!IsBSeparator(wordBuffer[2]))) { n = 2; while (( wordBuffer[n] ) && (!IsBOperator(wordBuffer[n])) && (!IsBSeparator(wordBuffer[n]))) n++; // Colorize Local Variable styler.ColourTo(startLine + offset - 1 - (wbl - n), SCE_TCMD_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - n); // Check for %% } else if ((wbl > 1) && (wordBuffer[1] == '%')) { // Colorize Symbols styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_TCMD_DEFAULT); // Reset Offset to re-process remainder of word offset -= (wbl - 2); } else { // Colorize Symbol styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_DEFAULT); // Reset Offset to re-process remainder of word offset -= (wbl - 1); } // Check for Operator } else if (IsBOperator(wordBuffer[0])) { // Colorize Default Text styler.ColourTo(startLine + offset - 1 - wbl, SCE_TCMD_DEFAULT); // Check for Pipe, compound, or conditional Operator if ((wordBuffer[0] == '|') || (wordBuffer[0] == '&')) { // Colorize Pipe Operator styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_OPERATOR); // Reset Offset to re-process remainder of word offset -= (wbl - 1); continueProcessing = true; // Check for Other Operator } else { // Check for > Operator if ((wordBuffer[0] == '>') || (wordBuffer[0] == '<')) { // Turn Keyword and External Command / Program checking back on continueProcessing = true; } // Colorize Other Operator if (!inString || !(wordBuffer[0] == '(' || wordBuffer[0] == ')')) styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_TCMD_OPERATOR); // Reset Offset to re-process remainder of word offset -= (wbl - 1); } // Check for Default Text } else { // Read up to %, Operator or Separator while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (!isDelayedExpansion || wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } // Colorize Default Text styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_TCMD_DEFAULT); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); } // Skip whitespace - nothing happens if Offset was Reset while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { offset++; } } // Colorize Default Text for remainder of line - currently not lexed styler.ColourTo(endPos, SCE_TCMD_DEFAULT); } static void ColouriseTCMDDoc( unsigned int startPos, int length, int /*initStyle*/, WordList *keywordlists[], Accessor &styler ) { char lineBuffer[16384]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseTCMDLine(lineBuffer, linePos, startLine, i, keywordlists, styler); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters lineBuffer[linePos] = '\0'; ColouriseTCMDLine(lineBuffer, linePos, startLine, startPos + length - 1, keywordlists, styler); } } // Convert string to upper case static void StrUpr(char *s) { while (*s) { *s = MakeUpperCase(*s); s++; } } // Folding support (for DO, IFF, SWITCH, TEXT, and command groups) static void FoldTCMDDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { int line = styler.GetLine(startPos); int level = styler.LevelAt(line); int levelIndent = 0; unsigned int endPos = startPos + length; char s[16]; char chPrev = styler.SafeGetCharAt(startPos - 1); // Scan for ( and ) for (unsigned int i = startPos; i < endPos; i++) { int c = styler.SafeGetCharAt(i, '\n'); int style = styler.StyleAt(i); bool bLineStart = ((chPrev == '\r') || (chPrev == '\n')) || i == 0; if (style == SCE_TCMD_OPERATOR) { // CheckFoldPoint if (c == '(') { levelIndent += 1; } else if (c == ')') { levelIndent -= 1; } } if (( bLineStart ) && ( style == SCE_TCMD_WORD )) { for (unsigned int j = 0; j < 10; j++) { if (!iswordchar(styler[i + j])) { break; } s[j] = styler[i + j]; s[j + 1] = '\0'; } StrUpr( s ); if ((strcmp(s, "DO") == 0) || (strcmp(s, "IFF") == 0) || (strcmp(s, "SWITCH") == 0) || (strcmp(s, "TEXT") == 0)) { levelIndent++; } else if ((strcmp(s, "ENDDO") == 0) || (strcmp(s, "ENDIFF") == 0) || (strcmp(s, "ENDSWITCH") == 0) || (strcmp(s, "ENDTEXT") == 0)) { levelIndent--; } } if (c == '\n') { // line end if (levelIndent > 0) { level |= SC_FOLDLEVELHEADERFLAG; } if (level != styler.LevelAt(line)) styler.SetLevel(line, level); level += levelIndent; if ((level & SC_FOLDLEVELNUMBERMASK) < SC_FOLDLEVELBASE) level = SC_FOLDLEVELBASE; line++; // reset state levelIndent = 0; level &= ~SC_FOLDLEVELHEADERFLAG; level &= ~SC_FOLDLEVELWHITEFLAG; } chPrev = c; } } static const char *const tcmdWordListDesc[] = { "Internal Commands", "Aliases", 0 }; LexerModule lmTCMD(SCLEX_TCMD, ColouriseTCMDDoc, "tcmd", FoldTCMDDoc, tcmdWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexFlagship.cxx0000644000175000017500000002775311615412040022073 00000000000000// Scintilla source code edit control /** @file LexFlagShip.cxx ** Lexer for Harbour and FlagShip. ** (Syntactically compatible to other xBase dialects, like Clipper, dBase, Clip, FoxPro etc.) **/ // Copyright 2005 by Randy Butler // Copyright 2010 by Xavi (Harbour) // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Extended to accept accented characters static inline bool IsAWordChar(int ch) { return ch >= 0x80 || (isalnum(ch) || ch == '_'); } static void ColouriseFlagShipDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; WordList &keywords5 = *keywordlists[4]; // property lexer.flagship.styling.within.preprocessor // For Harbour code, determines whether all preprocessor code is styled in the preprocessor style (0) or only from the // initial # to the end of the command word(1, the default). It also determines how to present text, dump, and disabled code. bool stylingWithinPreprocessor = styler.GetPropertyInt("lexer.flagship.styling.within.preprocessor", 1) != 0; CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); int visibleChars = 0; int closeStringChar = 0; int styleBeforeDCKeyword = SCE_FS_DEFAULT; bool bEnableCode = initStyle < SCE_FS_DISABLEDCODE; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Determine if the current state should terminate. switch (sc.state) { case SCE_FS_OPERATOR: case SCE_FS_OPERATOR_C: case SCE_FS_WORDOPERATOR: sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); break; case SCE_FS_IDENTIFIER: case SCE_FS_IDENTIFIER_C: if (!IsAWordChar(sc.ch)) { char s[64]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD : SCE_FS_KEYWORD_C); } else if (keywords2.InList(s)) { sc.ChangeState(bEnableCode ? SCE_FS_KEYWORD2 : SCE_FS_KEYWORD2_C); } else if (bEnableCode && keywords3.InList(s)) { sc.ChangeState(SCE_FS_KEYWORD3); } else if (bEnableCode && keywords4.InList(s)) { sc.ChangeState(SCE_FS_KEYWORD4); }// Else, it is really an identifier... sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } break; case SCE_FS_NUMBER: if (!IsAWordChar(sc.ch) && !(sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_FS_DEFAULT); } break; case SCE_FS_NUMBER_C: if (!IsAWordChar(sc.ch) && sc.ch != '.') { sc.SetState(SCE_FS_DEFAULT_C); } break; case SCE_FS_CONSTANT: if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_FS_DEFAULT); } break; case SCE_FS_STRING: case SCE_FS_STRING_C: if (sc.ch == closeStringChar) { sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } else if (sc.atLineEnd) { sc.ChangeState(bEnableCode ? SCE_FS_STRINGEOL : SCE_FS_STRINGEOL_C); } break; case SCE_FS_STRINGEOL: case SCE_FS_STRINGEOL_C: if (sc.atLineStart) { sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } break; case SCE_FS_COMMENTDOC: case SCE_FS_COMMENTDOC_C: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C; sc.SetState(SCE_FS_COMMENTDOCKEYWORD); } } break; case SCE_FS_COMMENT: case SCE_FS_COMMENTLINE: if (sc.atLineStart) { sc.SetState(SCE_FS_DEFAULT); } break; case SCE_FS_COMMENTLINEDOC: case SCE_FS_COMMENTLINEDOC_C: if (sc.atLineStart) { sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C; sc.SetState(SCE_FS_COMMENTDOCKEYWORD); } } break; case SCE_FS_COMMENTDOCKEYWORD: if ((styleBeforeDCKeyword == SCE_FS_COMMENTDOC || styleBeforeDCKeyword == SCE_FS_COMMENTDOC_C) && sc.Match('*', '/')) { sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR); sc.Forward(); sc.ForwardSetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } else if (!setDoxygen.Contains(sc.ch)) { char s[64]; sc.GetCurrentLowered(s, sizeof(s)); if (!IsASpace(sc.ch) || !keywords5.InList(s + 1)) { sc.ChangeState(SCE_FS_COMMENTDOCKEYWORDERROR); } sc.SetState(styleBeforeDCKeyword); } break; case SCE_FS_PREPROCESSOR: case SCE_FS_PREPROCESSOR_C: if (sc.atLineEnd) { if (!(sc.chPrev == ';' || sc.GetRelative(-2) == ';')) { sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } } else if (stylingWithinPreprocessor) { if (IsASpaceOrTab(sc.ch)) { sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } } else if (sc.Match('/', '*') || sc.Match('/', '/') || sc.Match('&', '&')) { sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } break; case SCE_FS_DISABLEDCODE: if (sc.ch == '#' && visibleChars == 0) { sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C); do { // Skip whitespace between # and preprocessor word sc.Forward(); } while (IsASpaceOrTab(sc.ch) && sc.More()); if (sc.MatchIgnoreCase("pragma")) { sc.Forward(6); do { // Skip more whitespace until keyword sc.Forward(); } while (IsASpaceOrTab(sc.ch) && sc.More()); if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) { bEnableCode = true; sc.SetState(SCE_FS_DISABLEDCODE); sc.Forward(sc.ch == '_' ? 8 : 6); sc.ForwardSetState(SCE_FS_DEFAULT); } else { sc.ChangeState(SCE_FS_DISABLEDCODE); } } else { sc.ChangeState(SCE_FS_DISABLEDCODE); } } break; case SCE_FS_DATE: if (sc.ch == '}') { sc.ForwardSetState(SCE_FS_DEFAULT); } else if (sc.atLineEnd) { sc.ChangeState(SCE_FS_STRINGEOL); } } // Determine if a new state should be entered. if (sc.state == SCE_FS_DEFAULT || sc.state == SCE_FS_DEFAULT_C) { if (bEnableCode && (sc.MatchIgnoreCase(".and.") || sc.MatchIgnoreCase(".not."))) { sc.SetState(SCE_FS_WORDOPERATOR); sc.Forward(4); } else if (bEnableCode && sc.MatchIgnoreCase(".or.")) { sc.SetState(SCE_FS_WORDOPERATOR); sc.Forward(3); } else if (bEnableCode && (sc.MatchIgnoreCase(".t.") || sc.MatchIgnoreCase(".f.") || (!IsAWordChar(sc.GetRelative(3)) && sc.MatchIgnoreCase("nil")))) { sc.SetState(SCE_FS_CONSTANT); sc.Forward(2); } else if (sc.Match('/', '*')) { sc.SetState(bEnableCode ? SCE_FS_COMMENTDOC : SCE_FS_COMMENTDOC_C); sc.Forward(); } else if (bEnableCode && sc.Match('&', '&')) { sc.SetState(SCE_FS_COMMENTLINE); sc.Forward(); } else if (sc.Match('/', '/')) { sc.SetState(bEnableCode ? SCE_FS_COMMENTLINEDOC : SCE_FS_COMMENTLINEDOC_C); sc.Forward(); } else if (bEnableCode && sc.ch == '*' && visibleChars == 0) { sc.SetState(SCE_FS_COMMENT); } else if (sc.ch == '\"' || sc.ch == '\'') { sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C); closeStringChar = sc.ch; } else if (closeStringChar == '>' && sc.ch == '<') { sc.SetState(bEnableCode ? SCE_FS_STRING : SCE_FS_STRING_C); } else if (sc.ch == '#' && visibleChars == 0) { sc.SetState(bEnableCode ? SCE_FS_PREPROCESSOR : SCE_FS_PREPROCESSOR_C); do { // Skip whitespace between # and preprocessor word sc.Forward(); } while (IsASpaceOrTab(sc.ch) && sc.More()); if (sc.atLineEnd) { sc.SetState(bEnableCode ? SCE_FS_DEFAULT : SCE_FS_DEFAULT_C); } else if (sc.MatchIgnoreCase("include")) { if (stylingWithinPreprocessor) { closeStringChar = '>'; } } else if (sc.MatchIgnoreCase("pragma")) { sc.Forward(6); do { // Skip more whitespace until keyword sc.Forward(); } while (IsASpaceOrTab(sc.ch) && sc.More()); if (sc.MatchIgnoreCase("begindump") || sc.MatchIgnoreCase("__cstream")) { bEnableCode = false; if (stylingWithinPreprocessor) { sc.SetState(SCE_FS_DISABLEDCODE); sc.Forward(8); sc.ForwardSetState(SCE_FS_DEFAULT_C); } else { sc.SetState(SCE_FS_DISABLEDCODE); } } else if (sc.MatchIgnoreCase("enddump") || sc.MatchIgnoreCase("__endtext")) { bEnableCode = true; sc.SetState(SCE_FS_DISABLEDCODE); sc.Forward(sc.ch == '_' ? 8 : 6); sc.ForwardSetState(SCE_FS_DEFAULT); } } } else if (bEnableCode && sc.ch == '{') { int p = 0; int chSeek; unsigned int endPos(startPos + length); do { // Skip whitespace chSeek = sc.GetRelative(++p); } while (IsASpaceOrTab(chSeek) && (sc.currentPos + p < endPos)); if (chSeek == '^') { sc.SetState(SCE_FS_DATE); } else { sc.SetState(SCE_FS_OPERATOR); } } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(bEnableCode ? SCE_FS_NUMBER : SCE_FS_NUMBER_C); } else if (IsAWordChar(sc.ch)) { sc.SetState(bEnableCode ? SCE_FS_IDENTIFIER : SCE_FS_IDENTIFIER_C); } else if (isoperator(static_cast(sc.ch)) || (bEnableCode && sc.ch == '@')) { sc.SetState(bEnableCode ? SCE_FS_OPERATOR : SCE_FS_OPERATOR_C); } } if (sc.atLineEnd) { visibleChars = 0; closeStringChar = 0; } if (!IsASpace(sc.ch)) { visibleChars++; } } sc.Complete(); } static void FoldFlagShipDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { int endPos = startPos + length; // Backtrack to previous line in case need to fix its fold status int lineCurrent = styler.GetLine(startPos); if (startPos > 0 && lineCurrent > 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); } int spaceFlags = 0; int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags); char chNext = styler[startPos]; for (int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos-1)) { int lev = indentCurrent; int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags); if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } else if (indentNext & SC_FOLDLEVELWHITEFLAG) { int spaceFlags2 = 0; int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2); if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } } } indentCurrent = indentNext; styler.SetLevel(lineCurrent, lev); lineCurrent++; } } } static const char * const FSWordListDesc[] = { "Keywords Commands", "Std Library Functions", "Procedure, return, exit", "Class (oop)", "Doxygen keywords", 0 }; LexerModule lmFlagShip(SCLEX_FLAGSHIP, ColouriseFlagShipDoc, "flagship", FoldFlagShipDoc, FSWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexNsis.cxx0000644000175000017500000004446111717550114021255 00000000000000// Scintilla source code edit control /** @file LexNsis.cxx ** Lexer for NSIS **/ // Copyright 2003 - 2005 by Angelo Mandato // Last Updated: 03/13/2005 // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /* // located in SciLexer.h #define SCLEX_NSIS 43 #define SCE_NSIS_DEFAULT 0 #define SCE_NSIS_COMMENT 1 #define SCE_NSIS_STRINGDQ 2 #define SCE_NSIS_STRINGLQ 3 #define SCE_NSIS_STRINGRQ 4 #define SCE_NSIS_FUNCTION 5 #define SCE_NSIS_VARIABLE 6 #define SCE_NSIS_LABEL 7 #define SCE_NSIS_USERDEFINED 8 #define SCE_NSIS_SECTIONDEF 9 #define SCE_NSIS_SUBSECTIONDEF 10 #define SCE_NSIS_IFDEFINEDEF 11 #define SCE_NSIS_MACRODEF 12 #define SCE_NSIS_STRINGVAR 13 #define SCE_NSIS_NUMBER 14 // ADDED for Scintilla v1.63 #define SCE_NSIS_SECTIONGROUP 15 #define SCE_NSIS_PAGEEX 16 #define SCE_NSIS_FUNCTIONDEF 17 #define SCE_NSIS_COMMENTBOX 18 */ static bool isNsisNumber(char ch) { return (ch >= '0' && ch <= '9'); } static bool isNsisChar(char ch) { return (ch == '.' ) || (ch == '_' ) || isNsisNumber(ch) || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } static bool isNsisLetter(char ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } static bool NsisNextLineHasElse(unsigned int start, unsigned int end, Accessor &styler) { int nNextLine = -1; for( unsigned int i = start; i < end; i++ ) { char cNext = styler.SafeGetCharAt( i ); if( cNext == '\n' ) { nNextLine = i+1; break; } } if( nNextLine == -1 ) // We never found the next line... return false; for( unsigned int firstChar = nNextLine; firstChar < end; firstChar++ ) { char cNext = styler.SafeGetCharAt( firstChar ); if( cNext == ' ' ) continue; if( cNext == '\t' ) continue; if( cNext == '!' ) { if( styler.Match(firstChar, "!else") ) return true; } break; } return false; } static int NsisCmp( const char *s1, const char *s2, bool bIgnoreCase ) { if( bIgnoreCase ) return CompareCaseInsensitive( s1, s2); return strcmp( s1, s2 ); } static int calculateFoldNsis(unsigned int start, unsigned int end, int foldlevel, Accessor &styler, bool bElse, bool foldUtilityCmd ) { int style = styler.StyleAt(end); // If the word is too long, it is not what we are looking for if( end - start > 20 ) return foldlevel; if( foldUtilityCmd ) { // Check the style at this point, if it is not valid, then return zero if( style != SCE_NSIS_FUNCTIONDEF && style != SCE_NSIS_SECTIONDEF && style != SCE_NSIS_SUBSECTIONDEF && style != SCE_NSIS_IFDEFINEDEF && style != SCE_NSIS_MACRODEF && style != SCE_NSIS_SECTIONGROUP && style != SCE_NSIS_PAGEEX ) return foldlevel; } else { if( style != SCE_NSIS_FUNCTIONDEF && style != SCE_NSIS_SECTIONDEF && style != SCE_NSIS_SUBSECTIONDEF && style != SCE_NSIS_SECTIONGROUP && style != SCE_NSIS_PAGEEX ) return foldlevel; } int newFoldlevel = foldlevel; bool bIgnoreCase = false; if( styler.GetPropertyInt("nsis.ignorecase") == 1 ) bIgnoreCase = true; char s[20]; // The key word we are looking for has atmost 13 characters s[0] = '\0'; for (unsigned int i = 0; i < end - start + 1 && i < 19; i++) { s[i] = static_cast( styler[ start + i ] ); s[i + 1] = '\0'; } if( s[0] == '!' ) { if( NsisCmp(s, "!ifndef", bIgnoreCase) == 0 || NsisCmp(s, "!ifdef", bIgnoreCase ) == 0 || NsisCmp(s, "!ifmacrodef", bIgnoreCase ) == 0 || NsisCmp(s, "!ifmacrondef", bIgnoreCase ) == 0 || NsisCmp(s, "!if", bIgnoreCase ) == 0 || NsisCmp(s, "!macro", bIgnoreCase ) == 0 ) newFoldlevel++; else if( NsisCmp(s, "!endif", bIgnoreCase) == 0 || NsisCmp(s, "!macroend", bIgnoreCase ) == 0 ) newFoldlevel--; else if( bElse && NsisCmp(s, "!else", bIgnoreCase) == 0 ) newFoldlevel++; } else { if( NsisCmp(s, "Section", bIgnoreCase ) == 0 || NsisCmp(s, "SectionGroup", bIgnoreCase ) == 0 || NsisCmp(s, "Function", bIgnoreCase) == 0 || NsisCmp(s, "SubSection", bIgnoreCase ) == 0 || NsisCmp(s, "PageEx", bIgnoreCase ) == 0 ) newFoldlevel++; else if( NsisCmp(s, "SectionGroupEnd", bIgnoreCase ) == 0 || NsisCmp(s, "SubSectionEnd", bIgnoreCase ) == 0 || NsisCmp(s, "FunctionEnd", bIgnoreCase) == 0 || NsisCmp(s, "SectionEnd", bIgnoreCase ) == 0 || NsisCmp(s, "PageExEnd", bIgnoreCase ) == 0 ) newFoldlevel--; } return newFoldlevel; } static int classifyWordNsis(unsigned int start, unsigned int end, WordList *keywordLists[], Accessor &styler ) { bool bIgnoreCase = false; if( styler.GetPropertyInt("nsis.ignorecase") == 1 ) bIgnoreCase = true; bool bUserVars = false; if( styler.GetPropertyInt("nsis.uservars") == 1 ) bUserVars = true; char s[100]; WordList &Functions = *keywordLists[0]; WordList &Variables = *keywordLists[1]; WordList &Lables = *keywordLists[2]; WordList &UserDefined = *keywordLists[3]; for (unsigned int i = 0; i < end - start + 1 && i < 99; i++) { if( bIgnoreCase ) s[i] = static_cast( tolower(styler[ start + i ] ) ); else s[i] = static_cast( styler[ start + i ] ); s[i + 1] = '\0'; } // Check for special words... if( NsisCmp(s, "!macro", bIgnoreCase ) == 0 || NsisCmp(s, "!macroend", bIgnoreCase) == 0 ) // Covers !macro and !macroend return SCE_NSIS_MACRODEF; if( NsisCmp(s, "!ifdef", bIgnoreCase ) == 0 || NsisCmp(s, "!ifndef", bIgnoreCase) == 0 || NsisCmp(s, "!endif", bIgnoreCase) == 0 ) // Covers !ifdef, !ifndef and !endif return SCE_NSIS_IFDEFINEDEF; if( NsisCmp(s, "!if", bIgnoreCase ) == 0 || NsisCmp(s, "!else", bIgnoreCase ) == 0 ) // Covers !if and else return SCE_NSIS_IFDEFINEDEF; if (NsisCmp(s, "!ifmacrodef", bIgnoreCase ) == 0 || NsisCmp(s, "!ifmacrondef", bIgnoreCase ) == 0 ) // Covers !ifmacrodef and !ifnmacrodef return SCE_NSIS_IFDEFINEDEF; if( NsisCmp(s, "SectionGroup", bIgnoreCase) == 0 || NsisCmp(s, "SectionGroupEnd", bIgnoreCase) == 0 ) // Covers SectionGroup and SectionGroupEnd return SCE_NSIS_SECTIONGROUP; if( NsisCmp(s, "Section", bIgnoreCase ) == 0 || NsisCmp(s, "SectionEnd", bIgnoreCase) == 0 ) // Covers Section and SectionEnd return SCE_NSIS_SECTIONDEF; if( NsisCmp(s, "SubSection", bIgnoreCase) == 0 || NsisCmp(s, "SubSectionEnd", bIgnoreCase) == 0 ) // Covers SubSection and SubSectionEnd return SCE_NSIS_SUBSECTIONDEF; if( NsisCmp(s, "PageEx", bIgnoreCase) == 0 || NsisCmp(s, "PageExEnd", bIgnoreCase) == 0 ) // Covers PageEx and PageExEnd return SCE_NSIS_PAGEEX; if( NsisCmp(s, "Function", bIgnoreCase) == 0 || NsisCmp(s, "FunctionEnd", bIgnoreCase) == 0 ) // Covers Function and FunctionEnd return SCE_NSIS_FUNCTIONDEF; if ( Functions.InList(s) ) return SCE_NSIS_FUNCTION; if ( Variables.InList(s) ) return SCE_NSIS_VARIABLE; if ( Lables.InList(s) ) return SCE_NSIS_LABEL; if( UserDefined.InList(s) ) return SCE_NSIS_USERDEFINED; if( strlen(s) > 3 ) { if( s[1] == '{' && s[strlen(s)-1] == '}' ) return SCE_NSIS_VARIABLE; } // See if the variable is a user defined variable if( s[0] == '$' && bUserVars ) { bool bHasSimpleNsisChars = true; for (unsigned int j = 1; j < end - start + 1 && j < 99; j++) { if( !isNsisChar( s[j] ) ) { bHasSimpleNsisChars = false; break; } } if( bHasSimpleNsisChars ) return SCE_NSIS_VARIABLE; } // To check for numbers if( isNsisNumber( s[0] ) ) { bool bHasSimpleNsisNumber = true; for (unsigned int j = 1; j < end - start + 1 && j < 99; j++) { if( !isNsisNumber( s[j] ) ) { bHasSimpleNsisNumber = false; break; } } if( bHasSimpleNsisNumber ) return SCE_NSIS_NUMBER; } return SCE_NSIS_DEFAULT; } static void ColouriseNsisDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler) { int state = SCE_NSIS_DEFAULT; if( startPos > 0 ) state = styler.StyleAt(startPos-1); // Use the style from the previous line, usually default, but could be commentbox styler.StartAt( startPos ); styler.GetLine( startPos ); unsigned int nLengthDoc = startPos + length; styler.StartSegment( startPos ); char cCurrChar; bool bVarInString = false; bool bClassicVarInString = false; unsigned int i; for( i = startPos; i < nLengthDoc; i++ ) { cCurrChar = styler.SafeGetCharAt( i ); char cNextChar = styler.SafeGetCharAt(i+1); switch(state) { case SCE_NSIS_DEFAULT: if( cCurrChar == ';' || cCurrChar == '#' ) // we have a comment line { styler.ColourTo(i-1, state ); state = SCE_NSIS_COMMENT; break; } if( cCurrChar == '"' ) { styler.ColourTo(i-1, state ); state = SCE_NSIS_STRINGDQ; bVarInString = false; bClassicVarInString = false; break; } if( cCurrChar == '\'' ) { styler.ColourTo(i-1, state ); state = SCE_NSIS_STRINGRQ; bVarInString = false; bClassicVarInString = false; break; } if( cCurrChar == '`' ) { styler.ColourTo(i-1, state ); state = SCE_NSIS_STRINGLQ; bVarInString = false; bClassicVarInString = false; break; } // NSIS KeyWord,Function, Variable, UserDefined: if( cCurrChar == '$' || isNsisChar(cCurrChar) || cCurrChar == '!' ) { styler.ColourTo(i-1,state); state = SCE_NSIS_FUNCTION; // If it is a number, we must check and set style here first... if( isNsisNumber(cCurrChar) && (cNextChar == '\t' || cNextChar == ' ' || cNextChar == '\r' || cNextChar == '\n' ) ) styler.ColourTo( i, SCE_NSIS_NUMBER); break; } if( cCurrChar == '/' && cNextChar == '*' ) { styler.ColourTo(i-1,state); state = SCE_NSIS_COMMENTBOX; break; } break; case SCE_NSIS_COMMENT: if( cNextChar == '\n' || cNextChar == '\r' ) { // Special case: if( cCurrChar == '\\' ) { styler.ColourTo(i-2,state); styler.ColourTo(i,SCE_NSIS_DEFAULT); } else { styler.ColourTo(i,state); state = SCE_NSIS_DEFAULT; } } break; case SCE_NSIS_STRINGDQ: case SCE_NSIS_STRINGLQ: case SCE_NSIS_STRINGRQ: if( styler.SafeGetCharAt(i-1) == '\\' && styler.SafeGetCharAt(i-2) == '$' ) break; // Ignore the next character, even if it is a quote of some sort if( cCurrChar == '"' && state == SCE_NSIS_STRINGDQ ) { styler.ColourTo(i,state); state = SCE_NSIS_DEFAULT; break; } if( cCurrChar == '`' && state == SCE_NSIS_STRINGLQ ) { styler.ColourTo(i,state); state = SCE_NSIS_DEFAULT; break; } if( cCurrChar == '\'' && state == SCE_NSIS_STRINGRQ ) { styler.ColourTo(i,state); state = SCE_NSIS_DEFAULT; break; } if( cNextChar == '\r' || cNextChar == '\n' ) { int nCurLine = styler.GetLine(i+1); int nBack = i; // We need to check if the previous line has a \ in it... bool bNextLine = false; while( nBack > 0 ) { if( styler.GetLine(nBack) != nCurLine ) break; char cTemp = styler.SafeGetCharAt(nBack, 'a'); // Letter 'a' is safe here if( cTemp == '\\' ) { bNextLine = true; break; } if( cTemp != '\r' && cTemp != '\n' && cTemp != '\t' && cTemp != ' ' ) break; nBack--; } if( bNextLine ) { styler.ColourTo(i+1,state); } if( bNextLine == false ) { styler.ColourTo(i,state); state = SCE_NSIS_DEFAULT; } } break; case SCE_NSIS_FUNCTION: // NSIS KeyWord: if( cCurrChar == '$' ) state = SCE_NSIS_DEFAULT; else if( cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' ) ) state = SCE_NSIS_DEFAULT; else if( (isNsisChar(cCurrChar) && !isNsisChar( cNextChar) && cNextChar != '}') || cCurrChar == '}' ) { state = classifyWordNsis( styler.GetStartSegment(), i, keywordLists, styler ); styler.ColourTo( i, state); state = SCE_NSIS_DEFAULT; } else if( !isNsisChar( cCurrChar ) && cCurrChar != '{' && cCurrChar != '}' ) { if( classifyWordNsis( styler.GetStartSegment(), i-1, keywordLists, styler) == SCE_NSIS_NUMBER ) styler.ColourTo( i-1, SCE_NSIS_NUMBER ); state = SCE_NSIS_DEFAULT; if( cCurrChar == '"' ) { state = SCE_NSIS_STRINGDQ; bVarInString = false; bClassicVarInString = false; } else if( cCurrChar == '`' ) { state = SCE_NSIS_STRINGLQ; bVarInString = false; bClassicVarInString = false; } else if( cCurrChar == '\'' ) { state = SCE_NSIS_STRINGRQ; bVarInString = false; bClassicVarInString = false; } else if( cCurrChar == '#' || cCurrChar == ';' ) { state = SCE_NSIS_COMMENT; } } break; case SCE_NSIS_COMMENTBOX: if( styler.SafeGetCharAt(i-1) == '*' && cCurrChar == '/' ) { styler.ColourTo(i,state); state = SCE_NSIS_DEFAULT; } break; } if( state == SCE_NSIS_COMMENT || state == SCE_NSIS_COMMENTBOX ) { styler.ColourTo(i,state); } else if( state == SCE_NSIS_STRINGDQ || state == SCE_NSIS_STRINGLQ || state == SCE_NSIS_STRINGRQ ) { bool bIngoreNextDollarSign = false; bool bUserVars = false; if( styler.GetPropertyInt("nsis.uservars") == 1 ) bUserVars = true; if( bVarInString && cCurrChar == '$' ) { bVarInString = false; bIngoreNextDollarSign = true; } else if( bVarInString && cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' || cNextChar == '"' || cNextChar == '`' || cNextChar == '\'' ) ) { styler.ColourTo( i+1, SCE_NSIS_STRINGVAR); bVarInString = false; bIngoreNextDollarSign = false; } // Covers "$INSTDIR and user vars like $MYVAR" else if( bVarInString && !isNsisChar(cNextChar) ) { int nWordState = classifyWordNsis( styler.GetStartSegment(), i, keywordLists, styler); if( nWordState == SCE_NSIS_VARIABLE ) styler.ColourTo( i, SCE_NSIS_STRINGVAR); else if( bUserVars ) styler.ColourTo( i, SCE_NSIS_STRINGVAR); bVarInString = false; } // Covers "${TEST}..." else if( bClassicVarInString && cNextChar == '}' ) { styler.ColourTo( i+1, SCE_NSIS_STRINGVAR); bClassicVarInString = false; } // Start of var in string if( !bIngoreNextDollarSign && cCurrChar == '$' && cNextChar == '{' ) { styler.ColourTo( i-1, state); bClassicVarInString = true; bVarInString = false; } else if( !bIngoreNextDollarSign && cCurrChar == '$' ) { styler.ColourTo( i-1, state); bVarInString = true; bClassicVarInString = false; } } } // Colourise remaining document styler.ColourTo(nLengthDoc-1,state); } static void FoldNsisDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { // No folding enabled, no reason to continue... if( styler.GetPropertyInt("fold") == 0 ) return; bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) == 1; bool foldUtilityCmd = styler.GetPropertyInt("nsis.foldutilcmd", 1) == 1; bool blockComment = false; int lineCurrent = styler.GetLine(startPos); unsigned int safeStartPos = styler.LineStart( lineCurrent ); bool bArg1 = true; int nWordStart = -1; int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelNext = levelCurrent; int style = styler.StyleAt(safeStartPos); if( style == SCE_NSIS_COMMENTBOX ) { if( styler.SafeGetCharAt(safeStartPos) == '/' && styler.SafeGetCharAt(safeStartPos+1) == '*' ) levelNext++; blockComment = true; } for (unsigned int i = safeStartPos; i < startPos + length; i++) { char chCurr = styler.SafeGetCharAt(i); style = styler.StyleAt(i); if( blockComment && style != SCE_NSIS_COMMENTBOX ) { levelNext--; blockComment = false; } else if( !blockComment && style == SCE_NSIS_COMMENTBOX ) { levelNext++; blockComment = true; } if( bArg1 && !blockComment) { if( nWordStart == -1 && (isNsisLetter(chCurr) || chCurr == '!') ) { nWordStart = i; } else if( isNsisLetter(chCurr) == false && nWordStart > -1 ) { int newLevel = calculateFoldNsis( nWordStart, i-1, levelNext, styler, foldAtElse, foldUtilityCmd ); if( newLevel == levelNext ) { if( foldAtElse && foldUtilityCmd ) { if( NsisNextLineHasElse(i, startPos + length, styler) ) levelNext--; } } else levelNext = newLevel; bArg1 = false; } } if( chCurr == '\n' ) { if( bArg1 && foldAtElse && foldUtilityCmd && !blockComment ) { if( NsisNextLineHasElse(i, startPos + length, styler) ) levelNext--; } // If we are on a new line... int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (levelUse < levelNext ) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); lineCurrent++; levelCurrent = levelNext; bArg1 = true; // New line, lets look at first argument again nWordStart = -1; } } int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); } static const char * const nsisWordLists[] = { "Functions", "Variables", "Lables", "UserDefined", 0, }; LexerModule lmNsis(SCLEX_NSIS, ColouriseNsisDoc, "nsis", FoldNsisDoc, nsisWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexAsn1.cxx0000644000175000017500000001224311615412040021124 00000000000000// Scintilla source code edit control /** @file LexAsn1.cxx ** Lexer for ASN.1 **/ // Copyright 2004 by Herr Pfarrer rpfarrer yahoo de // Last Updated: 20/07/2004 // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Some char test functions static bool isAsn1Number(int ch) { return (ch >= '0' && ch <= '9'); } static bool isAsn1Letter(int ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } static bool isAsn1Char(int ch) { return (ch == '-' ) || isAsn1Number(ch) || isAsn1Letter (ch); } // // Function determining the color of a given code portion // Based on a "state" // static void ColouriseAsn1Doc(unsigned int startPos, int length, int initStyle, WordList *keywordLists[], Accessor &styler) { // The keywords WordList &Keywords = *keywordLists[0]; WordList &Attributes = *keywordLists[1]; WordList &Descriptors = *keywordLists[2]; WordList &Types = *keywordLists[3]; // Parse the whole buffer character by character using StyleContext StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // The state engine switch (sc.state) { case SCE_ASN1_DEFAULT: // Plain characters asn1_default: if (sc.ch == '-' && sc.chNext == '-') // A comment begins here sc.SetState(SCE_ASN1_COMMENT); else if (sc.ch == '"') // A string begins here sc.SetState(SCE_ASN1_STRING); else if (isAsn1Number (sc.ch)) // A number starts here (identifier should start with a letter in ASN.1) sc.SetState(SCE_ASN1_SCALAR); else if (isAsn1Char (sc.ch)) // An identifier starts here (identifier always start with a letter) sc.SetState(SCE_ASN1_IDENTIFIER); else if (sc.ch == ':') // A ::= operator starts here sc.SetState(SCE_ASN1_OPERATOR); break; case SCE_ASN1_COMMENT: // A comment if (sc.ch == '\r' || sc.ch == '\n') // A comment ends here sc.SetState(SCE_ASN1_DEFAULT); break; case SCE_ASN1_IDENTIFIER: // An identifier (keyword, attribute, descriptor or type) if (!isAsn1Char (sc.ch)) { // The end of identifier is here: we can look for it in lists by now and change its state char s[100]; sc.GetCurrent(s, sizeof(s)); if (Keywords.InList(s)) // It's a keyword, change its state sc.ChangeState(SCE_ASN1_KEYWORD); else if (Attributes.InList(s)) // It's an attribute, change its state sc.ChangeState(SCE_ASN1_ATTRIBUTE); else if (Descriptors.InList(s)) // It's a descriptor, change its state sc.ChangeState(SCE_ASN1_DESCRIPTOR); else if (Types.InList(s)) // It's a type, change its state sc.ChangeState(SCE_ASN1_TYPE); // Set to default now sc.SetState(SCE_ASN1_DEFAULT); } break; case SCE_ASN1_STRING: // A string delimited by "" if (sc.ch == '"') { // A string ends here sc.ForwardSetState(SCE_ASN1_DEFAULT); // To correctly manage a char sticking to the string quote goto asn1_default; } break; case SCE_ASN1_SCALAR: // A plain number if (!isAsn1Number (sc.ch)) // A number ends here sc.SetState(SCE_ASN1_DEFAULT); break; case SCE_ASN1_OPERATOR: // The affectation operator ::= and wath follows (eg: ::= { org 6 } OID or ::= 12 trap) if (sc.ch == '{') { // An OID definition starts here: enter the sub loop for (; sc.More(); sc.Forward()) { if (isAsn1Number (sc.ch) && (!isAsn1Char (sc.chPrev) || isAsn1Number (sc.chPrev))) // The OID number is highlighted sc.SetState(SCE_ASN1_OID); else if (isAsn1Char (sc.ch)) // The OID parent identifier is plain sc.SetState(SCE_ASN1_IDENTIFIER); else sc.SetState(SCE_ASN1_DEFAULT); if (sc.ch == '}') // Here ends the OID and the operator sub loop: go back to main loop break; } } else if (isAsn1Number (sc.ch)) { // A trap number definition starts here: enter the sub loop for (; sc.More(); sc.Forward()) { if (isAsn1Number (sc.ch)) // The trap number is highlighted sc.SetState(SCE_ASN1_OID); else { // The number ends here: go back to main loop sc.SetState(SCE_ASN1_DEFAULT); break; } } } else if (sc.ch != ':' && sc.ch != '=' && sc.ch != ' ') // The operator doesn't imply an OID definition nor a trap, back to main loop goto asn1_default; // To be sure to handle actually the state change break; } } sc.Complete(); } static void FoldAsn1Doc(unsigned int, int, int, WordList *[], Accessor &styler) { // No folding enabled, no reason to continue... if( styler.GetPropertyInt("fold") == 0 ) return; // No folding implemented: doesn't make sense for ASN.1 } static const char * const asn1WordLists[] = { "Keywords", "Attributes", "Descriptors", "Types", 0, }; LexerModule lmAns1(SCLEX_ASN1, ColouriseAsn1Doc, "asn1", FoldAsn1Doc, asn1WordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexPB.cxx0000644000175000017500000003040511615412040020623 00000000000000// Scintilla source code edit control // @file LexPB.cxx // Lexer for PowerBasic by Roland Walter, roland@rowalt.de (for PowerBasic see www.powerbasic.com) // // Changes: // 17.10.2003: Toggling of subs/functions now until next sub/function - this gives better results // 29.10.2003: 1. Bug: Toggling didn't work for subs/functions added in editor // 2. Own colors for PB constants and Inline Assembler SCE_B_CONSTANT and SCE_B_ASM // 3. Several smaller syntax coloring improvements and speed optimizations // 12.07.2004: 1. Toggling for macros added // 2. Further folding speed optimitations (for people dealing with very large listings) // // Necessary changes for the PB lexer in Scintilla project: // - In SciLexer.h and Scintilla.iface: // // #define SCLEX_POWERBASIC 51 //ID for PowerBasic lexer // (...) // #define SCE_B_DEFAULT 0 //in both VB and PB lexer // #define SCE_B_COMMENT 1 //in both VB and PB lexer // #define SCE_B_NUMBER 2 //in both VB and PB lexer // #define SCE_B_KEYWORD 3 //in both VB and PB lexer // #define SCE_B_STRING 4 //in both VB and PB lexer // #define SCE_B_PREPROCESSOR 5 //VB lexer only, not in PB lexer // #define SCE_B_OPERATOR 6 //in both VB and PB lexer // #define SCE_B_IDENTIFIER 7 //in both VB and PB lexer // #define SCE_B_DATE 8 //VB lexer only, not in PB lexer // #define SCE_B_CONSTANT 13 //PB lexer only, not in VB lexer // #define SCE_B_ASM 14 //PB lexer only, not in VB lexer // - Statement added to KeyWords.cxx: 'LINK_LEXER(lmPB);' // - Statement added to scintilla_vc6.mak: '$(DIR_O)\LexPB.obj: ...\src\LexPB.cxx $(LEX_HEADERS)' // // Copyright for Scintilla: 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsTypeCharacter(const int ch) { return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$' || ch == '?'; } static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } bool MatchUpperCase(Accessor &styler, int pos, const char *s) //Same as styler.Match() but uppercase comparison (a-z,A-Z and space only) { char ch; for (int i=0; *s; i++) { ch=styler.SafeGetCharAt(pos+i); if (ch > 0x60) ch -= '\x20'; if (*s != ch) return false; s++; } return true; } static void ColourisePBDoc(unsigned int startPos, int length, int initStyle,WordList *keywordlists[],Accessor &styler) { WordList &keywords = *keywordlists[0]; styler.StartAt(startPos); StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { switch (sc.state) { case SCE_B_OPERATOR: { sc.SetState(SCE_B_DEFAULT); break; } case SCE_B_KEYWORD: { if (!IsAWordChar(sc.ch)) { if (!IsTypeCharacter(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { if (strcmp(s, "rem") == 0) { sc.ChangeState(SCE_B_COMMENT); if (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);} } else if (strcmp(s, "asm") == 0) { sc.ChangeState(SCE_B_ASM); if (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);} } else { sc.SetState(SCE_B_DEFAULT); } } else { sc.ChangeState(SCE_B_IDENTIFIER); sc.SetState(SCE_B_DEFAULT); } } } break; } case SCE_B_NUMBER: { if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_B_DEFAULT);} break; } case SCE_B_STRING: { if (sc.ch == '\"'){sc.ForwardSetState(SCE_B_DEFAULT);} break; } case SCE_B_CONSTANT: { if (!IsAWordChar(sc.ch)) {sc.SetState(SCE_B_DEFAULT);} break; } case SCE_B_COMMENT: { if (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);} break; } case SCE_B_ASM: { if (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);} break; } } //switch (sc.state) // Determine if a new state should be entered: if (sc.state == SCE_B_DEFAULT) { if (sc.ch == '\'') {sc.SetState(SCE_B_COMMENT);} else if (sc.ch == '\"') {sc.SetState(SCE_B_STRING);} else if (sc.ch == '&' && tolower(sc.chNext) == 'h') {sc.SetState(SCE_B_NUMBER);} else if (sc.ch == '&' && tolower(sc.chNext) == 'b') {sc.SetState(SCE_B_NUMBER);} else if (sc.ch == '&' && tolower(sc.chNext) == 'o') {sc.SetState(SCE_B_NUMBER);} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {sc.SetState(SCE_B_NUMBER);} else if (IsAWordStart(sc.ch)) {sc.SetState(SCE_B_KEYWORD);} else if (sc.ch == '%') {sc.SetState(SCE_B_CONSTANT);} else if (sc.ch == '$') {sc.SetState(SCE_B_CONSTANT);} else if (sc.ch == '#') {sc.SetState(SCE_B_KEYWORD);} else if (sc.ch == '!') {sc.SetState(SCE_B_ASM);} else if (isoperator(static_cast(sc.ch)) || (sc.ch == '\\')) {sc.SetState(SCE_B_OPERATOR);} } } //for (; sc.More(); sc.Forward()) sc.Complete(); } //The folding routine for PowerBasic toggles SUBs and FUNCTIONs only. This was exactly what I wanted, //nothing more. I had worked with this kind of toggling for several years when I used the great good old //GFA Basic which is dead now. After testing the feature of toggling FOR-NEXT loops, WHILE-WEND loops //and so on too I found this is more disturbing then helping (for me). So if You think in another way //you can (or must) write Your own toggling routine ;-) static void FoldPBDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { // No folding enabled, no reason to continue... if( styler.GetPropertyInt("fold") == 0 ) return; unsigned int endPos = startPos + length; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelNext = levelCurrent; char chNext = styler[startPos]; bool fNewLine=true; bool fMightBeMultiLineMacro=false; bool fBeginOfCommentFound=false; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if (fNewLine) //Begin of a new line (The Sub/Function/Macro keywords may occur at begin of line only) { fNewLine=false; fBeginOfCommentFound=false; switch (ch) { case ' ': //Most lines start with space - so check this first, the code is the same as for 'default:' case '\t': //Handle tab too { int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; styler.SetLevel(lineCurrent, lev); break; } case 'F': case 'f': { switch (chNext) { case 'U': case 'u': { if( MatchUpperCase(styler,i,"FUNCTION") ) { styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG); levelNext=SC_FOLDLEVELBASE+1; } break; } } break; } case 'S': case 's': { switch (chNext) { case 'U': case 'u': { if( MatchUpperCase(styler,i,"SUB") ) { styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG); levelNext=SC_FOLDLEVELBASE+1; } break; } case 'T': case 't': { if( MatchUpperCase(styler,i,"STATIC FUNCTION") ) { styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG); levelNext=SC_FOLDLEVELBASE+1; } else if( MatchUpperCase(styler,i,"STATIC SUB") ) { styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG); levelNext=SC_FOLDLEVELBASE+1; } break; } } break; } case 'C': case 'c': { switch (chNext) { case 'A': case 'a': { if( MatchUpperCase(styler,i,"CALLBACK FUNCTION") ) { styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG); levelNext=SC_FOLDLEVELBASE+1; } break; } } break; } case 'M': case 'm': { switch (chNext) { case 'A': case 'a': { if( MatchUpperCase(styler,i,"MACRO") ) { fMightBeMultiLineMacro=true; //Set folder level at end of line, we have to check for single line macro } break; } } break; } default: { int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; styler.SetLevel(lineCurrent, lev); break; } } //switch (ch) } //if( fNewLine ) switch (ch) { case '=': //To test single line macros { if (fBeginOfCommentFound==false) fMightBeMultiLineMacro=false; //The found macro is a single line macro only; break; } case '\'': //A comment starts { fBeginOfCommentFound=true; break; } case '\n': { if (fMightBeMultiLineMacro) //The current line is the begin of a multi line macro { fMightBeMultiLineMacro=false; styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG); levelNext=SC_FOLDLEVELBASE+1; } lineCurrent++; levelCurrent = levelNext; fNewLine=true; break; } case '\r': { if (chNext != '\n') { lineCurrent++; levelCurrent = levelNext; fNewLine=true; } break; } } //switch (ch) } //for (unsigned int i = startPos; i < endPos; i++) } static const char * const pbWordListDesc[] = { "Keywords", 0 }; LexerModule lmPB(SCLEX_POWERBASIC, ColourisePBDoc, "powerbasic", FoldPBDoc, pbWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexCLW.cxx0000644000175000017500000005304411615412040020753 00000000000000// Scintilla source code edit control /** @file LexClw.cxx ** Lexer for Clarion. ** 2004/12/17 Updated Lexer **/ // Copyright 2003-2004 by Ron Schofield // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Is an end of line character inline bool IsEOL(const int ch) { return(ch == '\n'); } // Convert character to uppercase static char CharacterUpper(char chChar) { if (chChar < 'a' || chChar > 'z') { return(chChar); } else { return(static_cast(chChar - 'a' + 'A')); } } // Convert string to uppercase static void StringUpper(char *szString) { while (*szString) { *szString = CharacterUpper(*szString); szString++; } } // Is a label start character inline bool IsALabelStart(const int iChar) { return(isalpha(iChar) || iChar == '_'); } // Is a label character inline bool IsALabelCharacter(const int iChar) { return(isalnum(iChar) || iChar == '_' || iChar == ':'); } // Is the character is a ! and the the next character is not a ! inline bool IsACommentStart(const int iChar) { return(iChar == '!'); } // Is the character a Clarion hex character (ABCDEF) inline bool IsAHexCharacter(const int iChar, bool bCaseSensitive) { // Case insensitive. if (!bCaseSensitive) { if (strchr("ABCDEFabcdef", iChar) != NULL) { return(true); } } // Case sensitive else { if (strchr("ABCDEF", iChar) != NULL) { return(true); } } return(false); } // Is the character a Clarion base character (B=Binary, O=Octal, H=Hex) inline bool IsANumericBaseCharacter(const int iChar, bool bCaseSensitive) { // Case insensitive. if (!bCaseSensitive) { // If character is a numeric base character if (strchr("BOHboh", iChar) != NULL) { return(true); } } // Case sensitive else { // If character is a numeric base character if (strchr("BOH", iChar) != NULL) { return(true); } } return(false); } // Set the correct numeric constant state inline bool SetNumericConstantState(StyleContext &scDoc) { int iPoints = 0; // Point counter char cNumericString[512]; // Numeric string buffer // Buffer the current numberic string scDoc.GetCurrent(cNumericString, sizeof(cNumericString)); // Loop through the string until end of string (NULL termination) for (int iIndex = 0; cNumericString[iIndex] != '\0'; iIndex++) { // Depending on the character switch (cNumericString[iIndex]) { // Is a . (point) case '.' : // Increment point counter iPoints++; break; default : break; } } // If points found (can be more than one for improper formatted number if (iPoints > 0) { return(true); } // Else no points found else { return(false); } } // Get the next word in uppercase from the current position (keyword lookahead) inline bool GetNextWordUpper(Accessor &styler, unsigned int uiStartPos, int iLength, char *cWord) { unsigned int iIndex = 0; // Buffer Index // Loop through the remaining string from the current position for (int iOffset = uiStartPos; iOffset < iLength; iOffset++) { // Get the character from the buffer using the offset char cCharacter = styler[iOffset]; if (IsEOL(cCharacter)) { break; } // If the character is alphabet character if (isalpha(cCharacter)) { // Add UPPERCASE character to the word buffer cWord[iIndex++] = CharacterUpper(cCharacter); } } // Add null termination cWord[iIndex] = '\0'; // If no word was found if (iIndex == 0) { // Return failure return(false); } // Else word was found else { // Return success return(true); } } // Clarion Language Colouring Procedure static void ColouriseClarionDoc(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler, bool bCaseSensitive) { int iParenthesesLevel = 0; // Parenthese Level int iColumn1Label = false; // Label starts in Column 1 WordList &wlClarionKeywords = *wlKeywords[0]; // Clarion Keywords WordList &wlCompilerDirectives = *wlKeywords[1]; // Compiler Directives WordList &wlRuntimeExpressions = *wlKeywords[2]; // Runtime Expressions WordList &wlBuiltInProcsFuncs = *wlKeywords[3]; // Builtin Procedures and Functions WordList &wlStructsDataTypes = *wlKeywords[4]; // Structures and Data Types WordList &wlAttributes = *wlKeywords[5]; // Procedure Attributes WordList &wlStandardEquates = *wlKeywords[6]; // Standard Equates WordList &wlLabelReservedWords = *wlKeywords[7]; // Clarion Reserved Keywords (Labels) WordList &wlProcLabelReservedWords = *wlKeywords[8]; // Clarion Reserved Keywords (Procedure Labels) const char wlProcReservedKeywordList[] = "PROCEDURE FUNCTION"; WordList wlProcReservedKeywords; wlProcReservedKeywords.Set(wlProcReservedKeywordList); const char wlCompilerKeywordList[] = "COMPILE OMIT"; WordList wlCompilerKeywords; wlCompilerKeywords.Set(wlCompilerKeywordList); const char wlLegacyStatementsList[] = "BOF EOF FUNCTION POINTER SHARE"; WordList wlLegacyStatements; wlLegacyStatements.Set(wlLegacyStatementsList); StyleContext scDoc(uiStartPos, iLength, iInitStyle, accStyler); // lex source code for (; scDoc.More(); scDoc.Forward()) { // // Determine if the current state should terminate. // // Label State Handling if (scDoc.state == SCE_CLW_LABEL) { // If the character is not a valid label if (!IsALabelCharacter(scDoc.ch)) { // If the character is a . (dot syntax) if (scDoc.ch == '.') { // Turn off column 1 label flag as label now cannot be reserved work iColumn1Label = false; // Uncolour the . (dot) to default state, move forward one character, // and change back to the label state. scDoc.SetState(SCE_CLW_DEFAULT); scDoc.Forward(); scDoc.SetState(SCE_CLW_LABEL); } // Else check label else { char cLabel[512]; // Label buffer // Buffer the current label string scDoc.GetCurrent(cLabel,sizeof(cLabel)); // If case insensitive, convert string to UPPERCASE to match passed keywords. if (!bCaseSensitive) { StringUpper(cLabel); } // Else if UPPERCASE label string is in the Clarion compiler keyword list if (wlCompilerKeywords.InList(cLabel) && iColumn1Label){ // change the label to error state scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); } // Else if UPPERCASE label string is in the Clarion reserved keyword list else if (wlLabelReservedWords.InList(cLabel) && iColumn1Label){ // change the label to error state scDoc.ChangeState(SCE_CLW_ERROR); } // Else if UPPERCASE label string is else if (wlProcLabelReservedWords.InList(cLabel) && iColumn1Label) { char cWord[512]; // Word buffer // Get the next word from the current position if (GetNextWordUpper(accStyler,scDoc.currentPos,uiStartPos+iLength,cWord)) { // If the next word is a procedure reserved word if (wlProcReservedKeywords.InList(cWord)) { // Change the label to error state scDoc.ChangeState(SCE_CLW_ERROR); } } } // Else if label string is in the compiler directive keyword list else if (wlCompilerDirectives.InList(cLabel)) { // change the state to compiler directive state scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); } // Terminate the label state and set to default state scDoc.SetState(SCE_CLW_DEFAULT); } } } // Keyword State Handling else if (scDoc.state == SCE_CLW_KEYWORD) { // If character is : (colon) if (scDoc.ch == ':') { char cEquate[512]; // Equate buffer // Move forward to include : (colon) in buffer scDoc.Forward(); // Buffer the equate string scDoc.GetCurrent(cEquate,sizeof(cEquate)); // If case insensitive, convert string to UPPERCASE to match passed keywords. if (!bCaseSensitive) { StringUpper(cEquate); } // If statement string is in the equate list if (wlStandardEquates.InList(cEquate)) { // Change to equate state scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE); } } // If the character is not a valid label character else if (!IsALabelCharacter(scDoc.ch)) { char cStatement[512]; // Statement buffer // Buffer the statement string scDoc.GetCurrent(cStatement,sizeof(cStatement)); // If case insensitive, convert string to UPPERCASE to match passed keywords. if (!bCaseSensitive) { StringUpper(cStatement); } // If statement string is in the Clarion keyword list if (wlClarionKeywords.InList(cStatement)) { // Change the statement string to the Clarion keyword state scDoc.ChangeState(SCE_CLW_KEYWORD); } // Else if statement string is in the compiler directive keyword list else if (wlCompilerDirectives.InList(cStatement)) { // Change the statement string to the compiler directive state scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); } // Else if statement string is in the runtime expressions keyword list else if (wlRuntimeExpressions.InList(cStatement)) { // Change the statement string to the runtime expressions state scDoc.ChangeState(SCE_CLW_RUNTIME_EXPRESSIONS); } // Else if statement string is in the builtin procedures and functions keyword list else if (wlBuiltInProcsFuncs.InList(cStatement)) { // Change the statement string to the builtin procedures and functions state scDoc.ChangeState(SCE_CLW_BUILTIN_PROCEDURES_FUNCTION); } // Else if statement string is in the tructures and data types keyword list else if (wlStructsDataTypes.InList(cStatement)) { // Change the statement string to the structures and data types state scDoc.ChangeState(SCE_CLW_STRUCTURE_DATA_TYPE); } // Else if statement string is in the procedure attribute keyword list else if (wlAttributes.InList(cStatement)) { // Change the statement string to the procedure attribute state scDoc.ChangeState(SCE_CLW_ATTRIBUTE); } // Else if statement string is in the standard equate keyword list else if (wlStandardEquates.InList(cStatement)) { // Change the statement string to the standard equate state scDoc.ChangeState(SCE_CLW_STANDARD_EQUATE); } // Else if statement string is in the deprecated or legacy keyword list else if (wlLegacyStatements.InList(cStatement)) { // Change the statement string to the standard equate state scDoc.ChangeState(SCE_CLW_DEPRECATED); } // Else the statement string doesn't match any work list else { // Change the statement string to the default state scDoc.ChangeState(SCE_CLW_DEFAULT); } // Terminate the keyword state and set to default state scDoc.SetState(SCE_CLW_DEFAULT); } } // String State Handling else if (scDoc.state == SCE_CLW_STRING) { // If the character is an ' (single quote) if (scDoc.ch == '\'') { // Set the state to default and move forward colouring // the ' (single quote) as default state // terminating the string state scDoc.SetState(SCE_CLW_DEFAULT); scDoc.Forward(); } // If the next character is an ' (single quote) if (scDoc.chNext == '\'') { // Move forward one character and set to default state // colouring the next ' (single quote) as default state // terminating the string state scDoc.ForwardSetState(SCE_CLW_DEFAULT); scDoc.Forward(); } } // Picture String State Handling else if (scDoc.state == SCE_CLW_PICTURE_STRING) { // If the character is an ( (open parenthese) if (scDoc.ch == '(') { // Increment the parenthese level iParenthesesLevel++; } // Else if the character is a ) (close parenthese) else if (scDoc.ch == ')') { // If the parenthese level is set to zero // parentheses matched if (!iParenthesesLevel) { scDoc.SetState(SCE_CLW_DEFAULT); } // Else parenthese level is greater than zero // still looking for matching parentheses else { // Decrement the parenthese level iParenthesesLevel--; } } } // Standard Equate State Handling else if (scDoc.state == SCE_CLW_STANDARD_EQUATE) { if (!isalnum(scDoc.ch)) { scDoc.SetState(SCE_CLW_DEFAULT); } } // Integer Constant State Handling else if (scDoc.state == SCE_CLW_INTEGER_CONSTANT) { // If the character is not a digit (0-9) // or character is not a hexidecimal character (A-F) // or character is not a . (point) // or character is not a numberic base character (B,O,H) if (!(isdigit(scDoc.ch) || IsAHexCharacter(scDoc.ch, bCaseSensitive) || scDoc.ch == '.' || IsANumericBaseCharacter(scDoc.ch, bCaseSensitive))) { // If the number was a real if (SetNumericConstantState(scDoc)) { // Colour the matched string to the real constant state scDoc.ChangeState(SCE_CLW_REAL_CONSTANT); } // Else the number was an integer else { // Colour the matched string to an integer constant state scDoc.ChangeState(SCE_CLW_INTEGER_CONSTANT); } // Terminate the integer constant state and set to default state scDoc.SetState(SCE_CLW_DEFAULT); } } // // Determine if a new state should be entered. // // Beginning of Line Handling if (scDoc.atLineStart) { // Reset the column 1 label flag iColumn1Label = false; // If column 1 character is a label start character if (IsALabelStart(scDoc.ch)) { // Label character is found in column 1 // so set column 1 label flag and clear last column 1 label iColumn1Label = true; // Set the state to label scDoc.SetState(SCE_CLW_LABEL); } // else if character is a space or tab else if (IsASpace(scDoc.ch)){ // Set to default state scDoc.SetState(SCE_CLW_DEFAULT); } // else if comment start (!) or is an * (asterisk) else if (IsACommentStart(scDoc.ch) || scDoc.ch == '*' ) { // then set the state to comment. scDoc.SetState(SCE_CLW_COMMENT); } // else the character is a ? (question mark) else if (scDoc.ch == '?') { // Change to the compiler directive state, move forward, // colouring the ? (question mark), change back to default state. scDoc.ChangeState(SCE_CLW_COMPILER_DIRECTIVE); scDoc.Forward(); scDoc.SetState(SCE_CLW_DEFAULT); } // else an invalid character in column 1 else { // Set to error state scDoc.SetState(SCE_CLW_ERROR); } } // End of Line Handling else if (scDoc.atLineEnd) { // Reset to the default state at the end of each line. scDoc.SetState(SCE_CLW_DEFAULT); } // Default Handling else { // If in default state if (scDoc.state == SCE_CLW_DEFAULT) { // If is a letter could be a possible statement if (isalpha(scDoc.ch)) { // Set the state to Clarion Keyword and verify later scDoc.SetState(SCE_CLW_KEYWORD); } // else is a number else if (isdigit(scDoc.ch)) { // Set the state to Integer Constant and verify later scDoc.SetState(SCE_CLW_INTEGER_CONSTANT); } // else if the start of a comment or a | (line continuation) else if (IsACommentStart(scDoc.ch) || scDoc.ch == '|') { // then set the state to comment. scDoc.SetState(SCE_CLW_COMMENT); } // else if the character is a ' (single quote) else if (scDoc.ch == '\'') { // If the character is also a ' (single quote) // Embedded Apostrophe if (scDoc.chNext == '\'') { // Move forward colouring it as default state scDoc.ForwardSetState(SCE_CLW_DEFAULT); } else { // move to the next character and then set the state to comment. scDoc.ForwardSetState(SCE_CLW_STRING); } } // else the character is an @ (ampersand) else if (scDoc.ch == '@') { // Case insensitive. if (!bCaseSensitive) { // If character is a valid picture token character if (strchr("DEKNPSTdeknpst", scDoc.chNext) != NULL) { // Set to the picture string state scDoc.SetState(SCE_CLW_PICTURE_STRING); } } // Case sensitive else { // If character is a valid picture token character if (strchr("DEKNPST", scDoc.chNext) != NULL) { // Set the picture string state scDoc.SetState(SCE_CLW_PICTURE_STRING); } } } } } } // lexing complete scDoc.Complete(); } // Clarion Language Case Sensitive Colouring Procedure static void ColouriseClarionDocSensitive(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) { ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, true); } // Clarion Language Case Insensitive Colouring Procedure static void ColouriseClarionDocInsensitive(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *wlKeywords[], Accessor &accStyler) { ColouriseClarionDoc(uiStartPos, iLength, iInitStyle, wlKeywords, accStyler, false); } // Fill Buffer static void FillBuffer(unsigned int uiStart, unsigned int uiEnd, Accessor &accStyler, char *szBuffer, unsigned int uiLength) { unsigned int uiPos = 0; while ((uiPos < uiEnd - uiStart + 1) && (uiPos < uiLength-1)) { szBuffer[uiPos] = static_cast(toupper(accStyler[uiStart + uiPos])); uiPos++; } szBuffer[uiPos] = '\0'; } // Classify Clarion Fold Point static int ClassifyClarionFoldPoint(int iLevel, const char* szString) { if (!(isdigit(szString[0]) || (szString[0] == '.'))) { if (strcmp(szString, "PROCEDURE") == 0) { // iLevel = SC_FOLDLEVELBASE + 1; } else if (strcmp(szString, "MAP") == 0 || strcmp(szString,"ACCEPT") == 0 || strcmp(szString,"BEGIN") == 0 || strcmp(szString,"CASE") == 0 || strcmp(szString,"EXECUTE") == 0 || strcmp(szString,"IF") == 0 || strcmp(szString,"ITEMIZE") == 0 || strcmp(szString,"INTERFACE") == 0 || strcmp(szString,"JOIN") == 0 || strcmp(szString,"LOOP") == 0 || strcmp(szString,"MODULE") == 0 || strcmp(szString,"RECORD") == 0) { iLevel++; } else if (strcmp(szString, "APPLICATION") == 0 || strcmp(szString, "CLASS") == 0 || strcmp(szString, "DETAIL") == 0 || strcmp(szString, "FILE") == 0 || strcmp(szString, "FOOTER") == 0 || strcmp(szString, "FORM") == 0 || strcmp(szString, "GROUP") == 0 || strcmp(szString, "HEADER") == 0 || strcmp(szString, "INTERFACE") == 0 || strcmp(szString, "MENU") == 0 || strcmp(szString, "MENUBAR") == 0 || strcmp(szString, "OLE") == 0 || strcmp(szString, "OPTION") == 0 || strcmp(szString, "QUEUE") == 0 || strcmp(szString, "REPORT") == 0 || strcmp(szString, "SHEET") == 0 || strcmp(szString, "TAB") == 0 || strcmp(szString, "TOOLBAR") == 0 || strcmp(szString, "VIEW") == 0 || strcmp(szString, "WINDOW") == 0) { iLevel++; } else if (strcmp(szString, "END") == 0 || strcmp(szString, "UNTIL") == 0 || strcmp(szString, "WHILE") == 0) { iLevel--; } } return(iLevel); } // Clarion Language Folding Procedure static void FoldClarionDoc(unsigned int uiStartPos, int iLength, int iInitStyle, WordList *[], Accessor &accStyler) { unsigned int uiEndPos = uiStartPos + iLength; int iLineCurrent = accStyler.GetLine(uiStartPos); int iLevelPrev = accStyler.LevelAt(iLineCurrent) & SC_FOLDLEVELNUMBERMASK; int iLevelCurrent = iLevelPrev; char chNext = accStyler[uiStartPos]; int iStyle = iInitStyle; int iStyleNext = accStyler.StyleAt(uiStartPos); int iVisibleChars = 0; int iLastStart = 0; for (unsigned int uiPos = uiStartPos; uiPos < uiEndPos; uiPos++) { char chChar = chNext; chNext = accStyler.SafeGetCharAt(uiPos + 1); int iStylePrev = iStyle; iStyle = iStyleNext; iStyleNext = accStyler.StyleAt(uiPos + 1); bool bEOL = (chChar == '\r' && chNext != '\n') || (chChar == '\n'); if (iStylePrev == SCE_CLW_DEFAULT) { if (iStyle == SCE_CLW_KEYWORD || iStyle == SCE_CLW_STRUCTURE_DATA_TYPE) { // Store last word start point. iLastStart = uiPos; } } if (iStylePrev == SCE_CLW_KEYWORD || iStylePrev == SCE_CLW_STRUCTURE_DATA_TYPE) { if(iswordchar(chChar) && !iswordchar(chNext)) { char chBuffer[100]; FillBuffer(iLastStart, uiPos, accStyler, chBuffer, sizeof(chBuffer)); iLevelCurrent = ClassifyClarionFoldPoint(iLevelCurrent,chBuffer); // if ((iLevelCurrent == SC_FOLDLEVELBASE + 1) && iLineCurrent > 1) { // accStyler.SetLevel(iLineCurrent-1,SC_FOLDLEVELBASE); // iLevelPrev = SC_FOLDLEVELBASE; // } } } if (bEOL) { int iLevel = iLevelPrev; if ((iLevelCurrent > iLevelPrev) && (iVisibleChars > 0)) iLevel |= SC_FOLDLEVELHEADERFLAG; if (iLevel != accStyler.LevelAt(iLineCurrent)) { accStyler.SetLevel(iLineCurrent,iLevel); } iLineCurrent++; iLevelPrev = iLevelCurrent; iVisibleChars = 0; } if (!isspacechar(chChar)) iVisibleChars++; } // Fill in the real level of the next line, keeping the current flags // as they will be filled in later. int iFlagsNext = accStyler.LevelAt(iLineCurrent) & ~SC_FOLDLEVELNUMBERMASK; accStyler.SetLevel(iLineCurrent, iLevelPrev | iFlagsNext); } // Word List Descriptions static const char * const rgWordListDescriptions[] = { "Clarion Keywords", "Compiler Directives", "Built-in Procedures and Functions", "Runtime Expressions", "Structure and Data Types", "Attributes", "Standard Equates", "Reserved Words (Labels)", "Reserved Words (Procedure Labels)", 0, }; // Case Sensitive Clarion Language Lexer LexerModule lmClw(SCLEX_CLW, ColouriseClarionDocSensitive, "clarion", FoldClarionDoc, rgWordListDescriptions); // Case Insensitive Clarion Language Lexer LexerModule lmClwNoCase(SCLEX_CLWNOCASE, ColouriseClarionDocInsensitive, "clarionnocase", FoldClarionDoc, rgWordListDescriptions); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexOScript.cxx0000644000175000017500000004623511763437013021730 00000000000000// Scintilla source code edit control /** @file LexOScript.cxx ** Lexer for OScript sources; ocx files and/or OSpace dumps. ** OScript is a programming language used to develop applications for the ** Livelink server platform. **/ // Written by Ferdinand Prantl , inspired by the code from // LexVB.cxx and LexPascal.cxx. The License.txt file describes the conditions // under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // ----------------------------------------- // Functions classifying a single character. // This function is generic and should be probably moved to CharSet.h where // IsAlphaNumeric the others reside. inline bool IsAlpha(int ch) { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); } static inline bool IsIdentifierChar(int ch) { // Identifiers cannot contain non-ASCII letters; a word with non-English // language-specific characters cannot be an identifier. return IsAlphaNumeric(ch) || ch == '_'; } static inline bool IsIdentifierStart(int ch) { // Identifiers cannot contain non-ASCII letters; a word with non-English // language-specific characters cannot be an identifier. return IsAlpha(ch) || ch == '_'; } static inline bool IsNumberChar(int ch, int chNext) { // Numeric constructs are not checked for lexical correctness. They are // expected to look like +1.23-E9 but actually any bunch of the following // characters will be styled as number. // KNOWN PROBLEM: if you put + or - operators immediately after a number // and the next operand starts with the letter E, the operator will not be // recognized and it will be styled together with the preceding number. // This should not occur; at least not often. The coding style recommends // putting spaces around operators. return IsADigit(ch) || toupper(ch) == 'E' || ch == '.' || ((ch == '-' || ch == '+') && toupper(chNext) == 'E'); } // This function checks for the start or a natural number without any symbols // or operators as a prefix; the IsPrefixedNumberStart should be called // immediately after this one to cover all possible numeric constructs. static inline bool IsNaturalNumberStart(int ch) { return IsADigit(ch) != 0; } static inline bool IsPrefixedNumberStart(int ch, int chNext) { // KNOWN PROBLEM: if you put + or - operators immediately before a number // the operator will not be recognized and it will be styled together with // the succeeding number. This should not occur; at least not often. The // coding style recommends putting spaces around operators. return (ch == '.' || ch == '-' || ch == '+') && IsADigit(chNext); } static inline bool IsOperator(int ch) { return strchr("%^&*()-+={}[]:;<>,/?!.~|\\", ch) != NULL; } // --------------------------------------------------------------- // Functions classifying a token currently processed in the lexer. // Checks if the current line starts with the preprocessor directive used // usually to introduce documentation comments: #ifdef DOC. This method is // supposed to be called if the line has been recognized as a preprocessor // directive already. static bool IsDocCommentStart(StyleContext &sc) { // Check the line back to its start only if the end looks promising. if (sc.LengthCurrent() == 10 && !IsAlphaNumeric(sc.ch)) { char s[11]; sc.GetCurrentLowered(s, sizeof(s)); return strcmp(s, "#ifdef doc") == 0; } return false; } // Checks if the current line starts with the preprocessor directive that // is complementary to the #ifdef DOC start: #endif. This method is supposed // to be called if the current state point to the documentation comment. // QUESTIONAL ASSUMPTION: The complete #endif directive is not checked; just // the starting #e. However, there is no other preprocessor directive with // the same starting letter and thus this optimization should always work. static bool IsDocCommentEnd(StyleContext &sc) { return sc.ch == '#' && sc.chNext == 'e'; } class IdentifierClassifier { WordList &keywords; // Passed from keywords property. WordList &constants; // Passed from keywords2 property. WordList &operators; // Passed from keywords3 property. WordList &types; // Passed from keywords4 property. WordList &functions; // Passed from keywords5 property. WordList &objects; // Passed from keywords6 property. IdentifierClassifier(IdentifierClassifier const&); IdentifierClassifier& operator=(IdentifierClassifier const&); public: IdentifierClassifier(WordList *keywordlists[]) : keywords(*keywordlists[0]), constants(*keywordlists[1]), operators(*keywordlists[2]), types(*keywordlists[3]), functions(*keywordlists[4]), objects(*keywordlists[5]) {} void ClassifyIdentifier(StyleContext &sc) { // Opening parenthesis following an identifier makes it a possible // function call. // KNOWN PROBLEM: If some whitespace is inserted between the // identifier and the parenthesis they will not be able to be // recognized as a function call. This should not occur; at // least not often. Such coding style would be weird. if (sc.Match('(')) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); // Before an opening brace can be control statements and // operators too; function call is the last option. if (keywords.InList(s)) { sc.ChangeState(SCE_OSCRIPT_KEYWORD); } else if (operators.InList(s)) { sc.ChangeState(SCE_OSCRIPT_OPERATOR); } else if (functions.InList(s)) { sc.ChangeState(SCE_OSCRIPT_FUNCTION); } else { sc.ChangeState(SCE_OSCRIPT_METHOD); } sc.SetState(SCE_OSCRIPT_OPERATOR); } else { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); // A dot following an identifier means an access to an object // member. The related object identifier can be special. // KNOWN PROBLEM: If there is whitespace between the identifier // and the following dot, the identifier will not be recognized // as an object in an object member access. If it is one of the // listed static objects it will not be styled. if (sc.Match('.') && objects.InList(s)) { sc.ChangeState(SCE_OSCRIPT_OBJECT); sc.SetState(SCE_OSCRIPT_OPERATOR); } else { if (keywords.InList(s)) { sc.ChangeState(SCE_OSCRIPT_KEYWORD); } else if (constants.InList(s)) { sc.ChangeState(SCE_OSCRIPT_CONSTANT); } else if (operators.InList(s)) { sc.ChangeState(SCE_OSCRIPT_OPERATOR); } else if (types.InList(s)) { sc.ChangeState(SCE_OSCRIPT_TYPE); } else if (functions.InList(s)) { sc.ChangeState(SCE_OSCRIPT_FUNCTION); } sc.SetState(SCE_OSCRIPT_DEFAULT); } } } }; // ------------------------------------------------ // Function colourising an excerpt of OScript code. static void ColouriseOScriptDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { // I wonder how whole-line styles ended by EOLN can escape the resetting // code in the loop below and overflow to the next line. Let us make sure // that a new line does not start with them carried from the previous one. // NOTE: An overflowing string is intentionally not checked; it reminds // the developer that the string must be ended on the same line. if (initStyle == SCE_OSCRIPT_LINE_COMMENT || initStyle == SCE_OSCRIPT_PREPROCESSOR) { initStyle = SCE_OSCRIPT_DEFAULT; } styler.StartAt(startPos); StyleContext sc(startPos, length, initStyle, styler); IdentifierClassifier identifierClassifier(keywordlists); // It starts with true at the beginning of a line and changes to false as // soon as the first non-whitespace character has been processed. bool isFirstToken = true; // It starts with true at the beginning of a line and changes to false as // soon as the first identifier on the line is passed by. bool isFirstIdentifier = true; // It becomes false when #ifdef DOC (the preprocessor directive often // used to start a documentation comment) is encountered and remain false // until the end of the documentation block is not detected. This is done // by checking for the complementary #endif preprocessor directive. bool endDocComment = false; for (; sc.More(); sc.Forward()) { if (sc.atLineStart) { isFirstToken = true; isFirstIdentifier = true; // Detect the current state is neither whitespace nor identifier. It // means that no next identifier can be the first token on the line. } else if (isFirstIdentifier && sc.state != SCE_OSCRIPT_DEFAULT && sc.state != SCE_OSCRIPT_IDENTIFIER) { isFirstIdentifier = false; } // Check if the current state should be changed. if (sc.state == SCE_OSCRIPT_OPERATOR) { // Multiple-symbol operators are marked by single characters. sc.SetState(SCE_OSCRIPT_DEFAULT); } else if (sc.state == SCE_OSCRIPT_IDENTIFIER) { if (!IsIdentifierChar(sc.ch)) { // Colon after an identifier makes it a label if it is the // first token on the line. // KNOWN PROBLEM: If some whitespace is inserted between the // identifier and the colon they will not be recognized as a // label. This should not occur; at least not often. It would // make the code structure less legible and examples in the // Livelink documentation do not show it. if (sc.Match(':') && isFirstIdentifier) { sc.ChangeState(SCE_OSCRIPT_LABEL); sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } else { identifierClassifier.ClassifyIdentifier(sc); } // Avoid a sequence of two words be mistaken for a label. A // switch case would be an example. isFirstIdentifier = false; } } else if (sc.state == SCE_OSCRIPT_GLOBAL) { if (!IsIdentifierChar(sc.ch)) { sc.SetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_PROPERTY) { if (!IsIdentifierChar(sc.ch)) { // Any member access introduced by the dot operator is // initially marked as a property access. If an opening // parenthesis is detected later it is changed to method call. // KNOWN PROBLEM: The same as at the function call recognition // for SCE_OSCRIPT_IDENTIFIER above. if (sc.Match('(')) { sc.ChangeState(SCE_OSCRIPT_METHOD); } sc.SetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_NUMBER) { if (!IsNumberChar(sc.ch, sc.chNext)) { sc.SetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_SINGLEQUOTE_STRING) { if (sc.ch == '\'') { // Two consequential apostrophes convert to a single one. if (sc.chNext == '\'') { sc.Forward(); } else { sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.atLineEnd) { sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_DOUBLEQUOTE_STRING) { if (sc.ch == '\"') { // Two consequential quotation marks convert to a single one. if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.atLineEnd) { sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_BLOCK_COMMENT) { if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_LINE_COMMENT) { if (sc.atLineEnd) { sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_PREPROCESSOR) { if (IsDocCommentStart(sc)) { sc.ChangeState(SCE_OSCRIPT_DOC_COMMENT); endDocComment = false; } else if (sc.atLineEnd) { sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } else if (sc.state == SCE_OSCRIPT_DOC_COMMENT) { // KNOWN PROBLEM: The first line detected that would close a // conditional preprocessor block (#endif) the documentation // comment block will end. (Nested #if-#endif blocks are not // supported. Hopefully it will not occur often that a line // within the text block would stat with #endif. if (isFirstToken && IsDocCommentEnd(sc)) { endDocComment = true; } else if (sc.atLineEnd && endDocComment) { sc.ForwardSetState(SCE_OSCRIPT_DEFAULT); } } // Check what state starts with the current character. if (sc.state == SCE_OSCRIPT_DEFAULT) { if (sc.Match('\'')) { sc.SetState(SCE_OSCRIPT_SINGLEQUOTE_STRING); } else if (sc.Match('\"')) { sc.SetState(SCE_OSCRIPT_DOUBLEQUOTE_STRING); } else if (sc.Match('/', '/')) { sc.SetState(SCE_OSCRIPT_LINE_COMMENT); sc.Forward(); } else if (sc.Match('/', '*')) { sc.SetState(SCE_OSCRIPT_BLOCK_COMMENT); sc.Forward(); } else if (isFirstToken && sc.Match('#')) { sc.SetState(SCE_OSCRIPT_PREPROCESSOR); } else if (sc.Match('$')) { // Both process-global ($xxx) and thread-global ($$xxx) // variables are handled as one global. sc.SetState(SCE_OSCRIPT_GLOBAL); } else if (IsNaturalNumberStart(sc.ch)) { sc.SetState(SCE_OSCRIPT_NUMBER); } else if (IsPrefixedNumberStart(sc.ch, sc.chNext)) { sc.SetState(SCE_OSCRIPT_NUMBER); sc.Forward(); } else if (sc.Match('.') && IsIdentifierStart(sc.chNext)) { // Every object member access is marked as a property access // initially. The decision between property and method is made // after parsing the identifier and looking what comes then. // KNOWN PROBLEM: If there is whitespace between the following // identifier and the dot, the dot will not be recognized // as a member accessing operator. In turn, the identifier // will not be recognizable as a property or a method too. sc.SetState(SCE_OSCRIPT_OPERATOR); sc.Forward(); sc.SetState(SCE_OSCRIPT_PROPERTY); } else if (IsIdentifierStart(sc.ch)) { sc.SetState(SCE_OSCRIPT_IDENTIFIER); } else if (IsOperator(sc.ch)) { sc.SetState(SCE_OSCRIPT_OPERATOR); } } if (isFirstToken && !IsASpaceOrTab(sc.ch)) { isFirstToken = false; } } sc.Complete(); } // ------------------------------------------ // Functions supporting OScript code folding. static inline bool IsBlockComment(int style) { return style == SCE_OSCRIPT_BLOCK_COMMENT; } static bool IsLineComment(int line, Accessor &styler) { int pos = styler.LineStart(line); int eolPos = styler.LineStart(line + 1) - 1; for (int i = pos; i < eolPos; i++) { char ch = styler[i]; char chNext = styler.SafeGetCharAt(i + 1); int style = styler.StyleAt(i); if (ch == '/' && chNext == '/' && style == SCE_OSCRIPT_LINE_COMMENT) { return true; } else if (!IsASpaceOrTab(ch)) { return false; } } return false; } static inline bool IsPreprocessor(int style) { return style == SCE_OSCRIPT_PREPROCESSOR || style == SCE_OSCRIPT_DOC_COMMENT; } static void GetRangeLowered(unsigned int start, unsigned int end, Accessor &styler, char *s, unsigned int len) { unsigned int i = 0; while (i < end - start + 1 && i < len - 1) { s[i] = static_cast(tolower(styler[start + i])); i++; } s[i] = '\0'; } static void GetForwardWordLowered(unsigned int start, Accessor &styler, char *s, unsigned int len) { unsigned int i = 0; while (i < len - 1 && IsAlpha(styler.SafeGetCharAt(start + i))) { s[i] = static_cast(tolower(styler.SafeGetCharAt(start + i))); i++; } s[i] = '\0'; } static void UpdatePreprocessorFoldLevel(int &levelCurrent, unsigned int startPos, Accessor &styler) { char s[7]; // Size of the longest possible keyword + null. GetForwardWordLowered(startPos, styler, s, sizeof(s)); if (strcmp(s, "ifdef") == 0 || strcmp(s, "ifndef") == 0) { levelCurrent++; } else if (strcmp(s, "endif") == 0) { levelCurrent--; if (levelCurrent < SC_FOLDLEVELBASE) { levelCurrent = SC_FOLDLEVELBASE; } } } static void UpdateKeywordFoldLevel(int &levelCurrent, unsigned int lastStart, unsigned int currentPos, Accessor &styler) { char s[9]; GetRangeLowered(lastStart, currentPos, styler, s, sizeof(s)); if (strcmp(s, "if") == 0 || strcmp(s, "for") == 0 || strcmp(s, "switch") == 0 || strcmp(s, "function") == 0 || strcmp(s, "while") == 0 || strcmp(s, "repeat") == 0) { levelCurrent++; } else if (strcmp(s, "end") == 0 || strcmp(s, "until") == 0) { levelCurrent--; if (levelCurrent < SC_FOLDLEVELBASE) { levelCurrent = SC_FOLDLEVELBASE; } } } // ------------------------------ // Function folding OScript code. static void FoldOScriptDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; int lastStart = 0; for (int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atLineEnd = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && IsBlockComment(style)) { if (!IsBlockComment(stylePrev)) { levelCurrent++; } else if (!IsBlockComment(styleNext) && !atLineEnd) { // Comments do not end at end of line and the next character // may not be styled. levelCurrent--; } } if (foldComment && atLineEnd && IsLineComment(lineCurrent, styler)) { if (!IsLineComment(lineCurrent - 1, styler) && IsLineComment(lineCurrent + 1, styler)) levelCurrent++; else if (IsLineComment(lineCurrent - 1, styler) && !IsLineComment(lineCurrent+1, styler)) levelCurrent--; } if (foldPreprocessor) { if (ch == '#' && IsPreprocessor(style)) { UpdatePreprocessorFoldLevel(levelCurrent, i + 1, styler); } } if (stylePrev != SCE_OSCRIPT_KEYWORD && style == SCE_OSCRIPT_KEYWORD) { lastStart = i; } if (stylePrev == SCE_OSCRIPT_KEYWORD) { if(IsIdentifierChar(ch) && !IsIdentifierChar(chNext)) { UpdateKeywordFoldLevel(levelCurrent, lastStart, i, styler); } } if (!IsASpace(ch)) visibleChars++; if (atLineEnd) { int level = levelPrev; if (visibleChars == 0 && foldCompact) level |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) level |= SC_FOLDLEVELHEADERFLAG; if (level != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, level); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } } // If we did not reach EOLN in the previous loop, store the line level and // whitespace information. The rest will be filled in later. int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; styler.SetLevel(lineCurrent, lev); } // -------------------------------------------- // Declaration of the OScript lexer descriptor. static const char * const oscriptWordListDesc[] = { "Keywords and reserved words", "Literal constants", "Literal operators", "Built-in value and reference types", "Built-in global functions", "Built-in static objects", 0 }; LexerModule lmOScript(SCLEX_OSCRIPT, ColouriseOScriptDoc, "oscript", FoldOScriptDoc, oscriptWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexTCL.cxx0000644000175000017500000003133211660423551020755 00000000000000// Scintilla source code edit control /** @file LexTCL.cxx ** Lexer for TCL language. **/ // Copyright 1998-2001 by Andre Arpin // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Extended to accept accented characters static inline bool IsAWordChar(int ch) { return ch >= 0x80 || (isalnum(ch) || ch == '_' || ch ==':' || ch=='.'); // : name space separator } static inline bool IsAWordStart(int ch) { return ch >= 0x80 || (ch ==':' || isalpha(ch) || ch == '_'); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (IsADigit(ch, 0x10) || toupper(ch) == 'E' || ch == '.' || ch == '-' || ch == '+'); } static void ColouriseTCLDoc(unsigned int startPos, int length, int , WordList *keywordlists[], Accessor &styler) { #define isComment(s) (s==SCE_TCL_COMMENT || s==SCE_TCL_COMMENTLINE || s==SCE_TCL_COMMENT_BOX || s==SCE_TCL_BLOCK_COMMENT) bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool commentLevel = false; bool subBrace = false; // substitution begin with a brace ${.....} enum tLineState {LS_DEFAULT, LS_OPEN_COMMENT, LS_OPEN_DOUBLE_QUOTE, LS_COMMENT_BOX, LS_MASK_STATE = 0xf, LS_COMMAND_EXPECTED = 16, LS_BRACE_ONLY = 32 } lineState = LS_DEFAULT; bool prevSlash = false; int currentLevel = 0; bool expected = 0; bool subParen = 0; int currentLine = styler.GetLine(startPos); if (currentLine > 0) currentLine--; length += startPos - styler.LineStart(currentLine); // make sure lines overlap startPos = styler.LineStart(currentLine); WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; WordList &keywords5 = *keywordlists[4]; WordList &keywords6 = *keywordlists[5]; WordList &keywords7 = *keywordlists[6]; WordList &keywords8 = *keywordlists[7]; WordList &keywords9 = *keywordlists[8]; if (currentLine > 0) { int ls = styler.GetLineState(currentLine - 1); lineState = tLineState(ls & LS_MASK_STATE); expected = LS_COMMAND_EXPECTED == tLineState(ls & LS_COMMAND_EXPECTED); subBrace = LS_BRACE_ONLY == tLineState(ls & LS_BRACE_ONLY); currentLevel = styler.LevelAt(currentLine - 1) >> 17; commentLevel = (styler.LevelAt(currentLine - 1) >> 16) & 1; } else styler.SetLevel(0, SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG); bool visibleChars = false; int previousLevel = currentLevel; StyleContext sc(startPos, length, SCE_TCL_DEFAULT, styler); for (; ; sc.Forward()) { next: if (sc.ch=='\r' && sc.chNext == '\n') // only ignore \r on PC process on the mac continue; bool atEnd = !sc.More(); // make sure we coloured the last word if (lineState != LS_DEFAULT) { sc.SetState(SCE_TCL_DEFAULT); if (lineState == LS_OPEN_COMMENT) sc.SetState(SCE_TCL_COMMENTLINE); else if (lineState == LS_OPEN_DOUBLE_QUOTE) sc.SetState(SCE_TCL_IN_QUOTE); else if (lineState == LS_COMMENT_BOX && (sc.ch == '#' || (sc.ch == ' ' && sc.chNext=='#'))) sc.SetState(SCE_TCL_COMMENT_BOX); lineState = LS_DEFAULT; } if (subBrace) { // ${ overrides every thing even \ except } if (sc.ch == '}') { subBrace = false; sc.SetState(SCE_TCL_OPERATOR); sc.ForwardSetState(SCE_TCL_DEFAULT); goto next; } else sc.SetState(SCE_TCL_SUB_BRACE); if (!sc.atLineEnd) continue; } else if (sc.state == SCE_TCL_DEFAULT || sc.state ==SCE_TCL_OPERATOR) { expected &= isspacechar(static_cast(sc.ch)) || IsAWordStart(sc.ch) || sc.ch =='#'; } else if (sc.state == SCE_TCL_SUBSTITUTION) { switch(sc.ch) { case '(': subParen=true; sc.SetState(SCE_TCL_OPERATOR); sc.ForwardSetState(SCE_TCL_SUBSTITUTION); continue; case ')': sc.SetState(SCE_TCL_OPERATOR); subParen=false; continue; case '$': continue; case ',': sc.SetState(SCE_TCL_OPERATOR); if (subParen) sc.ForwardSetState(SCE_TCL_SUBSTITUTION); continue; default : // maybe spaces should be allowed ??? if (!IsAWordChar(sc.ch)) { // probably the code is wrong sc.SetState(SCE_TCL_DEFAULT); subParen = 0; } break; } } else if (isComment(sc.state)) { } else if (!IsAWordChar(sc.ch)) { if ((sc.state == SCE_TCL_IDENTIFIER && expected) || sc.state == SCE_TCL_MODIFIER) { char w[100]; char *s=w; sc.GetCurrent(w, sizeof(w)); if (w[strlen(w)-1]=='\r') w[strlen(w)-1]=0; while(*s == ':') // ignore leading : like in ::set a 10 ++s; bool quote = sc.state == SCE_TCL_IN_QUOTE; if (commentLevel || expected) { if (keywords.InList(s)) { sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD3); } else if (keywords4.InList(s)) { sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD4); } else if (sc.GetRelative(-static_cast(strlen(s))-1) == '{' && keywords5.InList(s) && sc.ch == '}') { // {keyword} exactly no spaces sc.ChangeState(SCE_TCL_EXPAND); } if (keywords6.InList(s)) { sc.ChangeState(SCE_TCL_WORD5); } else if (keywords7.InList(s)) { sc.ChangeState(SCE_TCL_WORD6); } else if (keywords8.InList(s)) { sc.ChangeState(SCE_TCL_WORD7); } else if (keywords9.InList(s)) { sc.ChangeState(SCE_TCL_WORD8); } } expected = false; sc.SetState(quote ? SCE_TCL_IN_QUOTE : SCE_TCL_DEFAULT); } else if (sc.state == SCE_TCL_MODIFIER || sc.state == SCE_TCL_IDENTIFIER) { sc.SetState(SCE_TCL_DEFAULT); } } if (atEnd) break; if (sc.atLineEnd) { lineState = LS_DEFAULT; currentLine = styler.GetLine(sc.currentPos); if (foldComment && sc.state!=SCE_TCL_COMMENT && isComment(sc.state)) { if (currentLevel == 0) { ++currentLevel; commentLevel = true; } } else { if (visibleChars && commentLevel) { --currentLevel; --previousLevel; commentLevel = false; } } int flag = 0; if (!visibleChars) flag = SC_FOLDLEVELWHITEFLAG; if (currentLevel > previousLevel) flag = SC_FOLDLEVELHEADERFLAG; styler.SetLevel(currentLine, flag + previousLevel + SC_FOLDLEVELBASE + (currentLevel << 17) + (commentLevel << 16)); // Update the line state, so it can be seen by next line if (sc.state == SCE_TCL_IN_QUOTE) lineState = LS_OPEN_DOUBLE_QUOTE; else { if (prevSlash) { if (isComment(sc.state)) lineState = LS_OPEN_COMMENT; } else if (sc.state == SCE_TCL_COMMENT_BOX) lineState = LS_COMMENT_BOX; } styler.SetLineState(currentLine, (subBrace ? LS_BRACE_ONLY : 0) | (expected ? LS_COMMAND_EXPECTED : 0) | lineState); if (lineState == LS_COMMENT_BOX) sc.ForwardSetState(SCE_TCL_COMMENT_BOX); else if (lineState == LS_OPEN_DOUBLE_QUOTE) sc.ForwardSetState(SCE_TCL_IN_QUOTE); else sc.ForwardSetState(SCE_TCL_DEFAULT); prevSlash = false; previousLevel = currentLevel; goto next; } if (prevSlash) { prevSlash = false; if (sc.ch == '#' && IsANumberChar(sc.chNext)) sc.ForwardSetState(SCE_TCL_NUMBER); continue; } prevSlash = sc.ch == '\\'; if (isComment(sc.state)) continue; if (sc.atLineStart) { visibleChars = false; if (sc.state!=SCE_TCL_IN_QUOTE && !isComment(sc.state)) { sc.SetState(SCE_TCL_DEFAULT); expected = IsAWordStart(sc.ch)|| isspacechar(static_cast(sc.ch)); } } switch (sc.state) { case SCE_TCL_NUMBER: if (!IsANumberChar(sc.ch)) sc.SetState(SCE_TCL_DEFAULT); break; case SCE_TCL_IN_QUOTE: if (sc.ch == '"') { sc.ForwardSetState(SCE_TCL_DEFAULT); visibleChars = true; // necessary if a " is the first and only character on a line goto next; } else if (sc.ch == '[' || sc.ch == ']' || sc.ch == '$') { sc.SetState(SCE_TCL_OPERATOR); expected = sc.ch == '['; sc.ForwardSetState(SCE_TCL_IN_QUOTE); goto next; } continue; case SCE_TCL_OPERATOR: sc.SetState(SCE_TCL_DEFAULT); break; } if (sc.ch == '#') { if (visibleChars) { if (sc.state != SCE_TCL_IN_QUOTE && expected) sc.SetState(SCE_TCL_COMMENT); } else { sc.SetState(SCE_TCL_COMMENTLINE); if (sc.chNext == '~') sc.SetState(SCE_TCL_BLOCK_COMMENT); if (sc.atLineStart && (sc.chNext == '#' || sc.chNext == '-')) sc.SetState(SCE_TCL_COMMENT_BOX); } } if (!isspacechar(static_cast(sc.ch))) { visibleChars = true; } if (sc.ch == '\\') { prevSlash = true; continue; } // Determine if a new state should be entered. if (sc.state == SCE_TCL_DEFAULT) { if (IsAWordStart(sc.ch)) { sc.SetState(SCE_TCL_IDENTIFIER); } else if (IsADigit(sc.ch) && !IsAWordChar(sc.chPrev)) { sc.SetState(SCE_TCL_NUMBER); } else { switch (sc.ch) { case '\"': sc.SetState(SCE_TCL_IN_QUOTE); break; case '{': sc.SetState(SCE_TCL_OPERATOR); expected = true; ++currentLevel; break; case '}': sc.SetState(SCE_TCL_OPERATOR); expected = true; --currentLevel; break; case '[': expected = true; case ']': case '(': case ')': sc.SetState(SCE_TCL_OPERATOR); break; case ';': expected = true; break; case '$': subParen = 0; if (sc.chNext != '{') { sc.SetState(SCE_TCL_SUBSTITUTION); } else { sc.SetState(SCE_TCL_OPERATOR); // $ sc.Forward(); // { sc.ForwardSetState(SCE_TCL_SUB_BRACE); subBrace = true; } break; case '#': if ((isspacechar(static_cast(sc.chPrev))|| isoperator(static_cast(sc.chPrev))) && IsADigit(sc.chNext,0x10)) sc.SetState(SCE_TCL_NUMBER); break; case '-': sc.SetState(IsADigit(sc.chNext)? SCE_TCL_NUMBER: SCE_TCL_MODIFIER); break; default: if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_TCL_OPERATOR); } } } } } sc.Complete(); } static const char * const tclWordListDesc[] = { "TCL Keywords", "TK Keywords", "iTCL Keywords", "tkCommands", "expand" "user1", "user2", "user3", "user4", 0 }; // this code supports folding in the colourizer LexerModule lmTCL(SCLEX_TCL, ColouriseTCLDoc, "tcl", 0, tclWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexD.cxx0000644000175000017500000004027111763437013020522 00000000000000/** @file LexD.cxx ** Lexer for D. ** ** Copyright (c) 2006 by Waldemar Augustyn ** Converted to lexer object and added further folding features/properties by "Udo Lechner" **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /* Nested comments require keeping the value of the nesting level for every position in the document. But since scintilla always styles line by line, we only need to store one value per line. The non-negative number indicates nesting level at the end of the line. */ // Underscore, letter, digit and universal alphas from C99 Appendix D. static bool IsWordStart(int ch) { return (isascii(ch) && (isalpha(ch) || ch == '_')) || !isascii(ch); } static bool IsWord(int ch) { return (isascii(ch) && (isalnum(ch) || ch == '_')) || !isascii(ch); } static bool IsDoxygen(int ch) { if (isascii(ch) && islower(ch)) return true; if (ch == '$' || ch == '@' || ch == '\\' || ch == '&' || ch == '#' || ch == '<' || ch == '>' || ch == '{' || ch == '}' || ch == '[' || ch == ']') return true; return false; } static bool IsStringSuffix(int ch) { return ch == 'c' || ch == 'w' || ch == 'd'; } static bool IsStreamCommentStyle(int style) { return style == SCE_D_COMMENT || style == SCE_D_COMMENTDOC || style == SCE_D_COMMENTDOCKEYWORD || style == SCE_D_COMMENTDOCKEYWORDERROR; } // An individual named option for use in an OptionSet // Options used for LexerD struct OptionsD { bool fold; bool foldSyntaxBased; bool foldComment; bool foldCommentMultiline; bool foldCommentExplicit; std::string foldExplicitStart; std::string foldExplicitEnd; bool foldExplicitAnywhere; bool foldCompact; int foldAtElseInt; bool foldAtElse; OptionsD() { fold = false; foldSyntaxBased = true; foldComment = false; foldCommentMultiline = true; foldCommentExplicit = true; foldExplicitStart = ""; foldExplicitEnd = ""; foldExplicitAnywhere = false; foldCompact = true; foldAtElseInt = -1; foldAtElse = false; } }; static const char * const dWordLists[] = { "Primary keywords and identifiers", "Secondary keywords and identifiers", "Documentation comment keywords", "Type definitions and aliases", "Keywords 5", "Keywords 6", "Keywords 7", 0, }; struct OptionSetD : public OptionSet { OptionSetD() { DefineProperty("fold", &OptionsD::fold); DefineProperty("fold.d.syntax.based", &OptionsD::foldSyntaxBased, "Set this property to 0 to disable syntax based folding."); DefineProperty("fold.comment", &OptionsD::foldComment); DefineProperty("fold.d.comment.multiline", &OptionsD::foldCommentMultiline, "Set this property to 0 to disable folding multi-line comments when fold.comment=1."); DefineProperty("fold.d.comment.explicit", &OptionsD::foldCommentExplicit, "Set this property to 0 to disable folding explicit fold points when fold.comment=1."); DefineProperty("fold.d.explicit.start", &OptionsD::foldExplicitStart, "The string to use for explicit fold start points, replacing the standard //{."); DefineProperty("fold.d.explicit.end", &OptionsD::foldExplicitEnd, "The string to use for explicit fold end points, replacing the standard //}."); DefineProperty("fold.d.explicit.anywhere", &OptionsD::foldExplicitAnywhere, "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); DefineProperty("fold.compact", &OptionsD::foldCompact); DefineProperty("lexer.d.fold.at.else", &OptionsD::foldAtElseInt, "This option enables D folding on a \"} else {\" line of an if statement."); DefineProperty("fold.at.else", &OptionsD::foldAtElse); DefineWordListSets(dWordLists); } }; class LexerD : public ILexer { bool caseSensitive; WordList keywords; WordList keywords2; WordList keywords3; WordList keywords4; WordList keywords5; WordList keywords6; WordList keywords7; OptionsD options; OptionSetD osD; public: LexerD(bool caseSensitive_) : caseSensitive(caseSensitive_) { } virtual ~LexerD() { } void SCI_METHOD Release() { delete this; } int SCI_METHOD Version() const { return lvOriginal; } const char * SCI_METHOD PropertyNames() { return osD.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) { return osD.PropertyType(name); } const char * SCI_METHOD DescribeProperty(const char *name) { return osD.DescribeProperty(name); } int SCI_METHOD PropertySet(const char *key, const char *val); const char * SCI_METHOD DescribeWordListSets() { return osD.DescribeWordListSets(); } int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void * SCI_METHOD PrivateCall(int, void *) { return 0; } static ILexer *LexerFactoryD() { return new LexerD(true); } static ILexer *LexerFactoryDInsensitive() { return new LexerD(false); } }; int SCI_METHOD LexerD::PropertySet(const char *key, const char *val) { if (osD.PropertySet(&options, key, val)) { return 0; } return -1; } int SCI_METHOD LexerD::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywords; break; case 1: wordListN = &keywords2; break; case 2: wordListN = &keywords3; break; case 3: wordListN = &keywords4; break; case 4: wordListN = &keywords5; break; case 5: wordListN = &keywords6; break; case 6: wordListN = &keywords7; break; } int firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } void SCI_METHOD LexerD::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); int styleBeforeDCKeyword = SCE_D_DEFAULT; StyleContext sc(startPos, length, initStyle, styler); int curLine = styler.GetLine(startPos); int curNcLevel = curLine > 0? styler.GetLineState(curLine-1): 0; bool numFloat = false; // Float literals have '+' and '-' signs bool numHex = false; for (; sc.More(); sc.Forward()) { if (sc.atLineStart) { curLine = styler.GetLine(sc.currentPos); styler.SetLineState(curLine, curNcLevel); } // Determine if the current state should terminate. switch (sc.state) { case SCE_D_OPERATOR: sc.SetState(SCE_D_DEFAULT); break; case SCE_D_NUMBER: // We accept almost anything because of hex. and number suffixes if (isascii(sc.ch) && (isalnum(sc.ch) || sc.ch == '_')) { continue; } else if (sc.ch == '.' && sc.chNext != '.' && !numFloat) { // Don't parse 0..2 as number. numFloat=true; continue; } else if ( ( sc.ch == '-' || sc.ch == '+' ) && ( /*sign and*/ ( !numHex && ( sc.chPrev == 'e' || sc.chPrev == 'E' ) ) || /*decimal or*/ ( sc.chPrev == 'p' || sc.chPrev == 'P' ) ) ) { /*hex*/ // Parse exponent sign in float literals: 2e+10 0x2e+10 continue; } else { sc.SetState(SCE_D_DEFAULT); } break; case SCE_D_IDENTIFIER: if (!IsWord(sc.ch)) { char s[1000]; if (caseSensitive) { sc.GetCurrent(s, sizeof(s)); } else { sc.GetCurrentLowered(s, sizeof(s)); } if (keywords.InList(s)) { sc.ChangeState(SCE_D_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_D_WORD2); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_D_TYPEDEF); } else if (keywords5.InList(s)) { sc.ChangeState(SCE_D_WORD5); } else if (keywords6.InList(s)) { sc.ChangeState(SCE_D_WORD6); } else if (keywords7.InList(s)) { sc.ChangeState(SCE_D_WORD7); } sc.SetState(SCE_D_DEFAULT); } break; case SCE_D_COMMENT: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_D_DEFAULT); } break; case SCE_D_COMMENTDOC: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_D_DEFAULT); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_D_COMMENTDOC; sc.SetState(SCE_D_COMMENTDOCKEYWORD); } } break; case SCE_D_COMMENTLINE: if (sc.atLineStart) { sc.SetState(SCE_D_DEFAULT); } break; case SCE_D_COMMENTLINEDOC: if (sc.atLineStart) { sc.SetState(SCE_D_DEFAULT); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_D_COMMENTLINEDOC; sc.SetState(SCE_D_COMMENTDOCKEYWORD); } } break; case SCE_D_COMMENTDOCKEYWORD: if ((styleBeforeDCKeyword == SCE_D_COMMENTDOC) && sc.Match('*', '/')) { sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR); sc.Forward(); sc.ForwardSetState(SCE_D_DEFAULT); } else if (!IsDoxygen(sc.ch)) { char s[100]; if (caseSensitive) { sc.GetCurrent(s, sizeof(s)); } else { sc.GetCurrentLowered(s, sizeof(s)); } if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) { sc.ChangeState(SCE_D_COMMENTDOCKEYWORDERROR); } sc.SetState(styleBeforeDCKeyword); } break; case SCE_D_COMMENTNESTED: if (sc.Match('+', '/')) { if (curNcLevel > 0) curNcLevel -= 1; curLine = styler.GetLine(sc.currentPos); styler.SetLineState(curLine, curNcLevel); sc.Forward(); if (curNcLevel == 0) { sc.ForwardSetState(SCE_D_DEFAULT); } } else if (sc.Match('/','+')) { curNcLevel += 1; curLine = styler.GetLine(sc.currentPos); styler.SetLineState(curLine, curNcLevel); sc.Forward(); } break; case SCE_D_STRING: if (sc.ch == '\\') { if (sc.chNext == '"' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '"') { if(IsStringSuffix(sc.chNext)) sc.Forward(); sc.ForwardSetState(SCE_D_DEFAULT); } break; case SCE_D_CHARACTER: if (sc.atLineEnd) { sc.ChangeState(SCE_D_STRINGEOL); } else if (sc.ch == '\\') { if (sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\'') { // Char has no suffixes sc.ForwardSetState(SCE_D_DEFAULT); } break; case SCE_D_STRINGEOL: if (sc.atLineStart) { sc.SetState(SCE_D_DEFAULT); } break; case SCE_D_STRINGB: if (sc.ch == '`') { if(IsStringSuffix(sc.chNext)) sc.Forward(); sc.ForwardSetState(SCE_D_DEFAULT); } break; case SCE_D_STRINGR: if (sc.ch == '"') { if(IsStringSuffix(sc.chNext)) sc.Forward(); sc.ForwardSetState(SCE_D_DEFAULT); } break; } // Determine if a new state should be entered. if (sc.state == SCE_D_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_D_NUMBER); numFloat = sc.ch == '.'; // Remember hex literal numHex = sc.ch == '0' && ( sc.chNext == 'x' || sc.chNext == 'X' ); } else if ( (sc.ch == 'r' || sc.ch == 'x' || sc.ch == 'q') && sc.chNext == '"' ) { // Limited support for hex and delimited strings: parse as r"" sc.SetState(SCE_D_STRINGR); sc.Forward(); } else if (IsWordStart(sc.ch) || sc.ch == '$') { sc.SetState(SCE_D_IDENTIFIER); } else if (sc.Match('/','+')) { curNcLevel += 1; curLine = styler.GetLine(sc.currentPos); styler.SetLineState(curLine, curNcLevel); sc.SetState(SCE_D_COMMENTNESTED); sc.Forward(); } else if (sc.Match('/', '*')) { if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style sc.SetState(SCE_D_COMMENTDOC); } else { sc.SetState(SCE_D_COMMENT); } sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!")) // Support of Qt/Doxygen doc. style sc.SetState(SCE_D_COMMENTLINEDOC); else sc.SetState(SCE_D_COMMENTLINE); } else if (sc.ch == '"') { sc.SetState(SCE_D_STRING); } else if (sc.ch == '\'') { sc.SetState(SCE_D_CHARACTER); } else if (sc.ch == '`') { sc.SetState(SCE_D_STRINGB); } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_D_OPERATOR); if (sc.ch == '.' && sc.chNext == '.') sc.Forward(); // Range operator } } } sc.Complete(); } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". void SCI_METHOD LexerD::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { if (!options.fold) return; LexAccessor styler(pAccess); unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; bool foldAtElse = options.foldAtElseInt >= 0 ? options.foldAtElseInt != 0 : options.foldAtElse; const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelNext--; } } if (options.foldComment && options.foldCommentExplicit && ((style == SCE_D_COMMENTLINE) || options.foldExplicitAnywhere)) { if (userDefinedFoldMarkers) { if (styler.Match(i, options.foldExplicitStart.c_str())) { levelNext++; } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { levelNext--; } } else { if ((ch == '/') && (chNext == '/')) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelNext++; } else if (chNext2 == '}') { levelNext--; } } } } if (options.foldSyntaxBased && (style == SCE_D_OPERATOR)) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (ch == '}') { levelNext--; } } if (atEOL || (i == endPos-1)) { if (options.foldComment && options.foldCommentMultiline) { // Handle nested comments int nc; nc = styler.GetLineState(lineCurrent); nc -= lineCurrent>0? styler.GetLineState(lineCurrent-1): 0; levelNext += nc; } int levelUse = levelCurrent; if (options.foldSyntaxBased && foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; visibleChars = 0; } if (!IsASpace(ch)) visibleChars++; } } LexerModule lmD(SCLEX_D, LexerD::LexerFactoryD, "d", dWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexSpecman.cxx0000644000175000017500000002150111615412040021705 00000000000000// Scintilla source code edit control /** @file LexSpecman.cxx ** Lexer for Specman E language. ** Written by Avi Yegudin, based on C++ lexer by Neil Hodgson **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\''); } static inline bool IsANumberChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '\''); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '`'); } static void ColouriseSpecmanDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler, bool caseSensitive) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; // Do not leak onto next line if (initStyle == SCE_SN_STRINGEOL) initStyle = SCE_SN_CODE; int visibleChars = 0; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineStart && (sc.state == SCE_SN_STRING)) { // Prevent SCE_SN_STRINGEOL from leaking back to previous line sc.SetState(SCE_SN_STRING); } // Handle line continuation generically. if (sc.ch == '\\') { if (sc.chNext == '\n' || sc.chNext == '\r') { sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } continue; } } // Determine if the current state should terminate. if (sc.state == SCE_SN_OPERATOR) { sc.SetState(SCE_SN_CODE); } else if (sc.state == SCE_SN_NUMBER) { if (!IsANumberChar(sc.ch)) { sc.SetState(SCE_SN_CODE); } } else if (sc.state == SCE_SN_IDENTIFIER) { if (!IsAWordChar(sc.ch) || (sc.ch == '.')) { char s[100]; if (caseSensitive) { sc.GetCurrent(s, sizeof(s)); } else { sc.GetCurrentLowered(s, sizeof(s)); } if (keywords.InList(s)) { sc.ChangeState(SCE_SN_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_SN_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_SN_WORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_SN_USER); } sc.SetState(SCE_SN_CODE); } } else if (sc.state == SCE_SN_PREPROCESSOR) { if (IsASpace(sc.ch)) { sc.SetState(SCE_SN_CODE); } } else if (sc.state == SCE_SN_DEFAULT) { if (sc.Match('<', '\'')) { sc.Forward(); sc.ForwardSetState(SCE_SN_CODE); } } else if (sc.state == SCE_SN_COMMENTLINE || sc.state == SCE_SN_COMMENTLINEBANG) { if (sc.atLineEnd) { sc.SetState(SCE_SN_CODE); visibleChars = 0; } } else if (sc.state == SCE_SN_STRING) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_SN_CODE); } else if (sc.atLineEnd) { sc.ChangeState(SCE_SN_STRINGEOL); sc.ForwardSetState(SCE_SN_CODE); visibleChars = 0; } } else if (sc.state == SCE_SN_SIGNAL) { if (sc.atLineEnd) { sc.ChangeState(SCE_SN_STRINGEOL); sc.ForwardSetState(SCE_SN_CODE); visibleChars = 0; } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_SN_CODE); } } else if (sc.state == SCE_SN_REGEXTAG) { if (!IsADigit(sc.ch)) { sc.SetState(SCE_SN_CODE); } } // Determine if a new state should be entered. if (sc.state == SCE_SN_CODE) { if (sc.ch == '$' && IsADigit(sc.chNext)) { sc.SetState(SCE_SN_REGEXTAG); sc.Forward(); } else if (IsADigit(sc.ch)) { sc.SetState(SCE_SN_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_SN_IDENTIFIER); } else if (sc.Match('\'', '>')) { sc.SetState(SCE_SN_DEFAULT); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { if (sc.Match("//!")) // Nice to have a different comment style sc.SetState(SCE_SN_COMMENTLINEBANG); else sc.SetState(SCE_SN_COMMENTLINE); } else if (sc.Match('-', '-')) { if (sc.Match("--!")) // Nice to have a different comment style sc.SetState(SCE_SN_COMMENTLINEBANG); else sc.SetState(SCE_SN_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_SN_STRING); } else if (sc.ch == '\'') { sc.SetState(SCE_SN_SIGNAL); } else if (sc.ch == '#' && visibleChars == 0) { // Preprocessor commands are alone on their line sc.SetState(SCE_SN_PREPROCESSOR); // Skip whitespace between # and preprocessor word do { sc.Forward(); } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); if (sc.atLineEnd) { sc.SetState(SCE_SN_CODE); } } else if (isoperator(static_cast(sc.ch)) || sc.ch == '@') { sc.SetState(SCE_SN_OPERATOR); } } if (sc.atLineEnd) { // Reset states to begining of colourise so no surprises // if different sets of lines lexed. visibleChars = 0; } if (!IsASpace(sc.ch)) { visibleChars++; } } sc.Complete(); } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". static void FoldNoBoxSpecmanDoc(unsigned int startPos, int length, int, Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); //int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && (style == SCE_SN_COMMENTLINE)) { if (((ch == '/') && (chNext == '/')) || ((ch == '-') && (chNext == '-'))) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelNext++; } else if (chNext2 == '}') { levelNext--; } } } if (style == SCE_SN_OPERATOR) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (ch == '}') { levelNext--; } } if (atEOL) { int levelUse = levelCurrent; if (foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } } static void FoldSpecmanDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { FoldNoBoxSpecmanDoc(startPos, length, initStyle, styler); } static const char * const specmanWordLists[] = { "Primary keywords and identifiers", "Secondary keywords and identifiers", "Sequence keywords and identifiers", "User defined keywords and identifiers", "Unused", 0, }; static void ColouriseSpecmanDocSensitive(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColouriseSpecmanDoc(startPos, length, initStyle, keywordlists, styler, true); } LexerModule lmSpecman(SCLEX_SPECMAN, ColouriseSpecmanDocSensitive, "specman", FoldSpecmanDoc, specmanWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexForth.cxx0000644000175000017500000001302511615412040021403 00000000000000// Scintilla source code edit control /** @file LexForth.cxx ** Lexer for FORTH **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '?' || ch == '"' || ch == '@' || ch == '!' || ch == '[' || ch == ']' || ch == '/' || ch == '+' || ch == '-' || ch == '*' || ch == '<' || ch == '>' || ch == '=' || ch == ';' || ch == '(' || ch == ')' ); } static inline bool IsAWordStart(int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'); } static inline bool IsANumChar(int ch) { return (ch < 0x80) && (isxdigit(ch) || ch == '.' || ch == 'e' || ch == 'E' ); } static inline bool IsASpaceChar(int ch) { return (ch < 0x80) && isspace(ch); } static void ColouriseForthDoc(unsigned int startPos, int length, int initStyle, WordList *keywordLists[], Accessor &styler) { WordList &control = *keywordLists[0]; WordList &keyword = *keywordLists[1]; WordList &defword = *keywordLists[2]; WordList &preword1 = *keywordLists[3]; WordList &preword2 = *keywordLists[4]; WordList &strings = *keywordLists[5]; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Determine if the current state should terminate. if (sc.state == SCE_FORTH_COMMENT) { if (sc.atLineEnd) { sc.SetState(SCE_FORTH_DEFAULT); } }else if (sc.state == SCE_FORTH_COMMENT_ML) { if (sc.ch == ')') { sc.ForwardSetState(SCE_FORTH_DEFAULT); } }else if (sc.state == SCE_FORTH_IDENTIFIER || sc.state == SCE_FORTH_NUMBER) { // handle numbers here too, because what we thought was a number might // turn out to be a keyword e.g. 2DUP if (IsASpaceChar(sc.ch) ) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); int newState = sc.state == SCE_FORTH_NUMBER ? SCE_FORTH_NUMBER : SCE_FORTH_DEFAULT; if (control.InList(s)) { sc.ChangeState(SCE_FORTH_CONTROL); } else if (keyword.InList(s)) { sc.ChangeState(SCE_FORTH_KEYWORD); } else if (defword.InList(s)) { sc.ChangeState(SCE_FORTH_DEFWORD); } else if (preword1.InList(s)) { sc.ChangeState(SCE_FORTH_PREWORD1); } else if (preword2.InList(s)) { sc.ChangeState(SCE_FORTH_PREWORD2); } else if (strings.InList(s)) { sc.ChangeState(SCE_FORTH_STRING); newState = SCE_FORTH_STRING; } sc.SetState(newState); } if (sc.state == SCE_FORTH_NUMBER) { if (IsASpaceChar(sc.ch)) { sc.SetState(SCE_FORTH_DEFAULT); } else if (!IsANumChar(sc.ch)) { sc.ChangeState(SCE_FORTH_IDENTIFIER); } } }else if (sc.state == SCE_FORTH_STRING) { if (sc.ch == '\"') { sc.ForwardSetState(SCE_FORTH_DEFAULT); } }else if (sc.state == SCE_FORTH_LOCALE) { if (sc.ch == '}') { sc.ForwardSetState(SCE_FORTH_DEFAULT); } }else if (sc.state == SCE_FORTH_DEFWORD) { if (IsASpaceChar(sc.ch)) { sc.SetState(SCE_FORTH_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_FORTH_DEFAULT) { if (sc.ch == '\\'){ sc.SetState(SCE_FORTH_COMMENT); } else if (sc.ch == '(' && (sc.atLineStart || IsASpaceChar(sc.chPrev)) && (sc.atLineEnd || IsASpaceChar(sc.chNext))) { sc.SetState(SCE_FORTH_COMMENT_ML); } else if ( (sc.ch == '$' && (isascii(sc.chNext) && isxdigit(sc.chNext))) ) { // number starting with $ is a hex number sc.SetState(SCE_FORTH_NUMBER); while(sc.More() && isascii(sc.chNext) && isxdigit(sc.chNext)) sc.Forward(); } else if ( (sc.ch == '%' && (isascii(sc.chNext) && (sc.chNext == '0' || sc.chNext == '1'))) ) { // number starting with % is binary sc.SetState(SCE_FORTH_NUMBER); while(sc.More() && isascii(sc.chNext) && (sc.chNext == '0' || sc.chNext == '1')) sc.Forward(); } else if ( isascii(sc.ch) && (isxdigit(sc.ch) || ((sc.ch == '.' || sc.ch == '-') && isascii(sc.chNext) && isxdigit(sc.chNext)) ) ){ sc.SetState(SCE_FORTH_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_FORTH_IDENTIFIER); } else if (sc.ch == '{') { sc.SetState(SCE_FORTH_LOCALE); } else if (sc.ch == ':' && isascii(sc.chNext) && isspace(sc.chNext)) { // highlight word definitions e.g. : GCD ( n n -- n ) ..... ; // ^ ^^^ sc.SetState(SCE_FORTH_DEFWORD); while(sc.More() && isascii(sc.chNext) && isspace(sc.chNext)) sc.Forward(); } else if (sc.ch == ';' && (sc.atLineStart || IsASpaceChar(sc.chPrev)) && (sc.atLineEnd || IsASpaceChar(sc.chNext)) ) { // mark the ';' that ends a word sc.SetState(SCE_FORTH_DEFWORD); sc.ForwardSetState(SCE_FORTH_DEFAULT); } } } sc.Complete(); } static void FoldForthDoc(unsigned int, int, int, WordList *[], Accessor &) { } static const char * const forthWordLists[] = { "control keywords", "keywords", "definition words", "prewords with one argument", "prewords with two arguments", "string definition keywords", 0, }; LexerModule lmForth(SCLEX_FORTH, ColouriseForthDoc, "forth", FoldForthDoc, forthWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexCPP.cxx0000644000175000017500000011206111763437013020756 00000000000000// Scintilla source code edit control /** @file LexCPP.cxx ** Lexer for C++, C, Java, and JavaScript. ** Further folding features and configuration properties added by "Udo Lechner" **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #include "SparseState.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static bool IsSpaceEquiv(int state) { return (state <= SCE_C_COMMENTDOC) || // including SCE_C_DEFAULT, SCE_C_COMMENT, SCE_C_COMMENTLINE (state == SCE_C_COMMENTLINEDOC) || (state == SCE_C_COMMENTDOCKEYWORD) || (state == SCE_C_COMMENTDOCKEYWORDERROR); } // Preconditions: sc.currentPos points to a character after '+' or '-'. // The test for pos reaching 0 should be redundant, // and is in only for safety measures. // Limitation: this code will give the incorrect answer for code like // a = b+++/ptn/... // Putting a space between the '++' post-inc operator and the '+' binary op // fixes this, and is highly recommended for readability anyway. static bool FollowsPostfixOperator(StyleContext &sc, LexAccessor &styler) { int pos = (int) sc.currentPos; while (--pos > 0) { char ch = styler[pos]; if (ch == '+' || ch == '-') { return styler[pos - 1] == ch; } } return false; } static bool followsReturnKeyword(StyleContext &sc, LexAccessor &styler) { // Don't look at styles, so no need to flush. int pos = (int) sc.currentPos; int currentLine = styler.GetLine(pos); int lineStartPos = styler.LineStart(currentLine); char ch; while (--pos > lineStartPos) { ch = styler.SafeGetCharAt(pos); if (ch != ' ' && ch != '\t') { break; } } const char *retBack = "nruter"; const char *s = retBack; while (*s && pos >= lineStartPos && styler.SafeGetCharAt(pos) == *s) { s++; pos--; } return !*s; } static std::string GetRestOfLine(LexAccessor &styler, int start, bool allowSpace) { std::string restOfLine; int i =0; char ch = styler.SafeGetCharAt(start, '\n'); while ((ch != '\r') && (ch != '\n')) { if (allowSpace || (ch != ' ')) restOfLine += ch; i++; ch = styler.SafeGetCharAt(start + i, '\n'); } return restOfLine; } static bool IsStreamCommentStyle(int style) { return style == SCE_C_COMMENT || style == SCE_C_COMMENTDOC || style == SCE_C_COMMENTDOCKEYWORD || style == SCE_C_COMMENTDOCKEYWORDERROR; } static std::vector Tokenize(const std::string &s) { // Break into space separated tokens std::string word; std::vector tokens; for (const char *cp = s.c_str(); *cp; cp++) { if ((*cp == ' ') || (*cp == '\t')) { if (!word.empty()) { tokens.push_back(word); word = ""; } } else { word += *cp; } } if (!word.empty()) { tokens.push_back(word); } return tokens; } struct PPDefinition { int line; std::string key; std::string value; PPDefinition(int line_, const std::string &key_, const std::string &value_) : line(line_), key(key_), value(value_) { } }; class LinePPState { int state; int ifTaken; int level; bool ValidLevel() const { return level >= 0 && level < 32; } int maskLevel() const { return 1 << level; } public: LinePPState() : state(0), ifTaken(0), level(-1) { } bool IsInactive() const { return state != 0; } bool CurrentIfTaken() { return (ifTaken & maskLevel()) != 0; } void StartSection(bool on) { level++; if (ValidLevel()) { if (on) { state &= ~maskLevel(); ifTaken |= maskLevel(); } else { state |= maskLevel(); ifTaken &= ~maskLevel(); } } } void EndSection() { if (ValidLevel()) { state &= ~maskLevel(); ifTaken &= ~maskLevel(); } level--; } void InvertCurrentLevel() { if (ValidLevel()) { state ^= maskLevel(); ifTaken |= maskLevel(); } } }; // Hold the preprocessor state for each line seen. // Currently one entry per line but could become sparse with just one entry per preprocessor line. class PPStates { std::vector vlls; public: LinePPState ForLine(int line) { if ((line > 0) && (vlls.size() > static_cast(line))) { return vlls[line]; } else { return LinePPState(); } } void Add(int line, LinePPState lls) { vlls.resize(line+1); vlls[line] = lls; } }; // An individual named option for use in an OptionSet // Options used for LexerCPP struct OptionsCPP { bool stylingWithinPreprocessor; bool identifiersAllowDollars; bool trackPreprocessor; bool updatePreprocessor; bool triplequotedStrings; bool hashquotedStrings; bool fold; bool foldSyntaxBased; bool foldComment; bool foldCommentMultiline; bool foldCommentExplicit; std::string foldExplicitStart; std::string foldExplicitEnd; bool foldExplicitAnywhere; bool foldPreprocessor; bool foldCompact; bool foldAtElse; OptionsCPP() { stylingWithinPreprocessor = false; identifiersAllowDollars = true; trackPreprocessor = true; updatePreprocessor = true; triplequotedStrings = false; hashquotedStrings = false; fold = false; foldSyntaxBased = true; foldComment = false; foldCommentMultiline = true; foldCommentExplicit = true; foldExplicitStart = ""; foldExplicitEnd = ""; foldExplicitAnywhere = false; foldPreprocessor = false; foldCompact = false; foldAtElse = false; } }; static const char *const cppWordLists[] = { "Primary keywords and identifiers", "Secondary keywords and identifiers", "Documentation comment keywords", "Global classes and typedefs", "Preprocessor definitions", 0, }; struct OptionSetCPP : public OptionSet { OptionSetCPP() { DefineProperty("styling.within.preprocessor", &OptionsCPP::stylingWithinPreprocessor, "For C++ code, determines whether all preprocessor code is styled in the " "preprocessor style (0, the default) or only from the initial # to the end " "of the command word(1)."); DefineProperty("lexer.cpp.allow.dollars", &OptionsCPP::identifiersAllowDollars, "Set to 0 to disallow the '$' character in identifiers with the cpp lexer."); DefineProperty("lexer.cpp.track.preprocessor", &OptionsCPP::trackPreprocessor, "Set to 1 to interpret #if/#else/#endif to grey out code that is not active."); DefineProperty("lexer.cpp.update.preprocessor", &OptionsCPP::updatePreprocessor, "Set to 1 to update preprocessor definitions when #define found."); DefineProperty("lexer.cpp.triplequoted.strings", &OptionsCPP::triplequotedStrings, "Set to 1 to enable highlighting of triple-quoted strings."); DefineProperty("lexer.cpp.hashquoted.strings", &OptionsCPP::hashquotedStrings, "Set to 1 to enable highlighting of hash-quoted strings."); DefineProperty("fold", &OptionsCPP::fold); DefineProperty("fold.cpp.syntax.based", &OptionsCPP::foldSyntaxBased, "Set this property to 0 to disable syntax based folding."); DefineProperty("fold.comment", &OptionsCPP::foldComment, "This option enables folding multi-line comments and explicit fold points when using the C++ lexer. " "Explicit fold points allows adding extra folding by placing a //{ comment at the start and a //} " "at the end of a section that should fold."); DefineProperty("fold.cpp.comment.multiline", &OptionsCPP::foldCommentMultiline, "Set this property to 0 to disable folding multi-line comments when fold.comment=1."); DefineProperty("fold.cpp.comment.explicit", &OptionsCPP::foldCommentExplicit, "Set this property to 0 to disable folding explicit fold points when fold.comment=1."); DefineProperty("fold.cpp.explicit.start", &OptionsCPP::foldExplicitStart, "The string to use for explicit fold start points, replacing the standard //{."); DefineProperty("fold.cpp.explicit.end", &OptionsCPP::foldExplicitEnd, "The string to use for explicit fold end points, replacing the standard //}."); DefineProperty("fold.cpp.explicit.anywhere", &OptionsCPP::foldExplicitAnywhere, "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); DefineProperty("fold.preprocessor", &OptionsCPP::foldPreprocessor, "This option enables folding preprocessor directives when using the C++ lexer. " "Includes C#'s explicit #region and #endregion folding directives."); DefineProperty("fold.compact", &OptionsCPP::foldCompact); DefineProperty("fold.at.else", &OptionsCPP::foldAtElse, "This option enables C++ folding on a \"} else {\" line of an if statement."); DefineWordListSets(cppWordLists); } }; class LexerCPP : public ILexer { bool caseSensitive; CharacterSet setWord; CharacterSet setNegationOp; CharacterSet setArithmethicOp; CharacterSet setRelOp; CharacterSet setLogicalOp; PPStates vlls; std::vector ppDefineHistory; WordList keywords; WordList keywords2; WordList keywords3; WordList keywords4; WordList ppDefinitions; std::map preprocessorDefinitionsStart; OptionsCPP options; OptionSetCPP osCPP; SparseState rawStringTerminators; enum { activeFlag = 0x40 }; public: LexerCPP(bool caseSensitive_) : caseSensitive(caseSensitive_), setWord(CharacterSet::setAlphaNum, "._", 0x80, true), setNegationOp(CharacterSet::setNone, "!"), setArithmethicOp(CharacterSet::setNone, "+-/*%"), setRelOp(CharacterSet::setNone, "=!<>"), setLogicalOp(CharacterSet::setNone, "|&") { } virtual ~LexerCPP() { } void SCI_METHOD Release() { delete this; } int SCI_METHOD Version() const { return lvOriginal; } const char * SCI_METHOD PropertyNames() { return osCPP.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) { return osCPP.PropertyType(name); } const char * SCI_METHOD DescribeProperty(const char *name) { return osCPP.DescribeProperty(name); } int SCI_METHOD PropertySet(const char *key, const char *val); const char * SCI_METHOD DescribeWordListSets() { return osCPP.DescribeWordListSets(); } int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void * SCI_METHOD PrivateCall(int, void *) { return 0; } static ILexer *LexerFactoryCPP() { return new LexerCPP(true); } static ILexer *LexerFactoryCPPInsensitive() { return new LexerCPP(false); } static int MaskActive(int style) { return style & ~activeFlag; } void EvaluateTokens(std::vector &tokens); bool EvaluateExpression(const std::string &expr, const std::map &preprocessorDefinitions); }; int SCI_METHOD LexerCPP::PropertySet(const char *key, const char *val) { if (osCPP.PropertySet(&options, key, val)) { return 0; } return -1; } int SCI_METHOD LexerCPP::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywords; break; case 1: wordListN = &keywords2; break; case 2: wordListN = &keywords3; break; case 3: wordListN = &keywords4; break; case 4: wordListN = &ppDefinitions; break; } int firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; if (n == 4) { // Rebuild preprocessorDefinitions preprocessorDefinitionsStart.clear(); for (int nDefinition = 0; nDefinition < ppDefinitions.len; nDefinition++) { char *cpDefinition = ppDefinitions.words[nDefinition]; char *cpEquals = strchr(cpDefinition, '='); if (cpEquals) { std::string name(cpDefinition, cpEquals - cpDefinition); std::string val(cpEquals+1); preprocessorDefinitionsStart[name] = val; } else { std::string name(cpDefinition); std::string val("1"); preprocessorDefinitionsStart[name] = val; } } } } } return firstModification; } // Functor used to truncate history struct After { int line; After(int line_) : line(line_) {} bool operator()(PPDefinition &p) const { return p.line > line; } }; void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-"); CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-"); CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true); if (options.identifiersAllowDollars) { setWordStart.Add('$'); setWord.Add('$'); } int chPrevNonWhite = ' '; int visibleChars = 0; bool lastWordWasUUID = false; int styleBeforeDCKeyword = SCE_C_DEFAULT; bool continuationLine = false; bool isIncludePreprocessor = false; int lineCurrent = styler.GetLine(startPos); if ((MaskActive(initStyle) == SCE_C_PREPROCESSOR) || (MaskActive(initStyle) == SCE_C_COMMENTLINE) || (MaskActive(initStyle) == SCE_C_COMMENTLINEDOC)) { // Set continuationLine if last character of previous line is '\' if (lineCurrent > 0) { int chBack = styler.SafeGetCharAt(startPos-1, 0); int chBack2 = styler.SafeGetCharAt(startPos-2, 0); int lineEndChar = '!'; if (chBack2 == '\r' && chBack == '\n') { lineEndChar = styler.SafeGetCharAt(startPos-3, 0); } else if (chBack == '\n' || chBack == '\r') { lineEndChar = chBack2; } continuationLine = lineEndChar == '\\'; } } // look back to set chPrevNonWhite properly for better regex colouring if (startPos > 0) { int back = startPos; while (--back && IsSpaceEquiv(MaskActive(styler.StyleAt(back)))) ; if (MaskActive(styler.StyleAt(back)) == SCE_C_OPERATOR) { chPrevNonWhite = styler.SafeGetCharAt(back); } } StyleContext sc(startPos, length, initStyle, styler, 0x7f); LinePPState preproc = vlls.ForLine(lineCurrent); bool definitionsChanged = false; // Truncate ppDefineHistory before current line if (!options.updatePreprocessor) ppDefineHistory.clear(); std::vector::iterator itInvalid = std::find_if(ppDefineHistory.begin(), ppDefineHistory.end(), After(lineCurrent-1)); if (itInvalid != ppDefineHistory.end()) { ppDefineHistory.erase(itInvalid, ppDefineHistory.end()); definitionsChanged = true; } std::map preprocessorDefinitions = preprocessorDefinitionsStart; for (std::vector::iterator itDef = ppDefineHistory.begin(); itDef != ppDefineHistory.end(); ++itDef) { preprocessorDefinitions[itDef->key] = itDef->value; } std::string rawStringTerminator = rawStringTerminators.ValueAt(lineCurrent-1); SparseState rawSTNew(lineCurrent); int activitySet = preproc.IsInactive() ? activeFlag : 0; for (; sc.More(); sc.Forward()) { if (sc.atLineStart) { // Using MaskActive() is not needed in the following statement. // Inside inactive preprocessor declaration, state will be reset anyway at the end of this block. if ((sc.state == SCE_C_STRING) || (sc.state == SCE_C_CHARACTER)) { // Prevent SCE_C_STRINGEOL from leaking back to previous line which // ends with a line continuation by locking in the state upto this position. sc.SetState(sc.state); } // Reset states to begining of colourise so no surprises // if different sets of lines lexed. visibleChars = 0; lastWordWasUUID = false; isIncludePreprocessor = false; if (preproc.IsInactive()) { activitySet = activeFlag; sc.SetState(sc.state | activitySet); } } if (sc.atLineEnd) { lineCurrent++; vlls.Add(lineCurrent, preproc); if (rawStringTerminator != "") { rawSTNew.Set(lineCurrent-1, rawStringTerminator); } } // Handle line continuation generically. if (sc.ch == '\\') { if (sc.chNext == '\n' || sc.chNext == '\r') { lineCurrent++; vlls.Add(lineCurrent, preproc); sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } continuationLine = true; continue; } } const bool atLineEndBeforeSwitch = sc.atLineEnd; // Determine if the current state should terminate. switch (MaskActive(sc.state)) { case SCE_C_OPERATOR: sc.SetState(SCE_C_DEFAULT|activitySet); break; case SCE_C_NUMBER: // We accept almost anything because of hex. and number suffixes if (!(setWord.Contains(sc.ch) || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) { sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_IDENTIFIER: if (!setWord.Contains(sc.ch) || (sc.ch == '.')) { char s[1000]; if (caseSensitive) { sc.GetCurrent(s, sizeof(s)); } else { sc.GetCurrentLowered(s, sizeof(s)); } if (keywords.InList(s)) { lastWordWasUUID = strcmp(s, "uuid") == 0; sc.ChangeState(SCE_C_WORD|activitySet); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_C_WORD2|activitySet); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_C_GLOBALCLASS|activitySet); } const bool literalString = sc.ch == '\"'; if (literalString || sc.ch == '\'') { size_t lenS = strlen(s); const bool raw = literalString && sc.chPrev == 'R'; if (raw) s[lenS--] = '\0'; bool valid = (lenS == 0) || ((lenS == 1) && ((s[0] == 'L') || (s[0] == 'u') || (s[0] == 'U'))) || ((lenS == 2) && literalString && (s[0] == 'u') && (s[1] == '8')); if (valid) { if (literalString) sc.ChangeState((raw ? SCE_C_STRINGRAW : SCE_C_STRING)|activitySet); else sc.ChangeState(SCE_C_CHARACTER|activitySet); } } sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_PREPROCESSOR: if (sc.atLineStart && !continuationLine) { sc.SetState(SCE_C_DEFAULT|activitySet); } else if (options.stylingWithinPreprocessor) { if (IsASpace(sc.ch)) { sc.SetState(SCE_C_DEFAULT|activitySet); } } else { if (sc.Match('/', '*') || sc.Match('/', '/')) { sc.SetState(SCE_C_DEFAULT|activitySet); } } break; case SCE_C_COMMENT: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_COMMENTDOC: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_C_COMMENTDOC; sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet); } } break; case SCE_C_COMMENTLINE: if (sc.atLineStart && !continuationLine) { sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_COMMENTLINEDOC: if (sc.atLineStart && !continuationLine) { sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_C_COMMENTLINEDOC; sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet); } } break; case SCE_C_COMMENTDOCKEYWORD: if ((styleBeforeDCKeyword == SCE_C_COMMENTDOC) && sc.Match('*', '/')) { sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR); sc.Forward(); sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } else if (!setDoxygen.Contains(sc.ch)) { char s[100]; if (caseSensitive) { sc.GetCurrent(s, sizeof(s)); } else { sc.GetCurrentLowered(s, sizeof(s)); } if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) { sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR|activitySet); } sc.SetState(styleBeforeDCKeyword|activitySet); } break; case SCE_C_STRING: if (sc.atLineEnd) { sc.ChangeState(SCE_C_STRINGEOL|activitySet); } else if (isIncludePreprocessor) { if (sc.ch == '>') { sc.ForwardSetState(SCE_C_DEFAULT|activitySet); isIncludePreprocessor = false; } } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_HASHQUOTEDSTRING: if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_STRINGRAW: if (sc.Match(rawStringTerminator.c_str())) { for (size_t termPos=rawStringTerminator.size(); termPos; termPos--) sc.Forward(); sc.SetState(SCE_C_DEFAULT|activitySet); rawStringTerminator = ""; } break; case SCE_C_CHARACTER: if (sc.atLineEnd) { sc.ChangeState(SCE_C_STRINGEOL|activitySet); } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_REGEX: if (sc.atLineStart) { sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '/') { sc.Forward(); while ((sc.ch < 0x80) && islower(sc.ch)) sc.Forward(); // gobble regex flags sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.ch == '\\') { // Gobble up the quoted character if (sc.chNext == '\\' || sc.chNext == '/') { sc.Forward(); } } break; case SCE_C_STRINGEOL: if (sc.atLineStart) { sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_VERBATIM: if (sc.ch == '\"') { if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_C_DEFAULT|activitySet); } } break; case SCE_C_TRIPLEVERBATIM: if (sc.Match("\"\"\"")) { while (sc.Match('"')) { sc.Forward(); } sc.SetState(SCE_C_DEFAULT|activitySet); } break; case SCE_C_UUID: if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') { sc.SetState(SCE_C_DEFAULT|activitySet); } } if (sc.atLineEnd && !atLineEndBeforeSwitch) { // State exit processing consumed characters up to end of line. lineCurrent++; vlls.Add(lineCurrent, preproc); } // Determine if a new state should be entered. if (MaskActive(sc.state) == SCE_C_DEFAULT) { if (sc.Match('@', '\"')) { sc.SetState(SCE_C_VERBATIM|activitySet); sc.Forward(); } else if (options.triplequotedStrings && sc.Match("\"\"\"")) { sc.SetState(SCE_C_TRIPLEVERBATIM|activitySet); sc.Forward(2); } else if (options.hashquotedStrings && sc.Match('#', '\"')) { sc.SetState(SCE_C_HASHQUOTEDSTRING|activitySet); sc.Forward(); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { if (lastWordWasUUID) { sc.SetState(SCE_C_UUID|activitySet); lastWordWasUUID = false; } else { sc.SetState(SCE_C_NUMBER|activitySet); } } else if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) { if (lastWordWasUUID) { sc.SetState(SCE_C_UUID|activitySet); lastWordWasUUID = false; } else { sc.SetState(SCE_C_IDENTIFIER|activitySet); } } else if (sc.Match('/', '*')) { if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style sc.SetState(SCE_C_COMMENTDOC|activitySet); } else { sc.SetState(SCE_C_COMMENT|activitySet); } sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!")) // Support of Qt/Doxygen doc. style sc.SetState(SCE_C_COMMENTLINEDOC|activitySet); else sc.SetState(SCE_C_COMMENTLINE|activitySet); } else if (sc.ch == '/' && (setOKBeforeRE.Contains(chPrevNonWhite) || followsReturnKeyword(sc, styler)) && (!setCouldBePostOp.Contains(chPrevNonWhite) || !FollowsPostfixOperator(sc, styler))) { sc.SetState(SCE_C_REGEX|activitySet); // JavaScript's RegEx } else if (sc.ch == '\"') { if (sc.chPrev == 'R') { styler.Flush(); if (MaskActive(styler.StyleAt(sc.currentPos - 1)) == SCE_C_STRINGRAW) { sc.SetState(SCE_C_STRINGRAW|activitySet); rawStringTerminator = ")"; for (int termPos = sc.currentPos + 1;; termPos++) { char chTerminator = styler.SafeGetCharAt(termPos, '('); if (chTerminator == '(') break; rawStringTerminator += chTerminator; } rawStringTerminator += '\"'; } else { sc.SetState(SCE_C_STRING|activitySet); } } else { sc.SetState(SCE_C_STRING|activitySet); } isIncludePreprocessor = false; // ensure that '>' won't end the string } else if (isIncludePreprocessor && sc.ch == '<') { sc.SetState(SCE_C_STRING|activitySet); } else if (sc.ch == '\'') { sc.SetState(SCE_C_CHARACTER|activitySet); } else if (sc.ch == '#' && visibleChars == 0) { // Preprocessor commands are alone on their line sc.SetState(SCE_C_PREPROCESSOR|activitySet); // Skip whitespace between # and preprocessor word do { sc.Forward(); } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); if (sc.atLineEnd) { sc.SetState(SCE_C_DEFAULT|activitySet); } else if (sc.Match("include")) { isIncludePreprocessor = true; } else { if (options.trackPreprocessor) { if (sc.Match("ifdef") || sc.Match("ifndef")) { bool isIfDef = sc.Match("ifdef"); int i = isIfDef ? 5 : 6; std::string restOfLine = GetRestOfLine(styler, sc.currentPos + i + 1, false); bool foundDef = preprocessorDefinitions.find(restOfLine) != preprocessorDefinitions.end(); preproc.StartSection(isIfDef == foundDef); } else if (sc.Match("if")) { std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true); bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions); preproc.StartSection(ifGood); } else if (sc.Match("else")) { if (!preproc.CurrentIfTaken()) { preproc.InvertCurrentLevel(); activitySet = preproc.IsInactive() ? activeFlag : 0; if (!activitySet) sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); } else if (!preproc.IsInactive()) { preproc.InvertCurrentLevel(); activitySet = preproc.IsInactive() ? activeFlag : 0; if (!activitySet) sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); } } else if (sc.Match("elif")) { // Ensure only one chosen out of #if .. #elif .. #elif .. #else .. #endif if (!preproc.CurrentIfTaken()) { // Similar to #if std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true); bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions); if (ifGood) { preproc.InvertCurrentLevel(); activitySet = preproc.IsInactive() ? activeFlag : 0; if (!activitySet) sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); } } else if (!preproc.IsInactive()) { preproc.InvertCurrentLevel(); activitySet = preproc.IsInactive() ? activeFlag : 0; if (!activitySet) sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); } } else if (sc.Match("endif")) { preproc.EndSection(); activitySet = preproc.IsInactive() ? activeFlag : 0; sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); } else if (sc.Match("define")) { if (options.updatePreprocessor && !preproc.IsInactive()) { std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 6, true); if (restOfLine.find(")") == std::string::npos) { // Don't handle macros with arguments std::vector tokens = Tokenize(restOfLine); std::string key; std::string value("1"); if (tokens.size() >= 1) { key = tokens[0]; if (tokens.size() >= 2) { value = tokens[1]; } preprocessorDefinitions[key] = value; ppDefineHistory.push_back(PPDefinition(lineCurrent, key, value)); definitionsChanged = true; } } } } } } } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_C_OPERATOR|activitySet); } } if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) { chPrevNonWhite = sc.ch; visibleChars++; } continuationLine = false; } const bool rawStringsChanged = rawStringTerminators.Merge(rawSTNew, lineCurrent); if (definitionsChanged || rawStringsChanged) styler.ChangeLexerState(startPos, startPos + length); sc.Complete(); } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { if (!options.fold) return; LexAccessor styler(pAccess); unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = MaskActive(styler.StyleAt(startPos)); int style = MaskActive(initStyle); const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = MaskActive(styler.StyleAt(i + 1)); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev) && (stylePrev != SCE_C_COMMENTLINEDOC)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && (styleNext != SCE_C_COMMENTLINEDOC) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelNext--; } } if (options.foldComment && options.foldCommentExplicit && ((style == SCE_C_COMMENTLINE) || options.foldExplicitAnywhere)) { if (userDefinedFoldMarkers) { if (styler.Match(i, options.foldExplicitStart.c_str())) { levelNext++; } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { levelNext--; } } else { if ((ch == '/') && (chNext == '/')) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelNext++; } else if (chNext2 == '}') { levelNext--; } } } } if (options.foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { if (ch == '#') { unsigned int j = i + 1; while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { j++; } if (styler.Match(j, "region") || styler.Match(j, "if")) { levelNext++; } else if (styler.Match(j, "end")) { levelNext--; } } } if (options.foldSyntaxBased && (style == SCE_C_OPERATOR)) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (ch == '}') { levelNext--; } } if (!IsASpace(ch)) visibleChars++; if (atEOL || (i == endPos-1)) { int levelUse = levelCurrent; if (options.foldSyntaxBased && options.foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; if (atEOL && (i == static_cast(styler.Length()-1))) { // There is an empty line at end of file so give it same level and empty styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG); } visibleChars = 0; } } } void LexerCPP::EvaluateTokens(std::vector &tokens) { // Evaluate defined() statements to either 0 or 1 for (size_t i=0; (i+2)) tokens.erase(tokens.begin() + i + 1, tokens.begin() + i + 4); val = "1"; } tokens[i] = val; } else { i++; } } // Find bracketed subexpressions and recurse on them std::vector::iterator itBracket = std::find(tokens.begin(), tokens.end(), "("); std::vector::iterator itEndBracket = std::find(tokens.begin(), tokens.end(), ")"); while ((itBracket != tokens.end()) && (itEndBracket != tokens.end()) && (itEndBracket > itBracket)) { std::vector inBracket(itBracket + 1, itEndBracket); EvaluateTokens(inBracket); // The insertion is done before the removal because there were failures with the opposite approach tokens.insert(itBracket, inBracket.begin(), inBracket.end()); itBracket = std::find(tokens.begin(), tokens.end(), "("); itEndBracket = std::find(tokens.begin(), tokens.end(), ")"); tokens.erase(itBracket, itEndBracket + 1); itBracket = std::find(tokens.begin(), tokens.end(), "("); itEndBracket = std::find(tokens.begin(), tokens.end(), ")"); } // Evaluate logical negations for (size_t j=0; (j+1)::iterator itInsert = tokens.erase(tokens.begin() + j, tokens.begin() + j + 2); tokens.insert(itInsert, isTrue ? "1" : "0"); } else { j++; } } // Evaluate expressions in precedence order enum precedence { precArithmetic, precRelative, precLogical }; for (int prec=precArithmetic; prec <= precLogical; prec++) { // Looking at 3 tokens at a time so end at 2 before end for (size_t k=0; (k+2)") result = valA > valB; else if (tokens[k+1] == ">=") result = valA >= valB; else if (tokens[k+1] == "==") result = valA == valB; else if (tokens[k+1] == "!=") result = valA != valB; else if (tokens[k+1] == "||") result = valA || valB; else if (tokens[k+1] == "&&") result = valA && valB; char sResult[30]; sprintf(sResult, "%d", result); std::vector::iterator itInsert = tokens.erase(tokens.begin() + k, tokens.begin() + k + 3); tokens.insert(itInsert, sResult); } else { k++; } } } } bool LexerCPP::EvaluateExpression(const std::string &expr, const std::map &preprocessorDefinitions) { // Break into tokens, replacing with definitions std::string word; std::vector tokens; const char *cp = expr.c_str(); for (;;) { if (setWord.Contains(*cp)) { word += *cp; } else { std::map::const_iterator it = preprocessorDefinitions.find(word); if (it != preprocessorDefinitions.end()) { tokens.push_back(it->second); } else if (!word.empty() && ((word[0] >= '0' && word[0] <= '9') || (word == "defined"))) { tokens.push_back(word); } word = ""; if (!*cp) { break; } if ((*cp != ' ') && (*cp != '\t')) { std::string op(cp, 1); if (setRelOp.Contains(*cp)) { if (setRelOp.Contains(cp[1])) { op += cp[1]; cp++; } } else if (setLogicalOp.Contains(*cp)) { if (setLogicalOp.Contains(cp[1])) { op += cp[1]; cp++; } } tokens.push_back(op); } } cp++; } EvaluateTokens(tokens); // "0" or "" -> false else true bool isFalse = tokens.empty() || ((tokens.size() == 1) && ((tokens[0] == "") || tokens[0] == "0")); return !isFalse; } LexerModule lmCPP(SCLEX_CPP, LexerCPP::LexerFactoryCPP, "cpp", cppWordLists); LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, LexerCPP::LexerFactoryCPPInsensitive, "cppnocase", cppWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexBasic.cxx0000644000175000017500000003421011763437013021354 00000000000000// Scintilla source code edit control /** @file LexBasic.cxx ** Lexer for BlitzBasic and PureBasic. ** Converted to lexer object and added further folding features/properties by "Udo Lechner" **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. // This tries to be a unified Lexer/Folder for all the BlitzBasic/BlitzMax/PurBasic basics // and derivatives. Once they diverge enough, might want to split it into multiple // lexers for more code clearity. // // Mail me (elias users sf net) for any bugs. // Folding only works for simple things like functions or types. // You may want to have a look at my ctags lexer as well, if you additionally to coloring // and folding need to extract things like label tags in your editor. #include #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /* Bits: * 1 - whitespace * 2 - operator * 4 - identifier * 8 - decimal digit * 16 - hex digit * 32 - bin digit */ static int character_classification[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2, 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4, 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0 }; static bool IsSpace(int c) { return c < 128 && (character_classification[c] & 1); } static bool IsOperator(int c) { return c < 128 && (character_classification[c] & 2); } static bool IsIdentifier(int c) { return c < 128 && (character_classification[c] & 4); } static bool IsDigit(int c) { return c < 128 && (character_classification[c] & 8); } static bool IsHexDigit(int c) { return c < 128 && (character_classification[c] & 16); } static bool IsBinDigit(int c) { return c < 128 && (character_classification[c] & 32); } static int LowerCase(int c) { if (c >= 'A' && c <= 'Z') return 'a' + c - 'A'; return c; } static int CheckBlitzFoldPoint(char const *token, int &level) { if (!strcmp(token, "function") || !strcmp(token, "type")) { level |= SC_FOLDLEVELHEADERFLAG; return 1; } if (!strcmp(token, "end function") || !strcmp(token, "end type")) { return -1; } return 0; } static int CheckPureFoldPoint(char const *token, int &level) { if (!strcmp(token, "procedure") || !strcmp(token, "enumeration") || !strcmp(token, "interface") || !strcmp(token, "structure")) { level |= SC_FOLDLEVELHEADERFLAG; return 1; } if (!strcmp(token, "endprocedure") || !strcmp(token, "endenumeration") || !strcmp(token, "endinterface") || !strcmp(token, "endstructure")) { return -1; } return 0; } static int CheckFreeFoldPoint(char const *token, int &level) { if (!strcmp(token, "function") || !strcmp(token, "sub") || !strcmp(token, "type")) { level |= SC_FOLDLEVELHEADERFLAG; return 1; } if (!strcmp(token, "end function") || !strcmp(token, "end sub") || !strcmp(token, "end type")) { return -1; } return 0; } // An individual named option for use in an OptionSet // Options used for LexerBasic struct OptionsBasic { bool fold; bool foldSyntaxBased; bool foldCommentExplicit; std::string foldExplicitStart; std::string foldExplicitEnd; bool foldExplicitAnywhere; bool foldCompact; OptionsBasic() { fold = false; foldSyntaxBased = true; foldCommentExplicit = false; foldExplicitStart = ""; foldExplicitEnd = ""; foldExplicitAnywhere = false; foldCompact = true; } }; static const char * const blitzbasicWordListDesc[] = { "BlitzBasic Keywords", "user1", "user2", "user3", 0 }; static const char * const purebasicWordListDesc[] = { "PureBasic Keywords", "PureBasic PreProcessor Keywords", "user defined 1", "user defined 2", 0 }; static const char * const freebasicWordListDesc[] = { "FreeBasic Keywords", "FreeBasic PreProcessor Keywords", "user defined 1", "user defined 2", 0 }; struct OptionSetBasic : public OptionSet { OptionSetBasic(const char * const wordListDescriptions[]) { DefineProperty("fold", &OptionsBasic::fold); DefineProperty("fold.basic.syntax.based", &OptionsBasic::foldSyntaxBased, "Set this property to 0 to disable syntax based folding."); DefineProperty("fold.basic.comment.explicit", &OptionsBasic::foldCommentExplicit, "This option enables folding explicit fold points when using the Basic lexer. " "Explicit fold points allows adding extra folding by placing a ;{ (BB/PB) or '{ (FB) comment at the start " "and a ;} (BB/PB) or '} (FB) at the end of a section that should be folded."); DefineProperty("fold.basic.explicit.start", &OptionsBasic::foldExplicitStart, "The string to use for explicit fold start points, replacing the standard ;{ (BB/PB) or '{ (FB)."); DefineProperty("fold.basic.explicit.end", &OptionsBasic::foldExplicitEnd, "The string to use for explicit fold end points, replacing the standard ;} (BB/PB) or '} (FB)."); DefineProperty("fold.basic.explicit.anywhere", &OptionsBasic::foldExplicitAnywhere, "Set this property to 1 to enable explicit fold points anywhere, not just in line comments."); DefineProperty("fold.compact", &OptionsBasic::foldCompact); DefineWordListSets(wordListDescriptions); } }; class LexerBasic : public ILexer { char comment_char; int (*CheckFoldPoint)(char const *, int &); WordList keywordlists[4]; OptionsBasic options; OptionSetBasic osBasic; public: LexerBasic(char comment_char_, int (*CheckFoldPoint_)(char const *, int &), const char * const wordListDescriptions[]) : comment_char(comment_char_), CheckFoldPoint(CheckFoldPoint_), osBasic(wordListDescriptions) { } virtual ~LexerBasic() { } void SCI_METHOD Release() { delete this; } int SCI_METHOD Version() const { return lvOriginal; } const char * SCI_METHOD PropertyNames() { return osBasic.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) { return osBasic.PropertyType(name); } const char * SCI_METHOD DescribeProperty(const char *name) { return osBasic.DescribeProperty(name); } int SCI_METHOD PropertySet(const char *key, const char *val); const char * SCI_METHOD DescribeWordListSets() { return osBasic.DescribeWordListSets(); } int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void * SCI_METHOD PrivateCall(int, void *) { return 0; } static ILexer *LexerFactoryBlitzBasic() { return new LexerBasic(';', CheckBlitzFoldPoint, blitzbasicWordListDesc); } static ILexer *LexerFactoryPureBasic() { return new LexerBasic(';', CheckPureFoldPoint, purebasicWordListDesc); } static ILexer *LexerFactoryFreeBasic() { return new LexerBasic('\'', CheckFreeFoldPoint, freebasicWordListDesc ); } }; int SCI_METHOD LexerBasic::PropertySet(const char *key, const char *val) { if (osBasic.PropertySet(&options, key, val)) { return 0; } return -1; } int SCI_METHOD LexerBasic::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywordlists[0]; break; case 1: wordListN = &keywordlists[1]; break; case 2: wordListN = &keywordlists[2]; break; case 3: wordListN = &keywordlists[3]; break; } int firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } void SCI_METHOD LexerBasic::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); bool wasfirst = true, isfirst = true; // true if first token in a line styler.StartAt(startPos); StyleContext sc(startPos, length, initStyle, styler); // Can't use sc.More() here else we miss the last character for (; ; sc.Forward()) { if (sc.state == SCE_B_IDENTIFIER) { if (!IsIdentifier(sc.ch)) { // Labels if (wasfirst && sc.Match(':')) { sc.ChangeState(SCE_B_LABEL); sc.ForwardSetState(SCE_B_DEFAULT); } else { char s[100]; int kstates[4] = { SCE_B_KEYWORD, SCE_B_KEYWORD2, SCE_B_KEYWORD3, SCE_B_KEYWORD4, }; sc.GetCurrentLowered(s, sizeof(s)); for (int i = 0; i < 4; i++) { if (keywordlists[i].InList(s)) { sc.ChangeState(kstates[i]); } } // Types, must set them as operator else they will be // matched as number/constant if (sc.Match('.') || sc.Match('$') || sc.Match('%') || sc.Match('#')) { sc.SetState(SCE_B_OPERATOR); } else { sc.SetState(SCE_B_DEFAULT); } } } } else if (sc.state == SCE_B_OPERATOR) { if (!IsOperator(sc.ch) || sc.Match('#')) sc.SetState(SCE_B_DEFAULT); } else if (sc.state == SCE_B_LABEL) { if (!IsIdentifier(sc.ch)) sc.SetState(SCE_B_DEFAULT); } else if (sc.state == SCE_B_CONSTANT) { if (!IsIdentifier(sc.ch)) sc.SetState(SCE_B_DEFAULT); } else if (sc.state == SCE_B_NUMBER) { if (!IsDigit(sc.ch)) sc.SetState(SCE_B_DEFAULT); } else if (sc.state == SCE_B_HEXNUMBER) { if (!IsHexDigit(sc.ch)) sc.SetState(SCE_B_DEFAULT); } else if (sc.state == SCE_B_BINNUMBER) { if (!IsBinDigit(sc.ch)) sc.SetState(SCE_B_DEFAULT); } else if (sc.state == SCE_B_STRING) { if (sc.ch == '"') { sc.ForwardSetState(SCE_B_DEFAULT); } if (sc.atLineEnd) { sc.ChangeState(SCE_B_ERROR); sc.SetState(SCE_B_DEFAULT); } } else if (sc.state == SCE_B_COMMENT || sc.state == SCE_B_PREPROCESSOR) { if (sc.atLineEnd) { sc.SetState(SCE_B_DEFAULT); } } if (sc.atLineStart) isfirst = true; if (sc.state == SCE_B_DEFAULT || sc.state == SCE_B_ERROR) { if (isfirst && sc.Match('.')) { sc.SetState(SCE_B_LABEL); } else if (isfirst && sc.Match('#')) { wasfirst = isfirst; sc.SetState(SCE_B_IDENTIFIER); } else if (sc.Match(comment_char)) { // Hack to make deprecated QBASIC '$Include show // up in freebasic with SCE_B_PREPROCESSOR. if (comment_char == '\'' && sc.Match(comment_char, '$')) sc.SetState(SCE_B_PREPROCESSOR); else sc.SetState(SCE_B_COMMENT); } else if (sc.Match('"')) { sc.SetState(SCE_B_STRING); } else if (IsDigit(sc.ch)) { sc.SetState(SCE_B_NUMBER); } else if (sc.Match('$')) { sc.SetState(SCE_B_HEXNUMBER); } else if (sc.Match('%')) { sc.SetState(SCE_B_BINNUMBER); } else if (sc.Match('#')) { sc.SetState(SCE_B_CONSTANT); } else if (IsOperator(sc.ch)) { sc.SetState(SCE_B_OPERATOR); } else if (IsIdentifier(sc.ch)) { wasfirst = isfirst; sc.SetState(SCE_B_IDENTIFIER); } else if (!IsSpace(sc.ch)) { sc.SetState(SCE_B_ERROR); } } if (!IsSpace(sc.ch)) isfirst = false; if (!sc.More()) break; } sc.Complete(); } void SCI_METHOD LexerBasic::Fold(unsigned int startPos, int length, int /* initStyle */, IDocument *pAccess) { if (!options.fold) return; LexAccessor styler(pAccess); int line = styler.GetLine(startPos); int level = styler.LevelAt(line); int go = 0, done = 0; int endPos = startPos + length; char word[256]; int wordlen = 0; const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty(); int cNext = styler[startPos]; // Scan for tokens at the start of the line (they may include // whitespace, for tokens like "End Function" for (int i = startPos; i < endPos; i++) { int c = cNext; cNext = styler.SafeGetCharAt(i + 1); bool atEOL = (c == '\r' && cNext != '\n') || (c == '\n'); if (options.foldSyntaxBased && !done && !go) { if (wordlen) { // are we scanning a token already? word[wordlen] = static_cast(LowerCase(c)); if (!IsIdentifier(c)) { // done with token word[wordlen] = '\0'; go = CheckFoldPoint(word, level); if (!go) { // Treat any whitespace as single blank, for // things like "End Function". if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) { word[wordlen] = ' '; if (wordlen < 255) wordlen++; } else // done with this line done = 1; } } else if (wordlen < 255) { wordlen++; } } else { // start scanning at first non-whitespace character if (!IsSpace(c)) { if (IsIdentifier(c)) { word[0] = static_cast(LowerCase(c)); wordlen = 1; } else // done with this line done = 1; } } } if (options.foldCommentExplicit && ((styler.StyleAt(i) == SCE_B_COMMENT) || options.foldExplicitAnywhere)) { if (userDefinedFoldMarkers) { if (styler.Match(i, options.foldExplicitStart.c_str())) { level |= SC_FOLDLEVELHEADERFLAG; go = 1; } else if (styler.Match(i, options.foldExplicitEnd.c_str())) { go = -1; } } else { if (c == comment_char) { if (cNext == '{') { level |= SC_FOLDLEVELHEADERFLAG; go = 1; } else if (cNext == '}') { go = -1; } } } } if (atEOL) { // line end if (!done && wordlen == 0 && options.foldCompact) // line was only space level |= SC_FOLDLEVELWHITEFLAG; if (level != styler.LevelAt(line)) styler.SetLevel(line, level); level += go; line++; // reset state wordlen = 0; level &= ~SC_FOLDLEVELHEADERFLAG; level &= ~SC_FOLDLEVELWHITEFLAG; go = 0; done = 0; } } } LexerModule lmBlitzBasic(SCLEX_BLITZBASIC, LexerBasic::LexerFactoryBlitzBasic, "blitzbasic", blitzbasicWordListDesc); LexerModule lmPureBasic(SCLEX_PUREBASIC, LexerBasic::LexerFactoryPureBasic, "purebasic", purebasicWordListDesc); LexerModule lmFreeBasic(SCLEX_FREEBASIC, LexerBasic::LexerFactoryFreeBasic, "freebasic", freebasicWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMMIXAL.cxx0000644000175000017500000001250211710634267021324 00000000000000// Scintilla source code edit control /** @file LexMMIXAL.cxx ** Lexer for MMIX Assembler Language. ** Written by Christoph Hösler ** For information about MMIX visit http://www-cs-faculty.stanford.edu/~knuth/mmix.html **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == ':' || ch == '_'); } inline bool isMMIXALOperator(char ch) { if (isascii(ch) && isalnum(ch)) return false; if (ch == '+' || ch == '-' || ch == '|' || ch == '^' || ch == '*' || ch == '/' || ch == '%' || ch == '<' || ch == '>' || ch == '&' || ch == '~' || ch == '$' || ch == ',' || ch == '(' || ch == ')' || ch == '[' || ch == ']') return true; return false; } static void ColouriseMMIXALDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &opcodes = *keywordlists[0]; WordList &special_register = *keywordlists[1]; WordList &predef_symbols = *keywordlists[2]; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // No EOL continuation if (sc.atLineStart) { if (sc.ch == '@' && sc.chNext == 'i') { sc.SetState(SCE_MMIXAL_INCLUDE); } else { sc.SetState(SCE_MMIXAL_LEADWS); } } // Check if first non whitespace character in line is alphanumeric if (sc.state == SCE_MMIXAL_LEADWS && !isspace(sc.ch)) { // LEADWS if(!IsAWordChar(sc.ch)) { sc.SetState(SCE_MMIXAL_COMMENT); } else { if(sc.atLineStart) { sc.SetState(SCE_MMIXAL_LABEL); } else { sc.SetState(SCE_MMIXAL_OPCODE_PRE); } } } // Determine if the current state should terminate. if (sc.state == SCE_MMIXAL_OPERATOR) { // OPERATOR sc.SetState(SCE_MMIXAL_OPERANDS); } else if (sc.state == SCE_MMIXAL_NUMBER) { // NUMBER if (!isdigit(sc.ch)) { if (IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrent(s, sizeof(s)); sc.ChangeState(SCE_MMIXAL_REF); sc.SetState(SCE_MMIXAL_REF); } else { sc.SetState(SCE_MMIXAL_OPERANDS); } } } else if (sc.state == SCE_MMIXAL_LABEL) { // LABEL if (!IsAWordChar(sc.ch) ) { sc.SetState(SCE_MMIXAL_OPCODE_PRE); } } else if (sc.state == SCE_MMIXAL_REF) { // REF if (!IsAWordChar(sc.ch) ) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (*s == ':') { // ignore base prefix for match for (size_t i = 0; i != sizeof(s); ++i) { *(s+i) = *(s+i+1); } } if (special_register.InList(s)) { sc.ChangeState(SCE_MMIXAL_REGISTER); } else if (predef_symbols.InList(s)) { sc.ChangeState(SCE_MMIXAL_SYMBOL); } sc.SetState(SCE_MMIXAL_OPERANDS); } } else if (sc.state == SCE_MMIXAL_OPCODE_PRE) { // OPCODE_PRE if (!isspace(sc.ch)) { sc.SetState(SCE_MMIXAL_OPCODE); } } else if (sc.state == SCE_MMIXAL_OPCODE) { // OPCODE if (!IsAWordChar(sc.ch) ) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (opcodes.InList(s)) { sc.ChangeState(SCE_MMIXAL_OPCODE_VALID); } else { sc.ChangeState(SCE_MMIXAL_OPCODE_UNKNOWN); } sc.SetState(SCE_MMIXAL_OPCODE_POST); } } else if (sc.state == SCE_MMIXAL_STRING) { // STRING if (sc.ch == '\"') { sc.ForwardSetState(SCE_MMIXAL_OPERANDS); } else if (sc.atLineEnd) { sc.ForwardSetState(SCE_MMIXAL_OPERANDS); } } else if (sc.state == SCE_MMIXAL_CHAR) { // CHAR if (sc.ch == '\'') { sc.ForwardSetState(SCE_MMIXAL_OPERANDS); } else if (sc.atLineEnd) { sc.ForwardSetState(SCE_MMIXAL_OPERANDS); } } else if (sc.state == SCE_MMIXAL_REGISTER) { // REGISTER if (!isdigit(sc.ch)) { sc.SetState(SCE_MMIXAL_OPERANDS); } } else if (sc.state == SCE_MMIXAL_HEX) { // HEX if (!isxdigit(sc.ch)) { sc.SetState(SCE_MMIXAL_OPERANDS); } } // Determine if a new state should be entered. if (sc.state == SCE_MMIXAL_OPCODE_POST || // OPCODE_POST sc.state == SCE_MMIXAL_OPERANDS) { // OPERANDS if (sc.state == SCE_MMIXAL_OPERANDS && isspace(sc.ch)) { if (!sc.atLineEnd) { sc.SetState(SCE_MMIXAL_COMMENT); } } else if (isdigit(sc.ch)) { sc.SetState(SCE_MMIXAL_NUMBER); } else if (IsAWordChar(sc.ch) || sc.Match('@')) { sc.SetState(SCE_MMIXAL_REF); } else if (sc.Match('\"')) { sc.SetState(SCE_MMIXAL_STRING); } else if (sc.Match('\'')) { sc.SetState(SCE_MMIXAL_CHAR); } else if (sc.Match('$')) { sc.SetState(SCE_MMIXAL_REGISTER); } else if (sc.Match('#')) { sc.SetState(SCE_MMIXAL_HEX); } else if (isMMIXALOperator(static_cast(sc.ch))) { sc.SetState(SCE_MMIXAL_OPERATOR); } } } sc.Complete(); } static const char * const MMIXALWordListDesc[] = { "Operation Codes", "Special Register", "Predefined Symbols", 0 }; LexerModule lmMMIXAL(SCLEX_MMIXAL, ColouriseMMIXALDoc, "mmixal", 0, MMIXALWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexGAP.cxx0000644000175000017500000001546111615412040020736 00000000000000// Scintilla source code edit control /** @file LexGAP.cxx ** Lexer for the GAP language. (The GAP System for Computational Discrete Algebra) ** http://www.gap-system.org **/ // Copyright 2007 by Istvan Szollosi ( szteven gmail com ) // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsGAPOperator(char ch) { if (isascii(ch) && isalnum(ch)) return false; if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' || ch == ',' || ch == '!' || ch == '.' || ch == '=' || ch == '<' || ch == '>' || ch == '(' || ch == ')' || ch == ';' || ch == '[' || ch == ']' || ch == '{' || ch == '}' || ch == ':' ) return true; return false; } static void GetRange(unsigned int start, unsigned int end, Accessor &styler, char *s, unsigned int len) { unsigned int i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = static_cast(styler[start + i]); i++; } s[i] = '\0'; } static void ColouriseGAPDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords1 = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; // Do not leak onto next line if (initStyle == SCE_GAP_STRINGEOL) initStyle = SCE_GAP_DEFAULT; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Prevent SCE_GAP_STRINGEOL from leaking back to previous line if ( sc.atLineStart ) { if (sc.state == SCE_GAP_STRING) sc.SetState(SCE_GAP_STRING); if (sc.state == SCE_GAP_CHAR) sc.SetState(SCE_GAP_CHAR); } // Handle line continuation generically if (sc.ch == '\\' ) { if (sc.chNext == '\n' || sc.chNext == '\r') { sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } continue; } } // Determine if the current state should terminate switch (sc.state) { case SCE_GAP_OPERATOR : sc.SetState(SCE_GAP_DEFAULT); break; case SCE_GAP_NUMBER : if (!IsADigit(sc.ch)) { if (sc.ch == '\\') { if (!sc.atLineEnd) { if (!IsADigit(sc.chNext)) { sc.Forward(); sc.ChangeState(SCE_GAP_IDENTIFIER); } } } else if (isalpha(sc.ch) || sc.ch == '_') { sc.ChangeState(SCE_GAP_IDENTIFIER); } else sc.SetState(SCE_GAP_DEFAULT); } break; case SCE_GAP_IDENTIFIER : if (!(iswordstart(static_cast(sc.ch)) || sc.ch == '$')) { if (sc.ch == '\\') sc.Forward(); else { char s[1000]; sc.GetCurrent(s, sizeof(s)); if (keywords1.InList(s)) { sc.ChangeState(SCE_GAP_KEYWORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_GAP_KEYWORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_GAP_KEYWORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_GAP_KEYWORD4); } sc.SetState(SCE_GAP_DEFAULT); } } break; case SCE_GAP_COMMENT : if (sc.atLineEnd) { sc.SetState(SCE_GAP_DEFAULT); } break; case SCE_GAP_STRING: if (sc.atLineEnd) { sc.ChangeState(SCE_GAP_STRINGEOL); } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_GAP_DEFAULT); } break; case SCE_GAP_CHAR: if (sc.atLineEnd) { sc.ChangeState(SCE_GAP_STRINGEOL); } else if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_GAP_DEFAULT); } break; case SCE_GAP_STRINGEOL: if (sc.atLineStart) { sc.SetState(SCE_GAP_DEFAULT); } break; } // Determine if a new state should be entered if (sc.state == SCE_GAP_DEFAULT) { if (IsGAPOperator(static_cast(sc.ch))) { sc.SetState(SCE_GAP_OPERATOR); } else if (IsADigit(sc.ch)) { sc.SetState(SCE_GAP_NUMBER); } else if (isalpha(sc.ch) || sc.ch == '_' || sc.ch == '\\' || sc.ch == '$' || sc.ch == '~') { sc.SetState(SCE_GAP_IDENTIFIER); if (sc.ch == '\\') sc.Forward(); } else if (sc.ch == '#') { sc.SetState(SCE_GAP_COMMENT); } else if (sc.ch == '\"') { sc.SetState(SCE_GAP_STRING); } else if (sc.ch == '\'') { sc.SetState(SCE_GAP_CHAR); } } } sc.Complete(); } static int ClassifyFoldPointGAP(const char* s) { int level = 0; if (strcmp(s, "function") == 0 || strcmp(s, "do") == 0 || strcmp(s, "if") == 0 || strcmp(s, "repeat") == 0 ) { level = 1; } else if (strcmp(s, "end") == 0 || strcmp(s, "od") == 0 || strcmp(s, "fi") == 0 || strcmp(s, "until") == 0 ) { level = -1; } return level; } static void FoldGAPDoc( unsigned int startPos, int length, int initStyle, WordList** , Accessor &styler) { unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; int lastStart = 0; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (stylePrev != SCE_GAP_KEYWORD && style == SCE_GAP_KEYWORD) { // Store last word start point. lastStart = i; } if (stylePrev == SCE_GAP_KEYWORD) { if(iswordchar(ch) && !iswordchar(chNext)) { char s[100]; GetRange(lastStart, i, styler, s, sizeof(s)); levelCurrent += ClassifyFoldPointGAP(s); } } if (atEOL) { int lev = levelPrev; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const GAPWordListDesc[] = { "Keywords 1", "Keywords 2", "Keywords 3 (unused)", "Keywords 4 (unused)", 0 }; LexerModule lmGAP( SCLEX_GAP, ColouriseGAPDoc, "gap", FoldGAPDoc, GAPWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexAPDL.cxx0000644000175000017500000001675511615412040021056 00000000000000// Scintilla source code edit control /** @file LexAPDL.cxx ** Lexer for APDL. Based on the lexer for Assembler by The Black Horus. ** By Hadar Raz. **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80 && (isalnum(ch) || ch == '_')); } static inline bool IsAnOperator(char ch) { // '.' left out as it is used to make up numbers if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || ch == '(' || ch == ')' || ch == '=' || ch == '^' || ch == '[' || ch == ']' || ch == '<' || ch == '&' || ch == '>' || ch == ',' || ch == '|' || ch == '~' || ch == '$' || ch == ':' || ch == '%') return true; return false; } static void ColouriseAPDLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { int stringStart = ' '; WordList &processors = *keywordlists[0]; WordList &commands = *keywordlists[1]; WordList &slashcommands = *keywordlists[2]; WordList &starcommands = *keywordlists[3]; WordList &arguments = *keywordlists[4]; WordList &functions = *keywordlists[5]; // Do not leak onto next line initStyle = SCE_APDL_DEFAULT; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Determine if the current state should terminate. if (sc.state == SCE_APDL_NUMBER) { if (!(IsADigit(sc.ch) || sc.ch == '.' || (sc.ch == 'e' || sc.ch == 'E') || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) { sc.SetState(SCE_APDL_DEFAULT); } } else if (sc.state == SCE_APDL_COMMENT) { if (sc.atLineEnd) { sc.SetState(SCE_APDL_DEFAULT); } } else if (sc.state == SCE_APDL_COMMENTBLOCK) { if (sc.atLineEnd) { if (sc.ch == '\r') { sc.Forward(); } sc.ForwardSetState(SCE_APDL_DEFAULT); } } else if (sc.state == SCE_APDL_STRING) { if (sc.atLineEnd) { sc.SetState(SCE_APDL_DEFAULT); } else if ((sc.ch == '\'' && stringStart == '\'') || (sc.ch == '\"' && stringStart == '\"')) { sc.ForwardSetState(SCE_APDL_DEFAULT); } } else if (sc.state == SCE_APDL_WORD) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (processors.InList(s)) { sc.ChangeState(SCE_APDL_PROCESSOR); } else if (slashcommands.InList(s)) { sc.ChangeState(SCE_APDL_SLASHCOMMAND); } else if (starcommands.InList(s)) { sc.ChangeState(SCE_APDL_STARCOMMAND); } else if (commands.InList(s)) { sc.ChangeState(SCE_APDL_COMMAND); } else if (arguments.InList(s)) { sc.ChangeState(SCE_APDL_ARGUMENT); } else if (functions.InList(s)) { sc.ChangeState(SCE_APDL_FUNCTION); } sc.SetState(SCE_APDL_DEFAULT); } } else if (sc.state == SCE_APDL_OPERATOR) { if (!IsAnOperator(static_cast(sc.ch))) { sc.SetState(SCE_APDL_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_APDL_DEFAULT) { if (sc.ch == '!' && sc.chNext == '!') { sc.SetState(SCE_APDL_COMMENTBLOCK); } else if (sc.ch == '!') { sc.SetState(SCE_APDL_COMMENT); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_APDL_NUMBER); } else if (sc.ch == '\'' || sc.ch == '\"') { sc.SetState(SCE_APDL_STRING); stringStart = sc.ch; } else if (IsAWordChar(sc.ch) || ((sc.ch == '*' || sc.ch == '/') && !isgraph(sc.chPrev))) { sc.SetState(SCE_APDL_WORD); } else if (IsAnOperator(static_cast(sc.ch))) { sc.SetState(SCE_APDL_OPERATOR); } } } sc.Complete(); } //------------------------------------------------------------------------------ // 06-27-07 Sergio Lucato // - Included code folding for Ansys APDL lexer // - Copyied from LexBasic.cxx and modified for APDL //------------------------------------------------------------------------------ /* Bits: * 1 - whitespace * 2 - operator * 4 - identifier * 8 - decimal digit * 16 - hex digit * 32 - bin digit */ static int character_classification[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 10, 6, 60, 60, 28, 28, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 4, 2, 20, 20, 20, 20, 20, 20, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0 }; static bool IsSpace(int c) { return c < 128 && (character_classification[c] & 1); } static bool IsIdentifier(int c) { return c < 128 && (character_classification[c] & 4); } static int LowerCase(int c) { if (c >= 'A' && c <= 'Z') return 'a' + c - 'A'; return c; } static int CheckAPDLFoldPoint(char const *token, int &level) { if (!strcmp(token, "*if") || !strcmp(token, "*do") || !strcmp(token, "*dowhile") ) { level |= SC_FOLDLEVELHEADERFLAG; return 1; } if (!strcmp(token, "*endif") || !strcmp(token, "*enddo") ) { return -1; } return 0; } static void FoldAPDLDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { int line = styler.GetLine(startPos); int level = styler.LevelAt(line); int go = 0, done = 0; int endPos = startPos + length; char word[256]; int wordlen = 0; int i; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; // Scan for tokens at the start of the line (they may include // whitespace, for tokens like "End Function" for (i = startPos; i < endPos; i++) { int c = styler.SafeGetCharAt(i); if (!done && !go) { if (wordlen) { // are we scanning a token already? word[wordlen] = static_cast(LowerCase(c)); if (!IsIdentifier(c)) { // done with token word[wordlen] = '\0'; go = CheckAPDLFoldPoint(word, level); if (!go) { // Treat any whitespace as single blank, for // things like "End Function". if (IsSpace(c) && IsIdentifier(word[wordlen - 1])) { word[wordlen] = ' '; if (wordlen < 255) wordlen++; } else // done with this line done = 1; } } else if (wordlen < 255) { wordlen++; } } else { // start scanning at first non-whitespace character if (!IsSpace(c)) { if (IsIdentifier(c)) { word[0] = static_cast(LowerCase(c)); wordlen = 1; } else // done with this line done = 1; } } } if (c == '\n') { // line end if (!done && wordlen == 0 && foldCompact) // line was only space level |= SC_FOLDLEVELWHITEFLAG; if (level != styler.LevelAt(line)) styler.SetLevel(line, level); level += go; line++; // reset state wordlen = 0; level &= ~SC_FOLDLEVELHEADERFLAG; level &= ~SC_FOLDLEVELWHITEFLAG; go = 0; done = 0; } } } static const char * const apdlWordListDesc[] = { "processors", "commands", "slashommands", "starcommands", "arguments", "functions", 0 }; LexerModule lmAPDL(SCLEX_APDL, ColouriseAPDLDoc, "apdl", FoldAPDLDoc, apdlWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexErlang.cxx0000644000175000017500000004000611615412040021530 00000000000000// Scintilla source code edit control // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. /** @file LexErlang.cxx ** Lexer for Erlang. ** Enhanced by Etienne 'Lenain' Girondel (lenaing@gmail.com) ** Originally wrote by Peter-Henry Mander, ** based on Matlab lexer by José Fonseca. **/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static int is_radix(int radix, int ch) { int digit; if (36 < radix || 2 > radix) return 0; if (isdigit(ch)) { digit = ch - '0'; } else if (isalnum(ch)) { digit = toupper(ch) - 'A' + 10; } else { return 0; } return (digit < radix); } typedef enum { STATE_NULL, COMMENT, COMMENT_FUNCTION, COMMENT_MODULE, COMMENT_DOC, COMMENT_DOC_MACRO, ATOM_UNQUOTED, ATOM_QUOTED, NODE_NAME_UNQUOTED, NODE_NAME_QUOTED, MACRO_START, MACRO_UNQUOTED, MACRO_QUOTED, RECORD_START, RECORD_UNQUOTED, RECORD_QUOTED, NUMERAL_START, NUMERAL_BASE_VALUE, NUMERAL_FLOAT, NUMERAL_EXPONENT, PREPROCESSOR } atom_parse_state_t; static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (ch != ' ') && (isalnum(ch) || ch == '_'); } static void ColouriseErlangDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { StyleContext sc(startPos, length, initStyle, styler); WordList &reservedWords = *keywordlists[0]; WordList &erlangBIFs = *keywordlists[1]; WordList &erlangPreproc = *keywordlists[2]; WordList &erlangModulesAtt = *keywordlists[3]; WordList &erlangDoc = *keywordlists[4]; WordList &erlangDocMacro = *keywordlists[5]; int radix_digits = 0; int exponent_digits = 0; atom_parse_state_t parse_state = STATE_NULL; atom_parse_state_t old_parse_state = STATE_NULL; bool to_late_to_comment = false; char cur[100]; int old_style = SCE_ERLANG_DEFAULT; styler.StartAt(startPos); for (; sc.More(); sc.Forward()) { int style = SCE_ERLANG_DEFAULT; if (STATE_NULL != parse_state) { switch (parse_state) { case STATE_NULL : sc.SetState(SCE_ERLANG_DEFAULT); break; /* COMMENTS ------------------------------------------------------*/ case COMMENT : { if (sc.ch != '%') { to_late_to_comment = true; } else if (!to_late_to_comment && sc.ch == '%') { // Switch to comment level 2 (Function) sc.ChangeState(SCE_ERLANG_COMMENT_FUNCTION); old_style = SCE_ERLANG_COMMENT_FUNCTION; parse_state = COMMENT_FUNCTION; sc.Forward(); } } // V--- Falling through! case COMMENT_FUNCTION : { if (sc.ch != '%') { to_late_to_comment = true; } else if (!to_late_to_comment && sc.ch == '%') { // Switch to comment level 3 (Module) sc.ChangeState(SCE_ERLANG_COMMENT_MODULE); old_style = SCE_ERLANG_COMMENT_MODULE; parse_state = COMMENT_MODULE; sc.Forward(); } } // V--- Falling through! case COMMENT_MODULE : { if (parse_state != COMMENT) { // Search for comment documentation if (sc.chNext == '@') { old_parse_state = parse_state; parse_state = ('{' == sc.ch) ? COMMENT_DOC_MACRO : COMMENT_DOC; sc.ForwardSetState(sc.state); } } // All comments types fall here. if (sc.atLineEnd) { to_late_to_comment = false; sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; case COMMENT_DOC : // V--- Falling through! case COMMENT_DOC_MACRO : { if (!isalnum(sc.ch)) { // Try to match documentation comment sc.GetCurrent(cur, sizeof(cur)); if (parse_state == COMMENT_DOC_MACRO && erlangDocMacro.InList(cur)) { sc.ChangeState(SCE_ERLANG_COMMENT_DOC_MACRO); while (sc.ch != '}' && !sc.atLineEnd) sc.Forward(); } else if (erlangDoc.InList(cur)) { sc.ChangeState(SCE_ERLANG_COMMENT_DOC); } else { sc.ChangeState(old_style); } // Switch back to old state sc.SetState(old_style); parse_state = old_parse_state; } if (sc.atLineEnd) { to_late_to_comment = false; sc.ChangeState(old_style); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* -------------------------------------------------------------- */ /* Atoms ---------------------------------------------------------*/ case ATOM_UNQUOTED : { if ('@' == sc.ch){ parse_state = NODE_NAME_UNQUOTED; } else if (sc.ch == ':') { // Searching for module name if (sc.chNext == ' ') { // error sc.ChangeState(SCE_ERLANG_UNKNOWN); parse_state = STATE_NULL; } else { sc.Forward(); if (isalnum(sc.ch)) { sc.GetCurrent(cur, sizeof(cur)); sc.ChangeState(SCE_ERLANG_MODULES); sc.SetState(SCE_ERLANG_MODULES); } } } else if (!IsAWordChar(sc.ch)) { sc.GetCurrent(cur, sizeof(cur)); if (reservedWords.InList(cur)) { style = SCE_ERLANG_KEYWORD; } else if (erlangBIFs.InList(cur) && strcmp(cur,"erlang:")){ style = SCE_ERLANG_BIFS; } else if (sc.ch == '(' || '/' == sc.ch){ style = SCE_ERLANG_FUNCTION_NAME; } else { style = SCE_ERLANG_ATOM; } sc.ChangeState(style); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; case ATOM_QUOTED : { if ( '@' == sc.ch ){ parse_state = NODE_NAME_QUOTED; } else if ('\'' == sc.ch && '\\' != sc.chPrev) { sc.ChangeState(SCE_ERLANG_ATOM); sc.ForwardSetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* -------------------------------------------------------------- */ /* Node names ----------------------------------------------------*/ case NODE_NAME_UNQUOTED : { if ('@' == sc.ch) { sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } else if (!IsAWordChar(sc.ch)) { sc.ChangeState(SCE_ERLANG_NODE_NAME); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; case NODE_NAME_QUOTED : { if ('@' == sc.ch) { sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } else if ('\'' == sc.ch && '\\' != sc.chPrev) { sc.ChangeState(SCE_ERLANG_NODE_NAME_QUOTED); sc.ForwardSetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* -------------------------------------------------------------- */ /* Records -------------------------------------------------------*/ case RECORD_START : { if ('\'' == sc.ch) { parse_state = RECORD_QUOTED; } else if (isalpha(sc.ch) && islower(sc.ch)) { parse_state = RECORD_UNQUOTED; } else { // error sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; case RECORD_UNQUOTED : { if (!IsAWordChar(sc.ch)) { sc.ChangeState(SCE_ERLANG_RECORD); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; case RECORD_QUOTED : { if ('\'' == sc.ch && '\\' != sc.chPrev) { sc.ChangeState(SCE_ERLANG_RECORD_QUOTED); sc.ForwardSetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* -------------------------------------------------------------- */ /* Macros --------------------------------------------------------*/ case MACRO_START : { if ('\'' == sc.ch) { parse_state = MACRO_QUOTED; } else if (isalpha(sc.ch)) { parse_state = MACRO_UNQUOTED; } else { // error sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; case MACRO_UNQUOTED : { if (!IsAWordChar(sc.ch)) { sc.ChangeState(SCE_ERLANG_MACRO); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; case MACRO_QUOTED : { if ('\'' == sc.ch && '\\' != sc.chPrev) { sc.ChangeState(SCE_ERLANG_MACRO_QUOTED); sc.ForwardSetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* -------------------------------------------------------------- */ /* Numerics ------------------------------------------------------*/ /* Simple integer */ case NUMERAL_START : { if (isdigit(sc.ch)) { radix_digits *= 10; radix_digits += sc.ch - '0'; // Assuming ASCII here! } else if ('#' == sc.ch) { if (2 > radix_digits || 36 < radix_digits) { sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } else { parse_state = NUMERAL_BASE_VALUE; } } else if ('.' == sc.ch && isdigit(sc.chNext)) { radix_digits = 0; parse_state = NUMERAL_FLOAT; } else if ('e' == sc.ch || 'E' == sc.ch) { exponent_digits = 0; parse_state = NUMERAL_EXPONENT; } else { radix_digits = 0; sc.ChangeState(SCE_ERLANG_NUMBER); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* Integer in other base than 10 (x#yyy) */ case NUMERAL_BASE_VALUE : { if (!is_radix(radix_digits,sc.ch)) { radix_digits = 0; if (!isalnum(sc.ch)) sc.ChangeState(SCE_ERLANG_NUMBER); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* Float (x.yyy) */ case NUMERAL_FLOAT : { if ('e' == sc.ch || 'E' == sc.ch) { exponent_digits = 0; parse_state = NUMERAL_EXPONENT; } else if (!isdigit(sc.ch)) { sc.ChangeState(SCE_ERLANG_NUMBER); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; /* Exponent, either integer or float (xEyy, x.yyEzzz) */ case NUMERAL_EXPONENT : { if (('-' == sc.ch || '+' == sc.ch) && (isdigit(sc.chNext))) { sc.Forward(); } else if (!isdigit(sc.ch)) { if (0 < exponent_digits) sc.ChangeState(SCE_ERLANG_NUMBER); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } else { ++exponent_digits; } } break; /* -------------------------------------------------------------- */ /* Preprocessor --------------------------------------------------*/ case PREPROCESSOR : { if (!IsAWordChar(sc.ch)) { sc.GetCurrent(cur, sizeof(cur)); if (erlangPreproc.InList(cur)) { style = SCE_ERLANG_PREPROC; } else if (erlangModulesAtt.InList(cur)) { style = SCE_ERLANG_MODULES_ATT; } sc.ChangeState(style); sc.SetState(SCE_ERLANG_DEFAULT); parse_state = STATE_NULL; } } break; } } /* End of : STATE_NULL != parse_state */ else { switch (sc.state) { case SCE_ERLANG_VARIABLE : { if (!IsAWordChar(sc.ch)) sc.SetState(SCE_ERLANG_DEFAULT); } break; case SCE_ERLANG_STRING : { if (sc.ch == '\"' && sc.chPrev != '\\') sc.ForwardSetState(SCE_ERLANG_DEFAULT); } break; case SCE_ERLANG_COMMENT : { if (sc.atLineEnd) sc.SetState(SCE_ERLANG_DEFAULT); } break; case SCE_ERLANG_CHARACTER : { if (sc.chPrev == '\\') { sc.ForwardSetState(SCE_ERLANG_DEFAULT); } else if (sc.ch != '\\') { sc.ForwardSetState(SCE_ERLANG_DEFAULT); } } break; case SCE_ERLANG_OPERATOR : { if (sc.chPrev == '.') { if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' || sc.ch == '^') { sc.ForwardSetState(SCE_ERLANG_DEFAULT); } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_ERLANG_DEFAULT); } else { sc.SetState(SCE_ERLANG_DEFAULT); } } else { sc.SetState(SCE_ERLANG_DEFAULT); } } break; } } if (sc.state == SCE_ERLANG_DEFAULT) { bool no_new_state = false; switch (sc.ch) { case '\"' : sc.SetState(SCE_ERLANG_STRING); break; case '$' : sc.SetState(SCE_ERLANG_CHARACTER); break; case '%' : { parse_state = COMMENT; sc.SetState(SCE_ERLANG_COMMENT); } break; case '#' : { parse_state = RECORD_START; sc.SetState(SCE_ERLANG_UNKNOWN); } break; case '?' : { parse_state = MACRO_START; sc.SetState(SCE_ERLANG_UNKNOWN); } break; case '\'' : { parse_state = ATOM_QUOTED; sc.SetState(SCE_ERLANG_UNKNOWN); } break; case '+' : case '-' : { if (IsADigit(sc.chNext)) { parse_state = NUMERAL_START; radix_digits = 0; sc.SetState(SCE_ERLANG_UNKNOWN); } else if (sc.ch != '+') { parse_state = PREPROCESSOR; sc.SetState(SCE_ERLANG_UNKNOWN); } } break; default : no_new_state = true; } if (no_new_state) { if (isdigit(sc.ch)) { parse_state = NUMERAL_START; radix_digits = sc.ch - '0'; sc.SetState(SCE_ERLANG_UNKNOWN); } else if (isupper(sc.ch) || '_' == sc.ch) { sc.SetState(SCE_ERLANG_VARIABLE); } else if (isalpha(sc.ch)) { parse_state = ATOM_UNQUOTED; sc.SetState(SCE_ERLANG_UNKNOWN); } else if (isoperator(static_cast(sc.ch)) || sc.ch == '\\') { sc.SetState(SCE_ERLANG_OPERATOR); } } } } sc.Complete(); } static int ClassifyErlangFoldPoint( Accessor &styler, int styleNext, int keyword_start ) { int lev = 0; if (styler.Match(keyword_start,"case") || ( styler.Match(keyword_start,"fun") && (SCE_ERLANG_FUNCTION_NAME != styleNext) ) || styler.Match(keyword_start,"if") || styler.Match(keyword_start,"query") || styler.Match(keyword_start,"receive") ) { ++lev; } else if (styler.Match(keyword_start,"end")) { --lev; } return lev; } static void FoldErlangDoc( unsigned int startPos, int length, int initStyle, WordList** /*keywordlists*/, Accessor &styler ) { unsigned int endPos = startPos + length; int currentLine = styler.GetLine(startPos); int lev; int previousLevel = styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK; int currentLevel = previousLevel; int styleNext = styler.StyleAt(startPos); int style = initStyle; int stylePrev; int keyword_start = 0; char ch; char chNext = styler.SafeGetCharAt(startPos); bool atEOL; for (unsigned int i = startPos; i < endPos; i++) { ch = chNext; chNext = styler.SafeGetCharAt(i + 1); // Get styles stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); atEOL = ((ch == '\r') && (chNext != '\n')) || (ch == '\n'); if (stylePrev != SCE_ERLANG_KEYWORD && style == SCE_ERLANG_KEYWORD) { keyword_start = i; } // Fold on keywords if (stylePrev == SCE_ERLANG_KEYWORD && style != SCE_ERLANG_KEYWORD && style != SCE_ERLANG_ATOM ) { currentLevel += ClassifyErlangFoldPoint(styler, styleNext, keyword_start); } // Fold on comments if (style == SCE_ERLANG_COMMENT || style == SCE_ERLANG_COMMENT_MODULE || style == SCE_ERLANG_COMMENT_FUNCTION) { if (ch == '%' && chNext == '{') { currentLevel++; } else if (ch == '%' && chNext == '}') { currentLevel--; } } // Fold on braces if (style == SCE_ERLANG_OPERATOR) { if (ch == '{' || ch == '(' || ch == '[') { currentLevel++; } else if (ch == '}' || ch == ')' || ch == ']') { currentLevel--; } } if (atEOL) { lev = previousLevel; if (currentLevel > previousLevel) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(currentLine)) styler.SetLevel(currentLine, lev); currentLine++; previousLevel = currentLevel; } } // Fill in the real level of the next line, keeping the current flags as they will be filled in later styler.SetLevel(currentLine, previousLevel | (styler.LevelAt(currentLine) & ~SC_FOLDLEVELNUMBERMASK)); } static const char * const erlangWordListDesc[] = { "Erlang Reserved words", "Erlang BIFs", "Erlang Preprocessor", "Erlang Module Attributes", "Erlang Documentation", "Erlang Documentation Macro", 0 }; LexerModule lmErlang( SCLEX_ERLANG, ColouriseErlangDoc, "erlang", FoldErlangDoc, erlangWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexSML.cxx0000644000175000017500000001320611615412040020755 00000000000000// Scintilla source code edit control /** @file LexSML.cxx ** Lexer for SML. **/ // Copyright 2009 by James Moffatt and Yuzhou Xin // Modified from LexCaml.cxx by Robert Roessler Copyright 2005 // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" inline int issml(int c) {return isalnum(c) || c == '_';} inline int issmlf(int c) {return isalpha(c) || c == '_';} inline int issmld(int c) {return isdigit(c) || c == '_';} #ifdef SCI_NAMESPACE using namespace Scintilla; #endif void ColouriseSMLDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { StyleContext sc(startPos, length, initStyle, styler); int nesting = 0; if (sc.state < SCE_SML_STRING) sc.state = SCE_SML_DEFAULT; if (sc.state >= SCE_SML_COMMENT) nesting = (sc.state & 0x0f) - SCE_SML_COMMENT; int chBase = 0, chToken = 0, chLit = 0; WordList& keywords = *keywordlists[0]; WordList& keywords2 = *keywordlists[1]; WordList& keywords3 = *keywordlists[2]; const int useMagic = styler.GetPropertyInt("lexer.caml.magic", 0); while (sc.More()) { int state2 = -1; int chColor = sc.currentPos - 1; bool advance = true; switch (sc.state & 0x0f) { case SCE_SML_DEFAULT: chToken = sc.currentPos; if (issmlf(sc.ch)) state2 = SCE_SML_IDENTIFIER; else if (sc.Match('`') && issmlf(sc.chNext)) state2 = SCE_SML_TAGNAME; else if (sc.Match('#')&&isdigit(sc.chNext)) state2 = SCE_SML_LINENUM; else if (sc.Match('#','\"')){ state2 = SCE_SML_CHAR,chLit = 0; sc.Forward(); } else if (isdigit(sc.ch)) { state2 = SCE_SML_NUMBER, chBase = 10; if (sc.Match('0') && strchr("xX", sc.chNext)) chBase = 16, sc.Forward();} else if (sc.Match('\"')&&sc.chPrev!='#') state2 = SCE_SML_STRING; else if (sc.Match('(', '*')){ state2 = SCE_SML_COMMENT, sc.ch = ' ', sc.Forward();} else if (strchr("!~" "=<>@^+-*/" "()[];,:.#", sc.ch)) state2 = SCE_SML_OPERATOR; break; case SCE_SML_IDENTIFIER: if (!(issml(sc.ch) || sc.Match('\''))) { const int n = sc.currentPos - chToken; if (n < 24) { char t[24]; for (int i = -n; i < 0; i++) t[n + i] = static_cast(sc.GetRelative(i)); t[n] = '\0'; if ((n == 1 && sc.chPrev == '_') || keywords.InList(t)) sc.ChangeState(SCE_SML_KEYWORD); else if (keywords2.InList(t)) sc.ChangeState(SCE_SML_KEYWORD2); else if (keywords3.InList(t)) sc.ChangeState(SCE_SML_KEYWORD3); } state2 = SCE_SML_DEFAULT, advance = false; } break; case SCE_SML_TAGNAME: if (!(issml(sc.ch) || sc.Match('\''))) state2 = SCE_SML_DEFAULT, advance = false; break; case SCE_SML_LINENUM: if (!isdigit(sc.ch)) state2 = SCE_SML_DEFAULT, advance = false; break; case SCE_SML_OPERATOR: { const char* o = 0; if (issml(sc.ch) || isspace(sc.ch) || (o = strchr(")]};,\'\"`#", sc.ch),o) || !strchr("!$%&*+-./:<=>?@^|~", sc.ch)) { if (o && strchr(")]};,", sc.ch)) { if ((sc.Match(')') && sc.chPrev == '(') || (sc.Match(']') && sc.chPrev == '[')) sc.ChangeState(SCE_SML_KEYWORD); chColor++; } else advance = false; state2 = SCE_SML_DEFAULT; } break; } case SCE_SML_NUMBER: if (issmld(sc.ch) || IsADigit(sc.ch, chBase)) break; if ((sc.Match('l') || sc.Match('L') || sc.Match('n')) && (issmld(sc.chPrev) || IsADigit(sc.chPrev, chBase))) break; if (chBase == 10) { if (sc.Match('.') && issmld(sc.chPrev)) break; if ((sc.Match('e') || sc.Match('E')) && (issmld(sc.chPrev) || sc.chPrev == '.')) break; if ((sc.Match('+') || sc.Match('-')) && (sc.chPrev == 'e' || sc.chPrev == 'E')) break; } state2 = SCE_SML_DEFAULT, advance = false; break; case SCE_SML_CHAR: if (sc.Match('\\')) { chLit = 1; if (sc.chPrev == '\\') sc.ch = ' '; } else if ((sc.Match('\"') && sc.chPrev != '\\') || sc.atLineEnd) { state2 = SCE_SML_DEFAULT; chLit = 1; if (sc.Match('\"')) chColor++; else sc.ChangeState(SCE_SML_IDENTIFIER); } else if (chLit < 1 && sc.currentPos - chToken >= 3) sc.ChangeState(SCE_SML_IDENTIFIER), advance = false; break; case SCE_SML_STRING: if (sc.Match('\\') && sc.chPrev == '\\') sc.ch = ' '; else if (sc.Match('\"') && sc.chPrev != '\\') state2 = SCE_SML_DEFAULT, chColor++; break; case SCE_SML_COMMENT: case SCE_SML_COMMENT1: case SCE_SML_COMMENT2: case SCE_SML_COMMENT3: if (sc.Match('(', '*')) state2 = sc.state + 1, chToken = sc.currentPos, sc.ch = ' ', sc.Forward(), nesting++; else if (sc.Match(')') && sc.chPrev == '*') { if (nesting) state2 = (sc.state & 0x0f) - 1, chToken = 0, nesting--; else state2 = SCE_SML_DEFAULT; chColor++; } else if (useMagic && sc.currentPos - chToken == 4 && sc.Match('c') && sc.chPrev == 'r' && sc.GetRelative(-2) == '@') sc.state |= 0x10; break; } if (state2 >= 0) styler.ColourTo(chColor, sc.state), sc.ChangeState(state2); if (advance) sc.Forward(); } sc.Complete(); } void FoldSMLDoc( unsigned int, int, int, WordList *[], Accessor &) { } static const char * const SMLWordListDesc[] = { "Keywords", "Keywords2", "Keywords3", 0 }; LexerModule lmSML(SCLEX_SML, ColouriseSMLDoc, "SML", FoldSMLDoc, SMLWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMPT.cxx0000644000175000017500000001220511660423551020771 00000000000000// Scintilla source code edit control /** @file LexMPT.cxx ** Lexer for MPT specific files. Based on LexOthers.cxx ** LOT = the text log file created by the MPT application while running a test program ** Other MPT specific files to be added later. **/ // Copyright 2003 by Marius Gheorghe // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static int GetLotLineState(std::string &line) { if (line.length()) { // Most of the time the first non-blank character in line determines that line's type // Now finds the first non-blank character unsigned i; // Declares counter here to make it persistent after the for loop for (i = 0; i < line.length(); ++i) { if (!(isascii(line[i]) && isspace(line[i]))) break; } // Checks if it was a blank line if (i == line.length()) return SCE_LOT_DEFAULT; switch (line[i]) { case '*': // Fail measurement return SCE_LOT_FAIL; case '+': // Header case '|': // Header return SCE_LOT_HEADER; case ':': // Set test limits return SCE_LOT_SET; case '-': // Section break return SCE_LOT_BREAK; default: // Any other line // Checks for message at the end of lot file if (line.find("PASSED") != std::string::npos) { return SCE_LOT_PASS; } else if (line.find("FAILED") != std::string::npos) { return SCE_LOT_FAIL; } else if (line.find("ABORTED") != std::string::npos) { return SCE_LOT_ABORT; } else { return i ? SCE_LOT_PASS : SCE_LOT_DEFAULT; } } } else { return SCE_LOT_DEFAULT; } } static void ColourizeLotDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { styler.StartAt(startPos); styler.StartSegment(startPos); bool atLineStart = true;// Arms the 'at line start' flag char chNext = styler.SafeGetCharAt(startPos); std::string line(""); line.reserve(256); // Lot lines are less than 256 chars long most of the time. This should avoid reallocations // Styles LOT document unsigned int i; // Declared here because it's used after the for loop for (i = startPos; i < startPos + length; ++i) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); line += ch; atLineStart = false; // LOT files are only used on the Win32 platform, thus EOL == CR+LF // Searches for the end of line if (ch == '\r' && chNext == '\n') { line += chNext; // Gets the '\n' ++i; // Advances past the '\n' chNext = styler.SafeGetCharAt(i + 1); // Gets character of next line styler.ColourTo(i, GetLotLineState(line)); line = ""; atLineStart = true; // Arms flag for next line } } // Last line may not have a line ending if (!atLineStart) { styler.ColourTo(i - 1, GetLotLineState(line)); } } // Folds an MPT LOT file: the blocks that can be folded are: // sections (headed by a set line) // passes (contiguous pass results within a section) // fails (contiguous fail results within a section) static void FoldLotDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldCompact = styler.GetPropertyInt("fold.compact", 0) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); char chNext = styler.SafeGetCharAt(startPos); int style = SCE_LOT_DEFAULT; int styleNext = styler.StyleAt(startPos); int lev = SC_FOLDLEVELBASE; // Gets style of previous line if not at the beginning of the document if (startPos > 1) style = styler.StyleAt(startPos - 2); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if (ch == '\r' && chNext == '\n') { // TO DO: // Should really get the state of the previous line from the styler int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 2); switch (style) { /* case SCE_LOT_SET: lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; break; */ case SCE_LOT_FAIL: /* if (stylePrev != SCE_LOT_FAIL) lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; else lev = SC_FOLDLEVELBASE + 1; */ lev = SC_FOLDLEVELBASE; break; default: if (lineCurrent == 0 || stylePrev == SCE_LOT_FAIL) lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; else lev = SC_FOLDLEVELBASE + 1; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; break; } if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); lineCurrent++; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, lev | flagsNext); } static const char * const emptyWordListDesc[] = { 0 }; LexerModule lmLot(SCLEX_LOT, ColourizeLotDoc, "lot", FoldLotDoc, emptyWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMarkdown.cxx0000644000175000017500000003663111634611460022123 00000000000000/****************************************************************** * LexMarkdown.cxx * * A simple Markdown lexer for scintilla. * * Includes highlighting for some extra features from the * Pandoc implementation; strikeout, using '#.' as a default * ordered list item marker, and delimited code blocks. * * Limitations: * * Standard indented code blocks are not highlighted at all, * as it would conflict with other indentation schemes. Use * delimited code blocks for blanket highlighting of an * entire code block. Embedded HTML is not highlighted either. * Blanket HTML highlighting has issues, because some Markdown * implementations allow Markdown markup inside of the HTML. Also, * there is a following blank line issue that can't be ignored, * explained in the next paragraph. Embedded HTML and code * blocks would be better supported with language specific * highlighting. * * The highlighting aims to accurately reflect correct syntax, * but a few restrictions are relaxed. Delimited code blocks are * highlighted, even if the line following the code block is not blank. * Requiring a blank line after a block, breaks the highlighting * in certain cases, because of the way Scintilla ends up calling * the lexer. * * Written by Jon Strait - jstrait@moonloop.net * * The License.txt file describes the conditions under which this * software may be distributed. * *****************************************************************/ #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsNewline(const int ch) { return (ch == '\n' || ch == '\r'); } // True if can follow ch down to the end with possibly trailing whitespace static bool FollowToLineEnd(const int ch, const int state, const unsigned int endPos, StyleContext &sc) { unsigned int i = 0; while (sc.GetRelative(++i) == ch) ; // Skip over whitespace while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos) ++i; if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) { sc.Forward(i); sc.ChangeState(state); sc.SetState(SCE_MARKDOWN_LINE_BEGIN); return true; } else return false; } // Set the state on text section from current to length characters, // then set the rest until the newline to default, except for any characters matching token static void SetStateAndZoom(const int state, const int length, const int token, StyleContext &sc) { sc.SetState(state); sc.Forward(length); sc.SetState(SCE_MARKDOWN_DEFAULT); sc.Forward(); bool started = false; while (sc.More() && !IsNewline(sc.ch)) { if (sc.ch == token && !started) { sc.SetState(state); started = true; } else if (sc.ch != token) { sc.SetState(SCE_MARKDOWN_DEFAULT); started = false; } sc.Forward(); } sc.SetState(SCE_MARKDOWN_LINE_BEGIN); } // Does the previous line have more than spaces and tabs? static bool HasPrevLineContent(StyleContext &sc) { int i = 0; // Go back to the previous newline while ((--i + (int)sc.currentPos) >= 0 && !IsNewline(sc.GetRelative(i))) ; while ((--i + (int)sc.currentPos) >= 0) { if (IsNewline(sc.GetRelative(i))) break; if (!IsASpaceOrTab(sc.GetRelative(i))) return true; } return false; } static bool AtTermStart(StyleContext &sc) { return sc.currentPos == 0 || isspacechar(sc.chPrev); } static bool IsValidHrule(const unsigned int endPos, StyleContext &sc) { int c, count = 1; unsigned int i = 0; while (++i) { c = sc.GetRelative(i); if (c == sc.ch) ++count; // hit a terminating character else if (!IsASpaceOrTab(c) || sc.currentPos + i == endPos) { // Are we a valid HRULE if ((IsNewline(c) || sc.currentPos + i == endPos) && count >= 3 && !HasPrevLineContent(sc)) { sc.SetState(SCE_MARKDOWN_HRULE); sc.Forward(i); sc.SetState(SCE_MARKDOWN_LINE_BEGIN); return true; } else { sc.SetState(SCE_MARKDOWN_DEFAULT); return false; } } } return false; } static void ColorizeMarkdownDoc(unsigned int startPos, int length, int initStyle, WordList **, Accessor &styler) { unsigned int endPos = startPos + length; int precharCount = 0; // Don't advance on a new loop iteration and retry at the same position. // Useful in the corner case of having to start at the beginning file position // in the default state. bool freezeCursor = false; StyleContext sc(startPos, length, initStyle, styler); while (sc.More()) { // Skip past escaped characters if (sc.ch == '\\') { sc.Forward(); continue; } // A blockquotes resets the line semantics if (sc.state == SCE_MARKDOWN_BLOCKQUOTE) sc.SetState(SCE_MARKDOWN_LINE_BEGIN); // Conditional state-based actions if (sc.state == SCE_MARKDOWN_CODE2) { if (sc.Match("``") && sc.GetRelative(-2) != ' ') { sc.Forward(2); sc.SetState(SCE_MARKDOWN_DEFAULT); } } else if (sc.state == SCE_MARKDOWN_CODE) { if (sc.ch == '`' && sc.chPrev != ' ') sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); } /* De-activated because it gets in the way of other valid indentation * schemes, for example multiple paragraphs inside a list item. // Code block else if (sc.state == SCE_MARKDOWN_CODEBK) { bool d = true; if (IsNewline(sc.ch)) { if (sc.chNext != '\t') { for (int c = 1; c < 5; ++c) { if (sc.GetRelative(c) != ' ') d = false; } } } else if (sc.atLineStart) { if (sc.ch != '\t' ) { for (int i = 0; i < 4; ++i) { if (sc.GetRelative(i) != ' ') d = false; } } } if (!d) sc.SetState(SCE_MARKDOWN_LINE_BEGIN); } */ // Strong else if (sc.state == SCE_MARKDOWN_STRONG1) { if (sc.Match("**") && sc.chPrev != ' ') { sc.Forward(2); sc.SetState(SCE_MARKDOWN_DEFAULT); } } else if (sc.state == SCE_MARKDOWN_STRONG2) { if (sc.Match("__") && sc.chPrev != ' ') { sc.Forward(2); sc.SetState(SCE_MARKDOWN_DEFAULT); } } // Emphasis else if (sc.state == SCE_MARKDOWN_EM1) { if (sc.ch == '*' && sc.chPrev != ' ') sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); } else if (sc.state == SCE_MARKDOWN_EM2) { if (sc.ch == '_' && sc.chPrev != ' ') sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); } else if (sc.state == SCE_MARKDOWN_CODEBK) { if (sc.atLineStart && sc.Match("~~~")) { int i = 1; while (!IsNewline(sc.GetRelative(i)) && sc.currentPos + i < endPos) i++; sc.Forward(i); sc.SetState(SCE_MARKDOWN_DEFAULT); } } else if (sc.state == SCE_MARKDOWN_STRIKEOUT) { if (sc.Match("~~") && sc.chPrev != ' ') { sc.Forward(2); sc.SetState(SCE_MARKDOWN_DEFAULT); } } else if (sc.state == SCE_MARKDOWN_LINE_BEGIN) { // Header if (sc.Match("######")) SetStateAndZoom(SCE_MARKDOWN_HEADER6, 6, '#', sc); else if (sc.Match("#####")) SetStateAndZoom(SCE_MARKDOWN_HEADER5, 5, '#', sc); else if (sc.Match("####")) SetStateAndZoom(SCE_MARKDOWN_HEADER4, 4, '#', sc); else if (sc.Match("###")) SetStateAndZoom(SCE_MARKDOWN_HEADER3, 3, '#', sc); else if (sc.Match("##")) SetStateAndZoom(SCE_MARKDOWN_HEADER2, 2, '#', sc); else if (sc.Match("#")) { // Catch the special case of an unordered list if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) { precharCount = 0; sc.SetState(SCE_MARKDOWN_PRECHAR); } else SetStateAndZoom(SCE_MARKDOWN_HEADER1, 1, '#', sc); } // Code block else if (sc.Match("~~~")) { if (!HasPrevLineContent(sc)) sc.SetState(SCE_MARKDOWN_CODEBK); else sc.SetState(SCE_MARKDOWN_DEFAULT); } else if (sc.ch == '=') { if (HasPrevLineContent(sc) && FollowToLineEnd('=', SCE_MARKDOWN_HEADER1, endPos, sc)) ; else sc.SetState(SCE_MARKDOWN_DEFAULT); } else if (sc.ch == '-') { if (HasPrevLineContent(sc) && FollowToLineEnd('-', SCE_MARKDOWN_HEADER2, endPos, sc)) ; else { precharCount = 0; sc.SetState(SCE_MARKDOWN_PRECHAR); } } else if (IsNewline(sc.ch)) sc.SetState(SCE_MARKDOWN_LINE_BEGIN); else { precharCount = 0; sc.SetState(SCE_MARKDOWN_PRECHAR); } } // The header lasts until the newline else if (sc.state == SCE_MARKDOWN_HEADER1 || sc.state == SCE_MARKDOWN_HEADER2 || sc.state == SCE_MARKDOWN_HEADER3 || sc.state == SCE_MARKDOWN_HEADER4 || sc.state == SCE_MARKDOWN_HEADER5 || sc.state == SCE_MARKDOWN_HEADER6) { if (IsNewline(sc.ch)) sc.SetState(SCE_MARKDOWN_LINE_BEGIN); } // New state only within the initial whitespace if (sc.state == SCE_MARKDOWN_PRECHAR) { // Blockquote if (sc.ch == '>' && precharCount < 5) sc.SetState(SCE_MARKDOWN_BLOCKQUOTE); /* // Begin of code block else if (!HasPrevLineContent(sc) && (sc.chPrev == '\t' || precharCount >= 4)) sc.SetState(SCE_MARKDOWN_CODEBK); */ // HRule - Total of three or more hyphens, asterisks, or underscores // on a line by themselves else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '_') && IsValidHrule(endPos, sc)) ; // Unordered list else if ((sc.ch == '-' || sc.ch == '*' || sc.ch == '+') && IsASpaceOrTab(sc.chNext)) { sc.SetState(SCE_MARKDOWN_ULIST_ITEM); sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); } // Ordered list else if (IsADigit(sc.ch)) { int digitCount = 0; while (IsADigit(sc.GetRelative(++digitCount))) ; if (sc.GetRelative(digitCount) == '.' && IsASpaceOrTab(sc.GetRelative(digitCount + 1))) { sc.SetState(SCE_MARKDOWN_OLIST_ITEM); sc.Forward(digitCount + 1); sc.SetState(SCE_MARKDOWN_DEFAULT); } } // Alternate Ordered list else if (sc.ch == '#' && sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) { sc.SetState(SCE_MARKDOWN_OLIST_ITEM); sc.Forward(2); sc.SetState(SCE_MARKDOWN_DEFAULT); } else if (sc.ch != ' ' || precharCount > 2) sc.SetState(SCE_MARKDOWN_DEFAULT); else ++precharCount; } // New state anywhere in doc if (sc.state == SCE_MARKDOWN_DEFAULT) { if (sc.atLineStart && sc.ch == '#') { sc.SetState(SCE_MARKDOWN_LINE_BEGIN); freezeCursor = true; } // Links and Images if (sc.Match("![") || sc.ch == '[') { int i = 0, j = 0, k = 0; int len = endPos - sc.currentPos; while (i < len && (sc.GetRelative(++i) != ']' || sc.GetRelative(i - 1) == '\\')) ; if (sc.GetRelative(i) == ']') { j = i; if (sc.GetRelative(++i) == '(') { while (i < len && (sc.GetRelative(++i) != ')' || sc.GetRelative(i - 1) == '\\')) ; if (sc.GetRelative(i) == ')') k = i; } else if (sc.GetRelative(i) == '[' || sc.GetRelative(++i) == '[') { while (i < len && (sc.GetRelative(++i) != ']' || sc.GetRelative(i - 1) == '\\')) ; if (sc.GetRelative(i) == ']') k = i; } } // At least a link text if (j) { sc.SetState(SCE_MARKDOWN_LINK); sc.Forward(j); // Also has a URL or reference portion if (k) sc.Forward(k - j); sc.ForwardSetState(SCE_MARKDOWN_DEFAULT); } } // Code - also a special case for alternate inside spacing if (sc.Match("``") && sc.GetRelative(3) != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_CODE2); sc.Forward(); } else if (sc.ch == '`' && sc.chNext != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_CODE); } // Strong else if (sc.Match("**") && sc.GetRelative(2) != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_STRONG1); sc.Forward(); } else if (sc.Match("__") && sc.GetRelative(2) != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_STRONG2); sc.Forward(); } // Emphasis else if (sc.ch == '*' && sc.chNext != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_EM1); } else if (sc.ch == '_' && sc.chNext != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_EM2); } // Strikeout else if (sc.Match("~~") && sc.GetRelative(2) != ' ' && AtTermStart(sc)) { sc.SetState(SCE_MARKDOWN_STRIKEOUT); sc.Forward(); } // Beginning of line else if (IsNewline(sc.ch)) { sc.SetState(SCE_MARKDOWN_LINE_BEGIN); } } // Advance if not holding back the cursor for this iteration. if (!freezeCursor) sc.Forward(); freezeCursor = false; } sc.Complete(); } LexerModule lmMarkdown(SCLEX_MARKDOWN, ColorizeMarkdownDoc, "markdown"); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexPerl.cxx0000644000175000017500000015301611763437013021243 00000000000000// Scintilla source code edit control /** @file LexPerl.cxx ** Lexer for Perl. ** Converted to lexer object by "Udo Lechner" **/ // Copyright 1998-2008 by Neil Hodgson // Lexical analysis fixes by Kein-Hong Man // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Info for HERE document handling from perldata.pod (reformatted): // ---------------------------------------------------------------- // A line-oriented form of quoting is based on the shell ``here-doc'' syntax. // Following a << you specify a string to terminate the quoted material, and // all lines following the current line down to the terminating string are // the value of the item. // * The terminating string may be either an identifier (a word), or some // quoted text. // * If quoted, the type of quotes you use determines the treatment of the // text, just as in regular quoting. // * An unquoted identifier works like double quotes. // * There must be no space between the << and the identifier. // (If you put a space it will be treated as a null identifier, // which is valid, and matches the first empty line.) // (This is deprecated, -w warns of this syntax) // * The terminating string must appear by itself (unquoted and // with no surrounding whitespace) on the terminating line. #define HERE_DELIM_MAX 256 // maximum length of HERE doc delimiter #define PERLNUM_BINARY 1 // order is significant: 1-4 cannot have a dot #define PERLNUM_HEX 2 #define PERLNUM_OCTAL 3 #define PERLNUM_FLOAT_EXP 4 // exponent part only #define PERLNUM_DECIMAL 5 // 1-5 are numbers; 6-7 are strings #define PERLNUM_VECTOR 6 #define PERLNUM_V_VECTOR 7 #define PERLNUM_BAD 8 #define BACK_NONE 0 // lookback state for bareword disambiguation: #define BACK_OPERATOR 1 // whitespace/comments are insignificant #define BACK_KEYWORD 2 // operators/keywords are needed for disambiguation // all interpolated styles are different from their parent styles by a constant difference // we also assume SCE_PL_STRING_VAR is the interpolated style with the smallest value #define INTERPOLATE_SHIFT (SCE_PL_STRING_VAR - SCE_PL_STRING) static bool isPerlKeyword(unsigned int start, unsigned int end, WordList &keywords, LexAccessor &styler) { // old-style keyword matcher; needed because GetCurrent() needs // current segment to be committed, but we may abandon early... char s[100]; unsigned int i, len = end - start; if (len > 30) { len = 30; } for (i = 0; i < len; i++, start++) s[i] = styler[start]; s[i] = '\0'; return keywords.InList(s); } static int disambiguateBareword(LexAccessor &styler, unsigned int bk, unsigned int fw, int backFlag, unsigned int backPos, unsigned int endPos) { // identifiers are recognized by Perl as barewords under some // conditions, the following attempts to do the disambiguation // by looking backward and forward; result in 2 LSB int result = 0; bool moreback = false; // true if passed newline/comments bool brace = false; // true if opening brace found // if BACK_NONE, neither operator nor keyword, so skip test if (backFlag == BACK_NONE) return result; // first look backwards past whitespace/comments to set EOL flag // (some disambiguation patterns must be on a single line) if (backPos <= static_cast(styler.LineStart(styler.GetLine(bk)))) moreback = true; // look backwards at last significant lexed item for disambiguation bk = backPos - 1; int ch = static_cast(styler.SafeGetCharAt(bk)); if (ch == '{' && !moreback) { // {bareword: possible variable spec brace = true; } else if ((ch == '&' && styler.SafeGetCharAt(bk - 1) != '&') // &bareword: subroutine call || styler.Match(bk - 1, "->") // ->bareword: part of variable spec || styler.Match(bk - 2, "sub")) { // sub bareword: subroutine declaration // (implied BACK_KEYWORD, no keywords end in 'sub'!) result |= 1; } // next, scan forward after word past tab/spaces only; // if ch isn't one of '[{(,' we can skip the test if ((ch == '{' || ch == '(' || ch == '['|| ch == ',') && fw < endPos) { while (ch = static_cast(styler.SafeGetCharAt(fw)), IsASpaceOrTab(ch) && fw < endPos) { fw++; } if ((ch == '}' && brace) // {bareword}: variable spec || styler.Match(fw, "=>")) { // [{(, bareword=>: hash literal result |= 2; } } return result; } static void skipWhitespaceComment(LexAccessor &styler, unsigned int &p) { // when backtracking, we need to skip whitespace and comments int style; while ((p > 0) && (style = styler.StyleAt(p), style == SCE_PL_DEFAULT || style == SCE_PL_COMMENTLINE)) p--; } static int styleBeforeBracePair(LexAccessor &styler, unsigned int bk) { // backtrack to find open '{' corresponding to a '}', balanced // return significant style to be tested for '/' disambiguation int braceCount = 1; if (bk == 0) return SCE_PL_DEFAULT; while (--bk > 0) { if (styler.StyleAt(bk) == SCE_PL_OPERATOR) { int bkch = static_cast(styler.SafeGetCharAt(bk)); if (bkch == ';') { // early out break; } else if (bkch == '}') { braceCount++; } else if (bkch == '{') { if (--braceCount == 0) break; } } } if (bk > 0 && braceCount == 0) { // balanced { found, bk > 0, skip more whitespace/comments bk--; skipWhitespaceComment(styler, bk); return styler.StyleAt(bk); } return SCE_PL_DEFAULT; } static int styleCheckIdentifier(LexAccessor &styler, unsigned int bk) { // backtrack to classify sub-styles of identifier under test // return sub-style to be tested for '/' disambiguation if (styler.SafeGetCharAt(bk) == '>') // inputsymbol, like return 1; // backtrack to check for possible "->" or "::" before identifier while (bk > 0 && styler.StyleAt(bk) == SCE_PL_IDENTIFIER) { bk--; } while (bk > 0) { int bkstyle = styler.StyleAt(bk); if (bkstyle == SCE_PL_DEFAULT || bkstyle == SCE_PL_COMMENTLINE) { // skip whitespace, comments } else if (bkstyle == SCE_PL_OPERATOR) { // test for "->" and "::" if (styler.Match(bk - 1, "->") || styler.Match(bk - 1, "::")) return 2; } else return 3; // bare identifier bk--; } return 0; } static int inputsymbolScan(LexAccessor &styler, unsigned int pos, unsigned int endPos) { // looks forward for matching > on same line; a bit ugly unsigned int fw = pos; while (++fw < endPos) { int fwch = static_cast(styler.SafeGetCharAt(fw)); if (fwch == '\r' || fwch == '\n') { return 0; } else if (fwch == '>') { if (styler.Match(fw - 2, "<=>")) // '<=>' case return 0; return fw - pos; } } return 0; } static int podLineScan(LexAccessor &styler, unsigned int &pos, unsigned int endPos) { // forward scan the current line to classify line for POD style int state = -1; while (pos <= endPos) { int ch = static_cast(styler.SafeGetCharAt(pos)); if (ch == '\n' || ch == '\r' || pos >= endPos) { if (ch == '\r' && styler.SafeGetCharAt(pos + 1) == '\n') pos++; break; } if (IsASpaceOrTab(ch)) { // whitespace, take note if (state == -1) state = SCE_PL_DEFAULT; } else if (state == SCE_PL_DEFAULT) { // verbatim POD line state = SCE_PL_POD_VERB; } else if (state != SCE_PL_POD_VERB) { // regular POD line state = SCE_PL_POD; } pos++; } if (state == -1) state = SCE_PL_DEFAULT; return state; } static bool styleCheckSubPrototype(LexAccessor &styler, unsigned int bk) { // backtrack to identify if we're starting a subroutine prototype // we also need to ignore whitespace/comments: // 'sub' [whitespace|comment] [whitespace|comment] styler.Flush(); skipWhitespaceComment(styler, bk); if (bk == 0 || styler.StyleAt(bk) != SCE_PL_IDENTIFIER) // check identifier return false; while (bk > 0 && (styler.StyleAt(bk) == SCE_PL_IDENTIFIER)) { bk--; } skipWhitespaceComment(styler, bk); if (bk < 2 || styler.StyleAt(bk) != SCE_PL_WORD // check "sub" keyword || !styler.Match(bk - 2, "sub")) // assume suffix is unique! return false; return true; } static int actualNumStyle(int numberStyle) { if (numberStyle == PERLNUM_VECTOR || numberStyle == PERLNUM_V_VECTOR) { return SCE_PL_STRING; } else if (numberStyle == PERLNUM_BAD) { return SCE_PL_ERROR; } return SCE_PL_NUMBER; } static int opposite(int ch) { if (ch == '(') return ')'; if (ch == '[') return ']'; if (ch == '{') return '}'; if (ch == '<') return '>'; return ch; } static bool IsCommentLine(int line, LexAccessor &styler) { int pos = styler.LineStart(line); int eol_pos = styler.LineStart(line + 1) - 1; for (int i = pos; i < eol_pos; i++) { char ch = styler[i]; int style = styler.StyleAt(i); if (ch == '#' && style == SCE_PL_COMMENTLINE) return true; else if (!IsASpaceOrTab(ch)) return false; } return false; } static bool IsPackageLine(int line, LexAccessor &styler) { int pos = styler.LineStart(line); int style = styler.StyleAt(pos); if (style == SCE_PL_WORD && styler.Match(pos, "package")) { return true; } return false; } static int PodHeadingLevel(int pos, LexAccessor &styler) { int lvl = static_cast(styler.SafeGetCharAt(pos + 5)); if (lvl >= '1' && lvl <= '4') { return lvl - '0'; } return 0; } // An individual named option for use in an OptionSet // Options used for LexerPerl struct OptionsPerl { bool fold; bool foldComment; bool foldCompact; // Custom folding of POD and packages bool foldPOD; // fold.perl.pod // Enable folding Pod blocks when using the Perl lexer. bool foldPackage; // fold.perl.package // Enable folding packages when using the Perl lexer. bool foldCommentExplicit; bool foldAtElse; OptionsPerl() { fold = false; foldComment = false; foldCompact = true; foldPOD = true; foldPackage = true; foldCommentExplicit = true; foldAtElse = false; } }; static const char *const perlWordListDesc[] = { "Keywords", 0 }; struct OptionSetPerl : public OptionSet { OptionSetPerl() { DefineProperty("fold", &OptionsPerl::fold); DefineProperty("fold.comment", &OptionsPerl::foldComment); DefineProperty("fold.compact", &OptionsPerl::foldCompact); DefineProperty("fold.perl.pod", &OptionsPerl::foldPOD, "Set to 0 to disable folding Pod blocks when using the Perl lexer."); DefineProperty("fold.perl.package", &OptionsPerl::foldPackage, "Set to 0 to disable folding packages when using the Perl lexer."); DefineProperty("fold.perl.comment.explicit", &OptionsPerl::foldCommentExplicit, "Set to 0 to disable explicit folding."); DefineProperty("fold.perl.at.else", &OptionsPerl::foldAtElse, "This option enables Perl folding on a \"} else {\" line of an if statement."); DefineWordListSets(perlWordListDesc); } }; class LexerPerl : public ILexer { CharacterSet setWordStart; CharacterSet setWord; CharacterSet setSpecialVar; CharacterSet setControlVar; WordList keywords; OptionsPerl options; OptionSetPerl osPerl; public: LexerPerl() : setWordStart(CharacterSet::setAlpha, "_", 0x80, true), setWord(CharacterSet::setAlphaNum, "_", 0x80, true), setSpecialVar(CharacterSet::setNone, "\"$;<>&`'+,./\\%:=~!?@[]"), setControlVar(CharacterSet::setNone, "ACDEFHILMNOPRSTVWX") { } virtual ~LexerPerl() { } void SCI_METHOD Release() { delete this; } int SCI_METHOD Version() const { return lvOriginal; } const char *SCI_METHOD PropertyNames() { return osPerl.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) { return osPerl.PropertyType(name); } const char *SCI_METHOD DescribeProperty(const char *name) { return osPerl.DescribeProperty(name); } int SCI_METHOD PropertySet(const char *key, const char *val); const char *SCI_METHOD DescribeWordListSets() { return osPerl.DescribeWordListSets(); } int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void *SCI_METHOD PrivateCall(int, void *) { return 0; } static ILexer *LexerFactoryPerl() { return new LexerPerl(); } void InterpolateSegment(StyleContext &sc, int maxSeg, bool isPattern=false); }; int SCI_METHOD LexerPerl::PropertySet(const char *key, const char *val) { if (osPerl.PropertySet(&options, key, val)) { return 0; } return -1; } int SCI_METHOD LexerPerl::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywords; break; } int firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } void LexerPerl::InterpolateSegment(StyleContext &sc, int maxSeg, bool isPattern) { // interpolate a segment (with no active backslashes or delimiters within) // switch in or out of an interpolation style or continue current style // commit variable patterns if found, trim segment, repeat until done while (maxSeg > 0) { bool isVar = false; int sLen = 0; if ((maxSeg > 1) && (sc.ch == '$' || sc.ch == '@')) { // $#[$]*word [$@][$]*word (where word or {word} is always present) bool braces = false; sLen = 1; if (sc.ch == '$' && sc.chNext == '#') { // starts with $# sLen++; } while ((maxSeg > sLen) && (sc.GetRelative(sLen) == '$')) // >0 $ dereference within sLen++; if ((maxSeg > sLen) && (sc.GetRelative(sLen) == '{')) { // { start for {word} sLen++; braces = true; } if (maxSeg > sLen) { int c = sc.GetRelative(sLen); if (setWordStart.Contains(c)) { // word (various) sLen++; isVar = true; while ((maxSeg > sLen) && setWord.Contains(sc.GetRelative(sLen))) sLen++; } else if (braces && IsADigit(c) && (sLen == 2)) { // digit for ${digit} sLen++; isVar = true; } } if (braces) { if ((maxSeg > sLen) && (sc.GetRelative(sLen) == '}')) { // } end for {word} sLen++; } else isVar = false; } } if (!isVar && (maxSeg > 1)) { // $- or @-specific variable patterns sLen = 1; int c = sc.chNext; if (sc.ch == '$') { if (IsADigit(c)) { // $[0-9] and slurp trailing digits sLen++; isVar = true; while ((maxSeg > sLen) && IsADigit(sc.GetRelative(sLen))) sLen++; } else if (setSpecialVar.Contains(c)) { // $ special variables sLen++; isVar = true; } else if (!isPattern && ((c == '(') || (c == ')') || (c == '|'))) { // $ additional sLen++; isVar = true; } else if (c == '^') { // $^A control-char style sLen++; if ((maxSeg > sLen) && setControlVar.Contains(sc.GetRelative(sLen))) { sLen++; isVar = true; } } } else if (sc.ch == '@') { if (!isPattern && ((c == '+') || (c == '-'))) { // @ specials non-pattern sLen++; isVar = true; } } } if (isVar) { // commit as interpolated variable or normal character if (sc.state < SCE_PL_STRING_VAR) sc.SetState(sc.state + INTERPOLATE_SHIFT); sc.Forward(sLen); maxSeg -= sLen; } else { if (sc.state >= SCE_PL_STRING_VAR) sc.SetState(sc.state - INTERPOLATE_SHIFT); sc.Forward(); maxSeg--; } } if (sc.state >= SCE_PL_STRING_VAR) sc.SetState(sc.state - INTERPOLATE_SHIFT); } void SCI_METHOD LexerPerl::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); // keywords that forces /PATTERN/ at all times; should track vim's behaviour WordList reWords; reWords.Set("elsif if split while"); // charset classes CharacterSet setSingleCharOp(CharacterSet::setNone, "rwxoRWXOezsfdlpSbctugkTBMAC"); // lexing of "%*,?!.~"); CharacterSet setQDelim(CharacterSet::setNone, "qrwx"); CharacterSet setModifiers(CharacterSet::setAlpha); CharacterSet setPreferRE(CharacterSet::setNone, "*/<%"); // setArray and setHash also accepts chars for special vars like $_, // which are then truncated when the next char does not match setVar CharacterSet setVar(CharacterSet::setAlphaNum, "#$_'", 0x80, true); CharacterSet setArray(CharacterSet::setAlpha, "#$_+-", 0x80, true); CharacterSet setHash(CharacterSet::setAlpha, "#$_!^+-", 0x80, true); CharacterSet &setPOD = setModifiers; CharacterSet setNonHereDoc(CharacterSet::setDigits, "=$@"); CharacterSet setHereDocDelim(CharacterSet::setAlphaNum, "_"); CharacterSet setSubPrototype(CharacterSet::setNone, "\\[$@%&*+];"); // for format identifiers CharacterSet setFormatStart(CharacterSet::setAlpha, "_="); CharacterSet &setFormat = setHereDocDelim; // Lexer for perl often has to backtrack to start of current style to determine // which characters are being used as quotes, how deeply nested is the // start position and what the termination string is for HERE documents. class HereDocCls { // Class to manage HERE doc sequence public: int State; // 0: '<<' encountered // 1: collect the delimiter // 2: here doc text (lines after the delimiter) int Quote; // the char after '<<' bool Quoted; // true if Quote in ('\'','"','`') int DelimiterLength; // strlen(Delimiter) char *Delimiter; // the Delimiter, 256: sizeof PL_tokenbuf HereDocCls() { State = 0; Quote = 0; Quoted = false; DelimiterLength = 0; Delimiter = new char[HERE_DELIM_MAX]; Delimiter[0] = '\0'; } void Append(int ch) { Delimiter[DelimiterLength++] = static_cast(ch); Delimiter[DelimiterLength] = '\0'; } ~HereDocCls() { delete []Delimiter; } }; HereDocCls HereDoc; // TODO: FIFO for stacked here-docs class QuoteCls { // Class to manage quote pairs public: int Rep; int Count; int Up, Down; QuoteCls() { this->New(1); } void New(int r = 1) { Rep = r; Count = 0; Up = '\0'; Down = '\0'; } void Open(int u) { Count++; Up = u; Down = opposite(Up); } }; QuoteCls Quote; // additional state for number lexing int numState = PERLNUM_DECIMAL; int dotCount = 0; unsigned int endPos = startPos + length; // Backtrack to beginning of style if required... // If in a long distance lexical state, backtrack to find quote characters. // Includes strings (may be multi-line), numbers (additional state), format // bodies, as well as POD sections. if (initStyle == SCE_PL_HERE_Q || initStyle == SCE_PL_HERE_QQ || initStyle == SCE_PL_HERE_QX || initStyle == SCE_PL_FORMAT || initStyle == SCE_PL_HERE_QQ_VAR || initStyle == SCE_PL_HERE_QX_VAR ) { // backtrack through multiple styles to reach the delimiter start int delim = (initStyle == SCE_PL_FORMAT) ? SCE_PL_FORMAT_IDENT:SCE_PL_HERE_DELIM; while ((startPos > 1) && (styler.StyleAt(startPos) != delim)) { startPos--; } startPos = styler.LineStart(styler.GetLine(startPos)); initStyle = styler.StyleAt(startPos - 1); } if (initStyle == SCE_PL_STRING || initStyle == SCE_PL_STRING_QQ || initStyle == SCE_PL_BACKTICKS || initStyle == SCE_PL_STRING_QX || initStyle == SCE_PL_REGEX || initStyle == SCE_PL_STRING_QR || initStyle == SCE_PL_REGSUBST || initStyle == SCE_PL_STRING_VAR || initStyle == SCE_PL_STRING_QQ_VAR || initStyle == SCE_PL_BACKTICKS_VAR || initStyle == SCE_PL_STRING_QX_VAR || initStyle == SCE_PL_REGEX_VAR || initStyle == SCE_PL_STRING_QR_VAR || initStyle == SCE_PL_REGSUBST_VAR ) { // for interpolation, must backtrack through a mix of two different styles int otherStyle = (initStyle >= SCE_PL_STRING_VAR) ? initStyle - INTERPOLATE_SHIFT : initStyle + INTERPOLATE_SHIFT; while (startPos > 1) { int st = styler.StyleAt(startPos - 1); if ((st != initStyle) && (st != otherStyle)) break; startPos--; } initStyle = SCE_PL_DEFAULT; } else if (initStyle == SCE_PL_STRING_Q || initStyle == SCE_PL_STRING_QW || initStyle == SCE_PL_XLAT || initStyle == SCE_PL_CHARACTER || initStyle == SCE_PL_NUMBER || initStyle == SCE_PL_IDENTIFIER || initStyle == SCE_PL_ERROR || initStyle == SCE_PL_SUB_PROTOTYPE ) { while ((startPos > 1) && (styler.StyleAt(startPos - 1) == initStyle)) { startPos--; } initStyle = SCE_PL_DEFAULT; } else if (initStyle == SCE_PL_POD || initStyle == SCE_PL_POD_VERB ) { // POD backtracking finds preceeding blank lines and goes back past them int ln = styler.GetLine(startPos); if (ln > 0) { initStyle = styler.StyleAt(styler.LineStart(--ln)); if (initStyle == SCE_PL_POD || initStyle == SCE_PL_POD_VERB) { while (ln > 0 && styler.GetLineState(ln) == SCE_PL_DEFAULT) ln--; } startPos = styler.LineStart(++ln); initStyle = styler.StyleAt(startPos - 1); } else { startPos = 0; initStyle = SCE_PL_DEFAULT; } } // backFlag, backPos are additional state to aid identifier corner cases. // Look backwards past whitespace and comments in order to detect either // operator or keyword. Later updated as we go along. int backFlag = BACK_NONE; unsigned int backPos = startPos; if (backPos > 0) { backPos--; skipWhitespaceComment(styler, backPos); if (styler.StyleAt(backPos) == SCE_PL_OPERATOR) backFlag = BACK_OPERATOR; else if (styler.StyleAt(backPos) == SCE_PL_WORD) backFlag = BACK_KEYWORD; backPos++; } StyleContext sc(startPos, endPos - startPos, initStyle, styler, static_cast(STYLE_MAX)); for (; sc.More(); sc.Forward()) { // Determine if the current state should terminate. switch (sc.state) { case SCE_PL_OPERATOR: sc.SetState(SCE_PL_DEFAULT); backFlag = BACK_OPERATOR; backPos = sc.currentPos; break; case SCE_PL_IDENTIFIER: // identifier, bareword, inputsymbol if ((!setWord.Contains(sc.ch) && sc.ch != '\'') || sc.Match('.', '.') || sc.chPrev == '>') { // end of inputsymbol sc.SetState(SCE_PL_DEFAULT); } break; case SCE_PL_WORD: // keyword, plus special cases if (!setWord.Contains(sc.ch)) { char s[100]; sc.GetCurrent(s, sizeof(s)); if ((strcmp(s, "__DATA__") == 0) || (strcmp(s, "__END__") == 0)) { sc.ChangeState(SCE_PL_DATASECTION); } else { if ((strcmp(s, "format") == 0)) { sc.SetState(SCE_PL_FORMAT_IDENT); HereDoc.State = 0; } else { sc.SetState(SCE_PL_DEFAULT); } backFlag = BACK_KEYWORD; backPos = sc.currentPos; } } break; case SCE_PL_SCALAR: case SCE_PL_ARRAY: case SCE_PL_HASH: case SCE_PL_SYMBOLTABLE: if (sc.Match(':', ':')) { // skip :: sc.Forward(); } else if (!setVar.Contains(sc.ch)) { if (sc.LengthCurrent() == 1) { // Special variable: $(, $_ etc. sc.Forward(); } sc.SetState(SCE_PL_DEFAULT); } break; case SCE_PL_NUMBER: // if no early break, number style is terminated at "(go through)" if (sc.ch == '.') { if (sc.chNext == '.') { // double dot is always an operator (go through) } else if (numState <= PERLNUM_FLOAT_EXP) { // non-decimal number or float exponent, consume next dot sc.SetState(SCE_PL_OPERATOR); break; } else { // decimal or vectors allows dots dotCount++; if (numState == PERLNUM_DECIMAL) { if (dotCount <= 1) // number with one dot in it break; if (IsADigit(sc.chNext)) { // really a vector numState = PERLNUM_VECTOR; break; } // number then dot (go through) } else if (IsADigit(sc.chNext)) // vectors break; // vector then dot (go through) } } else if (sc.ch == '_') { // permissive underscoring for number and vector literals break; } else if (numState == PERLNUM_DECIMAL) { if (sc.ch == 'E' || sc.ch == 'e') { // exponent, sign numState = PERLNUM_FLOAT_EXP; if (sc.chNext == '+' || sc.chNext == '-') { sc.Forward(); } break; } else if (IsADigit(sc.ch)) break; // number then word (go through) } else if (numState == PERLNUM_HEX) { if (IsADigit(sc.ch, 16)) break; } else if (numState == PERLNUM_VECTOR || numState == PERLNUM_V_VECTOR) { if (IsADigit(sc.ch)) // vector break; if (setWord.Contains(sc.ch) && dotCount == 0) { // change to word sc.ChangeState(SCE_PL_IDENTIFIER); break; } // vector then word (go through) } else if (IsADigit(sc.ch)) { if (numState == PERLNUM_FLOAT_EXP) { break; } else if (numState == PERLNUM_OCTAL) { if (sc.ch <= '7') break; } else if (numState == PERLNUM_BINARY) { if (sc.ch <= '1') break; } // mark invalid octal, binary numbers (go through) numState = PERLNUM_BAD; break; } // complete current number or vector sc.ChangeState(actualNumStyle(numState)); sc.SetState(SCE_PL_DEFAULT); break; case SCE_PL_COMMENTLINE: if (sc.atLineEnd) { sc.SetState(SCE_PL_DEFAULT); } break; case SCE_PL_HERE_DELIM: if (HereDoc.State == 0) { // '<<' encountered int delim_ch = sc.chNext; int ws_skip = 0; HereDoc.State = 1; // pre-init HERE doc class HereDoc.Quote = sc.chNext; HereDoc.Quoted = false; HereDoc.DelimiterLength = 0; HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; if (IsASpaceOrTab(delim_ch)) { // skip whitespace; legal only for quoted delimiters unsigned int i = sc.currentPos + 1; while ((i < endPos) && IsASpaceOrTab(delim_ch)) { i++; delim_ch = static_cast(styler.SafeGetCharAt(i)); } ws_skip = i - sc.currentPos - 1; } if (delim_ch == '\'' || delim_ch == '"' || delim_ch == '`') { // a quoted here-doc delimiter; skip any whitespace sc.Forward(ws_skip + 1); HereDoc.Quote = delim_ch; HereDoc.Quoted = true; } else if ((ws_skip == 0 && setNonHereDoc.Contains(sc.chNext)) || ws_skip > 0) { // left shift << or <<= operator cases // restore position if operator sc.ChangeState(SCE_PL_OPERATOR); sc.ForwardSetState(SCE_PL_DEFAULT); backFlag = BACK_OPERATOR; backPos = sc.currentPos; HereDoc.State = 0; } else { // specially handle initial '\' for identifier if (ws_skip == 0 && HereDoc.Quote == '\\') sc.Forward(); // an unquoted here-doc delimiter, no special handling // (cannot be prefixed by spaces/tabs), or // symbols terminates; deprecated zero-length delimiter } } else if (HereDoc.State == 1) { // collect the delimiter backFlag = BACK_NONE; if (HereDoc.Quoted) { // a quoted here-doc delimiter if (sc.ch == HereDoc.Quote) { // closing quote => end of delimiter sc.ForwardSetState(SCE_PL_DEFAULT); } else if (!sc.atLineEnd) { if (sc.Match('\\', static_cast(HereDoc.Quote))) { // escaped quote sc.Forward(); } if (sc.ch != '\r') { // skip CR if CRLF HereDoc.Append(sc.ch); } } } else { // an unquoted here-doc delimiter if (setHereDocDelim.Contains(sc.ch)) { HereDoc.Append(sc.ch); } else { sc.SetState(SCE_PL_DEFAULT); } } if (HereDoc.DelimiterLength >= HERE_DELIM_MAX - 1) { sc.SetState(SCE_PL_ERROR); HereDoc.State = 0; } } break; case SCE_PL_HERE_Q: case SCE_PL_HERE_QQ: case SCE_PL_HERE_QX: // also implies HereDoc.State == 2 sc.Complete(); if (HereDoc.DelimiterLength == 0 || sc.Match(HereDoc.Delimiter)) { int c = sc.GetRelative(HereDoc.DelimiterLength); if (c == '\r' || c == '\n') { // peek first, do not consume match sc.Forward(HereDoc.DelimiterLength); sc.SetState(SCE_PL_DEFAULT); backFlag = BACK_NONE; HereDoc.State = 0; if (!sc.atLineEnd) sc.Forward(); break; } } if (sc.state == SCE_PL_HERE_Q) { // \EOF and 'EOF' non-interpolated while (!sc.atLineEnd) sc.Forward(); break; } while (!sc.atLineEnd) { // "EOF" and `EOF` interpolated int s = 0, endType = 0; int maxSeg = endPos - sc.currentPos; while (s < maxSeg) { // scan to break string into segments int c = sc.GetRelative(s); if (c == '\\') { endType = 1; break; } else if (c == '\r' || c == '\n') { endType = 2; break; } s++; } if (s > 0) // process non-empty segments InterpolateSegment(sc, s); if (endType == 1) { sc.Forward(); // \ at end-of-line does not appear to have any effect, skip if (sc.ch != '\r' && sc.ch != '\n') sc.Forward(); } else if (endType == 2) { if (!sc.atLineEnd) sc.Forward(); } } break; case SCE_PL_POD: case SCE_PL_POD_VERB: { unsigned int fw = sc.currentPos; int ln = styler.GetLine(fw); if (sc.atLineStart && sc.Match("=cut")) { // end of POD sc.SetState(SCE_PL_POD); sc.Forward(4); sc.SetState(SCE_PL_DEFAULT); styler.SetLineState(ln, SCE_PL_POD); break; } int pod = podLineScan(styler, fw, endPos); // classify POD line styler.SetLineState(ln, pod); if (pod == SCE_PL_DEFAULT) { if (sc.state == SCE_PL_POD_VERB) { unsigned int fw2 = fw; while (fw2 <= endPos && pod == SCE_PL_DEFAULT) { fw = fw2++; // penultimate line (last blank line) pod = podLineScan(styler, fw2, endPos); styler.SetLineState(styler.GetLine(fw2), pod); } if (pod == SCE_PL_POD) { // truncate verbatim POD early sc.SetState(SCE_PL_POD); } else fw = fw2; } } else { if (pod == SCE_PL_POD_VERB // still part of current paragraph && (styler.GetLineState(ln - 1) == SCE_PL_POD)) { pod = SCE_PL_POD; styler.SetLineState(ln, pod); } else if (pod == SCE_PL_POD && (styler.GetLineState(ln - 1) == SCE_PL_POD_VERB)) { pod = SCE_PL_POD_VERB; styler.SetLineState(ln, pod); } sc.SetState(pod); } sc.Forward(fw - sc.currentPos); // commit style } break; case SCE_PL_REGEX: case SCE_PL_STRING_QR: if (Quote.Rep <= 0) { if (!setModifiers.Contains(sc.ch)) sc.SetState(SCE_PL_DEFAULT); } else if (!Quote.Up && !IsASpace(sc.ch)) { Quote.Open(sc.ch); } else { int s = 0, endType = 0; int maxSeg = endPos - sc.currentPos; while (s < maxSeg) { // scan to break string into segments int c = sc.GetRelative(s); if (IsASpace(c)) { break; } else if (c == '\\' && Quote.Up != '\\') { endType = 1; break; } else if (c == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { Quote.Rep--; break; } } else if (c == Quote.Up) Quote.Count++; s++; } if (s > 0) { // process non-empty segments if (Quote.Up != '\'') { InterpolateSegment(sc, s, true); } else // non-interpolated path sc.Forward(s); } if (endType == 1) sc.Forward(); } break; case SCE_PL_REGSUBST: case SCE_PL_XLAT: if (Quote.Rep <= 0) { if (!setModifiers.Contains(sc.ch)) sc.SetState(SCE_PL_DEFAULT); } else if (!Quote.Up && !IsASpace(sc.ch)) { Quote.Open(sc.ch); } else { int s = 0, endType = 0; int maxSeg = endPos - sc.currentPos; bool isPattern = (Quote.Rep == 2); while (s < maxSeg) { // scan to break string into segments int c = sc.GetRelative(s); if (c == '\\' && Quote.Up != '\\') { endType = 2; break; } else if (Quote.Count == 0 && Quote.Rep == 1) { // We matched something like s(...) or tr{...}, Perl 5.10 // appears to allow almost any character for use as the // next delimiters. Whitespace and comments are accepted in // between, but we'll limit to whitespace here. // For '#', if no whitespace in between, it's a delimiter. if (IsASpace(c)) { // Keep going } else if (c == '#' && IsASpaceOrTab(sc.GetRelative(s - 1))) { endType = 3; } else Quote.Open(c); break; } else if (c == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { Quote.Rep--; endType = 1; } if (Quote.Up == Quote.Down) Quote.Count++; if (endType == 1) break; } else if (c == Quote.Up) { Quote.Count++; } else if (IsASpace(c)) break; s++; } if (s > 0) { // process non-empty segments if (sc.state == SCE_PL_REGSUBST && Quote.Up != '\'') { InterpolateSegment(sc, s, isPattern); } else // non-interpolated path sc.Forward(s); } if (endType == 2) { sc.Forward(); } else if (endType == 3) sc.SetState(SCE_PL_DEFAULT); } break; case SCE_PL_STRING_Q: case SCE_PL_STRING_QQ: case SCE_PL_STRING_QX: case SCE_PL_STRING_QW: case SCE_PL_STRING: case SCE_PL_CHARACTER: case SCE_PL_BACKTICKS: if (!Quote.Down && !IsASpace(sc.ch)) { Quote.Open(sc.ch); } else { int s = 0, endType = 0; int maxSeg = endPos - sc.currentPos; while (s < maxSeg) { // scan to break string into segments int c = sc.GetRelative(s); if (IsASpace(c)) { break; } else if (c == '\\' && Quote.Up != '\\') { endType = 2; break; } else if (c == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { endType = 3; break; } } else if (c == Quote.Up) Quote.Count++; s++; } if (s > 0) { // process non-empty segments switch (sc.state) { case SCE_PL_STRING: case SCE_PL_STRING_QQ: case SCE_PL_BACKTICKS: InterpolateSegment(sc, s); break; case SCE_PL_STRING_QX: if (Quote.Up != '\'') { InterpolateSegment(sc, s); break; } // (continued for ' delim) default: // non-interpolated path sc.Forward(s); } } if (endType == 2) { sc.Forward(); } else if (endType == 3) sc.ForwardSetState(SCE_PL_DEFAULT); } break; case SCE_PL_SUB_PROTOTYPE: { int i = 0; // forward scan; must all be valid proto characters while (setSubPrototype.Contains(sc.GetRelative(i))) i++; if (sc.GetRelative(i) == ')') { // valid sub prototype sc.Forward(i); sc.ForwardSetState(SCE_PL_DEFAULT); } else { // abandon prototype, restart from '(' sc.ChangeState(SCE_PL_OPERATOR); sc.SetState(SCE_PL_DEFAULT); } } break; case SCE_PL_FORMAT: { sc.Complete(); if (sc.Match('.')) { sc.Forward(); if (sc.atLineEnd || ((sc.ch == '\r' && sc.chNext == '\n'))) sc.SetState(SCE_PL_DEFAULT); } while (!sc.atLineEnd) sc.Forward(); } break; case SCE_PL_ERROR: break; } // Needed for specific continuation styles (one follows the other) switch (sc.state) { // continued from SCE_PL_WORD case SCE_PL_FORMAT_IDENT: // occupies HereDoc state 3 to avoid clashing with HERE docs if (IsASpaceOrTab(sc.ch)) { // skip whitespace sc.ChangeState(SCE_PL_DEFAULT); while (IsASpaceOrTab(sc.ch) && !sc.atLineEnd) sc.Forward(); sc.SetState(SCE_PL_FORMAT_IDENT); } if (setFormatStart.Contains(sc.ch)) { // identifier or '=' if (sc.ch != '=') { do { sc.Forward(); } while (setFormat.Contains(sc.ch)); } while (IsASpaceOrTab(sc.ch) && !sc.atLineEnd) sc.Forward(); if (sc.ch == '=') { sc.ForwardSetState(SCE_PL_DEFAULT); HereDoc.State = 3; } else { // invalid indentifier; inexact fallback, but hey sc.ChangeState(SCE_PL_IDENTIFIER); sc.SetState(SCE_PL_DEFAULT); } } else { sc.ChangeState(SCE_PL_DEFAULT); // invalid indentifier } backFlag = BACK_NONE; break; } // Must check end of HereDoc states here before default state is handled if (HereDoc.State == 1 && sc.atLineEnd) { // Begin of here-doc (the line after the here-doc delimiter): // Lexically, the here-doc starts from the next line after the >>, but the // first line of here-doc seem to follow the style of the last EOL sequence int st_new = SCE_PL_HERE_QQ; HereDoc.State = 2; if (HereDoc.Quoted) { if (sc.state == SCE_PL_HERE_DELIM) { // Missing quote at end of string! We are stricter than perl. // Colour here-doc anyway while marking this bit as an error. sc.ChangeState(SCE_PL_ERROR); } switch (HereDoc.Quote) { case '\'': st_new = SCE_PL_HERE_Q ; break; case '"' : st_new = SCE_PL_HERE_QQ; break; case '`' : st_new = SCE_PL_HERE_QX; break; } } else { if (HereDoc.Quote == '\\') st_new = SCE_PL_HERE_Q; } sc.SetState(st_new); } if (HereDoc.State == 3 && sc.atLineEnd) { // Start of format body. HereDoc.State = 0; sc.SetState(SCE_PL_FORMAT); } // Determine if a new state should be entered. if (sc.state == SCE_PL_DEFAULT) { if (IsADigit(sc.ch) || (IsADigit(sc.chNext) && (sc.ch == '.' || sc.ch == 'v'))) { sc.SetState(SCE_PL_NUMBER); backFlag = BACK_NONE; numState = PERLNUM_DECIMAL; dotCount = 0; if (sc.ch == '0') { // hex,bin,octal if (sc.chNext == 'x' || sc.chNext == 'X') { numState = PERLNUM_HEX; } else if (sc.chNext == 'b' || sc.chNext == 'B') { numState = PERLNUM_BINARY; } else if (IsADigit(sc.chNext)) { numState = PERLNUM_OCTAL; } if (numState != PERLNUM_DECIMAL) { sc.Forward(); } } else if (sc.ch == 'v') { // vector numState = PERLNUM_V_VECTOR; } } else if (setWord.Contains(sc.ch)) { // if immediately prefixed by '::', always a bareword sc.SetState(SCE_PL_WORD); if (sc.chPrev == ':' && sc.GetRelative(-2) == ':') { sc.ChangeState(SCE_PL_IDENTIFIER); } unsigned int bk = sc.currentPos; unsigned int fw = sc.currentPos + 1; // first check for possible quote-like delimiter if (sc.ch == 's' && !setWord.Contains(sc.chNext)) { sc.ChangeState(SCE_PL_REGSUBST); Quote.New(2); } else if (sc.ch == 'm' && !setWord.Contains(sc.chNext)) { sc.ChangeState(SCE_PL_REGEX); Quote.New(); } else if (sc.ch == 'q' && !setWord.Contains(sc.chNext)) { sc.ChangeState(SCE_PL_STRING_Q); Quote.New(); } else if (sc.ch == 'y' && !setWord.Contains(sc.chNext)) { sc.ChangeState(SCE_PL_XLAT); Quote.New(2); } else if (sc.Match('t', 'r') && !setWord.Contains(sc.GetRelative(2))) { sc.ChangeState(SCE_PL_XLAT); Quote.New(2); sc.Forward(); fw++; } else if (sc.ch == 'q' && setQDelim.Contains(sc.chNext) && !setWord.Contains(sc.GetRelative(2))) { if (sc.chNext == 'q') sc.ChangeState(SCE_PL_STRING_QQ); else if (sc.chNext == 'x') sc.ChangeState(SCE_PL_STRING_QX); else if (sc.chNext == 'r') sc.ChangeState(SCE_PL_STRING_QR); else sc.ChangeState(SCE_PL_STRING_QW); // sc.chNext == 'w' Quote.New(); sc.Forward(); fw++; } else if (sc.ch == 'x' && (sc.chNext == '=' || // repetition !setWord.Contains(sc.chNext) || (IsADigit(sc.chPrev) && IsADigit(sc.chNext)))) { sc.ChangeState(SCE_PL_OPERATOR); } // if potentially a keyword, scan forward and grab word, then check // if it's really one; if yes, disambiguation test is performed // otherwise it is always a bareword and we skip a lot of scanning if (sc.state == SCE_PL_WORD) { while (setWord.Contains(static_cast(styler.SafeGetCharAt(fw)))) fw++; if (!isPerlKeyword(styler.GetStartSegment(), fw, keywords, styler)) { sc.ChangeState(SCE_PL_IDENTIFIER); } } // if already SCE_PL_IDENTIFIER, then no ambiguity, skip this // for quote-like delimiters/keywords, attempt to disambiguate // to select for bareword, change state -> SCE_PL_IDENTIFIER if (sc.state != SCE_PL_IDENTIFIER && bk > 0) { if (disambiguateBareword(styler, bk, fw, backFlag, backPos, endPos)) sc.ChangeState(SCE_PL_IDENTIFIER); } backFlag = BACK_NONE; } else if (sc.ch == '#') { sc.SetState(SCE_PL_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_PL_STRING); Quote.New(); Quote.Open(sc.ch); backFlag = BACK_NONE; } else if (sc.ch == '\'') { if (sc.chPrev == '&' && setWordStart.Contains(sc.chNext)) { // Archaic call sc.SetState(SCE_PL_IDENTIFIER); } else { sc.SetState(SCE_PL_CHARACTER); Quote.New(); Quote.Open(sc.ch); } backFlag = BACK_NONE; } else if (sc.ch == '`') { sc.SetState(SCE_PL_BACKTICKS); Quote.New(); Quote.Open(sc.ch); backFlag = BACK_NONE; } else if (sc.ch == '$') { sc.SetState(SCE_PL_SCALAR); if (sc.chNext == '{') { sc.ForwardSetState(SCE_PL_OPERATOR); } else if (IsASpace(sc.chNext)) { sc.ForwardSetState(SCE_PL_DEFAULT); } else { sc.Forward(); if (sc.Match('`', '`') || sc.Match(':', ':')) { sc.Forward(); } } backFlag = BACK_NONE; } else if (sc.ch == '@') { sc.SetState(SCE_PL_ARRAY); if (setArray.Contains(sc.chNext)) { // no special treatment } else if (sc.chNext == ':' && sc.GetRelative(2) == ':') { sc.Forward(2); } else if (sc.chNext == '{' || sc.chNext == '[') { sc.ForwardSetState(SCE_PL_OPERATOR); } else { sc.ChangeState(SCE_PL_OPERATOR); } backFlag = BACK_NONE; } else if (setPreferRE.Contains(sc.ch)) { // Explicit backward peeking to set a consistent preferRE for // any slash found, so no longer need to track preferRE state. // Find first previous significant lexed element and interpret. // A few symbols shares this code for disambiguation. bool preferRE = false; bool isHereDoc = sc.Match('<', '<'); bool hereDocSpace = false; // for: SCALAR [whitespace] '<<' unsigned int bk = (sc.currentPos > 0) ? sc.currentPos - 1: 0; sc.Complete(); styler.Flush(); if (styler.StyleAt(bk) == SCE_PL_DEFAULT) hereDocSpace = true; skipWhitespaceComment(styler, bk); if (bk == 0) { // avoid backward scanning breakage preferRE = true; } else { int bkstyle = styler.StyleAt(bk); int bkch = static_cast(styler.SafeGetCharAt(bk)); switch (bkstyle) { case SCE_PL_OPERATOR: preferRE = true; if (bkch == ')' || bkch == ']') { preferRE = false; } else if (bkch == '}') { // backtrack by counting balanced brace pairs // needed to test for variables like ${}, @{} etc. bkstyle = styleBeforeBracePair(styler, bk); if (bkstyle == SCE_PL_SCALAR || bkstyle == SCE_PL_ARRAY || bkstyle == SCE_PL_HASH || bkstyle == SCE_PL_SYMBOLTABLE || bkstyle == SCE_PL_OPERATOR) { preferRE = false; } } else if (bkch == '+' || bkch == '-') { if (bkch == static_cast(styler.SafeGetCharAt(bk - 1)) && bkch != static_cast(styler.SafeGetCharAt(bk - 2))) // exceptions for operators: unary suffixes ++, -- preferRE = false; } break; case SCE_PL_IDENTIFIER: preferRE = true; bkstyle = styleCheckIdentifier(styler, bk); if ((bkstyle == 1) || (bkstyle == 2)) { // inputsymbol or var with "->" or "::" before identifier preferRE = false; } else if (bkstyle == 3) { // bare identifier, test cases follows: if (sc.ch == '/') { // if '/', /PATTERN/ unless digit/space immediately after '/' // if '//', always expect defined-or operator to follow identifier if (IsASpace(sc.chNext) || IsADigit(sc.chNext) || sc.chNext == '/') preferRE = false; } else if (sc.ch == '*' || sc.ch == '%') { if (IsASpace(sc.chNext) || IsADigit(sc.chNext) || sc.Match('*', '*')) preferRE = false; } else if (sc.ch == '<') { if (IsASpace(sc.chNext) || sc.chNext == '=') preferRE = false; } } break; case SCE_PL_SCALAR: // for $var<< case: if (isHereDoc && hereDocSpace) // if SCALAR whitespace '<<', *always* a HERE doc preferRE = true; break; case SCE_PL_WORD: preferRE = true; // for HERE docs, always true if (sc.ch == '/') { // adopt heuristics similar to vim-style rules: // keywords always forced as /PATTERN/: split, if, elsif, while // everything else /PATTERN/ unless digit/space immediately after '/' // for '//', defined-or favoured unless special keywords unsigned int bkend = bk + 1; while (bk > 0 && styler.StyleAt(bk - 1) == SCE_PL_WORD) { bk--; } if (isPerlKeyword(bk, bkend, reWords, styler)) break; if (IsASpace(sc.chNext) || IsADigit(sc.chNext) || sc.chNext == '/') preferRE = false; } else if (sc.ch == '*' || sc.ch == '%') { if (IsASpace(sc.chNext) || IsADigit(sc.chNext) || sc.Match('*', '*')) preferRE = false; } else if (sc.ch == '<') { if (IsASpace(sc.chNext) || sc.chNext == '=') preferRE = false; } break; // other styles uses the default, preferRE=false case SCE_PL_POD: case SCE_PL_HERE_Q: case SCE_PL_HERE_QQ: case SCE_PL_HERE_QX: preferRE = true; break; } } backFlag = BACK_NONE; if (isHereDoc) { // handle '<<', HERE doc if (preferRE) { sc.SetState(SCE_PL_HERE_DELIM); HereDoc.State = 0; } else { // << operator sc.SetState(SCE_PL_OPERATOR); sc.Forward(); } } else if (sc.ch == '*') { // handle '*', typeglob if (preferRE) { sc.SetState(SCE_PL_SYMBOLTABLE); if (sc.chNext == ':' && sc.GetRelative(2) == ':') { sc.Forward(2); } else if (sc.chNext == '{') { sc.ForwardSetState(SCE_PL_OPERATOR); } else { sc.Forward(); } } else { sc.SetState(SCE_PL_OPERATOR); if (sc.chNext == '*') // exponentiation sc.Forward(); } } else if (sc.ch == '%') { // handle '%', hash if (preferRE) { sc.SetState(SCE_PL_HASH); if (setHash.Contains(sc.chNext)) { sc.Forward(); } else if (sc.chNext == ':' && sc.GetRelative(2) == ':') { sc.Forward(2); } else if (sc.chNext == '{') { sc.ForwardSetState(SCE_PL_OPERATOR); } else { sc.ChangeState(SCE_PL_OPERATOR); } } else { sc.SetState(SCE_PL_OPERATOR); } } else if (sc.ch == '<') { // handle '<', inputsymbol if (preferRE) { // forward scan int i = inputsymbolScan(styler, sc.currentPos, endPos); if (i > 0) { sc.SetState(SCE_PL_IDENTIFIER); sc.Forward(i); } else { sc.SetState(SCE_PL_OPERATOR); } } else { sc.SetState(SCE_PL_OPERATOR); } } else { // handle '/', regexp if (preferRE) { sc.SetState(SCE_PL_REGEX); Quote.New(); Quote.Open(sc.ch); } else { // / and // operators sc.SetState(SCE_PL_OPERATOR); if (sc.chNext == '/') { sc.Forward(); } } } } else if (sc.ch == '=' // POD && setPOD.Contains(sc.chNext) && sc.atLineStart) { sc.SetState(SCE_PL_POD); backFlag = BACK_NONE; } else if (sc.ch == '-' && setWordStart.Contains(sc.chNext)) { // extended '-' cases unsigned int bk = sc.currentPos; unsigned int fw = 2; if (setSingleCharOp.Contains(sc.chNext) && // file test operators !setWord.Contains(sc.GetRelative(2))) { sc.SetState(SCE_PL_WORD); } else { // nominally a minus and bareword; find extent of bareword while (setWord.Contains(sc.GetRelative(fw))) fw++; sc.SetState(SCE_PL_OPERATOR); } // force to bareword for hash key => or {variable literal} cases if (disambiguateBareword(styler, bk, bk + fw, backFlag, backPos, endPos) & 2) { sc.ChangeState(SCE_PL_IDENTIFIER); } backFlag = BACK_NONE; } else if (sc.ch == '(' && sc.currentPos > 0) { // '(' or subroutine prototype sc.Complete(); if (styleCheckSubPrototype(styler, sc.currentPos - 1)) { sc.SetState(SCE_PL_SUB_PROTOTYPE); backFlag = BACK_NONE; } else { sc.SetState(SCE_PL_OPERATOR); } } else if (setPerlOperator.Contains(sc.ch)) { // operators sc.SetState(SCE_PL_OPERATOR); if (sc.Match('.', '.')) { // .. and ... sc.Forward(); if (sc.chNext == '.') sc.Forward(); } } else if (sc.ch == 4 || sc.ch == 26) { // ^D and ^Z ends valid perl source sc.SetState(SCE_PL_DATASECTION); } else { // keep colouring defaults sc.Complete(); } } } sc.Complete(); if (sc.state == SCE_PL_HERE_Q || sc.state == SCE_PL_HERE_QQ || sc.state == SCE_PL_HERE_QX || sc.state == SCE_PL_FORMAT) { styler.ChangeLexerState(sc.currentPos, styler.Length()); } sc.Complete(); } #define PERL_HEADFOLD_SHIFT 4 #define PERL_HEADFOLD_MASK 0xF0 void SCI_METHOD LexerPerl::Fold(unsigned int startPos, int length, int /* initStyle */, IDocument *pAccess) { if (!options.fold) return; LexAccessor styler(pAccess); unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); // Backtrack to previous line in case need to fix its fold status if (startPos > 0) { if (lineCurrent > 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); } } int levelPrev = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelPrev = styler.LevelAt(lineCurrent - 1) >> 16; int levelCurrent = levelPrev; char chNext = styler[startPos]; char chPrev = styler.SafeGetCharAt(startPos - 1); int styleNext = styler.StyleAt(startPos); // Used at end of line to determine if the line was a package definition bool isPackageLine = false; int podHeading = 0; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styleNext; styleNext = styler.StyleAt(i + 1); int stylePrevCh = (i) ? styler.StyleAt(i - 1):SCE_PL_DEFAULT; bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); bool atLineStart = ((chPrev == '\r') || (chPrev == '\n')) || i == 0; // Comment folding if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler)) { if (!IsCommentLine(lineCurrent - 1, styler) && IsCommentLine(lineCurrent + 1, styler)) levelCurrent++; else if (IsCommentLine(lineCurrent - 1, styler) && !IsCommentLine(lineCurrent + 1, styler)) levelCurrent--; } // {} [] block folding if (style == SCE_PL_OPERATOR) { if (ch == '{') { if (options.foldAtElse && levelCurrent < levelPrev) --levelPrev; levelCurrent++; } else if (ch == '}') { levelCurrent--; } if (ch == '[') { if (options.foldAtElse && levelCurrent < levelPrev) --levelPrev; levelCurrent++; } else if (ch == ']') { levelCurrent--; } } // POD folding if (options.foldPOD && atLineStart) { if (style == SCE_PL_POD) { if (stylePrevCh != SCE_PL_POD && stylePrevCh != SCE_PL_POD_VERB) levelCurrent++; else if (styler.Match(i, "=cut")) levelCurrent = (levelCurrent & ~PERL_HEADFOLD_MASK) - 1; else if (styler.Match(i, "=head")) podHeading = PodHeadingLevel(i, styler); } else if (style == SCE_PL_DATASECTION) { if (ch == '=' && isascii(chNext) && isalpha(chNext) && levelCurrent == SC_FOLDLEVELBASE) levelCurrent++; else if (styler.Match(i, "=cut") && levelCurrent > SC_FOLDLEVELBASE) levelCurrent = (levelCurrent & ~PERL_HEADFOLD_MASK) - 1; else if (styler.Match(i, "=head")) podHeading = PodHeadingLevel(i, styler); // if package used or unclosed brace, level > SC_FOLDLEVELBASE! // reset needed as level test is vs. SC_FOLDLEVELBASE else if (stylePrevCh != SCE_PL_DATASECTION) levelCurrent = SC_FOLDLEVELBASE; } } // package folding if (options.foldPackage && atLineStart) { if (IsPackageLine(lineCurrent, styler) && !IsPackageLine(lineCurrent + 1, styler)) isPackageLine = true; } //heredoc folding switch (style) { case SCE_PL_HERE_QQ : case SCE_PL_HERE_Q : case SCE_PL_HERE_QX : switch (stylePrevCh) { case SCE_PL_HERE_QQ : case SCE_PL_HERE_Q : case SCE_PL_HERE_QX : //do nothing; break; default : levelCurrent++; break; } break; default: switch (stylePrevCh) { case SCE_PL_HERE_QQ : case SCE_PL_HERE_Q : case SCE_PL_HERE_QX : levelCurrent--; break; default : //do nothing; break; } break; } //explicit folding if (options.foldCommentExplicit && style == SCE_PL_COMMENTLINE && ch == '#') { if (chNext == '{') { levelCurrent++; } else if (levelCurrent > SC_FOLDLEVELBASE && chNext == '}') { levelCurrent--; } } if (atEOL) { int lev = levelPrev; // POD headings occupy bits 7-4, leaving some breathing room for // non-standard practice -- POD sections stuck in blocks, etc. if (podHeading > 0) { levelCurrent = (lev & ~PERL_HEADFOLD_MASK) | (podHeading << PERL_HEADFOLD_SHIFT); lev = levelCurrent - 1; lev |= SC_FOLDLEVELHEADERFLAG; podHeading = 0; } // Check if line was a package declaration // because packages need "special" treatment if (isPackageLine) { lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; levelCurrent = SC_FOLDLEVELBASE + 1; isPackageLine = false; } lev |= levelCurrent << 16; if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; chPrev = ch; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } LexerModule lmPerl(SCLEX_PERL, LexerPerl::LexerFactoryPerl, "perl", perlWordListDesc, 8); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexPowerShell.cxx0000644000175000017500000001400211615412040022401 00000000000000// Scintilla source code edit control /** @file LexPowerShell.cxx ** Lexer for PowerShell scripts. **/ // Copyright 2008 by Tim Gerundt // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Extended to accept accented characters static inline bool IsAWordChar(int ch) { return ch >= 0x80 || isalnum(ch) || ch == '-' || ch == '_'; } static void ColourisePowerShellDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; WordList &keywords5 = *keywordlists[4]; styler.StartAt(startPos); StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.state == SCE_POWERSHELL_COMMENT) { if (sc.atLineEnd) { sc.SetState(SCE_POWERSHELL_DEFAULT); } } else if (sc.state == SCE_POWERSHELL_COMMENTSTREAM) { if (sc.ch == '>' && sc.chPrev == '#') { sc.ForwardSetState(SCE_POWERSHELL_DEFAULT); } } else if (sc.state == SCE_POWERSHELL_STRING) { // This is a doubles quotes string if (sc.ch == '\"') { sc.ForwardSetState(SCE_POWERSHELL_DEFAULT); } } else if (sc.state == SCE_POWERSHELL_CHARACTER) { // This is a single quote string if (sc.ch == '\'') { sc.ForwardSetState(SCE_POWERSHELL_DEFAULT); } } else if (sc.state == SCE_POWERSHELL_NUMBER) { if (!IsADigit(sc.ch)) { sc.SetState(SCE_POWERSHELL_DEFAULT); } } else if (sc.state == SCE_POWERSHELL_VARIABLE) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_POWERSHELL_DEFAULT); } } else if (sc.state == SCE_POWERSHELL_OPERATOR) { if (!isoperator(static_cast(sc.ch))) { sc.SetState(SCE_POWERSHELL_DEFAULT); } } else if (sc.state == SCE_POWERSHELL_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_POWERSHELL_KEYWORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_POWERSHELL_CMDLET); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_POWERSHELL_ALIAS); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_POWERSHELL_FUNCTION); } else if (keywords5.InList(s)) { sc.ChangeState(SCE_POWERSHELL_USER1); } sc.SetState(SCE_POWERSHELL_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_POWERSHELL_DEFAULT) { if (sc.ch == '#') { sc.SetState(SCE_POWERSHELL_COMMENT); } else if (sc.ch == '<' && sc.chNext == '#') { sc.SetState(SCE_POWERSHELL_COMMENTSTREAM); } else if (sc.ch == '\"') { sc.SetState(SCE_POWERSHELL_STRING); } else if (sc.ch == '\'') { sc.SetState(SCE_POWERSHELL_CHARACTER); } else if (sc.ch == '$') { sc.SetState(SCE_POWERSHELL_VARIABLE); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_POWERSHELL_NUMBER); } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_POWERSHELL_OPERATOR); } else if (IsAWordChar(sc.ch)) { sc.SetState(SCE_POWERSHELL_IDENTIFIER); } } } sc.Complete(); } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". static void FoldPowerShellDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_POWERSHELL_OPERATOR) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (ch == '}') { levelNext--; } } else if (foldComment && style == SCE_POWERSHELL_COMMENTSTREAM) { if (stylePrev != SCE_POWERSHELL_COMMENTSTREAM) { levelNext++; } else if (styleNext != SCE_POWERSHELL_COMMENTSTREAM) { levelNext--; } } if (!IsASpace(ch)) visibleChars++; if (atEOL || (i == endPos-1)) { int levelUse = levelCurrent; if (foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; visibleChars = 0; } } } static const char * const powershellWordLists[] = { "Commands", "Cmdlets", "Aliases", "Functions", "User1", 0 }; LexerModule lmPowerShell(SCLEX_POWERSHELL, ColourisePowerShellDoc, "powershell", FoldPowerShellDoc, powershellWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexProgress.cxx0000644000175000017500000002161211615412040022126 00000000000000// Scintilla source code edit control /** @file LexProgress.cxx ** Lexer for Progress 4GL. ** Based on LexCPP.cxx of Neil Hodgson **/ // Copyright 2006-2007 by Yuval Papish // The License.txt file describes the conditions under which this software may be distributed. /** TODO: WebSpeed support in html lexer Support "end triggers" expression of the triggers phrase Support more than 6 comments levels **/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAWordStart(int ch) { return (ch < 0x80) && (isalpha(ch) || ch == '_'); } enum SentenceStart { SetSentenceStart = 0xf, ResetSentenceStart = 0x10}; // true -> bit = 0 static void Colourise4glDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords1 = *keywordlists[0]; // regular keywords WordList &keywords2 = *keywordlists[1]; // block opening keywords, only when SentenceStart WordList &keywords3 = *keywordlists[2]; // block opening keywords //WordList &keywords4 = *keywordlists[3]; // preprocessor keywords. Not implemented int visibleChars = 0; int mask; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineStart) { // Reset states to begining of colourise so no surprises // if different sets of lines lexed. visibleChars = 0; } // Handle line continuation generically. if ((sc.state & 0xf) < SCE_4GL_COMMENT1) { if (sc.ch == '~') { if (sc.chNext > ' ') { // skip special char after ~ sc.Forward(); continue; } else { // Skip whitespace between ~ and EOL while (sc.More() && (sc.chNext == ' ' || sc.chNext == '\t') ) { sc.Forward(); } if (sc.chNext == '\n' || sc.chNext == '\r') { sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } sc.Forward(); continue; } } } } // Determine if a new state should be terminated. mask = sc.state & 0x10; switch (sc.state & 0xf) { case SCE_4GL_OPERATOR: sc.SetState(SCE_4GL_DEFAULT | mask); break; case SCE_4GL_NUMBER: if (!(IsADigit(sc.ch))) { sc.SetState(SCE_4GL_DEFAULT | mask); } break; case SCE_4GL_IDENTIFIER: if (!IsAWordChar(sc.ch) && sc.ch != '-') { char s[1000]; sc.GetCurrentLowered(s, sizeof(s)); if ((((sc.state & 0x10) == 0) && keywords2.InList(s)) || keywords3.InList(s)) { sc.ChangeState(SCE_4GL_BLOCK | ResetSentenceStart); } else if (keywords1.InList(s)) { if ((s[0] == 'e' && s[1] =='n' && s[2] == 'd' && !isalnum(s[3]) && s[3] != '-') || (s[0] == 'f' && s[1] =='o' && s[2] == 'r' && s[3] == 'w' && s[4] =='a' && s[5] == 'r' && s[6] == 'd'&& !isalnum(s[7]))) { sc.ChangeState(SCE_4GL_END | ResetSentenceStart); } else if ((s[0] == 'e' && s[1] =='l' && s[2] == 's' && s[3] == 'e') || (s[0] == 't' && s[1] =='h' && s[2] == 'e' && s[3] == 'n')) { sc.ChangeState(SCE_4GL_WORD & SetSentenceStart); } else { sc.ChangeState(SCE_4GL_WORD | ResetSentenceStart); } } sc.SetState(SCE_4GL_DEFAULT | (sc.state & 0x10)); } break; case SCE_4GL_PREPROCESSOR: if (sc.atLineStart) { sc.SetState(SCE_4GL_DEFAULT & SetSentenceStart); } /* code removed to allow comments inside preprocessor else if (sc.ch == '*' && sc.chNext == '/') { sc.ForwardSetState(SCE_4GL_DEFAULT | sentenceStartState); } */ break; case SCE_4GL_STRING: if (sc.ch == '\"') { sc.ForwardSetState(SCE_4GL_DEFAULT | mask); } break; case SCE_4GL_CHARACTER: if (sc.ch == '\'') { sc.ForwardSetState(SCE_4GL_DEFAULT | mask); } break; default: if ((sc.state & 0xf) >= SCE_4GL_COMMENT1) { if (sc.ch == '*' && sc.chNext == '/') { sc.Forward(); if ((sc.state & 0xf) == SCE_4GL_COMMENT1) { sc.ForwardSetState(SCE_4GL_DEFAULT | mask); } else sc.SetState((sc.state & 0x1f) - 1); } else if (sc.ch == '/' && sc.chNext == '*') { sc.Forward(); sc.SetState((sc.state & 0x1f) + 1); } } } // Determine if a new state should be entered. mask = sc.state & 0x10; if ((sc.state & 0xf) == SCE_4GL_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_4GL_NUMBER | ResetSentenceStart); } else if (IsAWordStart(sc.ch) || (sc.ch == '@')) { sc.SetState(SCE_4GL_IDENTIFIER | mask); } else if (sc.ch == '/' && sc.chNext == '*') { sc.SetState(SCE_4GL_COMMENT1 | mask); sc.Forward(); } else if (sc.ch == '\"') { sc.SetState(SCE_4GL_STRING | ResetSentenceStart); } else if (sc.ch == '\'') { sc.SetState(SCE_4GL_CHARACTER | ResetSentenceStart); } else if (sc.ch == '&' && visibleChars == 0 && ((sc.state & 0x10) == 0)) { sc.SetState(SCE_4GL_PREPROCESSOR | ResetSentenceStart); // Skip whitespace between & and preprocessor word do { sc.Forward(); } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); // Handle syntactical line termination } else if ((sc.ch == '.' || sc.ch == ':' || sc.ch == '}') && (sc.chNext == ' ' || sc.chNext == '\t' || sc.chNext == '\n' || sc.chNext == '\r')) { sc.SetState(sc.state & SetSentenceStart); } else if (isoperator(static_cast(sc.ch))) { /* This code allows highlight of handles. Alas, it would cause the phrase "last-event:function" to be recognized as a BlockBegin */ if (sc.ch == ':') sc.SetState(SCE_4GL_OPERATOR & SetSentenceStart); /* else */ sc.SetState(SCE_4GL_OPERATOR | ResetSentenceStart); } } if (!IsASpace(sc.ch)) { visibleChars++; } } sc.Complete(); } static bool IsStreamCommentStyle(int style) { return (style & 0xf) >= SCE_4GL_COMMENT1 ; } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". static void FoldNoBox4glDoc(unsigned int startPos, int length, int initStyle, Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = static_cast(tolower(styler[startPos])); int styleNext = styler.StyleAt(startPos); int style = initStyle; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = static_cast(tolower(styler.SafeGetCharAt(i + 1))); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext)) { // && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelNext--; } } else if ((style & 0xf) == SCE_4GL_BLOCK && !isalnum(chNext)) { levelNext++; } else if ((style & 0xf) == SCE_4GL_END && (ch == 'e' || ch == 'f')) { levelNext--; } if (atEOL) { int levelUse = levelCurrent; if (foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } } static void Fold4glDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { FoldNoBox4glDoc(startPos, length, initStyle, styler); } static const char * const FglWordLists[] = { "Primary keywords and identifiers", "Secondary keywords and identifiers", "Documentation comment keywords", "Unused", "Global classes and typedefs", 0, }; LexerModule lmProgress(SCLEX_PROGRESS, Colourise4glDoc, "progress", Fold4glDoc, FglWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexR.cxx0000644000175000017500000001416511615412040020530 00000000000000// Scintilla source code edit control /** @file Lexr.cxx ** Lexer for R, S, SPlus Statistics Program (Heavily derived from CPP Lexer). ** **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAnOperator(const int ch) { if (isascii(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '-' || ch == '+' || ch == '!' || ch == '~' || ch == '?' || ch == ':' || ch == '*' || ch == '/' || ch == '^' || ch == '<' || ch == '>' || ch == '=' || ch == '&' || ch == '|' || ch == '$' || ch == '(' || ch == ')' || ch == '}' || ch == '{' || ch == '[' || ch == ']') return true; return false; } static void ColouriseRDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; // Do not leak onto next line if (initStyle == SCE_R_INFIXEOL) initStyle = SCE_R_DEFAULT; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineStart && (sc.state == SCE_R_STRING)) { // Prevent SCE_R_STRINGEOL from leaking back to previous line sc.SetState(SCE_R_STRING); } // Determine if the current state should terminate. if (sc.state == SCE_R_OPERATOR) { sc.SetState(SCE_R_DEFAULT); } else if (sc.state == SCE_R_NUMBER) { if (!IsADigit(sc.ch) && !(sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_R_DEFAULT); } } else if (sc.state == SCE_R_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_R_KWORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_R_BASEKWORD); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_R_OTHERKWORD); } sc.SetState(SCE_R_DEFAULT); } } else if (sc.state == SCE_R_COMMENT) { if (sc.ch == '\r' || sc.ch == '\n') { sc.SetState(SCE_R_DEFAULT); } } else if (sc.state == SCE_R_STRING) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_R_DEFAULT); } } else if (sc.state == SCE_R_INFIX) { if (sc.ch == '%') { sc.ForwardSetState(SCE_R_DEFAULT); } else if (sc.atLineEnd) { sc.ChangeState(SCE_R_INFIXEOL); sc.ForwardSetState(SCE_R_DEFAULT); } }else if (sc.state == SCE_R_STRING2) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_R_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_R_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_R_NUMBER); } else if (IsAWordStart(sc.ch) ) { sc.SetState(SCE_R_IDENTIFIER); } else if (sc.Match('#')) { sc.SetState(SCE_R_COMMENT); } else if (sc.ch == '\"') { sc.SetState(SCE_R_STRING); } else if (sc.ch == '%') { sc.SetState(SCE_R_INFIX); } else if (sc.ch == '\'') { sc.SetState(SCE_R_STRING2); } else if (IsAnOperator(sc.ch)) { sc.SetState(SCE_R_OPERATOR); } } } sc.Complete(); } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". static void FoldRDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_R_OPERATOR) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (ch == '}') { levelNext--; } } if (atEOL) { int levelUse = levelCurrent; if (foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } } static const char * const RWordLists[] = { "Language Keywords", "Base / Default package function", "Other Package Functions", "Unused", "Unused", 0, }; LexerModule lmR(SCLEX_R, ColouriseRDoc, "r", FoldRDoc, RWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexCmake.cxx0000644000175000017500000003663211615412040021352 00000000000000// Scintilla source code edit control /** @file LexCmake.cxx ** Lexer for Cmake **/ // Copyright 2007 by Cristian Adam // based on the NSIS lexer // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static bool isCmakeNumber(char ch) { return(ch >= '0' && ch <= '9'); } static bool isCmakeChar(char ch) { return(ch == '.' ) || (ch == '_' ) || isCmakeNumber(ch) || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } static bool isCmakeLetter(char ch) { return(ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } static bool CmakeNextLineHasElse(unsigned int start, unsigned int end, Accessor &styler) { int nNextLine = -1; for ( unsigned int i = start; i < end; i++ ) { char cNext = styler.SafeGetCharAt( i ); if ( cNext == '\n' ) { nNextLine = i+1; break; } } if ( nNextLine == -1 ) // We never foudn the next line... return false; for ( unsigned int firstChar = nNextLine; firstChar < end; firstChar++ ) { char cNext = styler.SafeGetCharAt( firstChar ); if ( cNext == ' ' ) continue; if ( cNext == '\t' ) continue; if ( styler.Match(firstChar, "ELSE") || styler.Match(firstChar, "else")) return true; break; } return false; } static int calculateFoldCmake(unsigned int start, unsigned int end, int foldlevel, Accessor &styler, bool bElse) { // If the word is too long, it is not what we are looking for if ( end - start > 20 ) return foldlevel; int newFoldlevel = foldlevel; char s[20]; // The key word we are looking for has atmost 13 characters for (unsigned int i = 0; i < end - start + 1 && i < 19; i++) { s[i] = static_cast( styler[ start + i ] ); s[i + 1] = '\0'; } if ( CompareCaseInsensitive(s, "IF") == 0 || CompareCaseInsensitive(s, "WHILE") == 0 || CompareCaseInsensitive(s, "MACRO") == 0 || CompareCaseInsensitive(s, "FOREACH") == 0 || CompareCaseInsensitive(s, "ELSEIF") == 0 ) newFoldlevel++; else if ( CompareCaseInsensitive(s, "ENDIF") == 0 || CompareCaseInsensitive(s, "ENDWHILE") == 0 || CompareCaseInsensitive(s, "ENDMACRO") == 0 || CompareCaseInsensitive(s, "ENDFOREACH") == 0) newFoldlevel--; else if ( bElse && CompareCaseInsensitive(s, "ELSEIF") == 0 ) newFoldlevel++; else if ( bElse && CompareCaseInsensitive(s, "ELSE") == 0 ) newFoldlevel++; return newFoldlevel; } static int classifyWordCmake(unsigned int start, unsigned int end, WordList *keywordLists[], Accessor &styler ) { char word[100] = {0}; char lowercaseWord[100] = {0}; WordList &Commands = *keywordLists[0]; WordList &Parameters = *keywordLists[1]; WordList &UserDefined = *keywordLists[2]; for (unsigned int i = 0; i < end - start + 1 && i < 99; i++) { word[i] = static_cast( styler[ start + i ] ); lowercaseWord[i] = static_cast(tolower(word[i])); } // Check for special words... if ( CompareCaseInsensitive(word, "MACRO") == 0 || CompareCaseInsensitive(word, "ENDMACRO") == 0 ) return SCE_CMAKE_MACRODEF; if ( CompareCaseInsensitive(word, "IF") == 0 || CompareCaseInsensitive(word, "ENDIF") == 0 ) return SCE_CMAKE_IFDEFINEDEF; if ( CompareCaseInsensitive(word, "ELSEIF") == 0 || CompareCaseInsensitive(word, "ELSE") == 0 ) return SCE_CMAKE_IFDEFINEDEF; if ( CompareCaseInsensitive(word, "WHILE") == 0 || CompareCaseInsensitive(word, "ENDWHILE") == 0) return SCE_CMAKE_WHILEDEF; if ( CompareCaseInsensitive(word, "FOREACH") == 0 || CompareCaseInsensitive(word, "ENDFOREACH") == 0) return SCE_CMAKE_FOREACHDEF; if ( Commands.InList(lowercaseWord) ) return SCE_CMAKE_COMMANDS; if ( Parameters.InList(word) ) return SCE_CMAKE_PARAMETERS; if ( UserDefined.InList(word) ) return SCE_CMAKE_USERDEFINED; if ( strlen(word) > 3 ) { if ( word[1] == '{' && word[strlen(word)-1] == '}' ) return SCE_CMAKE_VARIABLE; } // To check for numbers if ( isCmakeNumber( word[0] ) ) { bool bHasSimpleCmakeNumber = true; for (unsigned int j = 1; j < end - start + 1 && j < 99; j++) { if ( !isCmakeNumber( word[j] ) ) { bHasSimpleCmakeNumber = false; break; } } if ( bHasSimpleCmakeNumber ) return SCE_CMAKE_NUMBER; } return SCE_CMAKE_DEFAULT; } static void ColouriseCmakeDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler) { int state = SCE_CMAKE_DEFAULT; if ( startPos > 0 ) state = styler.StyleAt(startPos-1); // Use the style from the previous line, usually default, but could be commentbox styler.StartAt( startPos ); styler.GetLine( startPos ); unsigned int nLengthDoc = startPos + length; styler.StartSegment( startPos ); char cCurrChar; bool bVarInString = false; bool bClassicVarInString = false; unsigned int i; for ( i = startPos; i < nLengthDoc; i++ ) { cCurrChar = styler.SafeGetCharAt( i ); char cNextChar = styler.SafeGetCharAt(i+1); switch (state) { case SCE_CMAKE_DEFAULT: if ( cCurrChar == '#' ) { // we have a comment line styler.ColourTo(i-1, state ); state = SCE_CMAKE_COMMENT; break; } if ( cCurrChar == '"' ) { styler.ColourTo(i-1, state ); state = SCE_CMAKE_STRINGDQ; bVarInString = false; bClassicVarInString = false; break; } if ( cCurrChar == '\'' ) { styler.ColourTo(i-1, state ); state = SCE_CMAKE_STRINGRQ; bVarInString = false; bClassicVarInString = false; break; } if ( cCurrChar == '`' ) { styler.ColourTo(i-1, state ); state = SCE_CMAKE_STRINGLQ; bVarInString = false; bClassicVarInString = false; break; } // CMake Variable if ( cCurrChar == '$' || isCmakeChar(cCurrChar)) { styler.ColourTo(i-1,state); state = SCE_CMAKE_VARIABLE; // If it is a number, we must check and set style here first... if ( isCmakeNumber(cCurrChar) && (cNextChar == '\t' || cNextChar == ' ' || cNextChar == '\r' || cNextChar == '\n' ) ) styler.ColourTo( i, SCE_CMAKE_NUMBER); break; } break; case SCE_CMAKE_COMMENT: if ( cNextChar == '\n' || cNextChar == '\r' ) { // Special case: if ( cCurrChar == '\\' ) { styler.ColourTo(i-2,state); styler.ColourTo(i,SCE_CMAKE_DEFAULT); } else { styler.ColourTo(i,state); state = SCE_CMAKE_DEFAULT; } } break; case SCE_CMAKE_STRINGDQ: case SCE_CMAKE_STRINGLQ: case SCE_CMAKE_STRINGRQ: if ( styler.SafeGetCharAt(i-1) == '\\' && styler.SafeGetCharAt(i-2) == '$' ) break; // Ignore the next character, even if it is a quote of some sort if ( cCurrChar == '"' && state == SCE_CMAKE_STRINGDQ ) { styler.ColourTo(i,state); state = SCE_CMAKE_DEFAULT; break; } if ( cCurrChar == '`' && state == SCE_CMAKE_STRINGLQ ) { styler.ColourTo(i,state); state = SCE_CMAKE_DEFAULT; break; } if ( cCurrChar == '\'' && state == SCE_CMAKE_STRINGRQ ) { styler.ColourTo(i,state); state = SCE_CMAKE_DEFAULT; break; } if ( cNextChar == '\r' || cNextChar == '\n' ) { int nCurLine = styler.GetLine(i+1); int nBack = i; // We need to check if the previous line has a \ in it... bool bNextLine = false; while ( nBack > 0 ) { if ( styler.GetLine(nBack) != nCurLine ) break; char cTemp = styler.SafeGetCharAt(nBack, 'a'); // Letter 'a' is safe here if ( cTemp == '\\' ) { bNextLine = true; break; } if ( cTemp != '\r' && cTemp != '\n' && cTemp != '\t' && cTemp != ' ' ) break; nBack--; } if ( bNextLine ) { styler.ColourTo(i+1,state); } if ( bNextLine == false ) { styler.ColourTo(i,state); state = SCE_CMAKE_DEFAULT; } } break; case SCE_CMAKE_VARIABLE: // CMake Variable: if ( cCurrChar == '$' ) state = SCE_CMAKE_DEFAULT; else if ( cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' ) ) state = SCE_CMAKE_DEFAULT; else if ( (isCmakeChar(cCurrChar) && !isCmakeChar( cNextChar) && cNextChar != '}') || cCurrChar == '}' ) { state = classifyWordCmake( styler.GetStartSegment(), i, keywordLists, styler ); styler.ColourTo( i, state); state = SCE_CMAKE_DEFAULT; } else if ( !isCmakeChar( cCurrChar ) && cCurrChar != '{' && cCurrChar != '}' ) { if ( classifyWordCmake( styler.GetStartSegment(), i-1, keywordLists, styler) == SCE_CMAKE_NUMBER ) styler.ColourTo( i-1, SCE_CMAKE_NUMBER ); state = SCE_CMAKE_DEFAULT; if ( cCurrChar == '"' ) { state = SCE_CMAKE_STRINGDQ; bVarInString = false; bClassicVarInString = false; } else if ( cCurrChar == '`' ) { state = SCE_CMAKE_STRINGLQ; bVarInString = false; bClassicVarInString = false; } else if ( cCurrChar == '\'' ) { state = SCE_CMAKE_STRINGRQ; bVarInString = false; bClassicVarInString = false; } else if ( cCurrChar == '#' ) { state = SCE_CMAKE_COMMENT; } } break; } if ( state == SCE_CMAKE_COMMENT) { styler.ColourTo(i,state); } else if ( state == SCE_CMAKE_STRINGDQ || state == SCE_CMAKE_STRINGLQ || state == SCE_CMAKE_STRINGRQ ) { bool bIngoreNextDollarSign = false; if ( bVarInString && cCurrChar == '$' ) { bVarInString = false; bIngoreNextDollarSign = true; } else if ( bVarInString && cCurrChar == '\\' && (cNextChar == 'n' || cNextChar == 'r' || cNextChar == 't' || cNextChar == '"' || cNextChar == '`' || cNextChar == '\'' ) ) { styler.ColourTo( i+1, SCE_CMAKE_STRINGVAR); bVarInString = false; bIngoreNextDollarSign = false; } else if ( bVarInString && !isCmakeChar(cNextChar) ) { int nWordState = classifyWordCmake( styler.GetStartSegment(), i, keywordLists, styler); if ( nWordState == SCE_CMAKE_VARIABLE ) styler.ColourTo( i, SCE_CMAKE_STRINGVAR); bVarInString = false; } // Covers "${TEST}..." else if ( bClassicVarInString && cNextChar == '}' ) { styler.ColourTo( i+1, SCE_CMAKE_STRINGVAR); bClassicVarInString = false; } // Start of var in string if ( !bIngoreNextDollarSign && cCurrChar == '$' && cNextChar == '{' ) { styler.ColourTo( i-1, state); bClassicVarInString = true; bVarInString = false; } else if ( !bIngoreNextDollarSign && cCurrChar == '$' ) { styler.ColourTo( i-1, state); bVarInString = true; bClassicVarInString = false; } } } // Colourise remaining document styler.ColourTo(nLengthDoc-1,state); } static void FoldCmakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { // No folding enabled, no reason to continue... if ( styler.GetPropertyInt("fold") == 0 ) return; bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) == 1; int lineCurrent = styler.GetLine(startPos); unsigned int safeStartPos = styler.LineStart( lineCurrent ); bool bArg1 = true; int nWordStart = -1; int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelNext = levelCurrent; for (unsigned int i = safeStartPos; i < startPos + length; i++) { char chCurr = styler.SafeGetCharAt(i); if ( bArg1 ) { if ( nWordStart == -1 && (isCmakeLetter(chCurr)) ) { nWordStart = i; } else if ( isCmakeLetter(chCurr) == false && nWordStart > -1 ) { int newLevel = calculateFoldCmake( nWordStart, i-1, levelNext, styler, foldAtElse); if ( newLevel == levelNext ) { if ( foldAtElse ) { if ( CmakeNextLineHasElse(i, startPos + length, styler) ) levelNext--; } } else levelNext = newLevel; bArg1 = false; } } if ( chCurr == '\n' ) { if ( bArg1 && foldAtElse) { if ( CmakeNextLineHasElse(i, startPos + length, styler) ) levelNext--; } // If we are on a new line... int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (levelUse < levelNext ) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); lineCurrent++; levelCurrent = levelNext; bArg1 = true; // New line, lets look at first argument again nWordStart = -1; } } int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); } static const char * const cmakeWordLists[] = { "Commands", "Parameters", "UserDefined", 0, 0,}; LexerModule lmCmake(SCLEX_CMAKE, ColouriseCmakeDoc, "cmake", FoldCmakeDoc, cmakeWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexAda.cxx0000644000175000017500000002751611660423551021031 00000000000000// Scintilla source code edit control /** @file LexAda.cxx ** Lexer for Ada 95 **/ // Copyright 2002 by Sergey Koshcheyev // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /* * Interface */ static void ColouriseDocument( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler); static const char * const adaWordListDesc[] = { "Keywords", 0 }; LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc); /* * Implementation */ // Functions that have apostropheStartsAttribute as a parameter set it according to whether // an apostrophe encountered after processing the current token will start an attribute or // a character literal. static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL); static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute); static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute); static inline bool IsDelimiterCharacter(int ch); static inline bool IsNumberStartCharacter(int ch); static inline bool IsNumberCharacter(int ch); static inline bool IsSeparatorOrDelimiterCharacter(int ch); static bool IsValidIdentifier(const std::string& identifier); static bool IsValidNumber(const std::string& number); static inline bool IsWordStartCharacter(int ch); static inline bool IsWordCharacter(int ch); static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) { apostropheStartsAttribute = true; sc.SetState(SCE_ADA_CHARACTER); // Skip the apostrophe and one more character (so that '' is shown as non-terminated and ''' // is handled correctly) sc.Forward(); sc.Forward(); ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL); } static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) { while (!sc.atLineEnd && !sc.Match(chEnd)) { sc.Forward(); } if (!sc.atLineEnd) { sc.ForwardSetState(SCE_ADA_DEFAULT); } else { sc.ChangeState(stateEOL); } } static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) { // Apostrophe meaning is not changed, but the parameter is present for uniformity sc.SetState(SCE_ADA_COMMENTLINE); while (!sc.atLineEnd) { sc.Forward(); } } static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) { apostropheStartsAttribute = sc.Match (')'); sc.SetState(SCE_ADA_DELIMITER); sc.ForwardSetState(SCE_ADA_DEFAULT); } static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) { apostropheStartsAttribute = false; sc.SetState(SCE_ADA_LABEL); // Skip "<<" sc.Forward(); sc.Forward(); std::string identifier; while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) { identifier += static_cast(tolower(sc.ch)); sc.Forward(); } // Skip ">>" if (sc.Match('>', '>')) { sc.Forward(); sc.Forward(); } else { sc.ChangeState(SCE_ADA_ILLEGAL); } // If the name is an invalid identifier or a keyword, then make it invalid label if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) { sc.ChangeState(SCE_ADA_ILLEGAL); } sc.SetState(SCE_ADA_DEFAULT); } static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) { apostropheStartsAttribute = true; std::string number; sc.SetState(SCE_ADA_NUMBER); // Get all characters up to a delimiter or a separator, including points, but excluding // double points (ranges). while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) { number += static_cast(sc.ch); sc.Forward(); } // Special case: exponent with sign if ((sc.chPrev == 'e' || sc.chPrev == 'E') && (sc.ch == '+' || sc.ch == '-')) { number += static_cast(sc.ch); sc.Forward (); while (!IsSeparatorOrDelimiterCharacter(sc.ch)) { number += static_cast(sc.ch); sc.Forward(); } } if (!IsValidNumber(number)) { sc.ChangeState(SCE_ADA_ILLEGAL); } sc.SetState(SCE_ADA_DEFAULT); } static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) { apostropheStartsAttribute = true; sc.SetState(SCE_ADA_STRING); sc.Forward(); ColouriseContext(sc, '"', SCE_ADA_STRINGEOL); } static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) { // Apostrophe meaning is not changed, but the parameter is present for uniformity sc.SetState(SCE_ADA_DEFAULT); sc.ForwardSetState(SCE_ADA_DEFAULT); } static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) { apostropheStartsAttribute = true; sc.SetState(SCE_ADA_IDENTIFIER); std::string word; while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) { word += static_cast(tolower(sc.ch)); sc.Forward(); } if (!IsValidIdentifier(word)) { sc.ChangeState(SCE_ADA_ILLEGAL); } else if (keywords.InList(word.c_str())) { sc.ChangeState(SCE_ADA_WORD); if (word != "all") { apostropheStartsAttribute = false; } } sc.SetState(SCE_ADA_DEFAULT); } // // ColouriseDocument // static void ColouriseDocument( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; StyleContext sc(startPos, length, initStyle, styler); int lineCurrent = styler.GetLine(startPos); bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0; while (sc.More()) { if (sc.atLineEnd) { // Go to the next line sc.Forward(); lineCurrent++; // Remember the line state for future incremental lexing styler.SetLineState(lineCurrent, apostropheStartsAttribute); // Don't continue any styles on the next line sc.SetState(SCE_ADA_DEFAULT); } // Comments if (sc.Match('-', '-')) { ColouriseComment(sc, apostropheStartsAttribute); // Strings } else if (sc.Match('"')) { ColouriseString(sc, apostropheStartsAttribute); // Characters } else if (sc.Match('\'') && !apostropheStartsAttribute) { ColouriseCharacter(sc, apostropheStartsAttribute); // Labels } else if (sc.Match('<', '<')) { ColouriseLabel(sc, keywords, apostropheStartsAttribute); // Whitespace } else if (IsASpace(sc.ch)) { ColouriseWhiteSpace(sc, apostropheStartsAttribute); // Delimiters } else if (IsDelimiterCharacter(sc.ch)) { ColouriseDelimiter(sc, apostropheStartsAttribute); // Numbers } else if (IsADigit(sc.ch) || sc.ch == '#') { ColouriseNumber(sc, apostropheStartsAttribute); // Keywords or identifiers } else { ColouriseWord(sc, keywords, apostropheStartsAttribute); } } sc.Complete(); } static inline bool IsDelimiterCharacter(int ch) { switch (ch) { case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '|': return true; default: return false; } } static inline bool IsNumberCharacter(int ch) { return IsNumberStartCharacter(ch) || ch == '_' || ch == '.' || ch == '#' || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); } static inline bool IsNumberStartCharacter(int ch) { return IsADigit(ch); } static inline bool IsSeparatorOrDelimiterCharacter(int ch) { return IsASpace(ch) || IsDelimiterCharacter(ch); } static bool IsValidIdentifier(const std::string& identifier) { // First character can't be '_', so initialize the flag to true bool lastWasUnderscore = true; size_t length = identifier.length(); // Zero-length identifiers are not valid (these can occur inside labels) if (length == 0) { return false; } // Check for valid character at the start if (!IsWordStartCharacter(identifier[0])) { return false; } // Check for only valid characters and no double underscores for (size_t i = 0; i < length; i++) { if (!IsWordCharacter(identifier[i]) || (identifier[i] == '_' && lastWasUnderscore)) { return false; } lastWasUnderscore = identifier[i] == '_'; } // Check for underscore at the end if (lastWasUnderscore == true) { return false; } // All checks passed return true; } static bool IsValidNumber(const std::string& number) { size_t hashPos = number.find("#"); bool seenDot = false; size_t i = 0; size_t length = number.length(); if (length == 0) return false; // Just in case // Decimal number if (hashPos == std::string::npos) { bool canBeSpecial = false; for (; i < length; i++) { if (number[i] == '_') { if (!canBeSpecial) { return false; } canBeSpecial = false; } else if (number[i] == '.') { if (!canBeSpecial || seenDot) { return false; } canBeSpecial = false; seenDot = true; } else if (IsADigit(number[i])) { canBeSpecial = true; } else { break; } } if (!canBeSpecial) return false; } else { // Based number bool canBeSpecial = false; int base = 0; // Parse base for (; i < length; i++) { int ch = number[i]; if (ch == '_') { if (!canBeSpecial) return false; canBeSpecial = false; } else if (IsADigit(ch)) { base = base * 10 + (ch - '0'); if (base > 16) return false; canBeSpecial = true; } else if (ch == '#' && canBeSpecial) { break; } else { return false; } } if (base < 2) return false; if (i == length) return false; i++; // Skip over '#' // Parse number canBeSpecial = false; for (; i < length; i++) { int ch = tolower(number[i]); if (ch == '_') { if (!canBeSpecial) { return false; } canBeSpecial = false; } else if (ch == '.') { if (!canBeSpecial || seenDot) { return false; } canBeSpecial = false; seenDot = true; } else if (IsADigit(ch)) { if (ch - '0' >= base) { return false; } canBeSpecial = true; } else if (ch >= 'a' && ch <= 'f') { if (ch - 'a' + 10 >= base) { return false; } canBeSpecial = true; } else if (ch == '#' && canBeSpecial) { break; } else { return false; } } if (i == length) { return false; } i++; } // Exponent (optional) if (i < length) { if (number[i] != 'e' && number[i] != 'E') return false; i++; // Move past 'E' if (i == length) { return false; } if (number[i] == '+') i++; else if (number[i] == '-') { if (seenDot) { i++; } else { return false; // Integer literals should not have negative exponents } } if (i == length) { return false; } bool canBeSpecial = false; for (; i < length; i++) { if (number[i] == '_') { if (!canBeSpecial) { return false; } canBeSpecial = false; } else if (IsADigit(number[i])) { canBeSpecial = true; } else { return false; } } if (!canBeSpecial) return false; } // if i == length, number was parsed successfully. return i == length; } static inline bool IsWordCharacter(int ch) { return IsWordStartCharacter(ch) || IsADigit(ch); } static inline bool IsWordStartCharacter(int ch) { return (isascii(ch) && isalpha(ch)) || ch == '_'; } presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexEScript.cxx0000644000175000017500000001775711615412040021712 00000000000000// Scintilla source code edit control /** @file LexESCRIPT.cxx ** Lexer for ESCRIPT **/ // Copyright 2003 by Patrizio Bekerle (patrizio@bekerle.com) #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static void ColouriseESCRIPTDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; // Do not leak onto next line /*if (initStyle == SCE_ESCRIPT_STRINGEOL) initStyle = SCE_ESCRIPT_DEFAULT;*/ StyleContext sc(startPos, length, initStyle, styler); bool caseSensitive = styler.GetPropertyInt("escript.case.sensitive", 0) != 0; for (; sc.More(); sc.Forward()) { /*if (sc.atLineStart && (sc.state == SCE_ESCRIPT_STRING)) { // Prevent SCE_ESCRIPT_STRINGEOL from leaking back to previous line sc.SetState(SCE_ESCRIPT_STRING); }*/ // Handle line continuation generically. if (sc.ch == '\\') { if (sc.chNext == '\n' || sc.chNext == '\r') { sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } continue; } } // Determine if the current state should terminate. if (sc.state == SCE_ESCRIPT_OPERATOR || sc.state == SCE_ESCRIPT_BRACE) { sc.SetState(SCE_ESCRIPT_DEFAULT); } else if (sc.state == SCE_ESCRIPT_NUMBER) { if (!IsADigit(sc.ch) || sc.ch != '.') { sc.SetState(SCE_ESCRIPT_DEFAULT); } } else if (sc.state == SCE_ESCRIPT_IDENTIFIER) { if (!IsAWordChar(sc.ch) || (sc.ch == '.')) { char s[100]; if (caseSensitive) { sc.GetCurrent(s, sizeof(s)); } else { sc.GetCurrentLowered(s, sizeof(s)); } // sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_ESCRIPT_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_ESCRIPT_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_ESCRIPT_WORD3); // sc.state = SCE_ESCRIPT_IDENTIFIER; } sc.SetState(SCE_ESCRIPT_DEFAULT); } } else if (sc.state == SCE_ESCRIPT_COMMENT) { if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_ESCRIPT_DEFAULT); } } else if (sc.state == SCE_ESCRIPT_COMMENTDOC) { if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_ESCRIPT_DEFAULT); } } else if (sc.state == SCE_ESCRIPT_COMMENTLINE) { if (sc.atLineEnd) { sc.SetState(SCE_ESCRIPT_DEFAULT); } } else if (sc.state == SCE_ESCRIPT_STRING) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_ESCRIPT_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_ESCRIPT_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_ESCRIPT_NUMBER); } else if (IsAWordStart(sc.ch) || (sc.ch == '#')) { sc.SetState(SCE_ESCRIPT_IDENTIFIER); } else if (sc.Match('/', '*')) { sc.SetState(SCE_ESCRIPT_COMMENT); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { sc.SetState(SCE_ESCRIPT_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_ESCRIPT_STRING); //} else if (isoperator(static_cast(sc.ch))) { } else if (sc.ch == '+' || sc.ch == '-' || sc.ch == '*' || sc.ch == '/' || sc.ch == '=' || sc.ch == '<' || sc.ch == '>' || sc.ch == '&' || sc.ch == '|' || sc.ch == '!' || sc.ch == '?' || sc.ch == ':') { sc.SetState(SCE_ESCRIPT_OPERATOR); } else if (sc.ch == '{' || sc.ch == '}') { sc.SetState(SCE_ESCRIPT_BRACE); } } } sc.Complete(); } static int classifyFoldPointESCRIPT(const char* s, const char* prevWord) { int lev = 0; if (strcmp(prevWord, "end") == 0) return lev; if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "elseif") == 0) return -1; if (strcmp(s, "for") == 0 || strcmp(s, "foreach") == 0 || strcmp(s, "program") == 0 || strcmp(s, "function") == 0 || strcmp(s, "while") == 0 || strcmp(s, "case") == 0 || strcmp(s, "if") == 0 ) { lev = 1; } else if ( strcmp(s, "endfor") == 0 || strcmp(s, "endforeach") == 0 || strcmp(s, "endprogram") == 0 || strcmp(s, "endfunction") == 0 || strcmp(s, "endwhile") == 0 || strcmp(s, "endcase") == 0 || strcmp(s, "endif") == 0 ) { lev = -1; } return lev; } static bool IsStreamCommentStyle(int style) { return style == SCE_ESCRIPT_COMMENT || style == SCE_ESCRIPT_COMMENTDOC || style == SCE_ESCRIPT_COMMENTLINE; } static void FoldESCRIPTDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { //~ bool foldComment = styler.GetPropertyInt("fold.comment") != 0; // Do not know how to fold the comment at the moment. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldComment = true; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; int lastStart = 0; char prevWord[32] = ""; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelCurrent++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelCurrent--; } } if (foldComment && (style == SCE_ESCRIPT_COMMENTLINE)) { if ((ch == '/') && (chNext == '/')) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelCurrent++; } else if (chNext2 == '}') { levelCurrent--; } } } if (stylePrev == SCE_ESCRIPT_DEFAULT && style == SCE_ESCRIPT_WORD3) { // Store last word start point. lastStart = i; } if (style == SCE_ESCRIPT_WORD3) { if(iswordchar(ch) && !iswordchar(chNext)) { char s[32]; unsigned int j; for(j = 0; ( j < 31 ) && ( j < i-lastStart+1 ); j++) { s[j] = static_cast(tolower(styler[lastStart + j])); } s[j] = '\0'; levelCurrent += classifyFoldPointESCRIPT(s, prevWord); strcpy(prevWord, s); } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; strcpy(prevWord, ""); } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const ESCRIPTWordLists[] = { "Primary keywords and identifiers", "Intrinsic functions", "Extended and user defined functions", 0, }; LexerModule lmESCRIPT(SCLEX_ESCRIPT, ColouriseESCRIPTDoc, "escript", FoldESCRIPTDoc, ESCRIPTWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexAVE.cxx0000644000175000017500000001513111615412040020734 00000000000000// SciTE - Scintilla based Text Editor /** @file LexAVE.cxx ** Lexer for Avenue. ** ** Written by Alexey Yutkin . **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_'); } static inline bool IsEnumChar(const int ch) { return (ch < 0x80) && (isalnum(ch)|| ch == '_'); } static inline bool IsANumberChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' ); } inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } inline bool isAveOperator(char ch) { if (isascii(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || ch == '(' || ch == ')' || ch == '=' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == ';' || ch == '<' || ch == '>' || ch == ',' || ch == '.' ) return true; return false; } static void ColouriseAveDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; WordList &keywords5 = *keywordlists[4]; WordList &keywords6 = *keywordlists[5]; // Do not leak onto next line if (initStyle == SCE_AVE_STRINGEOL) { initStyle = SCE_AVE_DEFAULT; } StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineEnd) { // Update the line state, so it can be seen by next line int currentLine = styler.GetLine(sc.currentPos); styler.SetLineState(currentLine, 0); } if (sc.atLineStart && (sc.state == SCE_AVE_STRING)) { // Prevent SCE_AVE_STRINGEOL from leaking back to previous line sc.SetState(SCE_AVE_STRING); } // Determine if the current state should terminate. if (sc.state == SCE_AVE_OPERATOR) { sc.SetState(SCE_AVE_DEFAULT); } else if (sc.state == SCE_AVE_NUMBER) { if (!IsANumberChar(sc.ch)) { sc.SetState(SCE_AVE_DEFAULT); } } else if (sc.state == SCE_AVE_ENUM) { if (!IsEnumChar(sc.ch)) { sc.SetState(SCE_AVE_DEFAULT); } } else if (sc.state == SCE_AVE_IDENTIFIER) { if (!IsAWordChar(sc.ch) || (sc.ch == '.')) { char s[100]; //sc.GetCurrent(s, sizeof(s)); sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_AVE_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_AVE_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_AVE_WORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_AVE_WORD4); } else if (keywords5.InList(s)) { sc.ChangeState(SCE_AVE_WORD5); } else if (keywords6.InList(s)) { sc.ChangeState(SCE_AVE_WORD6); } sc.SetState(SCE_AVE_DEFAULT); } } else if (sc.state == SCE_AVE_COMMENT) { if (sc.atLineEnd) { sc.SetState(SCE_AVE_DEFAULT); } } else if (sc.state == SCE_AVE_STRING) { if (sc.ch == '\"') { sc.ForwardSetState(SCE_AVE_DEFAULT); } else if (sc.atLineEnd) { sc.ChangeState(SCE_AVE_STRINGEOL); sc.ForwardSetState(SCE_AVE_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_AVE_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_AVE_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_AVE_IDENTIFIER); } else if (sc.Match('\"')) { sc.SetState(SCE_AVE_STRING); } else if (sc.Match('\'')) { sc.SetState(SCE_AVE_COMMENT); sc.Forward(); } else if (isAveOperator(static_cast(sc.ch))) { sc.SetState(SCE_AVE_OPERATOR); } else if (sc.Match('#')) { sc.SetState(SCE_AVE_ENUM); sc.Forward(); } } } sc.Complete(); } static void FoldAveDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[], Accessor &styler) { unsigned int lengthDoc = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = static_cast(tolower(styler[startPos])); bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; int styleNext = styler.StyleAt(startPos); char s[10]; for (unsigned int i = startPos; i < lengthDoc; i++) { char ch = static_cast(tolower(chNext)); chNext = static_cast(tolower(styler.SafeGetCharAt(i + 1))); int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_AVE_WORD) { if (ch == 't' || ch == 'f' || ch == 'w' || ch == 'e') { for (unsigned int j = 0; j < 6; j++) { if (!iswordchar(styler[i + j])) { break; } s[j] = static_cast(tolower(styler[i + j])); s[j + 1] = '\0'; } if ((strcmp(s, "then") == 0) || (strcmp(s, "for") == 0) || (strcmp(s, "while") == 0)) { levelCurrent++; } if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) { // Normally "elseif" and "then" will be on the same line and will cancel // each other out. // As implemented, this does not support fold.at.else. levelCurrent--; } } } else if (style == SCE_AVE_OPERATOR) { if (ch == '{' || ch == '(') { levelCurrent++; } else if (ch == '}' || ch == ')') { levelCurrent--; } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) { lev |= SC_FOLDLEVELWHITEFLAG; } if ((levelCurrent > levelPrev) && (visibleChars > 0)) { lev |= SC_FOLDLEVELHEADERFLAG; } if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) { visibleChars++; } } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } LexerModule lmAVE(SCLEX_AVE, ColouriseAveDoc, "ave", FoldAveDoc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexOthers.cxx0000644000175000017500000014222011763437013021600 00000000000000// Scintilla source code edit control /** @file LexOthers.cxx ** Lexers for batch files, diff results, properties files, make files and error lists. ** Also lexer for LaTeX documents. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static bool strstart(const char *haystack, const char *needle) { return strncmp(haystack, needle, strlen(needle)) == 0; } static bool Is0To9(char ch) { return (ch >= '0') && (ch <= '9'); } static bool Is1To9(char ch) { return (ch >= '1') && (ch <= '9'); } static bool IsAlphabetic(int ch) { return isascii(ch) && isalpha(ch); } static inline bool AtEOL(Accessor &styler, unsigned int i) { return (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')); } // Tests for BATCH Operators static bool IsBOperator(char ch) { return (ch == '=') || (ch == '+') || (ch == '>') || (ch == '<') || (ch == '|') || (ch == '?') || (ch == '*'); } // Tests for BATCH Separators static bool IsBSeparator(char ch) { return (ch == '\\') || (ch == '.') || (ch == ';') || (ch == '\"') || (ch == '\'') || (ch == '/'); } static void ColouriseBatchLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, WordList *keywordlists[], Accessor &styler) { unsigned int offset = 0; // Line Buffer Offset unsigned int cmdLoc; // External Command / Program Location char wordBuffer[81]; // Word Buffer - large to catch long paths unsigned int wbl; // Word Buffer Length unsigned int wbo; // Word Buffer Offset - also Special Keyword Buffer Length WordList &keywords = *keywordlists[0]; // Internal Commands WordList &keywords2 = *keywordlists[1]; // External Commands (optional) // CHOICE, ECHO, GOTO, PROMPT and SET have Default Text that may contain Regular Keywords // Toggling Regular Keyword Checking off improves readability // Other Regular Keywords and External Commands / Programs might also benefit from toggling // Need a more robust algorithm to properly toggle Regular Keyword Checking bool continueProcessing = true; // Used to toggle Regular Keyword Checking // Special Keywords are those that allow certain characters without whitespace after the command // Examples are: cd. cd\ md. rd. dir| dir> echo: echo. path= // Special Keyword Buffer used to determine if the first n characters is a Keyword char sKeywordBuffer[10]; // Special Keyword Buffer bool sKeywordFound; // Exit Special Keyword for-loop if found // Skip initial spaces while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { offset++; } // Colorize Default Text styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); // Set External Command / Program Location cmdLoc = offset; // Check for Fake Label (Comment) or Real Label - return if found if (lineBuffer[offset] == ':') { if (lineBuffer[offset + 1] == ':') { // Colorize Fake Label (Comment) - :: is similar to REM, see http://content.techweb.com/winmag/columns/explorer/2000/21.htm styler.ColourTo(endPos, SCE_BAT_COMMENT); } else { // Colorize Real Label styler.ColourTo(endPos, SCE_BAT_LABEL); } return; // Check for Drive Change (Drive Change is internal command) - return if found } else if ((IsAlphabetic(lineBuffer[offset])) && (lineBuffer[offset + 1] == ':') && ((isspacechar(lineBuffer[offset + 2])) || (((lineBuffer[offset + 2] == '\\')) && (isspacechar(lineBuffer[offset + 3]))))) { // Colorize Regular Keyword styler.ColourTo(endPos, SCE_BAT_WORD); return; } // Check for Hide Command (@ECHO OFF/ON) if (lineBuffer[offset] == '@') { styler.ColourTo(startLine + offset, SCE_BAT_HIDE); offset++; } // Skip next spaces while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { offset++; } // Read remainder of line word-at-a-time or remainder-of-word-at-a-time while (offset < lengthLine) { if (offset > startLine) { // Colorize Default Text styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); } // Copy word from Line Buffer into Word Buffer wbl = 0; for (; offset < lengthLine && wbl < 80 && !isspacechar(lineBuffer[offset]); wbl++, offset++) { wordBuffer[wbl] = static_cast(tolower(lineBuffer[offset])); } wordBuffer[wbl] = '\0'; wbo = 0; // Check for Comment - return if found if (CompareCaseInsensitive(wordBuffer, "rem") == 0) { styler.ColourTo(endPos, SCE_BAT_COMMENT); return; } // Check for Separator if (IsBSeparator(wordBuffer[0])) { // Check for External Command / Program if ((cmdLoc == offset - wbl) && ((wordBuffer[0] == ':') || (wordBuffer[0] == '\\') || (wordBuffer[0] == '.'))) { // Reset Offset to re-process remainder of word offset -= (wbl - 1); // Colorize External Command / Program if (!keywords2) { styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); } else if (keywords2.InList(wordBuffer)) { styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); } else { styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); } // Reset External Command / Program Location cmdLoc = offset; } else { // Reset Offset to re-process remainder of word offset -= (wbl - 1); // Colorize Default Text styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); } // Check for Regular Keyword in list } else if ((keywords.InList(wordBuffer)) && (continueProcessing)) { // ECHO, GOTO, PROMPT and SET require no further Regular Keyword Checking if ((CompareCaseInsensitive(wordBuffer, "echo") == 0) || (CompareCaseInsensitive(wordBuffer, "goto") == 0) || (CompareCaseInsensitive(wordBuffer, "prompt") == 0) || (CompareCaseInsensitive(wordBuffer, "set") == 0)) { continueProcessing = false; } // Identify External Command / Program Location for ERRORLEVEL, and EXIST if ((CompareCaseInsensitive(wordBuffer, "errorlevel") == 0) || (CompareCaseInsensitive(wordBuffer, "exist") == 0)) { // Reset External Command / Program Location cmdLoc = offset; // Skip next spaces while ((cmdLoc < lengthLine) && (isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } // Skip comparison while ((cmdLoc < lengthLine) && (!isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } // Skip next spaces while ((cmdLoc < lengthLine) && (isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } // Identify External Command / Program Location for CALL, DO, LOADHIGH and LH } else if ((CompareCaseInsensitive(wordBuffer, "call") == 0) || (CompareCaseInsensitive(wordBuffer, "do") == 0) || (CompareCaseInsensitive(wordBuffer, "loadhigh") == 0) || (CompareCaseInsensitive(wordBuffer, "lh") == 0)) { // Reset External Command / Program Location cmdLoc = offset; // Skip next spaces while ((cmdLoc < lengthLine) && (isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } } // Colorize Regular keyword styler.ColourTo(startLine + offset - 1, SCE_BAT_WORD); // No need to Reset Offset // Check for Special Keyword in list, External Command / Program, or Default Text } else if ((wordBuffer[0] != '%') && (wordBuffer[0] != '!') && (!IsBOperator(wordBuffer[0])) && (continueProcessing)) { // Check for Special Keyword // Affected Commands are in Length range 2-6 // Good that ERRORLEVEL, EXIST, CALL, DO, LOADHIGH, and LH are unaffected sKeywordFound = false; for (unsigned int keywordLength = 2; keywordLength < wbl && keywordLength < 7 && !sKeywordFound; keywordLength++) { wbo = 0; // Copy Keyword Length from Word Buffer into Special Keyword Buffer for (; wbo < keywordLength; wbo++) { sKeywordBuffer[wbo] = static_cast(wordBuffer[wbo]); } sKeywordBuffer[wbo] = '\0'; // Check for Special Keyword in list if ((keywords.InList(sKeywordBuffer)) && ((IsBOperator(wordBuffer[wbo])) || (IsBSeparator(wordBuffer[wbo])))) { sKeywordFound = true; // ECHO requires no further Regular Keyword Checking if (CompareCaseInsensitive(sKeywordBuffer, "echo") == 0) { continueProcessing = false; } // Colorize Special Keyword as Regular Keyword styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_WORD); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); } } // Check for External Command / Program or Default Text if (!sKeywordFound) { wbo = 0; // Check for External Command / Program if (cmdLoc == offset - wbl) { // Read up to %, Operator or Separator while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } // Reset External Command / Program Location cmdLoc = offset - (wbl - wbo); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); // CHOICE requires no further Regular Keyword Checking if (CompareCaseInsensitive(wordBuffer, "choice") == 0) { continueProcessing = false; } // Check for START (and its switches) - What follows is External Command \ Program if (CompareCaseInsensitive(wordBuffer, "start") == 0) { // Reset External Command / Program Location cmdLoc = offset; // Skip next spaces while ((cmdLoc < lengthLine) && (isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } // Reset External Command / Program Location if command switch detected if (lineBuffer[cmdLoc] == '/') { // Skip command switch while ((cmdLoc < lengthLine) && (!isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } // Skip next spaces while ((cmdLoc < lengthLine) && (isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } } } // Colorize External Command / Program if (!keywords2) { styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); } else if (keywords2.InList(wordBuffer)) { styler.ColourTo(startLine + offset - 1, SCE_BAT_COMMAND); } else { styler.ColourTo(startLine + offset - 1, SCE_BAT_DEFAULT); } // No need to Reset Offset // Check for Default Text } else { // Read up to %, Operator or Separator while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } // Colorize Default Text styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); } } // Check for Argument (%n), Environment Variable (%x...%) or Local Variable (%%a) } else if (wordBuffer[0] == '%') { // Colorize Default Text styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT); wbo++; // Search to end of word for second % (can be a long path) while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } // Check for Argument (%n) or (%*) if (((Is0To9(wordBuffer[1])) || (wordBuffer[1] == '*')) && (wordBuffer[wbo] != '%')) { // Check for External Command / Program if (cmdLoc == offset - wbl) { cmdLoc = offset - (wbl - 2); } // Colorize Argument styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - 2); // Check for Expanded Argument (%~...) / Variable (%%~...) } else if (((wbl > 1) && (wordBuffer[1] == '~')) || ((wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] == '~'))) { // Check for External Command / Program if (cmdLoc == offset - wbl) { cmdLoc = offset - (wbl - wbo); } // Colorize Expanded Argument / Variable styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); // Check for Environment Variable (%x...%) } else if ((wordBuffer[1] != '%') && (wordBuffer[wbo] == '%')) { wbo++; // Check for External Command / Program if (cmdLoc == offset - wbl) { cmdLoc = offset - (wbl - wbo); } // Colorize Environment Variable styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); // Check for Local Variable (%%a) } else if ( (wbl > 2) && (wordBuffer[1] == '%') && (wordBuffer[2] != '%') && (!IsBOperator(wordBuffer[2])) && (!IsBSeparator(wordBuffer[2]))) { // Check for External Command / Program if (cmdLoc == offset - wbl) { cmdLoc = offset - (wbl - 3); } // Colorize Local Variable styler.ColourTo(startLine + offset - 1 - (wbl - 3), SCE_BAT_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - 3); } // Check for Environment Variable (!x...!) } else if (wordBuffer[0] == '!') { // Colorize Default Text styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT); wbo++; // Search to end of word for second ! (can be a long path) while ((wbo < wbl) && (wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } if (wordBuffer[wbo] == '!') { wbo++; // Check for External Command / Program if (cmdLoc == offset - wbl) { cmdLoc = offset - (wbl - wbo); } // Colorize Environment Variable styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_IDENTIFIER); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); } // Check for Operator } else if (IsBOperator(wordBuffer[0])) { // Colorize Default Text styler.ColourTo(startLine + offset - 1 - wbl, SCE_BAT_DEFAULT); // Check for Comparison Operator if ((wordBuffer[0] == '=') && (wordBuffer[1] == '=')) { // Identify External Command / Program Location for IF cmdLoc = offset; // Skip next spaces while ((cmdLoc < lengthLine) && (isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } // Colorize Comparison Operator styler.ColourTo(startLine + offset - 1 - (wbl - 2), SCE_BAT_OPERATOR); // Reset Offset to re-process remainder of word offset -= (wbl - 2); // Check for Pipe Operator } else if (wordBuffer[0] == '|') { // Reset External Command / Program Location cmdLoc = offset - wbl + 1; // Skip next spaces while ((cmdLoc < lengthLine) && (isspacechar(lineBuffer[cmdLoc]))) { cmdLoc++; } // Colorize Pipe Operator styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); // Reset Offset to re-process remainder of word offset -= (wbl - 1); // Check for Other Operator } else { // Check for > Operator if (wordBuffer[0] == '>') { // Turn Keyword and External Command / Program checking back on continueProcessing = true; } // Colorize Other Operator styler.ColourTo(startLine + offset - 1 - (wbl - 1), SCE_BAT_OPERATOR); // Reset Offset to re-process remainder of word offset -= (wbl - 1); } // Check for Default Text } else { // Read up to %, Operator or Separator while ((wbo < wbl) && (wordBuffer[wbo] != '%') && (wordBuffer[wbo] != '!') && (!IsBOperator(wordBuffer[wbo])) && (!IsBSeparator(wordBuffer[wbo]))) { wbo++; } // Colorize Default Text styler.ColourTo(startLine + offset - 1 - (wbl - wbo), SCE_BAT_DEFAULT); // Reset Offset to re-process remainder of word offset -= (wbl - wbo); } // Skip next spaces - nothing happens if Offset was Reset while ((offset < lengthLine) && (isspacechar(lineBuffer[offset]))) { offset++; } } // Colorize Default Text for remainder of line - currently not lexed styler.ColourTo(endPos, SCE_BAT_DEFAULT); } static void ColouriseBatchDoc( unsigned int startPos, int length, int /*initStyle*/, WordList *keywordlists[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseBatchLine(lineBuffer, linePos, startLine, i, keywordlists, styler); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters lineBuffer[linePos] = '\0'; ColouriseBatchLine(lineBuffer, linePos, startLine, startPos + length - 1, keywordlists, styler); } } #define DIFF_BUFFER_START_SIZE 16 // Note that ColouriseDiffLine analyzes only the first DIFF_BUFFER_START_SIZE // characters of each line to classify the line. static void ColouriseDiffLine(char *lineBuffer, int endLine, Accessor &styler) { // It is needed to remember the current state to recognize starting // comment lines before the first "diff " or "--- ". If a real // difference starts then each line starting with ' ' is a whitespace // otherwise it is considered a comment (Only in..., Binary file...) if (0 == strncmp(lineBuffer, "diff ", 5)) { styler.ColourTo(endLine, SCE_DIFF_COMMAND); } else if (0 == strncmp(lineBuffer, "Index: ", 7)) { // For subversion's diff styler.ColourTo(endLine, SCE_DIFF_COMMAND); } else if (0 == strncmp(lineBuffer, "---", 3) && lineBuffer[3] != '-') { // In a context diff, --- appears in both the header and the position markers if (lineBuffer[3] == ' ' && atoi(lineBuffer + 4) && !strchr(lineBuffer, '/')) styler.ColourTo(endLine, SCE_DIFF_POSITION); else if (lineBuffer[3] == '\r' || lineBuffer[3] == '\n') styler.ColourTo(endLine, SCE_DIFF_POSITION); else styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "+++ ", 4)) { // I don't know of any diff where "+++ " is a position marker, but for // consistency, do the same as with "--- " and "*** ". if (atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) styler.ColourTo(endLine, SCE_DIFF_POSITION); else styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "====", 4)) { // For p4's diff styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "***", 3)) { // In a context diff, *** appears in both the header and the position markers. // Also ******** is a chunk header, but here it's treated as part of the // position marker since there is no separate style for a chunk header. if (lineBuffer[3] == ' ' && atoi(lineBuffer+4) && !strchr(lineBuffer, '/')) styler.ColourTo(endLine, SCE_DIFF_POSITION); else if (lineBuffer[3] == '*') styler.ColourTo(endLine, SCE_DIFF_POSITION); else styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (0 == strncmp(lineBuffer, "? ", 2)) { // For difflib styler.ColourTo(endLine, SCE_DIFF_HEADER); } else if (lineBuffer[0] == '@') { styler.ColourTo(endLine, SCE_DIFF_POSITION); } else if (lineBuffer[0] >= '0' && lineBuffer[0] <= '9') { styler.ColourTo(endLine, SCE_DIFF_POSITION); } else if (lineBuffer[0] == '-' || lineBuffer[0] == '<') { styler.ColourTo(endLine, SCE_DIFF_DELETED); } else if (lineBuffer[0] == '+' || lineBuffer[0] == '>') { styler.ColourTo(endLine, SCE_DIFF_ADDED); } else if (lineBuffer[0] == '!') { styler.ColourTo(endLine, SCE_DIFF_CHANGED); } else if (lineBuffer[0] != ' ') { styler.ColourTo(endLine, SCE_DIFF_COMMENT); } else { styler.ColourTo(endLine, SCE_DIFF_DEFAULT); } } static void ColouriseDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[DIFF_BUFFER_START_SIZE]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; for (unsigned int i = startPos; i < startPos + length; i++) { if (AtEOL(styler, i)) { if (linePos < DIFF_BUFFER_START_SIZE) { lineBuffer[linePos] = 0; } ColouriseDiffLine(lineBuffer, i, styler); linePos = 0; } else if (linePos < DIFF_BUFFER_START_SIZE - 1) { lineBuffer[linePos++] = styler[i]; } else if (linePos == DIFF_BUFFER_START_SIZE - 1) { lineBuffer[linePos++] = 0; } } if (linePos > 0) { // Last line does not have ending characters if (linePos < DIFF_BUFFER_START_SIZE) { lineBuffer[linePos] = 0; } ColouriseDiffLine(lineBuffer, startPos + length - 1, styler); } } static void FoldDiffDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { int curLine = styler.GetLine(startPos); int curLineStart = styler.LineStart(curLine); int prevLevel = curLine > 0 ? styler.LevelAt(curLine - 1) : SC_FOLDLEVELBASE; int nextLevel; do { int lineType = styler.StyleAt(curLineStart); if (lineType == SCE_DIFF_COMMAND) nextLevel = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; else if (lineType == SCE_DIFF_HEADER) nextLevel = (SC_FOLDLEVELBASE + 1) | SC_FOLDLEVELHEADERFLAG; else if (lineType == SCE_DIFF_POSITION && styler[curLineStart] != '-') nextLevel = (SC_FOLDLEVELBASE + 2) | SC_FOLDLEVELHEADERFLAG; else if (prevLevel & SC_FOLDLEVELHEADERFLAG) nextLevel = (prevLevel & SC_FOLDLEVELNUMBERMASK) + 1; else nextLevel = prevLevel; if ((nextLevel & SC_FOLDLEVELHEADERFLAG) && (nextLevel == prevLevel)) styler.SetLevel(curLine-1, prevLevel & ~SC_FOLDLEVELHEADERFLAG); styler.SetLevel(curLine, nextLevel); prevLevel = nextLevel; curLineStart = styler.LineStart(++curLine); } while (static_cast(startPos) + length > curLineStart); } static void ColourisePoLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, Accessor &styler) { unsigned int i = 0; static unsigned int state = SCE_PO_DEFAULT; unsigned int state_start = SCE_PO_DEFAULT; while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces i++; if (i < lengthLine) { if (lineBuffer[i] == '#') { // check if the comment contains any flags ("#, ") and // then whether the flags contain "fuzzy" if (strstart(lineBuffer, "#, ") && strstr(lineBuffer, "fuzzy")) styler.ColourTo(endPos, SCE_PO_FUZZY); else styler.ColourTo(endPos, SCE_PO_COMMENT); } else { if (lineBuffer[0] == '"') { // line continuation, use previous style styler.ColourTo(endPos, state); return; // this implicitly also matches "msgid_plural" } else if (strstart(lineBuffer, "msgid")) { state_start = SCE_PO_MSGID; state = SCE_PO_MSGID_TEXT; } else if (strstart(lineBuffer, "msgstr")) { state_start = SCE_PO_MSGSTR; state = SCE_PO_MSGSTR_TEXT; } else if (strstart(lineBuffer, "msgctxt")) { state_start = SCE_PO_MSGCTXT; state = SCE_PO_MSGCTXT_TEXT; } if (state_start != SCE_PO_DEFAULT) { // find the next space while ((i < lengthLine) && ! isspacechar(lineBuffer[i])) i++; styler.ColourTo(startLine + i - 1, state_start); styler.ColourTo(startLine + i, SCE_PO_DEFAULT); styler.ColourTo(endPos, state); } } } else { styler.ColourTo(endPos, SCE_PO_DEFAULT); } } static void ColourisePoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColourisePoLine(lineBuffer, linePos, startLine, i, styler); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters ColourisePoLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); } } static inline bool isassignchar(unsigned char ch) { return (ch == '=') || (ch == ':'); } static void ColourisePropsLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, Accessor &styler, bool allowInitialSpaces) { unsigned int i = 0; if (allowInitialSpaces) { while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces i++; } else { if (isspacechar(lineBuffer[i])) // don't allow initial spaces i = lengthLine; } if (i < lengthLine) { if (lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';') { styler.ColourTo(endPos, SCE_PROPS_COMMENT); } else if (lineBuffer[i] == '[') { styler.ColourTo(endPos, SCE_PROPS_SECTION); } else if (lineBuffer[i] == '@') { styler.ColourTo(startLine + i, SCE_PROPS_DEFVAL); if (isassignchar(lineBuffer[i++])) styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT); styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } else { // Search for the '=' character while ((i < lengthLine) && !isassignchar(lineBuffer[i])) i++; if ((i < lengthLine) && isassignchar(lineBuffer[i])) { styler.ColourTo(startLine + i - 1, SCE_PROPS_KEY); styler.ColourTo(startLine + i, SCE_PROPS_ASSIGNMENT); styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } else { styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } } } else { styler.ColourTo(endPos, SCE_PROPS_DEFAULT); } } static void ColourisePropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; // property lexer.props.allow.initial.spaces // For properties files, set to 0 to style all lines that start with whitespace in the default style. // This is not suitable for SciTE .properties files which use indentation for flow control but // can be used for RFC2822 text where indentation is used for continuation lines. bool allowInitialSpaces = styler.GetPropertyInt("lexer.props.allow.initial.spaces", 1) != 0; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColourisePropsLine(lineBuffer, linePos, startLine, i, styler, allowInitialSpaces); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters ColourisePropsLine(lineBuffer, linePos, startLine, startPos + length - 1, styler, allowInitialSpaces); } } // adaption by ksc, using the "} else {" trick of 1.53 // 030721 static void FoldPropsDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); bool headerPoint = false; int lev; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler[i+1]; int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_PROPS_SECTION) { headerPoint = true; } if (atEOL) { lev = SC_FOLDLEVELBASE; if (lineCurrent > 0) { int levelPrevious = styler.LevelAt(lineCurrent - 1); if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { lev = SC_FOLDLEVELBASE + 1; } else { lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; } } if (headerPoint) { lev = SC_FOLDLEVELBASE; } if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (headerPoint) { lev |= SC_FOLDLEVELHEADERFLAG; } if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; visibleChars = 0; headerPoint = false; } if (!isspacechar(ch)) visibleChars++; } if (lineCurrent > 0) { int levelPrevious = styler.LevelAt(lineCurrent - 1); if (levelPrevious & SC_FOLDLEVELHEADERFLAG) { lev = SC_FOLDLEVELBASE + 1; } else { lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; } } else { lev = SC_FOLDLEVELBASE; } int flagsNext = styler.LevelAt(lineCurrent); styler.SetLevel(lineCurrent, lev | (flagsNext & ~SC_FOLDLEVELNUMBERMASK)); } static void ColouriseMakeLine( char *lineBuffer, unsigned int lengthLine, unsigned int startLine, unsigned int endPos, Accessor &styler) { unsigned int i = 0; int lastNonSpace = -1; unsigned int state = SCE_MAKE_DEFAULT; bool bSpecial = false; // check for a tab character in column 0 indicating a command bool bCommand = false; if ((lengthLine > 0) && (lineBuffer[0] == '\t')) bCommand = true; // Skip initial spaces while ((i < lengthLine) && isspacechar(lineBuffer[i])) { i++; } if (lineBuffer[i] == '#') { // Comment styler.ColourTo(endPos, SCE_MAKE_COMMENT); return; } if (lineBuffer[i] == '!') { // Special directive styler.ColourTo(endPos, SCE_MAKE_PREPROCESSOR); return; } int varCount = 0; while (i < lengthLine) { if (lineBuffer[i] == '$' && lineBuffer[i + 1] == '(') { styler.ColourTo(startLine + i - 1, state); state = SCE_MAKE_IDENTIFIER; varCount++; } else if (state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')') { if (--varCount == 0) { styler.ColourTo(startLine + i, state); state = SCE_MAKE_DEFAULT; } } // skip identifier and target styling if this is a command line if (!bSpecial && !bCommand) { if (lineBuffer[i] == ':') { if (((i + 1) < lengthLine) && (lineBuffer[i + 1] == '=')) { // it's a ':=', so style as an identifier if (lastNonSpace >= 0) styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER); styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT); styler.ColourTo(startLine + i + 1, SCE_MAKE_OPERATOR); } else { // We should check that no colouring was made since the beginning of the line, // to avoid colouring stuff like /OUT:file if (lastNonSpace >= 0) styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_TARGET); styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT); styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR); } bSpecial = true; // Only react to the first ':' of the line state = SCE_MAKE_DEFAULT; } else if (lineBuffer[i] == '=') { if (lastNonSpace >= 0) styler.ColourTo(startLine + lastNonSpace, SCE_MAKE_IDENTIFIER); styler.ColourTo(startLine + i - 1, SCE_MAKE_DEFAULT); styler.ColourTo(startLine + i, SCE_MAKE_OPERATOR); bSpecial = true; // Only react to the first '=' of the line state = SCE_MAKE_DEFAULT; } } if (!isspacechar(lineBuffer[i])) { lastNonSpace = i; } i++; } if (state == SCE_MAKE_IDENTIFIER) { styler.ColourTo(endPos, SCE_MAKE_IDEOL); // Error, variable reference not ended } else { styler.ColourTo(endPos, SCE_MAKE_DEFAULT); } } static void ColouriseMakeDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[1024]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; unsigned int startLine = startPos; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseMakeLine(lineBuffer, linePos, startLine, i, styler); linePos = 0; startLine = i + 1; } } if (linePos > 0) { // Last line does not have ending characters ColouriseMakeLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); } } static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLine, int &startValue) { if (lineBuffer[0] == '>') { // Command or return status return SCE_ERR_CMD; } else if (lineBuffer[0] == '<') { // Diff removal. return SCE_ERR_DIFF_DELETION; } else if (lineBuffer[0] == '!') { return SCE_ERR_DIFF_CHANGED; } else if (lineBuffer[0] == '+') { if (strstart(lineBuffer, "+++ ")) { return SCE_ERR_DIFF_MESSAGE; } else { return SCE_ERR_DIFF_ADDITION; } } else if (lineBuffer[0] == '-') { if (strstart(lineBuffer, "--- ")) { return SCE_ERR_DIFF_MESSAGE; } else { return SCE_ERR_DIFF_DELETION; } } else if (strstart(lineBuffer, "cf90-")) { // Absoft Pro Fortran 90/95 v8.2 error and/or warning message return SCE_ERR_ABSF; } else if (strstart(lineBuffer, "fortcom:")) { // Intel Fortran Compiler v8.0 error/warning message return SCE_ERR_IFORT; } else if (strstr(lineBuffer, "File \"") && strstr(lineBuffer, ", line ")) { return SCE_ERR_PYTHON; } else if (strstr(lineBuffer, " in ") && strstr(lineBuffer, " on line ")) { return SCE_ERR_PHP; } else if ((strstart(lineBuffer, "Error ") || strstart(lineBuffer, "Warning ")) && strstr(lineBuffer, " at (") && strstr(lineBuffer, ") : ") && (strstr(lineBuffer, " at (") < strstr(lineBuffer, ") : "))) { // Intel Fortran Compiler error/warning message return SCE_ERR_IFC; } else if (strstart(lineBuffer, "Error ")) { // Borland error message return SCE_ERR_BORLAND; } else if (strstart(lineBuffer, "Warning ")) { // Borland warning message return SCE_ERR_BORLAND; } else if (strstr(lineBuffer, "at line ") && (strstr(lineBuffer, "at line ") < (lineBuffer + lengthLine)) && strstr(lineBuffer, "file ") && (strstr(lineBuffer, "file ") < (lineBuffer + lengthLine))) { // Lua 4 error message return SCE_ERR_LUA; } else if (strstr(lineBuffer, " at ") && (strstr(lineBuffer, " at ") < (lineBuffer + lengthLine)) && strstr(lineBuffer, " line ") && (strstr(lineBuffer, " line ") < (lineBuffer + lengthLine)) && (strstr(lineBuffer, " at ") < (strstr(lineBuffer, " line ")))) { // perl error message return SCE_ERR_PERL; } else if ((memcmp(lineBuffer, " at ", 6) == 0) && strstr(lineBuffer, ":line ")) { // A .NET traceback return SCE_ERR_NET; } else if (strstart(lineBuffer, "Line ") && strstr(lineBuffer, ", file ")) { // Essential Lahey Fortran error message return SCE_ERR_ELF; } else if (strstart(lineBuffer, "line ") && strstr(lineBuffer, " column ")) { // HTML tidy style: line 42 column 1 return SCE_ERR_TIDY; } else if (strstart(lineBuffer, "\tat ") && strstr(lineBuffer, "(") && strstr(lineBuffer, ".java:")) { // Java stack back trace return SCE_ERR_JAVA_STACK; } else { // Look for one of the following formats: // GCC: :: // Microsoft: () : // Common: (): warning|error|note|remark|catastrophic|fatal // Common: () warning|error|note|remark|catastrophic|fatal // Microsoft: (,) // CTags: \t // Lua 5 traceback: \t:: // Lua 5.1: : :: bool initialTab = (lineBuffer[0] == '\t'); bool initialColonPart = false; enum { stInitial, stGccStart, stGccDigit, stGccColumn, stGcc, stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet, stCtagsStart, stCtagsStartString, stCtagsStringDollar, stCtags, stUnrecognized } state = stInitial; for (unsigned int i = 0; i < lengthLine; i++) { char ch = lineBuffer[i]; char chNext = ' '; if ((i + 1) < lengthLine) chNext = lineBuffer[i + 1]; if (state == stInitial) { if (ch == ':') { // May be GCC, or might be Lua 5 (Lua traceback same but with tab prefix) if ((chNext != '\\') && (chNext != '/') && (chNext != ' ')) { // This check is not completely accurate as may be on // GTK+ with a file name that includes ':'. state = stGccStart; } else if (chNext == ' ') { // indicates a Lua 5.1 error message initialColonPart = true; } } else if ((ch == '(') && Is1To9(chNext) && (!initialTab)) { // May be Microsoft // Check against '0' often removes phone numbers state = stMsStart; } else if ((ch == '\t') && (!initialTab)) { // May be CTags state = stCtagsStart; } } else if (state == stGccStart) { // : state = Is1To9(ch) ? stGccDigit : stUnrecognized; } else if (state == stGccDigit) { // : if (ch == ':') { state = stGccColumn; // :9.*: is GCC startValue = i + 1; } else if (!Is0To9(ch)) { state = stUnrecognized; } } else if (state == stGccColumn) { // :: if (!Is0To9(ch)) { state = stGcc; if (ch == ':') startValue = i + 1; break; } } else if (state == stMsStart) { // ( state = Is0To9(ch) ? stMsDigit : stUnrecognized; } else if (state == stMsDigit) { // ( if (ch == ',') { state = stMsDigitComma; } else if (ch == ')') { state = stMsBracket; } else if ((ch != ' ') && !Is0To9(ch)) { state = stUnrecognized; } } else if (state == stMsBracket) { // () if ((ch == ' ') && (chNext == ':')) { state = stMsVc; } else if ((ch == ':' && chNext == ' ') || (ch == ' ')) { // Possibly Delphi.. don't test against chNext as it's one of the strings below. char word[512]; unsigned int j, chPos; unsigned numstep; chPos = 0; if (ch == ' ') numstep = 1; // ch was ' ', handle as if it's a delphi errorline, only add 1 to i. else numstep = 2; // otherwise add 2. for (j = i + numstep; j < lengthLine && IsAlphabetic(lineBuffer[j]) && chPos < sizeof(word) - 1; j++) word[chPos++] = lineBuffer[j]; word[chPos] = 0; if (!CompareCaseInsensitive(word, "error") || !CompareCaseInsensitive(word, "warning") || !CompareCaseInsensitive(word, "fatal") || !CompareCaseInsensitive(word, "catastrophic") || !CompareCaseInsensitive(word, "note") || !CompareCaseInsensitive(word, "remark")) { state = stMsVc; } else state = stUnrecognized; } else { state = stUnrecognized; } } else if (state == stMsDigitComma) { // (, if (ch == ')') { state = stMsDotNet; break; } else if ((ch != ' ') && !Is0To9(ch)) { state = stUnrecognized; } } else if (state == stCtagsStart) { if ((lineBuffer[i - 1] == '\t') && ((ch == '/' && lineBuffer[i + 1] == '^') || Is0To9(ch))) { state = stCtags; break; } else if ((ch == '/') && (lineBuffer[i + 1] == '^')) { state = stCtagsStartString; } } else if ((state == stCtagsStartString) && ((lineBuffer[i] == '$') && (lineBuffer[i + 1] == '/'))) { state = stCtagsStringDollar; break; } } if (state == stGcc) { return initialColonPart ? SCE_ERR_LUA : SCE_ERR_GCC; } else if ((state == stMsVc) || (state == stMsDotNet)) { return SCE_ERR_MS; } else if ((state == stCtagsStringDollar) || (state == stCtags)) { return SCE_ERR_CTAG; } else { return SCE_ERR_DEFAULT; } } } static void ColouriseErrorListLine( char *lineBuffer, unsigned int lengthLine, unsigned int endPos, Accessor &styler, bool valueSeparate) { int startValue = -1; int style = RecogniseErrorListLine(lineBuffer, lengthLine, startValue); if (valueSeparate && (startValue >= 0)) { styler.ColourTo(endPos - (lengthLine - startValue), style); styler.ColourTo(endPos, SCE_ERR_VALUE); } else { styler.ColourTo(endPos, style); } } static void ColouriseErrorListDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { char lineBuffer[10000]; styler.StartAt(startPos); styler.StartSegment(startPos); unsigned int linePos = 0; // property lexer.errorlist.value.separate // For lines in the output pane that are matches from Find in Files or GCC-style // diagnostics, style the path and line number separately from the rest of the // line with style 21 used for the rest of the line. // This allows matched text to be more easily distinguished from its location. bool valueSeparate = styler.GetPropertyInt("lexer.errorlist.value.separate", 0) != 0; for (unsigned int i = startPos; i < startPos + length; i++) { lineBuffer[linePos++] = styler[i]; if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { // End of line (or of line buffer) met, colourise it lineBuffer[linePos] = '\0'; ColouriseErrorListLine(lineBuffer, linePos, i, styler, valueSeparate); linePos = 0; } } if (linePos > 0) { // Last line does not have ending characters ColouriseErrorListLine(lineBuffer, linePos, startPos + length - 1, styler, valueSeparate); } } static bool latexIsSpecial(int ch) { return (ch == '#') || (ch == '$') || (ch == '%') || (ch == '&') || (ch == '_') || (ch == '{') || (ch == '}') || (ch == ' '); } static bool latexIsBlank(int ch) { return (ch == ' ') || (ch == '\t'); } static bool latexIsBlankAndNL(int ch) { return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n'); } static bool latexIsLetter(int ch) { return isascii(ch) && isalpha(ch); } static bool latexIsTagValid(int &i, int l, Accessor &styler) { while (i < l) { if (styler.SafeGetCharAt(i) == '{') { while (i < l) { i++; if (styler.SafeGetCharAt(i) == '}') { return true; } else if (!latexIsLetter(styler.SafeGetCharAt(i)) && styler.SafeGetCharAt(i)!='*') { return false; } } } else if (!latexIsBlank(styler.SafeGetCharAt(i))) { return false; } i++; } return false; } static bool latexNextNotBlankIs(int i, int l, Accessor &styler, char needle) { char ch; while (i < l) { ch = styler.SafeGetCharAt(i); if (!latexIsBlankAndNL(ch) && ch != '*') { if (ch == needle) return true; else return false; } i++; } return false; } static bool latexLastWordIs(int start, Accessor &styler, const char *needle) { unsigned int i = 0; unsigned int l = static_cast(strlen(needle)); int ini = start-l+1; char s[32]; while (i < l && i < 32) { s[i] = styler.SafeGetCharAt(ini + i); i++; } s[i] = '\0'; return (strcmp(s, needle) == 0); } static void ColouriseLatexDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { styler.StartAt(startPos); int state = initStyle; char chNext = styler.SafeGetCharAt(startPos); styler.StartSegment(startPos); int lengthDoc = startPos + length; char chVerbatimDelim = '\0'; for (int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if (styler.IsLeadByte(ch)) { i++; chNext = styler.SafeGetCharAt(i + 1); continue; } switch (state) { case SCE_L_DEFAULT : switch (ch) { case '\\' : styler.ColourTo(i - 1, state); if (latexIsSpecial(chNext)) { state = SCE_L_SPECIAL; } else { if (latexIsLetter(chNext)) { state = SCE_L_COMMAND; } else { if (chNext == '(' || chNext == '[') { styler.ColourTo(i-1, state); styler.ColourTo(i+1, SCE_L_SHORTCMD); state = SCE_L_MATH; if (chNext == '[') state = SCE_L_MATH2; i++; chNext = styler.SafeGetCharAt(i+1); } else { state = SCE_L_SHORTCMD; } } } break; case '$' : styler.ColourTo(i - 1, state); state = SCE_L_MATH; if (chNext == '$') { state = SCE_L_MATH2; i++; chNext = styler.SafeGetCharAt(i + 1); } break; case '%' : styler.ColourTo(i - 1, state); state = SCE_L_COMMENT; break; } break; case SCE_L_ERROR: styler.ColourTo(i-1, state); state = SCE_L_DEFAULT; break; case SCE_L_SPECIAL: case SCE_L_SHORTCMD: styler.ColourTo(i, state); state = SCE_L_DEFAULT; break; case SCE_L_COMMAND : if (!latexIsLetter(chNext)) { styler.ColourTo(i, state); state = SCE_L_DEFAULT; if (latexNextNotBlankIs(i+1, lengthDoc, styler, '[' )) { state = SCE_L_CMDOPT; } else if (latexLastWordIs(i, styler, "\\begin")) { state = SCE_L_TAG; } else if (latexLastWordIs(i, styler, "\\end")) { state = SCE_L_TAG2; } else if (latexLastWordIs(i, styler, "\\verb") && chNext != '*' && chNext != ' ') { chVerbatimDelim = chNext; state = SCE_L_VERBATIM; } } break; case SCE_L_CMDOPT : if (ch == ']') { styler.ColourTo(i, state); state = SCE_L_DEFAULT; } break; case SCE_L_TAG : if (latexIsTagValid(i, lengthDoc, styler)) { styler.ColourTo(i, state); state = SCE_L_DEFAULT; if (latexLastWordIs(i, styler, "{verbatim}")) { state = SCE_L_VERBATIM; } else if (latexLastWordIs(i, styler, "{comment}")) { state = SCE_L_COMMENT2; } else if (latexLastWordIs(i, styler, "{math}")) { state = SCE_L_MATH; } else if (latexLastWordIs(i, styler, "{displaymath}")) { state = SCE_L_MATH2; } else if (latexLastWordIs(i, styler, "{equation}")) { state = SCE_L_MATH2; } } else { state = SCE_L_ERROR; styler.ColourTo(i, state); state = SCE_L_DEFAULT; } chNext = styler.SafeGetCharAt(i+1); break; case SCE_L_TAG2 : if (latexIsTagValid(i, lengthDoc, styler)) { styler.ColourTo(i, state); state = SCE_L_DEFAULT; } else { state = SCE_L_ERROR; } chNext = styler.SafeGetCharAt(i+1); break; case SCE_L_MATH : if (ch == '$') { styler.ColourTo(i, state); state = SCE_L_DEFAULT; } else if (ch == '\\' && chNext == ')') { styler.ColourTo(i-1, state); styler.ColourTo(i+1, SCE_L_SHORTCMD); i++; chNext = styler.SafeGetCharAt(i+1); state = SCE_L_DEFAULT; } else if (ch == '\\') { int match = i + 3; if (latexLastWordIs(match, styler, "\\end")) { match++; if (latexIsTagValid(match, lengthDoc, styler)) { if (latexLastWordIs(match, styler, "{math}")) { styler.ColourTo(i-1, state); state = SCE_L_COMMAND; } } } } break; case SCE_L_MATH2 : if (ch == '$') { if (chNext == '$') { i++; chNext = styler.SafeGetCharAt(i + 1); styler.ColourTo(i, state); state = SCE_L_DEFAULT; } else { styler.ColourTo(i, SCE_L_ERROR); state = SCE_L_DEFAULT; } } else if (ch == '\\' && chNext == ']') { styler.ColourTo(i-1, state); styler.ColourTo(i+1, SCE_L_SHORTCMD); i++; chNext = styler.SafeGetCharAt(i+1); state = SCE_L_DEFAULT; } else if (ch == '\\') { int match = i + 3; if (latexLastWordIs(match, styler, "\\end")) { match++; if (latexIsTagValid(match, lengthDoc, styler)) { if (latexLastWordIs(match, styler, "{displaymath}")) { styler.ColourTo(i-1, state); state = SCE_L_COMMAND; } else if (latexLastWordIs(match, styler, "{equation}")) { styler.ColourTo(i-1, state); state = SCE_L_COMMAND; } } } } break; case SCE_L_COMMENT : if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, state); state = SCE_L_DEFAULT; } break; case SCE_L_COMMENT2 : if (ch == '\\') { int match = i + 3; if (latexLastWordIs(match, styler, "\\end")) { match++; if (latexIsTagValid(match, lengthDoc, styler)) { if (latexLastWordIs(match, styler, "{comment}")) { styler.ColourTo(i-1, state); state = SCE_L_COMMAND; } } } } break; case SCE_L_VERBATIM : if (ch == '\\') { int match = i + 3; if (latexLastWordIs(match, styler, "\\end")) { match++; if (latexIsTagValid(match, lengthDoc, styler)) { if (latexLastWordIs(match, styler, "{verbatim}")) { styler.ColourTo(i-1, state); state = SCE_L_COMMAND; } } } } else if (chNext == chVerbatimDelim) { styler.ColourTo(i+1, state); state = SCE_L_DEFAULT; chVerbatimDelim = '\0'; } else if (chVerbatimDelim != '\0' && (ch == '\n' || ch == '\r')) { styler.ColourTo(i, SCE_L_ERROR); state = SCE_L_DEFAULT; chVerbatimDelim = '\0'; } break; } } styler.ColourTo(lengthDoc-1, state); } static const char *const batchWordListDesc[] = { "Internal Commands", "External Commands", 0 }; static const char *const emptyWordListDesc[] = { 0 }; static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { // Null language means all style bytes are 0 so just mark the end - no need to fill in. if (length > 0) { styler.StartAt(startPos + length - 1); styler.StartSegment(startPos + length - 1); styler.ColourTo(startPos + length - 1, 0); } } LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", 0, batchWordListDesc); LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc); LexerModule lmPo(SCLEX_PO, ColourisePoDoc, "po", 0, emptyWordListDesc); LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc); LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc); LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc); LexerModule lmLatex(SCLEX_LATEX, ColouriseLatexDoc, "latex", 0, emptyWordListDesc); LexerModule lmNull(SCLEX_NULL, ColouriseNullDoc, "null"); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexTeX.cxx0000644000175000017500000003315011634611460021032 00000000000000// Scintilla source code edit control // File: LexTeX.cxx - general context conformant tex coloring scheme // Author: Hans Hagen - PRAGMA ADE - Hasselt NL - www.pragma-ade.com // Version: September 28, 2003 // Copyright: 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. // This lexer is derived from the one written for the texwork environment (1999++) which in // turn is inspired on texedit (1991++) which finds its roots in wdt (1986). // If you run into strange boundary cases, just tell me and I'll look into it. // TeX Folding code added by instanton (soft_share@126.com) with borrowed code from VisualTeX source by Alex Romanenko. // Version: June 22, 2007 #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // val SCE_TEX_DEFAULT = 0 // val SCE_TEX_SPECIAL = 1 // val SCE_TEX_GROUP = 2 // val SCE_TEX_SYMBOL = 3 // val SCE_TEX_COMMAND = 4 // val SCE_TEX_TEXT = 5 // Definitions in SciTEGlobal.properties: // // TeX Highlighting // // # Default // style.tex.0=fore:#7F7F00 // # Special // style.tex.1=fore:#007F7F // # Group // style.tex.2=fore:#880000 // # Symbol // style.tex.3=fore:#7F7F00 // # Command // style.tex.4=fore:#008800 // # Text // style.tex.5=fore:#000000 // lexer.tex.interface.default=0 // lexer.tex.comment.process=0 // todo: lexer.tex.auto.if // Auxiliary functions: static inline bool endOfLine(Accessor &styler, unsigned int i) { return (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ; } static inline bool isTeXzero(int ch) { return (ch == '%') ; } static inline bool isTeXone(int ch) { return (ch == '[') || (ch == ']') || (ch == '=') || (ch == '#') || (ch == '(') || (ch == ')') || (ch == '<') || (ch == '>') || (ch == '"') ; } static inline bool isTeXtwo(int ch) { return (ch == '{') || (ch == '}') || (ch == '$') ; } static inline bool isTeXthree(int ch) { return (ch == '~') || (ch == '^') || (ch == '_') || (ch == '&') || (ch == '-') || (ch == '+') || (ch == '\"') || (ch == '`') || (ch == '/') || (ch == '|') || (ch == '%') ; } static inline bool isTeXfour(int ch) { return (ch == '\\') ; } static inline bool isTeXfive(int ch) { return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || (ch == '@') || (ch == '!') || (ch == '?') ; } static inline bool isTeXsix(int ch) { return (ch == ' ') ; } static inline bool isTeXseven(int ch) { return (ch == '^') ; } // Interface determination static int CheckTeXInterface( unsigned int startPos, int length, Accessor &styler, int defaultInterface) { char lineBuffer[1024] ; unsigned int linePos = 0 ; // some day we can make something lexer.tex.mapping=(all,0)(nl,1)(en,2)... if (styler.SafeGetCharAt(0) == '%') { for (unsigned int i = 0; i < startPos + length; i++) { lineBuffer[linePos++] = styler.SafeGetCharAt(i) ; if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { lineBuffer[linePos] = '\0'; if (strstr(lineBuffer, "interface=all")) { return 0 ; } else if (strstr(lineBuffer, "interface=tex")) { return 1 ; } else if (strstr(lineBuffer, "interface=nl")) { return 2 ; } else if (strstr(lineBuffer, "interface=en")) { return 3 ; } else if (strstr(lineBuffer, "interface=de")) { return 4 ; } else if (strstr(lineBuffer, "interface=cz")) { return 5 ; } else if (strstr(lineBuffer, "interface=it")) { return 6 ; } else if (strstr(lineBuffer, "interface=ro")) { return 7 ; } else if (strstr(lineBuffer, "interface=latex")) { // we will move latex cum suis up to 91+ when more keyword lists are supported return 8 ; } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) { // better would be to limit the search to just one line return 3 ; } else { return defaultInterface ; } } } } return defaultInterface ; } static void ColouriseTeXDoc( unsigned int startPos, int length, int, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos) ; styler.StartSegment(startPos) ; bool processComment = styler.GetPropertyInt("lexer.tex.comment.process", 0) == 1 ; bool useKeywords = styler.GetPropertyInt("lexer.tex.use.keywords", 1) == 1 ; bool autoIf = styler.GetPropertyInt("lexer.tex.auto.if", 1) == 1 ; int defaultInterface = styler.GetPropertyInt("lexer.tex.interface.default", 1) ; char key[100] ; int k ; bool newifDone = false ; bool inComment = false ; int currentInterface = CheckTeXInterface(startPos,length,styler,defaultInterface) ; if (currentInterface == 0) { useKeywords = false ; currentInterface = 1 ; } WordList &keywords = *keywordlists[currentInterface-1] ; StyleContext sc(startPos, length, SCE_TEX_TEXT, styler); bool going = sc.More() ; // needed because of a fuzzy end of file state for (; going; sc.Forward()) { if (! sc.More()) { going = false ; } // we need to go one behind the end of text if (inComment) { if (sc.atLineEnd) { sc.SetState(SCE_TEX_TEXT) ; newifDone = false ; inComment = false ; } } else { if (! isTeXfive(sc.ch)) { if (sc.state == SCE_TEX_COMMAND) { if (sc.LengthCurrent() == 1) { // \ if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) { sc.Forward(2) ; // \^^ and \^^ } sc.ForwardSetState(SCE_TEX_TEXT) ; } else { sc.GetCurrent(key, sizeof(key)-1) ; k = static_cast(strlen(key)) ; memmove(key,key+1,k) ; // shift left over escape token key[k] = '\0' ; k-- ; if (! keywords || ! useKeywords) { sc.SetState(SCE_TEX_COMMAND) ; newifDone = false ; } else if (k == 1) { //\ sc.SetState(SCE_TEX_COMMAND) ; newifDone = false ; } else if (keywords.InList(key)) { sc.SetState(SCE_TEX_COMMAND) ; newifDone = autoIf && (strcmp(key,"newif") == 0) ; } else if (autoIf && ! newifDone && (key[0] == 'i') && (key[1] == 'f') && keywords.InList("if")) { sc.SetState(SCE_TEX_COMMAND) ; } else { sc.ChangeState(SCE_TEX_TEXT) ; sc.SetState(SCE_TEX_TEXT) ; newifDone = false ; } } } if (isTeXzero(sc.ch)) { sc.SetState(SCE_TEX_SYMBOL); if (!endOfLine(styler,sc.currentPos + 1)) sc.ForwardSetState(SCE_TEX_DEFAULT) ; inComment = ! processComment ; newifDone = false ; } else if (isTeXseven(sc.ch) && isTeXseven(sc.chNext)) { sc.SetState(SCE_TEX_TEXT) ; sc.ForwardSetState(SCE_TEX_TEXT) ; } else if (isTeXone(sc.ch)) { sc.SetState(SCE_TEX_SPECIAL) ; newifDone = false ; } else if (isTeXtwo(sc.ch)) { sc.SetState(SCE_TEX_GROUP) ; newifDone = false ; } else if (isTeXthree(sc.ch)) { sc.SetState(SCE_TEX_SYMBOL) ; newifDone = false ; } else if (isTeXfour(sc.ch)) { sc.SetState(SCE_TEX_COMMAND) ; } else if (isTeXsix(sc.ch)) { sc.SetState(SCE_TEX_TEXT) ; } else if (sc.atLineEnd) { sc.SetState(SCE_TEX_TEXT) ; newifDone = false ; inComment = false ; } else { sc.SetState(SCE_TEX_TEXT) ; } } else if (sc.state != SCE_TEX_COMMAND) { sc.SetState(SCE_TEX_TEXT) ; } } } sc.ChangeState(SCE_TEX_TEXT) ; sc.Complete(); } static inline bool isNumber(int ch) { return (ch == '0') || (ch == '1') || (ch == '2') || (ch == '3') || (ch == '4') || (ch == '5') || (ch == '6') || (ch == '7') || (ch == '8') || (ch == '9'); } static inline bool isWordChar(int ch) { return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')); } static int ParseTeXCommand(unsigned int pos, Accessor &styler, char *command) { int length=0; char ch=styler.SafeGetCharAt(pos+1); if(ch==',' || ch==':' || ch==';' || ch=='%'){ command[0]=ch; command[1]=0; return 1; } // find end while(isWordChar(ch) && !isNumber(ch) && ch!='_' && ch!='.' && length<100){ command[length]=ch; length++; ch=styler.SafeGetCharAt(pos+length+1); } command[length]='\0'; if(!length) return 0; return length+1; } static int classifyFoldPointTeXPaired(const char* s) { int lev=0; if (!(isdigit(s[0]) || (s[0] == '.'))){ if (strcmp(s, "begin")==0||strcmp(s,"FoldStart")==0|| strcmp(s,"abstract")==0||strcmp(s,"unprotect")==0|| strcmp(s,"title")==0||strncmp(s,"start",5)==0||strncmp(s,"Start",5)==0|| strcmp(s,"documentclass")==0||strncmp(s,"if",2)==0 ) lev=1; if (strcmp(s, "end")==0||strcmp(s,"FoldStop")==0|| strcmp(s,"maketitle")==0||strcmp(s,"protect")==0|| strncmp(s,"stop",4)==0||strncmp(s,"Stop",4)==0|| strcmp(s,"fi")==0 ) lev=-1; } return lev; } static int classifyFoldPointTeXUnpaired(const char* s) { int lev=0; if (!(isdigit(s[0]) || (s[0] == '.'))){ if (strcmp(s,"part")==0|| strcmp(s,"chapter")==0|| strcmp(s,"section")==0|| strcmp(s,"subsection")==0|| strcmp(s,"subsubsection")==0|| strcmp(s,"CJKfamily")==0|| strcmp(s,"appendix")==0|| strcmp(s,"Topic")==0||strcmp(s,"topic")==0|| strcmp(s,"subject")==0||strcmp(s,"subsubject")==0|| strcmp(s,"def")==0||strcmp(s,"gdef")==0||strcmp(s,"edef")==0|| strcmp(s,"xdef")==0||strcmp(s,"framed")==0|| strcmp(s,"frame")==0|| strcmp(s,"foilhead")==0||strcmp(s,"overlays")==0||strcmp(s,"slide")==0 ){ lev=1; } } return lev; } static bool IsTeXCommentLine(int line, Accessor &styler) { int pos = styler.LineStart(line); int eol_pos = styler.LineStart(line + 1) - 1; int startpos = pos; while (startpos SC_FOLDLEVELBASE && ((ch == '\r' || ch=='\n') && (chNext == '\\'))) { ParseTeXCommand(i+1, styler, buffer); levelCurrent -= classifyFoldPointTeXUnpaired(buffer); } char chNext2; char chNext3; char chNext4; char chNext5; chNext2=styler.SafeGetCharAt(i+2); chNext3=styler.SafeGetCharAt(i+3); chNext4=styler.SafeGetCharAt(i+4); chNext5=styler.SafeGetCharAt(i+5); bool atEOfold = (ch == '%') && (chNext == '%') && (chNext2=='}') && (chNext3=='}')&& (chNext4=='-')&& (chNext5=='-'); bool atBOfold = (ch == '%') && (chNext == '%') && (chNext2=='-') && (chNext3=='-')&& (chNext4=='{')&& (chNext5=='{'); if(atBOfold){ levelCurrent+=1; } if(atEOfold){ levelCurrent-=1; } if(ch=='\\' && chNext=='['){ levelCurrent+=1; } if(ch=='\\' && chNext==']'){ levelCurrent-=1; } bool foldComment = styler.GetPropertyInt("fold.comment") != 0; if (foldComment && atEOL && IsTeXCommentLine(lineCurrent, styler)) { if (lineCurrent==0 && IsTeXCommentLine(lineCurrent + 1, styler) ) levelCurrent++; else if (lineCurrent!=0 && !IsTeXCommentLine(lineCurrent - 1, styler) && IsTeXCommentLine(lineCurrent + 1, styler) ) levelCurrent++; else if (lineCurrent!=0 && IsTeXCommentLine(lineCurrent - 1, styler) && !IsTeXCommentLine(lineCurrent+1, styler)) levelCurrent--; } //--------------------------------------------------------------------------------------------- if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const texWordListDesc[] = { "TeX, eTeX, pdfTeX, Omega", "ConTeXt Dutch", "ConTeXt English", "ConTeXt German", "ConTeXt Czech", "ConTeXt Italian", "ConTeXt Romanian", 0, } ; LexerModule lmTeX(SCLEX_TEX, ColouriseTeXDoc, "tex", FoldTexDoc, texWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexKix.cxx0000644000175000017500000000661011615412040021056 00000000000000// Scintilla source code edit control /** @file LexKix.cxx ** Lexer for KIX-Scripts. **/ // Copyright 2004 by Manfred Becker // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Extended to accept accented characters static inline bool IsAWordChar(int ch) { return ch >= 0x80 || isalnum(ch) || ch == '_'; } static inline bool IsOperator(const int ch) { return (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '&' || ch == '|' || ch == '<' || ch == '>' || ch == '='); } static void ColouriseKixDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; // WordList &keywords4 = *keywordlists[3]; styler.StartAt(startPos); StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.state == SCE_KIX_COMMENT) { if (sc.atLineEnd) { sc.SetState(SCE_KIX_DEFAULT); } } else if (sc.state == SCE_KIX_STRING1) { // This is a doubles quotes string if (sc.ch == '\"') { sc.ForwardSetState(SCE_KIX_DEFAULT); } } else if (sc.state == SCE_KIX_STRING2) { // This is a single quote string if (sc.ch == '\'') { sc.ForwardSetState(SCE_KIX_DEFAULT); } } else if (sc.state == SCE_KIX_NUMBER) { if (!IsADigit(sc.ch)) { sc.SetState(SCE_KIX_DEFAULT); } } else if (sc.state == SCE_KIX_VAR) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_KIX_DEFAULT); } } else if (sc.state == SCE_KIX_MACRO) { if (!IsAWordChar(sc.ch) && !IsADigit(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (!keywords3.InList(&s[1])) { sc.ChangeState(SCE_KIX_DEFAULT); } sc.SetState(SCE_KIX_DEFAULT); } } else if (sc.state == SCE_KIX_OPERATOR) { if (!IsOperator(sc.ch)) { sc.SetState(SCE_KIX_DEFAULT); } } else if (sc.state == SCE_KIX_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_KIX_KEYWORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_KIX_FUNCTIONS); } sc.SetState(SCE_KIX_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_KIX_DEFAULT) { if (sc.ch == ';') { sc.SetState(SCE_KIX_COMMENT); } else if (sc.ch == '\"') { sc.SetState(SCE_KIX_STRING1); } else if (sc.ch == '\'') { sc.SetState(SCE_KIX_STRING2); } else if (sc.ch == '$') { sc.SetState(SCE_KIX_VAR); } else if (sc.ch == '@') { sc.SetState(SCE_KIX_MACRO); } else if (IsADigit(sc.ch) || ((sc.ch == '.' || sc.ch == '&') && IsADigit(sc.chNext))) { sc.SetState(SCE_KIX_NUMBER); } else if (IsOperator(sc.ch)) { sc.SetState(SCE_KIX_OPERATOR); } else if (IsAWordChar(sc.ch)) { sc.SetState(SCE_KIX_IDENTIFIER); } } } sc.Complete(); } LexerModule lmKix(SCLEX_KIX, ColouriseKixDoc, "kix"); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexSorcus.cxx0000644000175000017500000001123211615412040021575 00000000000000// Scintilla source code edit control /** @file LexSorcus.cxx ** Lexer for SORCUS installation files ** Written by Eugen Bitter and Christoph Baumann at SORCUS Computer, Heidelberg Germany ** Based on the ASM Lexer by The Black Horus **/ // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif //each character a..z and A..Z + '_' can be part of a keyword //additionally numbers that follow 'M' can be contained in a keyword static inline bool IsSWordStart(const int ch, const int prev_ch) { if (isalpha(ch) || (ch == '_') || ((isdigit(ch)) && (prev_ch == 'M'))) return true; return false; } //only digits that are not preceded by 'M' count as a number static inline bool IsSorcusNumber(const int ch, const int prev_ch) { if ((isdigit(ch)) && (prev_ch != 'M')) return true; return false; } //only = is a valid operator static inline bool IsSorcusOperator(const int ch) { if (ch == '=') return true; return false; } static void ColouriseSorcusDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &Command = *keywordlists[0]; WordList &Parameter = *keywordlists[1]; WordList &Constant = *keywordlists[2]; // Do not leak onto next line if (initStyle == SCE_SORCUS_STRINGEOL) initStyle = SCE_SORCUS_DEFAULT; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Prevent SCE_SORCUS_STRINGEOL from leaking back to previous line if (sc.atLineStart && (sc.state == SCE_SORCUS_STRING)) { sc.SetState(SCE_SORCUS_STRING); } // Determine if the current state should terminate. if (sc.state == SCE_SORCUS_OPERATOR) { if (!IsSorcusOperator(sc.ch)) { sc.SetState(SCE_SORCUS_DEFAULT); } } else if(sc.state == SCE_SORCUS_NUMBER) { if(!IsSorcusNumber(sc.ch, sc.chPrev)) { sc.SetState(SCE_SORCUS_DEFAULT); } } else if (sc.state == SCE_SORCUS_IDENTIFIER) { if (!IsSWordStart(sc.ch, sc.chPrev)) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (Command.InList(s)) { sc.ChangeState(SCE_SORCUS_COMMAND); } else if (Parameter.InList(s)) { sc.ChangeState(SCE_SORCUS_PARAMETER); } else if (Constant.InList(s)) { sc.ChangeState(SCE_SORCUS_CONSTANT); } sc.SetState(SCE_SORCUS_DEFAULT); } } else if (sc.state == SCE_SORCUS_COMMENTLINE ) { if (sc.atLineEnd) { sc.SetState(SCE_SORCUS_DEFAULT); } } else if (sc.state == SCE_SORCUS_STRING) { if (sc.ch == '\"') { sc.ForwardSetState(SCE_SORCUS_DEFAULT); } else if (sc.atLineEnd) { sc.ChangeState(SCE_SORCUS_STRINGEOL); sc.ForwardSetState(SCE_SORCUS_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_SORCUS_DEFAULT) { if ((sc.ch == ';') || (sc.ch == '\'')) { sc.SetState(SCE_SORCUS_COMMENTLINE); } else if (IsSWordStart(sc.ch, sc.chPrev)) { sc.SetState(SCE_SORCUS_IDENTIFIER); } else if (sc.ch == '\"') { sc.SetState(SCE_SORCUS_STRING); } else if (IsSorcusOperator(sc.ch)) { sc.SetState(SCE_SORCUS_OPERATOR); } else if (IsSorcusNumber(sc.ch, sc.chPrev)) { sc.SetState(SCE_SORCUS_NUMBER); } } } sc.Complete(); } static const char* const SorcusWordListDesc[] = {"Command","Parameter", "Constant", 0}; LexerModule lmSorc(SCLEX_SORCUS, ColouriseSorcusDoc, "sorcins", 0, SorcusWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexHaskell.cxx0000644000175000017500000002547411615412040021717 00000000000000/****************************************************************** * LexHaskell.cxx * * A haskell lexer for the scintilla code control. * Some stuff "lended" from LexPython.cxx and LexCPP.cxx. * External lexer stuff inspired from the caml external lexer. * * Written by Tobias Engvall - tumm at dtek dot chalmers dot se * * Several bug fixes by Krasimir Angelov - kr.angelov at gmail.com * * TODO: * * Implement a folder :) * * Nice Character-lexing (stuff inside '\''), LexPython has * this. * * *****************************************************************/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #ifdef BUILD_AS_EXTERNAL_LEXER #include "ExternalLexer.h" #include "WindowAccessor.h" #define BUILD_EXTERNAL_LEXER 0 #endif #define HA_MODE_DEFAULT 0 #define HA_MODE_IMPORT1 1 #define HA_MODE_IMPORT2 2 #define HA_MODE_IMPORT3 3 #define HA_MODE_MODULE 4 #define HA_MODE_FFI 5 #define HA_MODE_TYPE 6 static inline bool IsNewline(const int ch) { return (ch == '\n' || ch == '\r'); } static inline bool IsWhitespace(const int ch) { return ( ch == ' ' || ch == '\t' || IsNewline(ch) ); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\''); } static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &ffi = *keywordlists[1]; StyleContext sc(startPos, length, initStyle, styler); int lineCurrent = styler.GetLine(startPos); int state = lineCurrent ? styler.GetLineState(lineCurrent-1) : HA_MODE_DEFAULT; int mode = state & 0xF; int xmode = state >> 4; while (sc.More()) { // Check for state end // Operator if (sc.state == SCE_HA_OPERATOR) { if (isascii(sc.ch) && isoperator(static_cast(sc.ch))) { sc.Forward(); } else { styler.ColourTo(sc.currentPos - 1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } } // String else if (sc.state == SCE_HA_STRING) { if (sc.ch == '\"') { sc.Forward(); styler.ColourTo(sc.currentPos-1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } else if (sc.ch == '\\') { sc.Forward(2); } else if (sc.atLineEnd) { styler.ColourTo(sc.currentPos-1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } else { sc.Forward(); } } // Char else if (sc.state == SCE_HA_CHARACTER) { if (sc.ch == '\'') { sc.Forward(); styler.ColourTo(sc.currentPos-1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } else if (sc.ch == '\\') { sc.Forward(2); } else if (sc.atLineEnd) { styler.ColourTo(sc.currentPos-1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } else { sc.Forward(); } } // Number else if (sc.state == SCE_HA_NUMBER) { if (IsADigit(sc.ch, xmode)) { sc.Forward(); } else if ((xmode == 10) && (sc.ch == 'e' || sc.ch == 'E') && (IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-')) { sc.Forward(); if (sc.ch == '+' || sc.ch == '-') sc.Forward(); } else { styler.ColourTo(sc.currentPos - 1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } } // Identifier else if (sc.state == SCE_HA_IDENTIFIER) { if (IsAWordChar(sc.ch)) { sc.Forward(); } else { char s[100]; sc.GetCurrent(s, sizeof(s)); int style = sc.state; int new_mode = 0; if (keywords.InList(s)) { style = SCE_HA_KEYWORD; } else if (isupper(s[0])) { if (mode >= HA_MODE_IMPORT1 && mode <= HA_MODE_IMPORT3) { style = SCE_HA_MODULE; new_mode = HA_MODE_IMPORT2; } else if (mode == HA_MODE_MODULE) style = SCE_HA_MODULE; else style = SCE_HA_CAPITAL; } else if (mode == HA_MODE_IMPORT1 && strcmp(s,"qualified") == 0) { style = SCE_HA_KEYWORD; new_mode = HA_MODE_IMPORT1; } else if (mode == HA_MODE_IMPORT2) { if (strcmp(s,"as") == 0) { style = SCE_HA_KEYWORD; new_mode = HA_MODE_IMPORT3; } else if (strcmp(s,"hiding") == 0) { style = SCE_HA_KEYWORD; } } else if (mode == HA_MODE_FFI) { if (ffi.InList(s)) { style = SCE_HA_KEYWORD; new_mode = HA_MODE_FFI; } } else if (mode == HA_MODE_TYPE) { if (strcmp(s,"family") == 0) style = SCE_HA_KEYWORD; } styler.ColourTo(sc.currentPos - 1, style); if (strcmp(s,"import") == 0 && mode != HA_MODE_FFI) new_mode = HA_MODE_IMPORT1; else if (strcmp(s,"module") == 0) new_mode = HA_MODE_MODULE; else if (strcmp(s,"foreign") == 0) new_mode = HA_MODE_FFI; else if (strcmp(s,"type") == 0) new_mode = HA_MODE_TYPE; sc.ChangeState(SCE_HA_DEFAULT); mode = new_mode; } } // Comments // Oneliner else if (sc.state == SCE_HA_COMMENTLINE) { if (sc.atLineEnd) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } else { sc.Forward(); } } // Nested else if (sc.state == SCE_HA_COMMENTBLOCK) { if (sc.Match("{-")) { sc.Forward(2); xmode++; } else if (sc.Match("-}")) { sc.Forward(2); xmode--; if (xmode == 0) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.ChangeState(SCE_HA_DEFAULT); } } else { if (sc.atLineEnd) { // Remember the line state for future incremental lexing styler.SetLineState(lineCurrent, (xmode << 4) | mode); lineCurrent++; } sc.Forward(); } } // New state? if (sc.state == SCE_HA_DEFAULT) { // Digit if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)) || (sc.ch == '-' && IsADigit(sc.chNext))) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.ChangeState(SCE_HA_NUMBER); if (sc.ch == '0' && (sc.chNext == 'X' || sc.chNext == 'x')) { // Match anything starting with "0x" or "0X", too sc.Forward(2); xmode = 16; } else if (sc.ch == '0' && (sc.chNext == 'O' || sc.chNext == 'o')) { // Match anything starting with "0x" or "0X", too sc.Forward(2); xmode = 8; } else { sc.Forward(); xmode = 10; } mode = HA_MODE_DEFAULT; } // Comment line else if (sc.Match("--")) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(2); sc.ChangeState(SCE_HA_COMMENTLINE); // Comment block } else if (sc.Match("{-")) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(2); sc.ChangeState(SCE_HA_COMMENTBLOCK); xmode = 1; } // String else if (sc.Match('\"')) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(); sc.ChangeState(SCE_HA_STRING); } // Character else if (sc.Match('\'')) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(); sc.ChangeState(SCE_HA_CHARACTER); } else if (sc.ch == '(' || sc.ch == ')' || sc.ch == '{' || sc.ch == '}' || sc.ch == '[' || sc.ch == ']') { styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(); styler.ColourTo(sc.currentPos - 1, SCE_HA_OPERATOR); mode = HA_MODE_DEFAULT; } // Operator else if (isascii(sc.ch) && isoperator(static_cast(sc.ch))) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(); sc.ChangeState(SCE_HA_OPERATOR); mode = HA_MODE_DEFAULT; } // Keyword else if (IsAWordStart(sc.ch)) { styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(); sc.ChangeState(SCE_HA_IDENTIFIER); } else { if (sc.atLineEnd) { // Remember the line state for future incremental lexing styler.SetLineState(lineCurrent, (xmode << 4) | mode); lineCurrent++; } sc.Forward(); } } } sc.Complete(); } // External stuff - used for dynamic-loading, not implemented in wxStyledTextCtrl yet. // Inspired by the caml external lexer - Credits to Robert Roessler - http://www.rftp.com #ifdef BUILD_EXTERNAL_LEXER static const char* LexerName = "haskell"; void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props) { PropSetSimple ps; ps.SetMultiple(props); WindowAccessor wa(window, ps); int nWL = 0; for (; words[nWL]; nWL++) ; WordList** wl = new WordList* [nWL + 1]; int i = 0; for (; iSet(words[i]); } wl[i] = 0; ColorizeHaskellDoc(startPos, length, initStyle, wl, wa); wa.Flush(); for (i=nWL-1;i>=0;i--) delete wl[i]; delete [] wl; } void EXT_LEXER_DECL Fold (unsigned int lexer, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props) { } int EXT_LEXER_DECL GetLexerCount() { return 1; } void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int buflength) { if (buflength > 0) { buflength--; int n = strlen(LexerName); if (n > buflength) n = buflength; memcpy(name, LexerName, n), name[n] = '\0'; } } #endif LexerModule lmHaskell(SCLEX_HASKELL, ColorizeHaskellDoc, "haskell"); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexTxt2tags.cxx0000644000175000017500000004125011615412040022042 00000000000000/****************************************************************** * LexTxt2tags.cxx * * A simple Txt2tags lexer for scintilla. * * * Adapted by Eric Forgeot * Based on the LexMarkdown.cxx by Jon Strait - jstrait@moonloop.net * * What could be improved: * - Verbatim lines could be like for raw lines : when there is no space between the ``` and the following text, the first letter should be colored so the user would understand there must be a space for a valid tag. * - marks such as bold, italic, strikeout, underline should begin to be highlighted only when they are closed and valid. * - verbatim and raw area should be highlighted too. * * The License.txt file describes the conditions under which this * software may be distributed. * *****************************************************************/ #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsNewline(const int ch) { return (ch == '\n' || ch == '\r'); } // True if can follow ch down to the end with possibly trailing whitespace static bool FollowToLineEnd(const int ch, const int state, const unsigned int endPos, StyleContext &sc) { unsigned int i = 0; while (sc.GetRelative(++i) == ch) ; // Skip over whitespace while (IsASpaceOrTab(sc.GetRelative(i)) && sc.currentPos + i < endPos) ++i; if (IsNewline(sc.GetRelative(i)) || sc.currentPos + i == endPos) { sc.Forward(i); sc.ChangeState(state); sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); return true; } else return false; } // Does the previous line have more than spaces and tabs? static bool HasPrevLineContent(StyleContext &sc) { int i = 0; // Go back to the previous newline while ((--i + sc.currentPos) && !IsNewline(sc.GetRelative(i))) ; while (--i + sc.currentPos) { if (IsNewline(sc.GetRelative(i))) break; if (!IsASpaceOrTab(sc.GetRelative(i))) return true; } return false; } // Separator line static bool IsValidHrule(const unsigned int endPos, StyleContext &sc) { int c, count = 1; unsigned int i = 0; while (++i) { c = sc.GetRelative(i); if (c == sc.ch) ++count; // hit a terminating character else if (!IsASpaceOrTab(c) || sc.currentPos + i == endPos) { // Are we a valid HRULE if ((IsNewline(c) || sc.currentPos + i == endPos) && count >= 20 && !HasPrevLineContent(sc)) { sc.SetState(SCE_TXT2TAGS_HRULE); sc.Forward(i); sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); return true; } else { sc.SetState(SCE_TXT2TAGS_DEFAULT); return false; } } } return false; } static void ColorizeTxt2tagsDoc(unsigned int startPos, int length, int initStyle, WordList **, Accessor &styler) { unsigned int endPos = startPos + length; int precharCount = 0; // Don't advance on a new loop iteration and retry at the same position. // Useful in the corner case of having to start at the beginning file position // in the default state. bool freezeCursor = false; StyleContext sc(startPos, length, initStyle, styler); while (sc.More()) { // Skip past escaped characters if (sc.ch == '\\') { sc.Forward(); continue; } // A blockquotes resets the line semantics if (sc.state == SCE_TXT2TAGS_BLOCKQUOTE){ sc.Forward(2); sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); } // An option colors the whole line if (sc.state == SCE_TXT2TAGS_OPTION){ FollowToLineEnd('%', SCE_TXT2TAGS_OPTION, endPos, sc); } if (sc.state == SCE_TXT2TAGS_POSTPROC){ FollowToLineEnd('%', SCE_TXT2TAGS_POSTPROC, endPos, sc); } if (sc.state == SCE_TXT2TAGS_PREPROC){ FollowToLineEnd('%', SCE_TXT2TAGS_PREPROC, endPos, sc); } // A comment colors the whole line if (sc.state == SCE_TXT2TAGS_COMMENT){ FollowToLineEnd('%', SCE_TXT2TAGS_COMMENT, endPos, sc); } // Conditional state-based actions if (sc.state == SCE_TXT2TAGS_CODE2) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); if (sc.Match("``") && sc.GetRelative(-2) != ' ') { sc.Forward(2); sc.SetState(SCE_TXT2TAGS_DEFAULT); } } // Table else if (sc.state == SCE_TXT2TAGS_CODE) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); if (sc.ch == '|' && sc.chPrev != ' ') sc.ForwardSetState(SCE_TXT2TAGS_DEFAULT); } // Strong else if (sc.state == SCE_TXT2TAGS_STRONG1) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); if (sc.Match("**") && sc.chPrev != ' ') { sc.Forward(2); sc.SetState(SCE_TXT2TAGS_DEFAULT); } } // Emphasis else if (sc.state == SCE_TXT2TAGS_EM1) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); if (sc.Match("//") && sc.chPrev != ' ') { sc.Forward(2); sc.ForwardSetState(SCE_TXT2TAGS_DEFAULT); } } // Underline else if (sc.state == SCE_TXT2TAGS_EM2) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); if (sc.Match("__") && sc.chPrev != ' ') { sc.Forward(2); sc.ForwardSetState(SCE_TXT2TAGS_DEFAULT); } } // codeblock else if (sc.state == SCE_TXT2TAGS_CODEBK) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); if (sc.atLineStart && sc.Match("```")) { int i = 1; while (!IsNewline(sc.GetRelative(i)) && sc.currentPos + i < endPos) i++; sc.Forward(i); sc.SetState(SCE_TXT2TAGS_DEFAULT); } } // strikeout else if (sc.state == SCE_TXT2TAGS_STRIKEOUT) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); if (sc.Match("--") && sc.chPrev != ' ') { sc.Forward(2); sc.SetState(SCE_TXT2TAGS_DEFAULT); } } // Headers else if (sc.state == SCE_TXT2TAGS_LINE_BEGIN) { if (sc.Match("======")) { sc.SetState(SCE_TXT2TAGS_HEADER6); sc.Forward(); } else if (sc.Match("=====")) { sc.SetState(SCE_TXT2TAGS_HEADER5); sc.Forward(); } else if (sc.Match("====")) { sc.SetState(SCE_TXT2TAGS_HEADER4); sc.Forward(); } else if (sc.Match("===")) { sc.SetState(SCE_TXT2TAGS_HEADER3); sc.Forward(); } //SetStateAndZoom(SCE_TXT2TAGS_HEADER3, 3, '=', sc); else if (sc.Match("==")) { sc.SetState(SCE_TXT2TAGS_HEADER2); sc.Forward(); } //SetStateAndZoom(SCE_TXT2TAGS_HEADER2, 2, '=', sc); else if (sc.Match("=")) { // Catch the special case of an unordered list if (sc.chNext == '.' && IsASpaceOrTab(sc.GetRelative(2))) { precharCount = 0; sc.SetState(SCE_TXT2TAGS_PRECHAR); } else { sc.SetState(SCE_TXT2TAGS_HEADER1); sc.Forward(); } //SetStateAndZoom(SCE_TXT2TAGS_HEADER1, 1, '=', sc); } // Numbered title else if (sc.Match("++++++")) { sc.SetState(SCE_TXT2TAGS_HEADER6); sc.Forward(); } else if (sc.Match("+++++")) { sc.SetState(SCE_TXT2TAGS_HEADER5); sc.Forward(); } else if (sc.Match("++++")) { sc.SetState(SCE_TXT2TAGS_HEADER4); sc.Forward(); } else if (sc.Match("+++")) { sc.SetState(SCE_TXT2TAGS_HEADER3); sc.Forward(); } //SetStateAndZoom(SCE_TXT2TAGS_HEADER3, 3, '+', sc); else if (sc.Match("++")) { sc.SetState(SCE_TXT2TAGS_HEADER2); sc.Forward(); } //SetStateAndZoom(SCE_TXT2TAGS_HEADER2, 2, '+', sc); else if (sc.Match("+")) { // Catch the special case of an unordered list if (sc.chNext == ' ' && IsASpaceOrTab(sc.GetRelative(1))) { // if (IsNewline(sc.ch)) { //precharCount = 0; // sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); //sc.SetState(SCE_TXT2TAGS_PRECHAR); // } // else { // precharCount = 0; sc.SetState(SCE_TXT2TAGS_OLIST_ITEM); sc.Forward(2); sc.SetState(SCE_TXT2TAGS_DEFAULT); // sc.SetState(SCE_TXT2TAGS_PRECHAR); // } } else { sc.SetState(SCE_TXT2TAGS_HEADER1); sc.Forward(); } } // Codeblock else if (sc.Match("```")) { if (!HasPrevLineContent(sc)) // if (!FollowToLineEnd(sc)) sc.SetState(SCE_TXT2TAGS_CODEBK); else sc.SetState(SCE_TXT2TAGS_DEFAULT); } // Preproc else if (sc.Match("%!preproc")) { sc.SetState(SCE_TXT2TAGS_PREPROC); } // Postproc else if (sc.Match("%!postproc")) { sc.SetState(SCE_TXT2TAGS_POSTPROC); } // Option else if (sc.Match("%!")) { sc.SetState(SCE_TXT2TAGS_OPTION); } // Comment else if (sc.ch == '%') { sc.SetState(SCE_TXT2TAGS_COMMENT); } // list else if (sc.ch == '-') { precharCount = 0; sc.SetState(SCE_TXT2TAGS_PRECHAR); } // def list else if (sc.ch == ':') { precharCount = 0; sc.SetState(SCE_TXT2TAGS_OLIST_ITEM); sc.Forward(1); sc.SetState(SCE_TXT2TAGS_PRECHAR); } else if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); else { precharCount = 0; sc.SetState(SCE_TXT2TAGS_PRECHAR); } } // The header lasts until the newline else if (sc.state == SCE_TXT2TAGS_HEADER1 || sc.state == SCE_TXT2TAGS_HEADER2 || sc.state == SCE_TXT2TAGS_HEADER3 || sc.state == SCE_TXT2TAGS_HEADER4 || sc.state == SCE_TXT2TAGS_HEADER5 || sc.state == SCE_TXT2TAGS_HEADER6) { if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); } // New state only within the initial whitespace if (sc.state == SCE_TXT2TAGS_PRECHAR) { // Blockquote if (sc.Match("\"\"\"") && precharCount < 5){ sc.SetState(SCE_TXT2TAGS_BLOCKQUOTE); sc.Forward(1); } /* // Begin of code block else if (!HasPrevLineContent(sc) && (sc.chPrev == '\t' || precharCount >= 4)) sc.SetState(SCE_TXT2TAGS_CODEBK); */ // HRule - Total of 20 or more hyphens, asterisks, or underscores // on a line by themselves else if ((sc.ch == '-' ) && IsValidHrule(endPos, sc)) ; // Unordered list else if ((sc.ch == '-') && IsASpaceOrTab(sc.chNext)) { sc.SetState(SCE_TXT2TAGS_ULIST_ITEM); sc.ForwardSetState(SCE_TXT2TAGS_DEFAULT); } // Ordered list else if (IsADigit(sc.ch)) { int digitCount = 0; while (IsADigit(sc.GetRelative(++digitCount))) ; if (sc.GetRelative(digitCount) == '.' && IsASpaceOrTab(sc.GetRelative(digitCount + 1))) { sc.SetState(SCE_TXT2TAGS_OLIST_ITEM); sc.Forward(digitCount + 1); sc.SetState(SCE_TXT2TAGS_DEFAULT); } } // Alternate Ordered list else if (sc.ch == '+' && sc.chNext == ' ' && IsASpaceOrTab(sc.GetRelative(2))) { // sc.SetState(SCE_TXT2TAGS_OLIST_ITEM); // sc.Forward(2); // sc.SetState(SCE_TXT2TAGS_DEFAULT); } else if (sc.ch != ' ' || precharCount > 2) sc.SetState(SCE_TXT2TAGS_DEFAULT); else ++precharCount; } // New state anywhere in doc if (sc.state == SCE_TXT2TAGS_DEFAULT) { // if (sc.atLineStart && sc.ch == '#') { // sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); // freezeCursor = true; // } // Links and Images if (sc.Match("![") || sc.ch == '[') { int i = 0, j = 0, k = 0; int len = endPos - sc.currentPos; while (i < len && (sc.GetRelative(++i) != ']' || sc.GetRelative(i - 1) == '\\')) ; if (sc.GetRelative(i) == ']') { j = i; if (sc.GetRelative(++i) == '(') { while (i < len && (sc.GetRelative(++i) != '(' || sc.GetRelative(i - 1) == '\\')) ; if (sc.GetRelative(i) == '(') k = i; } else if (sc.GetRelative(i) == '[' || sc.GetRelative(++i) == '[') { while (i < len && (sc.GetRelative(++i) != ']' || sc.GetRelative(i - 1) == '\\')) ; if (sc.GetRelative(i) == ']') k = i; } } // At least a link text if (j) { sc.SetState(SCE_TXT2TAGS_LINK); sc.Forward(j); // Also has a URL or reference portion if (k) sc.Forward(k - j); sc.ForwardSetState(SCE_TXT2TAGS_DEFAULT); } } // Code - also a special case for alternate inside spacing if (sc.Match("``") && sc.GetRelative(3) != ' ') { sc.SetState(SCE_TXT2TAGS_CODE2); sc.Forward(); } else if (sc.ch == '|' && sc.GetRelative(3) != ' ') { sc.SetState(SCE_TXT2TAGS_CODE); } // Strong else if (sc.Match("**") && sc.GetRelative(2) != ' ') { sc.SetState(SCE_TXT2TAGS_STRONG1); sc.Forward(); } // Emphasis else if (sc.Match("//") && sc.GetRelative(2) != ' ') { sc.SetState(SCE_TXT2TAGS_EM1); sc.Forward(); } else if (sc.Match("__") && sc.GetRelative(2) != ' ') { sc.SetState(SCE_TXT2TAGS_EM2); sc.Forward(); } // Strikeout else if (sc.Match("--") && sc.GetRelative(2) != ' ') { sc.SetState(SCE_TXT2TAGS_STRIKEOUT); sc.Forward(); } // Beginning of line else if (IsNewline(sc.ch)) sc.SetState(SCE_TXT2TAGS_LINE_BEGIN); } // Advance if not holding back the cursor for this iteration. if (!freezeCursor) sc.Forward(); freezeCursor = false; } sc.Complete(); } LexerModule lmTxt2tags(SCLEX_TXT2TAGS, ColorizeTxt2tagsDoc, "txt2tags"); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexModula.cxx0000644000175000017500000004001211634611460021546 00000000000000// -*- coding: utf-8 -*- // Scintilla source code edit control /** * @file LexModula.cxx * @author Dariusz "DKnoto" KnociÅ„ski * @date 2011/02/03 * @brief Lexer for Modula-2/3 documents. */ // The License.txt file describes the conditions under which this software may // be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #ifdef DEBUG_LEX_MODULA #define DEBUG_STATE( p, c )\ fprintf( stderr, "Unknown state: currentPos = %d, char = '%c'\n", p, c ); #else #define DEBUG_STATE( p, c ) #endif static inline bool IsDigitOfBase( unsigned ch, unsigned base ) { if( ch < '0' || ch > 'f' ) return false; if( base <= 10 ) { if( ch >= ( '0' + base ) ) return false; } else { if( ch > '9' ) { unsigned nb = base - 10; if( ( ch < 'A' ) || ( ch >= ( 'A' + nb ) ) ) { if( ( ch < 'a' ) || ( ch >= ( 'a' + nb ) ) ) { return false; } } } } return true; } static inline unsigned IsOperator( StyleContext & sc, WordList & op ) { int i; char s[3]; s[0] = sc.ch; s[1] = sc.chNext; s[2] = 0; for( i = 0; i < op.len; i++ ) { if( ( strlen( op.words[i] ) == 2 ) && ( s[0] == op.words[i][0] && s[1] == op.words[i][1] ) ) { return 2; } } s[1] = 0; for( i = 0; i < op.len; i++ ) { if( ( strlen( op.words[i] ) == 1 ) && ( s[0] == op.words[i][0] ) ) { return 1; } } return 0; } static inline bool IsEOL( Accessor &styler, unsigned curPos ) { unsigned ch = styler.SafeGetCharAt( curPos ); if( ( ch == '\r' && styler.SafeGetCharAt( curPos + 1 ) == '\n' ) || ( ch == '\n' ) ) { return true; } return false; } static inline bool checkStatement( Accessor &styler, int &curPos, const char *stt, bool spaceAfter = true ) { int len = static_cast(strlen( stt )); int i; for( i = 0; i < len; i++ ) { if( styler.SafeGetCharAt( curPos + i ) != stt[i] ) { return false; } } if( spaceAfter ) { if( ! isspace( styler.SafeGetCharAt( curPos + i ) ) ) { return false; } } curPos += ( len - 1 ); return true; } static inline bool checkEndSemicolon( Accessor &styler, int &curPos, int endPos ) { const char *stt = "END"; int len = static_cast(strlen( stt )); int i; for( i = 0; i < len; i++ ) { if( styler.SafeGetCharAt( curPos + i ) != stt[i] ) { return false; } } while( isspace( styler.SafeGetCharAt( curPos + i ) ) ) { i++; if( ( curPos + i ) >= endPos ) return false; } if( styler.SafeGetCharAt( curPos + i ) != ';' ) { return false; } curPos += ( i - 1 ); return true; } static inline bool checkKeyIdentOper( Accessor &styler, int &curPos, int endPos, const char *stt, const char etk ) { int newPos = curPos; if( ! checkStatement( styler, newPos, stt ) ) return false; newPos++; if( newPos >= endPos ) return false; if( ! isspace( styler.SafeGetCharAt( newPos ) ) ) return false; newPos++; if( newPos >= endPos ) return false; while( isspace( styler.SafeGetCharAt( newPos ) ) ) { newPos++; if( newPos >= endPos ) return false; } if( ! isalpha( styler.SafeGetCharAt( newPos ) ) ) return false; newPos++; if( newPos >= endPos ) return false; char ch; ch = styler.SafeGetCharAt( newPos ); while( isalpha( ch ) || isdigit( ch ) || ch == '_' ) { newPos++; if( newPos >= endPos ) return false; ch = styler.SafeGetCharAt( newPos ); } while( isspace( styler.SafeGetCharAt( newPos ) ) ) { newPos++; if( newPos >= endPos ) return false; } if( styler.SafeGetCharAt( newPos ) != etk ) return false; curPos = newPos; return true; } static void FoldModulaDoc( unsigned int startPos, int length, int , WordList *[], Accessor &styler) { int curLine = styler.GetLine(startPos); int curLevel = SC_FOLDLEVELBASE; int endPos = startPos + length; if( curLine > 0 ) curLevel = styler.LevelAt( curLine - 1 ) >> 16; int curPos = startPos; int style = styler.StyleAt( curPos ); int visChars = 0; int nextLevel = curLevel; while( curPos < endPos ) { if( ! isspace( styler.SafeGetCharAt( curPos ) ) ) visChars++; switch( style ) { case SCE_MODULA_COMMENT: if( checkStatement( styler, curPos, "(*" ) ) nextLevel++; else if( checkStatement( styler, curPos, "*)" ) ) nextLevel--; break; case SCE_MODULA_DOXYCOMM: if( checkStatement( styler, curPos, "(**", false ) ) nextLevel++; else if( checkStatement( styler, curPos, "*)" ) ) nextLevel--; break; case SCE_MODULA_KEYWORD: if( checkStatement( styler, curPos, "IF" ) ) nextLevel++; else if( checkStatement( styler, curPos, "BEGIN" ) ) nextLevel++; else if( checkStatement( styler, curPos, "TRY" ) ) nextLevel++; else if( checkStatement( styler, curPos, "LOOP" ) ) nextLevel++; else if( checkStatement( styler, curPos, "FOR" ) ) nextLevel++; else if( checkStatement( styler, curPos, "WHILE" ) ) nextLevel++; else if( checkStatement( styler, curPos, "REPEAT" ) ) nextLevel++; else if( checkStatement( styler, curPos, "UNTIL" ) ) nextLevel--; else if( checkStatement( styler, curPos, "WITH" ) ) nextLevel++; else if( checkStatement( styler, curPos, "CASE" ) ) nextLevel++; else if( checkStatement( styler, curPos, "TYPECASE" ) ) nextLevel++; else if( checkStatement( styler, curPos, "LOCK" ) ) nextLevel++; else if( checkKeyIdentOper( styler, curPos, endPos, "PROCEDURE", '(' ) ) nextLevel++; else if( checkKeyIdentOper( styler, curPos, endPos, "END", ';' ) ) { int cln = curLine; int clv_old = curLevel; int pos; char ch; int clv_new; while( cln > 0 ) { clv_new = styler.LevelAt( cln - 1 ) >> 16; if( clv_new < clv_old ) { nextLevel--; pos = styler.LineStart( cln ); while( ( ch = styler.SafeGetCharAt( pos ) ) != '\n' ) { if( ch == 'P' ) { if( styler.StyleAt(pos) == SCE_MODULA_KEYWORD ) { if( checkKeyIdentOper( styler, pos, endPos, "PROCEDURE", '(' ) ) { break; } } } pos++; } clv_old = clv_new; } cln--; } } else if( checkKeyIdentOper( styler, curPos, endPos, "END", '.' ) ) nextLevel--; else if( checkEndSemicolon( styler, curPos, endPos ) ) nextLevel--; else { while( styler.StyleAt( curPos + 1 ) == SCE_MODULA_KEYWORD ) curPos++; } break; default: break; } if( IsEOL( styler, curPos ) || ( curPos == endPos - 1 ) ) { int efectiveLevel = curLevel | nextLevel << 16; if( visChars == 0 ) efectiveLevel |= SC_FOLDLEVELWHITEFLAG; if( curLevel < nextLevel ) efectiveLevel |= SC_FOLDLEVELHEADERFLAG; if( efectiveLevel != styler.LevelAt(curLine) ) { styler.SetLevel(curLine, efectiveLevel ); } curLine++; curLevel = nextLevel; if( IsEOL( styler, curPos ) && ( curPos == endPos - 1 ) ) { styler.SetLevel( curLine, ( curLevel | curLevel << 16) | SC_FOLDLEVELWHITEFLAG); } visChars = 0; } curPos++; style = styler.StyleAt( curPos ); } } static inline bool skipWhiteSpaces( StyleContext & sc ) { while( isspace( sc.ch ) ) { sc.SetState( SCE_MODULA_DEFAULT ); if( sc.More() ) sc.Forward(); else return false; } return true; } static void ColouriseModulaDoc( unsigned int startPos, int length, int initStyle, WordList *wl[], Accessor &styler ) { WordList& keyWords = *wl[0]; WordList& reservedWords = *wl[1]; WordList& operators = *wl[2]; WordList& pragmaWords = *wl[3]; WordList& escapeCodes = *wl[4]; WordList& doxyKeys = *wl[5]; const int BUFLEN = 128; char buf[BUFLEN]; int i, kl; int charPos = 0; StyleContext sc( startPos, length, initStyle, styler ); while( sc.More() ) { switch( sc.state ) { case SCE_MODULA_DEFAULT: if( ! skipWhiteSpaces( sc ) ) break; if( sc.ch == '(' && sc.chNext == '*' ) { if( sc.GetRelative(2) == '*' ) { sc.SetState( SCE_MODULA_DOXYCOMM ); sc.Forward(); } else { sc.SetState( SCE_MODULA_COMMENT ); } sc.Forward(); } else if( isalpha( sc.ch ) ) { if( isupper( sc.ch ) && isupper( sc.chNext ) ) { for( i = 0; i < BUFLEN - 1; i++ ) { buf[i] = sc.GetRelative(i); if( !isalpha( buf[i] ) && !(buf[i] == '_') ) break; } kl = i; buf[kl] = 0; if( keyWords.InList( buf ) ) { sc.SetState( SCE_MODULA_KEYWORD ); sc.Forward( kl ); sc.SetState( SCE_MODULA_DEFAULT ); continue; } else if( reservedWords.InList( buf ) ) { sc.SetState( SCE_MODULA_RESERVED ); sc.Forward( kl ); sc.SetState( SCE_MODULA_DEFAULT ); continue; } else { /** check procedure identifier */ } } else { for( i = 0; i < BUFLEN - 1; i++ ) { buf[i] = sc.GetRelative(i); if( !isalpha( buf[i] ) && !isdigit( buf[i] ) && !(buf[i] == '_') ) break; } kl = i; buf[kl] = 0; sc.SetState( SCE_MODULA_DEFAULT ); sc.Forward( kl ); continue; } } else if( isdigit( sc.ch ) ) { sc.SetState( SCE_MODULA_NUMBER ); continue; } else if( sc.ch == '\"' ) { sc.SetState( SCE_MODULA_STRING ); } else if( sc.ch == '\'' ) { charPos = sc.currentPos; sc.SetState( SCE_MODULA_CHAR ); } else if( sc.ch == '<' && sc.chNext == '*' ) { sc.SetState( SCE_MODULA_PRAGMA ); sc.Forward(); } else { unsigned len = IsOperator( sc, operators ); if( len > 0 ) { sc.SetState( SCE_MODULA_OPERATOR ); sc.Forward( len ); sc.SetState( SCE_MODULA_DEFAULT ); continue; } else { DEBUG_STATE( sc.currentPos, sc.ch ); } } break; case SCE_MODULA_COMMENT: if( sc.ch == '*' && sc.chNext == ')' ) { sc.Forward( 2 ); sc.SetState( SCE_MODULA_DEFAULT ); continue; } break; case SCE_MODULA_DOXYCOMM: switch( sc.ch ) { case '*': if( sc.chNext == ')' ) { sc.Forward( 2 ); sc.SetState( SCE_MODULA_DEFAULT ); continue; } break; case '@': if( islower( sc.chNext ) ) { for( i = 0; i < BUFLEN - 1; i++ ) { buf[i] = sc.GetRelative(i+1); if( isspace( buf[i] ) ) break; } buf[i] = 0; kl = i; if( doxyKeys.InList( buf ) ) { sc.SetState( SCE_MODULA_DOXYKEY ); sc.Forward( kl + 1 ); sc.SetState( SCE_MODULA_DOXYCOMM ); } } break; default: break; } break; case SCE_MODULA_NUMBER: { buf[0] = sc.ch; for( i = 1; i < BUFLEN - 1; i++ ) { buf[i] = sc.GetRelative(i); if( ! isdigit( buf[i] ) ) break; } kl = i; buf[kl] = 0; switch( sc.GetRelative(kl) ) { case '_': { int base = atoi( buf ); if( base < 2 || base > 16 ) { sc.SetState( SCE_MODULA_BADSTR ); } else { int imax; kl++; for( i = 0; i < BUFLEN - 1; i++ ) { buf[i] = sc.GetRelative(kl+i); if( ! IsDigitOfBase( buf[i], 16 ) ) { break; } } imax = i; for( i = 0; i < imax; i++ ) { if( ! IsDigitOfBase( buf[i], base ) ) { sc.SetState( SCE_MODULA_BADSTR ); break; } } kl += imax; } sc.SetState( SCE_MODULA_BASENUM ); for( i = 0; i < kl; i++ ) { sc.Forward(); } sc.SetState( SCE_MODULA_DEFAULT ); continue; } break; case '.': if( sc.GetRelative(kl+1) == '.' ) { kl--; for( i = 0; i < kl; i++ ) { sc.Forward(); } sc.Forward(); sc.SetState( SCE_MODULA_DEFAULT ); continue; } else { bool doNext = false; kl++; buf[0] = sc.GetRelative(kl); if( isdigit( buf[0] ) ) { for( i = 0;; i++ ) { if( !isdigit(sc.GetRelative(kl+i)) ) break; } kl += i; buf[0] = sc.GetRelative(kl); switch( buf[0] ) { case 'E': case 'e': case 'D': case 'd': case 'X': case 'x': kl++; buf[0] = sc.GetRelative(kl); if( buf[0] == '-' || buf[0] == '+' ) { kl++; } buf[0] = sc.GetRelative(kl); if( isdigit( buf[0] ) ) { for( i = 0;; i++ ) { if( !isdigit(sc.GetRelative(kl+i)) ) { buf[0] = sc.GetRelative(kl+i); break; } } kl += i; doNext = true; } else { sc.SetState( SCE_MODULA_BADSTR ); } break; default: doNext = true; break; } } else { sc.SetState( SCE_MODULA_BADSTR ); } if( doNext ) { if( ! isspace( buf[0] ) && buf[0] != ')' && buf[0] != '>' && buf[0] != '<' && buf[0] != '=' && buf[0] != '#' && buf[0] != '+' && buf[0] != '-' && buf[0] != '*' && buf[0] != '/' && buf[0] != ',' && buf[0] != ';' ) { sc.SetState( SCE_MODULA_BADSTR ); } else { kl--; } } } sc.SetState( SCE_MODULA_FLOAT ); for( i = 0; i < kl; i++ ) { sc.Forward(); } sc.SetState( SCE_MODULA_DEFAULT ); continue; break; default: for( i = 0; i < kl; i++ ) { sc.Forward(); } break; } sc.SetState( SCE_MODULA_DEFAULT ); continue; } break; case SCE_MODULA_STRING: if( sc.ch == '\"' ) { sc.Forward(); sc.SetState( SCE_MODULA_DEFAULT ); continue; } else { if( sc.ch == '\\' ) { i = 1; if( IsDigitOfBase( sc.chNext, 8 ) ) { for( i = 1; i < BUFLEN - 1; i++ ) { if( ! IsDigitOfBase(sc.GetRelative(i+1), 8 ) ) break; } if( i == 3 ) { sc.SetState( SCE_MODULA_STRSPEC ); } else { sc.SetState( SCE_MODULA_BADSTR ); } } else { buf[0] = sc.chNext; buf[1] = 0; if( escapeCodes.InList( buf ) ) { sc.SetState( SCE_MODULA_STRSPEC ); } else { sc.SetState( SCE_MODULA_BADSTR ); } } sc.Forward(i+1); sc.SetState( SCE_MODULA_STRING ); continue; } } break; case SCE_MODULA_CHAR: if( sc.ch == '\'' ) { sc.Forward(); sc.SetState( SCE_MODULA_DEFAULT ); continue; } else if( ( sc.currentPos - charPos ) == 1 ) { if( sc.ch == '\\' ) { i = 1; if( IsDigitOfBase( sc.chNext, 8 ) ) { for( i = 1; i < BUFLEN - 1; i++ ) { if( ! IsDigitOfBase(sc.GetRelative(i+1), 8 ) ) break; } if( i == 3 ) { sc.SetState( SCE_MODULA_CHARSPEC ); } else { sc.SetState( SCE_MODULA_BADSTR ); } } else { buf[0] = sc.chNext; buf[1] = 0; if( escapeCodes.InList( buf ) ) { sc.SetState( SCE_MODULA_CHARSPEC ); } else { sc.SetState( SCE_MODULA_BADSTR ); } } sc.Forward(i+1); sc.SetState( SCE_MODULA_CHAR ); continue; } } else { sc.SetState( SCE_MODULA_BADSTR ); sc.Forward(); sc.SetState( SCE_MODULA_CHAR ); continue; } break; case SCE_MODULA_PRAGMA: if( sc.ch == '*' && sc.chNext == '>' ) { sc.Forward(); sc.Forward(); sc.SetState( SCE_MODULA_DEFAULT ); continue; } else if( isupper( sc.ch ) && isupper( sc.chNext ) ) { buf[0] = sc.ch; buf[1] = sc.chNext; for( i = 2; i < BUFLEN - 1; i++ ) { buf[i] = sc.GetRelative(i); if( !isupper( buf[i] ) ) break; } kl = i; buf[kl] = 0; if( pragmaWords.InList( buf ) ) { sc.SetState( SCE_MODULA_PRGKEY ); sc.Forward( kl ); sc.SetState( SCE_MODULA_PRAGMA ); continue; } } break; default: break; } sc.Forward(); } sc.Complete(); } static const char *const modulaWordListDesc[] = { "Keywords", "ReservedKeywords", "Operators", "PragmaKeyswords", "EscapeCodes", "DoxygeneKeywords", 0 }; LexerModule lmModula( SCLEX_MODULA, ColouriseModulaDoc, "modula", FoldModulaDoc, modulaWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexSQL.cxx0000644000175000017500000006271211763437013021002 00000000000000//-*- coding: utf-8 -*- // Scintilla source code edit control /** @file LexSQL.cxx ** Lexer for SQL, including PL/SQL and SQL*Plus. ** Improved by Jérôme LAFORGE from 2010 to 2012. **/ // Copyright 1998-2012 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #include "SparseState.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch, bool sqlAllowDottedWord) { if (!sqlAllowDottedWord) return (ch < 0x80) && (isalnum(ch) || ch == '_'); else return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'); } static inline bool IsAWordStart(int ch) { return (ch < 0x80) && (isalpha(ch) || ch == '_'); } static inline bool IsADoxygenChar(int ch) { return (islower(ch) || ch == '$' || ch == '@' || ch == '\\' || ch == '&' || ch == '<' || ch == '>' || ch == '#' || ch == '{' || ch == '}' || ch == '[' || ch == ']'); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || toupper(ch) == 'E' || ch == '.' || ch == '-' || ch == '+'); } class SQLStates { public : void Set(int lineNumber, unsigned short int sqlStatesLine) { sqlStatement.Set(lineNumber, sqlStatesLine); } unsigned short int IgnoreWhen (unsigned short int sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_IGNORE_WHEN; else sqlStatesLine &= ~MASK_IGNORE_WHEN; return sqlStatesLine; } unsigned short int IntoCondition (unsigned short int sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_CONDITION; else sqlStatesLine &= ~MASK_INTO_CONDITION; return sqlStatesLine; } unsigned short int IntoExceptionBlock (unsigned short int sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_EXCEPTION; else sqlStatesLine &= ~MASK_INTO_EXCEPTION; return sqlStatesLine; } unsigned short int IntoDeclareBlock (unsigned short int sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_INTO_DECLARE; else sqlStatesLine &= ~MASK_INTO_DECLARE; return sqlStatesLine; } unsigned short int IntoMergeStatement (unsigned short int sqlStatesLine, bool enable) { if (enable) sqlStatesLine |= MASK_MERGE_STATEMENT; else sqlStatesLine &= ~MASK_MERGE_STATEMENT; return sqlStatesLine; } unsigned short int CaseMergeWithoutWhenFound (unsigned short int sqlStatesLine, bool found) { if (found) sqlStatesLine |= MASK_CASE_MERGE_WITHOUT_WHEN_FOUND; else sqlStatesLine &= ~MASK_CASE_MERGE_WITHOUT_WHEN_FOUND; return sqlStatesLine; } unsigned short int IntoSelectStatement (unsigned short int sqlStatesLine, bool found) { if (found) sqlStatesLine |= MASK_INTO_SELECT_STATEMENT; else sqlStatesLine &= ~MASK_INTO_SELECT_STATEMENT; return sqlStatesLine; } unsigned short int BeginCaseBlock (unsigned short int sqlStatesLine) { if ((sqlStatesLine & MASK_NESTED_CASES) < MASK_NESTED_CASES) { sqlStatesLine++; } return sqlStatesLine; } unsigned short int EndCaseBlock (unsigned short int sqlStatesLine) { if ((sqlStatesLine & MASK_NESTED_CASES) > 0) { sqlStatesLine--; } return sqlStatesLine; } bool IsIgnoreWhen (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_IGNORE_WHEN) != 0; } bool IsIntoCondition (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_INTO_CONDITION) != 0; } bool IsIntoCaseBlock (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_NESTED_CASES) != 0; } bool IsIntoExceptionBlock (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_INTO_EXCEPTION) != 0; } bool IsIntoSelectStatement (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_INTO_SELECT_STATEMENT) != 0; } bool IsCaseMergeWithoutWhenFound (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_CASE_MERGE_WITHOUT_WHEN_FOUND) != 0; } bool IsIntoDeclareBlock (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_INTO_DECLARE) != 0; } bool IsIntoMergeStatement (unsigned short int sqlStatesLine) { return (sqlStatesLine & MASK_MERGE_STATEMENT) != 0; } unsigned short int ForLine(int lineNumber) { return sqlStatement.ValueAt(lineNumber); } SQLStates() {} private : SparseState sqlStatement; enum { MASK_NESTED_CASES = 0x01FF, MASK_INTO_SELECT_STATEMENT = 0x0200, MASK_CASE_MERGE_WITHOUT_WHEN_FOUND = 0x0400, MASK_MERGE_STATEMENT = 0x0800, MASK_INTO_DECLARE = 0x1000, MASK_INTO_EXCEPTION = 0x2000, MASK_INTO_CONDITION = 0x4000, MASK_IGNORE_WHEN = 0x8000 }; }; // Options used for LexerSQL struct OptionsSQL { bool fold; bool foldAtElse; bool foldComment; bool foldCompact; bool foldOnlyBegin; bool sqlBackticksIdentifier; bool sqlNumbersignComment; bool sqlBackslashEscapes; bool sqlAllowDottedWord; OptionsSQL() { fold = false; foldAtElse = false; foldComment = false; foldCompact = false; foldOnlyBegin = false; sqlBackticksIdentifier = false; sqlNumbersignComment = false; sqlBackslashEscapes = false; sqlAllowDottedWord = false; } }; static const char * const sqlWordListDesc[] = { "Keywords", "Database Objects", "PLDoc", "SQL*Plus", "User Keywords 1", "User Keywords 2", "User Keywords 3", "User Keywords 4", 0 }; struct OptionSetSQL : public OptionSet { OptionSetSQL() { DefineProperty("fold", &OptionsSQL::fold); DefineProperty("fold.sql.at.else", &OptionsSQL::foldAtElse, "This option enables SQL folding on a \"ELSE\" and \"ELSIF\" line of an IF statement."); DefineProperty("fold.comment", &OptionsSQL::foldComment); DefineProperty("fold.compact", &OptionsSQL::foldCompact); DefineProperty("fold.sql.only.begin", &OptionsSQL::foldOnlyBegin); DefineProperty("lexer.sql.backticks.identifier", &OptionsSQL::sqlBackticksIdentifier); DefineProperty("lexer.sql.numbersign.comment", &OptionsSQL::sqlNumbersignComment, "If \"lexer.sql.numbersign.comment\" property is set to 0 a line beginning with '#' will not be a comment."); DefineProperty("sql.backslash.escapes", &OptionsSQL::sqlBackslashEscapes, "Enables backslash as an escape character in SQL."); DefineProperty("lexer.sql.allow.dotted.word", &OptionsSQL::sqlAllowDottedWord, "Set to 1 to colourise recognized words with dots " "(recommended for Oracle PL/SQL objects)."); DefineWordListSets(sqlWordListDesc); } }; class LexerSQL : public ILexer { public : LexerSQL() {} virtual ~LexerSQL() {} int SCI_METHOD Version () const { return lvOriginal; } void SCI_METHOD Release() { delete this; } const char * SCI_METHOD PropertyNames() { return osSQL.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) { return osSQL.PropertyType(name); } const char * SCI_METHOD DescribeProperty(const char *name) { return osSQL.DescribeProperty(name); } int SCI_METHOD PropertySet(const char *key, const char *val) { if (osSQL.PropertySet(&options, key, val)) { return 0; } return -1; } const char * SCI_METHOD DescribeWordListSets() { return osSQL.DescribeWordListSets(); } int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex (unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int lengthDoc, int initStyle, IDocument *pAccess); void * SCI_METHOD PrivateCall(int, void *) { return 0; } static ILexer *LexerFactorySQL() { return new LexerSQL(); } private: bool IsStreamCommentStyle(int style) { return style == SCE_SQL_COMMENT || style == SCE_SQL_COMMENTDOC || style == SCE_SQL_COMMENTDOCKEYWORD || style == SCE_SQL_COMMENTDOCKEYWORDERROR; } bool IsCommentStyle (int style) { switch (style) { case SCE_SQL_COMMENT : case SCE_SQL_COMMENTDOC : case SCE_SQL_COMMENTLINE : case SCE_SQL_COMMENTLINEDOC : case SCE_SQL_COMMENTDOCKEYWORD : case SCE_SQL_COMMENTDOCKEYWORDERROR : return true; default : return false; } } bool IsCommentLine (int line, LexAccessor &styler) { int pos = styler.LineStart(line); int eol_pos = styler.LineStart(line + 1) - 1; for (int i = pos; i + 1 < eol_pos; i++) { int style = styler.StyleAt(i); // MySQL needs -- comments to be followed by space or control char if (style == SCE_SQL_COMMENTLINE && styler.Match(i, "--")) return true; else if (!IsASpaceOrTab(styler[i])) return false; } return false; } OptionsSQL options; OptionSetSQL osSQL; SQLStates sqlStates; WordList keywords1; WordList keywords2; WordList kw_pldoc; WordList kw_sqlplus; WordList kw_user1; WordList kw_user2; WordList kw_user3; WordList kw_user4; }; int SCI_METHOD LexerSQL::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &keywords1; break; case 1: wordListN = &keywords2; break; case 2: wordListN = &kw_pldoc; break; case 3: wordListN = &kw_sqlplus; break; case 4: wordListN = &kw_user1; break; case 5: wordListN = &kw_user2; break; case 6: wordListN = &kw_user3; break; case 7: wordListN = &kw_user4; } int firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } void SCI_METHOD LexerSQL::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); StyleContext sc(startPos, length, initStyle, styler); int styleBeforeDCKeyword = SCE_SQL_DEFAULT; int offset = 0; for (; sc.More(); sc.Forward(), offset++) { // Determine if the current state should terminate. switch (sc.state) { case SCE_SQL_OPERATOR: sc.SetState(SCE_SQL_DEFAULT); break; case SCE_SQL_NUMBER: // We stop the number definition on non-numerical non-dot non-eE non-sign char if (!IsANumberChar(sc.ch)) { sc.SetState(SCE_SQL_DEFAULT); } break; case SCE_SQL_IDENTIFIER: if (!IsAWordChar(sc.ch, options.sqlAllowDottedWord)) { int nextState = SCE_SQL_DEFAULT; char s[1000]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords1.InList(s)) { sc.ChangeState(SCE_SQL_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_SQL_WORD2); } else if (kw_sqlplus.InListAbbreviated(s, '~')) { sc.ChangeState(SCE_SQL_SQLPLUS); if (strncmp(s, "rem", 3) == 0) { nextState = SCE_SQL_SQLPLUS_COMMENT; } else if (strncmp(s, "pro", 3) == 0) { nextState = SCE_SQL_SQLPLUS_PROMPT; } } else if (kw_user1.InList(s)) { sc.ChangeState(SCE_SQL_USER1); } else if (kw_user2.InList(s)) { sc.ChangeState(SCE_SQL_USER2); } else if (kw_user3.InList(s)) { sc.ChangeState(SCE_SQL_USER3); } else if (kw_user4.InList(s)) { sc.ChangeState(SCE_SQL_USER4); } sc.SetState(nextState); } break; case SCE_SQL_QUOTEDIDENTIFIER: if (sc.ch == 0x60) { if (sc.chNext == 0x60) { sc.Forward(); // Ignore it } else { sc.ForwardSetState(SCE_SQL_DEFAULT); } } break; case SCE_SQL_COMMENT: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_SQL_DEFAULT); } break; case SCE_SQL_COMMENTDOC: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_SQL_DEFAULT); } else if (sc.ch == '@' || sc.ch == '\\') { // Doxygen support // Verify that we have the conditions to mark a comment-doc-keyword if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) { styleBeforeDCKeyword = SCE_SQL_COMMENTDOC; sc.SetState(SCE_SQL_COMMENTDOCKEYWORD); } } break; case SCE_SQL_COMMENTLINE: case SCE_SQL_COMMENTLINEDOC: case SCE_SQL_SQLPLUS_COMMENT: case SCE_SQL_SQLPLUS_PROMPT: if (sc.atLineStart) { sc.SetState(SCE_SQL_DEFAULT); } break; case SCE_SQL_COMMENTDOCKEYWORD: if ((styleBeforeDCKeyword == SCE_SQL_COMMENTDOC) && sc.Match('*', '/')) { sc.ChangeState(SCE_SQL_COMMENTDOCKEYWORDERROR); sc.Forward(); sc.ForwardSetState(SCE_SQL_DEFAULT); } else if (!IsADoxygenChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (!isspace(sc.ch) || !kw_pldoc.InList(s + 1)) { sc.ChangeState(SCE_SQL_COMMENTDOCKEYWORDERROR); } sc.SetState(styleBeforeDCKeyword); } break; case SCE_SQL_CHARACTER: if (options.sqlBackslashEscapes && sc.ch == '\\') { sc.Forward(); } else if (sc.ch == '\'') { if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_SQL_DEFAULT); } } break; case SCE_SQL_STRING: if (sc.ch == '\\') { // Escape sequence sc.Forward(); } else if (sc.ch == '\"') { if (sc.chNext == '\"') { sc.Forward(); } else { sc.ForwardSetState(SCE_SQL_DEFAULT); } } break; } // Determine if a new state should be entered. if (sc.state == SCE_SQL_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_SQL_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_SQL_IDENTIFIER); } else if (sc.ch == 0x60 && options.sqlBackticksIdentifier) { sc.SetState(SCE_SQL_QUOTEDIDENTIFIER); } else if (sc.Match('/', '*')) { if (sc.Match("/**") || sc.Match("/*!")) { // Support of Doxygen doc. style sc.SetState(SCE_SQL_COMMENTDOC); } else { sc.SetState(SCE_SQL_COMMENT); } sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('-', '-')) { // MySQL requires a space or control char after -- // http://dev.mysql.com/doc/mysql/en/ansi-diff-comments.html // Perhaps we should enforce that with proper property: //~ } else if (sc.Match("-- ")) { sc.SetState(SCE_SQL_COMMENTLINE); } else if (sc.ch == '#' && options.sqlNumbersignComment) { sc.SetState(SCE_SQL_COMMENTLINEDOC); } else if (sc.ch == '\'') { sc.SetState(SCE_SQL_CHARACTER); } else if (sc.ch == '\"') { sc.SetState(SCE_SQL_STRING); } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_SQL_OPERATOR); } } } sc.Complete(); } void SCI_METHOD LexerSQL::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { if (!options.fold) return; LexAccessor styler(pAccess); unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) { // Backtrack to previous line in case need to fix its fold status for folding block of single-line comments (i.e. '--'). lineCurrent -= 1; startPos = styler.LineStart(lineCurrent); if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16; } int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; bool endFound = false; bool isUnfoldingIgnored = false; // this statementFound flag avoids to fold when the statement is on only one line by ignoring ELSE or ELSIF // eg. "IF condition1 THEN ... ELSIF condition2 THEN ... ELSE ... END IF;" bool statementFound = false; unsigned short int sqlStatesCurrentLine = 0; if (!options.foldOnlyBegin) { sqlStatesCurrentLine = sqlStates.ForLine(lineCurrent); } for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (atEOL || (!IsCommentStyle(style) && ch == ';')) { if (endFound) { //Maybe this is the end of "EXCEPTION" BLOCK (eg. "BEGIN ... EXCEPTION ... END;") sqlStatesCurrentLine = sqlStates.IntoExceptionBlock(sqlStatesCurrentLine, false); } // set endFound and isUnfoldingIgnored to false if EOL is reached or ';' is found endFound = false; isUnfoldingIgnored = false; } if ((!IsCommentStyle(style) && ch == ';')) { if (sqlStates.IsIntoMergeStatement(sqlStatesCurrentLine)) { // This is the end of "MERGE" statement. if (!sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) levelNext--; sqlStatesCurrentLine = sqlStates.IntoMergeStatement(sqlStatesCurrentLine, false); levelNext--; } if (sqlStates.IsIntoSelectStatement(sqlStatesCurrentLine)) sqlStatesCurrentLine = sqlStates.IntoSelectStatement(sqlStatesCurrentLine, false); } if (options.foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelNext--; } } if (options.foldComment && (style == SCE_SQL_COMMENTLINE)) { // MySQL needs -- comments to be followed by space or control char if ((ch == '-') && (chNext == '-')) { char chNext2 = styler.SafeGetCharAt(i + 2); char chNext3 = styler.SafeGetCharAt(i + 3); if (chNext2 == '{' || chNext3 == '{') { levelNext++; } else if (chNext2 == '}' || chNext3 == '}') { levelNext--; } } } // Fold block of single-line comments (i.e. '--'). if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler)) { if (!IsCommentLine(lineCurrent - 1, styler) && IsCommentLine(lineCurrent + 1, styler)) levelNext++; else if (IsCommentLine(lineCurrent - 1, styler) && !IsCommentLine(lineCurrent + 1, styler)) levelNext--; } if (style == SCE_SQL_OPERATOR) { if (ch == '(') { if (levelCurrent > levelNext) levelCurrent--; levelNext++; } else if (ch == ')') { levelNext--; } else if ((!options.foldOnlyBegin) && ch == ';') { sqlStatesCurrentLine = sqlStates.IgnoreWhen(sqlStatesCurrentLine, false); } } // If new keyword (cannot trigger on elseif or nullif, does less tests) if (style == SCE_SQL_WORD && stylePrev != SCE_SQL_WORD) { const int MAX_KW_LEN = 9; // Maximum length of folding keywords char s[MAX_KW_LEN + 2]; unsigned int j = 0; for (; j < MAX_KW_LEN + 1; j++) { if (!iswordchar(styler[i + j])) { break; } s[j] = static_cast(tolower(styler[i + j])); } if (j == MAX_KW_LEN + 1) { // Keyword too long, don't test it s[0] = '\0'; } else { s[j] = '\0'; } if (!options.foldOnlyBegin && strcmp(s, "select") == 0) { sqlStatesCurrentLine = sqlStates.IntoSelectStatement(sqlStatesCurrentLine, true); } else if (strcmp(s, "if") == 0) { if (endFound) { endFound = false; if (options.foldOnlyBegin && !isUnfoldingIgnored) { // this end isn't for begin block, but for if block ("end if;") // so ignore previous "end" by increment levelNext. levelNext++; } } else { if (!options.foldOnlyBegin) sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); if (levelCurrent > levelNext) { // doesn't include this line into the folding block // because doesn't hide IF (eg "END; IF") levelCurrent = levelNext; } } } else if (!options.foldOnlyBegin && strcmp(s, "then") == 0 && sqlStates.IsIntoCondition(sqlStatesCurrentLine)) { sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, false); if (!options.foldOnlyBegin) { if (levelCurrent > levelNext) { levelCurrent = levelNext; } if (!statementFound) levelNext++; statementFound = true; } else if (levelCurrent > levelNext) { // doesn't include this line into the folding block // because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE") levelCurrent = levelNext; } } else if (strcmp(s, "loop") == 0 || strcmp(s, "case") == 0) { if (endFound) { endFound = false; if (options.foldOnlyBegin && !isUnfoldingIgnored) { // this end isn't for begin block, but for loop block ("end loop;") or case block ("end case;") // so ignore previous "end" by increment levelNext. levelNext++; } if ((!options.foldOnlyBegin) && strcmp(s, "case") == 0) { sqlStatesCurrentLine = sqlStates.EndCaseBlock(sqlStatesCurrentLine); if (!sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) levelNext--; //again for the "end case;" and block when } } else if (!options.foldOnlyBegin) { if (strcmp(s, "case") == 0) sqlStatesCurrentLine = sqlStates.BeginCaseBlock(sqlStatesCurrentLine); if (levelCurrent > levelNext) levelCurrent = levelNext; if (!statementFound) levelNext++; sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, true); statementFound = true; } else if (levelCurrent > levelNext) { // doesn't include this line into the folding block // because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE") levelCurrent = levelNext; } } else if ((!options.foldOnlyBegin) && ( // folding for ELSE and ELSIF block only if foldAtElse is set // and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound) options.foldAtElse && !statementFound) && strcmp(s, "elsif") == 0) { sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); levelCurrent--; levelNext--; } else if ((!options.foldOnlyBegin) && ( // folding for ELSE and ELSIF block only if foldAtElse is set // and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound) options.foldAtElse && !statementFound) && strcmp(s, "else") == 0) { // prevent also ELSE is on the same line (eg. "ELSE ... END IF;") statementFound = true; if (sqlStates.IsIntoCaseBlock(sqlStatesCurrentLine) && sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) { sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, false); levelNext++; } else { // we are in same case "} ELSE {" in C language levelCurrent--; } } else if (strcmp(s, "begin") == 0) { levelNext++; sqlStatesCurrentLine = sqlStates.IntoDeclareBlock(sqlStatesCurrentLine, false); } else if ((strcmp(s, "end") == 0) || // SQL Anywhere permits IF ... ELSE ... ENDIF // will only be active if "endif" appears in the // keyword list. (strcmp(s, "endif") == 0)) { endFound = true; levelNext--; if (sqlStates.IsIntoSelectStatement(sqlStatesCurrentLine) && !sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) levelNext--; if (levelNext < SC_FOLDLEVELBASE) { levelNext = SC_FOLDLEVELBASE; isUnfoldingIgnored = true; } } else if ((!options.foldOnlyBegin) && strcmp(s, "when") == 0 && !sqlStates.IsIgnoreWhen(sqlStatesCurrentLine) && !sqlStates.IsIntoExceptionBlock(sqlStatesCurrentLine) && ( sqlStates.IsIntoCaseBlock(sqlStatesCurrentLine) || sqlStates.IsIntoMergeStatement(sqlStatesCurrentLine) ) ) { sqlStatesCurrentLine = sqlStates.IntoCondition(sqlStatesCurrentLine, true); // Don't foldind when CASE and WHEN are on the same line (with flag statementFound) (eg. "CASE selector WHEN expression1 THEN sequence_of_statements1;\n") // and same way for MERGE statement. if (!statementFound) { if (!sqlStates.IsCaseMergeWithoutWhenFound(sqlStatesCurrentLine)) { levelCurrent--; levelNext--; } sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, false); } } else if ((!options.foldOnlyBegin) && strcmp(s, "exit") == 0) { sqlStatesCurrentLine = sqlStates.IgnoreWhen(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && !sqlStates.IsIntoDeclareBlock(sqlStatesCurrentLine) && strcmp(s, "exception") == 0) { sqlStatesCurrentLine = sqlStates.IntoExceptionBlock(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && (strcmp(s, "declare") == 0 || strcmp(s, "function") == 0 || strcmp(s, "procedure") == 0 || strcmp(s, "package") == 0)) { sqlStatesCurrentLine = sqlStates.IntoDeclareBlock(sqlStatesCurrentLine, true); } else if ((!options.foldOnlyBegin) && strcmp(s, "merge") == 0) { sqlStatesCurrentLine = sqlStates.IntoMergeStatement(sqlStatesCurrentLine, true); sqlStatesCurrentLine = sqlStates.CaseMergeWithoutWhenFound(sqlStatesCurrentLine, true); levelNext++; statementFound = true; } } if (atEOL) { int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (visibleChars == 0 && options.foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; visibleChars = 0; statementFound = false; if (!options.foldOnlyBegin) sqlStates.Set(lineCurrent, sqlStatesCurrentLine); } if (!isspacechar(ch)) { visibleChars++; } } } LexerModule lmSQL(SCLEX_SQL, LexerSQL::LexerFactorySQL, "sql", sqlWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMySQL.cxx0000644000175000017500000004054311615412040021273 00000000000000/** * Scintilla source code edit control * @file LexMySQL.cxx * Lexer for MySQL * * Improved by Mike Lischke * Adopted from LexSQL.cxx by Anders Karlsson * Original work by Neil Hodgson * Copyright 1998-2005 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAWordStart(int ch) { return (ch < 0x80) && (isalpha(ch) || ch == '_'); } static inline bool IsADoxygenChar(int ch) { return (islower(ch) || ch == '$' || ch == '@' || ch == '\\' || ch == '&' || ch == '<' || ch == '>' || ch == '#' || ch == '{' || ch == '}' || ch == '[' || ch == ']'); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || toupper(ch) == 'E' || ch == '.' || ch == '-' || ch == '+'); } //-------------------------------------------------------------------------------------------------- /** * Check if the current content context represent a keyword and set the context state if so. */ static void CheckForKeyword(StyleContext& sc, WordList* keywordlists[]) { int length = sc.LengthCurrent() + 1; // +1 for the next char char* s = new char[length]; sc.GetCurrentLowered(s, length); if (keywordlists[0]->InList(s)) sc.ChangeState(SCE_MYSQL_MAJORKEYWORD); else if (keywordlists[1]->InList(s)) sc.ChangeState(SCE_MYSQL_KEYWORD); else if (keywordlists[2]->InList(s)) sc.ChangeState(SCE_MYSQL_DATABASEOBJECT); else if (keywordlists[3]->InList(s)) sc.ChangeState(SCE_MYSQL_FUNCTION); else if (keywordlists[5]->InList(s)) sc.ChangeState(SCE_MYSQL_PROCEDUREKEYWORD); else if (keywordlists[6]->InList(s)) sc.ChangeState(SCE_MYSQL_USER1); else if (keywordlists[7]->InList(s)) sc.ChangeState(SCE_MYSQL_USER2); else if (keywordlists[8]->InList(s)) sc.ChangeState(SCE_MYSQL_USER3); delete [] s; } //-------------------------------------------------------------------------------------------------- static void ColouriseMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Determine if the current state should terminate. switch (sc.state) { case SCE_MYSQL_OPERATOR: sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_NUMBER: // We stop the number definition on non-numerical non-dot non-eE non-sign char. if (!IsANumberChar(sc.ch)) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_IDENTIFIER: // Switch from identifier to keyword state and open a new state for the new char. if (!IsAWordChar(sc.ch)) { CheckForKeyword(sc, keywordlists); // Additional check for function keywords needed. // A function name must be followed by an opening parenthesis. if (sc.state == SCE_MYSQL_FUNCTION && sc.ch != '(') sc.ChangeState(SCE_MYSQL_DEFAULT); sc.SetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_VARIABLE: if (!IsAWordChar(sc.ch)) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_SYSTEMVARIABLE: if (!IsAWordChar(sc.ch)) { int length = sc.LengthCurrent() + 1; char* s = new char[length]; sc.GetCurrentLowered(s, length); // Check for known system variables here. if (keywordlists[4]->InList(&s[2])) sc.ChangeState(SCE_MYSQL_KNOWNSYSTEMVARIABLE); delete [] s; sc.SetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_QUOTEDIDENTIFIER: if (sc.ch == '`') { if (sc.chNext == '`') sc.Forward(); // Ignore it else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_COMMENT: case SCE_MYSQL_HIDDENCOMMAND: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_COMMENTLINE: if (sc.atLineStart) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_SQSTRING: if (sc.ch == '\\') sc.Forward(); // Escape sequence else if (sc.ch == '\'') { // End of single quoted string reached? if (sc.chNext == '\'') sc.Forward(); else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_DQSTRING: if (sc.ch == '\\') sc.Forward(); // Escape sequence else if (sc.ch == '\"') { // End of single quoted string reached? if (sc.chNext == '\"') sc.Forward(); else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; } // Determine if a new state should be entered. if (sc.state == SCE_MYSQL_DEFAULT) { switch (sc.ch) { case '@': if (sc.chNext == '@') { sc.SetState(SCE_MYSQL_SYSTEMVARIABLE); sc.Forward(2); // Skip past @@. } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_MYSQL_VARIABLE); sc.Forward(); // Skip past @. } else sc.SetState(SCE_MYSQL_OPERATOR); break; case '`': sc.SetState(SCE_MYSQL_QUOTEDIDENTIFIER); break; case '#': sc.SetState(SCE_MYSQL_COMMENTLINE); break; case '\'': sc.SetState(SCE_MYSQL_SQSTRING); break; case '\"': sc.SetState(SCE_MYSQL_DQSTRING); break; default: if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) sc.SetState(SCE_MYSQL_NUMBER); else if (IsAWordStart(sc.ch)) sc.SetState(SCE_MYSQL_IDENTIFIER); else if (sc.Match('/', '*')) { sc.SetState(SCE_MYSQL_COMMENT); // Skip comment introducer and check for hidden command. sc.Forward(2); if (sc.ch == '!') { sc.ChangeState(SCE_MYSQL_HIDDENCOMMAND); sc.Forward(); } } else if (sc.Match("--")) { // Special MySQL single line comment. sc.SetState(SCE_MYSQL_COMMENTLINE); sc.Forward(2); // Check the third character too. It must be a space or EOL. if (sc.ch != ' ' && sc.ch != '\n' && sc.ch != '\r') sc.ChangeState(SCE_MYSQL_OPERATOR); } else if (isoperator(static_cast(sc.ch))) sc.SetState(SCE_MYSQL_OPERATOR); } } } // Do a final check for keywords if we currently have an identifier, to highlight them // also at the end of a line. if (sc.state == SCE_MYSQL_IDENTIFIER) { CheckForKeyword(sc, keywordlists); // Additional check for function keywords needed. // A function name must be followed by an opening parenthesis. if (sc.state == SCE_MYSQL_FUNCTION && sc.ch != '(') sc.ChangeState(SCE_MYSQL_DEFAULT); } sc.Complete(); } //-------------------------------------------------------------------------------------------------- /** * Helper function to determine if we have a foldable comment currently. */ static bool IsStreamCommentStyle(int style) { return style == SCE_MYSQL_COMMENT; } //-------------------------------------------------------------------------------------------------- /** * Code copied from StyleContext and modified to work here. Should go into Accessor as a * companion to Match()... */ bool MatchIgnoreCase(Accessor &styler, int currentPos, const char *s) { for (int n = 0; *s; n++) { if (*s != tolower(styler.SafeGetCharAt(currentPos + n))) return false; s++; } return true; } //-------------------------------------------------------------------------------------------------- // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment. static void FoldMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldOnlyBegin = styler.GetPropertyInt("fold.sql.only.begin", 0) != 0; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16; int levelNext = levelCurrent; int styleNext = styler.StyleAt(startPos); int style = initStyle; bool endPending = false; bool whenPending = false; bool elseIfPending = false; char nextChar = styler.SafeGetCharAt(startPos); for (unsigned int i = startPos; length > 0; i++, length--) { int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); char currentChar = nextChar; nextChar = styler.SafeGetCharAt(i + 1); bool atEOL = (currentChar == '\r' && nextChar != '\n') || (currentChar == '\n'); switch (style) { case SCE_MYSQL_COMMENT: if (foldComment) { // Multiline comment style /* .. */. if (IsStreamCommentStyle(style)) { // Increase level if we just start a foldable comment. if (!IsStreamCommentStyle(stylePrev)) levelNext++; else // If we are in the middle of a foldable comment check if it ends now. // Don't end at the line end, though. if (!IsStreamCommentStyle(styleNext) && !atEOL) levelNext--; } } break; case SCE_MYSQL_COMMENTLINE: if (foldComment) { // Not really a standard, but we add support for single line comments // with special curly braces syntax as foldable comments too. // MySQL needs -- comments to be followed by space or control char if (styler.Match(i, "--")) { char chNext2 = styler.SafeGetCharAt(i + 2); char chNext3 = styler.SafeGetCharAt(i + 3); if (chNext2 == '{' || chNext3 == '{') levelNext++; else if (chNext2 == '}' || chNext3 == '}') levelNext--; } } break; case SCE_MYSQL_HIDDENCOMMAND: if (endPending) { // A conditional command is not a white space so it should end the current block // before opening a new one. endPending = false; levelNext--; if (levelNext < SC_FOLDLEVELBASE) levelNext = SC_FOLDLEVELBASE; } if (style != stylePrev) levelNext++; else if (style != styleNext) { levelNext--; if (levelNext < SC_FOLDLEVELBASE) levelNext = SC_FOLDLEVELBASE; } break; case SCE_MYSQL_OPERATOR: if (endPending) { endPending = false; levelNext--; if (levelNext < SC_FOLDLEVELBASE) levelNext = SC_FOLDLEVELBASE; } if (currentChar == '(') levelNext++; else if (currentChar == ')') { levelNext--; if (levelNext < SC_FOLDLEVELBASE) levelNext = SC_FOLDLEVELBASE; } break; case SCE_MYSQL_MAJORKEYWORD: case SCE_MYSQL_KEYWORD: case SCE_MYSQL_FUNCTION: case SCE_MYSQL_PROCEDUREKEYWORD: // Reserved and other keywords. if (style != stylePrev) { // END decreases the folding level, regardless which keyword follows. bool endFound = MatchIgnoreCase(styler, i, "end"); if (endPending) { levelNext--; if (levelNext < SC_FOLDLEVELBASE) levelNext = SC_FOLDLEVELBASE; } else if (!endFound) { if (MatchIgnoreCase(styler, i, "begin")) levelNext++; else { if (!foldOnlyBegin) { bool whileFound = MatchIgnoreCase(styler, i, "while"); bool loopFound = MatchIgnoreCase(styler, i, "loop"); bool repeatFound = MatchIgnoreCase(styler, i, "repeat"); bool caseFound = MatchIgnoreCase(styler, i, "case"); if (whileFound || loopFound || repeatFound || caseFound) levelNext++; else { // IF alone does not increase the fold level as it is also used in non-block'ed // code like DROP PROCEDURE blah IF EXISTS. // Instead THEN opens the new level (if not part of an ELSEIF or WHEN (case) branch). if (MatchIgnoreCase(styler, i, "then")) { if (!elseIfPending && !whenPending) levelNext++; else { elseIfPending = false; whenPending = false; } } else { // Neither of if/then/while/loop/repeat/case, so check for // sub parts of IF and CASE. if (MatchIgnoreCase(styler, i, "elseif")) elseIfPending = true; if (MatchIgnoreCase(styler, i, "when")) whenPending = true; } } } } } // Keep the current end state for the next round. endPending = endFound; } break; default: if (!isspace(currentChar) && endPending) { // END followed by a non-whitespace character (not covered by other cases like identifiers) // also should end a folding block. Typical case: END followed by self defined delimiter. levelNext--; if (levelNext < SC_FOLDLEVELBASE) levelNext = SC_FOLDLEVELBASE; } break; } if (atEOL) { // Apply the new folding level to this line. // Leave pending states as they are otherwise a line break will de-sync // code folding and valid syntax. int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) styler.SetLevel(lineCurrent, lev); lineCurrent++; levelCurrent = levelNext; visibleChars = 0; } if (!isspacechar(currentChar)) visibleChars++; } } //-------------------------------------------------------------------------------------------------- static const char * const mysqlWordListDesc[] = { "Major Keywords", "Keywords", "Database Objects", "Functions", "System Variables", "Procedure keywords", "User Keywords 1", "User Keywords 2", "User Keywords 3", 0 }; LexerModule lmMySQL(SCLEX_MYSQL, ColouriseMySQLDoc, "mysql", FoldMySQLDoc, mysqlWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexRuby.cxx0000644000175000017500000017456111726020232021260 00000000000000// Scintilla source code edit control /** @file LexRuby.cxx ** Lexer for Ruby. **/ // Copyright 2001- by Clemens Wyss // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif //XXX Identical to Perl, put in common area static inline bool isEOLChar(char ch) { return (ch == '\r') || (ch == '\n'); } #define isSafeASCII(ch) ((unsigned int)(ch) <= 127) // This one's redundant, but makes for more readable code #define isHighBitChar(ch) ((unsigned int)(ch) > 127) static inline bool isSafeAlpha(char ch) { return (isSafeASCII(ch) && isalpha(ch)) || ch == '_'; } static inline bool isSafeAlnum(char ch) { return (isSafeASCII(ch) && isalnum(ch)) || ch == '_'; } static inline bool isSafeAlnumOrHigh(char ch) { return isHighBitChar(ch) || isalnum(ch) || ch == '_'; } static inline bool isSafeDigit(char ch) { return isSafeASCII(ch) && isdigit(ch); } static inline bool isSafeWordcharOrHigh(char ch) { // Error: scintilla's KeyWords.h includes '.' as a word-char // we want to separate things that can take methods from the // methods. return isHighBitChar(ch) || isalnum(ch) || ch == '_'; } static bool inline iswhitespace(char ch) { return ch == ' ' || ch == '\t'; } #define MAX_KEYWORD_LENGTH 200 #define STYLE_MASK 63 #define actual_style(style) (style & STYLE_MASK) static bool followsDot(unsigned int pos, Accessor &styler) { styler.Flush(); for (; pos >= 1; --pos) { int style = actual_style(styler.StyleAt(pos)); char ch; switch (style) { case SCE_RB_DEFAULT: ch = styler[pos]; if (ch == ' ' || ch == '\t') { //continue } else { return false; } break; case SCE_RB_OPERATOR: return styler[pos] == '.'; default: return false; } } return false; } // Forward declarations static bool keywordIsAmbiguous(const char *prevWord); static bool keywordDoStartsLoop(int pos, Accessor &styler); static bool keywordIsModifier(const char *word, int pos, Accessor &styler); static int ClassifyWordRb(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord) { char s[MAX_KEYWORD_LENGTH]; unsigned int i, j; unsigned int lim = end - start + 1; // num chars to copy if (lim >= MAX_KEYWORD_LENGTH) { lim = MAX_KEYWORD_LENGTH - 1; } for (i = start, j = 0; j < lim; i++, j++) { s[j] = styler[i]; } s[j] = '\0'; int chAttr; if (0 == strcmp(prevWord, "class")) chAttr = SCE_RB_CLASSNAME; else if (0 == strcmp(prevWord, "module")) chAttr = SCE_RB_MODULE_NAME; else if (0 == strcmp(prevWord, "def")) chAttr = SCE_RB_DEFNAME; else if (keywords.InList(s) && !followsDot(start - 1, styler)) { if (keywordIsAmbiguous(s) && keywordIsModifier(s, start, styler)) { // Demoted keywords are colored as keywords, // but do not affect changes in indentation. // // Consider the word 'if': // 1. <> : normal // 2. <> : demoted // 3. <> : normal: start a new indent level // 4. <> : color as identifer, since it follows '.' chAttr = SCE_RB_WORD_DEMOTED; } else { chAttr = SCE_RB_WORD; } } else chAttr = SCE_RB_IDENTIFIER; styler.ColourTo(end, chAttr); if (chAttr == SCE_RB_WORD) { strcpy(prevWord, s); } else { prevWord[0] = 0; } return chAttr; } //XXX Identical to Perl, put in common area static bool isMatch(Accessor &styler, int lengthDoc, int pos, const char *val) { if ((pos + static_cast(strlen(val))) >= lengthDoc) { return false; } while (*val) { if (*val != styler[pos++]) { return false; } val++; } return true; } // Do Ruby better -- find the end of the line, work back, // and then check for leading white space // Precondition: the here-doc target can be indented static bool lookingAtHereDocDelim(Accessor &styler, int pos, int lengthDoc, const char *HereDocDelim) { if (!isMatch(styler, lengthDoc, pos, HereDocDelim)) { return false; } while (--pos > 0) { char ch = styler[pos]; if (isEOLChar(ch)) { return true; } else if (ch != ' ' && ch != '\t') { return false; } } return false; } //XXX Identical to Perl, put in common area static char opposite(char ch) { if (ch == '(') return ')'; if (ch == '[') return ']'; if (ch == '{') return '}'; if (ch == '<') return '>'; return ch; } // Null transitions when we see we've reached the end // and need to relex the curr char. static void redo_char(int &i, char &ch, char &chNext, char &chNext2, int &state) { i--; chNext2 = chNext; chNext = ch; state = SCE_RB_DEFAULT; } static void advance_char(int &i, char &ch, char &chNext, char &chNext2) { i++; ch = chNext; chNext = chNext2; } // precondition: startPos points to one after the EOL char static bool currLineContainsHereDelims(int& startPos, Accessor &styler) { if (startPos <= 1) return false; int pos; for (pos = startPos - 1; pos > 0; pos--) { char ch = styler.SafeGetCharAt(pos); if (isEOLChar(ch)) { // Leave the pointers where they are -- there are no // here doc delims on the current line, even if // the EOL isn't default style return false; } else { styler.Flush(); if (actual_style(styler.StyleAt(pos)) == SCE_RB_HERE_DELIM) { break; } } } if (pos == 0) { return false; } // Update the pointers so we don't have to re-analyze the string startPos = pos; return true; } // This class is used by the enter and exit methods, so it needs // to be hoisted out of the function. class QuoteCls { public: int Count; char Up; char Down; QuoteCls() { this->New(); } void New() { Count = 0; Up = '\0'; Down = '\0'; } void Open(char u) { Count++; Up = u; Down = opposite(Up); } QuoteCls(const QuoteCls& q) { // copy constructor -- use this for copying in Count = q.Count; Up = q.Up; Down = q.Down; } QuoteCls& operator=(const QuoteCls& q) { // assignment constructor if (this != &q) { Count = q.Count; Up = q.Up; Down = q.Down; } return *this; } }; static void enterInnerExpression(int *p_inner_string_types, int *p_inner_expn_brace_counts, QuoteCls *p_inner_quotes, int& inner_string_count, int& state, int& brace_counts, QuoteCls curr_quote ) { p_inner_string_types[inner_string_count] = state; state = SCE_RB_DEFAULT; p_inner_expn_brace_counts[inner_string_count] = brace_counts; brace_counts = 0; p_inner_quotes[inner_string_count] = curr_quote; ++inner_string_count; } static void exitInnerExpression(int *p_inner_string_types, int *p_inner_expn_brace_counts, QuoteCls *p_inner_quotes, int& inner_string_count, int& state, int& brace_counts, QuoteCls& curr_quote ) { --inner_string_count; state = p_inner_string_types[inner_string_count]; brace_counts = p_inner_expn_brace_counts[inner_string_count]; curr_quote = p_inner_quotes[inner_string_count]; } static bool isEmptyLine(int pos, Accessor &styler) { int spaceFlags = 0; int lineCurrent = styler.GetLine(pos); int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); return (indentCurrent & SC_FOLDLEVELWHITEFLAG) != 0; } static bool RE_CanFollowKeyword(const char *keyword) { if (!strcmp(keyword, "and") || !strcmp(keyword, "begin") || !strcmp(keyword, "break") || !strcmp(keyword, "case") || !strcmp(keyword, "do") || !strcmp(keyword, "else") || !strcmp(keyword, "elsif") || !strcmp(keyword, "if") || !strcmp(keyword, "next") || !strcmp(keyword, "return") || !strcmp(keyword, "when") || !strcmp(keyword, "unless") || !strcmp(keyword, "until") || !strcmp(keyword, "not") || !strcmp(keyword, "or")) { return true; } return false; } // Look at chars up to but not including endPos // Don't look at styles in case we're looking forward static int skipWhitespace(int startPos, int endPos, Accessor &styler) { for (int i = startPos; i < endPos; i++) { if (!iswhitespace(styler[i])) { return i; } } return endPos; } // This routine looks for false positives like // undef foo, << // There aren't too many. // // iPrev points to the start of << static bool sureThisIsHeredoc(int iPrev, Accessor &styler, char *prevWord) { // Not so fast, since Ruby's so dynamic. Check the context // to make sure we're OK. int prevStyle; int lineStart = styler.GetLine(iPrev); int lineStartPosn = styler.LineStart(lineStart); styler.Flush(); // Find the first word after some whitespace int firstWordPosn = skipWhitespace(lineStartPosn, iPrev, styler); if (firstWordPosn >= iPrev) { // Have something like {^ <<} //XXX Look at the first previous non-comment non-white line // to establish the context. Not too likely though. return true; } else { switch (prevStyle = styler.StyleAt(firstWordPosn)) { case SCE_RB_WORD: case SCE_RB_WORD_DEMOTED: case SCE_RB_IDENTIFIER: break; default: return true; } } int firstWordEndPosn = firstWordPosn; char *dst = prevWord; for (;;) { if (firstWordEndPosn >= iPrev || styler.StyleAt(firstWordEndPosn) != prevStyle) { *dst = 0; break; } *dst++ = styler[firstWordEndPosn]; firstWordEndPosn += 1; } //XXX Write a style-aware thing to regex scintilla buffer objects if (!strcmp(prevWord, "undef") || !strcmp(prevWord, "def") || !strcmp(prevWord, "alias")) { // These keywords are what we were looking for return false; } return true; } // Routine that saves us from allocating a buffer for the here-doc target // targetEndPos points one past the end of the current target static bool haveTargetMatch(int currPos, int lengthDoc, int targetStartPos, int targetEndPos, Accessor &styler) { if (lengthDoc - currPos < targetEndPos - targetStartPos) { return false; } int i, j; for (i = targetStartPos, j = currPos; i < targetEndPos && j < lengthDoc; i++, j++) { if (styler[i] != styler[j]) { return false; } } return true; } // We need a check because the form // [identifier] <<[target] // is ambiguous. The Ruby lexer/parser resolves it by // looking to see if [identifier] names a variable or a // function. If it's the first, it's the start of a here-doc. // If it's a var, it's an operator. This lexer doesn't // maintain a symbol table, so it looks ahead to see what's // going on, in cases where we have // ^[white-space]*[identifier([.|::]identifier)*][white-space]*<<[target] // // If there's no occurrence of [target] on a line, assume we don't. // return true == yes, we have no heredocs static bool sureThisIsNotHeredoc(int lt2StartPos, Accessor &styler) { int prevStyle; // Use full document, not just part we're styling int lengthDoc = styler.Length(); int lineStart = styler.GetLine(lt2StartPos); int lineStartPosn = styler.LineStart(lineStart); styler.Flush(); const bool definitely_not_a_here_doc = true; const bool looks_like_a_here_doc = false; // Find the first word after some whitespace int firstWordPosn = skipWhitespace(lineStartPosn, lt2StartPos, styler); if (firstWordPosn >= lt2StartPos) { return definitely_not_a_here_doc; } prevStyle = styler.StyleAt(firstWordPosn); // If we have '<<' following a keyword, it's not a heredoc if (prevStyle != SCE_RB_IDENTIFIER) { return definitely_not_a_here_doc; } int newStyle = prevStyle; // Some compilers incorrectly warn about uninit newStyle for (firstWordPosn += 1; firstWordPosn <= lt2StartPos; firstWordPosn += 1) { // Inner loop looks at the name for (; firstWordPosn <= lt2StartPos; firstWordPosn += 1) { newStyle = styler.StyleAt(firstWordPosn); if (newStyle != prevStyle) { break; } } // Do we have '::' or '.'? if (firstWordPosn < lt2StartPos && newStyle == SCE_RB_OPERATOR) { char ch = styler[firstWordPosn]; if (ch == '.') { // yes } else if (ch == ':') { if (styler.StyleAt(++firstWordPosn) != SCE_RB_OPERATOR) { return definitely_not_a_here_doc; } else if (styler[firstWordPosn] != ':') { return definitely_not_a_here_doc; } } else { break; } } else { break; } } // Skip next batch of white-space firstWordPosn = skipWhitespace(firstWordPosn, lt2StartPos, styler); if (firstWordPosn != lt2StartPos) { // Have [[^ws[identifier]ws[*something_else*]ws<< return definitely_not_a_here_doc; } // OK, now 'j' will point to the current spot moving ahead int j = firstWordPosn + 1; if (styler.StyleAt(j) != SCE_RB_OPERATOR || styler[j] != '<') { // This shouldn't happen return definitely_not_a_here_doc; } int nextLineStartPosn = styler.LineStart(lineStart + 1); if (nextLineStartPosn >= lengthDoc) { return definitely_not_a_here_doc; } j = skipWhitespace(j + 1, nextLineStartPosn, styler); if (j >= lengthDoc) { return definitely_not_a_here_doc; } bool allow_indent; int target_start, target_end; // From this point on no more styling, since we're looking ahead if (styler[j] == '-') { allow_indent = true; j++; } else { allow_indent = false; } // Allow for quoted targets. char target_quote = 0; switch (styler[j]) { case '\'': case '"': case '`': target_quote = styler[j]; j += 1; } if (isSafeAlnum(styler[j])) { // Init target_end because some compilers think it won't // be initialized by the time it's used target_start = target_end = j; j++; } else { return definitely_not_a_here_doc; } for (; j < lengthDoc; j++) { if (!isSafeAlnum(styler[j])) { if (target_quote && styler[j] != target_quote) { // unquoted end return definitely_not_a_here_doc; } // And for now make sure that it's a newline // don't handle arbitrary expressions yet target_end = j; if (target_quote) { // Now we can move to the character after the string delimiter. j += 1; } j = skipWhitespace(j, lengthDoc, styler); if (j >= lengthDoc) { return definitely_not_a_here_doc; } else { char ch = styler[j]; if (ch == '#' || isEOLChar(ch)) { // This is OK, so break and continue; break; } else { return definitely_not_a_here_doc; } } } } // Just look at the start of each line int last_line = styler.GetLine(lengthDoc - 1); // But don't go too far if (last_line > lineStart + 50) { last_line = lineStart + 50; } for (int line_num = lineStart + 1; line_num <= last_line; line_num++) { if (allow_indent) { j = skipWhitespace(styler.LineStart(line_num), lengthDoc, styler); } else { j = styler.LineStart(line_num); } // target_end is one past the end if (haveTargetMatch(j, lengthDoc, target_start, target_end, styler)) { // We got it return looks_like_a_here_doc; } } return definitely_not_a_here_doc; } //todo: if we aren't looking at a stdio character, // move to the start of the first line that is not in a // multi-line construct static void synchronizeDocStart(unsigned int& startPos, int &length, int &initStyle, Accessor &styler, bool skipWhiteSpace=false) { styler.Flush(); int style = actual_style(styler.StyleAt(startPos)); switch (style) { case SCE_RB_STDIN: case SCE_RB_STDOUT: case SCE_RB_STDERR: // Don't do anything else with these. return; } int pos = startPos; // Quick way to characterize each line int lineStart; for (lineStart = styler.GetLine(pos); lineStart > 0; lineStart--) { // Now look at the style before the previous line's EOL pos = styler.LineStart(lineStart) - 1; if (pos <= 10) { lineStart = 0; break; } char ch = styler.SafeGetCharAt(pos); char chPrev = styler.SafeGetCharAt(pos - 1); if (ch == '\n' && chPrev == '\r') { pos--; } if (styler.SafeGetCharAt(pos - 1) == '\\') { // Continuation line -- keep going } else if (actual_style(styler.StyleAt(pos)) != SCE_RB_DEFAULT) { // Part of multi-line construct -- keep going } else if (currLineContainsHereDelims(pos, styler)) { // Keep going, with pos and length now pointing // at the end of the here-doc delimiter } else if (skipWhiteSpace && isEmptyLine(pos, styler)) { // Keep going } else { break; } } pos = styler.LineStart(lineStart); length += (startPos - pos); startPos = pos; initStyle = SCE_RB_DEFAULT; } static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { // Lexer for Ruby often has to backtrack to start of current style to determine // which characters are being used as quotes, how deeply nested is the // start position and what the termination string is for here documents WordList &keywords = *keywordlists[0]; class HereDocCls { public: int State; // States // 0: '<<' encountered // 1: collect the delimiter // 1b: text between the end of the delimiter and the EOL // 2: here doc text (lines after the delimiter) char Quote; // the char after '<<' bool Quoted; // true if Quote in ('\'','"','`') int DelimiterLength; // strlen(Delimiter) char Delimiter[256]; // the Delimiter, limit of 256: from Perl bool CanBeIndented; HereDocCls() { State = 0; DelimiterLength = 0; Delimiter[0] = '\0'; CanBeIndented = false; } }; HereDocCls HereDoc; QuoteCls Quote; int numDots = 0; // For numbers -- // Don't start lexing in the middle of a num synchronizeDocStart(startPos, length, initStyle, styler, // ref args false); bool preferRE = true; int state = initStyle; int lengthDoc = startPos + length; char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero prevWord[0] = '\0'; if (length == 0) return; char chPrev = styler.SafeGetCharAt(startPos - 1); char chNext = styler.SafeGetCharAt(startPos); bool is_real_number = true; // Differentiate between constants and ?-sequences. // Ruby uses a different mask because bad indentation is marked by oring with 32 styler.StartAt(startPos, 127); styler.StartSegment(startPos); static int q_states[] = {SCE_RB_STRING_Q, SCE_RB_STRING_QQ, SCE_RB_STRING_QR, SCE_RB_STRING_QW, SCE_RB_STRING_QW, SCE_RB_STRING_QX}; static const char* q_chars = "qQrwWx"; // In most cases a value of 2 should be ample for the code in the // Ruby library, and the code the user is likely to enter. // For example, // fu_output_message "mkdir #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" // if options[:verbose] // from fileutils.rb nests to a level of 2 // If the user actually hits a 6th occurrence of '#{' in a double-quoted // string (including regex'es, %Q, %, %w, and other strings // that interpolate), it will stay as a string. The problem with this // is that quotes might flip, a 7th '#{' will look like a comment, // and code-folding might be wrong. // If anyone runs into this problem, I recommend raising this // value slightly higher to replacing the fixed array with a linked // list. Keep in mind this code will be called everytime the lexer // is invoked. #define INNER_STRINGS_MAX_COUNT 5 // These vars track our instances of "...#{,,,%Q<..#{,,,}...>,,,}..." int inner_string_types[INNER_STRINGS_MAX_COUNT]; // Track # braces when we push a new #{ thing int inner_expn_brace_counts[INNER_STRINGS_MAX_COUNT]; QuoteCls inner_quotes[INNER_STRINGS_MAX_COUNT]; int inner_string_count = 0; int brace_counts = 0; // Number of #{ ... } things within an expression int i; for (i = 0; i < INNER_STRINGS_MAX_COUNT; i++) { inner_string_types[i] = 0; inner_expn_brace_counts[i] = 0; } for (i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); char chNext2 = styler.SafeGetCharAt(i + 2); if (styler.IsLeadByte(ch)) { chNext = chNext2; chPrev = ' '; i += 1; continue; } // skip on DOS/Windows //No, don't, because some things will get tagged on, // so we won't recognize keywords, for example #if 0 if (ch == '\r' && chNext == '\n') { continue; } #endif if (HereDoc.State == 1 && isEOLChar(ch)) { // Begin of here-doc (the line after the here-doc delimiter): HereDoc.State = 2; styler.ColourTo(i-1, state); // Don't check for a missing quote, just jump into // the here-doc state state = SCE_RB_HERE_Q; } // Regular transitions if (state == SCE_RB_DEFAULT) { if (isSafeDigit(ch)) { styler.ColourTo(i - 1, state); state = SCE_RB_NUMBER; is_real_number = true; numDots = 0; } else if (isHighBitChar(ch) || iswordstart(ch)) { styler.ColourTo(i - 1, state); state = SCE_RB_WORD; } else if (ch == '#') { styler.ColourTo(i - 1, state); state = SCE_RB_COMMENTLINE; } else if (ch == '=') { // =begin indicates the start of a comment (doc) block if ((i == 0 || isEOLChar(chPrev)) && chNext == 'b' && styler.SafeGetCharAt(i + 2) == 'e' && styler.SafeGetCharAt(i + 3) == 'g' && styler.SafeGetCharAt(i + 4) == 'i' && styler.SafeGetCharAt(i + 5) == 'n' && !isSafeWordcharOrHigh(styler.SafeGetCharAt(i + 6))) { styler.ColourTo(i - 1, state); state = SCE_RB_POD; } else { styler.ColourTo(i - 1, state); styler.ColourTo(i, SCE_RB_OPERATOR); preferRE = true; } } else if (ch == '"') { styler.ColourTo(i - 1, state); state = SCE_RB_STRING; Quote.New(); Quote.Open(ch); } else if (ch == '\'') { styler.ColourTo(i - 1, state); state = SCE_RB_CHARACTER; Quote.New(); Quote.Open(ch); } else if (ch == '`') { styler.ColourTo(i - 1, state); state = SCE_RB_BACKTICKS; Quote.New(); Quote.Open(ch); } else if (ch == '@') { // Instance or class var styler.ColourTo(i - 1, state); if (chNext == '@') { state = SCE_RB_CLASS_VAR; advance_char(i, ch, chNext, chNext2); // pass by ref } else { state = SCE_RB_INSTANCE_VAR; } } else if (ch == '$') { // Check for a builtin global styler.ColourTo(i - 1, state); // Recognize it bit by bit state = SCE_RB_GLOBAL; } else if (ch == '/' && preferRE) { // Ambigous operator styler.ColourTo(i - 1, state); state = SCE_RB_REGEX; Quote.New(); Quote.Open(ch); } else if (ch == '<' && chNext == '<' && chNext2 != '=') { // Recognise the '<<' symbol - either a here document or a binary op styler.ColourTo(i - 1, state); i++; chNext = chNext2; styler.ColourTo(i, SCE_RB_OPERATOR); if (! (strchr("\"\'`_-", chNext2) || isSafeAlpha(chNext2))) { // It's definitely not a here-doc, // based on Ruby's lexer/parser in the // heredoc_identifier routine. // Nothing else to do. } else if (preferRE) { if (sureThisIsHeredoc(i - 1, styler, prevWord)) { state = SCE_RB_HERE_DELIM; HereDoc.State = 0; } // else leave it in default state } else { if (sureThisIsNotHeredoc(i - 1, styler)) { // leave state as default // We don't have all the heuristics Perl has for indications // of a here-doc, because '<<' is overloadable and used // for so many other classes. } else { state = SCE_RB_HERE_DELIM; HereDoc.State = 0; } } preferRE = (state != SCE_RB_HERE_DELIM); } else if (ch == ':') { styler.ColourTo(i - 1, state); if (chNext == ':') { // Mark "::" as an operator, not symbol start styler.ColourTo(i + 1, SCE_RB_OPERATOR); advance_char(i, ch, chNext, chNext2); // pass by ref state = SCE_RB_DEFAULT; preferRE = false; } else if (isSafeWordcharOrHigh(chNext)) { state = SCE_RB_SYMBOL; } else if (strchr("[*!~+-*/%=<>&^|", chNext)) { // Do the operator analysis in-line, looking ahead // Based on the table in pickaxe 2nd ed., page 339 bool doColoring = true; switch (chNext) { case '[': if (chNext2 == ']' ) { char ch_tmp = styler.SafeGetCharAt(i + 3); if (ch_tmp == '=') { i += 3; ch = ch_tmp; chNext = styler.SafeGetCharAt(i + 1); } else { i += 2; ch = chNext2; chNext = ch_tmp; } } else { doColoring = false; } break; case '*': if (chNext2 == '*') { i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); } else { advance_char(i, ch, chNext, chNext2); } break; case '!': if (chNext2 == '=' || chNext2 == '~') { i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); } else { advance_char(i, ch, chNext, chNext2); } break; case '<': if (chNext2 == '<') { i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); } else if (chNext2 == '=') { char ch_tmp = styler.SafeGetCharAt(i + 3); if (ch_tmp == '>') { // <=> operator i += 3; ch = ch_tmp; chNext = styler.SafeGetCharAt(i + 1); } else { i += 2; ch = chNext2; chNext = ch_tmp; } } else { advance_char(i, ch, chNext, chNext2); } break; default: // Simple one-character operators advance_char(i, ch, chNext, chNext2); break; } if (doColoring) { styler.ColourTo(i, SCE_RB_SYMBOL); state = SCE_RB_DEFAULT; } } else if (!preferRE) { // Don't color symbol strings (yet) // Just color the ":" and color rest as string styler.ColourTo(i, SCE_RB_SYMBOL); state = SCE_RB_DEFAULT; } else { styler.ColourTo(i, SCE_RB_OPERATOR); state = SCE_RB_DEFAULT; preferRE = true; } } else if (ch == '%') { styler.ColourTo(i - 1, state); bool have_string = false; if (strchr(q_chars, chNext) && !isSafeWordcharOrHigh(chNext2)) { Quote.New(); const char *hit = strchr(q_chars, chNext); if (hit != NULL) { state = q_states[hit - q_chars]; Quote.Open(chNext2); i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); have_string = true; } } else if (preferRE && !isSafeWordcharOrHigh(chNext)) { // Ruby doesn't allow high bit chars here, // but the editor host might Quote.New(); state = SCE_RB_STRING_QQ; Quote.Open(chNext); advance_char(i, ch, chNext, chNext2); // pass by ref have_string = true; } else if (!isSafeWordcharOrHigh(chNext) && !iswhitespace(chNext) && !isEOLChar(chNext)) { // Ruby doesn't allow high bit chars here, // but the editor host might Quote.New(); state = SCE_RB_STRING_QQ; Quote.Open(chNext); advance_char(i, ch, chNext, chNext2); // pass by ref have_string = true; } if (!have_string) { styler.ColourTo(i, SCE_RB_OPERATOR); // stay in default preferRE = true; } } else if (ch == '?') { styler.ColourTo(i - 1, state); if (iswhitespace(chNext) || chNext == '\n' || chNext == '\r') { styler.ColourTo(i, SCE_RB_OPERATOR); } else { // It's the start of a character code escape sequence // Color it as a number. state = SCE_RB_NUMBER; is_real_number = false; } } else if (isoperator(ch) || ch == '.') { styler.ColourTo(i - 1, state); styler.ColourTo(i, SCE_RB_OPERATOR); // If we're ending an expression or block, // assume it ends an object, and the ambivalent // constructs are binary operators // // So if we don't have one of these chars, // we aren't ending an object exp'n, and ops // like : << / are unary operators. if (ch == '{') { ++brace_counts; preferRE = true; } else if (ch == '}' && --brace_counts < 0 && inner_string_count > 0) { styler.ColourTo(i, SCE_RB_OPERATOR); exitInnerExpression(inner_string_types, inner_expn_brace_counts, inner_quotes, inner_string_count, state, brace_counts, Quote); } else { preferRE = (strchr(")}].", ch) == NULL); } // Stay in default state } else if (isEOLChar(ch)) { // Make sure it's a true line-end, with no backslash if ((ch == '\r' || (ch == '\n' && chPrev != '\r')) && chPrev != '\\') { // Assume we've hit the end of the statement. preferRE = true; } } } else if (state == SCE_RB_WORD) { if (ch == '.' || !isSafeWordcharOrHigh(ch)) { // Words include x? in all contexts, // and = after either 'def' or a dot // Move along until a complete word is on our left // Default accessor treats '.' as word-chars, // but we don't for now. if (ch == '=' && isSafeWordcharOrHigh(chPrev) && (chNext == '(' || strchr(" \t\n\r", chNext) != NULL) && (!strcmp(prevWord, "def") || followsDot(styler.GetStartSegment(), styler))) { // = is a name only when being def'd -- Get it the next time // This means that = is always lexed as // , (op, =), } else if ((ch == '?' || ch == '!') && isSafeWordcharOrHigh(chPrev) && !isSafeWordcharOrHigh(chNext)) { // ? is a name -- Get it the next time // But ? is always lexed as // , (op, ?), // Same with ! to indicate a method that // modifies its target } else if (isEOLChar(ch) && isMatch(styler, lengthDoc, i - 7, "__END__")) { styler.ColourTo(i, SCE_RB_DATASECTION); state = SCE_RB_DATASECTION; // No need to handle this state -- we'll just move to the end preferRE = false; } else { int wordStartPos = styler.GetStartSegment(); int word_style = ClassifyWordRb(wordStartPos, i - 1, keywords, styler, prevWord); switch (word_style) { case SCE_RB_WORD: preferRE = RE_CanFollowKeyword(prevWord); break; case SCE_RB_WORD_DEMOTED: preferRE = true; break; case SCE_RB_IDENTIFIER: if (isMatch(styler, lengthDoc, wordStartPos, "print")) { preferRE = true; } else if (isEOLChar(ch)) { preferRE = true; } else { preferRE = false; } break; default: preferRE = false; } if (ch == '.') { // We might be redefining an operator-method preferRE = false; } // And if it's the first redo_char(i, ch, chNext, chNext2, state); // pass by ref } } } else if (state == SCE_RB_NUMBER) { if (!is_real_number) { if (ch != '\\') { styler.ColourTo(i, state); state = SCE_RB_DEFAULT; preferRE = false; } else if (strchr("\\ntrfvaebs", chNext)) { // Terminal escape sequence -- handle it next time // Nothing more to do this time through the loop } else if (chNext == 'C' || chNext == 'M') { if (chNext2 != '-') { // \C or \M ends the sequence -- handle it next time } else { // Move from abc?\C-x // ^ // to // ^ i += 2; ch = chNext2; chNext = styler.SafeGetCharAt(i + 1); } } else if (chNext == 'c') { // Stay here, \c is a combining sequence advance_char(i, ch, chNext, chNext2); // pass by ref } else { // ?\x, including ?\\ is final. styler.ColourTo(i + 1, state); state = SCE_RB_DEFAULT; preferRE = false; advance_char(i, ch, chNext, chNext2); } } else if (isSafeAlnumOrHigh(ch) || ch == '_') { // Keep going } else if (ch == '.' && chNext == '.') { ++numDots; styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref } else if (ch == '.' && ++numDots == 1) { // Keep going } else { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref preferRE = false; } } else if (state == SCE_RB_COMMENTLINE) { if (isEOLChar(ch)) { styler.ColourTo(i - 1, state); state = SCE_RB_DEFAULT; // Use whatever setting we had going into the comment } } else if (state == SCE_RB_HERE_DELIM) { // See the comment for SCE_RB_HERE_DELIM in LexPerl.cxx // Slightly different: if we find an immediate '-', // the target can appear indented. if (HereDoc.State == 0) { // '<<' encountered HereDoc.State = 1; HereDoc.DelimiterLength = 0; if (ch == '-') { HereDoc.CanBeIndented = true; advance_char(i, ch, chNext, chNext2); // pass by ref } else { HereDoc.CanBeIndented = false; } if (isEOLChar(ch)) { // Bail out of doing a here doc if there's no target state = SCE_RB_DEFAULT; preferRE = false; } else { HereDoc.Quote = ch; if (ch == '\'' || ch == '"' || ch == '`') { HereDoc.Quoted = true; HereDoc.Delimiter[0] = '\0'; } else { HereDoc.Quoted = false; HereDoc.Delimiter[0] = ch; HereDoc.Delimiter[1] = '\0'; HereDoc.DelimiterLength = 1; } } } else if (HereDoc.State == 1) { // collect the delimiter if (isEOLChar(ch)) { // End the quote now, and go back for more styler.ColourTo(i - 1, state); state = SCE_RB_DEFAULT; i--; chNext = ch; preferRE = false; } else if (HereDoc.Quoted) { if (ch == HereDoc.Quote) { // closing quote => end of delimiter styler.ColourTo(i, state); state = SCE_RB_DEFAULT; preferRE = false; } else { if (ch == '\\' && !isEOLChar(chNext)) { advance_char(i, ch, chNext, chNext2); } HereDoc.Delimiter[HereDoc.DelimiterLength++] = ch; HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; } } else { // an unquoted here-doc delimiter if (isSafeAlnumOrHigh(ch) || ch == '_') { HereDoc.Delimiter[HereDoc.DelimiterLength++] = ch; HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; } else { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); preferRE = false; } } if (HereDoc.DelimiterLength >= static_cast(sizeof(HereDoc.Delimiter)) - 1) { styler.ColourTo(i - 1, state); state = SCE_RB_ERROR; preferRE = false; } } } else if (state == SCE_RB_HERE_Q) { // Not needed: HereDoc.State == 2 // Indentable here docs: look backwards // Non-indentable: look forwards, like in Perl // // Why: so we can quickly resolve things like <<-" abc" if (!HereDoc.CanBeIndented) { if (isEOLChar(chPrev) && isMatch(styler, lengthDoc, i, HereDoc.Delimiter)) { styler.ColourTo(i - 1, state); i += HereDoc.DelimiterLength - 1; chNext = styler.SafeGetCharAt(i + 1); if (isEOLChar(chNext)) { styler.ColourTo(i, SCE_RB_HERE_DELIM); state = SCE_RB_DEFAULT; HereDoc.State = 0; preferRE = false; } // Otherwise we skipped through the here doc faster. } } else if (isEOLChar(chNext) && lookingAtHereDocDelim(styler, i - HereDoc.DelimiterLength + 1, lengthDoc, HereDoc.Delimiter)) { styler.ColourTo(i - 1 - HereDoc.DelimiterLength, state); styler.ColourTo(i, SCE_RB_HERE_DELIM); state = SCE_RB_DEFAULT; preferRE = false; HereDoc.State = 0; } } else if (state == SCE_RB_CLASS_VAR || state == SCE_RB_INSTANCE_VAR || state == SCE_RB_SYMBOL) { if (!isSafeWordcharOrHigh(ch)) { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref preferRE = false; } } else if (state == SCE_RB_GLOBAL) { if (!isSafeWordcharOrHigh(ch)) { // handle special globals here as well if (chPrev == '$') { if (ch == '-') { // Include the next char, like $-a advance_char(i, ch, chNext, chNext2); } styler.ColourTo(i, state); state = SCE_RB_DEFAULT; } else { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref } preferRE = false; } } else if (state == SCE_RB_POD) { // PODs end with ^=end\s, -- any whitespace can follow =end if (strchr(" \t\n\r", ch) != NULL && i > 5 && isEOLChar(styler[i - 5]) && isMatch(styler, lengthDoc, i - 4, "=end")) { styler.ColourTo(i - 1, state); state = SCE_RB_DEFAULT; preferRE = false; } } else if (state == SCE_RB_REGEX || state == SCE_RB_STRING_QR) { if (ch == '\\' && Quote.Up != '\\') { // Skip one advance_char(i, ch, chNext, chNext2); } else if (ch == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { // Include the options while (isSafeAlpha(chNext)) { i++; ch = chNext; chNext = styler.SafeGetCharAt(i + 1); } styler.ColourTo(i, state); state = SCE_RB_DEFAULT; preferRE = false; } } else if (ch == Quote.Up) { // Only if close quoter != open quoter Quote.Count++; } else if (ch == '#' ) { if (chNext == '{' && inner_string_count < INNER_STRINGS_MAX_COUNT) { // process #{ ... } styler.ColourTo(i - 1, state); styler.ColourTo(i + 1, SCE_RB_OPERATOR); enterInnerExpression(inner_string_types, inner_expn_brace_counts, inner_quotes, inner_string_count, state, brace_counts, Quote); preferRE = true; // Skip one advance_char(i, ch, chNext, chNext2); } else { //todo: distinguish comments from pound chars // for now, handle as comment styler.ColourTo(i - 1, state); bool inEscape = false; while (++i < lengthDoc) { ch = styler.SafeGetCharAt(i); if (ch == '\\') { inEscape = true; } else if (isEOLChar(ch)) { // Comment inside a regex styler.ColourTo(i - 1, SCE_RB_COMMENTLINE); break; } else if (inEscape) { inEscape = false; // don't look at char } else if (ch == Quote.Down) { // Have the regular handler deal with this // to get trailing modifiers. i--; ch = styler[i]; break; } } chNext = styler.SafeGetCharAt(i + 1); } } // Quotes of all kinds... } else if (state == SCE_RB_STRING_Q || state == SCE_RB_STRING_QQ || state == SCE_RB_STRING_QX || state == SCE_RB_STRING_QW || state == SCE_RB_STRING || state == SCE_RB_CHARACTER || state == SCE_RB_BACKTICKS) { if (!Quote.Down && !isspacechar(ch)) { Quote.Open(ch); } else if (ch == '\\' && Quote.Up != '\\') { //Riddle me this: Is it safe to skip *every* escaped char? advance_char(i, ch, chNext, chNext2); } else if (ch == Quote.Down) { Quote.Count--; if (Quote.Count == 0) { styler.ColourTo(i, state); state = SCE_RB_DEFAULT; preferRE = false; } } else if (ch == Quote.Up) { Quote.Count++; } else if (ch == '#' && chNext == '{' && inner_string_count < INNER_STRINGS_MAX_COUNT && state != SCE_RB_CHARACTER && state != SCE_RB_STRING_Q) { // process #{ ... } styler.ColourTo(i - 1, state); styler.ColourTo(i + 1, SCE_RB_OPERATOR); enterInnerExpression(inner_string_types, inner_expn_brace_counts, inner_quotes, inner_string_count, state, brace_counts, Quote); preferRE = true; // Skip one advance_char(i, ch, chNext, chNext2); } } if (state == SCE_RB_ERROR) { break; } chPrev = ch; } if (state == SCE_RB_WORD) { // We've ended on a word, possibly at EOF, and need to // classify it. (void) ClassifyWordRb(styler.GetStartSegment(), lengthDoc - 1, keywords, styler, prevWord); } else { styler.ColourTo(lengthDoc - 1, state); } } // Helper functions for folding, disambiguation keywords // Assert that there are no high-bit chars static void getPrevWord(int pos, char *prevWord, Accessor &styler, int word_state) { int i; styler.Flush(); for (i = pos - 1; i > 0; i--) { if (actual_style(styler.StyleAt(i)) != word_state) { i++; break; } } if (i < pos - MAX_KEYWORD_LENGTH) // overflow i = pos - MAX_KEYWORD_LENGTH; char *dst = prevWord; for (; i <= pos; i++) { *dst++ = styler[i]; } *dst = 0; } static bool keywordIsAmbiguous(const char *prevWord) { // Order from most likely used to least likely // Lots of ways to do a loop in Ruby besides 'while/until' if (!strcmp(prevWord, "if") || !strcmp(prevWord, "do") || !strcmp(prevWord, "while") || !strcmp(prevWord, "unless") || !strcmp(prevWord, "until")) { return true; } else { return false; } } // Demote keywords in the following conditions: // if, while, unless, until modify a statement // do after a while or until, as a noise word (like then after if) static bool keywordIsModifier(const char *word, int pos, Accessor &styler) { if (word[0] == 'd' && word[1] == 'o' && !word[2]) { return keywordDoStartsLoop(pos, styler); } char ch, chPrev, chPrev2; int style = SCE_RB_DEFAULT; int lineStart = styler.GetLine(pos); int lineStartPosn = styler.LineStart(lineStart); // We want to step backwards until we don't care about the current // position. But first move lineStartPosn back behind any // continuations immediately above word. while (lineStartPosn > 0) { ch = styler[lineStartPosn-1]; if (ch == '\n' || ch == '\r') { chPrev = styler.SafeGetCharAt(lineStartPosn-2); chPrev2 = styler.SafeGetCharAt(lineStartPosn-3); lineStart = styler.GetLine(lineStartPosn-1); // If we find a continuation line, include it in our analysis. if (chPrev == '\\') { lineStartPosn = styler.LineStart(lineStart); } else if (ch == '\n' && chPrev == '\r' && chPrev2 == '\\') { lineStartPosn = styler.LineStart(lineStart); } else { break; } } else { break; } } styler.Flush(); while (--pos >= lineStartPosn) { style = actual_style(styler.StyleAt(pos)); if (style == SCE_RB_DEFAULT) { if (iswhitespace(ch = styler[pos])) { //continue } else if (ch == '\r' || ch == '\n') { // Scintilla's LineStart() and GetLine() routines aren't // platform-independent, so if we have text prepared with // a different system we can't rely on it. // Also, lineStartPosn may have been moved to more than one // line above word's line while pushing past continuations. chPrev = styler.SafeGetCharAt(pos - 1); chPrev2 = styler.SafeGetCharAt(pos - 2); if (chPrev == '\\') { pos-=1; // gloss over the "\\" //continue } else if (ch == '\n' && chPrev == '\r' && chPrev2 == '\\') { pos-=2; // gloss over the "\\\r" //continue } else { return false; } } } else { break; } } if (pos < lineStartPosn) { return false; } // First things where the action is unambiguous switch (style) { case SCE_RB_DEFAULT: case SCE_RB_COMMENTLINE: case SCE_RB_POD: case SCE_RB_CLASSNAME: case SCE_RB_DEFNAME: case SCE_RB_MODULE_NAME: return false; case SCE_RB_OPERATOR: break; case SCE_RB_WORD: // Watch out for uses of 'else if' //XXX: Make a list of other keywords where 'if' isn't a modifier // and can appear legitimately // Formulate this to avoid warnings from most compilers if (strcmp(word, "if") == 0) { char prevWord[MAX_KEYWORD_LENGTH + 1]; getPrevWord(pos, prevWord, styler, SCE_RB_WORD); return strcmp(prevWord, "else") != 0; } return true; default: return true; } // Assume that if the keyword follows an operator, // usually it's a block assignment, like // a << if x then y else z ch = styler[pos]; switch (ch) { case ')': case ']': case '}': return true; default: return false; } } #define WHILE_BACKWARDS "elihw" #define UNTIL_BACKWARDS "litnu" // Nothing fancy -- look to see if we follow a while/until somewhere // on the current line static bool keywordDoStartsLoop(int pos, Accessor &styler) { char ch; int style; int lineStart = styler.GetLine(pos); int lineStartPosn = styler.LineStart(lineStart); styler.Flush(); while (--pos >= lineStartPosn) { style = actual_style(styler.StyleAt(pos)); if (style == SCE_RB_DEFAULT) { if ((ch = styler[pos]) == '\r' || ch == '\n') { // Scintilla's LineStart() and GetLine() routines aren't // platform-independent, so if we have text prepared with // a different system we can't rely on it. return false; } } else if (style == SCE_RB_WORD) { // Check for while or until, but write the word in backwards char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero char *dst = prevWord; int wordLen = 0; int start_word; for (start_word = pos; start_word >= lineStartPosn && actual_style(styler.StyleAt(start_word)) == SCE_RB_WORD; start_word--) { if (++wordLen < MAX_KEYWORD_LENGTH) { *dst++ = styler[start_word]; } } *dst = 0; // Did we see our keyword? if (!strcmp(prevWord, WHILE_BACKWARDS) || !strcmp(prevWord, UNTIL_BACKWARDS)) { return true; } // We can move pos to the beginning of the keyword, and then // accept another decrement, as we can never have two contiguous // keywords: // word1 word2 // ^ // <- move to start_word // ^ // <- loop decrement // ^ # pointing to end of word1 is fine pos = start_word; } } return false; } /* * Folding Ruby * * The language is quite complex to analyze without a full parse. * For example, this line shouldn't affect fold level: * * print "hello" if feeling_friendly? * * Neither should this: * * print "hello" \ * if feeling_friendly? * * * But this should: * * if feeling_friendly? #++ * print "hello" \ * print "goodbye" * end #-- * * So we cheat, by actually looking at the existing indentation * levels for each line, and just echoing it back. Like Python. * Then if we get better at it, we'll take braces into consideration, * which always affect folding levels. * How the keywords should work: * No effect: * __FILE__ __LINE__ BEGIN END alias and * defined? false in nil not or self super then * true undef * Always increment: * begin class def do for module when { * * Always decrement: * end } * * Increment if these start a statement * if unless until while -- do nothing if they're modifiers * These end a block if there's no modifier, but don't bother * break next redo retry return yield * * These temporarily de-indent, but re-indent * case else elsif ensure rescue * * This means that the folder reflects indentation rather * than setting it. The language-service updates indentation * when users type return and finishes entering de-denters. * * Later offer to fold POD, here-docs, strings, and blocks of comments */ static void FoldRbDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldComment = styler.GetPropertyInt("fold.comment") != 0; synchronizeDocStart(startPos, length, initStyle, styler, // ref args false); unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = startPos == 0 ? 0 : (styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK & ~SC_FOLDLEVELBASE); int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int stylePrev = startPos <= 1 ? SCE_RB_DEFAULT : styler.StyleAt(startPos - 1); bool buffer_ends_with_eol = false; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_RB_COMMENTLINE) { if (foldComment && stylePrev != SCE_RB_COMMENTLINE) { if (chNext == '{') { levelCurrent++; } else if (chNext == '}' && levelCurrent > 0) { levelCurrent--; } } } else if (style == SCE_RB_OPERATOR) { if (strchr("[{(", ch)) { levelCurrent++; } else if (strchr(")}]", ch)) { // Don't decrement below 0 if (levelCurrent > 0) levelCurrent--; } } else if (style == SCE_RB_WORD && styleNext != SCE_RB_WORD) { // Look at the keyword on the left and decide what to do char prevWord[MAX_KEYWORD_LENGTH + 1]; // 1 byte for zero prevWord[0] = 0; getPrevWord(i, prevWord, styler, SCE_RB_WORD); if (!strcmp(prevWord, "end")) { // Don't decrement below 0 if (levelCurrent > 0) levelCurrent--; } else if ( !strcmp(prevWord, "if") || !strcmp(prevWord, "def") || !strcmp(prevWord, "class") || !strcmp(prevWord, "module") || !strcmp(prevWord, "begin") || !strcmp(prevWord, "case") || !strcmp(prevWord, "do") || !strcmp(prevWord, "while") || !strcmp(prevWord, "unless") || !strcmp(prevWord, "until") || !strcmp(prevWord, "for") ) { levelCurrent++; } } else if (style == SCE_RB_HERE_DELIM) { if (styler.SafeGetCharAt(i-2) == '<' && styler.SafeGetCharAt(i-1) == '<') { levelCurrent++; } else if (styleNext == SCE_RB_DEFAULT) { levelCurrent--; } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; styler.SetLevel(lineCurrent, lev|SC_FOLDLEVELBASE); lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; buffer_ends_with_eol = true; } else if (!isspacechar(ch)) { visibleChars++; buffer_ends_with_eol = false; } stylePrev = style; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later if (!buffer_ends_with_eol) { lineCurrent++; int new_lev = levelCurrent; if (visibleChars == 0 && foldCompact) new_lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) new_lev |= SC_FOLDLEVELHEADERFLAG; levelCurrent = new_lev; } styler.SetLevel(lineCurrent, levelCurrent|SC_FOLDLEVELBASE); } static const char * const rubyWordListDesc[] = { "Keywords", 0 }; LexerModule lmRuby(SCLEX_RUBY, ColouriseRbDoc, "ruby", FoldRbDoc, rubyWordListDesc, 6); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMagik.cxx0000644000175000017500000003243411634611460021366 00000000000000// Scintilla source code edit control /** * @file LexMagik.cxx * Lexer for GE(r) Smallworld(tm) MagikSF */ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /** * Is it a core character (C isalpha(), exclamation and question mark) * * \param ch The character * \return True if ch is a character, False otherwise */ static inline bool IsAlphaCore(int ch) { return (isalpha(ch) || ch == '!' || ch == '?'); } /** * Is it a character (IsAlphaCore() and underscore) * * \param ch The character * \return True if ch is a character, False otherwise */ static inline bool IsAlpha(int ch) { return (IsAlphaCore(ch) || ch == '_'); } /** * Is it a symbolic character (IsAlpha() and colon) * * \param ch The character * \return True if ch is a character, False otherwise */ static inline bool IsAlphaSym(int ch) { return (IsAlpha(ch) || ch == ':'); } /** * Is it a numerical character (IsAlpha() and 0 - 9) * * \param ch The character * \return True if ch is a character, False otherwise */ static inline bool IsAlNum(int ch) { return ((ch >= '0' && ch <= '9') || IsAlpha(ch)); } /** * Is it a symbolic numerical character (IsAlNum() and colon) * * \param ch The character * \return True if ch is a character, False otherwise */ static inline bool IsAlNumSym(int ch) { return (IsAlNum(ch) || ch == ':'); } /** * The lexer function * * \param startPos Where to start scanning * \param length Where to scan to * \param initStyle The style at the initial point, not used in this folder * \param keywordslists The keywordslists, currently, number 5 is used * \param styler The styler */ static void ColouriseMagikDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos); WordList &keywords = *keywordlists[0]; WordList &pragmatics = *keywordlists[1]; WordList &containers = *keywordlists[2]; WordList &flow = *keywordlists[3]; WordList &characters = *keywordlists[4]; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { repeat: if(sc.ch == '#') { if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT); else sc.SetState(SCE_MAGIK_COMMENT); for(; sc.More() && !(sc.atLineEnd); sc.Forward()); sc.SetState(SCE_MAGIK_DEFAULT); goto repeat; } if(sc.ch == '"') { sc.SetState(SCE_MAGIK_STRING); if(sc.More()) { sc.Forward(); for(; sc.More() && sc.ch != '"'; sc.Forward()); } sc.ForwardSetState(SCE_MAGIK_DEFAULT); goto repeat; } // The default state if(sc.state == SCE_MAGIK_DEFAULT) { // A certain keyword has been detected if (sc.ch == '_' && ( sc.currentPos == 0 || !IsAlNum(sc.chPrev))) { char keyword[50]; memset(keyword, '\0', 50); for( int scanPosition = 0; scanPosition < 50; scanPosition++) { char keywordChar = static_cast( tolower(styler.SafeGetCharAt( scanPosition + static_cast(sc.currentPos+1), ' '))); if(IsAlpha(keywordChar)) { keyword[scanPosition] = keywordChar; } else { break; } } // It is a pragma if(pragmatics.InList(keyword)) { sc.SetState(SCE_MAGIK_PRAGMA); } // it is a normal keyword like _local, _self, etc. else if(keywords.InList(keyword)) { sc.SetState(SCE_MAGIK_KEYWORD); } // It is a container keyword, such as _method, _proc, etc. else if(containers.InList(keyword)) { sc.SetState(SCE_MAGIK_CONTAINER); } // It is a flow keyword, such as _for, _if, _try, etc. else if(flow.InList(keyword)) { sc.SetState(SCE_MAGIK_FLOW); } // Interpret as unknown keyword else { sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD); } } // Symbolic expression else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) { sc.SetState(SCE_MAGIK_SYMBOL); bool firstTrip = true; for(sc.Forward(); sc.More(); sc.Forward()) { if(firstTrip && IsAlphaSym(sc.ch)); else if(!firstTrip && IsAlNumSym(sc.ch)); else if(sc.ch == '|') { for(sc.Forward(); sc.More() && sc.ch != '|'; sc.Forward()); } else break; firstTrip = false; } sc.SetState(SCE_MAGIK_DEFAULT); goto repeat; } // Identifier (label) expression else if(sc.ch == '@') { sc.SetState(SCE_MAGIK_IDENTIFIER); bool firstTrip = true; for(sc.Forward(); sc.More(); sc.Forward()) { if(firstTrip && IsAlphaCore(sc.ch)) { firstTrip = false; } else if(!firstTrip && IsAlpha(sc.ch)); else break; } sc.SetState(SCE_MAGIK_DEFAULT); goto repeat; } // Start of a character else if(sc.ch == '%') { sc.SetState(SCE_MAGIK_CHARACTER); sc.Forward(); char keyword[50]; memset(keyword, '\0', 50); for( int scanPosition = 0; scanPosition < 50; scanPosition++) { char keywordChar = static_cast( tolower(styler.SafeGetCharAt( scanPosition + static_cast(sc.currentPos), ' '))); if(IsAlpha(keywordChar)) { keyword[scanPosition] = keywordChar; } else { break; } } if(characters.InList(keyword)) { sc.Forward(static_cast(strlen(keyword))); } else { sc.Forward(); } sc.SetState(SCE_MAGIK_DEFAULT); goto repeat; } // Operators else if( sc.ch == '>' || sc.ch == '<' || sc.ch == '.' || sc.ch == ',' || sc.ch == '+' || sc.ch == '-' || sc.ch == '/' || sc.ch == '*' || sc.ch == '~' || sc.ch == '$' || sc.ch == '=') { sc.SetState(SCE_MAGIK_OPERATOR); } // Braces else if(sc.ch == '(' || sc.ch == ')') { sc.SetState(SCE_MAGIK_BRACE_BLOCK); } // Brackets else if(sc.ch == '{' || sc.ch == '}') { sc.SetState(SCE_MAGIK_BRACKET_BLOCK); } // Square Brackets else if(sc.ch == '[' || sc.ch == ']') { sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK); } } // It is an operator else if( sc.state == SCE_MAGIK_OPERATOR || sc.state == SCE_MAGIK_BRACE_BLOCK || sc.state == SCE_MAGIK_BRACKET_BLOCK || sc.state == SCE_MAGIK_SQBRACKET_BLOCK) { sc.SetState(SCE_MAGIK_DEFAULT); goto repeat; } // It is the pragma state else if(sc.state == SCE_MAGIK_PRAGMA) { if(!IsAlpha(sc.ch)) { sc.SetState(SCE_MAGIK_DEFAULT); goto repeat; } } // It is the keyword state else if( sc.state == SCE_MAGIK_KEYWORD || sc.state == SCE_MAGIK_CONTAINER || sc.state == SCE_MAGIK_FLOW || sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) { if(!IsAlpha(sc.ch)) { sc.SetState(SCE_MAGIK_DEFAULT); goto repeat; } } } sc.Complete(); } /** * The word list description */ static const char * const magikWordListDesc[] = { "Accessors (local, global, self, super, thisthread)", "Pragmatic (pragma, private)", "Containers (method, block, proc)", "Flow (if, then, elif, else)", "Characters (space, tab, newline, return)", "Fold Containers (method, proc, block, if, loop)", 0}; /** * This function detects keywords which are able to have a body. Note that it * uses the Fold Containers word description, not the containers description. It * only works when the style at that particular position is set on Containers * or Flow (number 3 or 4). * * \param keywordslist The list of keywords that are scanned, they should only * contain the start keywords, not the end keywords * \param The actual keyword * \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword * 0 otherwise */ static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) { if( strlen(keyword) > 3 && keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') { if (keywordslist.InList(keyword + 3)) { return -1; } } else { if(keywordslist.InList(keyword)) { return 1; } } return 0; } /** * The folding function * * \param startPos Where to start scanning * \param length Where to scan to * \param keywordslists The keywordslists, currently, number 5 is used * \param styler The styler */ static void FoldMagikDoc(unsigned int startPos, int length, int, WordList *keywordslists[], Accessor &styler) { bool compact = styler.GetPropertyInt("fold.compact") != 0; WordList &foldingElements = *keywordslists[5]; int endPos = startPos + length; int line = styler.GetLine(startPos); int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK; int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK; for( int currentPos = startPos; currentPos < endPos; currentPos++) { char currentState = styler.StyleAt(currentPos); char c = styler.SafeGetCharAt(currentPos, ' '); int prevLine = styler.GetLine(currentPos - 1); line = styler.GetLine(currentPos); // Default situation if(prevLine < line) { styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG); flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK; } if( ( currentState == SCE_MAGIK_CONTAINER || currentState == SCE_MAGIK_FLOW ) && c == '_') { char keyword[50]; memset(keyword, '\0', 50); for( int scanPosition = 0; scanPosition < 50; scanPosition++) { char keywordChar = static_cast( tolower(styler.SafeGetCharAt( scanPosition + currentPos + 1, ' '))); if(IsAlpha(keywordChar)) { keyword[scanPosition] = keywordChar; } else { break; } } if(IsFoldingContainer(foldingElements, keyword) > 0) { styler.SetLevel( line, styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG); level++; } else if(IsFoldingContainer(foldingElements, keyword) < 0) { styler.SetLevel(line, styler.LevelAt(line)); level--; } } if( compact && ( currentState == SCE_MAGIK_BRACE_BLOCK || currentState == SCE_MAGIK_BRACKET_BLOCK || currentState == SCE_MAGIK_SQBRACKET_BLOCK)) { if(c == '{' || c == '[' || c == '(') { styler.SetLevel( line, styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG); level++; } else if(c == '}' || c == ']' || c == ')') { styler.SetLevel(line, styler.LevelAt(line)); level--; } } } } /** * Injecting the module */ LexerModule lmMagikSF( SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexNimrod.cxx0000644000175000017500000003240711615412040021556 00000000000000// Scintilla source code edit control // Nimrod lexer // (c) 2009 Andreas Rumpf /** @file LexNimrod.cxx ** Lexer for Nimrod. **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch) { return (ch >= 0x80) || isalnum(ch) || ch == '_'; } static int tillEndOfTripleQuote(Accessor &styler, int pos, int max) { /* search for """ */ for (;;) { if (styler.SafeGetCharAt(pos, '\0') == '\0') return pos; if (pos >= max) return pos; if (styler.Match(pos, "\"\"\"")) { return pos + 2; } pos++; } } #define CR 13 /* use both because Scite allows changing the line ending */ #define LF 10 static bool inline isNewLine(int ch) { return ch == CR || ch == LF; } static int scanString(Accessor &styler, int pos, int max, bool rawMode) { for (;;) { if (pos >= max) return pos; char ch = styler.SafeGetCharAt(pos, '\0'); if (ch == CR || ch == LF || ch == '\0') return pos; if (ch == '"') return pos; if (ch == '\\' && !rawMode) { pos += 2; } else { pos++; } } } static int scanChar(Accessor &styler, int pos, int max) { for (;;) { if (pos >= max) return pos; char ch = styler.SafeGetCharAt(pos, '\0'); if (ch == CR || ch == LF || ch == '\0') return pos; if (ch == '\'' && !isalnum(styler.SafeGetCharAt(pos+1, '\0')) ) return pos; if (ch == '\\') { pos += 2; } else { pos++; } } } static int scanIdent(Accessor &styler, int pos, WordList &keywords) { char buf[100]; /* copy to lowercase and ignore underscores */ int i = 0; for (;;) { char ch = styler.SafeGetCharAt(pos, '\0'); if (!IsAWordChar(ch)) break; if (ch != '_' && i < ((int)sizeof(buf))-1) { buf[i] = static_cast(tolower(ch)); i++; } pos++; } buf[i] = '\0'; /* look for keyword */ if (keywords.InList(buf)) { styler.ColourTo(pos-1, SCE_P_WORD); } else { styler.ColourTo(pos-1, SCE_P_IDENTIFIER); } return pos; } static int scanNumber(Accessor &styler, int pos) { char ch, ch2; ch = styler.SafeGetCharAt(pos, '\0'); ch2 = styler.SafeGetCharAt(pos+1, '\0'); if (ch == '0' && (ch2 == 'b' || ch2 == 'B')) { /* binary number: */ pos += 2; for (;;) { ch = styler.SafeGetCharAt(pos, '\0'); if (ch == '_' || (ch >= '0' && ch <= '1')) ++pos; else break; } } else if (ch == '0' && (ch2 == 'o' || ch2 == 'O' || ch2 == 'c' || ch2 == 'C')) { /* octal number: */ pos += 2; for (;;) { ch = styler.SafeGetCharAt(pos, '\0'); if (ch == '_' || (ch >= '0' && ch <= '7')) ++pos; else break; } } else if (ch == '0' && (ch2 == 'x' || ch2 == 'X')) { /* hexadecimal number: */ pos += 2; for (;;) { ch = styler.SafeGetCharAt(pos, '\0'); if (ch == '_' || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) ++pos; else break; } } else { // skip decimal part: for (;;) { ch = styler.SafeGetCharAt(pos, '\0'); if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; else break; } ch2 = styler.SafeGetCharAt(pos+1, '\0'); if (ch == '.' && ch2 >= '0' && ch2 <= '9') { ++pos; // skip '.' for (;;) { ch = styler.SafeGetCharAt(pos, '\0'); if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; else break; } } if (ch == 'e' || ch == 'E') { ++pos; ch = styler.SafeGetCharAt(pos, '\0'); if (ch == '-' || ch == '+') ++pos; for (;;) { ch = styler.SafeGetCharAt(pos, '\0'); if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; else break; } } } if (ch == '\'') { /* a type suffix: */ pos++; for (;;) { ch = styler.SafeGetCharAt(pos); if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_') ++pos; else break; } } styler.ColourTo(pos-1, SCE_P_NUMBER); return pos; } /* rewritten from scratch, because I couldn't get rid of the bugs... (A character based approach sucks!) */ static void ColouriseNimrodDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { int pos = startPos; int max = startPos + length; char ch; WordList &keywords = *keywordlists[0]; styler.StartAt(startPos); styler.StartSegment(startPos); switch (initStyle) { /* check where we are: */ case SCE_P_TRIPLEDOUBLE: pos = tillEndOfTripleQuote(styler, pos, max); styler.ColourTo(pos, SCE_P_TRIPLEDOUBLE); pos++; break; default: /* nothing to do: */ break; } while (pos < max) { ch = styler.SafeGetCharAt(pos, '\0'); switch (ch) { case '\0': return; case '#': { bool doccomment = (styler.SafeGetCharAt(pos+1) == '#'); while (pos < max && !isNewLine(styler.SafeGetCharAt(pos, LF))) pos++; if (doccomment) styler.ColourTo(pos, SCE_C_COMMENTLINEDOC); else styler.ColourTo(pos, SCE_P_COMMENTLINE); } break; case 'r': case 'R': { if (styler.SafeGetCharAt(pos+1) == '"') { pos = scanString(styler, pos+2, max, true); styler.ColourTo(pos, SCE_P_STRING); pos++; } else { pos = scanIdent(styler, pos, keywords); } } break; case '"': if (styler.Match(pos+1, "\"\"")) { pos = tillEndOfTripleQuote(styler, pos+3, max); styler.ColourTo(pos, SCE_P_TRIPLEDOUBLE); } else { pos = scanString(styler, pos+1, max, false); styler.ColourTo(pos, SCE_P_STRING); } pos++; break; case '\'': pos = scanChar(styler, pos+1, max); styler.ColourTo(pos, SCE_P_CHARACTER); pos++; break; default: // identifers, numbers, operators, whitespace if (ch >= '0' && ch <= '9') { pos = scanNumber(styler, pos); } else if (IsAWordChar(ch)) { pos = scanIdent(styler, pos, keywords); } else if (ch == '`') { pos++; while (pos < max) { ch = styler.SafeGetCharAt(pos, LF); if (ch == '`') { ++pos; break; } if (ch == CR || ch == LF) break; ++pos; } styler.ColourTo(pos, SCE_P_IDENTIFIER); } else if (strchr("()[]{}:=;-\\/&%$!+<>|^?,.*~@", ch)) { styler.ColourTo(pos, SCE_P_OPERATOR); pos++; } else { styler.ColourTo(pos, SCE_P_DEFAULT); pos++; } break; } } } static bool IsCommentLine(int line, Accessor &styler) { int pos = styler.LineStart(line); int eol_pos = styler.LineStart(line + 1) - 1; for (int i = pos; i < eol_pos; i++) { char ch = styler[i]; if (ch == '#') return true; else if (ch != ' ' && ch != '\t') return false; } return false; } static bool IsQuoteLine(int line, Accessor &styler) { int style = styler.StyleAt(styler.LineStart(line)) & 31; return ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE)); } static void FoldNimrodDoc(unsigned int startPos, int length, int /*initStyle - unused*/, WordList *[], Accessor &styler) { const int maxPos = startPos + length; const int maxLines = styler.GetLine(maxPos - 1); // Requested last line const int docLines = styler.GetLine(styler.Length() - 1); // Available last line const bool foldComment = styler.GetPropertyInt("fold.comment.nimrod") != 0; const bool foldQuotes = styler.GetPropertyInt("fold.quotes.nimrod") != 0; // Backtrack to previous non-blank line so we can determine indent level // for any white space lines (needed esp. within triple quoted strings) // and so we can fix any preceding fold level (which is why we go back // at least one line in all cases) int spaceFlags = 0; int lineCurrent = styler.GetLine(startPos); int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); while (lineCurrent > 0) { lineCurrent--; indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) && (!IsCommentLine(lineCurrent, styler)) && (!IsQuoteLine(lineCurrent, styler))) break; } int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; // Set up initial loop state startPos = styler.LineStart(lineCurrent); int prev_state = SCE_P_DEFAULT & 31; if (lineCurrent >= 1) prev_state = styler.StyleAt(startPos - 1) & 31; int prevQuote = foldQuotes && ((prev_state == SCE_P_TRIPLE) || (prev_state == SCE_P_TRIPLEDOUBLE)); int prevComment = 0; if (lineCurrent >= 1) prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler); // Process all characters to end of requested range or end of any triple quote // or comment that hangs over the end of the range. Cap processing in all cases // to end of document (in case of unclosed quote or comment at end). while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevQuote || prevComment)) { // Gather info int lev = indentCurrent; int lineNext = lineCurrent + 1; int indentNext = indentCurrent; int quote = false; if (lineNext <= docLines) { // Information about next line is only available if not at end of document indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); int style = styler.StyleAt(styler.LineStart(lineNext)) & 31; quote = foldQuotes && ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE)); } const int quote_start = (quote && !prevQuote); const int quote_continue = (quote && prevQuote); const int comment = foldComment && IsCommentLine(lineCurrent, styler); const int comment_start = (comment && !prevComment && (lineNext <= docLines) && IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE)); const int comment_continue = (comment && prevComment); if ((!quote || !prevQuote) && !comment) indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; if (quote) indentNext = indentCurrentLevel; if (indentNext & SC_FOLDLEVELWHITEFLAG) indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel; if (quote_start) { // Place fold point at start of triple quoted string lev |= SC_FOLDLEVELHEADERFLAG; } else if (quote_continue || prevQuote) { // Add level to rest of lines in the string lev = lev + 1; } else if (comment_start) { // Place fold point at start of a block of comments lev |= SC_FOLDLEVELHEADERFLAG; } else if (comment_continue) { // Add level to rest of lines in the block lev = lev + 1; } // Skip past any blank lines for next indent level info; we skip also // comments (all comments, not just those starting in column 0) // which effectively folds them into surrounding code rather // than screwing up folding. while (!quote && (lineNext < docLines) && ((indentNext & SC_FOLDLEVELWHITEFLAG) || (lineNext <= docLines && IsCommentLine(lineNext, styler)))) { lineNext++; indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); } const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK; const int levelBeforeComments = Maximum(indentCurrentLevel,levelAfterComments); // Now set all the indent levels on the lines we skipped // Do this from end to start. Once we encounter one line // which is indented more than the line after the end of // the comment-block, use the level of the block before int skipLine = lineNext; int skipLevel = levelAfterComments; while (--skipLine > lineCurrent) { int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL); if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments) skipLevel = levelBeforeComments; int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG; styler.SetLevel(skipLine, skipLevel | whiteFlag); } // Set fold header on non-quote/non-comment line if (!quote && !comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) { if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) lev |= SC_FOLDLEVELHEADERFLAG; } // Keep track of triple quote and block comment state of previous line prevQuote = quote; prevComment = comment_start || comment_continue; // Set fold level for this line and move to next line styler.SetLevel(lineCurrent, lev); indentCurrent = indentNext; lineCurrent = lineNext; } // NOTE: Cannot set level of last line here because indentCurrent doesn't have // header flag set; the loop above is crafted to take care of this case! //styler.SetLevel(lineCurrent, indentCurrent); } static const char * const nimrodWordListDesc[] = { "Keywords", 0 }; LexerModule lmNimrod(SCLEX_NIMROD, ColouriseNimrodDoc, "nimrod", FoldNimrodDoc, nimrodWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexCSS.cxx0000644000175000017500000004275711710634267021004 00000000000000// Scintilla source code edit control /** @file LexCSS.cxx ** Lexer for Cascading Style Sheets ** Written by Jakub Vrána ** Improved by Philippe Lhoste (CSS2) ** Improved by Ross McKay (SCSS mode; see http://sass-lang.com/ ) **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. // TODO: handle SCSS nested properties like font: { weight: bold; size: 1em; } // TODO: handle SCSS interpolation: #{} // TODO: add features for Less if somebody feels like contributing; http://lesscss.org/ // TODO: refactor this monster so that the next poor slob can read it! #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const unsigned int ch) { /* FIXME: * The CSS spec allows "ISO 10646 characters U+00A1 and higher" to be treated as word chars. * Unfortunately, we are only getting string bytes here, and not full unicode characters. We cannot guarantee * that our byte is between U+0080 - U+00A0 (to return false), so we have to allow all characters U+0080 and higher */ return ch >= 0x80 || isalnum(ch) || ch == '-' || ch == '_'; } inline bool IsCssOperator(const int ch) { if (!((ch < 0x80) && isalnum(ch)) && (ch == '{' || ch == '}' || ch == ':' || ch == ',' || ch == ';' || ch == '.' || ch == '#' || ch == '!' || ch == '@' || /* CSS2 */ ch == '*' || ch == '>' || ch == '+' || ch == '=' || ch == '~' || ch == '|' || ch == '[' || ch == ']' || ch == '(' || ch == ')')) { return true; } return false; } // look behind (from start of document to our start position) to determine current nesting level inline int NestingLevelLookBehind(unsigned int startPos, Accessor &styler) { int ch; int nestingLevel = 0; for (unsigned int i = 0; i < startPos; i++) { ch = styler.SafeGetCharAt(i); if (ch == '{') nestingLevel++; else if (ch == '}') nestingLevel--; } return nestingLevel; } static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &css1Props = *keywordlists[0]; WordList &pseudoClasses = *keywordlists[1]; WordList &css2Props = *keywordlists[2]; WordList &css3Props = *keywordlists[3]; WordList &pseudoElements = *keywordlists[4]; WordList &exProps = *keywordlists[5]; WordList &exPseudoClasses = *keywordlists[6]; WordList &exPseudoElements = *keywordlists[7]; StyleContext sc(startPos, length, initStyle, styler); int lastState = -1; // before operator int lastStateC = -1; // before comment int lastStateS = -1; // before single-quoted/double-quoted string int lastStateVar = -1; // before variable (SCSS) int lastStateVal = -1; // before value (SCSS) int op = ' '; // last operator int opPrev = ' '; // last operator bool insideParentheses = false; // true if currently in a CSS url() or similar construct // property lexer.css.scss.language // Set to 1 for Sassy CSS (.scss) bool isScssDocument = styler.GetPropertyInt("lexer.css.scss.language") != 0; // TODO: implement Less support bool isLessDocument = false; // SCSS and Less both support single-line comments typedef enum _CommentModes { eCommentBlock = 0, eCommentLine = 1} CommentMode; CommentMode comment_mode = eCommentBlock; bool hasSingleLineComments = isScssDocument || isLessDocument; // must keep track of nesting level in document types that support it (SCSS, Less) bool hasNesting = false; int nestingLevel = 0; if (isScssDocument || isLessDocument) { hasNesting = true; nestingLevel = NestingLevelLookBehind(startPos, styler); } // "the loop" for (; sc.More(); sc.Forward()) { if (sc.state == SCE_CSS_COMMENT && ((comment_mode == eCommentBlock && sc.Match('*', '/')) || (comment_mode == eCommentLine && sc.atLineEnd))) { if (lastStateC == -1) { // backtrack to get last state: // comments are like whitespace, so we must return to the previous state unsigned int i = startPos; for (; i > 0; i--) { if ((lastStateC = styler.StyleAt(i-1)) != SCE_CSS_COMMENT) { if (lastStateC == SCE_CSS_OPERATOR) { op = styler.SafeGetCharAt(i-1); opPrev = styler.SafeGetCharAt(i-2); while (--i) { lastState = styler.StyleAt(i-1); if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT) break; } if (i == 0) lastState = SCE_CSS_DEFAULT; } break; } } if (i == 0) lastStateC = SCE_CSS_DEFAULT; } if (comment_mode == eCommentBlock) { sc.Forward(); sc.ForwardSetState(lastStateC); } else /* eCommentLine */ { sc.SetState(lastStateC); } } if (sc.state == SCE_CSS_COMMENT) continue; if (sc.state == SCE_CSS_DOUBLESTRING || sc.state == SCE_CSS_SINGLESTRING) { if (sc.ch != (sc.state == SCE_CSS_DOUBLESTRING ? '\"' : '\'')) continue; unsigned int i = sc.currentPos; while (i && styler[i-1] == '\\') i--; if ((sc.currentPos - i) % 2 == 1) continue; sc.ForwardSetState(lastStateS); } if (sc.state == SCE_CSS_OPERATOR) { if (op == ' ') { unsigned int i = startPos; op = styler.SafeGetCharAt(i-1); opPrev = styler.SafeGetCharAt(i-2); while (--i) { lastState = styler.StyleAt(i-1); if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT) break; } } switch (op) { case '@': if (lastState == SCE_CSS_DEFAULT || hasNesting) sc.SetState(SCE_CSS_DIRECTIVE); break; case '>': case '+': if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID || lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS) sc.SetState(SCE_CSS_DEFAULT); break; case '[': if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID || lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS) sc.SetState(SCE_CSS_ATTRIBUTE); break; case ']': if (lastState == SCE_CSS_ATTRIBUTE) sc.SetState(SCE_CSS_TAG); break; case '{': nestingLevel++; switch (lastState) { case SCE_CSS_MEDIA: sc.SetState(SCE_CSS_DEFAULT); break; case SCE_CSS_TAG: case SCE_CSS_DIRECTIVE: sc.SetState(SCE_CSS_IDENTIFIER); break; } break; case '}': if (--nestingLevel < 0) nestingLevel = 0; switch (lastState) { case SCE_CSS_DEFAULT: case SCE_CSS_VALUE: case SCE_CSS_IMPORTANT: case SCE_CSS_IDENTIFIER: case SCE_CSS_IDENTIFIER2: case SCE_CSS_IDENTIFIER3: if (hasNesting) sc.SetState(nestingLevel > 0 ? SCE_CSS_IDENTIFIER : SCE_CSS_DEFAULT); else sc.SetState(SCE_CSS_DEFAULT); break; } break; case '(': if (lastState == SCE_CSS_PSEUDOCLASS) sc.SetState(SCE_CSS_TAG); else if (lastState == SCE_CSS_EXTENDED_PSEUDOCLASS) sc.SetState(SCE_CSS_EXTENDED_PSEUDOCLASS); break; case ')': if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID || lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS || lastState == SCE_CSS_PSEUDOELEMENT || lastState == SCE_CSS_EXTENDED_PSEUDOELEMENT) sc.SetState(SCE_CSS_TAG); break; case ':': switch (lastState) { case SCE_CSS_TAG: case SCE_CSS_DEFAULT: case SCE_CSS_CLASS: case SCE_CSS_ID: case SCE_CSS_PSEUDOCLASS: case SCE_CSS_EXTENDED_PSEUDOCLASS: case SCE_CSS_UNKNOWN_PSEUDOCLASS: case SCE_CSS_PSEUDOELEMENT: case SCE_CSS_EXTENDED_PSEUDOELEMENT: sc.SetState(SCE_CSS_PSEUDOCLASS); break; case SCE_CSS_IDENTIFIER: case SCE_CSS_IDENTIFIER2: case SCE_CSS_IDENTIFIER3: case SCE_CSS_EXTENDED_IDENTIFIER: case SCE_CSS_UNKNOWN_IDENTIFIER: case SCE_CSS_VARIABLE: sc.SetState(SCE_CSS_VALUE); lastStateVal = lastState; break; } break; case '.': if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID || lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS) sc.SetState(SCE_CSS_CLASS); break; case '#': if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID || lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_EXTENDED_PSEUDOCLASS || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS) sc.SetState(SCE_CSS_ID); break; case ',': case '|': case '~': if (lastState == SCE_CSS_TAG) sc.SetState(SCE_CSS_DEFAULT); break; case ';': switch (lastState) { case SCE_CSS_DIRECTIVE: if (hasNesting) { sc.SetState(nestingLevel > 0 ? SCE_CSS_IDENTIFIER : SCE_CSS_DEFAULT); } else { sc.SetState(SCE_CSS_DEFAULT); } break; case SCE_CSS_VALUE: case SCE_CSS_IMPORTANT: // data URLs can have semicolons; simplistically check for wrapping parentheses and move along if (insideParentheses) { sc.SetState(lastState); } else { if (lastStateVal == SCE_CSS_VARIABLE) { sc.SetState(SCE_CSS_DEFAULT); } else { sc.SetState(SCE_CSS_IDENTIFIER); } } break; case SCE_CSS_VARIABLE: if (lastStateVar == SCE_CSS_VALUE) { // data URLs can have semicolons; simplistically check for wrapping parentheses and move along if (insideParentheses) { sc.SetState(SCE_CSS_VALUE); } else { sc.SetState(SCE_CSS_IDENTIFIER); } } else { sc.SetState(SCE_CSS_DEFAULT); } break; } break; case '!': if (lastState == SCE_CSS_VALUE) sc.SetState(SCE_CSS_IMPORTANT); break; } } if (sc.ch == '*' && sc.state == SCE_CSS_DEFAULT) { sc.SetState(SCE_CSS_TAG); continue; } // check for inside parentheses (whether part of an "operator" or not) if (sc.ch == '(') insideParentheses = true; else if (sc.ch == ')') insideParentheses = false; // SCSS special modes if (isScssDocument) { // variable name if (sc.ch == '$') { switch (sc.state) { case SCE_CSS_DEFAULT: case SCE_CSS_VALUE: lastStateVar = sc.state; sc.SetState(SCE_CSS_VARIABLE); continue; } } if (sc.state == SCE_CSS_VARIABLE) { if (IsAWordChar(sc.ch)) { // still looking at the variable name continue; } if (lastStateVar == SCE_CSS_VALUE) { // not looking at the variable name any more, and it was part of a value sc.SetState(SCE_CSS_VALUE); } } // nested rule parent selector if (sc.ch == '&') { switch (sc.state) { case SCE_CSS_DEFAULT: case SCE_CSS_IDENTIFIER: sc.SetState(SCE_CSS_TAG); continue; } } } // nesting rules that apply to SCSS and Less if (hasNesting) { // check for nested rule selector if (sc.state == SCE_CSS_IDENTIFIER && (IsAWordChar(sc.ch) || sc.ch == ':' || sc.ch == '.' || sc.ch == '#')) { // look ahead to see whether { comes before next ; and } unsigned int endPos = startPos + length; int ch; for (unsigned int i = sc.currentPos; i < endPos; i++) { ch = styler.SafeGetCharAt(i); if (ch == ';' || ch == '}') break; if (ch == '{') { sc.SetState(SCE_CSS_DEFAULT); continue; } } } } if (IsAWordChar(sc.ch)) { if (sc.state == SCE_CSS_DEFAULT) sc.SetState(SCE_CSS_TAG); continue; } if (IsAWordChar(sc.chPrev) && ( sc.state == SCE_CSS_IDENTIFIER || sc.state == SCE_CSS_IDENTIFIER2 || sc.state == SCE_CSS_IDENTIFIER3 || sc.state == SCE_CSS_EXTENDED_IDENTIFIER || sc.state == SCE_CSS_UNKNOWN_IDENTIFIER || sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_PSEUDOELEMENT || sc.state == SCE_CSS_EXTENDED_PSEUDOCLASS || sc.state == SCE_CSS_EXTENDED_PSEUDOELEMENT || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_IMPORTANT || sc.state == SCE_CSS_DIRECTIVE )) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); char *s2 = s; while (*s2 && !IsAWordChar(*s2)) s2++; switch (sc.state) { case SCE_CSS_IDENTIFIER: case SCE_CSS_IDENTIFIER2: case SCE_CSS_IDENTIFIER3: case SCE_CSS_EXTENDED_IDENTIFIER: case SCE_CSS_UNKNOWN_IDENTIFIER: if (css1Props.InList(s2)) sc.ChangeState(SCE_CSS_IDENTIFIER); else if (css2Props.InList(s2)) sc.ChangeState(SCE_CSS_IDENTIFIER2); else if (css3Props.InList(s2)) sc.ChangeState(SCE_CSS_IDENTIFIER3); else if (exProps.InList(s2)) sc.ChangeState(SCE_CSS_EXTENDED_IDENTIFIER); else sc.ChangeState(SCE_CSS_UNKNOWN_IDENTIFIER); break; case SCE_CSS_PSEUDOCLASS: case SCE_CSS_PSEUDOELEMENT: case SCE_CSS_EXTENDED_PSEUDOCLASS: case SCE_CSS_EXTENDED_PSEUDOELEMENT: case SCE_CSS_UNKNOWN_PSEUDOCLASS: if (op == ':' && opPrev != ':' && pseudoClasses.InList(s2)) sc.ChangeState(SCE_CSS_PSEUDOCLASS); else if (opPrev == ':' && pseudoElements.InList(s2)) sc.ChangeState(SCE_CSS_PSEUDOELEMENT); else if ((op == ':' || (op == '(' && lastState == SCE_CSS_EXTENDED_PSEUDOCLASS)) && opPrev != ':' && exPseudoClasses.InList(s2)) sc.ChangeState(SCE_CSS_EXTENDED_PSEUDOCLASS); else if (opPrev == ':' && exPseudoElements.InList(s2)) sc.ChangeState(SCE_CSS_EXTENDED_PSEUDOELEMENT); else sc.ChangeState(SCE_CSS_UNKNOWN_PSEUDOCLASS); break; case SCE_CSS_IMPORTANT: if (strcmp(s2, "important") != 0) sc.ChangeState(SCE_CSS_VALUE); break; case SCE_CSS_DIRECTIVE: if (op == '@' && strcmp(s2, "media") == 0) sc.ChangeState(SCE_CSS_MEDIA); break; } } if (sc.ch != '.' && sc.ch != ':' && sc.ch != '#' && ( sc.state == SCE_CSS_CLASS || sc.state == SCE_CSS_ID || (sc.ch != '(' && sc.ch != ')' && ( /* This line of the condition makes it possible to extend pseudo-classes with parentheses */ sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_PSEUDOELEMENT || sc.state == SCE_CSS_EXTENDED_PSEUDOCLASS || sc.state == SCE_CSS_EXTENDED_PSEUDOELEMENT || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS )) )) sc.SetState(SCE_CSS_TAG); if (sc.Match('/', '*')) { lastStateC = sc.state; comment_mode = eCommentBlock; sc.SetState(SCE_CSS_COMMENT); sc.Forward(); } else if (hasSingleLineComments && sc.Match('/', '/') && !insideParentheses) { // note that we've had to treat ([...]// as the start of a URL not a comment, e.g. url(http://example.com), url(//example.com) lastStateC = sc.state; comment_mode = eCommentLine; sc.SetState(SCE_CSS_COMMENT); sc.Forward(); } else if ((sc.state == SCE_CSS_VALUE || sc.state == SCE_CSS_ATTRIBUTE) && (sc.ch == '\"' || sc.ch == '\'')) { lastStateS = sc.state; sc.SetState((sc.ch == '\"' ? SCE_CSS_DOUBLESTRING : SCE_CSS_SINGLESTRING)); } else if (IsCssOperator(sc.ch) && (sc.state != SCE_CSS_ATTRIBUTE || sc.ch == ']') && (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!') && ((sc.state != SCE_CSS_DIRECTIVE && sc.state != SCE_CSS_MEDIA) || sc.ch == ';' || sc.ch == '{') ) { if (sc.state != SCE_CSS_OPERATOR) lastState = sc.state; sc.SetState(SCE_CSS_OPERATOR); op = sc.ch; opPrev = sc.chPrev; } } sc.Complete(); } static void FoldCSSDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; bool inComment = (styler.StyleAt(startPos-1) == SCE_CSS_COMMENT); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styler.StyleAt(i); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment) { if (!inComment && (style == SCE_CSS_COMMENT)) levelCurrent++; else if (inComment && (style != SCE_CSS_COMMENT)) levelCurrent--; inComment = (style == SCE_CSS_COMMENT); } if (style == SCE_CSS_OPERATOR) { if (ch == '{') { levelCurrent++; } else if (ch == '}') { levelCurrent--; } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const cssWordListDesc[] = { "CSS1 Properties", "Pseudo-classes", "CSS2 Properties", "CSS3 Properties", "Pseudo-elements", "Browser-Specific CSS Properties", "Browser-Specific Pseudo-classes", "Browser-Specific Pseudo-elements", 0 }; LexerModule lmCss(SCLEX_CSS, ColouriseCssDoc, "css", FoldCSSDoc, cssWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexBullant.cxx0000644000175000017500000001451611615412040021730 00000000000000// SciTE - Scintilla based Text Editor // LexBullant.cxx - lexer for Bullant #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static int classifyWordBullant(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) { char s[100]; s[0] = '\0'; for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { s[i] = static_cast(tolower(styler[start + i])); s[i + 1] = '\0'; } int lev= 0; char chAttr = SCE_C_IDENTIFIER; if (isdigit(s[0]) || (s[0] == '.')){ chAttr = SCE_C_NUMBER; } else { if (keywords.InList(s)) { chAttr = SCE_C_WORD; if (strcmp(s, "end") == 0) lev = -1; else if (strcmp(s, "method") == 0 || strcmp(s, "case") == 0 || strcmp(s, "class") == 0 || strcmp(s, "debug") == 0 || strcmp(s, "test") == 0 || strcmp(s, "if") == 0 || strcmp(s, "lock") == 0 || strcmp(s, "transaction") == 0 || strcmp(s, "trap") == 0 || strcmp(s, "until") == 0 || strcmp(s, "while") == 0) lev = 1; } } styler.ColourTo(end, chAttr); return lev; } static void ColouriseBullantDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; styler.StartAt(startPos); bool fold = styler.GetPropertyInt("fold") != 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; int state = initStyle; if (state == SCE_C_STRINGEOL) // Does not leak onto next line state = SCE_C_DEFAULT; char chPrev = ' '; char chNext = styler[startPos]; unsigned int lengthDoc = startPos + length; int visibleChars = 0; styler.StartSegment(startPos); int endFoundThisLine = 0; for (unsigned int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) // Avoid triggering two times on Dos/Win // End of line endFoundThisLine = 0; if (state == SCE_C_STRINGEOL) { styler.ColourTo(i, state); state = SCE_C_DEFAULT; } if (fold) { int lev = levelPrev; if (visibleChars == 0) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; styler.SetLevel(lineCurrent, lev); lineCurrent++; levelPrev = levelCurrent; } visibleChars = 0; /* int indentBlock = GetLineIndentation(lineCurrent); if (blockChange==1){ lineCurrent++; int pos=SetLineIndentation(lineCurrent, indentBlock + indentSize); } else if (blockChange==-1) { indentBlock -= indentSize; if (indentBlock < 0) indentBlock = 0; SetLineIndentation(lineCurrent, indentBlock); lineCurrent++; } blockChange=0; */ } if (!(isascii(ch) && isspace(ch))) visibleChars++; if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); chPrev = ' '; i += 1; continue; } if (state == SCE_C_DEFAULT) { if (iswordstart(ch)) { styler.ColourTo(i-1, state); state = SCE_C_IDENTIFIER; } else if (ch == '@' && chNext == 'o') { if ((styler.SafeGetCharAt(i+2) =='f') && (styler.SafeGetCharAt(i+3) == 'f')) { styler.ColourTo(i-1, state); state = SCE_C_COMMENT; } } else if (ch == '#') { styler.ColourTo(i-1, state); state = SCE_C_COMMENTLINE; } else if (ch == '\"') { styler.ColourTo(i-1, state); state = SCE_C_STRING; } else if (ch == '\'') { styler.ColourTo(i-1, state); state = SCE_C_CHARACTER; } else if (isoperator(ch)) { styler.ColourTo(i-1, state); styler.ColourTo(i, SCE_C_OPERATOR); } } else if (state == SCE_C_IDENTIFIER) { if (!iswordchar(ch)) { int levelChange = classifyWordBullant(styler.GetStartSegment(), i - 1, keywords, styler); state = SCE_C_DEFAULT; chNext = styler.SafeGetCharAt(i + 1); if (ch == '#') { state = SCE_C_COMMENTLINE; } else if (ch == '\"') { state = SCE_C_STRING; } else if (ch == '\'') { state = SCE_C_CHARACTER; } else if (isoperator(ch)) { styler.ColourTo(i, SCE_C_OPERATOR); } if (endFoundThisLine == 0) levelCurrent+=levelChange; if (levelChange == -1) endFoundThisLine=1; } } else if (state == SCE_C_COMMENT) { if (ch == '@' && chNext == 'o') { if (styler.SafeGetCharAt(i+2) == 'n') { styler.ColourTo(i+2, state); state = SCE_C_DEFAULT; i+=2; } } } else if (state == SCE_C_COMMENTLINE) { if (ch == '\r' || ch == '\n') { endFoundThisLine = 0; styler.ColourTo(i-1, state); state = SCE_C_DEFAULT; } } else if (state == SCE_C_STRING) { if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; ch = chNext; chNext = styler.SafeGetCharAt(i + 1); } } else if (ch == '\"') { styler.ColourTo(i, state); state = SCE_C_DEFAULT; } else if (chNext == '\r' || chNext == '\n') { endFoundThisLine = 0; styler.ColourTo(i-1, SCE_C_STRINGEOL); state = SCE_C_STRINGEOL; } } else if (state == SCE_C_CHARACTER) { if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) { endFoundThisLine = 0; styler.ColourTo(i-1, SCE_C_STRINGEOL); state = SCE_C_STRINGEOL; } else if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; ch = chNext; chNext = styler.SafeGetCharAt(i + 1); } } else if (ch == '\'') { styler.ColourTo(i, state); state = SCE_C_DEFAULT; } } chPrev = ch; } styler.ColourTo(lengthDoc - 1, state); // Fill in the real level of the next line, keeping the current flags as they will be filled in later if (fold) { int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; //styler.SetLevel(lineCurrent, levelCurrent | flagsNext); styler.SetLevel(lineCurrent, levelPrev | flagsNext); } } static const char * const bullantWordListDesc[] = { "Keywords", 0 }; LexerModule lmBullant(SCLEX_BULLANT, ColouriseBullantDoc, "bullant", 0, bullantWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexCsound.cxx0000644000175000017500000001427511615412040021564 00000000000000// Scintilla source code edit control /** @file LexCsound.cxx ** Lexer for Csound (Orchestra & Score) ** Written by Georg Ritter - **/ // Copyright 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '?'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.' || ch == '%' || ch == '@' || ch == '$' || ch == '?'); } static inline bool IsCsoundOperator(char ch) { if (isascii(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || ch == '(' || ch == ')' || ch == '=' || ch == '^' || ch == '[' || ch == ']' || ch == '<' || ch == '&' || ch == '>' || ch == ',' || ch == '|' || ch == '~' || ch == '%' || ch == ':') return true; return false; } static void ColouriseCsoundDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &opcode = *keywordlists[0]; WordList &headerStmt = *keywordlists[1]; WordList &otherKeyword = *keywordlists[2]; // Do not leak onto next line if (initStyle == SCE_CSOUND_STRINGEOL) initStyle = SCE_CSOUND_DEFAULT; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Handle line continuation generically. if (sc.ch == '\\') { if (sc.chNext == '\n' || sc.chNext == '\r') { sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } continue; } } // Determine if the current state should terminate. if (sc.state == SCE_CSOUND_OPERATOR) { if (!IsCsoundOperator(static_cast(sc.ch))) { sc.SetState(SCE_CSOUND_DEFAULT); } }else if (sc.state == SCE_CSOUND_NUMBER) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_CSOUND_DEFAULT); } } else if (sc.state == SCE_CSOUND_IDENTIFIER) { if (!IsAWordChar(sc.ch) ) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (opcode.InList(s)) { sc.ChangeState(SCE_CSOUND_OPCODE); } else if (headerStmt.InList(s)) { sc.ChangeState(SCE_CSOUND_HEADERSTMT); } else if (otherKeyword.InList(s)) { sc.ChangeState(SCE_CSOUND_USERKEYWORD); } else if (s[0] == 'p') { sc.ChangeState(SCE_CSOUND_PARAM); } else if (s[0] == 'a') { sc.ChangeState(SCE_CSOUND_ARATE_VAR); } else if (s[0] == 'k') { sc.ChangeState(SCE_CSOUND_KRATE_VAR); } else if (s[0] == 'i') { // covers both i-rate variables and i-statements sc.ChangeState(SCE_CSOUND_IRATE_VAR); } else if (s[0] == 'g') { sc.ChangeState(SCE_CSOUND_GLOBAL_VAR); } sc.SetState(SCE_CSOUND_DEFAULT); } } else if (sc.state == SCE_CSOUND_COMMENT ) { if (sc.atLineEnd) { sc.SetState(SCE_CSOUND_DEFAULT); } } else if ((sc.state == SCE_CSOUND_ARATE_VAR) || (sc.state == SCE_CSOUND_KRATE_VAR) || (sc.state == SCE_CSOUND_IRATE_VAR)) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_CSOUND_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_CSOUND_DEFAULT) { if (sc.ch == ';'){ sc.SetState(SCE_CSOUND_COMMENT); } else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) { sc.SetState(SCE_CSOUND_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_CSOUND_IDENTIFIER); } else if (IsCsoundOperator(static_cast(sc.ch))) { sc.SetState(SCE_CSOUND_OPERATOR); } else if (sc.ch == 'p') { sc.SetState(SCE_CSOUND_PARAM); } else if (sc.ch == 'a') { sc.SetState(SCE_CSOUND_ARATE_VAR); } else if (sc.ch == 'k') { sc.SetState(SCE_CSOUND_KRATE_VAR); } else if (sc.ch == 'i') { // covers both i-rate variables and i-statements sc.SetState(SCE_CSOUND_IRATE_VAR); } else if (sc.ch == 'g') { sc.SetState(SCE_CSOUND_GLOBAL_VAR); } } } sc.Complete(); } static void FoldCsoundInstruments(unsigned int startPos, int length, int /* initStyle */, WordList *[], Accessor &styler) { unsigned int lengthDoc = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int stylePrev = 0; int styleNext = styler.StyleAt(startPos); for (unsigned int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if ((stylePrev != SCE_CSOUND_OPCODE) && (style == SCE_CSOUND_OPCODE)) { char s[20]; unsigned int j = 0; while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) { s[j] = styler[i + j]; j++; } s[j] = '\0'; if (strcmp(s, "instr") == 0) levelCurrent++; if (strcmp(s, "endin") == 0) levelCurrent--; } if (atEOL) { int lev = levelPrev; if (visibleChars == 0) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; stylePrev = style; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const csoundWordListDesc[] = { "Opcodes", "Header Statements", "User keywords", 0 }; LexerModule lmCsound(SCLEX_CSOUND, ColouriseCsoundDoc, "csound", FoldCsoundInstruments, csoundWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexCaml.cxx0000644000175000017500000003375011615412040021204 00000000000000// Scintilla source code edit control /** @file LexCaml.cxx ** Lexer for Objective Caml. **/ // Copyright 2005-2009 by Robert Roessler // The License.txt file describes the conditions under which this software may be distributed. /* Release History 20050204 Initial release. 20050205 Quick compiler standards/"cleanliness" adjustment. 20050206 Added cast for IsLeadByte(). 20050209 Changes to "external" build support. 20050306 Fix for 1st-char-in-doc "corner" case. 20050502 Fix for [harmless] one-past-the-end coloring. 20050515 Refined numeric token recognition logic. 20051125 Added 2nd "optional" keywords class. 20051129 Support "magic" (read-only) comments for RCaml. 20051204 Swtich to using StyleContext infrastructure. 20090629 Add full Standard ML '97 support. */ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "PropSetSimple.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" // Since the Microsoft __iscsym[f] funcs are not ANSI... inline int iscaml(int c) {return isalnum(c) || c == '_';} inline int iscamlf(int c) {return isalpha(c) || c == '_';} static const int baseT[24] = { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A - L */ 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0,16 /* M - X */ }; #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #ifdef BUILD_AS_EXTERNAL_LEXER /* (actually seems to work!) */ #include #include "WindowAccessor.h" #include "ExternalLexer.h" #undef EXT_LEXER_DECL #define EXT_LEXER_DECL __declspec( dllexport ) __stdcall #if PLAT_WIN #include #endif static void ColouriseCamlDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler); static void FoldCamlDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler); static void InternalLexOrFold(int lexOrFold, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props); static const char* LexerName = "caml"; #ifdef TRACE void Platform::DebugPrintf(const char *format, ...) { char buffer[2000]; va_list pArguments; va_start(pArguments, format); vsprintf(buffer,format,pArguments); va_end(pArguments); Platform::DebugDisplay(buffer); } #else void Platform::DebugPrintf(const char *, ...) { } #endif bool Platform::IsDBCSLeadByte(int codePage, char ch) { return ::IsDBCSLeadByteEx(codePage, ch) != 0; } long Platform::SendScintilla(WindowID w, unsigned int msg, unsigned long wParam, long lParam) { return ::SendMessage(reinterpret_cast(w), msg, wParam, lParam); } long Platform::SendScintillaPointer(WindowID w, unsigned int msg, unsigned long wParam, void *lParam) { return ::SendMessage(reinterpret_cast(w), msg, wParam, reinterpret_cast(lParam)); } void EXT_LEXER_DECL Fold(unsigned int lexer, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props) { // below useless evaluation(s) to supress "not used" warnings lexer; // build expected data structures and do the Fold InternalLexOrFold(1, startPos, length, initStyle, words, window, props); } int EXT_LEXER_DECL GetLexerCount() { return 1; // just us [Objective] Caml lexers here! } void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int buflength) { // below useless evaluation(s) to supress "not used" warnings Index; // return as much of our lexer name as will fit (what's up with Index?) if (buflength > 0) { buflength--; int n = strlen(LexerName); if (n > buflength) n = buflength; memcpy(name, LexerName, n), name[n] = '\0'; } } void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props) { // below useless evaluation(s) to supress "not used" warnings lexer; // build expected data structures and do the Lex InternalLexOrFold(0, startPos, length, initStyle, words, window, props); } static void InternalLexOrFold(int foldOrLex, unsigned int startPos, int length, int initStyle, char *words[], WindowID window, char *props) { // create and initialize a WindowAccessor (including contained PropSet) PropSetSimple ps; ps.SetMultiple(props); WindowAccessor wa(window, ps); // create and initialize WordList(s) int nWL = 0; for (; words[nWL]; nWL++) ; // count # of WordList PTRs needed WordList** wl = new WordList* [nWL + 1];// alloc WordList PTRs int i = 0; for (; i < nWL; i++) { wl[i] = new WordList(); // (works or THROWS bad_alloc EXCEPTION) wl[i]->Set(words[i]); } wl[i] = 0; // call our "internal" folder/lexer (... then do Flush!) if (foldOrLex) FoldCamlDoc(startPos, length, initStyle, wl, wa); else ColouriseCamlDoc(startPos, length, initStyle, wl, wa); wa.Flush(); // clean up before leaving for (i = nWL - 1; i >= 0; i--) delete wl[i]; delete [] wl; } static #endif /* BUILD_AS_EXTERNAL_LEXER */ void ColouriseCamlDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { // initialize styler StyleContext sc(startPos, length, initStyle, styler); int chBase = 0, chToken = 0, chLit = 0; WordList& keywords = *keywordlists[0]; WordList& keywords2 = *keywordlists[1]; WordList& keywords3 = *keywordlists[2]; const bool isSML = keywords.InList("andalso"); const int useMagic = styler.GetPropertyInt("lexer.caml.magic", 0); // set up [initial] state info (terminating states that shouldn't "bleed") const int state_ = sc.state & 0x0f; if (state_ <= SCE_CAML_CHAR || (isSML && state_ == SCE_CAML_STRING)) sc.state = SCE_CAML_DEFAULT; int nesting = (state_ >= SCE_CAML_COMMENT)? (state_ - SCE_CAML_COMMENT): 0; // foreach char in range... while (sc.More()) { // set up [per-char] state info int state2 = -1; // (ASSUME no state change) int chColor = sc.currentPos - 1;// (ASSUME standard coloring range) bool advance = true; // (ASSUME scanner "eats" 1 char) // step state machine switch (sc.state & 0x0f) { case SCE_CAML_DEFAULT: chToken = sc.currentPos; // save [possible] token start (JIC) // it's wide open; what do we have? if (iscamlf(sc.ch)) state2 = SCE_CAML_IDENTIFIER; else if (!isSML && sc.Match('`') && iscamlf(sc.chNext)) state2 = SCE_CAML_TAGNAME; else if (!isSML && sc.Match('#') && isdigit(sc.chNext)) state2 = SCE_CAML_LINENUM; else if (isdigit(sc.ch)) { // it's a number, assume base 10 state2 = SCE_CAML_NUMBER, chBase = 10; if (sc.Match('0')) { // there MAY be a base specified... const char* baseC = "bBoOxX"; if (isSML) { if (sc.chNext == 'w') sc.Forward(); // (consume SML "word" indicator) baseC = "x"; } // ... change to specified base AS REQUIRED if (strchr(baseC, sc.chNext)) chBase = baseT[tolower(sc.chNext) - 'a'], sc.Forward(); } } else if (!isSML && sc.Match('\'')) // (Caml char literal?) state2 = SCE_CAML_CHAR, chLit = 0; else if (isSML && sc.Match('#', '"')) // (SML char literal?) state2 = SCE_CAML_CHAR, sc.Forward(); else if (sc.Match('"')) state2 = SCE_CAML_STRING; else if (sc.Match('(', '*')) state2 = SCE_CAML_COMMENT, sc.Forward(), sc.ch = ' '; // (*)... else if (strchr("!?~" /* Caml "prefix-symbol" */ "=<>@^|&+-*/$%" /* Caml "infix-symbol" */ "()[]{};,:.#", sc.ch) // Caml "bracket" or ;,:.# // SML "extra" ident chars || (isSML && (sc.Match('\\') || sc.Match('`')))) state2 = SCE_CAML_OPERATOR; break; case SCE_CAML_IDENTIFIER: // [try to] interpret as [additional] identifier char if (!(iscaml(sc.ch) || sc.Match('\''))) { const int n = sc.currentPos - chToken; if (n < 24) { // length is believable as keyword, [re-]construct token char t[24]; for (int i = -n; i < 0; i++) t[n + i] = static_cast(sc.GetRelative(i)); t[n] = '\0'; // special-case "_" token as KEYWORD if ((n == 1 && sc.chPrev == '_') || keywords.InList(t)) sc.ChangeState(SCE_CAML_KEYWORD); else if (keywords2.InList(t)) sc.ChangeState(SCE_CAML_KEYWORD2); else if (keywords3.InList(t)) sc.ChangeState(SCE_CAML_KEYWORD3); } state2 = SCE_CAML_DEFAULT, advance = false; } break; case SCE_CAML_TAGNAME: // [try to] interpret as [additional] tagname char if (!(iscaml(sc.ch) || sc.Match('\''))) state2 = SCE_CAML_DEFAULT, advance = false; break; /*case SCE_CAML_KEYWORD: case SCE_CAML_KEYWORD2: case SCE_CAML_KEYWORD3: // [try to] interpret as [additional] keyword char if (!iscaml(ch)) state2 = SCE_CAML_DEFAULT, advance = false; break;*/ case SCE_CAML_LINENUM: // [try to] interpret as [additional] linenum directive char if (!isdigit(sc.ch)) state2 = SCE_CAML_DEFAULT, advance = false; break; case SCE_CAML_OPERATOR: { // [try to] interpret as [additional] operator char const char* o = 0; if (iscaml(sc.ch) || isspace(sc.ch) // ident or whitespace || (o = strchr(")]};,\'\"#", sc.ch),o) // "termination" chars || (!isSML && sc.Match('`')) // Caml extra term char || (!strchr("!$%&*+-./:<=>?@^|~", sc.ch)// "operator" chars // SML extra ident chars && !(isSML && (sc.Match('\\') || sc.Match('`'))))) { // check for INCLUSIVE termination if (o && strchr(")]};,", sc.ch)) { if ((sc.Match(')') && sc.chPrev == '(') || (sc.Match(']') && sc.chPrev == '[')) // special-case "()" and "[]" tokens as KEYWORDS sc.ChangeState(SCE_CAML_KEYWORD); chColor++; } else advance = false; state2 = SCE_CAML_DEFAULT; } break; } case SCE_CAML_NUMBER: // [try to] interpret as [additional] numeric literal char if ((!isSML && sc.Match('_')) || IsADigit(sc.ch, chBase)) break; // how about an integer suffix? if (!isSML && (sc.Match('l') || sc.Match('L') || sc.Match('n')) && (sc.chPrev == '_' || IsADigit(sc.chPrev, chBase))) break; // or a floating-point literal? if (chBase == 10) { // with a decimal point? if (sc.Match('.') && ((!isSML && sc.chPrev == '_') || IsADigit(sc.chPrev, chBase))) break; // with an exponent? (I) if ((sc.Match('e') || sc.Match('E')) && ((!isSML && (sc.chPrev == '.' || sc.chPrev == '_')) || IsADigit(sc.chPrev, chBase))) break; // with an exponent? (II) if (((!isSML && (sc.Match('+') || sc.Match('-'))) || (isSML && sc.Match('~'))) && (sc.chPrev == 'e' || sc.chPrev == 'E')) break; } // it looks like we have run out of number state2 = SCE_CAML_DEFAULT, advance = false; break; case SCE_CAML_CHAR: if (!isSML) { // [try to] interpret as [additional] char literal char if (sc.Match('\\')) { chLit = 1; // (definitely IS a char literal) if (sc.chPrev == '\\') sc.ch = ' '; // (...\\') // should we be terminating - one way or another? } else if ((sc.Match('\'') && sc.chPrev != '\\') || sc.atLineEnd) { state2 = SCE_CAML_DEFAULT; if (sc.Match('\'')) chColor++; else sc.ChangeState(SCE_CAML_IDENTIFIER); // ... maybe a char literal, maybe not } else if (chLit < 1 && sc.currentPos - chToken >= 2) sc.ChangeState(SCE_CAML_IDENTIFIER), advance = false; break; }/* else // fall through for SML char literal (handle like string) */ case SCE_CAML_STRING: // [try to] interpret as [additional] [SML char/] string literal char if (isSML && sc.Match('\\') && sc.chPrev != '\\' && isspace(sc.chNext)) state2 = SCE_CAML_WHITE; else if (sc.Match('\\') && sc.chPrev == '\\') sc.ch = ' '; // (...\\") // should we be terminating - one way or another? else if ((sc.Match('"') && sc.chPrev != '\\') || (isSML && sc.atLineEnd)) { state2 = SCE_CAML_DEFAULT; if (sc.Match('"')) chColor++; } break; case SCE_CAML_WHITE: // [try to] interpret as [additional] SML embedded whitespace char if (sc.Match('\\')) { // style this puppy NOW... state2 = SCE_CAML_STRING, sc.ch = ' ' /* (...\") */, chColor++, styler.ColourTo(chColor, SCE_CAML_WHITE), styler.Flush(); // ... then backtrack to determine original SML literal type int p = chColor - 2; for (; p >= 0 && styler.StyleAt(p) == SCE_CAML_WHITE; p--) ; if (p >= 0) state2 = static_cast(styler.StyleAt(p)); // take care of state change NOW sc.ChangeState(state2), state2 = -1; } break; case SCE_CAML_COMMENT: case SCE_CAML_COMMENT1: case SCE_CAML_COMMENT2: case SCE_CAML_COMMENT3: // we're IN a comment - does this start a NESTED comment? if (sc.Match('(', '*')) state2 = sc.state + 1, chToken = sc.currentPos, sc.Forward(), sc.ch = ' ' /* (*)... */, nesting++; // [try to] interpret as [additional] comment char else if (sc.Match(')') && sc.chPrev == '*') { if (nesting) state2 = (sc.state & 0x0f) - 1, chToken = 0, nesting--; else state2 = SCE_CAML_DEFAULT; chColor++; // enable "magic" (read-only) comment AS REQUIRED } else if (useMagic && sc.currentPos - chToken == 4 && sc.Match('c') && sc.chPrev == 'r' && sc.GetRelative(-2) == '@') sc.state |= 0x10; // (switch to read-only comment style) break; } // handle state change and char coloring AS REQUIRED if (state2 >= 0) styler.ColourTo(chColor, sc.state), sc.ChangeState(state2); // move to next char UNLESS re-scanning current char if (advance) sc.Forward(); } // do any required terminal char coloring (JIC) sc.Complete(); } #ifdef BUILD_AS_EXTERNAL_LEXER static #endif /* BUILD_AS_EXTERNAL_LEXER */ void FoldCamlDoc( unsigned int, int, int, WordList *[], Accessor &) { } static const char * const camlWordListDesc[] = { "Keywords", // primary Objective Caml keywords "Keywords2", // "optional" keywords (typically from Pervasives) "Keywords3", // "optional" keywords (typically typenames) 0 }; #ifndef BUILD_AS_EXTERNAL_LEXER LexerModule lmCaml(SCLEX_CAML, ColouriseCamlDoc, "caml", FoldCamlDoc, camlWordListDesc); #endif /* BUILD_AS_EXTERNAL_LEXER */ presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexVisualProlog.cxx0000644000175000017500000004112711763437013022766 00000000000000// Scintilla source code edit control /** @file LexVisualProlog.cxx ** Lexer for Visual Prolog. **/ // Author Thomas Linder Puls, Prolog Development Denter A/S, http://www.visual-prolog.com // Based on Lexer for C++, C, Java, and JavaScript. // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable: 4786) #endif #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #include "OptionSet.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Options used for LexerVisualProlog struct OptionsVisualProlog { OptionsVisualProlog() { } }; static const char *const visualPrologWordLists[] = { "Major keywords (class, predicates, ...)", "Minor keywords (if, then, try, ...)", "Directive keywords without the '#' (include, requires, ...)", "Documentation keywords without the '@' (short, detail, ...)", 0, }; struct OptionSetVisualProlog : public OptionSet { OptionSetVisualProlog() { DefineWordListSets(visualPrologWordLists); } }; class LexerVisualProlog : public ILexer { WordList majorKeywords; WordList minorKeywords; WordList directiveKeywords; WordList docKeywords; OptionsVisualProlog options; OptionSetVisualProlog osVisualProlog; public: LexerVisualProlog() { } virtual ~LexerVisualProlog() { } void SCI_METHOD Release() { delete this; } int SCI_METHOD Version() const { return lvOriginal; } const char * SCI_METHOD PropertyNames() { return osVisualProlog.PropertyNames(); } int SCI_METHOD PropertyType(const char *name) { return osVisualProlog.PropertyType(name); } const char * SCI_METHOD DescribeProperty(const char *name) { return osVisualProlog.DescribeProperty(name); } int SCI_METHOD PropertySet(const char *key, const char *val); const char * SCI_METHOD DescribeWordListSets() { return osVisualProlog.DescribeWordListSets(); } int SCI_METHOD WordListSet(int n, const char *wl); void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess); void * SCI_METHOD PrivateCall(int, void *) { return 0; } static ILexer *LexerFactoryVisualProlog() { return new LexerVisualProlog(); } }; int SCI_METHOD LexerVisualProlog::PropertySet(const char *key, const char *val) { if (osVisualProlog.PropertySet(&options, key, val)) { return 0; } return -1; } int SCI_METHOD LexerVisualProlog::WordListSet(int n, const char *wl) { WordList *wordListN = 0; switch (n) { case 0: wordListN = &majorKeywords; break; case 1: wordListN = &minorKeywords; break; case 2: wordListN = &directiveKeywords; break; case 3: wordListN = &docKeywords; break; } int firstModification = -1; if (wordListN) { WordList wlNew; wlNew.Set(wl); if (*wordListN != wlNew) { wordListN->Set(wl); firstModification = 0; } } return firstModification; } // Functor used to truncate history struct After { int line; After(int line_) : line(line_) {} }; // Look ahead to see which colour "end" should have (takes colour after the following keyword) static void endLookAhead(char s[], LexAccessor &styler, int start, CharacterSet &setIdentifier) { char ch = styler.SafeGetCharAt(start, '\n'); while (' ' == ch) { start++; ch = styler.SafeGetCharAt(start, '\n'); } int i = 0; while (i < 100 && setIdentifier.Contains(ch)){ s[i] = ch; i++; ch = styler.SafeGetCharAt(start + i, '\n'); } s[i] = '\0'; } static void forwardEscapeLiteral(StyleContext &sc, int OwnChar, int EscapeState) { sc.Forward(); if (sc.ch == OwnChar || sc.ch == '\\' || sc.ch == 'n' || sc.ch == 'l' || sc.ch == 'r' || sc.ch == 't') { sc.ChangeState(EscapeState); } else if (sc.ch == 'u') { if (IsADigit(sc.chNext, 16)) { sc.Forward(); if (IsADigit(sc.chNext, 16)) { sc.Forward(); if (IsADigit(sc.chNext, 16)) { sc.Forward(); if (IsADigit(sc.chNext, 16)) { sc.Forward(); sc.ChangeState(EscapeState); } } } } } } void SCI_METHOD LexerVisualProlog::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]"); CharacterSet setLowerStart(CharacterSet::setLower); CharacterSet setVariableStart(CharacterSet::setUpper); CharacterSet setIdentifier(CharacterSet::setAlphaNum, "_", 0x80, true); int styleBeforeDocKeyword = SCE_VISUALPROLOG_DEFAULT; int currentLine = styler.GetLine(startPos); int nestLevel = 0; if (currentLine >= 1) { nestLevel = styler.GetLineState(currentLine - 1); } StyleContext sc(startPos, length, initStyle, styler, 0x7f); // Truncate ppDefineHistory before current line for (; sc.More(); sc.Forward()) { if (sc.atLineEnd) { // Update the line state, so it can be seen by next line styler.SetLineState(currentLine, nestLevel); currentLine++; } if (sc.atLineStart) { if ((sc.state == SCE_VISUALPROLOG_STRING) || (sc.state == SCE_VISUALPROLOG_CHARACTER)) { // Prevent SCE_VISUALPROLOG_STRING_EOL from leaking back to previous line which // ends with a line continuation by locking in the state upto this position. sc.SetState(sc.state); } } const bool atLineEndBeforeSwitch = sc.atLineEnd; // Determine if the current state should terminate. switch (sc.state) { case SCE_VISUALPROLOG_OPERATOR: sc.SetState(SCE_VISUALPROLOG_DEFAULT); break; case SCE_VISUALPROLOG_NUMBER: // We accept almost anything because of hex. and number suffixes if (!(setIdentifier.Contains(sc.ch) || (sc.ch == '.') || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) { sc.SetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_IDENTIFIER: if (!setIdentifier.Contains(sc.ch)) { char s[1000]; sc.GetCurrent(s, sizeof(s)); if (0 == strcmp(s, "end")) { endLookAhead(s, styler, sc.currentPos, setIdentifier); } if (majorKeywords.InList(s)) { sc.ChangeState(SCE_VISUALPROLOG_KEY_MAJOR); } else if (minorKeywords.InList(s)) { sc.ChangeState(SCE_VISUALPROLOG_KEY_MINOR); } sc.SetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_VARIABLE: case SCE_VISUALPROLOG_ANONYMOUS: if (!setIdentifier.Contains(sc.ch)) { sc.SetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_KEY_DIRECTIVE: if (!setLowerStart.Contains(sc.ch)) { char s[1000]; sc.GetCurrent(s, sizeof(s)); if (!directiveKeywords.InList(s+1)) { sc.ChangeState(SCE_VISUALPROLOG_IDENTIFIER); } sc.SetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_COMMENT_BLOCK: if (sc.Match('*', '/')) { sc.Forward(); nestLevel--; int nextState = (nestLevel == 0) ? SCE_VISUALPROLOG_DEFAULT : SCE_VISUALPROLOG_COMMENT_BLOCK; sc.ForwardSetState(nextState); } else if (sc.Match('/', '*')) { sc.Forward(); nestLevel++; } else if (sc.ch == '%') { sc.SetState(SCE_VISUALPROLOG_COMMENT_LINE); } else if (sc.ch == '@') { styleBeforeDocKeyword = sc.state; sc.SetState(SCE_VISUALPROLOG_COMMENT_KEY_ERROR); } break; case SCE_VISUALPROLOG_COMMENT_LINE: if (sc.atLineEnd) { int nextState = (nestLevel == 0) ? SCE_VISUALPROLOG_DEFAULT : SCE_VISUALPROLOG_COMMENT_BLOCK; sc.SetState(nextState); } else if (sc.ch == '@') { styleBeforeDocKeyword = sc.state; sc.SetState(SCE_VISUALPROLOG_COMMENT_KEY_ERROR); } break; case SCE_VISUALPROLOG_COMMENT_KEY_ERROR: if (!setDoxygen.Contains(sc.ch)) { char s[1000]; sc.GetCurrent(s, sizeof(s)); if (docKeywords.InList(s+1)) { sc.ChangeState(SCE_VISUALPROLOG_COMMENT_KEY); } sc.SetState(styleBeforeDocKeyword); } if (SCE_VISUALPROLOG_COMMENT_LINE == styleBeforeDocKeyword && sc.atLineStart) { sc.SetState(SCE_VISUALPROLOG_DEFAULT); } else if (SCE_VISUALPROLOG_COMMENT_BLOCK == styleBeforeDocKeyword && sc.atLineStart) { sc.SetState(SCE_VISUALPROLOG_COMMENT_BLOCK); } break; case SCE_VISUALPROLOG_STRING_ESCAPE: case SCE_VISUALPROLOG_STRING_ESCAPE_ERROR: // return to SCE_VISUALPROLOG_STRING and treat as such (fall-through) sc.SetState(SCE_VISUALPROLOG_STRING); case SCE_VISUALPROLOG_STRING: if (sc.atLineEnd) { sc.SetState(SCE_VISUALPROLOG_STRING_EOL_OPEN); } else if (sc.ch == '"') { sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); } else if (sc.ch == '\\') { sc.SetState(SCE_VISUALPROLOG_STRING_ESCAPE_ERROR); forwardEscapeLiteral(sc, '"', SCE_VISUALPROLOG_STRING_ESCAPE); } break; case SCE_VISUALPROLOG_CHARACTER_TOO_MANY: if (sc.atLineStart) { sc.SetState(SCE_VISUALPROLOG_DEFAULT); } else if (sc.ch == '\'') { sc.SetState(SCE_VISUALPROLOG_CHARACTER); sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_CHARACTER: if (sc.atLineEnd) { sc.SetState(SCE_VISUALPROLOG_STRING_EOL_OPEN); // reuse STRING_EOL_OPEN for this } else if (sc.ch == '\'') { sc.SetState(SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR); sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); } else { if (sc.ch == '\\') { sc.SetState(SCE_VISUALPROLOG_CHARACTER_ESCAPE_ERROR); forwardEscapeLiteral(sc, '\'', SCE_VISUALPROLOG_CHARACTER); } sc.ForwardSetState(SCE_VISUALPROLOG_CHARACTER); if (sc.ch == '\'') { sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); } else { sc.SetState(SCE_VISUALPROLOG_CHARACTER_TOO_MANY); } } break; case SCE_VISUALPROLOG_STRING_EOL_OPEN: if (sc.atLineStart) { sc.SetState(SCE_VISUALPROLOG_DEFAULT); } break; case SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL: case SCE_VISUALPROLOG_STRING_VERBATIM_EOL: // return to SCE_VISUALPROLOG_STRING_VERBATIM and treat as such (fall-through) sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM); case SCE_VISUALPROLOG_STRING_VERBATIM: if (sc.atLineEnd) { sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM_EOL); } else if (sc.ch == '\"') { if (sc.chNext == '\"') { sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM_SPECIAL); sc.Forward(); } else { sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); } } break; } if (sc.atLineEnd && !atLineEndBeforeSwitch) { // State exit processing consumed characters up to end of line. currentLine++; } // Determine if a new state should be entered. if (sc.state == SCE_VISUALPROLOG_DEFAULT) { if (sc.Match('@', '\"')) { sc.SetState(SCE_VISUALPROLOG_STRING_VERBATIM); sc.Forward(); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_VISUALPROLOG_NUMBER); } else if (setLowerStart.Contains(sc.ch)) { sc.SetState(SCE_VISUALPROLOG_IDENTIFIER); } else if (setVariableStart.Contains(sc.ch)) { sc.SetState(SCE_VISUALPROLOG_VARIABLE); } else if (sc.ch == '_') { sc.SetState(SCE_VISUALPROLOG_ANONYMOUS); } else if (sc.Match('/', '*')) { sc.SetState(SCE_VISUALPROLOG_COMMENT_BLOCK); nestLevel = 1; sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.ch == '%') { sc.SetState(SCE_VISUALPROLOG_COMMENT_LINE); } else if (sc.ch == '\"') { sc.SetState(SCE_VISUALPROLOG_STRING); } else if (sc.ch == '\'') { sc.SetState(SCE_VISUALPROLOG_CHARACTER); } else if (sc.ch == '#') { sc.SetState(SCE_VISUALPROLOG_KEY_DIRECTIVE); } else if (isoperator(static_cast(sc.ch)) || sc.ch == '\\') { sc.SetState(SCE_VISUALPROLOG_OPERATOR); } } } sc.Complete(); styler.Flush(); } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". void SCI_METHOD LexerVisualProlog::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) { LexAccessor styler(pAccess); unsigned int endPos = startPos + length; int visibleChars = 0; int currentLine = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (currentLine > 0) levelCurrent = styler.LevelAt(currentLine-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_VISUALPROLOG_OPERATOR) { if (ch == '{') { // Measure the minimum before a '{' to allow // folding on "} else {" if (levelMinCurrent > levelNext) { levelMinCurrent = levelNext; } levelNext++; } else if (ch == '}') { levelNext--; } } if (!IsASpace(ch)) visibleChars++; if (atEOL || (i == endPos-1)) { int levelUse = levelCurrent; int lev = levelUse | levelNext << 16; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(currentLine)) { styler.SetLevel(currentLine, lev); } currentLine++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; if (atEOL && (i == static_cast(styler.Length()-1))) { // There is an empty line at end of file so give it same level and empty styler.SetLevel(currentLine, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG); } visibleChars = 0; } } } LexerModule lmVisualProlog(SCLEX_VISUALPROLOG, LexerVisualProlog::LexerFactoryVisualProlog, "visualprolog", visualPrologWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexLisp.cxx0000644000175000017500000002014411615412040021230 00000000000000// Scintilla source code edit control /** @file LexLisp.cxx ** Lexer for Lisp. ** Written by Alexey Yutkin. **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #define SCE_LISP_CHARACTER 29 #define SCE_LISP_MACRO 30 #define SCE_LISP_MACRO_DISPATCH 31 static inline bool isLispoperator(char ch) { if (isascii(ch) && isalnum(ch)) return false; if (ch == '\'' || ch == '`' || ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '{' || ch == '}') return true; return false; } static inline bool isLispwordstart(char ch) { return isascii(ch) && ch != ';' && !isspacechar(ch) && !isLispoperator(ch) && ch != '\n' && ch != '\r' && ch != '\"'; } static void classifyWordLisp(unsigned int start, unsigned int end, WordList &keywords, WordList &keywords_kw, Accessor &styler) { assert(end >= start); char s[100]; unsigned int i; bool digit_flag = true; for (i = 0; (i < end - start + 1) && (i < 99); i++) { s[i] = styler[start + i]; s[i + 1] = '\0'; if (!isdigit(s[i]) && (s[i] != '.')) digit_flag = false; } char chAttr = SCE_LISP_IDENTIFIER; if(digit_flag) chAttr = SCE_LISP_NUMBER; else { if (keywords.InList(s)) { chAttr = SCE_LISP_KEYWORD; } else if (keywords_kw.InList(s)) { chAttr = SCE_LISP_KEYWORD_KW; } else if ((s[0] == '*' && s[i-1] == '*') || (s[0] == '+' && s[i-1] == '+')) { chAttr = SCE_LISP_SPECIAL; } } styler.ColourTo(end, chAttr); return; } static void ColouriseLispDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords_kw = *keywordlists[1]; styler.StartAt(startPos); int state = initStyle, radix = -1; char chNext = styler[startPos]; unsigned int lengthDoc = startPos + length; styler.StartSegment(startPos); for (unsigned int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); i += 1; continue; } if (state == SCE_LISP_DEFAULT) { if (ch == '#') { styler.ColourTo(i - 1, state); radix = -1; state = SCE_LISP_MACRO_DISPATCH; } else if (ch == ':' && isLispwordstart(chNext)) { styler.ColourTo(i - 1, state); state = SCE_LISP_SYMBOL; } else if (isLispwordstart(ch)) { styler.ColourTo(i - 1, state); state = SCE_LISP_IDENTIFIER; } else if (ch == ';') { styler.ColourTo(i - 1, state); state = SCE_LISP_COMMENT; } else if (isLispoperator(ch) || ch=='\'') { styler.ColourTo(i - 1, state); styler.ColourTo(i, SCE_LISP_OPERATOR); if (ch=='\'' && isLispwordstart(chNext)) { state = SCE_LISP_SYMBOL; } } else if (ch == '\"') { styler.ColourTo(i - 1, state); state = SCE_LISP_STRING; } } else if (state == SCE_LISP_IDENTIFIER || state == SCE_LISP_SYMBOL) { if (!isLispwordstart(ch)) { if (state == SCE_LISP_IDENTIFIER) { classifyWordLisp(styler.GetStartSegment(), i - 1, keywords, keywords_kw, styler); } else { styler.ColourTo(i - 1, state); } state = SCE_LISP_DEFAULT; } /*else*/ if (isLispoperator(ch) || ch=='\'') { styler.ColourTo(i - 1, state); styler.ColourTo(i, SCE_LISP_OPERATOR); if (ch=='\'' && isLispwordstart(chNext)) { state = SCE_LISP_SYMBOL; } } } else if (state == SCE_LISP_MACRO_DISPATCH) { if (!(isascii(ch) && isdigit(ch))) { if (ch != 'r' && ch != 'R' && (i - styler.GetStartSegment()) > 1) { state = SCE_LISP_DEFAULT; } else { switch (ch) { case '|': state = SCE_LISP_MULTI_COMMENT; break; case 'o': case 'O': radix = 8; state = SCE_LISP_MACRO; break; case 'x': case 'X': radix = 16; state = SCE_LISP_MACRO; break; case 'b': case 'B': radix = 2; state = SCE_LISP_MACRO; break; case '\\': state = SCE_LISP_CHARACTER; break; case ':': case '-': case '+': state = SCE_LISP_MACRO; break; case '\'': if (isLispwordstart(chNext)) { state = SCE_LISP_SPECIAL; } else { styler.ColourTo(i - 1, SCE_LISP_DEFAULT); styler.ColourTo(i, SCE_LISP_OPERATOR); state = SCE_LISP_DEFAULT; } break; default: if (isLispoperator(ch)) { styler.ColourTo(i - 1, SCE_LISP_DEFAULT); styler.ColourTo(i, SCE_LISP_OPERATOR); } state = SCE_LISP_DEFAULT; break; } } } } else if (state == SCE_LISP_MACRO) { if (isLispwordstart(ch) && (radix == -1 || IsADigit(ch, radix))) { state = SCE_LISP_SPECIAL; } else { state = SCE_LISP_DEFAULT; } } else if (state == SCE_LISP_CHARACTER) { if (isLispoperator(ch)) { styler.ColourTo(i, SCE_LISP_SPECIAL); state = SCE_LISP_DEFAULT; } else if (isLispwordstart(ch)) { styler.ColourTo(i, SCE_LISP_SPECIAL); state = SCE_LISP_SPECIAL; } else { state = SCE_LISP_DEFAULT; } } else if (state == SCE_LISP_SPECIAL) { if (!isLispwordstart(ch) || (radix != -1 && !IsADigit(ch, radix))) { styler.ColourTo(i - 1, state); state = SCE_LISP_DEFAULT; } if (isLispoperator(ch) || ch=='\'') { styler.ColourTo(i - 1, state); styler.ColourTo(i, SCE_LISP_OPERATOR); if (ch=='\'' && isLispwordstart(chNext)) { state = SCE_LISP_SYMBOL; } } } else { if (state == SCE_LISP_COMMENT) { if (atEOL) { styler.ColourTo(i - 1, state); state = SCE_LISP_DEFAULT; } } else if (state == SCE_LISP_MULTI_COMMENT) { if (ch == '|' && chNext == '#') { i++; chNext = styler.SafeGetCharAt(i + 1); styler.ColourTo(i, state); state = SCE_LISP_DEFAULT; } } else if (state == SCE_LISP_STRING) { if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; chNext = styler.SafeGetCharAt(i + 1); } } else if (ch == '\"') { styler.ColourTo(i, state); state = SCE_LISP_DEFAULT; } } } } styler.ColourTo(lengthDoc - 1, state); } static void FoldLispDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[], Accessor &styler) { unsigned int lengthDoc = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); for (unsigned int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_LISP_OPERATOR) { if (ch == '(' || ch == '[' || ch == '{') { levelCurrent++; } else if (ch == ')' || ch == ']' || ch == '}') { levelCurrent--; } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const lispWordListDesc[] = { "Functions and special operators", "Keywords", 0 }; LexerModule lmLISP(SCLEX_LISP, ColouriseLispDoc, "lisp", FoldLispDoc, lispWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexA68k.cxx0000644000175000017500000002644611615412040021045 00000000000000// Scintilla source code edit control /** @file LexA68k.cxx ** Lexer for Assembler, just for the MASM syntax ** Written by Martial Demolins AKA Folco **/ // Copyright 2010 Martial Demolins // The License.txt file describes the conditions under which this software // may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Return values for GetOperatorType #define NO_OPERATOR 0 #define OPERATOR_1CHAR 1 #define OPERATOR_2CHAR 2 /** * IsIdentifierStart * * Return true if the given char is a valid identifier first char */ static inline bool IsIdentifierStart (const int ch) { return (isalpha(ch) || (ch == '_') || (ch == '\\')); } /** * IsIdentifierChar * * Return true if the given char is a valid identifier char */ static inline bool IsIdentifierChar (const int ch) { return (isalnum(ch) || (ch == '_') || (ch == '@') || (ch == ':') || (ch == '.')); } /** * GetOperatorType * * Return: * NO_OPERATOR if char is not an operator * OPERATOR_1CHAR if the operator is one char long * OPERATOR_2CHAR if the operator is two chars long */ static inline int GetOperatorType (const int ch1, const int ch2) { int OpType = NO_OPERATOR; if ((ch1 == '+') || (ch1 == '-') || (ch1 == '*') || (ch1 == '/') || (ch1 == '#') || (ch1 == '(') || (ch1 == ')') || (ch1 == '~') || (ch1 == '&') || (ch1 == '|') || (ch1 == ',')) OpType = OPERATOR_1CHAR; else if ((ch1 == ch2) && (ch1 == '<' || ch1 == '>')) OpType = OPERATOR_2CHAR; return OpType; } /** * IsBin * * Return true if the given char is 0 or 1 */ static inline bool IsBin (const int ch) { return (ch == '0') || (ch == '1'); } /** * IsDoxygenChar * * Return true if the char may be part of a Doxygen keyword */ static inline bool IsDoxygenChar (const int ch) { return isalpha(ch) || (ch == '$') || (ch == '[') || (ch == ']') || (ch == '{') || (ch == '}'); } /** * ColouriseA68kDoc * * Main function, which colourises a 68k source */ static void ColouriseA68kDoc (unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { // Get references to keywords lists WordList &cpuInstruction = *keywordlists[0]; WordList ®isters = *keywordlists[1]; WordList &directive = *keywordlists[2]; WordList &extInstruction = *keywordlists[3]; WordList &commentSpecial = *keywordlists[4]; WordList &doxygenKeyword = *keywordlists[5]; // Instanciate a context for our source StyleContext sc(startPos, length, initStyle, styler); /************************************************************ * * Parse the text * ************************************************************/ for ( ; sc.More(); sc.Forward()) { char Buffer[100]; int OpType; // Reset style at beginning of line if (sc.atLineStart) sc.SetState(SCE_A68K_DEFAULT); /************************************************************ * * Handle current state if we are not in the "default style" * ************************************************************/ if (sc.state != SCE_A68K_DEFAULT) { // Check if current style continue. // If this case, we loop because there is nothing else to do if (((sc.state == SCE_A68K_NUMBER_DEC) && isdigit(sc.ch)) // Decimal number || ((sc.state == SCE_A68K_NUMBER_BIN) && IsBin(sc.ch)) // Binary number || ((sc.state == SCE_A68K_NUMBER_HEX) && isxdigit(sc.ch)) // Hexa number || ((sc.state == SCE_A68K_MACRO_ARG) && isdigit(sc.ch)) // Arg of macro || ((sc.state == SCE_A68K_STRING1) && (sc.ch != '\'')) // String single-quoted || ((sc.state == SCE_A68K_STRING2) && (sc.ch != '\"')) // String double-quoted || ((sc.state == SCE_A68K_MACRO_ARG) && isdigit(sc.ch)) // Macro argument // Label. ' ' and '\t' are needed to handle macro declarations || ((sc.state == SCE_A68K_LABEL) && (sc.ch != ':') && (sc.ch != ' ') && (sc.ch != '\t')) || ((sc.state == SCE_A68K_IDENTIFIER) && (sc.ch < 0x80) && IsIdentifierChar(sc.ch)) // Identifier || ((sc.state == SCE_A68K_COMMENT_DOXYGEN) && (sc.ch < 0x80) && IsDoxygenChar(sc.ch)) // Doxygen keyword || ((sc.state == SCE_A68K_COMMENT_WORD) && (sc.ch < 0x80) && isalpha(sc.ch))) // Comment current word { continue; } // Check if some states terminate at the current char: // we must include this char in the current style context else if (((sc.state == SCE_A68K_STRING1) && (sc.ch < 0x80) && (sc.ch == '\'')) // String single-quoted || ((sc.state == SCE_A68K_STRING2) && (sc.ch < 0x80) && (sc.ch == '\"')) // String double-quoted || ((sc.state == SCE_A68K_LABEL) && (sc.ch < 0x80) && (sc.ch == ':'))) // Label { sc.ForwardSetState(SCE_A68K_DEFAULT); } // Check for special words or Doxygen keywords in comments else if (sc.state == SCE_A68K_COMMENT) { if (sc.ch == '\\') { sc.SetState(SCE_A68K_COMMENT_DOXYGEN); } else if ((sc.ch < 0x80) && isalpha(sc.ch)) { sc.SetState(SCE_A68K_COMMENT_WORD); } continue; } // Check for special words in comment else if ((sc.state == SCE_A68K_COMMENT_WORD) && (sc.ch < 0x80) && !isalpha(sc.ch)) { sc.GetCurrent(Buffer, sizeof(Buffer)); if (commentSpecial.InList(Buffer)) { sc.ChangeState(SCE_A68K_COMMENT_SPECIAL); } else { sc.ChangeState(SCE_A68K_COMMENT); } sc.SetState(SCE_A68K_COMMENT); continue; } // Check for Doxygen keywords else if ((sc.state == SCE_A68K_COMMENT_DOXYGEN) && (sc.ch < 0x80) && !IsDoxygenChar(sc.ch)) { sc.GetCurrentLowered(Buffer, sizeof(Buffer)); // Buffer the string of the current context if (!doxygenKeyword.InList(Buffer)) { sc.ChangeState(SCE_A68K_COMMENT); } sc.SetState(SCE_A68K_COMMENT); continue; } // Check if we are in the case of a label which terminates without ':' // It should be a macro declaration, not a label else if ((sc.state == SCE_A68K_LABEL) && (sc.ch < 0x80) && ((sc.ch == ' ') || (sc.ch == '\t'))) { sc.ChangeState(SCE_A68K_MACRO_DECLARATION); } // Check if we are at the end of an identifier // In this case, colourise it if was a keyword. else if ((sc.state == SCE_A68K_IDENTIFIER) && !IsIdentifierChar(sc.ch)) { sc.GetCurrentLowered(Buffer, sizeof(Buffer)); // Buffer the string of the current context if (cpuInstruction.InList(Buffer)) { // And check if it belongs to a keyword list sc.ChangeState(SCE_A68K_CPUINSTRUCTION); } else if (extInstruction.InList(Buffer)) { sc.ChangeState(SCE_A68K_EXTINSTRUCTION); } else if (registers.InList(Buffer)) { sc.ChangeState(SCE_A68K_REGISTER); } else if (directive.InList(Buffer)) { sc.ChangeState(SCE_A68K_DIRECTIVE); } } // All special contexts are now handled.Come back to default style sc.SetState(SCE_A68K_DEFAULT); } /************************************************************ * * Check if we must enter a new state * ************************************************************/ // Label and macro identifiers start at the beginning of a line // We set both as a label, but if it wasn't one (no ':' at the end), // it will be changed as a macro identifier. if (sc.atLineStart && (sc.ch < 0x80) && IsIdentifierStart(sc.ch)) { sc.SetState(SCE_A68K_LABEL); } else if ((sc.ch < 0x80) && (sc.ch == ';')) { // Comment sc.SetState(SCE_A68K_COMMENT); } else if ((sc.ch < 0x80) && isdigit(sc.ch)) { // Decimal numbers haven't prefix sc.SetState(SCE_A68K_NUMBER_DEC); } else if ((sc.ch < 0x80) && (sc.ch == '%')) { // Binary numbers are prefixed with '%' sc.SetState(SCE_A68K_NUMBER_BIN); } else if ((sc.ch < 0x80) && (sc.ch == '$')) { // Hexadecimal numbers are prefixed with '$' sc.SetState(SCE_A68K_NUMBER_HEX); } else if ((sc.ch < 0x80) && (sc.ch == '\'')) { // String (single-quoted) sc.SetState(SCE_A68K_STRING1); } else if ((sc.ch < 0x80) && (sc.ch == '\"')) { // String (double-quoted) sc.SetState(SCE_A68K_STRING2); } else if ((sc.ch < 0x80) && (sc.ch == '\\') && (isdigit(sc.chNext))) { // Replacement symbols in macro sc.SetState(SCE_A68K_MACRO_ARG); } else if ((sc.ch < 0x80) && IsIdentifierStart(sc.ch)) { // An identifier: constant, label, etc... sc.SetState(SCE_A68K_IDENTIFIER); } else { if (sc.ch < 0x80) { OpType = GetOperatorType(sc.ch, sc.chNext); // Check if current char is an operator if (OpType != NO_OPERATOR) { sc.SetState(SCE_A68K_OPERATOR); if (OpType == OPERATOR_2CHAR) { // Check if the operator is 2 bytes long sc.ForwardSetState(SCE_A68K_OPERATOR); // (>> or <<) } } } } } // End of for() sc.Complete(); } // Names of the keyword lists static const char * const a68kWordListDesc[] = { "CPU instructions", "Registers", "Directives", "Extended instructions", "Comment special words", "Doxygen keywords", 0 }; LexerModule lmA68k(SCLEX_A68K, ColouriseA68kDoc, "a68k", 0, a68kWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexTACL.cxx0000644000175000017500000002556711615412040021062 00000000000000// Scintilla source code edit control /** @file LexTAL.cxx ** Lexer for TAL ** Based on LexPascal.cxx ** Written by Laurent le Tynevez ** Updated by Simon Steele September 2002 ** Updated by Mathias Rauen May 2003 (Delphi adjustments) ** Updated by Rod Falck, Aug 2006 Converted to TACL **/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif inline bool isTACLoperator(char ch) { return ch == '\'' || isoperator(ch); } inline bool isTACLwordchar(char ch) { return ch == '#' || ch == '^' || ch == '|' || ch == '_' || iswordchar(ch); } inline bool isTACLwordstart(char ch) { return ch == '#' || ch == '|' || ch == '_' || iswordstart(ch); } static void getRange(unsigned int start, unsigned int end, Accessor &styler, char *s, unsigned int len) { unsigned int i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = static_cast(tolower(styler[start + i])); i++; } s[i] = '\0'; } static bool IsStreamCommentStyle(int style) { return style == SCE_C_COMMENT || style == SCE_C_COMMENTDOC || style == SCE_C_COMMENTDOCKEYWORD || style == SCE_C_COMMENTDOCKEYWORDERROR; } static void ColourTo(Accessor &styler, unsigned int end, unsigned int attr, bool bInAsm) { if ((bInAsm) && (attr == SCE_C_OPERATOR || attr == SCE_C_NUMBER || attr == SCE_C_DEFAULT || attr == SCE_C_WORD || attr == SCE_C_IDENTIFIER)) { styler.ColourTo(end, SCE_C_REGEX); } else styler.ColourTo(end, attr); } // returns 1 if the item starts a class definition, and -1 if the word is "end", and 2 if the word is "asm" static int classifyWordTACL(unsigned int start, unsigned int end, /*WordList &keywords*/WordList *keywordlists[], Accessor &styler, bool bInAsm) { int ret = 0; WordList& keywords = *keywordlists[0]; WordList& builtins = *keywordlists[1]; WordList& commands = *keywordlists[2]; char s[100]; getRange(start, end, styler, s, sizeof(s)); char chAttr = SCE_C_IDENTIFIER; if (isdigit(s[0]) || (s[0] == '.')) { chAttr = SCE_C_NUMBER; } else { if (s[0] == '#' || keywords.InList(s)) { chAttr = SCE_C_WORD; if (strcmp(s, "asm") == 0) { ret = 2; } else if (strcmp(s, "end") == 0) { ret = -1; } } else if (s[0] == '|' || builtins.InList(s)) { chAttr = SCE_C_WORD2; } else if (commands.InList(s)) { chAttr = SCE_C_UUID; } else if (strcmp(s, "comment") == 0) { chAttr = SCE_C_COMMENTLINE; ret = 3; } } ColourTo(styler, end, chAttr, (bInAsm && ret != -1)); return ret; } static int classifyFoldPointTACL(const char* s) { int lev = 0; if (s[0] == '[') lev=1; else if (s[0] == ']') lev=-1; return lev; } static void ColouriseTACLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos); int state = initStyle; if (state == SCE_C_CHARACTER) // Does not leak onto next line state = SCE_C_DEFAULT; char chPrev = ' '; char chNext = styler[startPos]; unsigned int lengthDoc = startPos + length; bool bInClassDefinition; int currentLine = styler.GetLine(startPos); if (currentLine > 0) { styler.SetLineState(currentLine, styler.GetLineState(currentLine-1)); bInClassDefinition = (styler.GetLineState(currentLine) == 1); } else { styler.SetLineState(currentLine, 0); bInClassDefinition = false; } bool bInAsm = (state == SCE_C_REGEX); if (bInAsm) state = SCE_C_DEFAULT; styler.StartSegment(startPos); int visibleChars = 0; unsigned int i; for (i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) // Avoid triggering two times on Dos/Win // End of line if (state == SCE_C_CHARACTER) { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } visibleChars = 0; currentLine++; styler.SetLineState(currentLine, (bInClassDefinition ? 1 : 0)); } if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); chPrev = ' '; i += 1; continue; } if (state == SCE_C_DEFAULT) { if (isTACLwordstart(ch)) { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_IDENTIFIER; } else if (ch == '{') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENT; } else if (ch == '{' && chNext == '*') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENTDOC; } else if (ch == '=' && chNext == '=') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENTLINE; } else if (ch == '"') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_STRING; } else if (ch == '?' && visibleChars == 0) { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_PREPROCESSOR; } else if (isTACLoperator(ch)) { ColourTo(styler, i-1, state, bInAsm); ColourTo(styler, i, SCE_C_OPERATOR, bInAsm); } } else if (state == SCE_C_IDENTIFIER) { if (!isTACLwordchar(ch)) { int lStateChange = classifyWordTACL(styler.GetStartSegment(), i - 1, keywordlists, styler, bInAsm); if(lStateChange == 1) { styler.SetLineState(currentLine, 1); bInClassDefinition = true; } else if(lStateChange == 2) { bInAsm = true; } else if(lStateChange == -1) { styler.SetLineState(currentLine, 0); bInClassDefinition = false; bInAsm = false; } if (lStateChange == 3) { state = SCE_C_COMMENTLINE; } else { state = SCE_C_DEFAULT; chNext = styler.SafeGetCharAt(i + 1); if (ch == '{') { state = SCE_C_COMMENT; } else if (ch == '{' && chNext == '*') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_COMMENTDOC; } else if (ch == '=' && chNext == '=') { state = SCE_C_COMMENTLINE; } else if (ch == '"') { state = SCE_C_STRING; } else if (isTACLoperator(ch)) { ColourTo(styler, i, SCE_C_OPERATOR, bInAsm); } } } } else { if (state == SCE_C_PREPROCESSOR) { if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_DEFAULT; } } else if (state == SCE_C_COMMENT) { if (ch == '}' || (ch == '\r' || ch == '\n') ) { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } } else if (state == SCE_C_COMMENTDOC) { if (ch == '}' || (ch == '\r' || ch == '\n')) { if (((i > styler.GetStartSegment() + 2) || ( (initStyle == SCE_C_COMMENTDOC) && (styler.GetStartSegment() == static_cast(startPos))))) { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } } } else if (state == SCE_C_COMMENTLINE) { if (ch == '\r' || ch == '\n') { ColourTo(styler, i-1, state, bInAsm); state = SCE_C_DEFAULT; } } else if (state == SCE_C_STRING) { if (ch == '"' || ch == '\r' || ch == '\n') { ColourTo(styler, i, state, bInAsm); state = SCE_C_DEFAULT; } } } if (!isspacechar(ch)) visibleChars++; chPrev = ch; } // Process to end of document if (state == SCE_C_IDENTIFIER) { classifyWordTACL(styler.GetStartSegment(), i - 1, keywordlists, styler, bInAsm); } else ColourTo(styler, lengthDoc - 1, state, bInAsm); } static void FoldTACLDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; bool section = false; int lastStart = 0; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (stylePrev == SCE_C_DEFAULT && (style == SCE_C_WORD || style == SCE_C_PREPROCESSOR)) { // Store last word start point. lastStart = i; } if (stylePrev == SCE_C_WORD || stylePrev == SCE_C_PREPROCESSOR) { if(isTACLwordchar(ch) && !isTACLwordchar(chNext)) { char s[100]; getRange(lastStart, i, styler, s, sizeof(s)); if (stylePrev == SCE_C_PREPROCESSOR && strcmp(s, "?section") == 0) { section = true; levelCurrent = 1; levelPrev = 0; } else if (stylePrev == SCE_C_WORD) levelCurrent += classifyFoldPointTACL(s); } } if (style == SCE_C_OPERATOR) { if (ch == '[') { levelCurrent++; } else if (ch == ']') { levelCurrent--; } } if (foldComment && (style == SCE_C_COMMENTLINE)) { if ((ch == '/') && (chNext == '/')) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelCurrent++; } else if (chNext2 == '}') { levelCurrent--; } } } if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) { if (ch == '{' && chNext == '$') { unsigned int j=i+2; // skip {$ while ((j levelPrev || section) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; section = false; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const TACLWordListDesc[] = { "Builtins", "Labels", "Commands", 0 }; LexerModule lmTACL(SCLEX_TACL, ColouriseTACLDoc, "TACL", FoldTACLDoc, TACLWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMetapost.cxx0000644000175000017500000002531511615412040022122 00000000000000// Scintilla source code edit control // File: LexMetapost.cxx - general context conformant metapost coloring scheme // Author: Hans Hagen - PRAGMA ADE - Hasselt NL - www.pragma-ade.com // Version: September 28, 2003 // Modified by instanton: July 10, 2007 // Folding based on keywordlists[] // Copyright: 1998-2003 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. // This lexer is derived from the one written for the texwork environment (1999++) which in // turn is inspired on texedit (1991++) which finds its roots in wdt (1986). #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // val SCE_METAPOST_DEFAULT = 0 // val SCE_METAPOST_SPECIAL = 1 // val SCE_METAPOST_GROUP = 2 // val SCE_METAPOST_SYMBOL = 3 // val SCE_METAPOST_COMMAND = 4 // val SCE_METAPOST_TEXT = 5 // Definitions in SciTEGlobal.properties: // // Metapost Highlighting // // # Default // style.metapost.0=fore:#7F7F00 // # Special // style.metapost.1=fore:#007F7F // # Group // style.metapost.2=fore:#880000 // # Symbol // style.metapost.3=fore:#7F7F00 // # Command // style.metapost.4=fore:#008800 // # Text // style.metapost.5=fore:#000000 // lexer.tex.comment.process=0 // Auxiliary functions: static inline bool endOfLine(Accessor &styler, unsigned int i) { return (styler[i] == '\n') || ((styler[i] == '\r') && (styler.SafeGetCharAt(i + 1) != '\n')) ; } static inline bool isMETAPOSTcomment(int ch) { return (ch == '%') ; } static inline bool isMETAPOSTone(int ch) { return (ch == '[') || (ch == ']') || (ch == '(') || (ch == ')') || (ch == ':') || (ch == '=') || (ch == '<') || (ch == '>') || (ch == '{') || (ch == '}') || (ch == '\'') || (ch == '\"') ; } static inline bool isMETAPOSTtwo(int ch) { return (ch == ';') || (ch == '$') || (ch == '@') || (ch == '#'); } static inline bool isMETAPOSTthree(int ch) { return (ch == '.') || (ch == '-') || (ch == '+') || (ch == '/') || (ch == '*') || (ch == ',') || (ch == '|') || (ch == '`') || (ch == '!') || (ch == '?') || (ch == '^') || (ch == '&') || (ch == '%') ; } static inline bool isMETAPOSTidentifier(int ch) { return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || (ch == '_') ; } static inline bool isMETAPOSTnumber(int ch) { return (ch >= '0') && (ch <= '9') ; } static inline bool isMETAPOSTstring(int ch) { return (ch == '\"') ; } static inline bool isMETAPOSTcolon(int ch) { return (ch == ':') ; } static inline bool isMETAPOSTequal(int ch) { return (ch == '=') ; } static int CheckMETAPOSTInterface( unsigned int startPos, int length, Accessor &styler, int defaultInterface) { char lineBuffer[1024] ; unsigned int linePos = 0 ; // some day we can make something lexer.metapost.mapping=(none,0)(metapost,1)(mp,1)(metafun,2)... if (styler.SafeGetCharAt(0) == '%') { for (unsigned int i = 0; i < startPos + length; i++) { lineBuffer[linePos++] = styler.SafeGetCharAt(i) ; if (endOfLine(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { lineBuffer[linePos] = '\0'; if (strstr(lineBuffer, "interface=none")) { return 0 ; } else if (strstr(lineBuffer, "interface=metapost") || strstr(lineBuffer, "interface=mp")) { return 1 ; } else if (strstr(lineBuffer, "interface=metafun")) { return 2 ; } else if (styler.SafeGetCharAt(1) == 'D' && strstr(lineBuffer, "%D \\module")) { // better would be to limit the search to just one line return 2 ; } else { return defaultInterface ; } } } } return defaultInterface ; } static void ColouriseMETAPOSTDoc( unsigned int startPos, int length, int, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos) ; styler.StartSegment(startPos) ; bool processComment = styler.GetPropertyInt("lexer.metapost.comment.process", 0) == 1 ; int defaultInterface = styler.GetPropertyInt("lexer.metapost.interface.default", 1) ; int currentInterface = CheckMETAPOSTInterface(startPos,length,styler,defaultInterface) ; // 0 no keyword highlighting // 1 metapost keyword hightlighting // 2+ metafun keyword hightlighting int extraInterface = 0 ; if (currentInterface != 0) { extraInterface = currentInterface ; } WordList &keywords = *keywordlists[0] ; WordList &keywords2 = *keywordlists[extraInterface-1] ; StyleContext sc(startPos, length, SCE_METAPOST_TEXT, styler) ; char key[100] ; bool inTeX = false ; bool inComment = false ; bool inString = false ; bool inClause = false ; bool going = sc.More() ; // needed because of a fuzzy end of file state for (; going; sc.Forward()) { if (! sc.More()) { going = false ; } // we need to go one behind the end of text if (inClause) { sc.SetState(SCE_METAPOST_TEXT) ; inClause = false ; } if (inComment) { if (sc.atLineEnd) { sc.SetState(SCE_METAPOST_TEXT) ; inTeX = false ; inComment = false ; inClause = false ; inString = false ; // not correct but we want to stimulate one-lines } } else if (inString) { if (isMETAPOSTstring(sc.ch)) { sc.SetState(SCE_METAPOST_SPECIAL) ; sc.ForwardSetState(SCE_METAPOST_TEXT) ; inString = false ; } else if (sc.atLineEnd) { sc.SetState(SCE_METAPOST_TEXT) ; inTeX = false ; inComment = false ; inClause = false ; inString = false ; // not correct but we want to stimulate one-lines } } else { if ((! isMETAPOSTidentifier(sc.ch)) && (sc.LengthCurrent() > 0)) { if (sc.state == SCE_METAPOST_COMMAND) { sc.GetCurrent(key, sizeof(key)) ; if ((strcmp(key,"btex") == 0) || (strcmp(key,"verbatimtex") == 0)) { sc.ChangeState(SCE_METAPOST_GROUP) ; inTeX = true ; } else if (inTeX) { if (strcmp(key,"etex") == 0) { sc.ChangeState(SCE_METAPOST_GROUP) ; inTeX = false ; } else { sc.ChangeState(SCE_METAPOST_TEXT) ; } } else { if (keywords && keywords.InList(key)) { sc.ChangeState(SCE_METAPOST_COMMAND) ; } else if (keywords2 && keywords2.InList(key)) { sc.ChangeState(SCE_METAPOST_EXTRA) ; } else { sc.ChangeState(SCE_METAPOST_TEXT) ; } } } } if (isMETAPOSTcomment(sc.ch)) { if (! inTeX) { sc.SetState(SCE_METAPOST_SYMBOL) ; sc.ForwardSetState(SCE_METAPOST_DEFAULT) ; inComment = ! processComment ; } else { sc.SetState(SCE_METAPOST_TEXT) ; } } else if (isMETAPOSTstring(sc.ch)) { if (! inTeX) { sc.SetState(SCE_METAPOST_SPECIAL) ; if (! isMETAPOSTstring(sc.chNext)) { sc.ForwardSetState(SCE_METAPOST_TEXT) ; } inString = true ; } else { sc.SetState(SCE_METAPOST_TEXT) ; } } else if (isMETAPOSTcolon(sc.ch)) { if (! inTeX) { if (! isMETAPOSTequal(sc.chNext)) { sc.SetState(SCE_METAPOST_COMMAND) ; inClause = true ; } else { sc.SetState(SCE_METAPOST_SPECIAL) ; } } else { sc.SetState(SCE_METAPOST_TEXT) ; } } else if (isMETAPOSTone(sc.ch)) { if (! inTeX) { sc.SetState(SCE_METAPOST_SPECIAL) ; } else { sc.SetState(SCE_METAPOST_TEXT) ; } } else if (isMETAPOSTtwo(sc.ch)) { if (! inTeX) { sc.SetState(SCE_METAPOST_GROUP) ; } else { sc.SetState(SCE_METAPOST_TEXT) ; } } else if (isMETAPOSTthree(sc.ch)) { if (! inTeX) { sc.SetState(SCE_METAPOST_SYMBOL) ; } else { sc.SetState(SCE_METAPOST_TEXT) ; } } else if (isMETAPOSTidentifier(sc.ch)) { if (sc.state != SCE_METAPOST_COMMAND) { sc.SetState(SCE_METAPOST_TEXT) ; sc.ChangeState(SCE_METAPOST_COMMAND) ; } } else if (isMETAPOSTnumber(sc.ch)) { // rather redundant since for the moment we don't handle numbers sc.SetState(SCE_METAPOST_TEXT) ; } else if (sc.atLineEnd) { sc.SetState(SCE_METAPOST_TEXT) ; inTeX = false ; inComment = false ; inClause = false ; inString = false ; } else { sc.SetState(SCE_METAPOST_TEXT) ; } } } sc.Complete(); } // Hooks info the system: static const char * const metapostWordListDesc[] = { "MetaPost", "MetaFun", 0 } ; static int classifyFoldPointMetapost(const char* s,WordList *keywordlists[]) { WordList& keywordsStart=*keywordlists[3]; WordList& keywordsStop1=*keywordlists[4]; if (keywordsStart.InList(s)) {return 1;} else if (keywordsStop1.InList(s)) {return -1;} return 0; } static int ParseMetapostWord(unsigned int pos, Accessor &styler, char *word) { int length=0; char ch=styler.SafeGetCharAt(pos); *word=0; while(isMETAPOSTidentifier(ch) && isalpha(ch) && length<100){ word[length]=ch; length++; ch=styler.SafeGetCharAt(pos+length); } word[length]=0; return length; } static void FoldMetapostDoc(unsigned int startPos, int length, int, WordList *keywordlists[], Accessor &styler) { bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos+length; int visibleChars=0; int lineCurrent=styler.GetLine(startPos); int levelPrev=styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent=levelPrev; char chNext=styler[startPos]; char buffer[100]=""; for (unsigned int i=startPos; i < endPos; i++) { char ch=chNext; chNext=styler.SafeGetCharAt(i+1); char chPrev=styler.SafeGetCharAt(i-1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if(i==0 || chPrev == '\r' || chPrev=='\n'|| chPrev==' '|| chPrev=='(' || chPrev=='$') { ParseMetapostWord(i, styler, buffer); levelCurrent += classifyFoldPointMetapost(buffer,keywordlists); } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } LexerModule lmMETAPOST(SCLEX_METAPOST, ColouriseMETAPOSTDoc, "metapost", FoldMetapostDoc, metapostWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexGui4Cli.cxx0000644000175000017500000002141311615412040021561 00000000000000// Scintilla source code edit control // Copyright 1998-2002 by Neil Hodgson /* This is the Lexer for Gui4Cli, included in SciLexer.dll - by d. Keletsekis, 2/10/2003 To add to SciLexer.dll: 1. Add the values below to INCLUDE\Scintilla.iface 2. Run the include/HFacer.py script 3. Run the src/lexGen.py script val SCE_GC_DEFAULT=0 val SCE_GC_COMMENTLINE=1 val SCE_GC_COMMENTBLOCK=2 val SCE_GC_GLOBAL=3 val SCE_GC_EVENT=4 val SCE_GC_ATTRIBUTE=5 val SCE_GC_CONTROL=6 val SCE_GC_COMMAND=7 val SCE_GC_STRING=8 val SCE_GC_OPERATOR=9 */ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #define debug Platform::DebugPrintf static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch =='\\'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.'); } inline bool isGCOperator(int ch) { if (isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '*' || ch == '/' || ch == '-' || ch == '+' || ch == '(' || ch == ')' || ch == '=' || ch == '%' || ch == '[' || ch == ']' || ch == '<' || ch == '>' || ch == ',' || ch == ';' || ch == ':') return true; return false; } #define isSpace(x) ((x)==' ' || (x)=='\t') #define isNL(x) ((x)=='\n' || (x)=='\r') #define isSpaceOrNL(x) (isSpace(x) || isNL(x)) #define BUFFSIZE 500 #define isFoldPoint(x) ((styler.LevelAt(x) & SC_FOLDLEVELNUMBERMASK) == 1024) static void colorFirstWord(WordList *keywordlists[], Accessor &styler, StyleContext *sc, char *buff, int length, int) { int c = 0; while (sc->More() && isSpaceOrNL(sc->ch)) { sc->Forward(); } styler.ColourTo(sc->currentPos - 1, sc->state); if (!IsAWordChar(sc->ch)) // comment, marker, etc.. return; while (sc->More() && !isSpaceOrNL(sc->ch) && (c < length-1) && !isGCOperator(sc->ch)) { buff[c] = static_cast(sc->ch); ++c; sc->Forward(); } buff[c] = '\0'; char *p = buff; while (*p) // capitalize.. { if (islower(*p)) *p = static_cast(toupper(*p)); ++p; } WordList &kGlobal = *keywordlists[0]; // keyword lists set by the user WordList &kEvent = *keywordlists[1]; WordList &kAttribute = *keywordlists[2]; WordList &kControl = *keywordlists[3]; WordList &kCommand = *keywordlists[4]; int state = 0; // int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK; // debug ("line = %d, level = %d", line, level); if (kGlobal.InList(buff)) state = SCE_GC_GLOBAL; else if (kAttribute.InList(buff)) state = SCE_GC_ATTRIBUTE; else if (kControl.InList(buff)) state = SCE_GC_CONTROL; else if (kCommand.InList(buff)) state = SCE_GC_COMMAND; else if (kEvent.InList(buff)) state = SCE_GC_EVENT; if (state) { sc->ChangeState(state); styler.ColourTo(sc->currentPos - 1, sc->state); sc->ChangeState(SCE_GC_DEFAULT); } else { sc->ChangeState(SCE_GC_DEFAULT); styler.ColourTo(sc->currentPos - 1, sc->state); } } // Main colorizing function called by Scintilla static void ColouriseGui4CliDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos); int quotestart = 0, oldstate, currentline = styler.GetLine(startPos); styler.StartSegment(startPos); bool noforward; char buff[BUFFSIZE+1]; // buffer for command name StyleContext sc(startPos, length, initStyle, styler); buff[0] = '\0'; // cbuff = 0; if (sc.state != SCE_GC_COMMENTBLOCK) // colorize 1st word.. colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); while (sc.More()) { noforward = 0; switch (sc.ch) { case '/': if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_STRING) break; if (sc.chNext == '/') // line comment { sc.SetState (SCE_GC_COMMENTLINE); sc.Forward(); styler.ColourTo(sc.currentPos, sc.state); } else if (sc.chNext == '*') // block comment { sc.SetState(SCE_GC_COMMENTBLOCK); sc.Forward(); styler.ColourTo(sc.currentPos, sc.state); } else styler.ColourTo(sc.currentPos, sc.state); break; case '*': // end of comment block, or operator.. if (sc.state == SCE_GC_STRING) break; if (sc.state == SCE_GC_COMMENTBLOCK && sc.chNext == '/') { sc.Forward(); styler.ColourTo(sc.currentPos, sc.state); sc.ChangeState (SCE_GC_DEFAULT); } else styler.ColourTo(sc.currentPos, sc.state); break; case '\'': case '\"': // strings.. if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_COMMENTLINE) break; if (sc.state == SCE_GC_STRING) { if (sc.ch == quotestart) // match same quote char.. { styler.ColourTo(sc.currentPos, sc.state); sc.ChangeState(SCE_GC_DEFAULT); quotestart = 0; } } else { styler.ColourTo(sc.currentPos - 1, sc.state); sc.ChangeState(SCE_GC_STRING); quotestart = sc.ch; } break; case ';': // end of commandline character if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE && sc.state != SCE_GC_STRING) { styler.ColourTo(sc.currentPos - 1, sc.state); styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); sc.ChangeState(SCE_GC_DEFAULT); sc.Forward(); colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); noforward = 1; // don't move forward - already positioned at next char.. } break; case '+': case '-': case '=': case '!': // operators.. case '<': case '>': case '&': case '|': case '$': if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE && sc.state != SCE_GC_STRING) { styler.ColourTo(sc.currentPos - 1, sc.state); styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); sc.ChangeState(SCE_GC_DEFAULT); } break; case '\\': // escape - same as operator, but also mark in strings.. if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE) { oldstate = sc.state; styler.ColourTo(sc.currentPos - 1, sc.state); sc.Forward(); // mark also the next char.. styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR); sc.ChangeState(oldstate); } break; case '\n': case '\r': ++currentline; if (sc.state == SCE_GC_COMMENTLINE) { styler.ColourTo(sc.currentPos, sc.state); sc.ChangeState (SCE_GC_DEFAULT); } else if (sc.state != SCE_GC_COMMENTBLOCK) { colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline); noforward = 1; // don't move forward - already positioned at next char.. } break; // case ' ': case '\t': // default : } if (!noforward) sc.Forward(); } sc.Complete(); } // Main folding function called by Scintilla - (based on props (.ini) files function) static void FoldGui4Cli(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); bool headerPoint = false; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler[i+1]; int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_GC_EVENT || style == SCE_GC_GLOBAL) { headerPoint = true; // fold at events and globals } if (atEOL) { int lev = SC_FOLDLEVELBASE+1; if (headerPoint) lev = SC_FOLDLEVELBASE; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (headerPoint) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) // set level, if not already correct { styler.SetLevel(lineCurrent, lev); } lineCurrent++; // re-initialize our flags visibleChars = 0; headerPoint = false; } if (!(isspacechar(ch))) // || (style == SCE_GC_COMMENTLINE) || (style != SCE_GC_COMMENTBLOCK))) visibleChars++; } int lev = headerPoint ? SC_FOLDLEVELBASE : SC_FOLDLEVELBASE+1; int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, lev | flagsNext); } // I have no idea what these are for.. probably accessible by some message. static const char * const gui4cliWordListDesc[] = { "Globals", "Events", "Attributes", "Control", "Commands", 0 }; // Declare language & pass our function pointers to Scintilla LexerModule lmGui4Cli(SCLEX_GUI4CLI, ColouriseGui4CliDoc, "gui4cli", FoldGui4Cli, gui4cliWordListDesc); #undef debug presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMatlab.cxx0000644000175000017500000001624711615412040021532 00000000000000// Scintilla source code edit control /** @file LexMatlab.cxx ** Lexer for Matlab. ** Written by José Fonseca ** ** Changes by Christoph Dalitz 2003/12/04: ** - added support for Octave ** - Strings can now be included both in single or double quotes **/ // Copyright 1998-2001 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static bool IsMatlabCommentChar(int c) { return (c == '%') ; } static bool IsOctaveCommentChar(int c) { return (c == '%' || c == '#') ; } static bool IsMatlabComment(Accessor &styler, int pos, int len) { return len > 0 && IsMatlabCommentChar(styler[pos]) ; } static bool IsOctaveComment(Accessor &styler, int pos, int len) { return len > 0 && IsOctaveCommentChar(styler[pos]) ; } static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static void ColouriseMatlabOctaveDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler, bool (*IsCommentChar)(int)) { WordList &keywords = *keywordlists[0]; styler.StartAt(startPos); bool transpose = false; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.state == SCE_MATLAB_OPERATOR) { if (sc.chPrev == '.') { if (sc.ch == '*' || sc.ch == '/' || sc.ch == '\\' || sc.ch == '^') { sc.ForwardSetState(SCE_MATLAB_DEFAULT); transpose = false; } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_MATLAB_DEFAULT); transpose = true; } else { sc.SetState(SCE_MATLAB_DEFAULT); } } else { sc.SetState(SCE_MATLAB_DEFAULT); } } else if (sc.state == SCE_MATLAB_KEYWORD) { if (!isalnum(sc.ch) && sc.ch != '_') { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.SetState(SCE_MATLAB_DEFAULT); transpose = false; } else { sc.ChangeState(SCE_MATLAB_IDENTIFIER); sc.SetState(SCE_MATLAB_DEFAULT); transpose = true; } } } else if (sc.state == SCE_MATLAB_NUMBER) { if (!isdigit(sc.ch) && sc.ch != '.' && !(sc.ch == 'e' || sc.ch == 'E') && !((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E'))) { sc.SetState(SCE_MATLAB_DEFAULT); transpose = true; } } else if (sc.state == SCE_MATLAB_STRING) { if (sc.ch == '\'') { if (sc.chNext == '\'') { sc.Forward(); } else { sc.ForwardSetState(SCE_MATLAB_DEFAULT); } } } else if (sc.state == SCE_MATLAB_DOUBLEQUOTESTRING) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_MATLAB_DEFAULT); } } else if (sc.state == SCE_MATLAB_COMMENT || sc.state == SCE_MATLAB_COMMAND) { if (sc.atLineEnd) { sc.SetState(SCE_MATLAB_DEFAULT); transpose = false; } } if (sc.state == SCE_MATLAB_DEFAULT) { if (IsCommentChar(sc.ch)) { sc.SetState(SCE_MATLAB_COMMENT); } else if (sc.ch == '!' && sc.chNext != '=' ) { sc.SetState(SCE_MATLAB_COMMAND); } else if (sc.ch == '\'') { if (transpose) { sc.SetState(SCE_MATLAB_OPERATOR); } else { sc.SetState(SCE_MATLAB_STRING); } } else if (sc.ch == '"') { sc.SetState(SCE_MATLAB_DOUBLEQUOTESTRING); } else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) { sc.SetState(SCE_MATLAB_NUMBER); } else if (isalpha(sc.ch)) { sc.SetState(SCE_MATLAB_KEYWORD); } else if (isoperator(static_cast(sc.ch)) || sc.ch == '@' || sc.ch == '\\') { if (sc.ch == ')' || sc.ch == ']') { transpose = true; } else { transpose = false; } sc.SetState(SCE_MATLAB_OPERATOR); } else { transpose = false; } } } sc.Complete(); } static void ColouriseMatlabDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColouriseMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsMatlabCommentChar); } static void ColouriseOctaveDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColouriseMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsOctaveCommentChar); } static void FoldMatlabOctaveDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler, bool (*IsComment)(Accessor&, int, int)) { int endPos = startPos + length; // Backtrack to previous line in case need to fix its fold status int lineCurrent = styler.GetLine(startPos); if (startPos > 0) { if (lineCurrent > 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); } } int spaceFlags = 0; int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsComment); char chNext = styler[startPos]; for (int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) { int lev = indentCurrent; int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsComment); if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { // Only non whitespace lines can be headers if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } else if (indentNext & SC_FOLDLEVELWHITEFLAG) { // Line after is blank so check the next - maybe should continue further? int spaceFlags2 = 0; int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsComment); if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } } } indentCurrent = indentNext; styler.SetLevel(lineCurrent, lev); lineCurrent++; } } } static void FoldMatlabDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { FoldMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsMatlabComment); } static void FoldOctaveDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { FoldMatlabOctaveDoc(startPos, length, initStyle, keywordlists, styler, IsOctaveComment); } static const char * const matlabWordListDesc[] = { "Keywords", 0 }; static const char * const octaveWordListDesc[] = { "Keywords", 0 }; LexerModule lmMatlab(SCLEX_MATLAB, ColouriseMatlabDoc, "matlab", FoldMatlabDoc, matlabWordListDesc); LexerModule lmOctave(SCLEX_OCTAVE, ColouriseOctaveDoc, "octave", FoldOctaveDoc, octaveWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexPOV.cxx0000644000175000017500000002246311615412040020773 00000000000000// Scintilla source code edit control /** @file LexPOV.cxx ** Lexer for POV-Ray SDL (Persistance of Vision Raytracer, Scene Description Language). ** Written by Philippe Lhoste but this is mostly a derivative of LexCPP... **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. // Some points that distinguish from a simple C lexer: // Identifiers start only by a character. // No line continuation character. // Strings are limited to 256 characters. // Directives are similar to preprocessor commands, // but we match directive keywords and colorize incorrect ones. // Block comments can be nested (code stolen from my code in LexLua). #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch) { return ch < 0x80 && (isalnum(ch) || ch == '_'); } static inline bool IsAWordStart(int ch) { return ch < 0x80 && isalpha(ch); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || toupper(ch) == 'E' || ch == '.' || ch == '-' || ch == '+'); } static void ColourisePovDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords1 = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; WordList &keywords5 = *keywordlists[4]; WordList &keywords6 = *keywordlists[5]; WordList &keywords7 = *keywordlists[6]; WordList &keywords8 = *keywordlists[7]; int currentLine = styler.GetLine(startPos); // Initialize the block comment /* */ nesting level, if we are inside such a comment. int blockCommentLevel = 0; if (initStyle == SCE_POV_COMMENT) { blockCommentLevel = styler.GetLineState(currentLine - 1); } // Do not leak onto next line if (initStyle == SCE_POV_STRINGEOL || initStyle == SCE_POV_COMMENTLINE) { initStyle = SCE_POV_DEFAULT; } short stringLen = 0; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineEnd) { // Update the line state, so it can be seen by next line currentLine = styler.GetLine(sc.currentPos); if (sc.state == SCE_POV_COMMENT) { // Inside a block comment, we set the line state styler.SetLineState(currentLine, blockCommentLevel); } else { // Reset the line state styler.SetLineState(currentLine, 0); } } if (sc.atLineStart && (sc.state == SCE_POV_STRING)) { // Prevent SCE_POV_STRINGEOL from leaking back to previous line sc.SetState(SCE_POV_STRING); } // Determine if the current state should terminate. if (sc.state == SCE_POV_OPERATOR) { sc.SetState(SCE_POV_DEFAULT); } else if (sc.state == SCE_POV_NUMBER) { // We stop the number definition on non-numerical non-dot non-eE non-sign char if (!IsANumberChar(sc.ch)) { sc.SetState(SCE_POV_DEFAULT); } } else if (sc.state == SCE_POV_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (keywords2.InList(s)) { sc.ChangeState(SCE_POV_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_POV_WORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_POV_WORD4); } else if (keywords5.InList(s)) { sc.ChangeState(SCE_POV_WORD5); } else if (keywords6.InList(s)) { sc.ChangeState(SCE_POV_WORD6); } else if (keywords7.InList(s)) { sc.ChangeState(SCE_POV_WORD7); } else if (keywords8.InList(s)) { sc.ChangeState(SCE_POV_WORD8); } sc.SetState(SCE_POV_DEFAULT); } } else if (sc.state == SCE_POV_DIRECTIVE) { if (!IsAWordChar(sc.ch)) { char s[100]; char *p; sc.GetCurrent(s, sizeof(s)); p = s; // Skip # and whitespace between # and directive word do { p++; } while ((*p == ' ' || *p == '\t') && *p != '\0'); if (!keywords1.InList(p)) { sc.ChangeState(SCE_POV_BADDIRECTIVE); } sc.SetState(SCE_POV_DEFAULT); } } else if (sc.state == SCE_POV_COMMENT) { if (sc.Match('/', '*')) { blockCommentLevel++; sc.Forward(); } else if (sc.Match('*', '/') && blockCommentLevel > 0) { blockCommentLevel--; sc.Forward(); if (blockCommentLevel == 0) { sc.ForwardSetState(SCE_POV_DEFAULT); } } } else if (sc.state == SCE_POV_COMMENTLINE) { if (sc.atLineEnd) { sc.ForwardSetState(SCE_POV_DEFAULT); } } else if (sc.state == SCE_POV_STRING) { if (sc.ch == '\\') { stringLen++; if (strchr("abfnrtuv0'\"", sc.chNext)) { // Compound characters are counted as one. // Note: for Unicode chars \u, we shouldn't count the next 4 digits... sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_POV_DEFAULT); } else if (sc.atLineEnd) { sc.ChangeState(SCE_POV_STRINGEOL); sc.ForwardSetState(SCE_POV_DEFAULT); } else { stringLen++; } if (stringLen > 256) { // Strings are limited to 256 chars sc.SetState(SCE_POV_STRINGEOL); } } else if (sc.state == SCE_POV_STRINGEOL) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_C_DEFAULT); } else if (sc.atLineEnd) { sc.ForwardSetState(SCE_POV_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_POV_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_POV_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_POV_IDENTIFIER); } else if (sc.Match('/', '*')) { blockCommentLevel = 1; sc.SetState(SCE_POV_COMMENT); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { sc.SetState(SCE_POV_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_POV_STRING); stringLen = 0; } else if (sc.ch == '#') { sc.SetState(SCE_POV_DIRECTIVE); // Skip whitespace between # and directive word do { sc.Forward(); } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); if (sc.atLineEnd) { sc.SetState(SCE_POV_DEFAULT); } } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_POV_OPERATOR); } } } sc.Complete(); } static void FoldPovDoc( unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldDirective = styler.GetPropertyInt("fold.directive") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && (style == SCE_POV_COMMENT)) { if (stylePrev != SCE_POV_COMMENT) { levelCurrent++; } else if ((styleNext != SCE_POV_COMMENT) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelCurrent--; } } if (foldComment && (style == SCE_POV_COMMENTLINE)) { if ((ch == '/') && (chNext == '/')) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelCurrent++; } else if (chNext2 == '}') { levelCurrent--; } } } if (foldDirective && (style == SCE_POV_DIRECTIVE)) { if (ch == '#') { unsigned int j=i+1; while ((j levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const povWordLists[] = { "Language directives", "Objects & CSG & Appearance", "Types & Modifiers & Items", "Predefined Identifiers", "Predefined Functions", "User defined 1", "User defined 2", "User defined 3", 0, }; LexerModule lmPOV(SCLEX_POV, ColourisePovDoc, "pov", FoldPovDoc, povWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexVerilog.cxx0000644000175000017500000002714311615412040021736 00000000000000// Scintilla source code edit control /** @file LexVerilog.cxx ** Lexer for Verilog. ** Written by Avi Yegudin, based on C++ lexer by Neil Hodgson **/ // Copyright 1998-2002 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\''|| ch == '$'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '$'); } static void ColouriseVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; // Do not leak onto next line if (initStyle == SCE_V_STRINGEOL) initStyle = SCE_V_DEFAULT; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineStart && (sc.state == SCE_V_STRING)) { // Prevent SCE_V_STRINGEOL from leaking back to previous line sc.SetState(SCE_V_STRING); } // Handle line continuation generically. if (sc.ch == '\\') { if (sc.chNext == '\n' || sc.chNext == '\r') { sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } continue; } } // Determine if the current state should terminate. if (sc.state == SCE_V_OPERATOR) { sc.SetState(SCE_V_DEFAULT); } else if (sc.state == SCE_V_NUMBER) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_V_DEFAULT); } } else if (sc.state == SCE_V_IDENTIFIER) { if (!IsAWordChar(sc.ch) || (sc.ch == '.')) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_V_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_V_WORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_V_WORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_V_USER); } sc.SetState(SCE_V_DEFAULT); } } else if (sc.state == SCE_V_PREPROCESSOR) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_V_DEFAULT); } } else if (sc.state == SCE_V_COMMENT) { if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_V_DEFAULT); } } else if (sc.state == SCE_V_COMMENTLINE || sc.state == SCE_V_COMMENTLINEBANG) { if (sc.atLineStart) { sc.SetState(SCE_V_DEFAULT); } } else if (sc.state == SCE_V_STRING) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_V_DEFAULT); } else if (sc.atLineEnd) { sc.ChangeState(SCE_V_STRINGEOL); sc.ForwardSetState(SCE_V_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_V_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '\'') || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_V_NUMBER); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_V_IDENTIFIER); } else if (sc.Match('/', '*')) { sc.SetState(SCE_V_COMMENT); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { if (sc.Match("//!")) // Nice to have a different comment style sc.SetState(SCE_V_COMMENTLINEBANG); else sc.SetState(SCE_V_COMMENTLINE); } else if (sc.ch == '\"') { sc.SetState(SCE_V_STRING); } else if (sc.ch == '`') { sc.SetState(SCE_V_PREPROCESSOR); // Skip whitespace between ` and preprocessor word do { sc.Forward(); } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); if (sc.atLineEnd) { sc.SetState(SCE_V_DEFAULT); } } else if (isoperator(static_cast(sc.ch)) || sc.ch == '@' || sc.ch == '#') { sc.SetState(SCE_V_OPERATOR); } } } sc.Complete(); } static bool IsStreamCommentStyle(int style) { return style == SCE_V_COMMENT; } static bool IsCommentLine(int line, Accessor &styler) { int pos = styler.LineStart(line); int eolPos = styler.LineStart(line + 1) - 1; for (int i = pos; i < eolPos; i++) { char ch = styler[i]; char chNext = styler.SafeGetCharAt(i + 1); int style = styler.StyleAt(i); if (ch == '/' && chNext == '/' && (style == SCE_V_COMMENTLINE || style == SCE_V_COMMENTLINEBANG)) { return true; } else if (!IsASpaceOrTab(ch)) { return false; } } return false; } // Store both the current line's fold level and the next lines in the // level store to make it easy to pick up with each increment // and to make it possible to fiddle the current level for "} else {". static void FoldNoBoxVerilogDoc(unsigned int startPos, int length, int initStyle, Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0; // Verilog specific folding options: // fold_at_module - // Generally used methodology in verilog code is // one module per file, so folding at module definition is useless. // fold_at_brace/parenthese - // Folding of long port lists can be convenient. bool foldAtModule = styler.GetPropertyInt("fold.verilog.flags", 0) != 0; bool foldAtBrace = 1; bool foldAtParenthese = 1; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelCurrent = SC_FOLDLEVELBASE; if (lineCurrent > 0) levelCurrent = styler.LevelAt(lineCurrent-1) >> 16; int levelMinCurrent = levelCurrent; int levelNext = levelCurrent; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelNext++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelNext--; } } if (foldComment && atEOL && IsCommentLine(lineCurrent, styler)) { if (!IsCommentLine(lineCurrent - 1, styler) && IsCommentLine(lineCurrent + 1, styler)) levelNext++; else if (IsCommentLine(lineCurrent - 1, styler) && !IsCommentLine(lineCurrent+1, styler)) levelNext--; } if (foldComment && (style == SCE_V_COMMENTLINE)) { if ((ch == '/') && (chNext == '/')) { char chNext2 = styler.SafeGetCharAt(i + 2); if (chNext2 == '{') { levelNext++; } else if (chNext2 == '}') { levelNext--; } } } if (foldPreprocessor && (style == SCE_V_PREPROCESSOR)) { if (ch == '`') { unsigned int j = i + 1; while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { j++; } if (styler.Match(j, "if")) { levelNext++; } else if (styler.Match(j, "end")) { levelNext--; } } } if (style == SCE_V_OPERATOR) { if (foldAtParenthese) { if (ch == '(') { levelNext++; } else if (ch == ')') { levelNext--; } } } if (style == SCE_V_OPERATOR) { if (foldAtBrace) { if (ch == '{') { levelNext++; } else if (ch == '}') { levelNext--; } } } if (style == SCE_V_WORD && stylePrev != SCE_V_WORD) { unsigned int j = i; if (styler.Match(j, "case") || styler.Match(j, "casex") || styler.Match(j, "casez") || styler.Match(j, "class") || styler.Match(j, "function") || styler.Match(j, "generate") || styler.Match(j, "covergroup") || styler.Match(j, "package") || styler.Match(j, "primitive") || styler.Match(j, "program") || styler.Match(j, "sequence") || styler.Match(j, "specify") || styler.Match(j, "table") || styler.Match(j, "task") || styler.Match(j, "fork") || (styler.Match(j, "module") && foldAtModule) || styler.Match(j, "begin")) { levelNext++; } else if (styler.Match(j, "endcase") || styler.Match(j, "endclass") || styler.Match(j, "endfunction") || styler.Match(j, "endgenerate") || styler.Match(j, "endgroup") || styler.Match(j, "endpackage") || styler.Match(j, "endprimitive") || styler.Match(j, "endprogram") || styler.Match(j, "endsequence") || styler.Match(j, "endspecify") || styler.Match(j, "endtable") || styler.Match(j, "endtask") || styler.Match(j, "join") || styler.Match(j, "join_any") || styler.Match(j, "join_none") || (styler.Match(j, "endmodule") && foldAtModule) || (styler.Match(j, "end") && !IsAWordChar(styler.SafeGetCharAt(j+3)))) { levelNext--; } } if (atEOL) { int levelUse = levelCurrent; if (foldAtElse) { levelUse = levelMinCurrent; } int lev = levelUse | levelNext << 16; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if (levelUse < levelNext) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelCurrent = levelNext; levelMinCurrent = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } } static void FoldVerilogDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { FoldNoBoxVerilogDoc(startPos, length, initStyle, styler); } static const char * const verilogWordLists[] = { "Primary keywords and identifiers", "Secondary keywords and identifiers", "System Tasks", "User defined tasks and identifiers", "Unused", 0, }; LexerModule lmVerilog(SCLEX_VERILOG, ColouriseVerilogDoc, "verilog", FoldVerilogDoc, verilogWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexAVS.cxx0000644000175000017500000002056111710634267020772 00000000000000// Scintilla source code edit control /** @file LexAVS.cxx ** Lexer for AviSynth. **/ // Copyright 2012 by Bruno Barbieri // Heavily based on LexPOV by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAWordStart(int ch) { return isalpha(ch) || (ch != ' ' && ch != '\n' && ch != '(' && ch != '.' && ch != ','); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || ch == '.' || ch == '-' || ch == '+'); } static void ColouriseAvsDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &filters = *keywordlists[1]; WordList &plugins = *keywordlists[2]; WordList &functions = *keywordlists[3]; WordList &clipProperties = *keywordlists[4]; WordList &userDefined = *keywordlists[5]; int currentLine = styler.GetLine(startPos); // Initialize the block comment nesting level, if we are inside such a comment. int blockCommentLevel = 0; if (initStyle == SCE_AVS_COMMENTBLOCK || initStyle == SCE_AVS_COMMENTBLOCKN) { blockCommentLevel = styler.GetLineState(currentLine - 1); } // Do not leak onto next line if (initStyle == SCE_AVS_COMMENTLINE) { initStyle = SCE_AVS_DEFAULT; } StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineEnd) { // Update the line state, so it can be seen by next line currentLine = styler.GetLine(sc.currentPos); if (sc.state == SCE_AVS_COMMENTBLOCK || sc.state == SCE_AVS_COMMENTBLOCKN) { // Inside a block comment, we set the line state styler.SetLineState(currentLine, blockCommentLevel); } else { // Reset the line state styler.SetLineState(currentLine, 0); } } // Determine if the current state should terminate. if (sc.state == SCE_AVS_OPERATOR) { sc.SetState(SCE_AVS_DEFAULT); } else if (sc.state == SCE_AVS_NUMBER) { // We stop the number definition on non-numerical non-dot non-sign char if (!IsANumberChar(sc.ch)) { sc.SetState(SCE_AVS_DEFAULT); } } else if (sc.state == SCE_AVS_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_AVS_KEYWORD); } else if (filters.InList(s)) { sc.ChangeState(SCE_AVS_FILTER); } else if (plugins.InList(s)) { sc.ChangeState(SCE_AVS_PLUGIN); } else if (functions.InList(s)) { sc.ChangeState(SCE_AVS_FUNCTION); } else if (clipProperties.InList(s)) { sc.ChangeState(SCE_AVS_CLIPPROP); } else if (userDefined.InList(s)) { sc.ChangeState(SCE_AVS_USERDFN); } sc.SetState(SCE_AVS_DEFAULT); } } else if (sc.state == SCE_AVS_COMMENTBLOCK) { if (sc.Match('/', '*')) { blockCommentLevel++; sc.Forward(); } else if (sc.Match('*', '/') && blockCommentLevel > 0) { blockCommentLevel--; sc.Forward(); if (blockCommentLevel == 0) { sc.ForwardSetState(SCE_AVS_DEFAULT); } } } else if (sc.state == SCE_AVS_COMMENTBLOCKN) { if (sc.Match('[', '*')) { blockCommentLevel++; sc.Forward(); } else if (sc.Match('*', ']') && blockCommentLevel > 0) { blockCommentLevel--; sc.Forward(); if (blockCommentLevel == 0) { sc.ForwardSetState(SCE_AVS_DEFAULT); } } } else if (sc.state == SCE_AVS_COMMENTLINE) { if (sc.atLineEnd) { sc.ForwardSetState(SCE_AVS_DEFAULT); } } else if (sc.state == SCE_AVS_STRING) { if (sc.ch == '\"') { sc.ForwardSetState(SCE_AVS_DEFAULT); } } else if (sc.state == SCE_AVS_TRIPLESTRING) { if (sc.Match("\"\"\"")) { sc.Forward(); sc.Forward(); sc.ForwardSetState(SCE_AVS_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_AVS_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_AVS_NUMBER); } else if (IsADigit(sc.ch) || (sc.ch == ',' && IsADigit(sc.chNext))) { sc.Forward(); sc.SetState(SCE_AVS_NUMBER); } else if (sc.Match('/', '*')) { blockCommentLevel = 1; sc.SetState(SCE_AVS_COMMENTBLOCK); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('[', '*')) { blockCommentLevel = 1; sc.SetState(SCE_AVS_COMMENTBLOCKN); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.ch == '#') { sc.SetState(SCE_AVS_COMMENTLINE); } else if (sc.ch == '\"') { if (sc.Match("\"\"\"")) { sc.SetState(SCE_AVS_TRIPLESTRING); } else { sc.SetState(SCE_AVS_STRING); } } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_AVS_OPERATOR); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_AVS_IDENTIFIER); } } } // End of file: complete any pending changeState if (sc.state == SCE_AVS_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_AVS_KEYWORD); } else if (filters.InList(s)) { sc.ChangeState(SCE_AVS_FILTER); } else if (plugins.InList(s)) { sc.ChangeState(SCE_AVS_PLUGIN); } else if (functions.InList(s)) { sc.ChangeState(SCE_AVS_FUNCTION); } else if (clipProperties.InList(s)) { sc.ChangeState(SCE_AVS_CLIPPROP); } else if (userDefined.InList(s)) { sc.ChangeState(SCE_AVS_USERDFN); } sc.SetState(SCE_AVS_DEFAULT); } } sc.Complete(); } static void FoldAvsDoc( unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && style == SCE_AVS_COMMENTBLOCK) { if (stylePrev != SCE_AVS_COMMENTBLOCK) { levelCurrent++; } else if ((styleNext != SCE_AVS_COMMENTBLOCK) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelCurrent--; } } if (foldComment && style == SCE_AVS_COMMENTBLOCKN) { if (stylePrev != SCE_AVS_COMMENTBLOCKN) { levelCurrent++; } else if ((styleNext != SCE_AVS_COMMENTBLOCKN) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelCurrent--; } } if (style == SCE_AVS_OPERATOR) { if (ch == '{') { levelCurrent++; } else if (ch == '}') { levelCurrent--; } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const avsWordLists[] = { "Keywords", "Filters", "Plugins", "Functions", "Clip properties", "User defined functions", 0, }; LexerModule lmAVS(SCLEX_AVS, ColouriseAvsDoc, "avs", FoldAvsDoc, avsWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexHTML.cxx0000644000175000017500000021001411763437013021075 00000000000000// Scintilla source code edit control /** @file LexHTML.cxx ** Lexer for HTML. **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #define SCE_HA_JS (SCE_HJA_START - SCE_HJ_START) #define SCE_HA_VBS (SCE_HBA_START - SCE_HB_START) #define SCE_HA_PYTHON (SCE_HPA_START - SCE_HP_START) enum script_type { eScriptNone = 0, eScriptJS, eScriptVBS, eScriptPython, eScriptPHP, eScriptXML, eScriptSGML, eScriptSGMLblock, eScriptComment }; enum script_mode { eHtml = 0, eNonHtmlScript, eNonHtmlPreProc, eNonHtmlScriptPreProc }; static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } inline bool IsOperator(int ch) { if (isascii(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || ch == '(' || ch == ')' || ch == '-' || ch == '+' || ch == '=' || ch == '|' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == ':' || ch == ';' || ch == '<' || ch == '>' || ch == ',' || ch == '/' || ch == '?' || ch == '!' || ch == '.' || ch == '~') return true; return false; } static void GetTextSegment(Accessor &styler, unsigned int start, unsigned int end, char *s, size_t len) { unsigned int i = 0; for (; (i < end - start + 1) && (i < len-1); i++) { s[i] = static_cast(MakeLowerCase(styler[start + i])); } s[i] = '\0'; } static const char *GetNextWord(Accessor &styler, unsigned int start, char *s, size_t sLen) { unsigned int i = 0; for (; i < sLen-1; i++) { char ch = static_cast(styler.SafeGetCharAt(start + i)); if ((i == 0) && !IsAWordStart(ch)) break; if ((i > 0) && !IsAWordChar(ch)) break; s[i] = ch; } s[i] = '\0'; return s; } static script_type segIsScriptingIndicator(Accessor &styler, unsigned int start, unsigned int end, script_type prevValue) { char s[100]; GetTextSegment(styler, start, end, s, sizeof(s)); //Platform::DebugPrintf("Scripting indicator [%s]\n", s); if (strstr(s, "src")) // External script return eScriptNone; if (strstr(s, "vbs")) return eScriptVBS; if (strstr(s, "pyth")) return eScriptPython; if (strstr(s, "javas")) return eScriptJS; if (strstr(s, "jscr")) return eScriptJS; if (strstr(s, "php")) return eScriptPHP; if (strstr(s, "xml")) { const char *xml = strstr(s, "xml"); for (const char *t=s; t= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) { return eScriptPython; } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) { return eScriptVBS; } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) { return eScriptJS; } else if ((state >= SCE_HPHP_DEFAULT) && (state <= SCE_HPHP_COMMENTLINE)) { return eScriptPHP; } else if ((state >= SCE_H_SGML_DEFAULT) && (state < SCE_H_SGML_BLOCK_DEFAULT)) { return eScriptSGML; } else if (state == SCE_H_SGML_BLOCK_DEFAULT) { return eScriptSGMLblock; } else { return eScriptNone; } } static int statePrintForState(int state, script_mode inScriptType) { int StateToPrint = state; if (state >= SCE_HJ_START) { if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) { StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_PYTHON); } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) { StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_VBS); } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) { StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_JS); } } return StateToPrint; } static int stateForPrintState(int StateToPrint) { int state; if ((StateToPrint >= SCE_HPA_START) && (StateToPrint <= SCE_HPA_IDENTIFIER)) { state = StateToPrint - SCE_HA_PYTHON; } else if ((StateToPrint >= SCE_HBA_START) && (StateToPrint <= SCE_HBA_STRINGEOL)) { state = StateToPrint - SCE_HA_VBS; } else if ((StateToPrint >= SCE_HJA_START) && (StateToPrint <= SCE_HJA_REGEX)) { state = StateToPrint - SCE_HA_JS; } else { state = StateToPrint; } return state; } static inline bool IsNumber(unsigned int start, Accessor &styler) { return IsADigit(styler[start]) || (styler[start] == '.') || (styler[start] == '-') || (styler[start] == '#'); } static inline bool isStringState(int state) { bool bResult; switch (state) { case SCE_HJ_DOUBLESTRING: case SCE_HJ_SINGLESTRING: case SCE_HJA_DOUBLESTRING: case SCE_HJA_SINGLESTRING: case SCE_HB_STRING: case SCE_HBA_STRING: case SCE_HP_STRING: case SCE_HP_CHARACTER: case SCE_HP_TRIPLE: case SCE_HP_TRIPLEDOUBLE: case SCE_HPA_STRING: case SCE_HPA_CHARACTER: case SCE_HPA_TRIPLE: case SCE_HPA_TRIPLEDOUBLE: case SCE_HPHP_HSTRING: case SCE_HPHP_SIMPLESTRING: case SCE_HPHP_HSTRING_VARIABLE: case SCE_HPHP_COMPLEX_VARIABLE: bResult = true; break; default : bResult = false; break; } return bResult; } static inline bool stateAllowsTermination(int state) { bool allowTermination = !isStringState(state); if (allowTermination) { switch (state) { case SCE_HB_COMMENTLINE: case SCE_HPHP_COMMENT: case SCE_HP_COMMENTLINE: case SCE_HPA_COMMENTLINE: allowTermination = false; } } return allowTermination; } // not really well done, since it's only comments that should lex the %> and <% static inline bool isCommentASPState(int state) { bool bResult; switch (state) { case SCE_HJ_COMMENT: case SCE_HJ_COMMENTLINE: case SCE_HJ_COMMENTDOC: case SCE_HB_COMMENTLINE: case SCE_HP_COMMENTLINE: case SCE_HPHP_COMMENT: case SCE_HPHP_COMMENTLINE: bResult = true; break; default : bResult = false; break; } return bResult; } static void classifyAttribHTML(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) { bool wordIsNumber = IsNumber(start, styler); char chAttr = SCE_H_ATTRIBUTEUNKNOWN; if (wordIsNumber) { chAttr = SCE_H_NUMBER; } else { char s[100]; GetTextSegment(styler, start, end, s, sizeof(s)); if (keywords.InList(s)) chAttr = SCE_H_ATTRIBUTE; } if ((chAttr == SCE_H_ATTRIBUTEUNKNOWN) && !keywords) // No keywords -> all are known chAttr = SCE_H_ATTRIBUTE; styler.ColourTo(end, chAttr); } static int classifyTagHTML(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, bool &tagDontFold, bool caseSensitive, bool isXml, bool allowScripts) { char withSpace[30 + 2] = " "; const char *s = withSpace + 1; // Copy after the '<' unsigned int i = 1; for (unsigned int cPos = start; cPos <= end && i < 30; cPos++) { char ch = styler[cPos]; if ((ch != '<') && (ch != '/')) { withSpace[i++] = caseSensitive ? ch : static_cast(MakeLowerCase(ch)); } } //The following is only a quick hack, to see if this whole thing would work //we first need the tagname with a trailing space... withSpace[i] = ' '; withSpace[i+1] = '\0'; // if the current language is XML, I can fold any tag // if the current language is HTML, I don't want to fold certain tags (input, meta, etc.) //...to find it in the list of no-container-tags tagDontFold = (!isXml) && (NULL != strstr(" area base basefont br col command embed frame hr img input isindex keygen link meta param source track wbr ", withSpace)); //now we can remove the trailing space withSpace[i] = '\0'; // No keywords -> all are known char chAttr = SCE_H_TAGUNKNOWN; if (s[0] == '!') { chAttr = SCE_H_SGML_DEFAULT; } else if (!keywords || keywords.InList(s)) { chAttr = SCE_H_TAG; } styler.ColourTo(end, chAttr); if (chAttr == SCE_H_TAG) { if (allowScripts && 0 == strcmp(s, "script")) { // check to see if this is a self-closing tag by sniffing ahead bool isSelfClose = false; for (unsigned int cPos = end; cPos <= end + 100; cPos++) { char ch = styler.SafeGetCharAt(cPos, '\0'); if (ch == '\0' || ch == '>') break; else if (ch == '/' && styler.SafeGetCharAt(cPos + 1, '\0') == '>') { isSelfClose = true; break; } } // do not enter a script state if the tag self-closed if (!isSelfClose) chAttr = SCE_H_SCRIPT; } else if (!isXml && 0 == strcmp(s, "comment")) { chAttr = SCE_H_COMMENT; } } return chAttr; } static void classifyWordHTJS(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, script_mode inScriptType) { char s[30 + 1]; unsigned int i = 0; for (; i < end - start + 1 && i < 30; i++) { s[i] = styler[start + i]; } s[i] = '\0'; char chAttr = SCE_HJ_WORD; bool wordIsNumber = IsADigit(s[0]) || ((s[0] == '.') && IsADigit(s[1])); if (wordIsNumber) { chAttr = SCE_HJ_NUMBER; } else if (keywords.InList(s)) { chAttr = SCE_HJ_KEYWORD; } styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); } static int classifyWordHTVB(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, script_mode inScriptType) { char chAttr = SCE_HB_IDENTIFIER; bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.'); if (wordIsNumber) chAttr = SCE_HB_NUMBER; else { char s[100]; GetTextSegment(styler, start, end, s, sizeof(s)); if (keywords.InList(s)) { chAttr = SCE_HB_WORD; if (strcmp(s, "rem") == 0) chAttr = SCE_HB_COMMENTLINE; } } styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); if (chAttr == SCE_HB_COMMENTLINE) return SCE_HB_COMMENTLINE; else return SCE_HB_DEFAULT; } static void classifyWordHTPy(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord, script_mode inScriptType, bool isMako) { bool wordIsNumber = IsADigit(styler[start]); char s[30 + 1]; unsigned int i = 0; for (; i < end - start + 1 && i < 30; i++) { s[i] = styler[start + i]; } s[i] = '\0'; char chAttr = SCE_HP_IDENTIFIER; if (0 == strcmp(prevWord, "class")) chAttr = SCE_HP_CLASSNAME; else if (0 == strcmp(prevWord, "def")) chAttr = SCE_HP_DEFNAME; else if (wordIsNumber) chAttr = SCE_HP_NUMBER; else if (keywords.InList(s)) chAttr = SCE_HP_WORD; else if (isMako && 0 == strcmp(s, "block")) chAttr = SCE_HP_WORD; styler.ColourTo(end, statePrintForState(chAttr, inScriptType)); strcpy(prevWord, s); } // Update the word colour to default or keyword // Called when in a PHP word static void classifyWordHTPHP(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) { char chAttr = SCE_HPHP_DEFAULT; bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.' && start+1 <= end && IsADigit(styler[start+1])); if (wordIsNumber) chAttr = SCE_HPHP_NUMBER; else { char s[100]; GetTextSegment(styler, start, end, s, sizeof(s)); if (keywords.InList(s)) chAttr = SCE_HPHP_WORD; } styler.ColourTo(end, chAttr); } static bool isWordHSGML(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) { char s[30 + 1]; unsigned int i = 0; for (; i < end - start + 1 && i < 30; i++) { s[i] = styler[start + i]; } s[i] = '\0'; return keywords.InList(s); } static bool isWordCdata(unsigned int start, unsigned int end, Accessor &styler) { char s[30 + 1]; unsigned int i = 0; for (; i < end - start + 1 && i < 30; i++) { s[i] = styler[start + i]; } s[i] = '\0'; return (0 == strcmp(s, "[CDATA[")); } // Return the first state to reach when entering a scripting language static int StateForScript(script_type scriptLanguage) { int Result; switch (scriptLanguage) { case eScriptVBS: Result = SCE_HB_START; break; case eScriptPython: Result = SCE_HP_START; break; case eScriptPHP: Result = SCE_HPHP_DEFAULT; break; case eScriptXML: Result = SCE_H_TAGUNKNOWN; break; case eScriptSGML: Result = SCE_H_SGML_DEFAULT; break; case eScriptComment: Result = SCE_H_COMMENT; break; default : Result = SCE_HJ_START; break; } return Result; } static inline bool ishtmlwordchar(int ch) { return !isascii(ch) || (isalnum(ch) || ch == '.' || ch == '-' || ch == '_' || ch == ':' || ch == '!' || ch == '#'); } static inline bool issgmlwordchar(int ch) { return !isascii(ch) || (isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '['); } static inline bool IsPhpWordStart(int ch) { return (isascii(ch) && (isalpha(ch) || (ch == '_'))) || (ch >= 0x7f); } static inline bool IsPhpWordChar(int ch) { return IsADigit(ch) || IsPhpWordStart(ch); } static bool InTagState(int state) { return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN || state == SCE_H_SCRIPT || state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN || state == SCE_H_NUMBER || state == SCE_H_OTHER || state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING; } static bool IsCommentState(const int state) { return state == SCE_H_COMMENT || state == SCE_H_SGML_COMMENT; } static bool IsScriptCommentState(const int state) { return state == SCE_HJ_COMMENT || state == SCE_HJ_COMMENTLINE || state == SCE_HJA_COMMENT || state == SCE_HJA_COMMENTLINE || state == SCE_HB_COMMENTLINE || state == SCE_HBA_COMMENTLINE; } static bool isLineEnd(int ch) { return ch == '\r' || ch == '\n'; } static bool isOKBeforeRE(int ch) { return (ch == '(') || (ch == '=') || (ch == ','); } static bool isMakoBlockEnd(const int ch, const int chNext, const char *blockType) { if (strlen(blockType) == 0) { return ((ch == '%') && (chNext == '>')); } else if ((0 == strcmp(blockType, "inherit")) || (0 == strcmp(blockType, "namespace")) || (0 == strcmp(blockType, "include")) || (0 == strcmp(blockType, "page"))) { return ((ch == '/') && (chNext == '>')); } else if (0 == strcmp(blockType, "%")) { if (ch == '/' && isLineEnd(chNext)) return 1; else return isLineEnd(ch); } else if (0 == strcmp(blockType, "{")) { return ch == '}'; } else { return (ch == '>'); } } static bool isDjangoBlockEnd(const int ch, const int chNext, const char *blockType) { if (strlen(blockType) == 0) { return 0; } else if (0 == strcmp(blockType, "%")) { return ((ch == '%') && (chNext == '}')); } else if (0 == strcmp(blockType, "{")) { return ((ch == '}') && (chNext == '}')); } else { return 0; } } static bool isPHPStringState(int state) { return (state == SCE_HPHP_HSTRING) || (state == SCE_HPHP_SIMPLESTRING) || (state == SCE_HPHP_HSTRING_VARIABLE) || (state == SCE_HPHP_COMPLEX_VARIABLE); } static int FindPhpStringDelimiter(char *phpStringDelimiter, const int phpStringDelimiterSize, int i, const int lengthDoc, Accessor &styler, bool &isSimpleString) { int j; const int beginning = i - 1; bool isValidSimpleString = false; while (i < lengthDoc && (styler[i] == ' ' || styler[i] == '\t')) i++; char ch = styler.SafeGetCharAt(i); const char chNext = styler.SafeGetCharAt(i + 1); if (!IsPhpWordStart(ch)) { if (ch == '\'' && IsPhpWordStart(chNext)) { i++; ch = chNext; isSimpleString = true; } else { phpStringDelimiter[0] = '\0'; return beginning; } } phpStringDelimiter[0] = ch; i++; for (j = i; j < lengthDoc && !isLineEnd(styler[j]); j++) { if (!IsPhpWordChar(styler[j])) { if (isSimpleString && (styler[j] == '\'') && isLineEnd(styler.SafeGetCharAt(j + 1))) { isValidSimpleString = true; j++; break; } else { phpStringDelimiter[0] = '\0'; return beginning; } } if (j - i < phpStringDelimiterSize - 2) phpStringDelimiter[j-i+1] = styler[j]; else i++; } if (isSimpleString && !isValidSimpleString) { phpStringDelimiter[0] = '\0'; return beginning; } phpStringDelimiter[j-i+1 - (isSimpleString ? 1 : 0)] = '\0'; return j - 1; } static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler, bool isXml) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; WordList &keywords5 = *keywordlists[4]; WordList &keywords6 = *keywordlists[5]; // SGML (DTD) keywords // Lexer for HTML requires more lexical states (8 bits worth) than most lexers styler.StartAt(startPos, static_cast(STYLE_MAX)); char prevWord[200]; prevWord[0] = '\0'; char phpStringDelimiter[200]; // PHP is not limited in length, we are phpStringDelimiter[0] = '\0'; int StateToPrint = initStyle; int state = stateForPrintState(StateToPrint); char makoBlockType[200]; makoBlockType[0] = '\0'; int makoComment = 0; char djangoBlockType[2]; djangoBlockType[0] = '\0'; // If inside a tag, it may be a script tag, so reread from the start of line starting tag to ensure any language tags are seen if (InTagState(state)) { while ((startPos > 0) && (InTagState(styler.StyleAt(startPos - 1)))) { int backLineStart = styler.LineStart(styler.GetLine(startPos-1)); length += startPos - backLineStart; startPos = backLineStart; } state = SCE_H_DEFAULT; } // String can be heredoc, must find a delimiter first. Reread from beginning of line containing the string, to get the correct lineState if (isPHPStringState(state)) { while (startPos > 0 && (isPHPStringState(state) || !isLineEnd(styler[startPos - 1]))) { startPos--; length++; state = styler.StyleAt(startPos); } if (startPos == 0) state = SCE_H_DEFAULT; } styler.StartAt(startPos, static_cast(STYLE_MAX)); int lineCurrent = styler.GetLine(startPos); int lineState; if (lineCurrent > 0) { lineState = styler.GetLineState(lineCurrent-1); } else { // Default client and ASP scripting language is JavaScript lineState = eScriptJS << 8; // property asp.default.language // Script in ASP code is initially assumed to be in JavaScript. // To change this to VBScript set asp.default.language to 2. Python is 3. lineState |= styler.GetPropertyInt("asp.default.language", eScriptJS) << 4; } script_mode inScriptType = script_mode((lineState >> 0) & 0x03); // 2 bits of scripting mode bool tagOpened = (lineState >> 2) & 0x01; // 1 bit to know if we are in an opened tag bool tagClosing = (lineState >> 3) & 0x01; // 1 bit to know if we are in a closing tag bool tagDontFold = false; //some HTML tags should not be folded script_type aspScript = script_type((lineState >> 4) & 0x0F); // 4 bits of script name script_type clientScript = script_type((lineState >> 8) & 0x0F); // 4 bits of script name int beforePreProc = (lineState >> 12) & 0xFF; // 8 bits of state script_type scriptLanguage = ScriptOfState(state); // If eNonHtmlScript coincides with SCE_H_COMMENT, assume eScriptComment if (inScriptType == eNonHtmlScript && state == SCE_H_COMMENT) { scriptLanguage = eScriptComment; } script_type beforeLanguage = ScriptOfState(beforePreProc); // property fold.html // Folding is turned on or off for HTML and XML files with this option. // The fold option must also be on for folding to occur. const bool foldHTML = styler.GetPropertyInt("fold.html", 0) != 0; const bool fold = foldHTML && styler.GetPropertyInt("fold", 0); // property fold.html.preprocessor // Folding is turned on or off for scripts embedded in HTML files with this option. // The default is on. const bool foldHTMLPreprocessor = foldHTML && styler.GetPropertyInt("fold.html.preprocessor", 1); const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; // property fold.hypertext.comment // Allow folding for comments in scripts embedded in HTML. // The default is off. const bool foldComment = fold && styler.GetPropertyInt("fold.hypertext.comment", 0) != 0; // property fold.hypertext.heredoc // Allow folding for heredocs in scripts embedded in HTML. // The default is off. const bool foldHeredoc = fold && styler.GetPropertyInt("fold.hypertext.heredoc", 0) != 0; // property html.tags.case.sensitive // For XML and HTML, setting this property to 1 will make tags match in a case // sensitive way which is the expected behaviour for XML and XHTML. const bool caseSensitive = styler.GetPropertyInt("html.tags.case.sensitive", 0) != 0; // property lexer.xml.allow.scripts // Set to 0 to disable scripts in XML. const bool allowScripts = styler.GetPropertyInt("lexer.xml.allow.scripts", 1) != 0; // property lexer.html.mako // Set to 1 to enable the mako template language. const bool isMako = styler.GetPropertyInt("lexer.html.mako", 0) != 0; // property lexer.html.django // Set to 1 to enable the django template language. const bool isDjango = styler.GetPropertyInt("lexer.html.django", 0) != 0; const CharacterSet setHTMLWord(CharacterSet::setAlphaNum, ".-_:!#", 0x80, true); const CharacterSet setTagContinue(CharacterSet::setAlphaNum, ".-_:!#[", 0x80, true); const CharacterSet setAttributeContinue(CharacterSet::setAlphaNum, ".-_:!#/", 0x80, true); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; int visibleChars = 0; int lineStartVisibleChars = 0; int chPrev = ' '; int ch = ' '; int chPrevNonWhite = ' '; // look back to set chPrevNonWhite properly for better regex colouring if (scriptLanguage == eScriptJS && startPos > 0) { int back = startPos; int style = 0; while (--back) { style = styler.StyleAt(back); if (style < SCE_HJ_DEFAULT || style > SCE_HJ_COMMENTDOC) // includes SCE_HJ_COMMENT & SCE_HJ_COMMENTLINE break; } if (style == SCE_HJ_SYMBOLS) { chPrevNonWhite = static_cast(styler.SafeGetCharAt(back)); } } styler.StartSegment(startPos); const int lengthDoc = startPos + length; for (int i = startPos; i < lengthDoc; i++) { const int chPrev2 = chPrev; chPrev = ch; if (!IsASpace(ch) && state != SCE_HJ_COMMENT && state != SCE_HJ_COMMENTLINE && state != SCE_HJ_COMMENTDOC) chPrevNonWhite = ch; ch = static_cast(styler[i]); int chNext = static_cast(styler.SafeGetCharAt(i + 1)); const int chNext2 = static_cast(styler.SafeGetCharAt(i + 2)); // Handle DBCS codepages if (styler.IsLeadByte(static_cast(ch))) { chPrev = ' '; i += 1; continue; } if ((!IsASpace(ch) || !foldCompact) && fold) visibleChars++; if (!IsASpace(ch)) lineStartVisibleChars++; // decide what is the current state to print (depending of the script tag) StateToPrint = statePrintForState(state, inScriptType); // handle script folding if (fold) { switch (scriptLanguage) { case eScriptJS: case eScriptPHP: //not currently supported case eScriptVBS: if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC) && (!isStringState(state))) { //Platform::DebugPrintf("state=%d, StateToPrint=%d, initStyle=%d\n", state, StateToPrint, initStyle); //if ((state == SCE_HPHP_OPERATOR) || (state == SCE_HPHP_DEFAULT) || (state == SCE_HJ_SYMBOLS) || (state == SCE_HJ_START) || (state == SCE_HJ_DEFAULT)) { if (ch == '#') { int j = i + 1; while ((j < lengthDoc) && IsASpaceOrTab(styler.SafeGetCharAt(j))) { j++; } if (styler.Match(j, "region") || styler.Match(j, "if")) { levelCurrent++; } else if (styler.Match(j, "end")) { levelCurrent--; } } else if ((ch == '{') || (ch == '}') || (foldComment && (ch == '/') && (chNext == '*'))) { levelCurrent += (((ch == '{') || (ch == '/')) ? 1 : -1); } } else if (((state == SCE_HPHP_COMMENT) || (state == SCE_HJ_COMMENT)) && foldComment && (ch == '*') && (chNext == '/')) { levelCurrent--; } break; case eScriptPython: if (state != SCE_HP_COMMENTLINE && !isMako) { if ((ch == ':') && ((chNext == '\n') || (chNext == '\r' && chNext2 == '\n'))) { levelCurrent++; } else if ((ch == '\n') && !((chNext == '\r') && (chNext2 == '\n')) && (chNext != '\n')) { // check if the number of tabs is lower than the level int Findlevel = (levelCurrent & ~SC_FOLDLEVELBASE) * 8; for (int j = 0; Findlevel > 0; j++) { char chTmp = styler.SafeGetCharAt(i + j + 1); if (chTmp == '\t') { Findlevel -= 8; } else if (chTmp == ' ') { Findlevel--; } else { break; } } if (Findlevel > 0) { levelCurrent -= Findlevel / 8; if (Findlevel % 8) levelCurrent--; } } } break; default: break; } } if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix) // Avoid triggering two times on Dos/Win // New line -> record any line state onto /next/ line if (fold) { int lev = levelPrev; if (visibleChars == 0) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; styler.SetLevel(lineCurrent, lev); visibleChars = 0; levelPrev = levelCurrent; } styler.SetLineState(lineCurrent, ((inScriptType & 0x03) << 0) | ((tagOpened & 0x01) << 2) | ((tagClosing & 0x01) << 3) | ((aspScript & 0x0F) << 4) | ((clientScript & 0x0F) << 8) | ((beforePreProc & 0xFF) << 12)); lineCurrent++; lineStartVisibleChars = 0; } // handle start of Mako comment line if (isMako && ch == '#' && chNext == '#') { makoComment = 1; } // handle end of Mako comment line else if (isMako && makoComment && (ch == '\r' || ch == '\n')) { makoComment = 0; styler.ColourTo(i, SCE_HP_COMMENTLINE); state = SCE_HP_DEFAULT; } // Allow falling through to mako handling code if newline is going to end a block if (((ch == '\r' && chNext != '\n') || (ch == '\n')) && (!isMako || (0 != strcmp(makoBlockType, "%")))) { } // generic end of script processing else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) { // Check if it's the end of the script tag (or any other HTML tag) switch (state) { // in these cases, you can embed HTML tags (to confirm !!!!!!!!!!!!!!!!!!!!!!) case SCE_H_DOUBLESTRING: case SCE_H_SINGLESTRING: case SCE_HJ_COMMENT: case SCE_HJ_COMMENTDOC: //case SCE_HJ_COMMENTLINE: // removed as this is a common thing done to hide // the end of script marker from some JS interpreters. case SCE_HB_COMMENTLINE: case SCE_HBA_COMMENTLINE: case SCE_HJ_DOUBLESTRING: case SCE_HJ_SINGLESTRING: case SCE_HJ_REGEX: case SCE_HB_STRING: case SCE_HBA_STRING: case SCE_HP_STRING: case SCE_HP_TRIPLE: case SCE_HP_TRIPLEDOUBLE: case SCE_HPHP_HSTRING: case SCE_HPHP_SIMPLESTRING: case SCE_HPHP_COMMENT: case SCE_HPHP_COMMENTLINE: break; default : // check if the closing tag is a script tag if (const char *tag = state == SCE_HJ_COMMENTLINE || isXml ? "script" : state == SCE_H_COMMENT ? "comment" : 0) { int j = i + 2; int chr; do { chr = static_cast(*tag++); } while (chr != 0 && chr == MakeLowerCase(styler.SafeGetCharAt(j++))); if (chr != 0) break; } // closing tag of the script (it's a closing HTML tag anyway) styler.ColourTo(i - 1, StateToPrint); state = SCE_H_TAGUNKNOWN; inScriptType = eHtml; scriptLanguage = eScriptNone; clientScript = eScriptJS; i += 2; visibleChars += 2; tagClosing = true; continue; } } ///////////////////////////////////// // handle the start of PHP pre-processor = Non-HTML else if ((state != SCE_H_ASPAT) && !isPHPStringState(state) && (state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (ch == '<') && (chNext == '?') && !IsScriptCommentState(state)) { beforeLanguage = scriptLanguage; scriptLanguage = segIsScriptingIndicator(styler, i + 2, i + 6, isXml ? eScriptXML : eScriptPHP); if (scriptLanguage != eScriptPHP && isStringState(state)) continue; styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; i++; visibleChars++; i += PrintScriptingIndicatorOffset(styler, styler.GetStartSegment() + 2, i + 6); if (scriptLanguage == eScriptXML) styler.ColourTo(i, SCE_H_XMLSTART); else styler.ColourTo(i, SCE_H_QUESTION); state = StateForScript(scriptLanguage); if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; // Fold whole script, but not if the XML first tag (all XML-like tags in this case) if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) { levelCurrent++; } // should be better ch = static_cast(styler.SafeGetCharAt(i)); continue; } // handle the start Mako template Python code else if (isMako && scriptLanguage == eScriptNone && ((ch == '<' && chNext == '%') || (lineStartVisibleChars == 1 && ch == '%') || (lineStartVisibleChars == 1 && ch == '/' && chNext == '%') || (ch == '$' && chNext == '{') || (ch == '<' && chNext == '/' && chNext2 == '%'))) { if (ch == '%' || ch == '/') strcpy(makoBlockType, "%"); else if (ch == '$') strcpy(makoBlockType, "{"); else if (chNext == '/') GetNextWord(styler, i+3, makoBlockType, sizeof(makoBlockType)); else GetNextWord(styler, i+2, makoBlockType, sizeof(makoBlockType)); styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; if (chNext == '/') { i += 2; visibleChars += 2; } else if (ch != '%') { i++; visibleChars++; } state = SCE_HP_START; scriptLanguage = eScriptPython; styler.ColourTo(i, SCE_H_ASP); if (ch != '%' && ch != '$' && ch != '/') { i += static_cast(strlen(makoBlockType)); visibleChars += static_cast(strlen(makoBlockType)); if (keywords4.InList(makoBlockType)) styler.ColourTo(i, SCE_HP_WORD); else styler.ColourTo(i, SCE_H_TAGUNKNOWN); } ch = static_cast(styler.SafeGetCharAt(i)); continue; } // handle the start/end of Django comment else if (isDjango && state != SCE_H_COMMENT && (ch == '{' && chNext == '#')) { styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; beforeLanguage = scriptLanguage; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; i += 1; visibleChars += 1; scriptLanguage = eScriptComment; state = SCE_H_COMMENT; styler.ColourTo(i, SCE_H_ASP); ch = static_cast(styler.SafeGetCharAt(i)); continue; } else if (isDjango && state == SCE_H_COMMENT && (ch == '#' && chNext == '}')) { styler.ColourTo(i - 1, StateToPrint); i += 1; visibleChars += 1; styler.ColourTo(i, SCE_H_ASP); state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; scriptLanguage = beforeLanguage; continue; } // handle the start Django template code else if (isDjango && scriptLanguage != eScriptPython && (ch == '{' && (chNext == '%' || chNext == '{'))) { if (chNext == '%') strcpy(djangoBlockType, "%"); else strcpy(djangoBlockType, "{"); styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; i += 1; visibleChars += 1; state = SCE_HP_START; beforeLanguage = scriptLanguage; scriptLanguage = eScriptPython; styler.ColourTo(i, SCE_H_ASP); ch = static_cast(styler.SafeGetCharAt(i)); continue; } // handle the start of ASP pre-processor = Non-HTML else if (!isMako && !isDjango && !isCommentASPState(state) && (ch == '<') && (chNext == '%') && !isPHPStringState(state)) { styler.ColourTo(i - 1, StateToPrint); beforePreProc = state; if (inScriptType == eNonHtmlScript) inScriptType = eNonHtmlScriptPreProc; else inScriptType = eNonHtmlPreProc; if (chNext2 == '@') { i += 2; // place as if it was the second next char treated visibleChars += 2; state = SCE_H_ASPAT; } else if ((chNext2 == '-') && (styler.SafeGetCharAt(i + 3) == '-')) { styler.ColourTo(i + 3, SCE_H_ASP); state = SCE_H_XCCOMMENT; scriptLanguage = eScriptVBS; continue; } else { if (chNext2 == '=') { i += 2; // place as if it was the second next char treated visibleChars += 2; } else { i++; // place as if it was the next char treated visibleChars++; } state = StateForScript(aspScript); } scriptLanguage = eScriptVBS; styler.ColourTo(i, SCE_H_ASP); // fold whole script if (foldHTMLPreprocessor) levelCurrent++; // should be better ch = static_cast(styler.SafeGetCharAt(i)); continue; } ///////////////////////////////////// // handle the start of SGML language (DTD) else if (((scriptLanguage == eScriptNone) || (scriptLanguage == eScriptXML)) && (chPrev == '<') && (ch == '!') && (StateToPrint != SCE_H_CDATA) && (!IsCommentState(StateToPrint)) && (!IsScriptCommentState(StateToPrint))) { beforePreProc = state; styler.ColourTo(i - 2, StateToPrint); if ((chNext == '-') && (chNext2 == '-')) { state = SCE_H_COMMENT; // wait for a pending command styler.ColourTo(i + 2, SCE_H_COMMENT); i += 2; // follow styling after the -- } else if (isWordCdata(i + 1, i + 7, styler)) { state = SCE_H_CDATA; } else { styler.ColourTo(i, SCE_H_SGML_DEFAULT); // ') { i++; visibleChars++; } else if (0 == strcmp(makoBlockType, "%") && ch == '/') { i++; visibleChars++; } if (0 != strcmp(makoBlockType, "%") || ch == '/') { styler.ColourTo(i, SCE_H_ASP); } state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; scriptLanguage = eScriptNone; continue; } // handle the end of Django template code else if (isDjango && ((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) && (scriptLanguage != eScriptNone) && stateAllowsTermination(state) && isDjangoBlockEnd(ch, chNext, djangoBlockType)) { if (state == SCE_H_ASPAT) { aspScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, aspScript); } if (state == SCE_HP_WORD) { classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); } else { styler.ColourTo(i - 1, StateToPrint); } i += 1; visibleChars += 1; styler.ColourTo(i, SCE_H_ASP); state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; scriptLanguage = beforeLanguage; continue; } // handle the end of a pre-processor = Non-HTML else if ((!isMako && !isDjango && ((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) && (((scriptLanguage != eScriptNone) && stateAllowsTermination(state))) && (((ch == '%') || (ch == '?')) && (chNext == '>'))) || ((scriptLanguage == eScriptSGML) && (ch == '>') && (state != SCE_H_SGML_COMMENT))) { if (state == SCE_H_ASPAT) { aspScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, aspScript); } // Bounce out of any ASP mode switch (state) { case SCE_HJ_WORD: classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType); break; case SCE_HB_WORD: classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType); break; case SCE_HP_WORD: classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); break; case SCE_HPHP_WORD: classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler); break; case SCE_H_XCCOMMENT: styler.ColourTo(i - 1, state); break; default : styler.ColourTo(i - 1, StateToPrint); break; } if (scriptLanguage != eScriptSGML) { i++; visibleChars++; } if (ch == '%') styler.ColourTo(i, SCE_H_ASP); else if (scriptLanguage == eScriptXML) styler.ColourTo(i, SCE_H_XMLEND); else if (scriptLanguage == eScriptSGML) styler.ColourTo(i, SCE_H_SGML_DEFAULT); else styler.ColourTo(i, SCE_H_QUESTION); state = beforePreProc; if (inScriptType == eNonHtmlScriptPreProc) inScriptType = eNonHtmlScript; else inScriptType = eHtml; // Unfold all scripting languages, except for XML tag if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) { levelCurrent--; } scriptLanguage = beforeLanguage; continue; } ///////////////////////////////////// switch (state) { case SCE_H_DEFAULT: if (ch == '<') { // in HTML, fold on tag open and unfold on tag close tagOpened = true; tagClosing = (chNext == '/'); styler.ColourTo(i - 1, StateToPrint); if (chNext != '!') state = SCE_H_TAGUNKNOWN; } else if (ch == '&') { styler.ColourTo(i - 1, SCE_H_DEFAULT); state = SCE_H_ENTITY; } break; case SCE_H_SGML_DEFAULT: case SCE_H_SGML_BLOCK_DEFAULT: // if (scriptLanguage == eScriptSGMLblock) // StateToPrint = SCE_H_SGML_BLOCK_DEFAULT; if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_DOUBLESTRING; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_SIMPLESTRING; } else if ((ch == '-') && (chPrev == '-')) { if (static_cast(styler.GetStartSegment()) <= (i - 2)) { styler.ColourTo(i - 2, StateToPrint); } state = SCE_H_SGML_COMMENT; } else if (isascii(ch) && isalpha(ch) && (chPrev == '%')) { styler.ColourTo(i - 2, StateToPrint); state = SCE_H_SGML_ENTITY; } else if (ch == '#') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_SPECIAL; } else if (ch == '[') { styler.ColourTo(i - 1, StateToPrint); scriptLanguage = eScriptSGMLblock; state = SCE_H_SGML_BLOCK_DEFAULT; } else if (ch == ']') { if (scriptLanguage == eScriptSGMLblock) { styler.ColourTo(i, StateToPrint); scriptLanguage = eScriptSGML; } else { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, SCE_H_SGML_ERROR); } state = SCE_H_SGML_DEFAULT; } else if (scriptLanguage == eScriptSGMLblock) { if ((ch == '!') && (chPrev == '<')) { styler.ColourTo(i - 2, StateToPrint); styler.ColourTo(i, SCE_H_SGML_DEFAULT); state = SCE_H_SGML_COMMAND; } else if (ch == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, SCE_H_SGML_DEFAULT); } } break; case SCE_H_SGML_COMMAND: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i - 2, StateToPrint); state = SCE_H_SGML_COMMENT; } else if (!issgmlwordchar(ch)) { if (isWordHSGML(styler.GetStartSegment(), i - 1, keywords6, styler)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SGML_1ST_PARAM; } else { state = SCE_H_SGML_ERROR; } } break; case SCE_H_SGML_1ST_PARAM: // wait for the beginning of the word if ((ch == '-') && (chPrev == '-')) { if (scriptLanguage == eScriptSGMLblock) { styler.ColourTo(i - 2, SCE_H_SGML_BLOCK_DEFAULT); } else { styler.ColourTo(i - 2, SCE_H_SGML_DEFAULT); } state = SCE_H_SGML_1ST_PARAM_COMMENT; } else if (issgmlwordchar(ch)) { if (scriptLanguage == eScriptSGMLblock) { styler.ColourTo(i - 1, SCE_H_SGML_BLOCK_DEFAULT); } else { styler.ColourTo(i - 1, SCE_H_SGML_DEFAULT); } // find the length of the word int size = 1; while (setHTMLWord.Contains(static_cast(styler.SafeGetCharAt(i + size)))) size++; styler.ColourTo(i + size - 1, StateToPrint); i += size - 1; visibleChars += size - 1; ch = static_cast(styler.SafeGetCharAt(i)); if (scriptLanguage == eScriptSGMLblock) { state = SCE_H_SGML_BLOCK_DEFAULT; } else { state = SCE_H_SGML_DEFAULT; } continue; } break; case SCE_H_SGML_ERROR: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i - 2, StateToPrint); state = SCE_H_SGML_COMMENT; } case SCE_H_SGML_DOUBLESTRING: if (ch == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_SGML_SIMPLESTRING: if (ch == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_SGML_COMMENT: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_CDATA: if ((chPrev2 == ']') && (chPrev == ']') && (ch == '>')) { styler.ColourTo(i, StateToPrint); state = SCE_H_DEFAULT; levelCurrent--; } break; case SCE_H_COMMENT: if ((scriptLanguage != eScriptComment) && (chPrev2 == '-') && (chPrev == '-') && (ch == '>')) { styler.ColourTo(i, StateToPrint); state = SCE_H_DEFAULT; levelCurrent--; } break; case SCE_H_SGML_1ST_PARAM_COMMENT: if ((ch == '-') && (chPrev == '-')) { styler.ColourTo(i, SCE_H_SGML_COMMENT); state = SCE_H_SGML_1ST_PARAM; } break; case SCE_H_SGML_SPECIAL: if (!(isascii(ch) && isupper(ch))) { styler.ColourTo(i - 1, StateToPrint); if (isalnum(ch)) { state = SCE_H_SGML_ERROR; } else { state = SCE_H_SGML_DEFAULT; } } break; case SCE_H_SGML_ENTITY: if (ch == ';') { styler.ColourTo(i, StateToPrint); state = SCE_H_SGML_DEFAULT; } else if (!(isascii(ch) && isalnum(ch)) && ch != '-' && ch != '.') { styler.ColourTo(i, SCE_H_SGML_ERROR); state = SCE_H_SGML_DEFAULT; } break; case SCE_H_ENTITY: if (ch == ';') { styler.ColourTo(i, StateToPrint); state = SCE_H_DEFAULT; } if (ch != '#' && !(isascii(ch) && isalnum(ch)) // Should check that '#' follows '&', but it is unlikely anyway... && ch != '.' && ch != '-' && ch != '_' && ch != ':') { // valid in XML if (!isascii(ch)) // Possibly start of a multibyte character so don't allow this byte to be in entity style styler.ColourTo(i-1, SCE_H_TAGUNKNOWN); else styler.ColourTo(i, SCE_H_TAGUNKNOWN); state = SCE_H_DEFAULT; } break; case SCE_H_TAGUNKNOWN: if (!setTagContinue.Contains(ch) && !((ch == '/') && (chPrev == '<'))) { int eClass = classifyTagHTML(styler.GetStartSegment(), i - 1, keywords, styler, tagDontFold, caseSensitive, isXml, allowScripts); if (eClass == SCE_H_SCRIPT || eClass == SCE_H_COMMENT) { if (!tagClosing) { inScriptType = eNonHtmlScript; scriptLanguage = eClass == SCE_H_SCRIPT ? clientScript : eScriptComment; } else { scriptLanguage = eScriptNone; } eClass = SCE_H_TAG; } if (ch == '>') { styler.ColourTo(i, eClass); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else if (ch == '/' && chNext == '>') { if (eClass == SCE_H_TAGUNKNOWN) { styler.ColourTo(i + 1, SCE_H_TAGUNKNOWN); } else { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i + 1, SCE_H_TAGEND); } i++; ch = chNext; state = SCE_H_DEFAULT; tagOpened = false; } else { if (eClass != SCE_H_TAGUNKNOWN) { if (eClass == SCE_H_SGML_DEFAULT) { state = SCE_H_SGML_DEFAULT; } else { state = SCE_H_OTHER; } } } } break; case SCE_H_ATTRIBUTE: if (!setAttributeContinue.Contains(ch)) { if (inScriptType == eNonHtmlScript) { int scriptLanguagePrev = scriptLanguage; clientScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, scriptLanguage); scriptLanguage = clientScript; if ((scriptLanguagePrev != scriptLanguage) && (scriptLanguage == eScriptNone)) inScriptType = eHtml; } classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler); if (ch == '>') { styler.ColourTo(i, SCE_H_TAG); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else if (ch == '=') { styler.ColourTo(i, SCE_H_OTHER); state = SCE_H_VALUE; } else { state = SCE_H_OTHER; } } break; case SCE_H_OTHER: if (ch == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, SCE_H_TAG); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_DOUBLESTRING; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_SINGLESTRING; } else if (ch == '=') { styler.ColourTo(i, StateToPrint); state = SCE_H_VALUE; } else if (ch == '/' && chNext == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i + 1, SCE_H_TAGEND); i++; ch = chNext; state = SCE_H_DEFAULT; tagOpened = false; } else if (ch == '?' && chNext == '>') { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i + 1, SCE_H_XMLEND); i++; ch = chNext; state = SCE_H_DEFAULT; } else if (setHTMLWord.Contains(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_H_ATTRIBUTE; } break; case SCE_H_DOUBLESTRING: if (ch == '\"') { if (inScriptType == eNonHtmlScript) { scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); } styler.ColourTo(i, SCE_H_DOUBLESTRING); state = SCE_H_OTHER; } break; case SCE_H_SINGLESTRING: if (ch == '\'') { if (inScriptType == eNonHtmlScript) { scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage); } styler.ColourTo(i, SCE_H_SINGLESTRING); state = SCE_H_OTHER; } break; case SCE_H_VALUE: if (!setHTMLWord.Contains(ch)) { if (ch == '\"' && chPrev == '=') { // Should really test for being first character state = SCE_H_DOUBLESTRING; } else if (ch == '\'' && chPrev == '=') { state = SCE_H_SINGLESTRING; } else { if (IsNumber(styler.GetStartSegment(), styler)) { styler.ColourTo(i - 1, SCE_H_NUMBER); } else { styler.ColourTo(i - 1, StateToPrint); } if (ch == '>') { styler.ColourTo(i, SCE_H_TAG); if (inScriptType == eNonHtmlScript) { state = StateForScript(scriptLanguage); } else { state = SCE_H_DEFAULT; } tagOpened = false; if (!tagDontFold) { if (tagClosing) { levelCurrent--; } else { levelCurrent++; } } tagClosing = false; } else { state = SCE_H_OTHER; } } } break; case SCE_HJ_DEFAULT: case SCE_HJ_START: case SCE_HJ_SYMBOLS: if (IsAWordStart(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_WORD; } else if (ch == '/' && chNext == '*') { styler.ColourTo(i - 1, StateToPrint); if (chNext2 == '*') state = SCE_HJ_COMMENTDOC; else state = SCE_HJ_COMMENT; if (chNext2 == '/') { // Eat the * so it isn't used for the end of the comment i++; } } else if (ch == '/' && chNext == '/') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; } else if (ch == '/' && isOKBeforeRE(chPrevNonWhite)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_REGEX; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_DOUBLESTRING; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_SINGLESTRING; } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && styler.SafeGetCharAt(i + 3) == '-') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (IsOperator(ch)) { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); state = SCE_HJ_DEFAULT; } else if ((ch == ' ') || (ch == '\t')) { if (state == SCE_HJ_START) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_DEFAULT; } } break; case SCE_HJ_WORD: if (!IsAWordChar(ch)) { classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType); //styler.ColourTo(i - 1, eHTJSKeyword); state = SCE_HJ_DEFAULT; if (ch == '/' && chNext == '*') { if (chNext2 == '*') state = SCE_HJ_COMMENTDOC; else state = SCE_HJ_COMMENT; } else if (ch == '/' && chNext == '/') { state = SCE_HJ_COMMENTLINE; } else if (ch == '\"') { state = SCE_HJ_DOUBLESTRING; } else if (ch == '\'') { state = SCE_HJ_SINGLESTRING; } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); state = SCE_HJ_DEFAULT; } } break; case SCE_HJ_COMMENT: case SCE_HJ_COMMENTDOC: if (ch == '/' && chPrev == '*') { styler.ColourTo(i, StateToPrint); state = SCE_HJ_DEFAULT; ch = ' '; } break; case SCE_HJ_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, statePrintForState(SCE_HJ_COMMENTLINE, inScriptType)); state = SCE_HJ_DEFAULT; ch = ' '; } break; case SCE_HJ_DOUBLESTRING: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; } } else if (ch == '\"') { styler.ColourTo(i, statePrintForState(SCE_HJ_DOUBLESTRING, inScriptType)); state = SCE_HJ_DEFAULT; } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_STRINGEOL; } break; case SCE_HJ_SINGLESTRING: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; } } else if (ch == '\'') { styler.ColourTo(i, statePrintForState(SCE_HJ_SINGLESTRING, inScriptType)); state = SCE_HJ_DEFAULT; } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_COMMENTLINE; i += 2; } else if (isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); if (chPrev != '\\' && (chPrev2 != '\\' || chPrev != '\r' || ch != '\n')) { state = SCE_HJ_STRINGEOL; } } break; case SCE_HJ_STRINGEOL: if (!isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HJ_DEFAULT; } else if (!isLineEnd(chNext)) { styler.ColourTo(i, StateToPrint); state = SCE_HJ_DEFAULT; } break; case SCE_HJ_REGEX: if (ch == '\r' || ch == '\n' || ch == '/') { if (ch == '/') { while (isascii(chNext) && islower(chNext)) { // gobble regex flags i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } styler.ColourTo(i, StateToPrint); state = SCE_HJ_DEFAULT; } else if (ch == '\\') { // Gobble up the quoted character if (chNext == '\\' || chNext == '/') { i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } break; case SCE_HB_DEFAULT: case SCE_HB_START: if (IsAWordStart(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_WORD; } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_COMMENTLINE; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_STRING; } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && styler.SafeGetCharAt(i + 3) == '-') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_COMMENTLINE; } else if (IsOperator(ch)) { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType)); state = SCE_HB_DEFAULT; } else if ((ch == ' ') || (ch == '\t')) { if (state == SCE_HB_START) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_DEFAULT; } } break; case SCE_HB_WORD: if (!IsAWordChar(ch)) { state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType); if (state == SCE_HB_DEFAULT) { if (ch == '\"') { state = SCE_HB_STRING; } else if (ch == '\'') { state = SCE_HB_COMMENTLINE; } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType)); state = SCE_HB_DEFAULT; } } } break; case SCE_HB_STRING: if (ch == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_HB_DEFAULT; } else if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_STRINGEOL; } break; case SCE_HB_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_DEFAULT; } break; case SCE_HB_STRINGEOL: if (!isLineEnd(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HB_DEFAULT; } else if (!isLineEnd(chNext)) { styler.ColourTo(i, StateToPrint); state = SCE_HB_DEFAULT; } break; case SCE_HP_DEFAULT: case SCE_HP_START: if (IsAWordStart(ch)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_WORD; } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') && styler.SafeGetCharAt(i + 3) == '-') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_COMMENTLINE; } else if (ch == '#') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_COMMENTLINE; } else if (ch == '\"') { styler.ColourTo(i - 1, StateToPrint); if (chNext == '\"' && chNext2 == '\"') { i += 2; state = SCE_HP_TRIPLEDOUBLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { // state = statePrintForState(SCE_HP_STRING,inScriptType); state = SCE_HP_STRING; } } else if (ch == '\'') { styler.ColourTo(i - 1, StateToPrint); if (chNext == '\'' && chNext2 == '\'') { i += 2; state = SCE_HP_TRIPLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { state = SCE_HP_CHARACTER; } } else if (IsOperator(ch)) { styler.ColourTo(i - 1, StateToPrint); styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType)); } else if ((ch == ' ') || (ch == '\t')) { if (state == SCE_HP_START) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_DEFAULT; } } break; case SCE_HP_WORD: if (!IsAWordChar(ch)) { classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako); state = SCE_HP_DEFAULT; if (ch == '#') { state = SCE_HP_COMMENTLINE; } else if (ch == '\"') { if (chNext == '\"' && chNext2 == '\"') { i += 2; state = SCE_HP_TRIPLEDOUBLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { state = SCE_HP_STRING; } } else if (ch == '\'') { if (chNext == '\'' && chNext2 == '\'') { i += 2; state = SCE_HP_TRIPLE; ch = ' '; chPrev = ' '; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } else { state = SCE_HP_CHARACTER; } } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType)); } } break; case SCE_HP_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_STRING: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } else if (ch == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_CHARACTER: if (ch == '\\') { if (chNext == '\"' || chNext == '\'' || chNext == '\\') { i++; ch = chNext; chNext = static_cast(styler.SafeGetCharAt(i + 1)); } } else if (ch == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_TRIPLE: if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; case SCE_HP_TRIPLEDOUBLE: if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_HP_DEFAULT; } break; ///////////// start - PHP state handling case SCE_HPHP_WORD: if (!IsAWordChar(ch)) { classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler); if (ch == '/' && chNext == '*') { i++; state = SCE_HPHP_COMMENT; } else if (ch == '/' && chNext == '/') { i++; state = SCE_HPHP_COMMENTLINE; } else if (ch == '#') { state = SCE_HPHP_COMMENTLINE; } else if (ch == '\"') { state = SCE_HPHP_HSTRING; strcpy(phpStringDelimiter, "\""); } else if (styler.Match(i, "<<<")) { bool isSimpleString = false; i = FindPhpStringDelimiter(phpStringDelimiter, sizeof(phpStringDelimiter), i + 3, lengthDoc, styler, isSimpleString); if (strlen(phpStringDelimiter)) { state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING); if (foldHeredoc) levelCurrent++; } } else if (ch == '\'') { state = SCE_HPHP_SIMPLESTRING; strcpy(phpStringDelimiter, "\'"); } else if (ch == '$' && IsPhpWordStart(chNext)) { state = SCE_HPHP_VARIABLE; } else if (IsOperator(ch)) { state = SCE_HPHP_OPERATOR; } else { state = SCE_HPHP_DEFAULT; } } break; case SCE_HPHP_NUMBER: // recognize bases 8,10 or 16 integers OR floating-point numbers if (!IsADigit(ch) && strchr(".xXabcdefABCDEF", ch) == NULL && ((ch != '-' && ch != '+') || (chPrev != 'e' && chPrev != 'E'))) { styler.ColourTo(i - 1, SCE_HPHP_NUMBER); if (IsOperator(ch)) state = SCE_HPHP_OPERATOR; else state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_VARIABLE: if (!IsPhpWordChar(chNext)) { styler.ColourTo(i, SCE_HPHP_VARIABLE); state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_COMMENT: if (ch == '/' && chPrev == '*') { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_COMMENTLINE: if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, StateToPrint); state = SCE_HPHP_DEFAULT; } break; case SCE_HPHP_HSTRING: if (ch == '\\' && (phpStringDelimiter[0] == '\"' || chNext == '$' || chNext == '{')) { // skip the next char i++; } else if (((ch == '{' && chNext == '$') || (ch == '$' && chNext == '{')) && IsPhpWordStart(chNext2)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HPHP_COMPLEX_VARIABLE; } else if (ch == '$' && IsPhpWordStart(chNext)) { styler.ColourTo(i - 1, StateToPrint); state = SCE_HPHP_HSTRING_VARIABLE; } else if (styler.Match(i, phpStringDelimiter)) { if (phpStringDelimiter[0] == '\"') { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; } else if (isLineEnd(chPrev)) { const int psdLength = static_cast(strlen(phpStringDelimiter)); const char chAfterPsd = styler.SafeGetCharAt(i + psdLength); const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1); if (isLineEnd(chAfterPsd) || (chAfterPsd == ';' && isLineEnd(chAfterPsd2))) { i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1; styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; if (foldHeredoc) levelCurrent--; } } } break; case SCE_HPHP_SIMPLESTRING: if (phpStringDelimiter[0] == '\'') { if (ch == '\\') { // skip the next char i++; } else if (ch == '\'') { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; } } else if (isLineEnd(chPrev) && styler.Match(i, phpStringDelimiter)) { const int psdLength = static_cast(strlen(phpStringDelimiter)); const char chAfterPsd = styler.SafeGetCharAt(i + psdLength); const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1); if (isLineEnd(chAfterPsd) || (chAfterPsd == ';' && isLineEnd(chAfterPsd2))) { i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1; styler.ColourTo(i, StateToPrint); state = SCE_HPHP_DEFAULT; if (foldHeredoc) levelCurrent--; } } break; case SCE_HPHP_HSTRING_VARIABLE: if (!IsPhpWordChar(chNext)) { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_HSTRING; } break; case SCE_HPHP_COMPLEX_VARIABLE: if (ch == '}') { styler.ColourTo(i, StateToPrint); state = SCE_HPHP_HSTRING; } break; case SCE_HPHP_OPERATOR: case SCE_HPHP_DEFAULT: styler.ColourTo(i - 1, StateToPrint); if (IsADigit(ch) || (ch == '.' && IsADigit(chNext))) { state = SCE_HPHP_NUMBER; } else if (IsAWordStart(ch)) { state = SCE_HPHP_WORD; } else if (ch == '/' && chNext == '*') { i++; state = SCE_HPHP_COMMENT; } else if (ch == '/' && chNext == '/') { i++; state = SCE_HPHP_COMMENTLINE; } else if (ch == '#') { state = SCE_HPHP_COMMENTLINE; } else if (ch == '\"') { state = SCE_HPHP_HSTRING; strcpy(phpStringDelimiter, "\""); } else if (styler.Match(i, "<<<")) { bool isSimpleString = false; i = FindPhpStringDelimiter(phpStringDelimiter, sizeof(phpStringDelimiter), i + 3, lengthDoc, styler, isSimpleString); if (strlen(phpStringDelimiter)) { state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING); if (foldHeredoc) levelCurrent++; } } else if (ch == '\'') { state = SCE_HPHP_SIMPLESTRING; strcpy(phpStringDelimiter, "\'"); } else if (ch == '$' && IsPhpWordStart(chNext)) { state = SCE_HPHP_VARIABLE; } else if (IsOperator(ch)) { state = SCE_HPHP_OPERATOR; } else if ((state == SCE_HPHP_OPERATOR) && (IsASpace(ch))) { state = SCE_HPHP_DEFAULT; } break; ///////////// end - PHP state handling } // Some of the above terminated their lexeme but since the same character starts // the same class again, only reenter if non empty segment. bool nonEmptySegment = i >= static_cast(styler.GetStartSegment()); if (state == SCE_HB_DEFAULT) { // One of the above succeeded if ((ch == '\"') && (nonEmptySegment)) { state = SCE_HB_STRING; } else if (ch == '\'') { state = SCE_HB_COMMENTLINE; } else if (IsAWordStart(ch)) { state = SCE_HB_WORD; } else if (IsOperator(ch)) { styler.ColourTo(i, SCE_HB_DEFAULT); } } else if (state == SCE_HBA_DEFAULT) { // One of the above succeeded if ((ch == '\"') && (nonEmptySegment)) { state = SCE_HBA_STRING; } else if (ch == '\'') { state = SCE_HBA_COMMENTLINE; } else if (IsAWordStart(ch)) { state = SCE_HBA_WORD; } else if (IsOperator(ch)) { styler.ColourTo(i, SCE_HBA_DEFAULT); } } else if (state == SCE_HJ_DEFAULT) { // One of the above succeeded if (ch == '/' && chNext == '*') { if (styler.SafeGetCharAt(i + 2) == '*') state = SCE_HJ_COMMENTDOC; else state = SCE_HJ_COMMENT; } else if (ch == '/' && chNext == '/') { state = SCE_HJ_COMMENTLINE; } else if ((ch == '\"') && (nonEmptySegment)) { state = SCE_HJ_DOUBLESTRING; } else if ((ch == '\'') && (nonEmptySegment)) { state = SCE_HJ_SINGLESTRING; } else if (IsAWordStart(ch)) { state = SCE_HJ_WORD; } else if (IsOperator(ch)) { styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType)); } } } switch (state) { case SCE_HJ_WORD: classifyWordHTJS(styler.GetStartSegment(), lengthDoc - 1, keywords2, styler, inScriptType); break; case SCE_HB_WORD: classifyWordHTVB(styler.GetStartSegment(), lengthDoc - 1, keywords3, styler, inScriptType); break; case SCE_HP_WORD: classifyWordHTPy(styler.GetStartSegment(), lengthDoc - 1, keywords4, styler, prevWord, inScriptType, isMako); break; case SCE_HPHP_WORD: classifyWordHTPHP(styler.GetStartSegment(), lengthDoc - 1, keywords5, styler); break; default: StateToPrint = statePrintForState(state, inScriptType); if (static_cast(styler.GetStartSegment()) < lengthDoc) styler.ColourTo(lengthDoc - 1, StateToPrint); break; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later if (fold) { int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } } static void ColouriseXMLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { // Passing in true because we're lexing XML ColouriseHyperTextDoc(startPos, length, initStyle, keywordlists, styler, true); } static void ColouriseHTMLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { // Passing in false because we're notlexing XML ColouriseHyperTextDoc(startPos, length, initStyle, keywordlists, styler, false); } static void ColourisePHPScriptDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { if (startPos == 0) initStyle = SCE_HPHP_DEFAULT; ColouriseHTMLDoc(startPos, length, initStyle, keywordlists, styler); } static const char * const htmlWordListDesc[] = { "HTML elements and attributes", "JavaScript keywords", "VBScript keywords", "Python keywords", "PHP keywords", "SGML and DTD keywords", 0, }; static const char * const phpscriptWordListDesc[] = { "", //Unused "", //Unused "", //Unused "", //Unused "PHP keywords", "", //Unused 0, }; LexerModule lmHTML(SCLEX_HTML, ColouriseHTMLDoc, "hypertext", 0, htmlWordListDesc, 8); LexerModule lmXML(SCLEX_XML, ColouriseXMLDoc, "xml", 0, htmlWordListDesc, 8); LexerModule lmPHPSCRIPT(SCLEX_PHPSCRIPT, ColourisePHPScriptDoc, "phpscript", 0, phpscriptWordListDesc, 8); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexLout.cxx0000644000175000017500000001362111615412040021246 00000000000000// Scintilla source code edit control /** @file LexLout.cxx ** Lexer for the Basser Lout (>= version 3) typesetting language **/ // Copyright 2003 by Kein-Hong Man // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalpha(ch) || ch == '@' || ch == '_'); } static inline bool IsAnOther(const int ch) { return (ch < 0x80) && (ch == '{' || ch == '}' || ch == '!' || ch == '$' || ch == '%' || ch == '&' || ch == '\'' || ch == '(' || ch == ')' || ch == '*' || ch == '+' || ch == ',' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == ';' || ch == '<' || ch == '=' || ch == '>' || ch == '?' || ch == '[' || ch == ']' || ch == '^' || ch == '`' || ch == '|' || ch == '~'); } static void ColouriseLoutDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; int visibleChars = 0; int firstWordInLine = 0; int leadingAtSign = 0; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineStart && (sc.state == SCE_LOUT_STRING)) { // Prevent SCE_LOUT_STRINGEOL from leaking back to previous line sc.SetState(SCE_LOUT_STRING); } // Determine if the current state should terminate. if (sc.state == SCE_LOUT_COMMENT) { if (sc.atLineEnd) { sc.SetState(SCE_LOUT_DEFAULT); visibleChars = 0; } } else if (sc.state == SCE_LOUT_NUMBER) { if (!IsADigit(sc.ch) && sc.ch != '.') { sc.SetState(SCE_LOUT_DEFAULT); } } else if (sc.state == SCE_LOUT_STRING) { if (sc.ch == '\\') { if (sc.chNext == '\"' || sc.chNext == '\\') { sc.Forward(); } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_LOUT_DEFAULT); } else if (sc.atLineEnd) { sc.ChangeState(SCE_LOUT_STRINGEOL); sc.ForwardSetState(SCE_LOUT_DEFAULT); visibleChars = 0; } } else if (sc.state == SCE_LOUT_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (leadingAtSign) { if (keywords.InList(s)) { sc.ChangeState(SCE_LOUT_WORD); } else { sc.ChangeState(SCE_LOUT_WORD4); } } else if (firstWordInLine && keywords3.InList(s)) { sc.ChangeState(SCE_LOUT_WORD3); } sc.SetState(SCE_LOUT_DEFAULT); } } else if (sc.state == SCE_LOUT_OPERATOR) { if (!IsAnOther(sc.ch)) { char s[100]; sc.GetCurrent(s, sizeof(s)); if (keywords2.InList(s)) { sc.ChangeState(SCE_LOUT_WORD2); } sc.SetState(SCE_LOUT_DEFAULT); } } // Determine if a new state should be entered. if (sc.state == SCE_LOUT_DEFAULT) { if (sc.ch == '#') { sc.SetState(SCE_LOUT_COMMENT); } else if (sc.ch == '\"') { sc.SetState(SCE_LOUT_STRING); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_LOUT_NUMBER); } else if (IsAWordChar(sc.ch)) { firstWordInLine = (visibleChars == 0); leadingAtSign = (sc.ch == '@'); sc.SetState(SCE_LOUT_IDENTIFIER); } else if (IsAnOther(sc.ch)) { sc.SetState(SCE_LOUT_OPERATOR); } } if (sc.atLineEnd) { // Reset states to begining of colourise so no surprises // if different sets of lines lexed. visibleChars = 0; } if (!IsASpace(sc.ch)) { visibleChars++; } } sc.Complete(); } static void FoldLoutDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; int styleNext = styler.StyleAt(startPos); char s[10]; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (style == SCE_LOUT_WORD) { if (ch == '@') { for (unsigned int j = 0; j < 8; j++) { if (!IsAWordChar(styler[i + j])) { break; } s[j] = styler[i + j]; s[j + 1] = '\0'; } if (strcmp(s, "@Begin") == 0) { levelCurrent++; } else if (strcmp(s, "@End") == 0) { levelCurrent--; } } } else if (style == SCE_LOUT_OPERATOR) { if (ch == '{') { levelCurrent++; } else if (ch == '}') { levelCurrent--; } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) { lev |= SC_FOLDLEVELWHITEFLAG; } if ((levelCurrent > levelPrev) && (visibleChars > 0)) { lev |= SC_FOLDLEVELHEADERFLAG; } if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const loutWordLists[] = { "Predefined identifiers", "Predefined delimiters", "Predefined keywords", 0, }; LexerModule lmLout(SCLEX_LOUT, ColouriseLoutDoc, "lout", FoldLoutDoc, loutWordLists); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexOpal.cxx0000644000175000017500000002303311615412040021214 00000000000000// Scintilla source code edit control /** @file LexOpal.cxx ** Lexer for OPAL (functional language similar to Haskell) ** Written by Sebastian Pipping **/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif inline static void getRange( unsigned int start, unsigned int end, Accessor & styler, char * s, unsigned int len ) { unsigned int i = 0; while( ( i < end - start + 1 ) && ( i < len - 1 ) ) { s[i] = static_cast( styler[ start + i ] ); i++; } s[ i ] = '\0'; } inline bool HandleString( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { char ch; // Wait for string to close bool even_backslash_count = true; // Without gaps in between cur++; // Skip initial quote for( ; ; ) { if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_STRING ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ( ch == '\015' ) || ( ch == '\012' ) ) // Deny multi-line strings { styler.ColourTo( cur - 1, SCE_OPAL_STRING ); styler.StartSegment( cur ); return true; } else { if( even_backslash_count ) { if( ch == '"' ) { styler.ColourTo( cur, SCE_OPAL_STRING ); cur++; if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( ch == '\\' ) { even_backslash_count = false; } } else { even_backslash_count = true; } } cur++; } } inline bool HandleCommentBlock( unsigned int & cur, unsigned int one_too_much, Accessor & styler, bool could_fail ) { char ch; if( could_fail ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ch != '*' ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); styler.StartSegment( cur ); return true; } } // Wait for comment close cur++; bool star_found = false; for( ; ; ) { if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_BLOCK ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( star_found ) { if( ch == '/' ) { styler.ColourTo( cur, SCE_OPAL_COMMENT_BLOCK ); cur++; if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( ch != '*' ) { star_found = false; } } else if( ch == '*' ) { star_found = true; } cur++; } } inline bool HandleCommentLine( unsigned int & cur, unsigned int one_too_much, Accessor & styler, bool could_fail ) { char ch; if( could_fail ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ch != '-' ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); styler.StartSegment( cur ); return true; } cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( ( ch != ' ' ) && ( ch != '\t' ) ) { styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); styler.StartSegment( cur ); return true; } } // Wait for end of line bool fifteen_found = false; for( ; ; ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( fifteen_found ) { /* if( ch == '\012' ) { // One newline on Windows (015, 012) } else { // One newline on MAC (015) and another char } */ cur--; styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); styler.StartSegment( cur ); return true; } else { if( ch == '\015' ) { fifteen_found = true; } else if( ch == '\012' ) { // One newline on Linux (012) styler.ColourTo( cur - 1, SCE_OPAL_COMMENT_LINE ); styler.StartSegment( cur ); return true; } } } } inline bool HandlePar( unsigned int & cur, Accessor & styler ) { styler.ColourTo( cur, SCE_OPAL_PAR ); cur++; styler.StartSegment( cur ); return true; } inline bool HandleSpace( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { char ch; cur++; for( ; ; ) { if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_SPACE ); return false; } ch = styler.SafeGetCharAt( cur ); switch( ch ) { case ' ': case '\t': case '\015': case '\012': cur++; break; default: styler.ColourTo( cur - 1, SCE_OPAL_SPACE ); styler.StartSegment( cur ); return true; } } } inline bool HandleInteger( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { char ch; for( ; ; ) { cur++; if( cur >= one_too_much ) { styler.ColourTo( cur - 1, SCE_OPAL_INTEGER ); return false; // STOP } ch = styler.SafeGetCharAt( cur ); if( !( isascii( ch ) && isdigit( ch ) ) ) { styler.ColourTo( cur - 1, SCE_OPAL_INTEGER ); styler.StartSegment( cur ); return true; } } } inline bool HandleWord( unsigned int & cur, unsigned int one_too_much, Accessor & styler, WordList * keywordlists[] ) { char ch; const unsigned int beg = cur; cur++; for( ; ; ) { ch = styler.SafeGetCharAt( cur ); if( ( ch != '_' ) && ( ch != '-' ) && !( isascii( ch ) && ( islower( ch ) || isupper( ch ) || isdigit( ch ) ) ) ) break; cur++; if( cur >= one_too_much ) { break; } } const int ide_len = cur - beg + 1; char * ide = new char[ ide_len ]; getRange( beg, cur, styler, ide, ide_len ); WordList & keywords = *keywordlists[ 0 ]; WordList & classwords = *keywordlists[ 1 ]; if( keywords.InList( ide ) ) // Keyword { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_KEYWORD ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( classwords.InList( ide ) ) // Sort { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_SORT ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else if( !strcmp( ide, "true" ) || !strcmp( ide, "false" ) ) // Bool const { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_BOOL_CONST ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } else // Unknown keyword { delete [] ide; styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } } inline bool HandleSkip( unsigned int & cur, unsigned int one_too_much, Accessor & styler ) { cur++; styler.ColourTo( cur - 1, SCE_OPAL_DEFAULT ); if( cur >= one_too_much ) { return false; // STOP } else { styler.StartSegment( cur ); return true; } } static void ColouriseOpalDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor & styler ) { styler.StartAt( startPos ); styler.StartSegment( startPos ); unsigned int & cur = startPos; const unsigned int one_too_much = startPos + length; int state = initStyle; for( ; ; ) { switch( state ) { case SCE_OPAL_KEYWORD: case SCE_OPAL_SORT: if( !HandleWord( cur, one_too_much, styler, keywordlists ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_INTEGER: if( !HandleInteger( cur, one_too_much, styler ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_COMMENT_BLOCK: if( !HandleCommentBlock( cur, one_too_much, styler, false ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_COMMENT_LINE: if( !HandleCommentLine( cur, one_too_much, styler, false ) ) return; state = SCE_OPAL_DEFAULT; break; case SCE_OPAL_STRING: if( !HandleString( cur, one_too_much, styler ) ) return; state = SCE_OPAL_DEFAULT; break; default: // SCE_OPAL_DEFAULT: { char ch = styler.SafeGetCharAt( cur ); switch( ch ) { // String case '"': if( !HandleString( cur, one_too_much, styler ) ) return; break; // Comment block case '/': if( !HandleCommentBlock( cur, one_too_much, styler, true ) ) return; break; // Comment line case '-': if( !HandleCommentLine( cur, one_too_much, styler, true ) ) return; break; // Par case '(': case ')': case '[': case ']': case '{': case '}': if( !HandlePar( cur, styler ) ) return; break; // Whitespace case ' ': case '\t': case '\015': case '\012': if( !HandleSpace( cur, one_too_much, styler ) ) return; break; default: { // Integer if( isascii( ch ) && isdigit( ch ) ) { if( !HandleInteger( cur, one_too_much, styler ) ) return; } // Keyword else if( isascii( ch ) && ( islower( ch ) || isupper( ch ) ) ) { if( !HandleWord( cur, one_too_much, styler, keywordlists ) ) return; } // Skip else { if( !HandleSkip( cur, one_too_much, styler ) ) return; } } } break; } } } } static const char * const opalWordListDesc[] = { "Keywords", "Sorts", 0 }; LexerModule lmOpal(SCLEX_OPAL, ColouriseOpalDoc, "opal", NULL, opalWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexSpice.cxx0000644000175000017500000001522111660423551021375 00000000000000// Scintilla source code edit control /** @file LexSpice.cxx ** Lexer for Spice **/ // Copyright 2006 by Fabien Proriol // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif /* * Interface */ static void ColouriseDocument( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler); static const char * const spiceWordListDesc[] = { "Keywords", // SPICE command "Keywords2", // SPICE functions "Keywords3", // SPICE params 0 }; LexerModule lmSpice(SCLEX_SPICE, ColouriseDocument, "spice", NULL, spiceWordListDesc); /* * Implementation */ static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute); static void ColouriseWord(StyleContext& sc, WordList& keywords, WordList& keywords2, WordList& keywords3, bool& apostropheStartsAttribute); static inline bool IsDelimiterCharacter(int ch); static inline bool IsNumberStartCharacter(int ch); static inline bool IsNumberCharacter(int ch); static inline bool IsSeparatorOrDelimiterCharacter(int ch); static inline bool IsWordStartCharacter(int ch); static inline bool IsWordCharacter(int ch); static void ColouriseComment(StyleContext& sc, bool&) { sc.SetState(SCE_SPICE_COMMENTLINE); while (!sc.atLineEnd) { sc.Forward(); } } static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) { apostropheStartsAttribute = sc.Match (')'); sc.SetState(SCE_SPICE_DELIMITER); sc.ForwardSetState(SCE_SPICE_DEFAULT); } static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) { apostropheStartsAttribute = true; std::string number; sc.SetState(SCE_SPICE_NUMBER); // Get all characters up to a delimiter or a separator, including points, but excluding // double points (ranges). while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) { number += static_cast(sc.ch); sc.Forward(); } // Special case: exponent with sign if ((sc.chPrev == 'e' || sc.chPrev == 'E') && (sc.ch == '+' || sc.ch == '-')) { number += static_cast(sc.ch); sc.Forward (); while (!IsSeparatorOrDelimiterCharacter(sc.ch)) { number += static_cast(sc.ch); sc.Forward(); } } sc.SetState(SCE_SPICE_DEFAULT); } static void ColouriseWhiteSpace(StyleContext& sc, bool& ) { sc.SetState(SCE_SPICE_DEFAULT); sc.ForwardSetState(SCE_SPICE_DEFAULT); } static void ColouriseWord(StyleContext& sc, WordList& keywords, WordList& keywords2, WordList& keywords3, bool& apostropheStartsAttribute) { apostropheStartsAttribute = true; sc.SetState(SCE_SPICE_IDENTIFIER); std::string word; while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) { word += static_cast(tolower(sc.ch)); sc.Forward(); } if (keywords.InList(word.c_str())) { sc.ChangeState(SCE_SPICE_KEYWORD); if (word != "all") { apostropheStartsAttribute = false; } } else if (keywords2.InList(word.c_str())) { sc.ChangeState(SCE_SPICE_KEYWORD2); if (word != "all") { apostropheStartsAttribute = false; } } else if (keywords3.InList(word.c_str())) { sc.ChangeState(SCE_SPICE_KEYWORD3); if (word != "all") { apostropheStartsAttribute = false; } } sc.SetState(SCE_SPICE_DEFAULT); } // // ColouriseDocument // static void ColouriseDocument( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; StyleContext sc(startPos, length, initStyle, styler); int lineCurrent = styler.GetLine(startPos); bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0; while (sc.More()) { if (sc.atLineEnd) { // Go to the next line sc.Forward(); lineCurrent++; // Remember the line state for future incremental lexing styler.SetLineState(lineCurrent, apostropheStartsAttribute); // Don't continue any styles on the next line sc.SetState(SCE_SPICE_DEFAULT); } // Comments if ((sc.Match('*') && sc.atLineStart) || sc.Match('*','~')) { ColouriseComment(sc, apostropheStartsAttribute); // Whitespace } else if (IsASpace(sc.ch)) { ColouriseWhiteSpace(sc, apostropheStartsAttribute); // Delimiters } else if (IsDelimiterCharacter(sc.ch)) { ColouriseDelimiter(sc, apostropheStartsAttribute); // Numbers } else if (IsADigit(sc.ch) || sc.ch == '#') { ColouriseNumber(sc, apostropheStartsAttribute); // Keywords or identifiers } else { ColouriseWord(sc, keywords, keywords2, keywords3, apostropheStartsAttribute); } } sc.Complete(); } static inline bool IsDelimiterCharacter(int ch) { switch (ch) { case '&': case '\'': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '|': return true; default: return false; } } static inline bool IsNumberCharacter(int ch) { return IsNumberStartCharacter(ch) || ch == '_' || ch == '.' || ch == '#' || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); } static inline bool IsNumberStartCharacter(int ch) { return IsADigit(ch); } static inline bool IsSeparatorOrDelimiterCharacter(int ch) { return IsASpace(ch) || IsDelimiterCharacter(ch); } static inline bool IsWordCharacter(int ch) { return IsWordStartCharacter(ch) || IsADigit(ch); } static inline bool IsWordStartCharacter(int ch) { return (isascii(ch) && isalpha(ch)) || ch == '_'; } presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexPascal.cxx0000644000175000017500000005043611717550114021543 00000000000000// Scintilla source code edit control /** @file LexPascal.cxx ** Lexer for Pascal. ** Written by Laurent le Tynevez ** Updated by Simon Steele September 2002 ** Updated by Mathias Rauen May 2003 (Delphi adjustments) ** Completely rewritten by Marko Njezic October 2008 **/ /* A few words about features of the new completely rewritten LexPascal... Generally speaking LexPascal tries to support all available Delphi features (up to Delphi 2009 at this time), including .NET specific features. ~ HIGHLIGHTING: If you enable "lexer.pascal.smart.highlighting" property, some keywords will only be highlighted in appropriate context. As implemented those are keywords related to property and DLL exports declarations (similar to how Delphi IDE works). For example, keywords "read" and "write" will only be highlighted if they are in property declaration: property MyProperty: boolean read FMyProperty write FMyProperty; ~ FOLDING: Folding is supported in the following cases: - Folding of stream-like comments - Folding of groups of consecutive line comments - Folding of preprocessor blocks (the following preprocessor blocks are supported: IF / IFEND; IFDEF, IFNDEF, IFOPT / ENDIF and REGION / ENDREGION blocks), including nesting of preprocessor blocks up to 255 levels - Folding of code blocks on appropriate keywords (the following code blocks are supported: "begin, asm, record, try, case / end" blocks, class & object declarations and interface declarations) Remarks: - Folding of code blocks tries to handle all special cases in which folding should not occur. As implemented those are: 1. Structure "record case / end" (there's only one "end" statement and "case" is ignored as fold point) 2. Forward class declarations ("type TMyClass = class;") and object method declarations ("TNotifyEvent = procedure(Sender: TObject) of object;") are ignored as fold points 3. Simplified complete class declarations ("type TMyClass = class(TObject);") are ignored as fold points 4. Every other situation when class keyword doesn't actually start class declaration ("class procedure", "class function", "class of", "class var", "class property" and "class operator") 5. Forward (disp)interface declarations ("type IMyInterface = interface;") are ignored as fold points - Folding of code blocks inside preprocessor blocks is disabled (any comments inside them will be folded fine) because there is no guarantee that complete code block will be contained inside folded preprocessor block in which case folded code block could end prematurely at the end of preprocessor block if there is no closing statement inside. This was done in order to properly process document that may contain something like this: type {$IFDEF UNICODE} TMyClass = class(UnicodeAncestor) {$ELSE} TMyClass = class(AnsiAncestor) {$ENDIF} private ... public ... published ... end; If class declarations were folded, then the second class declaration would end at "$ENDIF" statement, first class statement would end at "end;" statement and preprocessor "$IFDEF" block would go all the way to the end of document. However, having in mind all this, if you want to enable folding of code blocks inside preprocessor blocks, you can disable folding of preprocessor blocks by changing "fold.preprocessor" property, in which case everything inside them would be folded. ~ KEYWORDS: The list of keywords that can be used in pascal.properties file (up to Delphi 2009): - Keywords: absolute abstract and array as asm assembler automated begin case cdecl class const constructor deprecated destructor dispid dispinterface div do downto dynamic else end except export exports external far file final finalization finally for forward function goto if implementation in inherited initialization inline interface is label library message mod near nil not object of on or out overload override packed pascal platform private procedure program property protected public published raise record register reintroduce repeat resourcestring safecall sealed set shl shr static stdcall strict string then threadvar to try type unit unsafe until uses var varargs virtual while with xor - Keywords related to the "smart highlithing" feature: add default implements index name nodefault read readonly remove stored write writeonly - Keywords related to Delphi packages (in addition to all above): package contains requires */ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static void GetRangeLowered(unsigned int start, unsigned int end, Accessor &styler, char *s, unsigned int len) { unsigned int i = 0; while ((i < end - start + 1) && (i < len-1)) { s[i] = static_cast(tolower(styler[start + i])); i++; } s[i] = '\0'; } static void GetForwardRangeLowered(unsigned int start, CharacterSet &charSet, Accessor &styler, char *s, unsigned int len) { unsigned int i = 0; while ((i < len-1) && charSet.Contains(styler.SafeGetCharAt(start + i))) { s[i] = static_cast(tolower(styler.SafeGetCharAt(start + i))); i++; } s[i] = '\0'; } enum { stateInAsm = 0x1000, stateInProperty = 0x2000, stateInExport = 0x4000, stateFoldInPreprocessor = 0x0100, stateFoldInRecord = 0x0200, stateFoldInPreprocessorLevelMask = 0x00FF, stateFoldMaskAll = 0x0FFF }; static void ClassifyPascalWord(WordList *keywordlists[], StyleContext &sc, int &curLineState, bool bSmartHighlighting) { WordList& keywords = *keywordlists[0]; char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { if (curLineState & stateInAsm) { if (strcmp(s, "end") == 0 && sc.GetRelative(-4) != '@') { curLineState &= ~stateInAsm; sc.ChangeState(SCE_PAS_WORD); } else { sc.ChangeState(SCE_PAS_ASM); } } else { bool ignoreKeyword = false; if (strcmp(s, "asm") == 0) { curLineState |= stateInAsm; } else if (bSmartHighlighting) { if (strcmp(s, "property") == 0) { curLineState |= stateInProperty; } else if (strcmp(s, "exports") == 0) { curLineState |= stateInExport; } else if (!(curLineState & (stateInProperty | stateInExport)) && strcmp(s, "index") == 0) { ignoreKeyword = true; } else if (!(curLineState & stateInExport) && strcmp(s, "name") == 0) { ignoreKeyword = true; } else if (!(curLineState & stateInProperty) && (strcmp(s, "read") == 0 || strcmp(s, "write") == 0 || strcmp(s, "default") == 0 || strcmp(s, "nodefault") == 0 || strcmp(s, "stored") == 0 || strcmp(s, "implements") == 0 || strcmp(s, "readonly") == 0 || strcmp(s, "writeonly") == 0 || strcmp(s, "add") == 0 || strcmp(s, "remove") == 0)) { ignoreKeyword = true; } } if (!ignoreKeyword) { sc.ChangeState(SCE_PAS_WORD); } } } else if (curLineState & stateInAsm) { sc.ChangeState(SCE_PAS_ASM); } sc.SetState(SCE_PAS_DEFAULT); } static void ColourisePascalDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { bool bSmartHighlighting = styler.GetPropertyInt("lexer.pascal.smart.highlighting", 1) != 0; CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true); CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true); CharacterSet setNumber(CharacterSet::setDigits, ".-+eE"); CharacterSet setHexNumber(CharacterSet::setDigits, "abcdefABCDEF"); CharacterSet setOperator(CharacterSet::setNone, "#$&'()*+,-./:;<=>@[]^{}"); int curLine = styler.GetLine(startPos); int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.atLineEnd) { // Update the line state, so it can be seen by next line curLine = styler.GetLine(sc.currentPos); styler.SetLineState(curLine, curLineState); } // Determine if the current state should terminate. switch (sc.state) { case SCE_PAS_NUMBER: if (!setNumber.Contains(sc.ch) || (sc.ch == '.' && sc.chNext == '.')) { sc.SetState(SCE_PAS_DEFAULT); } else if (sc.ch == '-' || sc.ch == '+') { if (sc.chPrev != 'E' && sc.chPrev != 'e') { sc.SetState(SCE_PAS_DEFAULT); } } break; case SCE_PAS_IDENTIFIER: if (!setWord.Contains(sc.ch)) { ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting); } break; case SCE_PAS_HEXNUMBER: if (!setHexNumber.Contains(sc.ch)) { sc.SetState(SCE_PAS_DEFAULT); } break; case SCE_PAS_COMMENT: case SCE_PAS_PREPROCESSOR: if (sc.ch == '}') { sc.ForwardSetState(SCE_PAS_DEFAULT); } break; case SCE_PAS_COMMENT2: case SCE_PAS_PREPROCESSOR2: if (sc.Match('*', ')')) { sc.Forward(); sc.ForwardSetState(SCE_PAS_DEFAULT); } break; case SCE_PAS_COMMENTLINE: if (sc.atLineStart) { sc.SetState(SCE_PAS_DEFAULT); } break; case SCE_PAS_STRING: if (sc.atLineEnd) { sc.ChangeState(SCE_PAS_STRINGEOL); } else if (sc.ch == '\'' && sc.chNext == '\'') { sc.Forward(); } else if (sc.ch == '\'') { sc.ForwardSetState(SCE_PAS_DEFAULT); } break; case SCE_PAS_STRINGEOL: if (sc.atLineStart) { sc.SetState(SCE_PAS_DEFAULT); } break; case SCE_PAS_CHARACTER: if (!setHexNumber.Contains(sc.ch) && sc.ch != '$') { sc.SetState(SCE_PAS_DEFAULT); } break; case SCE_PAS_OPERATOR: if (bSmartHighlighting && sc.chPrev == ';') { curLineState &= ~(stateInProperty | stateInExport); } sc.SetState(SCE_PAS_DEFAULT); break; case SCE_PAS_ASM: sc.SetState(SCE_PAS_DEFAULT); break; } // Determine if a new state should be entered. if (sc.state == SCE_PAS_DEFAULT) { if (IsADigit(sc.ch) && !(curLineState & stateInAsm)) { sc.SetState(SCE_PAS_NUMBER); } else if (setWordStart.Contains(sc.ch)) { sc.SetState(SCE_PAS_IDENTIFIER); } else if (sc.ch == '$' && !(curLineState & stateInAsm)) { sc.SetState(SCE_PAS_HEXNUMBER); } else if (sc.Match('{', '$')) { sc.SetState(SCE_PAS_PREPROCESSOR); } else if (sc.ch == '{') { sc.SetState(SCE_PAS_COMMENT); } else if (sc.Match("(*$")) { sc.SetState(SCE_PAS_PREPROCESSOR2); } else if (sc.Match('(', '*')) { sc.SetState(SCE_PAS_COMMENT2); sc.Forward(); // Eat the * so it isn't used for the end of the comment } else if (sc.Match('/', '/')) { sc.SetState(SCE_PAS_COMMENTLINE); } else if (sc.ch == '\'') { sc.SetState(SCE_PAS_STRING); } else if (sc.ch == '#') { sc.SetState(SCE_PAS_CHARACTER); } else if (setOperator.Contains(sc.ch) && !(curLineState & stateInAsm)) { sc.SetState(SCE_PAS_OPERATOR); } else if (curLineState & stateInAsm) { sc.SetState(SCE_PAS_ASM); } } } if (sc.state == SCE_PAS_IDENTIFIER && setWord.Contains(sc.chPrev)) { ClassifyPascalWord(keywordlists, sc, curLineState, bSmartHighlighting); } sc.Complete(); } static bool IsStreamCommentStyle(int style) { return style == SCE_PAS_COMMENT || style == SCE_PAS_COMMENT2; } static bool IsCommentLine(int line, Accessor &styler) { int pos = styler.LineStart(line); int eolPos = styler.LineStart(line + 1) - 1; for (int i = pos; i < eolPos; i++) { char ch = styler[i]; char chNext = styler.SafeGetCharAt(i + 1); int style = styler.StyleAt(i); if (ch == '/' && chNext == '/' && style == SCE_PAS_COMMENTLINE) { return true; } else if (!IsASpaceOrTab(ch)) { return false; } } return false; } static unsigned int GetFoldInPreprocessorLevelFlag(int lineFoldStateCurrent) { return lineFoldStateCurrent & stateFoldInPreprocessorLevelMask; } static void SetFoldInPreprocessorLevelFlag(int &lineFoldStateCurrent, unsigned int nestLevel) { lineFoldStateCurrent &= ~stateFoldInPreprocessorLevelMask; lineFoldStateCurrent |= nestLevel & stateFoldInPreprocessorLevelMask; } static void ClassifyPascalPreprocessorFoldPoint(int &levelCurrent, int &lineFoldStateCurrent, unsigned int startPos, Accessor &styler) { CharacterSet setWord(CharacterSet::setAlpha); char s[11]; // Size of the longest possible keyword + one additional character + null GetForwardRangeLowered(startPos, setWord, styler, s, sizeof(s)); unsigned int nestLevel = GetFoldInPreprocessorLevelFlag(lineFoldStateCurrent); if (strcmp(s, "if") == 0 || strcmp(s, "ifdef") == 0 || strcmp(s, "ifndef") == 0 || strcmp(s, "ifopt") == 0 || strcmp(s, "region") == 0) { nestLevel++; SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent, nestLevel); lineFoldStateCurrent |= stateFoldInPreprocessor; levelCurrent++; } else if (strcmp(s, "endif") == 0 || strcmp(s, "ifend") == 0 || strcmp(s, "endregion") == 0) { nestLevel--; SetFoldInPreprocessorLevelFlag(lineFoldStateCurrent, nestLevel); if (nestLevel == 0) { lineFoldStateCurrent &= ~stateFoldInPreprocessor; } levelCurrent--; if (levelCurrent < SC_FOLDLEVELBASE) { levelCurrent = SC_FOLDLEVELBASE; } } } static unsigned int SkipWhiteSpace(unsigned int currentPos, unsigned int endPos, Accessor &styler, bool includeChars = false) { CharacterSet setWord(CharacterSet::setAlphaNum, "_"); unsigned int j = currentPos + 1; char ch = styler.SafeGetCharAt(j); while ((j < endPos) && (IsASpaceOrTab(ch) || ch == '\r' || ch == '\n' || IsStreamCommentStyle(styler.StyleAt(j)) || (includeChars && setWord.Contains(ch)))) { j++; ch = styler.SafeGetCharAt(j); } return j; } static void ClassifyPascalWordFoldPoint(int &levelCurrent, int &lineFoldStateCurrent, int startPos, unsigned int endPos, unsigned int lastStart, unsigned int currentPos, Accessor &styler) { char s[100]; GetRangeLowered(lastStart, currentPos, styler, s, sizeof(s)); if (strcmp(s, "record") == 0) { lineFoldStateCurrent |= stateFoldInRecord; levelCurrent++; } else if (strcmp(s, "begin") == 0 || strcmp(s, "asm") == 0 || strcmp(s, "try") == 0 || (strcmp(s, "case") == 0 && !(lineFoldStateCurrent & stateFoldInRecord))) { levelCurrent++; } else if (strcmp(s, "class") == 0 || strcmp(s, "object") == 0) { // "class" & "object" keywords require special handling... bool ignoreKeyword = false; unsigned int j = SkipWhiteSpace(currentPos, endPos, styler); if (j < endPos) { CharacterSet setWordStart(CharacterSet::setAlpha, "_"); CharacterSet setWord(CharacterSet::setAlphaNum, "_"); if (styler.SafeGetCharAt(j) == ';') { // Handle forward class declarations ("type TMyClass = class;") // and object method declarations ("TNotifyEvent = procedure(Sender: TObject) of object;") ignoreKeyword = true; } else if (strcmp(s, "class") == 0) { // "class" keyword has a few more special cases... if (styler.SafeGetCharAt(j) == '(') { // Handle simplified complete class declarations ("type TMyClass = class(TObject);") j = SkipWhiteSpace(j, endPos, styler, true); if (j < endPos && styler.SafeGetCharAt(j) == ')') { j = SkipWhiteSpace(j, endPos, styler); if (j < endPos && styler.SafeGetCharAt(j) == ';') { ignoreKeyword = true; } } } else if (setWordStart.Contains(styler.SafeGetCharAt(j))) { char s2[11]; // Size of the longest possible keyword + one additional character + null GetForwardRangeLowered(j, setWord, styler, s2, sizeof(s2)); if (strcmp(s2, "procedure") == 0 || strcmp(s2, "function") == 0 || strcmp(s2, "of") == 0 || strcmp(s2, "var") == 0 || strcmp(s2, "property") == 0 || strcmp(s2, "operator") == 0) { ignoreKeyword = true; } } } } if (!ignoreKeyword) { levelCurrent++; } } else if (strcmp(s, "interface") == 0) { // "interface" keyword requires special handling... bool ignoreKeyword = true; int j = lastStart - 1; char ch = styler.SafeGetCharAt(j); while ((j >= startPos) && (IsASpaceOrTab(ch) || ch == '\r' || ch == '\n' || IsStreamCommentStyle(styler.StyleAt(j)))) { j--; ch = styler.SafeGetCharAt(j); } if (j >= startPos && styler.SafeGetCharAt(j) == '=') { ignoreKeyword = false; } if (!ignoreKeyword) { unsigned int k = SkipWhiteSpace(currentPos, endPos, styler); if (k < endPos && styler.SafeGetCharAt(k) == ';') { // Handle forward interface declarations ("type IMyInterface = interface;") ignoreKeyword = true; } } if (!ignoreKeyword) { levelCurrent++; } } else if (strcmp(s, "dispinterface") == 0) { // "dispinterface" keyword requires special handling... bool ignoreKeyword = false; unsigned int j = SkipWhiteSpace(currentPos, endPos, styler); if (j < endPos && styler.SafeGetCharAt(j) == ';') { // Handle forward dispinterface declarations ("type IMyInterface = dispinterface;") ignoreKeyword = true; } if (!ignoreKeyword) { levelCurrent++; } } else if (strcmp(s, "end") == 0) { lineFoldStateCurrent &= ~stateFoldInRecord; levelCurrent--; if (levelCurrent < SC_FOLDLEVELBASE) { levelCurrent = SC_FOLDLEVELBASE; } } } static void FoldPascalDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; int lineFoldStateCurrent = lineCurrent > 0 ? styler.GetLineState(lineCurrent - 1) & stateFoldMaskAll : 0; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; int lastStart = 0; CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true); for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && IsStreamCommentStyle(style)) { if (!IsStreamCommentStyle(stylePrev)) { levelCurrent++; } else if (!IsStreamCommentStyle(styleNext) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelCurrent--; } } if (foldComment && atEOL && IsCommentLine(lineCurrent, styler)) { if (!IsCommentLine(lineCurrent - 1, styler) && IsCommentLine(lineCurrent + 1, styler)) levelCurrent++; else if (IsCommentLine(lineCurrent - 1, styler) && !IsCommentLine(lineCurrent+1, styler)) levelCurrent--; } if (foldPreprocessor) { if (style == SCE_PAS_PREPROCESSOR && ch == '{' && chNext == '$') { ClassifyPascalPreprocessorFoldPoint(levelCurrent, lineFoldStateCurrent, i + 2, styler); } else if (style == SCE_PAS_PREPROCESSOR2 && ch == '(' && chNext == '*' && styler.SafeGetCharAt(i + 2) == '$') { ClassifyPascalPreprocessorFoldPoint(levelCurrent, lineFoldStateCurrent, i + 3, styler); } } if (stylePrev != SCE_PAS_WORD && style == SCE_PAS_WORD) { // Store last word start point. lastStart = i; } if (stylePrev == SCE_PAS_WORD && !(lineFoldStateCurrent & stateFoldInPreprocessor)) { if(setWord.Contains(ch) && !setWord.Contains(chNext)) { ClassifyPascalWordFoldPoint(levelCurrent, lineFoldStateCurrent, startPos, endPos, lastStart, i, styler); } } if (!IsASpace(ch)) visibleChars++; if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } int newLineState = (styler.GetLineState(lineCurrent) & ~stateFoldMaskAll) | lineFoldStateCurrent; styler.SetLineState(lineCurrent, newLineState); lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } } // If we didn't reach the EOL in previous loop, store line level and whitespace information. // The rest will be filled in later... int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; styler.SetLevel(lineCurrent, lev); } static const char * const pascalWordListDesc[] = { "Keywords", 0 }; LexerModule lmPascal(SCLEX_PASCAL, ColourisePascalDoc, "pascal", FoldPascalDoc, pascalWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexBaan.cxx0000644000175000017500000001344211615412040021165 00000000000000// Scintilla source code edit control /** @file LexBaan.cxx ** Lexer for Baan. ** Based heavily on LexCPP.cxx **/ // Copyright 2001- by Vamsi Potluru & Praveen Ambekar // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '$' || ch == ':'); } static inline bool IsAWordStart(const int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static void ColouriseBaanDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0; if (initStyle == SCE_BAAN_STRINGEOL) // Does not leak onto next line initStyle = SCE_BAAN_DEFAULT; int visibleChars = 0; StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.state == SCE_BAAN_OPERATOR) { sc.SetState(SCE_BAAN_DEFAULT); } else if (sc.state == SCE_BAAN_NUMBER) { if (!IsAWordChar(sc.ch)) { sc.SetState(SCE_BAAN_DEFAULT); } } else if (sc.state == SCE_BAAN_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (keywords.InList(s)) { sc.ChangeState(SCE_BAAN_WORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_BAAN_WORD2); } sc.SetState(SCE_BAAN_DEFAULT); } } else if (sc.state == SCE_BAAN_PREPROCESSOR) { if (stylingWithinPreprocessor) { if (IsASpace(sc.ch)) { sc.SetState(SCE_BAAN_DEFAULT); } } else { if (sc.atLineEnd && (sc.chNext != '^')) { sc.SetState(SCE_BAAN_DEFAULT); } } } else if (sc.state == SCE_BAAN_COMMENT) { if (sc.atLineEnd) { sc.SetState(SCE_BAAN_DEFAULT); } } else if (sc.state == SCE_BAAN_COMMENTDOC) { if (sc.MatchIgnoreCase("enddllusage")) { for (unsigned int i = 0; i < 10; i++){ sc.Forward(); } sc.ForwardSetState(SCE_BAAN_DEFAULT); } } else if (sc.state == SCE_BAAN_STRING) { if (sc.ch == '\"') { sc.ForwardSetState(SCE_BAAN_DEFAULT); } else if ((sc.atLineEnd) && (sc.chNext != '^')) { sc.ChangeState(SCE_BAAN_STRINGEOL); sc.ForwardSetState(SCE_C_DEFAULT); visibleChars = 0; } } if (sc.state == SCE_BAAN_DEFAULT) { if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_BAAN_NUMBER); } else if (sc.MatchIgnoreCase("dllusage")){ sc.SetState(SCE_BAAN_COMMENTDOC); do { sc.Forward(); } while ((!sc.atLineEnd) && sc.More()); } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_BAAN_IDENTIFIER); } else if (sc.Match('|')){ sc.SetState(SCE_BAAN_COMMENT); } else if (sc.ch == '\"') { sc.SetState(SCE_BAAN_STRING); } else if (sc.ch == '#' && visibleChars == 0) { // Preprocessor commands are alone on their line sc.SetState(SCE_BAAN_PREPROCESSOR); // Skip whitespace between # and preprocessor word do { sc.Forward(); } while (IsASpace(sc.ch) && sc.More()); } else if (isoperator(static_cast(sc.ch))) { sc.SetState(SCE_BAAN_OPERATOR); } } if (sc.atLineEnd) { // Reset states to begining of colourise so no surprises // if different sets of lines lexed. visibleChars = 0; } if (!IsASpace(sc.ch)) { visibleChars++; } } sc.Complete(); } static void FoldBaanDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; int styleNext = styler.StyleAt(startPos); int style = initStyle; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int stylePrev = style; style = styleNext; styleNext = styler.StyleAt(i + 1); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); if (foldComment && (style == SCE_BAAN_COMMENT || style == SCE_BAAN_COMMENTDOC)) { if (style != stylePrev) { levelCurrent++; } else if ((style != styleNext) && !atEOL) { // Comments don't end at end of line and the next character may be unstyled. levelCurrent--; } } if (style == SCE_BAAN_OPERATOR) { if (ch == '{') { levelCurrent++; } else if (ch == '}') { levelCurrent--; } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } LexerModule lmBaan(SCLEX_BAAN, ColouriseBaanDoc, "baan", FoldBaanDoc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexMSSQL.cxx0000644000175000017500000002661511615412040021231 00000000000000// Scintilla source code edit control /** @file LexMSSQL.cxx ** Lexer for MSSQL. **/ // By Filip Yaghob // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #define KW_MSSQL_STATEMENTS 0 #define KW_MSSQL_DATA_TYPES 1 #define KW_MSSQL_SYSTEM_TABLES 2 #define KW_MSSQL_GLOBAL_VARIABLES 3 #define KW_MSSQL_FUNCTIONS 4 #define KW_MSSQL_STORED_PROCEDURES 5 #define KW_MSSQL_OPERATORS 6 static bool isMSSQLOperator(char ch) { if (isascii(ch) && isalnum(ch)) return false; // '.' left out as it is used to make up numbers if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || ch == '-' || ch == '+' || ch == '=' || ch == '|' || ch == '<' || ch == '>' || ch == '/' || ch == '!' || ch == '~' || ch == '(' || ch == ')' || ch == ',') return true; return false; } static char classifyWordSQL(unsigned int start, unsigned int end, WordList *keywordlists[], Accessor &styler, unsigned int actualState, unsigned int prevState) { char s[256]; bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS]; WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES]; WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES]; WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES]; WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS]; WordList &kwStoredProcedures = *keywordlists[KW_MSSQL_STORED_PROCEDURES]; WordList &kwOperators = *keywordlists[KW_MSSQL_OPERATORS]; for (unsigned int i = 0; i < end - start + 1 && i < 128; i++) { s[i] = static_cast(tolower(styler[start + i])); s[i + 1] = '\0'; } char chAttr = SCE_MSSQL_IDENTIFIER; if (actualState == SCE_MSSQL_GLOBAL_VARIABLE) { if (kwGlobalVariables.InList(&s[2])) chAttr = SCE_MSSQL_GLOBAL_VARIABLE; } else if (wordIsNumber) { chAttr = SCE_MSSQL_NUMBER; } else if (prevState == SCE_MSSQL_DEFAULT_PREF_DATATYPE) { // Look first in datatypes if (kwDataTypes.InList(s)) chAttr = SCE_MSSQL_DATATYPE; else if (kwOperators.InList(s)) chAttr = SCE_MSSQL_OPERATOR; else if (kwStatements.InList(s)) chAttr = SCE_MSSQL_STATEMENT; else if (kwSystemTables.InList(s)) chAttr = SCE_MSSQL_SYSTABLE; else if (kwFunctions.InList(s)) chAttr = SCE_MSSQL_FUNCTION; else if (kwStoredProcedures.InList(s)) chAttr = SCE_MSSQL_STORED_PROCEDURE; } else { if (kwOperators.InList(s)) chAttr = SCE_MSSQL_OPERATOR; else if (kwStatements.InList(s)) chAttr = SCE_MSSQL_STATEMENT; else if (kwSystemTables.InList(s)) chAttr = SCE_MSSQL_SYSTABLE; else if (kwFunctions.InList(s)) chAttr = SCE_MSSQL_FUNCTION; else if (kwStoredProcedures.InList(s)) chAttr = SCE_MSSQL_STORED_PROCEDURE; else if (kwDataTypes.InList(s)) chAttr = SCE_MSSQL_DATATYPE; } styler.ColourTo(end, chAttr); return chAttr; } static void ColouriseMSSQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { styler.StartAt(startPos); bool fold = styler.GetPropertyInt("fold") != 0; int lineCurrent = styler.GetLine(startPos); int spaceFlags = 0; int state = initStyle; int prevState = initStyle; char chPrev = ' '; char chNext = styler[startPos]; styler.StartSegment(startPos); unsigned int lengthDoc = startPos + length; for (unsigned int i = startPos; i < lengthDoc; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags); int lev = indentCurrent; if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { // Only non whitespace lines can be headers int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags); if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) { lev |= SC_FOLDLEVELHEADERFLAG; } } if (fold) { styler.SetLevel(lineCurrent, lev); } } if (styler.IsLeadByte(ch)) { chNext = styler.SafeGetCharAt(i + 2); chPrev = ' '; i += 1; continue; } // When the last char isn't part of the state (have to deal with it too)... if ( (state == SCE_MSSQL_IDENTIFIER) || (state == SCE_MSSQL_STORED_PROCEDURE) || (state == SCE_MSSQL_DATATYPE) || //~ (state == SCE_MSSQL_COLUMN_NAME) || (state == SCE_MSSQL_FUNCTION) || //~ (state == SCE_MSSQL_GLOBAL_VARIABLE) || (state == SCE_MSSQL_VARIABLE)) { if (!iswordchar(ch)) { int stateTmp; if ((state == SCE_MSSQL_VARIABLE) || (state == SCE_MSSQL_COLUMN_NAME)) { styler.ColourTo(i - 1, state); stateTmp = state; } else stateTmp = classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState); prevState = state; if (stateTmp == SCE_MSSQL_IDENTIFIER || stateTmp == SCE_MSSQL_VARIABLE) state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; else state = SCE_MSSQL_DEFAULT; } } else if (state == SCE_MSSQL_LINE_COMMENT) { if (ch == '\r' || ch == '\n') { styler.ColourTo(i - 1, state); prevState = state; state = SCE_MSSQL_DEFAULT; } } else if (state == SCE_MSSQL_GLOBAL_VARIABLE) { if ((ch != '@') && !iswordchar(ch)) { classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState); prevState = state; state = SCE_MSSQL_DEFAULT; } } // If is the default or one of the above succeeded if (state == SCE_MSSQL_DEFAULT || state == SCE_MSSQL_DEFAULT_PREF_DATATYPE) { if (iswordstart(ch)) { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); prevState = state; state = SCE_MSSQL_IDENTIFIER; } else if (ch == '/' && chNext == '*') { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); prevState = state; state = SCE_MSSQL_COMMENT; } else if (ch == '-' && chNext == '-') { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); prevState = state; state = SCE_MSSQL_LINE_COMMENT; } else if (ch == '\'') { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); prevState = state; state = SCE_MSSQL_STRING; } else if (ch == '"') { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); prevState = state; state = SCE_MSSQL_COLUMN_NAME; } else if (ch == '[') { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); prevState = state; state = SCE_MSSQL_COLUMN_NAME_2; } else if (isMSSQLOperator(ch)) { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); styler.ColourTo(i, SCE_MSSQL_OPERATOR); //~ style = SCE_MSSQL_DEFAULT; prevState = state; state = SCE_MSSQL_DEFAULT; } else if (ch == '@') { styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); prevState = state; if (chNext == '@') { state = SCE_MSSQL_GLOBAL_VARIABLE; // i += 2; } else state = SCE_MSSQL_VARIABLE; } // When the last char is part of the state... } else if (state == SCE_MSSQL_COMMENT) { if (ch == '/' && chPrev == '*') { if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_MSSQL_COMMENT) && (styler.GetStartSegment() == startPos)))) { styler.ColourTo(i, state); //~ state = SCE_MSSQL_COMMENT; prevState = state; state = SCE_MSSQL_DEFAULT; } } } else if (state == SCE_MSSQL_STRING) { if (ch == '\'') { if ( chNext == '\'' ) { i++; ch = chNext; chNext = styler.SafeGetCharAt(i + 1); } else { styler.ColourTo(i, state); prevState = state; state = SCE_MSSQL_DEFAULT; //i++; } //ch = chNext; //chNext = styler.SafeGetCharAt(i + 1); } } else if (state == SCE_MSSQL_COLUMN_NAME) { if (ch == '"') { if (chNext == '"') { i++; ch = chNext; chNext = styler.SafeGetCharAt(i + 1); } else { styler.ColourTo(i, state); prevState = state; state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; //i++; } } } else if (state == SCE_MSSQL_COLUMN_NAME_2) { if (ch == ']') { styler.ColourTo(i, state); prevState = state; state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; //i++; } } chPrev = ch; } styler.ColourTo(lengthDoc - 1, state); } static void FoldMSSQLDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { bool foldComment = styler.GetPropertyInt("fold.comment") != 0; bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; unsigned int endPos = startPos + length; int visibleChars = 0; int lineCurrent = styler.GetLine(startPos); int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; int levelCurrent = levelPrev; char chNext = styler[startPos]; bool inComment = (styler.StyleAt(startPos-1) == SCE_MSSQL_COMMENT); char s[10]; for (unsigned int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); int style = styler.StyleAt(i); bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); // Comment folding if (foldComment) { if (!inComment && (style == SCE_MSSQL_COMMENT)) levelCurrent++; else if (inComment && (style != SCE_MSSQL_COMMENT)) levelCurrent--; inComment = (style == SCE_MSSQL_COMMENT); } if (style == SCE_MSSQL_STATEMENT) { // Folding between begin or case and end if (ch == 'b' || ch == 'B' || ch == 'c' || ch == 'C' || ch == 'e' || ch == 'E') { for (unsigned int j = 0; j < 5; j++) { if (!iswordchar(styler[i + j])) { break; } s[j] = static_cast(tolower(styler[i + j])); s[j + 1] = '\0'; } if ((strcmp(s, "begin") == 0) || (strcmp(s, "case") == 0)) { levelCurrent++; } if (strcmp(s, "end") == 0) { levelCurrent--; } } } if (atEOL) { int lev = levelPrev; if (visibleChars == 0 && foldCompact) lev |= SC_FOLDLEVELWHITEFLAG; if ((levelCurrent > levelPrev) && (visibleChars > 0)) lev |= SC_FOLDLEVELHEADERFLAG; if (lev != styler.LevelAt(lineCurrent)) { styler.SetLevel(lineCurrent, lev); } lineCurrent++; levelPrev = levelCurrent; visibleChars = 0; } if (!isspacechar(ch)) visibleChars++; } // Fill in the real level of the next line, keeping the current flags as they will be filled in later int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; styler.SetLevel(lineCurrent, levelPrev | flagsNext); } static const char * const sqlWordListDesc[] = { "Statements", "Data Types", "System tables", "Global variables", "Functions", "System Stored Procedures", "Operators", 0, }; LexerModule lmMSSQL(SCLEX_MSSQL, ColouriseMSSQLDoc, "mssql", FoldMSSQLDoc, sqlWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexVB.cxx0000644000175000017500000002310211615412040020625 00000000000000// Scintilla source code edit control /** @file LexVB.cxx ** Lexer for Visual Basic and VBScript. **/ // Copyright 1998-2005 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Internal state, highlighted as number #define SCE_B_FILENUMBER SCE_B_DEFAULT+100 static bool IsVBComment(Accessor &styler, int pos, int len) { return len > 0 && styler[pos] == '\''; } static inline bool IsTypeCharacter(int ch) { return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$'; } // Extended to accept accented characters static inline bool IsAWordChar(int ch) { return ch >= 0x80 || (isalnum(ch) || ch == '.' || ch == '_'); } static inline bool IsAWordStart(int ch) { return ch >= 0x80 || (isalpha(ch) || ch == '_'); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || toupper(ch) == 'E' || ch == '.' || ch == '-' || ch == '+'); } static void ColouriseVBDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler, bool vbScriptSyntax) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; styler.StartAt(startPos); int visibleChars = 0; int fileNbDigits = 0; // Do not leak onto next line if (initStyle == SCE_B_STRINGEOL || initStyle == SCE_B_COMMENT || initStyle == SCE_B_PREPROCESSOR) { initStyle = SCE_B_DEFAULT; } StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { if (sc.state == SCE_B_OPERATOR) { sc.SetState(SCE_B_DEFAULT); } else if (sc.state == SCE_B_IDENTIFIER) { if (!IsAWordChar(sc.ch)) { // In Basic (except VBScript), a variable name or a function name // can end with a special character indicating the type of the value // held or returned. bool skipType = false; if (!vbScriptSyntax && IsTypeCharacter(sc.ch)) { sc.Forward(); // Skip it skipType = true; } if (sc.ch == ']') { sc.Forward(); } char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (skipType) { s[strlen(s) - 1] = '\0'; } if (strcmp(s, "rem") == 0) { sc.ChangeState(SCE_B_COMMENT); } else { if (keywords.InList(s)) { sc.ChangeState(SCE_B_KEYWORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_B_KEYWORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_B_KEYWORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_B_KEYWORD4); } // Else, it is really an identifier... sc.SetState(SCE_B_DEFAULT); } } } else if (sc.state == SCE_B_NUMBER) { // We stop the number definition on non-numerical non-dot non-eE non-sign char // Also accepts A-F for hex. numbers if (!IsANumberChar(sc.ch) && !(tolower(sc.ch) >= 'a' && tolower(sc.ch) <= 'f')) { sc.SetState(SCE_B_DEFAULT); } } else if (sc.state == SCE_B_STRING) { // VB doubles quotes to preserve them, so just end this string // state now as a following quote will start again if (sc.ch == '\"') { if (sc.chNext == '\"') { sc.Forward(); } else { if (tolower(sc.chNext) == 'c') { sc.Forward(); } sc.ForwardSetState(SCE_B_DEFAULT); } } else if (sc.atLineEnd) { visibleChars = 0; sc.ChangeState(SCE_B_STRINGEOL); sc.ForwardSetState(SCE_B_DEFAULT); } } else if (sc.state == SCE_B_COMMENT) { if (sc.atLineEnd) { visibleChars = 0; sc.ForwardSetState(SCE_B_DEFAULT); } } else if (sc.state == SCE_B_PREPROCESSOR) { if (sc.atLineEnd) { visibleChars = 0; sc.ForwardSetState(SCE_B_DEFAULT); } } else if (sc.state == SCE_B_FILENUMBER) { if (IsADigit(sc.ch)) { fileNbDigits++; if (fileNbDigits > 3) { sc.ChangeState(SCE_B_DATE); } } else if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ',') { // Regular uses: Close #1; Put #1, ...; Get #1, ... etc. // Too bad if date is format #27, Oct, 2003# or something like that... // Use regular number state sc.ChangeState(SCE_B_NUMBER); sc.SetState(SCE_B_DEFAULT); } else if (sc.ch == '#') { sc.ChangeState(SCE_B_DATE); sc.ForwardSetState(SCE_B_DEFAULT); } else { sc.ChangeState(SCE_B_DATE); } if (sc.state != SCE_B_FILENUMBER) { fileNbDigits = 0; } } else if (sc.state == SCE_B_DATE) { if (sc.atLineEnd) { visibleChars = 0; sc.ChangeState(SCE_B_STRINGEOL); sc.ForwardSetState(SCE_B_DEFAULT); } else if (sc.ch == '#') { sc.ForwardSetState(SCE_B_DEFAULT); } } if (sc.state == SCE_B_DEFAULT) { if (sc.ch == '\'') { sc.SetState(SCE_B_COMMENT); } else if (sc.ch == '\"') { sc.SetState(SCE_B_STRING); } else if (sc.ch == '#' && visibleChars == 0) { // Preprocessor commands are alone on their line sc.SetState(SCE_B_PREPROCESSOR); } else if (sc.ch == '#') { // It can be a date literal, ending with #, or a file number, from 1 to 511 // The date literal depends on the locale, so anything can go between #'s. // Can be #January 1, 1993# or #1 Jan 93# or #05/11/2003#, etc. // So we set the FILENUMBER state, and switch to DATE if it isn't a file number sc.SetState(SCE_B_FILENUMBER); } else if (sc.ch == '&' && tolower(sc.chNext) == 'h') { // Hexadecimal number sc.SetState(SCE_B_NUMBER); sc.Forward(); } else if (sc.ch == '&' && tolower(sc.chNext) == 'o') { // Octal number sc.SetState(SCE_B_NUMBER); sc.Forward(); } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) { sc.SetState(SCE_B_NUMBER); } else if (IsAWordStart(sc.ch) || (sc.ch == '[')) { sc.SetState(SCE_B_IDENTIFIER); } else if (isoperator(static_cast(sc.ch)) || (sc.ch == '\\')) { // Integer division sc.SetState(SCE_B_OPERATOR); } } if (sc.atLineEnd) { visibleChars = 0; } if (!IsASpace(sc.ch)) { visibleChars++; } } if (sc.state == SCE_B_IDENTIFIER && !IsAWordChar(sc.ch)) { // In Basic (except VBScript), a variable name or a function name // can end with a special character indicating the type of the value // held or returned. bool skipType = false; if (!vbScriptSyntax && IsTypeCharacter(sc.ch)) { sc.Forward(); // Skip it skipType = true; } if (sc.ch == ']') { sc.Forward(); } char s[100]; sc.GetCurrentLowered(s, sizeof(s)); if (skipType) { s[strlen(s) - 1] = '\0'; } if (strcmp(s, "rem") == 0) { sc.ChangeState(SCE_B_COMMENT); } else { if (keywords.InList(s)) { sc.ChangeState(SCE_B_KEYWORD); } else if (keywords2.InList(s)) { sc.ChangeState(SCE_B_KEYWORD2); } else if (keywords3.InList(s)) { sc.ChangeState(SCE_B_KEYWORD3); } else if (keywords4.InList(s)) { sc.ChangeState(SCE_B_KEYWORD4); } // Else, it is really an identifier... sc.SetState(SCE_B_DEFAULT); } } sc.Complete(); } static void FoldVBDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { int endPos = startPos + length; // Backtrack to previous line in case need to fix its fold status int lineCurrent = styler.GetLine(startPos); if (startPos > 0) { if (lineCurrent > 0) { lineCurrent--; startPos = styler.LineStart(lineCurrent); } } int spaceFlags = 0; int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsVBComment); char chNext = styler[startPos]; for (int i = startPos; i < endPos; i++) { char ch = chNext; chNext = styler.SafeGetCharAt(i + 1); if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) { int lev = indentCurrent; int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsVBComment); if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { // Only non whitespace lines can be headers if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } else if (indentNext & SC_FOLDLEVELWHITEFLAG) { // Line after is blank so check the next - maybe should continue further? int spaceFlags2 = 0; int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsVBComment); if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) { lev |= SC_FOLDLEVELHEADERFLAG; } } } indentCurrent = indentNext; styler.SetLevel(lineCurrent, lev); lineCurrent++; } } } static void ColouriseVBNetDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, false); } static void ColouriseVBScriptDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { ColouriseVBDoc(startPos, length, initStyle, keywordlists, styler, true); } static const char * const vbWordListDesc[] = { "Keywords", "user1", "user2", "user3", 0 }; LexerModule lmVB(SCLEX_VB, ColouriseVBNetDoc, "vb", FoldVBDoc, vbWordListDesc); LexerModule lmVBScript(SCLEX_VBSCRIPT, ColouriseVBScriptDoc, "vbscript", FoldVBDoc, vbWordListDesc); presage-0.8.8/apps/gtk/gprompter/scintilla/lexers/LexLua.cxx0000644000175000017500000003246711634611460021065 00000000000000// Scintilla source code edit control /** @file LexLua.cxx ** Lexer for Lua language. ** ** Written by Paul Winwood. ** Folder by Alexey Yutkin. ** Modified by Marcos E. Wurzius & Philippe Lhoste **/ #include #include #include #include #include #include #include "ILexer.h" #include "Scintilla.h" #include "SciLexer.h" #include "WordList.h" #include "LexAccessor.h" #include "Accessor.h" #include "StyleContext.h" #include "CharacterSet.h" #include "LexerModule.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif // Test for [=[ ... ]=] delimiters, returns 0 if it's only a [ or ], // return 1 for [[ or ]], returns >=2 for [=[ or ]=] and so on. // The maximum number of '=' characters allowed is 254. static int LongDelimCheck(StyleContext &sc) { int sep = 1; while (sc.GetRelative(sep) == '=' && sep < 0xFF) sep++; if (sc.GetRelative(sep) == sc.ch) return sep; return 0; } static void ColouriseLuaDoc( unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { WordList &keywords = *keywordlists[0]; WordList &keywords2 = *keywordlists[1]; WordList &keywords3 = *keywordlists[2]; WordList &keywords4 = *keywordlists[3]; WordList &keywords5 = *keywordlists[4]; WordList &keywords6 = *keywordlists[5]; WordList &keywords7 = *keywordlists[6]; WordList &keywords8 = *keywordlists[7]; // Accepts accented characters CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true); CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true); // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. [pP] is for hex floats. CharacterSet setNumber(CharacterSet::setDigits, ".-+abcdefpABCDEFP"); CharacterSet setExponent(CharacterSet::setNone, "eEpP"); CharacterSet setLuaOperator(CharacterSet::setNone, "*/-+()={}~[];<>,.^%:#"); CharacterSet setEscapeSkip(CharacterSet::setNone, "\"'\\"); int currentLine = styler.GetLine(startPos); // Initialize long string [[ ... ]] or block comment --[[ ... ]] nesting level, // if we are inside such a string. Block comment was introduced in Lua 5.0, // blocks with separators [=[ ... ]=] in Lua 5.1. // Continuation of a string (\z whitespace escaping) is controlled by stringWs. int nestLevel = 0; int sepCount = 0; int stringWs = 0; if (initStyle == SCE_LUA_LITERALSTRING || initStyle == SCE_LUA_COMMENT || initStyle == SCE_LUA_STRING || initStyle == SCE_LUA_CHARACTER) { int lineState = styler.GetLineState(currentLine - 1); nestLevel = lineState >> 9; sepCount = lineState & 0xFF; stringWs = lineState & 0x100; } // Do not leak onto next line if (initStyle == SCE_LUA_STRINGEOL || initStyle == SCE_LUA_COMMENTLINE || initStyle == SCE_LUA_PREPROCESSOR) { initStyle = SCE_LUA_DEFAULT; } StyleContext sc(startPos, length, initStyle, styler); if (startPos == 0 && sc.ch == '#') { // shbang line: # is a comment only if first char of the script sc.SetState(SCE_LUA_COMMENTLINE); } for (; sc.More(); sc.Forward()) { if (sc.atLineEnd) { // Update the line state, so it can be seen by next line currentLine = styler.GetLine(sc.currentPos); switch (sc.state) { case SCE_LUA_LITERALSTRING: case SCE_LUA_COMMENT: case SCE_LUA_STRING: case SCE_LUA_CHARACTER: // Inside a literal string, block comment or string, we set the line state styler.SetLineState(currentLine, (nestLevel << 9) | stringWs | sepCount); break; default: // Reset the line state styler.SetLineState(currentLine, 0); break; } } if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) { // Prevent SCE_LUA_STRINGEOL from leaking back to previous line sc.SetState(SCE_LUA_STRING); } // Handle string line continuation if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) && sc.ch == '\\') { if (sc.chNext == '\n' || sc.chNext == '\r') { sc.Forward(); if (sc.ch == '\r' && sc.chNext == '\n') { sc.Forward(); } continue; } } // Determine if the current state should terminate. if (sc.state == SCE_LUA_OPERATOR) { if (sc.ch == ':' && sc.chPrev == ':') { // ::