Initial revision
authorMarc Cromme <marc@indexdata.dk>
Thu, 6 Oct 2005 09:37:25 +0000 (09:37 +0000)
committerMarc Cromme <marc@indexdata.dk>
Thu, 6 Oct 2005 09:37:25 +0000 (09:37 +0000)
25 files changed:
.cvsignore [new file with mode: 0644]
Doxyfile.in [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
buildconf.sh [new file with mode: 0755]
configure.in [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/msg-thread.cpp [new file with mode: 0644]
src/msg-thread.h [new file with mode: 0644]
src/p2.cpp [new file with mode: 0644]
src/p2_backend.h [new file with mode: 0644]
src/p2_backend_dummy.cpp [new file with mode: 0644]
src/p2_config.cpp [new file with mode: 0644]
src/p2_config.h [new file with mode: 0644]
src/p2_frontend.cpp [new file with mode: 0644]
src/p2_frontend.h [new file with mode: 0644]
src/p2_modules.cpp [new file with mode: 0644]
src/p2_modules.h [new file with mode: 0644]
src/p2_msg.cpp [new file with mode: 0644]
src/p2_xmlerror.cpp [new file with mode: 0644]
src/p2_xmlerror.h [new file with mode: 0644]
src/p3_filter.h [new file with mode: 0644]
src/p3_main.cpp [new file with mode: 0644]
usemarcon.m4 [new file with mode: 0644]
yaz.m4 [new file with mode: 0644]
yazpp.m4 [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..d572015
--- /dev/null
@@ -0,0 +1,9 @@
+Makefile
+Makefile.in
+aclocal.m4
+config.cache
+config.log
+config.status
+configure
+libtool
+autom4te.cache
diff --git a/Doxyfile.in b/Doxyfile.in
new file mode 100644 (file)
index 0000000..052549a
--- /dev/null
@@ -0,0 +1,1153 @@
+# Doxyfile 1.3.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = YAZ
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = @VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = dox
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of source 
+# files, where putting all generated files in the same directory would otherwise 
+# cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, 
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, 
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, 
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is used 
+# as the annotated text. Otherwise, the brief description is used as-is. If left 
+# blank, the following values are used ("$name" is automatically replaced with the 
+# name of the entity): "The $name class" "The $name widget" "The $name file" 
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = src include
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = "YAZ_BEGIN_CDECL= " "YAZ_END_CDECL=" "YAZ_EXPORT="
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = YAZ_BEGIN_CDECL YAZ_END_CDECL YAZ_EXPORT
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes that 
+# lay further from the root node will be omitted. Note that setting this option to 
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also 
+# note that a graph may be further truncated if the graph's image dimensions are 
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). 
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..16e47c8
--- /dev/null
@@ -0,0 +1,16 @@
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = src include etc doc 
+
+EXTRA_DIST= README LICENSE yazpp.m4 yaz.m4 usemarcon.m4 buildconf.sh
+
+dist-hook:
+       mkdir $(distdir)/win
+       cp $(srcdir)/win/makefile $(distdir)/win/
+       mkdir $(distdir)/debian
+       cp $(srcdir)/debian/control $(distdir)/debian
+       cp $(srcdir)/debian/changelog $(distdir)/debian
+       cp $(srcdir)/debian/rules $(distdir)/debian
+       cp $(srcdir)/debian/postinst $(distdir)/debian
+       cp $(srcdir)/debian/compat $(distdir)/debian
+       cp $(srcdir)/debian/*.install $(distdir)/debian
diff --git a/buildconf.sh b/buildconf.sh
new file mode 100755 (executable)
index 0000000..434e2f8
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/sh
+# $Id: buildconf.sh,v 1.1 2005-10-06 09:37:25 marc Exp $
+set -x
+aclocal -I .
+libtoolize --automake --force 
+automake --add-missing 
+autoconf
+set -
+if [ -f config.cache ]; then
+       rm config.cache
+fi
+
+enable_configure=false
+enable_help=true
+sh_flags=""
+conf_flags=""
+case $1 in
+    -d)
+       sh_flags="-g -Wall"
+       enable_configure=true
+       enable_help=false
+       shift
+       ;;
+    -c)
+       sh_flags=""
+       enable_configure=true
+       enable_help=false
+       shift
+       ;;
+esac
+
+if $enable_configure; then
+    if test -n "$sh_flags"; then
+       CXXFLAGS="$sh_flags" ./configure $*
+    else
+       ./configure $*
+    fi
+fi
+if $enable_help; then
+    cat <<EOF
+
+Build the Makefiles with the configure command.
+  ./configure [--someoption=somevalue ...]
+
+For help on options or configuring run
+  ./configure --help
+
+Build and install binaries with the usual
+  make
+  make check
+  make install
+
+Build distribution tarball with
+  make dist
+
+Verify distribution tarball with
+  make distcheck
+
+Or just build the Debian packages without configuring
+  dpkg-buildpackage -rfakeroot
+
+When building from a CVS checkout, you need these Debian tools:
+  docbook-utils, docbook, docbook-xml, docbook-dsssl, jade, jadetex,
+  libxslt1-dev, libyaz++-dev
+EOF
+fi
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..a41d27c
--- /dev/null
@@ -0,0 +1,64 @@
+AC_INIT(configure.in)
+AM_INIT_AUTOMAKE(yazproxy,1.1.0)
+
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AC_HEADER_STDC
+AM_PROG_LIBTOOL
+
+YAZPP_INIT(threads,1.0)
+if test -z "$YAZPPLIB"; then
+       AC_MSG_ERROR([YAZ++ development libraries missing])
+fi
+YAZ_DOC
+USEMARCON_INIT
+
+AC_CHECK_FUNCS(setrlimit getrlimit gettimeofday)
+AC_CHECK_HEADERS(pwd.h sys/resource.h sys/stat.h sys/time.h sys/types.h sys/wait.h unistd.h)
+AC_CHECK_LIB(dl,dlopen)
+dnl
+dnl ----- libXSLT
+AC_SUBST(XSLT_LIBS)
+AC_SUBST(XSLT_CFLAGS)
+xsltdir=default
+AC_ARG_WITH(xslt,[[  --with-xslt[=PREFIX]    use libxslt in PREFIX]],xsltdir=$withval)
+if test "$xsltdir" = "yes" -o "$xsltdir" = "default"; then
+       for d in /usr /usr/local; do
+               if test -x $d/bin/xslt-config; then
+                       xsltdir=$d
+               fi
+       done
+fi
+if test "$xsltdir" != "no"; then
+       AC_MSG_CHECKING(for libXSLT)
+       if test -x $xsltdir/bin/xslt-config; then
+               XSLT_LIBS=`$xsltdir/bin/xslt-config --libs`
+               XSLT_CFLAGS=`$xsltdir/bin/xslt-config --cflags`
+               XSLT_VER=`$xsltdir/bin/xslt-config --version`
+               AC_MSG_RESULT($XSLT_VER)
+               AC_DEFINE(HAVE_XSLT)
+       else
+               AC_MSG_RESULT(Not found)
+                if test "$xsltdir" = "default"; then
+                        AC_MSG_WARN([Libxslt development libraries not found.])
+                else
+                        AC_MSG_ERROR([libxslt development libraries not found.])                fi
+       fi
+fi
+
+AC_SUBST(YAZPROXY_SRC_ROOT)
+AC_SUBST(YAZPROXY_BUILD_ROOT)
+YAZPROXY_SRC_ROOT=`cd ${srcdir}; pwd`
+YAZPROXY_BUILD_ROOT=`pwd`
+AC_OUTPUT([
+       Makefile
+       src/Makefile
+       include/Makefile
+       include/yazproxy/Makefile
+       doc/Makefile
+       doc/yazproxy.xml
+       doc/yazprint.dsl doc/yazphp.dsl doc/yazhtml.dsl
+        doc/tkl.xsl
+       etc/Makefile
+])
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..c650337
--- /dev/null
@@ -0,0 +1,35 @@
+## $Id: Makefile.am,v 1.1 2005-10-06 09:37:25 marc Exp $
+
+AM_CXXFLAGS = $(YAZPPINC) -I$(srcdir)/../include $(XSLT_CFLAGS) $(USEMARCONINC)
+
+lib_LTLIBRARIES = libyazproxy.la
+libyazproxy_la_LDFLAGS=-version-info 1:0:0
+
+libyazproxy_la_SOURCES= yaz-proxy.cpp yaz-proxy-config.cpp yaz-bw.cpp \
+ proxyp.h yaz-usemarcon.cpp charset-converter.cpp msg-thread.cpp msg-thread.h \
+ modules.cpp
+
+bin_PROGRAMS = yazproxy
+check_PROGRAMS = cdetails
+noinst_PROGRAMS = tstthreads t-server p2
+
+TESTS=$(check_PROGRAMS)
+
+yazproxy_SOURCES=yaz-proxy-main.cpp
+cdetails_SOURCES=cdetails.cpp
+tstthreads_SOURCES=tstthreads.cpp
+t_server_SOURCES=t-server.cpp
+p2_SOURCES=p2_frontend.cpp p2_msg.cpp p2.cpp p2_frontend.h \
+ p2_config.cpp p2_config.h \
+ p2_backend.h p2_backend_dummy.cpp \
+ p2_modules.cpp p2_modules.h \
+ p2_xmlerror.cpp p2_xmlerror.h
+
+LDADD=libyazproxy.la $(YAZPPLALIB) $(XSLT_LIBS) $(USEMARCONLALIB)
+libyazproxy_la_LIBADD = $(XSLT_LIBS)
+
+# Modules
+mod_proxy_sample_la_SOURCES = mod_sample.cpp
+mod_proxy_sample_la_LDFLAGS = -rpath $(pkglibdir) -module -avoid-version
+
+pkglib_LTLIBRARIES = mod_proxy_sample.la
diff --git a/src/msg-thread.cpp b/src/msg-thread.cpp
new file mode 100644 (file)
index 0000000..2f82157
--- /dev/null
@@ -0,0 +1,173 @@
+/* $Id: msg-thread.cpp,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include <yaz++/socket-observer.h>
+#include <yaz/log.h>
+
+#include "msg-thread.h"
+
+using namespace yazpp_1;
+
+IMsg_Thread::~IMsg_Thread()
+{
+
+}
+
+Msg_Thread_Queue::Msg_Thread_Queue()
+{
+    m_list = 0;
+}
+
+int Msg_Thread_Queue::size()
+{
+    int no = 0;
+    Msg_Thread_Queue_List *l;
+    for (l = m_list; l; l = l->m_next)
+        no++;
+    return no;
+}
+
+void Msg_Thread_Queue::enqueue(IMsg_Thread *m)
+{
+    Msg_Thread_Queue_List *l = new Msg_Thread_Queue_List;
+    l->m_next = m_list;
+    l->m_item = m;
+    m_list = l;
+}
+
+IMsg_Thread *Msg_Thread_Queue::dequeue()
+{
+    Msg_Thread_Queue_List **l = &m_list;
+    if (!*l)
+        return 0;
+    while ((*l)->m_next)
+        l = &(*l)->m_next;
+    IMsg_Thread *m = (*l)->m_item;
+    delete *l;
+    *l = 0;
+    return m;
+}
+
+static void *tfunc(void *p)
+{
+    Msg_Thread *pt = (Msg_Thread *) p;
+    pt->run(0);
+    return 0;
+}
+
+
+Msg_Thread::Msg_Thread(ISocketObservable *obs, int no_threads)
+    : m_SocketObservable(obs)
+{
+    pipe(m_fd);
+    obs->addObserver(m_fd[0], this);
+    obs->maskObserver(this, SOCKET_OBSERVE_READ);
+
+    m_stop_flag = false;
+    pthread_mutex_init(&m_mutex_input_data, 0);
+    pthread_cond_init(&m_cond_input_data, 0);
+    pthread_mutex_init(&m_mutex_output_data, 0);
+
+    m_no_threads = no_threads;
+    m_thread_id = new pthread_t[no_threads];
+    int i;
+    for (i = 0; i<m_no_threads; i++)
+        pthread_create(&m_thread_id[i], 0, tfunc, this);
+}
+
+Msg_Thread::~Msg_Thread()
+{
+    pthread_mutex_lock(&m_mutex_input_data);
+    m_stop_flag = true;
+    pthread_cond_broadcast(&m_cond_input_data);
+    pthread_mutex_unlock(&m_mutex_input_data);
+    
+    int i;
+    for (i = 0; i<m_no_threads; i++)
+        pthread_join(m_thread_id[i], 0);
+    delete [] m_thread_id;
+
+    m_SocketObservable->deleteObserver(this);
+
+    pthread_cond_destroy(&m_cond_input_data);
+    pthread_mutex_destroy(&m_mutex_input_data);
+    pthread_mutex_destroy(&m_mutex_output_data);
+    close(m_fd[0]);
+    close(m_fd[1]);
+}
+
+void Msg_Thread::socketNotify(int event)
+{
+    if (event & SOCKET_OBSERVE_READ)
+    {
+        char buf[2];
+        read(m_fd[0], buf, 1);
+        pthread_mutex_lock(&m_mutex_output_data);
+        IMsg_Thread *out = m_output.dequeue();
+        pthread_mutex_unlock(&m_mutex_output_data);
+        if (out)
+            out->result();
+    }
+}
+
+void Msg_Thread::run(void *p)
+{
+    while(1)
+    {
+        pthread_mutex_lock(&m_mutex_input_data);
+        while (!m_stop_flag && m_input.size() == 0)
+            pthread_cond_wait(&m_cond_input_data, &m_mutex_input_data);
+        if (m_stop_flag)
+        {
+            pthread_mutex_unlock(&m_mutex_input_data);
+            break;
+        }
+        IMsg_Thread *in = m_input.dequeue();
+        pthread_mutex_unlock(&m_mutex_input_data);
+
+        IMsg_Thread *out = in->handle();
+        pthread_mutex_lock(&m_mutex_output_data);
+        m_output.enqueue(out);
+        
+        write(m_fd[1], "", 1);
+        pthread_mutex_unlock(&m_mutex_output_data);
+    }
+}
+
+void Msg_Thread::put(IMsg_Thread *m)
+{
+    pthread_mutex_lock(&m_mutex_input_data);
+    m_input.enqueue(m);
+    pthread_cond_signal(&m_cond_input_data);
+    pthread_mutex_unlock(&m_mutex_input_data);
+}
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/msg-thread.h b/src/msg-thread.h
new file mode 100644 (file)
index 0000000..0218c3c
--- /dev/null
@@ -0,0 +1,85 @@
+/* $Id: msg-thread.h,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <pthread.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <yaz++/socket-observer.h>
+#include <yaz/yconfig.h>
+
+class IMsg_Thread {
+public:
+    virtual IMsg_Thread *handle() = 0;
+    virtual void result() = 0;
+    virtual ~IMsg_Thread();
+};
+
+class Msg_Thread_Queue_List {
+    friend class Msg_Thread_Queue;
+ private:
+    IMsg_Thread *m_item;
+    Msg_Thread_Queue_List *m_next;
+};
+
+class Msg_Thread_Queue {
+ public:
+    Msg_Thread_Queue();
+    void enqueue(IMsg_Thread *in);
+    IMsg_Thread *dequeue();
+    int size();
+ private:
+    Msg_Thread_Queue_List *m_list;
+};
+
+class Msg_Thread : public yazpp_1::ISocketObserver {
+ public:
+    Msg_Thread(yazpp_1::ISocketObservable *obs, int no_threads);
+    virtual ~Msg_Thread();
+    void socketNotify(int event);
+    void put(IMsg_Thread *m);
+    IMsg_Thread *get();
+    void run(void *p);
+    int m_fd[2];
+private:
+    yazpp_1::ISocketObservable *m_SocketObservable;
+    int m_no_threads;
+    pthread_t *m_thread_id;
+    Msg_Thread_Queue m_input;
+    Msg_Thread_Queue m_output;
+    pthread_mutex_t m_mutex_input_data;
+    pthread_cond_t m_cond_input_data;
+    pthread_mutex_t m_mutex_output_data;
+    bool m_stop_flag;
+};
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/p2.cpp b/src/p2.cpp
new file mode 100644 (file)
index 0000000..11f8716
--- /dev/null
@@ -0,0 +1,146 @@
+/* $Id: p2.cpp,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <yaz/log.h>
+#include <yaz/diagbib1.h>
+#include <yaz/options.h>
+
+#include <yaz++/socket-manager.h>
+#include "p2_config.h"
+#include "p2_frontend.h"
+#include "p2_xmlerror.h"
+#include "p2_modules.h"
+
+using namespace yazpp_1;
+
+extern P2_ModuleEntry *p2_backend_dummy;
+
+/*
+  frontend result set map
+    resultset -> db,query
+
+  backend result set map
+    db,query -> resultset, target
+                resultset, target
+*/
+class P2_Frontend;
+
+P2_Config *P2_Server::lockConfig()
+{
+    pthread_mutex_lock(&m_mutex_config);
+    return m_config;
+}
+
+void P2_Server::unlockConfig()
+{
+    pthread_mutex_unlock(&m_mutex_config);
+}
+
+P2_Server::P2_Server(IPDU_Observable *the_PDU_Observable,
+                     Msg_Thread *my_thread,
+                     P2_Config *config,
+                     P2_ModuleFactory *modules)
+    :  Z_Assoc(the_PDU_Observable)
+{
+    m_my_thread = my_thread;
+    m_modules = modules;
+    m_config = config;
+
+    pthread_mutex_init(&m_mutex_config, 0);
+    
+    yaz_log(YLOG_LOG, "Construct P2_Server=%p", this);
+}
+
+IPDU_Observer *P2_Server::sessionNotify(IPDU_Observable
+                                       *the_PDU_Observable, int fd)
+{
+    P2_Frontend *my = new P2_Frontend(the_PDU_Observable, m_my_thread, this);
+    yaz_log(YLOG_LOG, "New session %s", the_PDU_Observable->getpeername());
+    return my;
+}
+
+P2_Server::~P2_Server()
+{
+    yaz_log(YLOG_LOG, "Destroy P2_server=%p", this);
+    pthread_mutex_destroy(&m_mutex_config);
+}
+
+void P2_Server::recv_GDU(Z_GDU *apdu, int len)
+{
+}
+
+void P2_Server::failNotify()
+{
+}
+
+void P2_Server::timeoutNotify()
+{
+}
+
+void P2_Server::connectNotify()
+{
+}
+
+int main(int argc, char **argv)
+{
+    p2_xmlerror_setup();
+
+    P2_Config config;
+
+    if (!config.parse_options(argc, argv))
+    {
+        yaz_log(YLOG_FATAL, "Configuration incorrect. Exiting");
+        exit(1);
+    }
+
+    SocketManager mySocketManager;
+
+    PDU_Assoc *my_PDU_Assoc = 0;
+    
+    Msg_Thread my_thread(&mySocketManager, config.m_no_threads);
+
+    my_PDU_Assoc = new PDU_Assoc(&mySocketManager);
+
+    P2_ModuleFactory modules;
+
+    modules.add(p2_backend_dummy);
+
+    std::list<P2_ConfigModule *>::const_iterator it;
+    for (it = config.m_modules.begin(); it != config.m_modules.end(); it++)
+        modules.add((*it)->m_fname.c_str());
+    
+    P2_Server z(my_PDU_Assoc, &my_thread, &config, &modules);
+    z.server(config.m_listen_address.c_str());
+
+    while (mySocketManager.processEvent() > 0)
+        ;
+    return 0;
+}
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/p2_backend.h b/src/p2_backend.h
new file mode 100644 (file)
index 0000000..b5864b3
--- /dev/null
@@ -0,0 +1,31 @@
+
+#ifndef P2_BACKEND_H
+#define P2_BACKEND_H
+
+#include <yaz++/z-query.h>
+
+class IP2_BackendSet {
+public:
+    virtual ~IP2_BackendSet();
+    virtual int get(int start, int number) = 0;
+};
+
+class IP2_Backend {
+ public:
+    virtual ~IP2_Backend();
+    virtual int search(yazpp_1::Yaz_Z_Query *q, IP2_BackendSet **rset, int *hits) = 0;
+};
+
+struct P2_ModuleInterface0 {
+    IP2_Backend *(*create)(const char *address);
+};
+    
+struct P2_ModuleEntry {
+    int version;
+    const char *name;
+    const char *description;
+    void *interface_ptr;
+};
+
+    
+#endif
diff --git a/src/p2_backend_dummy.cpp b/src/p2_backend_dummy.cpp
new file mode 100644 (file)
index 0000000..79e8490
--- /dev/null
@@ -0,0 +1,74 @@
+
+#include <yaz/log.h>
+#include "p2_backend.h"
+
+class P2_BackendSetDummy : public IP2_BackendSet {
+public:
+    P2_BackendSetDummy();
+    ~P2_BackendSetDummy();
+    int get(int start, int number);
+};
+
+class P2_BackendDummy : public IP2_Backend {
+public:
+    P2_BackendDummy(const char *address);
+    ~P2_BackendDummy();
+    int search(yazpp_1::Yaz_Z_Query *q, IP2_BackendSet **rset, int *hits);
+};
+
+P2_BackendDummy::P2_BackendDummy(const char *address)
+{
+    yaz_log(YLOG_LOG, "P2_backendDummy %p create", this);
+}
+
+P2_BackendDummy::~P2_BackendDummy()
+{
+    yaz_log(YLOG_LOG, "P2_backendDummy %p destroy", this);
+}
+
+int P2_BackendDummy::search(yazpp_1::Yaz_Z_Query *q, IP2_BackendSet **rset,
+                           int *hits)
+{
+    yaz_log(YLOG_LOG, "P2_backendDummy %p search", this);
+
+    P2_BackendSetDummy *s = new P2_BackendSetDummy();
+
+    *rset = s;
+    *hits = 42;
+    return 0;
+}
+
+int P2_BackendSetDummy::get(int start, int number)
+{
+    yaz_log(YLOG_LOG, "P2_backendSetDummy %p get", this);
+    return 0;
+}
+
+P2_BackendSetDummy::P2_BackendSetDummy()
+{
+    yaz_log(YLOG_LOG, "P2_backendSetDummy %p create", this);
+
+}
+
+P2_BackendSetDummy::~P2_BackendSetDummy()
+{
+    yaz_log(YLOG_LOG, "P2_backendSetDummy %p destroy", this);
+}
+
+static IP2_Backend *dummy_create(const char *address)
+{
+    return new P2_BackendDummy(address);
+}
+
+P2_ModuleInterface0 int0 = {
+    dummy_create
+};
+
+P2_ModuleEntry p2_module_entry = {
+    0,
+    "dummy",
+    "Dummy Backend",
+    (void *) &int0
+};
+
+P2_ModuleEntry *p2_backend_dummy = &p2_module_entry;
diff --git a/src/p2_config.cpp b/src/p2_config.cpp
new file mode 100644 (file)
index 0000000..6fd43f2
--- /dev/null
@@ -0,0 +1,383 @@
+/* $Id: p2_config.cpp,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <yaz/log.h>
+#include <yaz/options.h>
+#include <yaz/diagbib1.h>
+#include "p2_config.h"
+
+#if HAVE_XSLT
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xinclude.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+#endif
+
+#include <iostream>
+
+using namespace std;
+
+class P2_Config::Rep {
+    
+public:
+    Rep();
+    ~Rep();
+public:
+#if HAVE_XSLT
+    xmlDocPtr m_docPtr;
+    xmlNodePtr m_proxyPtr;
+#endif
+};
+
+P2_Config::Rep::Rep()
+{
+#if HAVE_XSLT
+    m_docPtr = 0;
+    m_proxyPtr = 0;
+#endif
+}
+
+P2_Config::Rep::~Rep()
+{
+#if HAVE_XSLT
+    if (m_docPtr)
+        xmlFreeDoc(m_docPtr);
+#endif
+}
+    
+P2_Config::P2_Config()
+{
+    m_max_clients = 500;
+    m_client_idletime = 600;
+    m_debug_mode = 0;
+    m_no_limit_files = 0;
+    m_no_threads = 20;
+    m_target_idletime = 600;
+
+    m_rep = new Rep();
+}
+
+bool P2_Config::parse_options(int argc, char **argv)
+{
+    char *arg;
+    int ret;
+    bool show_config = false;
+    while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:n:h:XS",
+                          argv, argc, &arg)) != -2)
+    {
+        switch (ret)
+        {
+        case 0:
+            if (m_listen_address.length())
+            {
+                yaz_log(YLOG_FATAL, "Multiple listener address given");
+                return false;
+            }
+            m_listen_address = arg;
+            break;
+        case 'a':
+            m_apdu_log = arg;
+            break;
+        case 'c':
+            if (m_xml_fname.length())
+            {
+                yaz_log(YLOG_FATAL, "Multiple -c options given");
+                return false;
+            }
+            if (!read_xml_config(arg))
+            {
+                return false;
+            }
+            m_xml_fname = arg;
+            break;
+        case 'i':
+            m_client_idletime = atoi(arg);
+            break;
+        case 'l':
+            m_log_file = arg;
+            break;
+        case 'm':
+            m_max_clients = atoi(arg);
+            break;
+        case 'n':
+            m_no_limit_files = atoi(arg);
+            break;
+        case 'h':
+            m_no_threads = atoi(arg);
+            break;
+        case 'o':
+            m_optimize_flags = arg;
+            break;
+        case 'p':
+            if (m_pid_fname.length())
+            {
+                yaz_log(YLOG_LOG, "Multiple -p options given");
+                return false;
+            }
+            m_pid_fname = arg;
+            break;
+        case 't':
+            if (m_default_target.length())
+            {
+                yaz_log(YLOG_LOG, "Multiple -t options given");
+                return false;
+            }
+            m_default_target = arg;
+            break;
+        case 'T':
+            m_target_idletime = atoi(arg);
+            break;
+        case 'u':
+            if (m_uid.length())
+            {
+                yaz_log(YLOG_FATAL, "-u specified more than once");
+                return false;
+            }
+            m_uid = arg;
+            break;
+        case 'v':
+            yaz_log_init_level(yaz_log_mask_str(arg));
+            break;
+        case 'X':
+            m_debug_mode = 1;
+            break;
+        case 'S':
+            show_config = true;
+            break;
+        default:
+            yaz_log(YLOG_FATAL, "Bad option %s", arg);
+            return false;
+        }
+    } 
+    if (m_log_file.length())
+        yaz_log_init_file(m_log_file.c_str());
+    if (show_config)
+        print();
+    return true;
+}
+
+bool P2_Config::parse_xml_text(void *xml_ptr, bool &val)
+{
+    string v;
+    if (!parse_xml_text(xml_ptr, v))
+        return false;
+    if (v.length() == 1 && v[0] == '1')
+        val = true;
+    else
+        val = false;
+    return true;
+}
+
+bool P2_Config::parse_xml_text(void *xml_ptr, string &val)
+{
+    xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
+    bool found = false;
+    string v;
+    for(ptr = ptr->children; ptr; ptr = ptr->next)
+        if (ptr->type == XML_TEXT_NODE)
+        {
+            xmlChar *t = ptr->content;
+            if (t)
+            {
+                v += (const char *) t;
+                found = true;
+            }
+        }
+    if (found)
+        val = v;
+    return found;
+}
+
+void P2_Config::parse_xml_element_target(void *xml_ptr,
+                                         P2_ConfigTarget *t)
+{
+    xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
+
+    for (ptr = ptr->children; ptr; ptr = ptr->next)
+    {
+        if (ptr->type != XML_ELEMENT_NODE)
+            continue;
+        if (!strcmp((const char *) ptr->name, "url"))
+        {
+            parse_xml_text(ptr, t->m_target_address);
+        }
+        else if (!strcmp((const char *) ptr->name, "database"))
+        {
+            parse_xml_text(ptr, t->m_target_database);
+        }
+        else
+        {
+            yaz_log(YLOG_WARN, "Unknown element '%s' inside target",
+                    (const char *) ptr->name);
+            m_errors++;
+        }
+    }
+}
+
+void P2_Config::parse_xml_element_proxy(void *xml_ptr)
+{
+    xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
+
+    for (ptr = ptr->children; ptr; ptr = ptr->next)
+    {
+        if (ptr->type != XML_ELEMENT_NODE)
+            continue;
+        if (!strcmp((const char *) ptr->name, "target"))
+        {
+            P2_ConfigTarget *t = new P2_ConfigTarget();
+
+            struct _xmlAttr *attr;
+            for (attr = ptr->properties; attr; attr = attr->next)
+                if (!strcmp((const char *) attr->name, "name")
+                    || !strcmp((const char *) attr->name, "host"))
+                {
+                    parse_xml_text(attr, t->m_virt_address);
+                }
+                else if (!strcmp((const char *) attr->name, "database"))
+                {
+                    parse_xml_text(attr, t->m_virt_database);
+                }
+                else if (!strcmp((const char *) attr->name, "default"))
+                {
+                    parse_xml_text(attr, t->m_default);
+                }
+                else if (!strcmp((const char *) attr->name, "type"))
+                {
+                    parse_xml_text(attr, t->m_type);
+                }
+                else
+                {
+                    yaz_log(YLOG_WARN, "Unknown attribute '%s' for "
+                            "element proxy",
+                            (const char *) attr->name);
+                    m_errors++;
+                }
+            parse_xml_element_target(ptr, t);
+            m_target_list.push_back(t);
+        }
+        else if (!strcmp((const char *) ptr->name, "max-clients"))
+        {
+            string v;
+            if (parse_xml_text(ptr, v))
+                m_max_clients = atoi(v.c_str());
+        }
+        else if (!strcmp((const char *) ptr->name, "module"))
+        {
+            P2_ConfigModule *t = new P2_ConfigModule();
+
+            string v;
+            if (parse_xml_text(ptr, v))
+            {
+                t->m_fname = v;
+                m_modules.push_back(t);
+            }
+        }
+        else
+        {
+            yaz_log(YLOG_WARN, "Unknown element '%s' inside proxy", ptr->name);
+            m_errors++;
+        }
+    }
+}
+
+void P2_Config::print()
+{
+    cout << "max_clients=" << m_max_clients << endl;
+    list<P2_ConfigTarget *>::const_iterator it;
+    
+    for (it = m_target_list.begin(); it != m_target_list.end(); it++)
+    {
+        cout << "type=" << (*it)->m_type << " ";
+        cout << "v-address=" << (*it)->m_virt_address << " ";
+        cout << "v-db=" << (*it)->m_virt_database << " ";
+        cout << "t-address=" << (*it)->m_target_address << " ";
+        cout << "t-db=" << (*it)->m_target_database << " ";
+        cout << "default=" << (*it)->m_default << endl;
+    }
+}
+
+bool P2_Config::read_xml_config(const char *fname)
+{
+    xmlDocPtr ndoc = xmlParseFile(fname);
+
+    if (!ndoc)
+    {
+        yaz_log(YLOG_WARN, "Config file %s not found or parse error", fname);
+        return false;
+    }
+    int noSubstitutions = xmlXIncludeProcess(ndoc);
+    if (noSubstitutions == -1)
+        yaz_log(YLOG_WARN, "XInclude processing failed on config %s", fname);
+
+    xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
+    if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
+        strcmp((const char *) proxyPtr->name, "proxy"))
+    {
+        yaz_log(YLOG_WARN, "No proxy element in %s", fname);
+        xmlFreeDoc(ndoc);
+        return false;
+    }
+    m_rep->m_proxyPtr = proxyPtr;
+    
+    // OK: release previous and make it the current one.
+    if (m_rep->m_docPtr)
+        xmlFreeDoc(m_rep->m_docPtr);
+    m_rep->m_docPtr = ndoc;
+
+    m_errors = 0;
+    parse_xml_element_proxy(proxyPtr);
+    if (m_errors && !m_debug_mode)
+        return false;
+    return true;
+}
+
+P2_Config::~P2_Config()
+{
+    delete m_rep;
+}
+
+P2_ConfigTarget::P2_ConfigTarget()
+{
+    m_default = false;
+}
+
+P2_ConfigTarget *P2_Config::find_target(string db)
+{
+    list<P2_ConfigTarget *>::const_iterator it;
+    for (it = m_target_list.begin(); it != m_target_list.end(); it++)
+    {
+        if ((*it)->m_virt_database == db)
+            return (*it);
+    }
+    return 0;
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/src/p2_config.h b/src/p2_config.h
new file mode 100644 (file)
index 0000000..161e6e9
--- /dev/null
@@ -0,0 +1,90 @@
+/* $Id: p2_config.h,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#ifndef P2_CONFIG_INCLUDED
+#define P2_CONFIG_INCLUDED
+
+#include <string>
+#include <list>
+
+class P2_ConfigTarget {
+ public:
+    P2_ConfigTarget();
+    std::string m_virt_address;
+    std::string m_virt_database;
+    std::string m_target_address;
+    std::string m_target_database;
+    std::string m_type;
+    bool m_default;
+};
+
+class P2_ConfigModule {
+ public:
+    std::string m_fname;
+};
+
+class P2_Config {
+    class Rep;
+ public:
+    P2_Config::P2_Config();
+    P2_Config::~P2_Config();
+    bool P2_Config::parse_options(int argc, char **argv);
+    P2_ConfigTarget *find_target(std::string db);
+    void print();
+ private:
+    bool read_xml_config(const char *fname);
+    void parse_xml_element_proxy(void *xml_ptr);
+    void parse_xml_element_target(void *xml_ptr,
+                                            P2_ConfigTarget *t);
+    bool parse_xml_text(void *xml_ptr, std::string &val);
+    bool parse_xml_text(void *xml_ptr, bool &val);
+ public:
+    std::string m_apdu_log;
+    std::string m_default_target;
+    std::string m_listen_address;
+    std::string m_log_file;
+    std::string m_optimize_flags;
+    std::string m_pid_fname;
+    std::string m_uid;
+    std::string m_xml_fname;
+
+    int m_max_clients;
+    int m_client_idletime;
+    int m_debug_mode;
+    int m_no_limit_files;
+    int m_no_threads;
+    int m_target_idletime;
+
+    std::list<P2_ConfigTarget *> m_target_list;
+    std::list<P2_ConfigModule *> m_modules;
+ private:
+    Rep *m_rep;
+    int m_errors;
+};
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/src/p2_frontend.cpp b/src/p2_frontend.cpp
new file mode 100644 (file)
index 0000000..faa602c
--- /dev/null
@@ -0,0 +1,95 @@
+/* $Id: p2_frontend.cpp,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <yaz/log.h>
+#include <yaz/diagbib1.h>
+#include "p2_frontend.h"
+
+using namespace yazpp_1;
+using namespace std;
+
+P2_Frontend::P2_Frontend(IPDU_Observable *the_PDU_Observable,
+                         Msg_Thread *my_thread, P2_Server *server)
+    :  Z_Assoc(the_PDU_Observable)
+{
+    m_my_thread = my_thread;
+    m_server = server;
+    m_no_requests = 0;
+    m_delete_flag = 0;
+    yaz_log(YLOG_LOG, "Construct P2_Frontend=%p", this);
+}
+
+
+IPDU_Observer *P2_Frontend::sessionNotify(IPDU_Observable
+                                          *the_PDU_Observable, int fd)
+{
+    return 0;
+}
+
+P2_Frontend::~P2_Frontend()
+{
+    yaz_log(YLOG_LOG, "Destroy P2_Frontend=%p", this);
+
+    list<P2_FrontResultSet *>::iterator it;
+    
+    for (it = m_resultSets.begin(); it != m_resultSets.end(); it++)
+    {
+        delete *it;
+        *it = 0;
+    }
+}
+
+void P2_Frontend::recv_GDU(Z_GDU *z_pdu, int len)
+{
+    GDU *gdu = new GDU(z_pdu);
+
+    P2_Msg *m = new P2_Msg(gdu, this, m_server);
+    m_no_requests++;
+    m_my_thread->put(m);  
+}
+
+void P2_Frontend::failNotify()
+{
+    m_delete_flag = 1;
+    if (m_no_requests == 0)
+        delete this;
+    
+}
+
+void P2_Frontend::timeoutNotify()
+{
+    m_delete_flag = 1;
+    if (m_no_requests == 0)
+        delete this;
+}
+
+void P2_Frontend::connectNotify()
+{
+
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/src/p2_frontend.h b/src/p2_frontend.h
new file mode 100644 (file)
index 0000000..1c60373
--- /dev/null
@@ -0,0 +1,163 @@
+/* $Id: p2_frontend.h,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#ifndef P2_FRONTEND_H
+#define P2_FRONTEND_H
+
+#include <list>
+#include <vector>
+#include <string>
+
+#include "msg-thread.h"
+#include <yaz++/z-assoc.h>
+#include <yaz++/pdu-assoc.h>
+#include <yaz++/gdu.h>
+#include <yaz++/z-query.h>
+
+class P2_Frontend;
+class P2_Server;
+class P2_Config;
+class P2_ConfigTarget;
+class P2_ModuleFactory;
+
+class IP2_BackendSet;
+
+class P2_BackendResultSet {
+ public:
+    P2_BackendResultSet();
+    ~P2_BackendResultSet();
+    yazpp_1::Yaz_Z_Query m_query;
+    std::list<std::string> m_db_list;
+    int m_hit_count;
+    IP2_BackendSet *m_int;
+    // record cache here 
+};
+
+class IP2_Backend;
+
+class P2_Backend {
+ public:
+    P2_Backend(P2_ConfigTarget *cfg, IP2_Backend *backend_interface);
+    ~P2_Backend();
+ public:
+    std::list<P2_BackendResultSet *>m_resultSets;
+    P2_ConfigTarget *m_configTarget;
+    bool m_busy;
+    IP2_Backend *m_int;
+};
+
+class P2_Server : public yazpp_1::Z_Assoc {
+public:
+    ~P2_Server();
+    P2_Server(yazpp_1::IPDU_Observable *the_PDU_Observable,
+              Msg_Thread *m_my_thread,
+              P2_Config *config,
+              P2_ModuleFactory *modules);
+    P2_Config *lockConfig();
+    void unlockConfig();
+    std::list<P2_Backend *>m_backend_list;
+    P2_ModuleFactory *m_modules;
+private:
+    yazpp_1::IPDU_Observer* sessionNotify(
+        yazpp_1::IPDU_Observable *the_PDU_Observable,
+        int fd);
+    void recv_GDU(Z_GDU *apdu, int len);
+
+    void failNotify();
+    void timeoutNotify();
+    void connectNotify();
+private:
+    P2_Config *m_config;
+    Msg_Thread *m_my_thread;
+    pthread_mutex_t m_mutex_config;
+};
+
+class P2_FrontResultSet {
+public:
+    P2_FrontResultSet(const char *id);
+    ~P2_FrontResultSet();
+    void setQuery(Z_Query *z_query);
+    void setDatabases(char **db, int num);
+    std::string m_resultSetId;
+    std::vector<std::string> m_db_list;
+    yazpp_1::Yaz_Z_Query m_query;
+};
+
+class P2_Msg : public IMsg_Thread {
+public:
+    int m_close_flag;
+    yazpp_1::GDU *m_gdu;
+    yazpp_1::GDU *m_output;
+    P2_Frontend *m_front;
+    P2_Server *m_server;
+    IMsg_Thread *handle();
+    void result();
+    P2_Msg(yazpp_1::GDU *gdu, P2_Frontend *front, P2_Server *server);
+    virtual ~P2_Msg();
+ private:
+
+    Z_APDU *frontend_search_resultset(Z_APDU *z_gdu, ODR odr,
+                                      P2_FrontResultSet **rset);
+    Z_APDU *frontend_present_resultset(Z_APDU *z_gdu, ODR odr,
+                                       P2_FrontResultSet **rset);
+    Z_APDU *frontend_search_apdu(Z_APDU *z_gdu, ODR odr);
+    Z_APDU *frontend_present_apdu(Z_APDU *z_gdu, ODR odr);
+    P2_Backend *select_backend(std::string db,
+                               yazpp_1::Yaz_Z_Query *query,
+                               P2_BackendResultSet **bset);
+    P2_Backend *create_backend(std::string db);
+};
+
+class P2_Frontend : public yazpp_1::Z_Assoc {
+ public:
+    ~P2_Frontend();
+    P2_Frontend(yazpp_1::IPDU_Observable *the_PDU_Observable,
+                Msg_Thread *m_my_thread, P2_Server *server);
+    IPDU_Observer* sessionNotify(yazpp_1::IPDU_Observable *the_PDU_Observable,
+                                 int fd);
+    
+    void recv_GDU(Z_GDU *apdu, int len);
+    
+    void failNotify();
+    void timeoutNotify();
+    void connectNotify();
+
+    int m_no_requests;
+    int m_delete_flag;
+    std::list<P2_FrontResultSet *> m_resultSets;
+    
+ private:
+    yazpp_1::GDUQueue m_in_queue;
+    Msg_Thread *m_my_thread;
+    P2_Server *m_server;
+ private:
+    bool P2_Frontend::search(Z_GDU *z_gdu);
+    bool P2_Frontend::handle_init(Z_GDU *z_gdu);
+};
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/src/p2_modules.cpp b/src/p2_modules.cpp
new file mode 100644 (file)
index 0000000..6f1778b
--- /dev/null
@@ -0,0 +1,77 @@
+
+#include <dlfcn.h>
+
+#include "p2_modules.h"
+
+class P2_ModuleDLEntry {
+public:
+    void *m_dl_handle;
+    P2_ModuleEntry *m_entry;
+    P2_ModuleDLEntry();
+    ~P2_ModuleDLEntry();
+};
+
+P2_ModuleDLEntry::P2_ModuleDLEntry()
+{
+    m_dl_handle = 0;
+    m_entry = 0;
+}
+    
+P2_ModuleDLEntry::~P2_ModuleDLEntry()
+{
+    if (m_dl_handle)
+       dlclose(m_dl_handle);
+}
+    
+P2_ModuleFactory::P2_ModuleFactory()
+{
+}
+
+P2_ModuleFactory::~P2_ModuleFactory()
+{
+}
+
+bool P2_ModuleFactory::add(P2_ModuleEntry *entry)
+{
+    P2_ModuleDLEntry *m = new P2_ModuleDLEntry();
+    m->m_entry = entry;
+    m_modules.push_back(m);
+    return true;
+}
+
+bool P2_ModuleFactory::add(const char *fname)
+{
+    void *dl_handle = dlopen(fname, RTLD_NOW|RTLD_GLOBAL);
+    if (!dl_handle)
+       return false;
+
+    P2_ModuleEntry *entry =
+       reinterpret_cast<P2_ModuleEntry *> 
+       (dlsym(dl_handle, "p2_module_entry"));
+    if (!entry)
+    {
+       dlclose(dl_handle);
+       return false;
+    }
+    P2_ModuleDLEntry *m = new P2_ModuleDLEntry();
+    m->m_dl_handle = dl_handle;
+    m->m_entry = entry;
+    m_modules.push_back(m);
+    return true;
+}
+
+void *P2_ModuleFactory::get_interface(const char *name, int version)
+{
+    std::list<P2_ModuleDLEntry *>::const_iterator it;
+    for (it = m_modules.begin();  it != m_modules.end(); it++)
+    {
+       P2_ModuleDLEntry *ent = *it;
+       if (!strcmp(ent->m_entry->name, name) &&
+           ent->m_entry->version == version)
+       {
+           return ent->m_entry->interface_ptr;
+       }
+    }
+    return 0;
+}
+
diff --git a/src/p2_modules.h b/src/p2_modules.h
new file mode 100644 (file)
index 0000000..c3f0e1b
--- /dev/null
@@ -0,0 +1,21 @@
+
+#ifndef P2_MODULES_H
+#define P2_MODULES_H
+
+#include "p2_backend.h"
+
+#include <list>
+
+class P2_ModuleDLEntry ;
+class P2_ModuleFactory {
+ public:
+    P2_ModuleFactory();
+    ~P2_ModuleFactory();
+    bool add(const char *fname);
+    bool add(P2_ModuleEntry *entry);
+    void *get_interface(const char *name, int version);
+ private:
+    std::list <P2_ModuleDLEntry *>m_modules;
+};
+
+#endif
diff --git a/src/p2_msg.cpp b/src/p2_msg.cpp
new file mode 100644 (file)
index 0000000..ae2177f
--- /dev/null
@@ -0,0 +1,387 @@
+/* $Id: p2_msg.cpp,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <yaz/log.h>
+#include <yaz/diagbib1.h>
+#include "p2_backend.h"
+#include "p2_frontend.h"
+#include "p2_config.h"
+#include "p2_modules.h"
+
+using namespace yazpp_1;
+using namespace std;
+
+IP2_BackendSet::~IP2_BackendSet()
+{
+}
+
+IP2_Backend::~IP2_Backend()
+{
+
+}
+
+P2_Backend::P2_Backend(P2_ConfigTarget *cfg, IP2_Backend *backend_int)
+{
+    m_configTarget = new P2_ConfigTarget;
+    *m_configTarget = *cfg;
+    m_busy = false;
+    m_int = backend_int;
+}
+
+P2_Backend::~P2_Backend()
+{
+    delete m_configTarget;
+}
+
+P2_BackendResultSet::P2_BackendResultSet()
+{
+    m_int = 0;
+}
+
+P2_BackendResultSet::~P2_BackendResultSet()
+{
+    delete m_int;
+}
+
+P2_Backend *P2_Msg::select_backend(string db,
+                                   Yaz_Z_Query *query,
+                                   P2_BackendResultSet **bset)
+{
+    P2_Config *cfg = m_server->lockConfig();
+
+    // see if some target has done this query before
+
+    *bset = 0;
+    P2_Backend *backend = 0;
+
+    list<P2_Backend *>::const_iterator it;
+    for (it = m_server->m_backend_list.begin(); 
+         it != m_server->m_backend_list.end(); it++)
+    {
+        if ((*it)->m_busy)
+            continue;
+
+        if (db != (*it)->m_configTarget->m_virt_database)
+            continue;
+        backend = *it;
+
+        if (query)
+        {
+            list<P2_BackendResultSet *>::const_iterator is;
+            for (is  = (*it)->m_resultSets.begin(); 
+                 is != (*it)->m_resultSets.end(); is++)
+            {
+                if (query->match(&(*is)->m_query))
+                {
+                    *bset = *is;
+                    break;
+                }
+            }
+        }
+        if (bset)
+            break;
+    }
+    if (!backend)
+    {
+        P2_ConfigTarget *target_cfg = cfg->find_target(db);
+
+        if (!target_cfg)
+        {
+            yaz_log(YLOG_WARN, "No backend for database %s",
+                    db.c_str());
+        }
+        else
+        {
+            P2_ModuleInterface0 *int0 =
+            reinterpret_cast<P2_ModuleInterface0 *>
+                (m_server->m_modules->get_interface(target_cfg->m_type.c_str(),
+                                                    0));
+            IP2_Backend *bint = 0;
+
+            if (int0)
+                bint = int0->create(target_cfg->m_target_address.c_str());
+
+            if (bint)
+                backend = new P2_Backend(target_cfg, bint);
+
+            if (backend)
+                m_server->m_backend_list.push_back(backend);
+        }
+    }
+    if (backend)
+        backend->m_busy = true;
+    m_server->unlockConfig();
+    return backend;
+}
+
+void P2_FrontResultSet::setQuery(Z_Query *z_query)
+{
+    m_query.set_Z_Query(z_query);
+}
+
+void P2_FrontResultSet::setDatabases(char **db, int num)
+{
+    m_db_list.clear();
+
+    int i;
+    for (i = 0; i<num; i++)
+        m_db_list.push_back(db[i]);
+}
+
+P2_FrontResultSet::P2_FrontResultSet(const char *id)
+{
+    m_resultSetId = id;
+}
+
+
+P2_FrontResultSet::~P2_FrontResultSet()
+{
+}
+
+P2_Msg::P2_Msg(GDU *gdu, P2_Frontend *front, P2_Server *server)
+{
+    m_front = front;
+    m_server = server;
+    m_output = 0;
+    m_gdu = gdu;
+    m_close_flag = 0;
+}
+
+P2_Msg::~P2_Msg()
+{
+    delete m_output;
+    delete m_gdu;
+}
+
+Z_APDU *P2_Msg::frontend_search_resultset(Z_APDU *z_gdu, ODR odr,
+                                          P2_FrontResultSet **rset)
+{
+    Z_SearchRequest *req = z_gdu->u.searchRequest;
+    list<P2_FrontResultSet *>::iterator it;
+    P2_FrontResultSet *s = 0;
+
+    string id = req->resultSetName;
+    for (it = m_front->m_resultSets.begin(); it != m_front->m_resultSets.end(); it++)
+    {
+       if ((*it)->m_resultSetId == id)
+        {
+            s = *it;
+           break;
+        }
+    }
+    if (s)
+    {
+       // result set already exists
+        *rset = s;
+       if (req->replaceIndicator && *req->replaceIndicator)
+       {  // replace indicator true
+           s->setQuery(req->query);
+           s->setDatabases(req->databaseNames, req->num_databaseNames);
+           return 0;
+       }
+       Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
+       Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
+       apdu->u.searchResponse->records = rec;
+       rec->which = Z_Records_NSD;
+       rec->u.nonSurrogateDiagnostic =
+           zget_DefaultDiagFormat(
+               odr, YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
+               req->resultSetName);
+       
+       return apdu;
+    }
+    // does not exist 
+    s = new P2_FrontResultSet(req->resultSetName);
+    s->setQuery(req->query);
+    s->setDatabases(req->databaseNames, req->num_databaseNames);
+    m_front->m_resultSets.push_back(s);
+    *rset = s;
+    return 0;
+}
+
+Z_APDU *P2_Msg::frontend_search_apdu(Z_APDU *request_apdu, ODR odr)
+{
+    P2_FrontResultSet *rset;
+    Z_APDU *response_apdu = frontend_search_resultset(request_apdu, odr,
+                                                      &rset);
+    if (response_apdu)
+        return response_apdu;
+
+    // no immediate error (yet) 
+    size_t i;
+    for (i = 0; i<rset->m_db_list.size(); i++)
+    {
+        string db = rset->m_db_list[i];
+        P2_BackendResultSet *bset;
+        P2_Backend *b = select_backend(db, &rset->m_query, &bset);
+        if (!b)
+        {
+            Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
+            Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
+            apdu->u.searchResponse->records = rec;
+            rec->which = Z_Records_NSD;
+            rec->u.nonSurrogateDiagnostic =
+                zget_DefaultDiagFormat(
+                    odr, YAZ_BIB1_DATABASE_UNAVAILABLE, db.c_str());
+            return apdu;
+        }
+        if (!bset)
+        {   // new set 
+            bset = new P2_BackendResultSet();
+
+            bset->m_query.set_Z_Query(request_apdu->u.searchRequest->query);
+            bset->m_db_list.push_back(db);
+
+            b->m_int->search(&bset->m_query, &bset->m_int, &bset->m_hit_count);
+            b->m_resultSets.push_back(bset);
+        }
+        else
+        {
+            bset->m_int->get(1, 1);
+        }
+        response_apdu = zget_APDU(odr, Z_APDU_searchResponse);
+        *response_apdu->u.searchResponse->resultCount = bset->m_hit_count;
+        b->m_busy = false;
+    }
+    if (!response_apdu)
+    {
+        Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse);
+        Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
+        apdu->u.searchResponse->records = rec;
+            rec->which = Z_Records_NSD;
+            rec->u.nonSurrogateDiagnostic =
+                zget_DefaultDiagFormat(odr, YAZ_BIB1_UNSUPP_SEARCH, 0);
+            return apdu;
+    }
+    return response_apdu;
+}
+
+Z_APDU *P2_Msg::frontend_present_resultset(Z_APDU *z_gdu, ODR odr,
+                                           P2_FrontResultSet **rset)
+{
+    Z_PresentRequest *req = z_gdu->u.presentRequest;
+    list<P2_FrontResultSet *>::iterator it;
+    P2_FrontResultSet *s = 0;
+
+    string id = req->resultSetId;
+    for (it = m_front->m_resultSets.begin(); it != m_front->m_resultSets.end(); it++)
+    {
+       if ((*it)->m_resultSetId == id)
+        {
+            s = *it;
+           break;
+        }
+    }
+    *rset = s;
+    if (s)
+       return 0;  // fine result set exists 
+
+    Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse);
+    
+    Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records));
+    apdu->u.presentResponse->records = rec;
+    rec->which = Z_Records_NSD;
+    rec->u.nonSurrogateDiagnostic =
+       zget_DefaultDiagFormat(
+           odr,
+           YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
+           req->resultSetId);
+    return apdu;
+}
+
+Z_APDU *P2_Msg::frontend_present_apdu(Z_APDU *request_apdu, ODR odr)
+{
+    P2_FrontResultSet *rset;
+    Z_APDU *response_apdu = frontend_present_resultset(request_apdu, odr,
+                                                       &rset);
+    if (response_apdu)
+        return response_apdu;
+    return zget_APDU(odr, Z_APDU_presentResponse);
+}
+    
+IMsg_Thread *P2_Msg::handle()
+{
+    ODR odr = odr_createmem(ODR_ENCODE);
+    yaz_log(YLOG_LOG, "P2_Msg:handle begin");
+    Z_GDU *request_gdu = m_gdu->get();
+
+    if (request_gdu->which == Z_GDU_Z3950)
+    {
+       Z_APDU *request_apdu = request_gdu->u.z3950;
+        Z_APDU *response_apdu = 0;
+        switch(request_apdu->which)
+        {
+        case Z_APDU_initRequest:
+            response_apdu = zget_APDU(odr, Z_APDU_initResponse);
+            ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_triggerResourceCtrl);
+            ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_search);
+            ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_present);
+           ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_namedResultSets);
+            break;
+        case Z_APDU_searchRequest:
+            response_apdu = frontend_search_apdu(request_apdu, odr);
+            break;
+       case Z_APDU_presentRequest:
+           response_apdu = frontend_present_apdu(request_apdu, odr);
+            break;
+        case Z_APDU_triggerResourceControlRequest:
+            break;
+        default:
+            response_apdu = zget_APDU(odr, Z_APDU_close);
+            m_close_flag = 1;
+            break;
+        }
+        if (response_apdu)
+            m_output = new GDU(response_apdu);
+    }
+    yaz_log(YLOG_LOG, "P2_Msg:handle end");
+    odr_destroy(odr);
+    return this;
+}
+
+void P2_Msg::result()
+{
+    m_front->m_no_requests--;
+    if (!m_front->m_delete_flag)
+    {
+        if (m_output)
+        {
+            int len;
+            m_front->send_GDU(m_output->get(), &len);
+        }
+        if (m_close_flag)
+        {
+            m_front->close();
+            m_front->m_delete_flag = 1;
+        }
+    }
+    if (m_front->m_delete_flag && m_front->m_no_requests == 0)
+        delete m_front;
+    delete this;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/src/p2_xmlerror.cpp b/src/p2_xmlerror.cpp
new file mode 100644 (file)
index 0000000..c0d9f90
--- /dev/null
@@ -0,0 +1,70 @@
+/* $Id: p2_xmlerror.cpp,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <yaz/log.h>
+
+#include "p2_xmlerror.h"
+
+#if HAVE_XSLT
+#include <libxml/parser.h>
+#include <libxslt/xsltutils.h>
+#endif
+
+#if HAVE_XSLT
+static void p2_xml_error_handler(void *ctx, const char *fmt, ...)
+{
+    char buf[1024];
+    size_t sz;
+
+    va_list ap;
+    va_start(ap, fmt);
+
+#ifdef WIN32
+    vsprintf(buf, fmt, ap);
+#else
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+#endif
+    sz = strlen(buf);
+    if (sz > 0 && buf[sz-1] == '\n')
+        buf[sz-1] = '\0';
+        
+    yaz_log(YLOG_WARN, "%s: %s", (char*) ctx, buf);
+
+    va_end (ap);
+}
+#endif
+
+void p2_xmlerror_setup()
+{
+#if HAVE_XSLT
+    xmlSetGenericErrorFunc((void *) "XML", p2_xml_error_handler);
+    xsltSetGenericErrorFunc((void *) "XSLT", p2_xml_error_handler);
+#endif
+}
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/src/p2_xmlerror.h b/src/p2_xmlerror.h
new file mode 100644 (file)
index 0000000..f8eb1e5
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id: p2_xmlerror.h,v 1.1 2005-10-06 09:37:25 marc Exp $
+   Copyright (c) 1998-2005, Index Data.
+
+This file is part of the yaz-proxy.
+
+YAZ proxy is free software; you can redistribute 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.
+
+YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with YAZ proxy; see the file LICENSE.  If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#ifndef P2_XMLERROR_H
+#define P2_XMLERROR_H
+
+void p2_xmlerror_setup();
+
+#endif
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
diff --git a/src/p3_filter.h b/src/p3_filter.h
new file mode 100644 (file)
index 0000000..bb6f5b1
--- /dev/null
@@ -0,0 +1,147 @@
+
+#ifndef P3_FILTER_H
+#define P3_FILTER_H
+
+#include <stdexcept>
+
+
+namespace p3 {
+
+  class Package;
+  
+
+  
+  class Filter {
+  public:
+    virtual ~Filter(){};
+    virtual  Package & process(Package & package) const {
+      return package;
+    };
+    virtual  void configure(){};
+
+    // set/get the C++ way .. just as showoff
+
+    // get function - returns copy and keeps object const, 
+    // thus is right val in assignment
+    unsigned int max_front_workers() const {
+      return m_max_front;
+    }
+    // set function - returns reference and changes object,
+    // thus is left val in assignment
+    unsigned int & max_front_workers() {
+      return m_max_front;
+    }
+    // more traditional set function, taking const reference 
+    // or copy (here const ref for demo), returning ref to object
+    // can be chained with other similar functions!
+    Filter & max_front_workers(const unsigned int & max_front){
+      m_max_front = max_front;
+      return *this;
+    }
+    
+  private:
+    unsigned int m_max_front;
+  };
+
+
+  class Filter_Exception : public std::runtime_error {
+  public:
+    Filter_Exception(const std::string message)
+      : std::runtime_error("Filter_Exception: " + message){
+    };
+  };
+
+
+  class Router {
+  public:
+    virtual ~Router(){};
+    virtual const Filter & 
+      route(const Filter & filter, Package & package) const {
+      //if (!m_sillyrule)
+      //throw Router_Exception("no routing rules known");
+          return m_sillyrule;
+    };
+    virtual void configure(){};
+    Router & rule(Filter filter){
+      m_sillyrule = filter;
+      return *this;
+    }
+  private:
+    Filter m_sillyrule;
+  };
+  
+  
+  class Router_Exception : public std::runtime_error {
+  public:
+    Router_Exception(const std::string message)
+      : std::runtime_error("Router_Exception: " + message){};
+  };
+  
+
+  class Package {
+  public:
+
+    // send package to it's next filter defined in chain
+    void move() {
+      Filter oldfilter;
+      Filter nextfilter = m_router.route(oldfilter, *this);
+      nextfilter.process(*this);
+    }
+    
+
+    // get function - returns copy and keeps object const, 
+    // thus is right val in assignment
+    unsigned int data() const {
+      return m_data;
+    }
+    // set function - returns reference and changes object,
+    // thus is left val in assignment
+    unsigned int & data() {
+      return m_data;
+    }
+
+    // more traditional set function, taking const reference 
+    // or copy (here const ref for demo), returning ref to object
+    // can be chained with other similar functions!
+    Package & data(const unsigned int & data){
+      m_data = data;
+      return *this;
+    }
+
+    // get function - returns copy and keeps object const, 
+    // thus is right val in assignment
+    Router router() const {
+      return m_router;
+    }
+    // set function - returns reference and changes object,
+    // thus is left val in assignment
+    Router & router() {
+      return m_router;
+    }
+    // more traditional set function, taking const reference 
+    // or copy (here const ref for demo), returning ref to object
+    // can be chained with other similar functions!
+    Package & router(const Router & router){
+      m_router = router;
+      return *this;
+    }
+    
+  private:
+    unsigned int m_data;
+    Router m_router;
+  };
+
+
+  class Package_Exception : public std::runtime_error {
+  public:
+    Package_Exception(const std::string message)
+      : std::runtime_error("Package_Exception: " + message){
+    };
+  };
+
+
+
+  
+}
+
+#endif
diff --git a/src/p3_main.cpp b/src/p3_main.cpp
new file mode 100644 (file)
index 0000000..ee4c4a2
--- /dev/null
@@ -0,0 +1,69 @@
+
+#include <iostream>
+#include  "p3_filter.h"
+
+
+
+int main(int argc, char **argv) {
+
+   // test filter set/get/exception
+  try {
+    std::cout << "\nTRY" << "\n";
+    p3::Filter filter;
+    unsigned int tmp;
+    
+    filter.max_front_workers(1).max_front_workers(2);
+    tmp = filter.max_front_workers();
+    std::cout << "workers: " << tmp << "\n";
+
+    filter.max_front_workers() = 3;
+    tmp = filter.max_front_workers();
+    std::cout << "workers: " << tmp << "\n";
+
+    throw p3::Filter_Exception("finished");
+  }
+  catch (std::exception &e) {
+    std::cout << e.what() << "\n";
+  }
+
+  
+  try {
+    std::cout << "\nTRY" << "\n";
+
+    p3::Filter filter1;
+    p3::Filter filter2;
+
+    std::cout << "filter1 filter2" << "\n";
+    
+    p3::Router router1;
+    router1.rule(filter1);
+    std::cout << "router1.rule(filter1)" << "\n";
+
+    p3::Router router2;
+    router2.rule(filter2);
+    std::cout << "router2.rule(filter2)" << "\n";
+
+    p3::Package pack_in;
+    pack_in.data(7).router(router1);
+    std::cout << "pack_in.data(7).router(router1)" << "\n";
+
+    pack_in.move();
+    std::cout << "pack_in.move()" << "\n";
+
+    pack_in.router(router2);
+    std::cout << "pack_in.router(router2)" << "\n";
+
+    pack_in.move();
+    std::cout << "pack_in.move()" << "\n";
+
+    throw  p3::Router_Exception("finished");
+
+  }
+  catch (std::exception &e) {
+    std::cout << e.what() << "\n";
+  }
+
+
+
+}
+
diff --git a/usemarcon.m4 b/usemarcon.m4
new file mode 100644 (file)
index 0000000..c52fe0c
--- /dev/null
@@ -0,0 +1,42 @@
+## $Id: usemarcon.m4,v 1.1 2005-10-06 09:37:25 marc Exp $
+AC_DEFUN([USEMARCON_INIT],
+[
+        AC_SUBST(USEMARCONLALIB)
+        AC_SUBST(USEMARCONINC)
+        usemarconconfig=NONE
+        usemarconpath=NONE
+        AC_ARG_WITH(usemarcon, [  --with-usemarcon=DIR    usemarcon-config in DIR (example /home/usemarcon145)], [usemarconpath=$withval])
+
+        if test "x$usemarconpath" != "xNONE"; then
+                usemarconconfig=$usemarconpath/usemarcon-config
+        else
+                if test "x$srcdir" = "x"; then
+                        usemarconsrcdir=.
+                else
+                        usemarconsrcdir=$srcdir
+                fi
+                for i in ${usemarconsrcdir}/../usemarcon*; do
+                        if test -d $i; then
+                                if test -r $i/usemarcon-config; then
+                                        usemarconconfig=$i/usemarcon-config
+                                fi
+                        fi
+                done
+                if test "x$usemarconconfig" = "xNONE"; then
+                        AC_PATH_PROG(usemarconconfig, usemarcon-config, NONE)
+                fi
+        fi
+
+        AC_MSG_CHECKING(for USEMARCON)
+        if $usemarconconfig --version >/dev/null 2>&1; then
+                USEMARCONLALIB=`$usemarconconfig --lalibs $1`
+                USEMARCONINC=`$usemarconconfig --cflags $1`
+                USEMARCONVERSION=`$usemarconconfig --version`
+                AC_MSG_RESULT($usemarconconfig)
+                AC_DEFINE(HAVE_USEMARCON)
+        else
+                AC_MSG_RESULT(Not found)
+                USEMARCONVERSION=NONE
+        fi
+])
+
diff --git a/yaz.m4 b/yaz.m4
new file mode 100644 (file)
index 0000000..2782a1d
--- /dev/null
+++ b/yaz.m4
@@ -0,0 +1,137 @@
+# Use this m4 function for autoconf if you use YAZ in your own
+# configure script.
+
+dnl ----- Setup Docbook documentation for YAZ
+AC_DEFUN([YAZ_DOC],
+[
+AC_SUBST(DTD_DIR)      
+AC_ARG_WITH(docbook-dtd,[[  --with-docbook-dtd=DIR  use docbookx.dtd in DIR]],
+[
+       if test -f "$withval/docbookx.dtd"; then
+               DTD_DIR=$withval
+       fi
+],[
+       AC_MSG_CHECKING(for docbookx.dtd)
+       DTD_DIR=""
+       for d in /usr/lib/sgml/dtd/docbook-xml \
+                /usr/share/sgml/docbook/dtd/4.2 \
+                /usr/share/sgml/docbook/dtd/xml/4.* \
+                /usr/share/sgml/docbook/xml-dtd-4.* 
+       do
+               if test -f $d/docbookx.dtd; then
+                       DTD_DIR=$d
+               fi
+       done
+       if test -z "$DTD_DIR"; then
+               AC_MSG_RESULT(Not found)
+       else
+               AC_MSG_RESULT($d)
+       fi
+])
+AC_SUBST(DSSSL_DIR)
+AC_ARG_WITH(docbook-dsssl,[[  --with-docbook-dsssl=DIR use Docbook DSSSL in DIR/{html,print}/docbook.dsl]],
+[
+       if test -f "$withval/html/docbook.dsl"; then
+               DSSSL_DIR=$withval
+       fi
+],[
+       AC_MSG_CHECKING(for docbook.dsl)
+       DSSSL_DIR=""
+       for d in /usr/share/sgml/docbook/stylesheet/dsssl/modular \
+               /usr/share/sgml/docbook/dsssl-stylesheets-1.* \
+               /usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh 
+       do
+               if test -f $d/html/docbook.dsl; then
+                       AC_MSG_RESULT($d)
+                       DSSSL_DIR=$d
+                       break
+               fi
+       done
+       if test -z "$DSSSL_DIR"; then
+               AC_MSG_RESULT(Not found)
+       fi
+])
+AC_SUBST(XSL_DIR)
+AC_ARG_WITH(docbook-xsl,[[  --with-docbook-xsl=DIR  use Docbook XSL in DIR/{htmlhelp,xhtml}]],
+[
+       if test -f "$withval/htmlhelp/htmlhelp.xsl"; then
+               XSL_DIR=$withval
+       fi
+],[
+       AC_MSG_CHECKING(for htmlhelp.xsl)
+       for d in /usr/share/sgml/docbook/stylesheet/xsl/nwalsh \
+               /usr/share/sgml/docbook/xsl-stylesheets-1.* 
+       do
+               if test -f $d/htmlhelp/htmlhelp.xsl; then
+                       AC_MSG_RESULT($d)
+                       XSL_DIR=$d
+                       break
+               fi
+       done
+       if test -z "$XSL_DIR"; then
+               AC_MSG_RESULT(Not found)
+       fi
+])
+]) 
+
+AC_DEFUN([YAZ_INIT],
+[
+       AC_SUBST(YAZLIB)
+       AC_SUBST(YAZLALIB)
+       AC_SUBST(YAZINC)
+       AC_SUBST(YAZVERSION)
+       yazconfig=NONE
+       yazpath=NONE
+       AC_ARG_WITH(yaz, [  --with-yaz=DIR          use yaz-config in DIR (example /home/yaz-1.7)], [yazpath=$withval])
+       if test "x$yazpath" != "xNONE"; then
+               yazconfig=$yazpath/yaz-config
+       else
+               if test "x$srcdir" = "x"; then
+                       yazsrcdir=.
+               else
+                       yazsrcdir=$srcdir
+               fi
+               for i in ${yazsrcdir}/../../yaz ${yazsrcdir}/../yaz* ${yazsrcdir}/../yaz; do
+                       if test -d $i; then
+                               if test -r $i/yaz-config; then
+                                       yazconfig=$i/yaz-config
+                               fi
+                       fi
+               done
+               if test "x$yazconfig" = "xNONE"; then
+                       AC_PATH_PROG(yazconfig, yaz-config, NONE)
+               fi
+       fi
+       AC_MSG_CHECKING(for YAZ)
+       if $yazconfig --version >/dev/null 2>&1; then
+               YAZLIB=`$yazconfig --libs $1`
+               # if this is empty, it's a simple version YAZ 1.6 script
+               # so we have to source it instead...
+               if test "X$YAZLIB" = "X"; then
+                       . $yazconfig
+               else
+                       YAZLALIB=`$yazconfig --lalibs $1`
+                       YAZINC=`$yazconfig --cflags $1`
+                       YAZVERSION=`$yazconfig --version`
+               fi
+               AC_MSG_RESULT([$yazconfig])
+       else
+               AC_MSG_RESULT(Not found)
+               YAZVERSION=NONE
+       fi
+       if test "X$YAZVERSION" != "XNONE"; then
+               AC_MSG_CHECKING([for YAZ version])
+               AC_MSG_RESULT([$YAZVERSION])
+               if test "$2"; then
+                       have_yaz_version=`echo "$YAZVERSION" | awk 'BEGIN { FS = "."; } { printf "%d", ([$]1 * 1000 + [$]2) * 1000 + [$]3;}'`
+                       req_yaz_version=`echo "$2" | awk 'BEGIN { FS = "."; } { printf "%d", ([$]1 * 1000 + [$]2) * 1000 + [$]3;}'`
+                       if test "$have_yaz_version" -lt "$req_yaz_version"; then
+                               AC_MSG_ERROR([$YAZVERSION. Requires $2 or later])
+                       fi
+                       if test "$req_yaz_version" -gt "2000028"; then
+                               YAZINC="$YAZINC -DYAZ_USE_NEW_LOG=1"
+                       fi
+               fi
+       fi
+]) 
+
diff --git a/yazpp.m4 b/yazpp.m4
new file mode 100644 (file)
index 0000000..63be11e
--- /dev/null
+++ b/yazpp.m4
@@ -0,0 +1,52 @@
+AC_DEFUN([YAZPP_INIT],
+[
+        AC_SUBST(YAZPPLIB)
+        AC_SUBST(YAZPPLALIB)
+        AC_SUBST(YAZPPINC)
+        AC_SUBST(YAZPPVERSION)
+        yazppconfig=NONE
+        yazpppath=NONE
+        AC_ARG_WITH(yazpp, [  --with-yazpp=DIR        yaz++-config in DIR (example /home/yaz++-0.8)], [yazpppath=$withval])
+        if test "x$yazpppath" != "xNONE"; then
+                yazppconfig=$yazpppath/yaz++-config
+        else
+                if test "x$srcdir" = "x"; then
+                        yazppsrcdir=.
+                else
+                        yazppsrcdir=$srcdir
+                fi
+                for i in ${yazppsrcdir}/../../yaz++ ${yazppsrcdir}/../yaz++-* ${yazppsrcdir}/../yaz++; do
+                        if test -d $i; then
+                                if test -r $i/yaz++-config; then
+                                        yazppconfig=$i/yaz++-config
+                                fi
+                        fi
+                done
+                if test "x$yazppconfig" = "xNONE"; then
+                        AC_PATH_PROG(yazppconfig, yaz++-config, NONE)
+                fi
+        fi
+        AC_MSG_CHECKING(for YAZ++)
+        if $yazppconfig --version >/dev/null 2>&1; then
+                YAZPPLIB=`$yazppconfig --libs $1`
+                YAZPPLALIB=`$yazppconfig --lalibs $1`
+                YAZPPINC=`$yazppconfig --cflags $1`
+                YAZPPVERSION=`$yazppconfig --version`
+                AC_MSG_RESULT($yazppconfig)
+        else
+                AC_MSG_RESULT(Not found)
+                YAZVERSION=NONE
+        fi
+       if test "X$YAZPPVERSION" != "XNONE"; then
+               AC_MSG_CHECKING([for YAZ++ version])
+               AC_MSG_RESULT([$YAZPPVERSION])
+               if test "$2"; then
+                       have_yaz_version=`echo "$YAZPPVERSION" | awk 'BEGIN { FS = "."; } { printf "%d", ([$]1 * 1000 + [$]2) * 1000 + [$]3;}'`
+                       req_yaz_version=`echo "$2" | awk 'BEGIN { FS = "."; } { printf "%d", ([$]1 * 1000 + [$]2) * 1000 + [$]3;}'`
+                       if test "$have_yaz_version" -lt "$req_yaz_version"; then
+                               AC_MSG_ERROR([$YAZPPVERSION. Requires $2 or later])
+                       fi
+               fi
+       fi
+])
+