@ intro

IOTK: INTRODUCTION

The input/output tool kit (IOTK) is a FORTRAN90 library intended
to provide an easy access to tagged files formatted using some specific rule.
In this context, a tagged file is a file containing tags and data.
Tagged files can be textual, in which case a XML-like format is used,
or binary, in which case a special format is used.
Note that IOTK is not an XML parser, but it can be used as a writer/parser
for a limited subset of the XML language.

To use the IOTK library from a FORTRAN90 source, the user should
use the module 'iotk_module'.
To minimize the possibility of name clashes, all public names exported
from this module has the "iotk_" prefix.
Communication between user and library is based on
integers, characters and logicals of the default kind (notice that
these kinds can be changed using proper compiler options, so that
the actual kinds depend on how the library was compiled on your machine).
However, the library can handle formatted input/output for
all intrinsic datatypes, kinds and ranks if properly configured.
This is obtained interfacing procedures which acts on all kinds,
types and (in almost all cases) ranks. Thus, a single generic
name has to be remembered for each subroutine, and the compiler will
link the correct one dependening on type, kind and rank of the arguments.
Backward API compatibility will be mantained (as long as it is possible)
in future versions.
Backward file compatibility will be mantained (as long as it is possible) in
future versions.
The library writes on files informations about the version of the library.
It also writes informations about the version of the file format (file_version).
The later has to be older or equal to the format supported in the actual library.

@ error_handling

IOTK: ERROR HANDLING
The way iotk handles error is sophisticated and allows for a trace back
of the error condition inside the library.
Every iotk routines which possibly leads to an error condition has an optional
intent(out) integer argument ierr. The returned value is conventionally
0 when the routine returns correctly, and different from 0 when the routines
raise an error. The value is effectively a handler for a more complex
object containing the error message. When an error is raised in a low-level
iotk routine, a message is written on the error object. Any intermediate routine
can add other messages to the error object, at least the number of the line in
the source file. In this way, the error message contains a complete trace of
the error plus some additional information.
At any point in the chain the messages can be exctracted from the error object.
At some point in the chain the error is really handled, usually by writing the
message on the appropriate unit and aborting the execution.

Scanning routines (iotk_scan_*) have an optional logical argument "found"
which returns true or false. When scanning for data, also a "default" argument
can be used. If one of these two argument is present, the searched
object is considered as an optional object. Otherwise, it is considered as a needed object.

If the ierr optional argument is absent, the error handling is leaved to the iotk library.
In this case, if a needed object is not present, the library handles the error with a 
forced stop.

If the ierr optional argument is present, it returns an error code.
ierr = 0 means that no error has occurred
ierr > 0 means that an error has occurred probably related to file corruption
ierr < 0 means that the item that was searched for has not been found
         (it is possible only for scanning routines and only if the
          found and the default keywords are both missing, i.e. only for no-optional objetcs)
In scanning routines, if the argument "found" is present it returns .true.
if the item has been found, .false. otherwise.
If a library routine returns an ierr /= 0 it is STRONGLY RECOMMENDED to
clear that error with "call iotk_error_clear(ierr)" before proceeding.
Thus, the final recipe is:
* if you want to handle errors, always use the 'ierr' optional argument.
  looking at the sign, you will discern between lacking data and file corruption.
  with iotk_error_print you can obtain a description of the error.
* if you want to leave the error handling to the library, don't use
  the 'ierr' optional argument.
  - if the object you are searching is optional, use 'found' or 'default' optional arguments.
  - if the object you are searching is non-optional, don't use 'found' nor 'default' optional arguments.

@ binary_and_textual_files

IOTK: BINARY AND TEXTUAL FILES
Units can be opened on textual or binary files.
The word 'binary' is used instead of the fortran 'unformatted' since
using this libray also binary files have a degree of formattation.
After a unit has been opened, the library automatically detects
its format through an INQUIRE and acts consequently.
Note that the iotk routines check for necessary properties of an opened unit
access="sequential"
blank ="null" (only textual i/o)
pad   ="yes"  (only textual i/o)
Moreover, a textual or binary unit can be designed as raw.
In that case, no tags are placed on the file and everything
has to be read and written in the same order.
This feature is provided for compatibility reasons but it should be
used as few as possible.

@ optional_arguments

IOTK: OPTIONAL ARGUMENTS

Most iotk routines accept optional arguments.
The calling routine will not compile if the names of the
arguments are not indicated.  For instance, use
call iotk_scan_dat(10,"pippo",aa(:),ierr=ii)
and NOT:
call iotk_scan_dat(10,"pippo",aa(:),ii)
The only exeption is the attr argument, for which the name can be
omitted if it is placed as the first of the optional arguments.
In any case, it is better to always explicitly label optional arguments.

@ basic_writing_routines iotk_write_begin iotk_write_end iotk_write_empty iotk_write_pi iotk_write_comment

IOTK: BASIC WRITING ROUTINES
iotk_write_begin  (unit,name[,attr][,ierr])
iotk_write_end    (unit,name[,ierr])
iotk_write_empty  (unit,name[,attr][,ierr])
iotk_write_pi     (unit,name[,attr][,ierr])
iotk_write_comment(unit,text[,ierr])
integer,          intent(in) :: unit
character(len=*), intent(in) :: name
character(len=*), intent(in) :: text
character(len=*), intent(in) :: attr
integer,          intent(out):: ierr ! see error_handling page
These routines write a tag named 'name' on fortran unit 'unit'.
The type of the tag is determined from the name of the routine:
iotk_write_begin   => <name attr>
iotk_write_end     => </name>
iotk_write_empty   => <name attr/>
iotk_write_pi      => <?name attr?>
iotk_write_comment => <!--text-->
An optional attribute string can be supplied in 'attr'
In end tags, no attribute is allowed.
To build the attribute string, use iotk_write_attr.
DON'T TRY TO MANIPULATE THE ATTRIBUTE STRING DIRECTLY!

@ basic_scanning_routines iotk_scan_begin iotk_scan_end iotk_scan_empty iotk_scan_pi

IOTK: BASIC SCANNING ROUTINES
iotk_scan_begin(unit,name[,attr][,found][,ierr])
iotk_scan_end  (unit,name[,found][,ierr])
iotk_scan_empty(unit,name[,attr][,found][,ierr])
iotk_scan_pi   (unit,name[,attr][,found][,ierr])
integer,          intent(in) :: unit
character(len=*), intent(in) :: name  ! len less or equal iotk_namlenx
character(len=*), intent(out):: attr  ! len possibily equal iotk_attlenx
logical,          intent(out):: found ! see error_handling page
integer,          intent(out):: ierr  ! see error_handling page
These routines scan for a tag named 'name' on fortran unit 'unit'.
The type of the tag is determined from the name of the routine:
iotk_scan_begin => <name attr>
iotk_scan_end   => </name>
iotk_scan_empty => <name attr/>
iotk_scan_pi    => <?name attr?>
These routines (except for iotk_scan_end) also fills the
attr string, which can be subsequently decoded with iotk_scan_attr.
DON'T TRY TO MANIPULATE THE ATTRIBUTE STRING DIRECTLY!

@ writing_attributes iotk_write_attr

IOTK: WRITING ATTRIBUTES
iotk_write_attr (attr,name,val[,first][,ierr])
character(len=*), intent(out):: attr  ! len less or equal iotk_namlenx
character(len=*), intent(in) :: name  ! len less or equal iotk_attlenx
TYPE(KIND),       intent(in) :: val   ! any type, any kind, any rank [but only scalars for character]
logical,          intent(in) :: first
integer,          intent(out):: ierr
This routine adds one attribute to the 'attr' string.
To clean the string (for the first attribute) use first=.true.
Example:
  call iotk_write_attr(attr,"pippo",1,first=.true.)
  call iotk_write_attr(attr,"paperino",2)
  call iotk_write_attr(attr,"pluto",3)
This is equivalent to attr="" before the call, but more efficient.
The attribute is added in the form name="value",
where "value" is a string containing a textual representation
of the val variable.
If one of <>&"' appears in val, it is automatically escaped.

@ scanning_attributes iotk_scan_attr

IOTK: SCANNING ATTRIBUTES
iotk_scan_attr  (attr,name,val[,found][,default][,eos][,ierr])
character(len=*), intent(in) :: attr    ! len possibily equal iotk_attlenx
character(len=*), intent(in) :: name    ! len less or equal iotk_namlenx
TYPE(KIND),       intent(out):: val     ! any type, any kind, any rank [but only scalars for character]
logical,          intent(out):: found   ! see error_handling page
TYPE(KIND),       intent(in) :: default ! same type, kind and rank as val
logical,          intent(in) :: eos
integer,          intent(out):: ierr    ! see error_handling page
This routine scans for one attribute named 'name' from the 'attr' string.
If the attribute is found, it is read to variable 'val'.
If it is not found and default is present, default is copied onto val.
If TYPE is character and eos is present and true,
an end-of-string terminator will be attached at the end of the read string,
and the following bytes will not be touched. This is faster, but requires
the user to take care directly of the end-of-string. Thus, it is discouraged.
The attribute can be delimited with "" or with ''

@ writing_data iotk_write_dat

IOTK: WRITING DATA
iotk_write_dat  (unit,name,dat[,fmt][,columns][,ierr])
integer,          intent(in) :: unit
character(len=*), intent(in) :: name    ! len less or equal iotk_namlenx
TYPE(KIND),       intent(in) :: dat     ! any type, any kind, any rank
character(len=*), intent(in) :: fmt
integer,          intent(in) :: columns
integer,          intent(out):: ierr    ! see error_handling page
This routines write a data object, that is a self-described
object containg fortran data.
A single data object has the following form
<name type="TYPE" kind="KIND" size="SIZE" columns="COLUMNS" len="LEN" fmt="FMT">
.. DATA ...
</name>
where
TYPE    is the intrinsic type (logical,integer,real,complex or character),
KIND    is the data kind (stored in binary files only)
SIZE    is the array size (shape informations are not stored)
COLUMNS is the number of data per line
LEN     is the string length
FMT     is a fortran format string used to write data
If the optional 'fmt' is not passed, default format ('columns' element per line)
is used and the fmt attribute is not written. Otherwise, the string
fmt is used as a FORTRAN format specifierfor the write statement. In this
case it is also written on the file (and used for reading the data back).
fmt="*" can be used and correspond to the "write(unit,*)" statement.
If the optional 'columns' is not passed, it is assumed to be 1 and
the columns attribute is not written. Note that this attribute is completely
ininfluent when reading.
columns and fmt arguments are incompatible.
For complex data, one element is a couple of comma separated real numbers.
If one of <>& appears in dat, it is escaped.

@ scanning_data iotk_scan_dat

IOTK: SCANNING DATA
iotk_scan_dat  (unit,name,dat[,found][,default][,ierr])
integer,          intent(in) :: unit
character(len=*), intent(in) :: name    ! len less or equal iotk_namlenx
TYPE(KIND),       intent(out):: dat     ! any type, any kind, any rank
logical,          intent(out):: found   ! see error_handling page
TYPE(KIND),       intent(in) :: default ! same type, kind and rank as dat
integer,          intent(out):: ierr    ! see error_handling page
A data object written with iotk_write_dat is read.
If it is not found and default is present, default is copied onto dat.
If a keyword is absent in the file, the value is deduced from the
dat argument and no check is performed. This allows to write
rapidly by hand data objects. For instance
  <datum> 1.0 </datum>
can be read with
  real :: val
  call iotk_scan_dat(unit,"datum",val)
If fmt is not present on file, the default format is used.
Types and sizes are checked.
Different kinds (for binary i/o) are automatically converted.
Length (for characters) are not checked. If strings on files
are longer then len(dat), only the first characters are read; if strings
on files are shorter, dat is padded with blanks.

@ opening_files iotk_open_write iotk_open_read

IOTK: OPENING FILES

iotk_open_write(unit[,file][,attr][,binary][,raw][,new][,root][,ierr])
integer,          intent(in)  :: unit
character(len=*), intent(in)  :: file
character(len=*), intent(in)  :: attr
logical,          intent(in)  :: binary
logical,          intent(in)  :: new
logical,          intent(in)  :: raw
character(len=*), intent(in)  :: root   ! len less or equal iotk_namlenx
integer,          intent(out) :: ierr   ! see error_handling page
If file is present, this routines opens file 'file' on
unit 'unit' with the proper options.
If binary is present and true, the file is binary.
If new is present and true, the file must not exist already.
If raw is present and true, the file is considered as a raw data file
(use of raw data files is discouraged).
If file is not present, unit is assumed to be already connected.
If root is present, it is used as the name of the root begin/end tag.
If it is absent, the default "Root" is used.
An optional attribute string can be supplied in 'attr', and will be used
as an attribute list for the begin root tag.
Also informations about iotk version and binary format are written as
pi informations.

iotk_open_read(unit[,file][,attr][,binary][,raw][,root][,ierr])
integer,          intent(in)  :: unit
character(len=*), intent(in)  :: file
character(len=*), intent(out) :: attr
logical,          intent(in)  :: binary
logical,          intent(in)  :: raw
character(len=*), intent(out) :: root   ! len possibly equal iotk_namlenx
integer,          intent(out) :: ierr   ! see error_handling page
If file is present, this routines opens file 'file' on
unit 'unit' with the proper options.
If binary is present and true, the file is binary.
If raw is present and true, the file is considered as a raw data file
(use of raw data files is discouraged).
If file is not present, unit is assumed to be already connected.
If root is present, the name of root in file is read onto that variable.
If attr is present, the attributes of the root tag are read onto that variable,
which can be subsequently decoded with iotk_scan_attr.
DON'T TRY TO MANIPULATE THE ATTRIBUTE STRING DIRECTLY!

@ closing_files iotk_close_write iotk_close_read

IOTK: CLOSING FILES

iotk_close_write(unit[,ierr])
iotk_close_read(unit[,ierr])
integer,      intent(in)  :: unit
integer,      intent(out) :: ierr ! see error_handling page
This routines close a file opened with iotk_open_*
Note that if the units were already connected before iotk_open_*, they
are left connected here.

@ multiple_files iotk_link

IOTK: MULTIPLE FILES

When reading, if a begin tag with an attribute iotk_link="FILENAME" is found,
file FILENAME is mounted in its place
If FILENAME begins with a "/", the path is absolute, otherwise it is relative
to the original file.
Note that the mounting is completely transparent for users, which can access
the new file using the old unit. However, if the user wants to access
directly the new file, iotk_physical_unit should be used.

When writing, the user can switch a logical unit to a different file using
the following routine

iotk_link(unit,name,file,dummy[,binary][,raw][,create][,ierr])
integer,          intent(in)  :: unit
character(len=*), intent(in)  :: name
character(len=*), intent(in)  :: file
logical,          intent(in)  :: binary
logical,          intent(in)  :: raw
logical,          intent(in)  :: create
integer,          intent(out) :: ierr
name is the name of the tag which represents the link.
file is the name of the new file
if binary is present and true, the new file will be binary
if raw is present and true, the new file will be raw
if create is present and true, the new file is actually created
and the next write statement will act on this new file automatically.
Otherwise, only the symbolic link is created.

@ utilities

IOTK: OTHER UTILITIES

Here a number of additional routines/parameters available
from the iotk_module is listed

character(len=*) :: iotk_index (index)
integer, intent(in) :: index ! scalar or rank 1
Returns a string representing the index in an array.
Example: index = (/1,2,3/) => iotk_index = ".1.2.3"
The correct way for writing an array of derived types is
to build the names as follows
! ONE-DIMENSIONAL ARRAY
do i = 1 , n
  call iotk_write_begin(unit,"dummy"//iotk_index(i))
! WRITE THE OBJECT HERE
  call iotk_write_end  (unit,"dummy"//iotk_index(i))
end do
do i = 1 , n
  do j = 1 , m
! NOTE THE ORDER OF INDEXES, THE FASTER IS THE LAST
    call iotk_write_begin(unit,"dummy"//iotk_index((/i,j/)))
! WRITE THE OBJECT HERE
    call iotk_write_end  (unit,"dummy"//iotk_index((/i,j/)))
  end do
end do

iotk_free_unit(unit[,ierr])
integer, intent(out) :: unit
integer, intent(out) :: ierr
This routine returns the number of a free FORTRAN unit.

character(len=*) :: iotk_version
version string of iotk

character :: iotk_newline
newline sequence

character :: iotk_eos
end-of-string character

integer :: iotk_taglenx
max length of a tag

integer :: iotk_namlenx
max length of a tag or attribute name

integer :: iotk_attlenx
max length of the attribute string

integer :: iotk_vallenx
max length of the value of an attribute

integer :: iotk_linlenx
max length of a line in textual files

integer :: iotk_fillenx
max length of a file name

integer :: iotk_header_kind
integer kind of headers in binary files


