Implementation notes:

This is a true OS/400 implementation, not a PASE implementation (for PASE,

use an AIX implementation).

The biggest problem with OS/400 is EBCDIC. The current libxml2 implementation

uses UTF-8 internally. To ease encoding conversion between the calling applications and libxml2, supplementary “convert and latch” functions are provided (See below). To bind the EBCDIC OS/400 system calls and libxml2, an ASCII run-time environment (QADRT) has been used and wrapper functions have been designed.

Other problems are:

Compiling on OS/400:

_ As a prerequisite, QADRT development environment must be installed. _ Install the libxml2 source directory in IFS. _ Enter shell (QSH) _ Change current directory to the libxml2 installation directory _ Change current directory to ./os400 _ Edit file iniscript.sh. You may want to change tunable configuration

parameters, like debug info generation, optimisation level, listing option,
target library, zlib availability, etc.

_ Copy any file in the current directory to makelog (i.e.:

cp initscript.sh makelog): this is intended to create the makelog file with
an ASCII CCSID!

_ Enter the command “sh make.sh >makelog 2>&1' _ Examine the makelog file to check for compilation errors.

Leaving file initscript.sh unchanged, this will produce the following

OS/400 objects: _ Library LIBXML2. All other objects will be stored in this library. _ Modules for all libxml2 units, with full debug info and no code optimization. _ Binding directory LIBXML2_A, to be used at calling program link time for

statically binding the modules (specify BNDSRVPGM(QADRTTS QGLDCLNT QGLDBRDR)
when creating a program using LIBXML2_A).

_ Service program LIBXML2. To be used at calling program run-time

when this program has dynamically bound libxml2 at link time.

_ Binding directory LIBXML2. To be used to dynamically bind libxml2 when

linking a calling program.

_ Source file LIBXML. It contains all the header members needed to compile a

C/C++ module using libxml2.

_ Standard and additional C/C++ libxml2 header members (possibly renamed) in

file LIBXML.

_ IFS directory /libxml2 with subdirectory include/libxml containing all

C/C++ header files for IFS-based compilation.

_ Source file LIBXMLRPG. It contains all the include members needed to compile a

ILE/RPG module/program using libxml2 (ILE/RPG binding).

_ ILE/RPG binding include members (possibly renamed) in file LIBXMLRPG. _ IFS subdirectory /libxml2/include/libxmlrpg containing all ILE/RPG include

files for IFS-based compilation.

Renamed header files in DB2 members:

DB2 member names are limited to 10 characters, thus the following C/C++

header members are renamed as:

parserInternals.h     -->     PARSERINTE
schemasInternals.h    -->     SCHEMASINT
xmlautomata.h         -->     XMLAUTOMAT
xmlschemastype.h      -->     SCHMTYPES
xpathInternals.h      -->     XPATHINTER

IFS header files are NOT renamed. ILE/RPG headers are processed likewise.

Special programming consideration:

QADRT being used, the following points must be considered: _ If static binding is used, service program QADRTTS must be linked too. _ The EBCDIC CCSID used by QADRT is 37 by default, NOT THE JOB'S CCSID. If

another EBCDIC CCSID is required, it must be set via a locale through a call
to setlocale_a (QADRT's setlocale() ASCII wrapper) with category LC_ALL or
LC_CTYPE, or by setting environment variable QADRT_ENV_LOCALE to the locale
object path before executing the program.

_ Always use *IFSIO or *IFS64IO to compile calling programs.

Supplementary (non libxml2 standard) support procedures for OS/400.

As cited above, there are some procedures to ease encoding conversion of

libxml2 function arguments and results: the mechanism is based on dictionaries. The functions convert a string, latch the result in a dictionary to ensure its persistence and return its address. It is the caller's responsibility to clean the dictionary when it becomes too big or disappears.

The procedures are:

include <libxml/transcode.h>

const char * xmlTranscodeResult(const xmlChar * s,

const char * encoding,
xmlDictPtr * dict,
void (*freeproc)(const void *));

const xmlChar * xmlTranscodeString(const char * s,

const char * encoding,
xmlDictPtr * dict);

const xmlChar * xmlTranscodeWString(const char * s,

const char * encoding,
xmlDictPtr * dict);

const xmlChar * xmlTranscodeWString(const char * s,

const char * encoding,
xmlDictPtr * dict);

where: s is the string to translate. encoding is the alternate character encoding. If null, the current job's

encoding (CCSID) is used.

dict is the address of the latching directory. If NULL, the procedure

functions as a simple non-latching encoding converter and
its result value should be freed by the caller.

freeproc is a procedure to release the original string, or NULL.

xmlTranscodeResult() converts from UTF-8 to the given alternate encoding. xmlTranscodeString() converts from the given 8-bit encoding to UTF-8 (note that

UTF-8 itself is considered as a 8-bit encoding).

xmlTranscodeWString() converts from the given 16-bit encoding to UTF-8. xmlTranscodeHString() converts from the given 32-bit encoding to UTF-8.

To shorten statements using these functions, shorthands are defined:

xmlTR for xmlTranscodeResult xmlTS for xmlTranscodeString xmlTW for xmlTranscodeWString xmlTH for xmlTranscodeHstring

These shorthands may be disabled by defining XML_NO_SHORT_NAMES before libxml/transcode.h inclusion.

A directory pointer must be preset to NULL before the first call using it to one of the above procedure.

To release a latching directory, use function

void xmlZapDict(xmlDictPtr * dict);

Example:

include <libxml/transcode.h> include <libxml/tree.h>

xmlDocPtr mySimpleXMLDoc(char * element, char * text) {

xmlDocPtr doc;
xmlNodePtr node;
xmlDictPtr dict = NULL;

   element and text are encoded in the current job's encoding.   

doc = xmlNewDoc();
xmlNewTextChild((xmlNodePtr) doc, NULL, xmlTS(element, NULL,
                       &dict), xmlTS(text, NULL, &dict));
xmlZapDict(&dict);
return doc;

}

Additionally, a formatter into latched/dynamic storage is provided:

const char * xmlVasprintf(xmlDictPtr * dict,

const char * encoding,
const xmlChar * fmt,
va_list args);

xmllint and xmlcatalog programs:

These programs are fully implemented at the qshell level, with standard

command line options. Links to these are installed in sub-directory bin of the IFS installation directory.

CL command interfaces to these programs are also provided with limited

support. In particular, interactive mode is not supported and argument count and lengths are limited by the CL command syntax.

ILE/RPG binding:

All standard types and procedures are provided. Since ILE/RPG does not

support macros, they have not been ported. However some of them are emulated as functions: these are the more useful ones (xmlXPathNodeSetGetLength, xmlXPathNodeSetItem, xmlXPathNodeSetIsEmpty, htmlDefaultSubelement, htmlElementAllowedHereDesc, htmlRequiredAttrs) and the global/threaded variables access macros. These variables can be read with function get_xxx(void), where xxxx is the name of the variable; they may be set by calling function set_xxxx(value), where value is of the same type as the variable.

The C va_list is not implemented as such in ILE/RPG. Functions implementing

va_list and associated methods are provided:

 /include "libxmlrpg/xmlstdarg"

d xmlVaStart      pr
d  list                               like(xmlVaList)
d  lastargaddr                    *   value
d  lastargsize                  10u 0 value

d xmlVaArg        pr
d  list                               like(xmlVaList)
d  dest                           *   value
d  argsize                      10i 0 value

d xmlVaEnd        pr
d  list                               like(xmlVaList)