.\" Copyright (c) 2007 Hypertriton, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
.\" (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd November 16, 2007
.Dt AG_DATASOURCE 3
.Os
.ds vT Agar API Reference
.ds oS Agar 1.3
.Sh NAME
.Nm AG_DataSource
.Nd agar data source access
.Sh SYNOPSIS
.Bd -literal
#include
.Ed
.Sh DESCRIPTION
The
.Nm
structure provides a generic interface to different data sources.
Built-in sources include
.Ft AG_FileSource
for files,
.Ft AG_CoreSource
for fixed-size memory,
.Ft AG_AutoCoreSource
for automatically-allocated memory and
.Ft AG_ConstCoreSource
for read-only memory.
.Pp
New data sources can be implemented by overloading the
.Nm
structure.
.Sh INTERFACE
.nr nS 1
.Ft "AG_DataSource *"
.Fn AG_OpenFile "const char *path" "const char *mode"
.Pp
.Ft "AG_DataSource *"
.Fn AG_OpenFileHandle "FILE *f"
.Pp
.Ft "AG_DataSource *"
.Fn AG_OpenCore "void *p" "size_t size"
.Pp
.Ft "AG_DataSource *"
.Fn AG_OpenConstCore "const void *p" "size_t size"
.Pp
.Ft "void"
.Fn AG_CloseFile "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_CloseFileHandle "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_CloseCore "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_CloseConstCore "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_CloseDataSource "AG_DataSource *ds"
.Pp
.Ft "AG_IOStatus"
.Fn AG_Read "AG_DataSource *ds" "void *buf" "size_t size" "size_t nmemb"
.Pp
.Ft "AG_IOStatus"
.Fn AG_ReadAt "AG_DataSource *ds" "void *buf" "size_t size" "size_t nmemb" "off_t pos"
.Pp
.Ft "AG_IOStatus"
.Fn AG_Write "AG_DataSource *ds" "const void *buf" "size_t size" "size_t nmemb"
.Pp
.Ft "AG_IOStatus"
.Fn AG_WriteAt "AG_DataSource *ds" "const void *buf" "size_t size" "size_t nmemb" "off_t pos"
.Pp
.Ft "off_t"
.Fn AG_Tell "AG_DataSource *ds"
.Pp
.Ft "int"
.Fn AG_Seek "AG_DataSource *ds" "off_t offs" "enum ag_seek_mode mode"
.Pp
.Ft "void"
.Fn AG_LockDataSource "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_UnlockDataSource "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_SetByteOrder "AG_DataSource *ds" "enum ag_byte_order order"
.Pp
.Ft "void"
.Fn AG_SetSourceDebug "AG_DataSource *ds" "int enable"
.Pp
.Ft "void"
.Fn AG_DataSourceInit "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_DataSourceDestroy "AG_DataSource *ds"
.Pp
.Ft "void"
.Fn AG_DataSourceSetErrorFn "AG_DataSource *ds" "void (*fn)(AG_Event *)" "const char *fmt" "..."
.Pp
.Ft "void"
.Fn AG_DataSourceError "AG_DataSource *ds" "const char *fmt" "..."
.Pp
.nr nS 0
The
.Fn AG_OpenFile
function opens the file at
.Fa path ,
where
.Fa mode
is a
.Xr fopen 3
style mode string.
.Fn AG_OpenFileHandle
creates a data source for a previously opened file.
.Pp
The
.Fn AG_OpenCore
and
.Fn AG_OpenConstCore
functions create data sources for the region of memory
.Fa p
of
.Fa size
bytes.
.Pp
.Fn AG_CloseFile ,
.Fn AG_CloseFileHandle ,
.Fn AG_CloseCore
and
.Fn AG_CloseConstCore
close a data source of the given type.
Alternatively,
.Fn AG_CloseDataSource
can be used to close any type of source.
.Pp
.Fn AG_Read
reads
.Fa nmemb
items of
.Fa size
bytes from the data source into
.Fa buf .
The
.Fn AG_ReadAt
variant reads from the given position
.Fa pos .
.Pp
.Fn AG_Write
writes
.Fa nmemb
items of
.Fa size
bytes
.Fa buf
into the data source.
The
.Fn AG_WriteAt
variant writes to the given position
.Fa pos .
.Pp
.Fn AG_Tell
returns the current position in the data source.
If the underlying data source does not support this operation, a value
of 0 is returned.
.Pp
.Fn AG_Seek
seeks to the given position in the data source.
Acceptable values for
.Fa mode
include
.Dv AG_SEEK_SET
(relative to data start),
.Dv AG_SEEK_CUR
(relative to current position),
.Dv AG_SEEK_END
(relative to data end).
.Pp
The
.Fn AG_LockDataSource
and
.Fn AG_UnlockDataSource
functions acquire and release the exclusive lock protecting this data
source, and are no-ops if thread support is disabled.
.Pp
.Fn AG_SetByteOrder
configures the byte order to be used by integer read/write operations.
Accepted parameters are
.Dv AG_BYTEORDER_BE
for big-endian and
.Dv AG_BYTEORDER_LE
for little-endian.
To determine the byte order of the current architecture, you can use the
standard
.Dv AG_BYTEORDER
define (which evaluates to
.Dv AG_BIG_ENDIAN
or
.Dv AG_LITTLE_ENDIAN ) .
.Pp
Prior to writing to a data source,
.Fn AG_SetSourceDebug
enables encoding and verification of debugging information in the archive.
At the cost of increasing the size of the archive, it enables, notably,
type-safety checks at primitive data type level as the archive decoded.
.Pp
The
.Fn AG_DataSourceInit
and
.Fn AG_DataSourceDestroy
functions are used when implementing new data source types.
They are used internally by the
.Fn AG_Open*
and
.Fn AG_Close*
functions.
.Pp
.Fn AG_DataSourceSetErrorFn
configures an alternate handler routine for data source exceptions (which
can occur when using routines such as
.Fn AG_ReadUint32 ,
for example on I/O error).
From the handler routine, a pointer to the
.Ft AG_DataSource
can be retrieved using
.Dv AG_SELF ,
and the error message is retrieved using
.Dv AG_STRING(1) .
The routine is expected to
.Xr free 3
the string.
The default exception handler simply calls
.Xr AG_FatalError 3 .
.Pp
The
.Fn AG_DataSourceError
function raises a data source error, with the optional error message string.
It is intended for use in custom I/O routines which do not return an error
status.
If
.Fa fmt
is NULL, the error is obtained from
.Xr AG_GetError 3 .
.Sh IMPLEMENTING NEW SOURCES
Implementing a new data source is simply a matter of inheriting from the
.Va AG_DataSource
structure and configuring a number of low-level I/O functions (any of which
can be set to NULL if not applicable to the data source).
.Pp
Public members of the
.Nm
structure include:
.Bd -literal
typedef struct ag_data_source {
AG_Mutex lock; /* Lock on all operations */
enum ag_byte_order byte_order; /* Byte order of source */
size_t wrLast; /* Last write count (bytes) */
size_t rdLast; /* Last read count (bytes) */
size_t wrTotal; /* Total write count (bytes) */
size_t rdTotal; /* Total read count (bytes) */
AG_IOStatus (*read)(struct ag_data_source *, void *buf,
size_t size, size_t nmemb, size_t *rv);
AG_IOStatus (*read_at)(struct ag_data_source *, void *buf,
size_t size, size_t nmemb, off_t pos,
size_t *rv);
AG_IOStatus (*write)(struct ag_data_source *, const void *buf,
size_t size, size_t nmemb, size_t *rv);
AG_IOStatus (*write_at)(struct ag_data_source *, const void *buf,
size_t size, size_t nmemb, off_t pos,
size_t *rv);
off_t (*tell)(struct ag_data_source *);
int (*seek)(struct ag_data_source *, off_t offs,
enum ag_seek_mode mode);
void (*close)(struct ag_data_source *);
} AG_DataSource;
.Ed
.Pp
The
.Va byte_order
setting affects integer read operations.
.Pp
The
.Va wrLast ,
.Va rdLast ,
.Va wrTotal
and
.Va rdTotal
fields keep count of the read/written bytes, and are automatically
incremented by the generic
.Nm
calls.
.Pp
The
.Va read
operation reads
.Fa nmemb
items of
.Fa size
bytes from the data source and into
.Fa buf ,
returning the total number of bytes read into
.Fa rv .
The
.Va read_at
variant reads data at a specified offset.
.Pp
The
.Va write
operation writes
.Fa nmemb
items of
.Fa size
bytes from
.Fa buf
to the data source, returning the total number of bytes written into
.Fa rv .
The
.Va write_at
variant writes the data at a specified offset.
.Pp
.Va tell
returns the current offset.
.Pp
.Va seek
moves to the specified offset and returns 0 on success and -1 on failure.
.Pp
.Va close
closes the data source.
.Sh INTEGER OPERATIONS
The following functions read and write integer values using the byte order
specified for the data source.
.Pp
.nr nS 1
.Ft Uint8
.Fn AG_ReadUint8 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadUint8v "AG_DataSource *ds" "Uint8 *v"
.Pp
.Ft Sint8
.Fn AG_ReadSint8 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadSint8v "AG_DataSource *ds" "Sint8 *v"
.Pp
.Ft Uint16
.Fn AG_ReadUint16 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadUint16v "AG_DataSource *ds" "Uint16 *v"
.Pp
.Ft Sint16
.Fn AG_ReadSint16 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadSint16v "AG_DataSource *ds" "Sint16 *v"
.Pp
.Ft Uint32
.Fn AG_ReadUint32 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadUint32v "AG_DataSource *ds" "Uint32 *v"
.Pp
.Ft Sint32
.Fn AG_ReadSint32 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadSint32 "AG_DataSource *ds" "Sint32 *v"
.Pp
.Ft Uint64
.Fn AG_ReadUint64 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadUint64v "AG_DataSource *ds" "Uint64 *v"
.Pp
.Ft Sint64
.Fn AG_ReadSint64 "AG_DataSource *ds"
.Pp
.Ft int
.Fn AG_ReadSint64v "AG_DataSource *ds" "Sint64 *v"
.Pp
.Ft void
.Fn AG_WriteUint8 "AG_DataSource *ds" "Uint8 value"
.Pp
.Ft int
.Fn AG_WriteUint8v "AG_DataSource *ds" "const Uint8 *value"
.Pp
.Ft void
.Fn AG_WriteSint8 "AG_DataSource *ds" "Sint8 value"
.Pp
.Ft int
.Fn AG_WriteSint8v "AG_DataSource *ds" "const Sint8 *value"
.Pp
.Ft void
.Fn AG_WriteUint16 "AG_DataSource *ds" "Uint16 value"
.Pp
.Ft int
.Fn AG_WriteUint16v "AG_DataSource *ds" "const Uint16 *value"
.Pp
.Ft void
.Fn AG_WriteSint16 "AG_DataSource *ds" "Sint16 value"
.Pp
.Ft int
.Fn AG_WriteSint16v "AG_DataSource *ds" "const Sint16 *value"
.Pp
.Ft void
.Fn AG_WriteUint32 "AG_DataSource *ds" "Uint32 value"
.Pp
.Ft int
.Fn AG_WriteUint32v "AG_DataSource *ds" "const Uint32 *value"
.Pp
.Ft void
.Fn AG_WriteSint32 "AG_DataSource *ds" "Sint32 value"
.Pp
.Ft int
.Fn AG_WriteSint32v "AG_DataSource *ds" "const Sint32 *value"
.Pp
.Ft void
.Fn AG_WriteUint64 "AG_DataSource *ds" "Uint64 value"
.Pp
.Ft int
.Fn AG_WriteUint64v "AG_DataSource *ds" "const Uint64 *value"
.Pp
.Ft void
.Fn AG_WriteSint64 "AG_DataSource *ds" "Sint64 value"
.Pp
.Ft int
.Fn AG_WriteSint64v "AG_DataSource *ds" "const Sint64 *value"
.Pp
.Ft void
.Fn AG_WriteUint8At "AG_DataSource *ds" "Uint8 value" "off_t offs"
.Pp
.Ft void
.Fn AG_WriteSint8At "AG_DataSource *ds" "Sint8 value" "off_t offs"
.Pp
.Ft void
.Fn AG_WriteUint16At "AG_DataSource *ds" "Uint16 value" "off_t offs"
.Pp
.Ft void
.Fn AG_WriteSint16At "AG_DataSource *ds" "Sint16 value" "off_t offs"
.Pp
.Ft void
.Fn AG_WriteUint32At "AG_DataSource *ds" "Uint32 value" "off_t offs"
.Pp
.Ft void
.Fn AG_WriteSint32At "AG_DataSource *ds" "Sint32 value" "off_t offs"
.Pp
.Ft void
.Fn AG_WriteUint64At "AG_DataSource *ds" "Uint64 value" "off_t offs"
.Pp
.Ft void
.Fn AG_WriteSint64At "AG_DataSource *ds" "Sint64 value" "off_t offs"
.Pp
.nr nS 0
.Pp
The
.Fn AG_Read[SU]intN
functions read and return an integer value of N bits from the data source.
The
.Fn AG_Read[SU]intNv
variants write the value to the specified pointer.
.Pp
The
.Fn AG_Write[SU]intN
functions write an integer value of N bits to the data source.
The
.Fn AG_Write[SU]intNv
variants accept a pointer argument.
.Pp
The
.Fn AG_Write[SU]intNAt
variants write the integer to the specified position in the data source.
.Pp
All
.Fn AG_Read*v
functions return 0 on success and -1 on failure, without raising any
exceptions.
The other functions will raise a data source exception if an failuer (e.g.,
an I/O error) occured.
.Pp
The 64-bit types are only available if
.Dv HAVE_64BIT
is defined.
.Sh FLOATING POINT OPERATIONS
The following routines read and write floating-point numbers in IEEE.754
representation.
.Pp
.nr nS 1
.Ft "float"
.Fn AG_ReadFloat "AG_DataSource *ds"
.Pp
.Ft "int"
.Fn AG_ReadFloatv "AG_DataSource *ds" "float *f"
.Pp
.Ft "double"
.Fn AG_ReadDouble "AG_DataSource *ds"
.Pp
.Ft "int"
.Fn AG_ReadDoublev "AG_DataSource *ds" "double *f"
.Pp
.Ft "long double"
.Fn AG_ReadLongDouble "AG_DataSource *ds"
.Pp
.Ft "int"
.Fn AG_ReadLongDouble "AG_DataSource *ds" "long double *f"
.Pp
.Ft "void"
.Fn AG_WriteFloat "AG_DataSource *ds" "float f"
.Pp
.Ft "int"
.Fn AG_WriteFloatv "AG_DataSource *ds" "float *f"
.Pp
.Ft "void"
.Fn AG_WriteFloatAt "AG_DataSource *ds" "float f" "off_t pos"
.Pp
.Ft "void"
.Fn AG_WriteDouble "AG_DataSource *ds" "double f"
.Pp
.Ft "int"
.Fn AG_WriteDoublev "AG_DataSource *ds" "double *f"
.Pp
.Ft "void"
.Fn AG_WriteDoubleAt "AG_DataSource *ds" "double f" "off_t pos"
.Pp
.Ft "void"
.Fn AG_WriteLongDouble "AG_DataSource *ds" "long double f"
.Pp
.Ft "int"
.Fn AG_WriteLongDoublev "AG_DataSource *ds" "long double *f"
.Pp
.Ft "void"
.Fn AG_WriteLongDoubleAt "AG_DataSource *ds" "long double f" "off_t pos"
.Pp
.nr nS 0
.Fn AG_ReadFloat ,
.Fn AG_ReadDouble
and
.Fn AG_ReadLongDouble
read a floating-point value from the data source.
.Pp
.Fn AG_WriteFloat ,
.Fn AG_WriteDouble
and
.Fn AG_WriteLongDouble
write a floating-point value to the data source.
The
.Fn AG_Write*At
variants write the value at a given position.
.Pp
All
.Fn AG_Read*v
functions return 0 on success and -1 on failure, without raising any
exceptions.
The other functions will raise a data source exception if an failuer (e.g.,
an I/O error) occured.
.Pp
The
.Fa "long double"
functions are available only if
.Dv HAVE_LONG_DOUBLE
is defined.
.Sh STRING OPERATIONS
The following functions read and write arbitrary strings, and are commonly
used for text.
The encoding of the strings is simply an unsigned 32-bit integer byte count,
followed by the string.
The encoding may or may not include a terminating NUL.
.Pp
.nr nS 1
.Ft "char *"
.Fn AG_ReadStringLen "AG_DataSource *ds" "size_t maxsize"
.Pp
.Ft "int"
.Fn AG_ReadStringLenv "AG_DataSource *ds" "size_t maxsize" "char **s"
.Pp
.Ft "char *"
.Fn AG_ReadString "AG_DataSource *ds"
.Pp
.Ft "int"
.Fn AG_ReadStringv "AG_DataSource *ds" "char **s"
.Pp
.Ft "char *"
.Fn AG_ReadNulStringLen "AG_DataSource *ds" "size_t maxsize"
.Pp
.Ft "char *"
.Fn AG_ReadNulString "AG_DataSource *ds"
.Pp
.Ft size_t
.Fn AG_CopyString "char *buf" "AG_DataSource *ds" "size buf_size"
.Pp
.Ft size_t
.Fn AG_CopyNulString "char *buf" "AG_DataSource *ds" "size buf_size"
.Pp
.Ft void
.Fn AG_SkipString "AG_DataSource *ds"
.Pp
.Ft void
.Fn AG_WriteString "AG_DataSource *ds" "const char *s"
.Pp
.Ft int
.Fn AG_WriteStringv "AG_DataSource *ds" "const char *s"
.Pp
.nr nS 0
.Pp
The
.Fn AG_ReadStringLen
function reads a string of up to
.Fa maxsize
bytes and returns a dynamically allocated, NUL-terminated copy of the string.
.Fn AG_ReadString
implicitely limits the string to
.Dv AG_LOAD_STRING_MAX
bytes.
On error, a data source exception is raised.
.Pp
The
.Fn AG_ReadStringLenv
and
.Fn AG_ReadStringv
variants accept pointer arguments and will not raise exceptions on error.
.Pp
.Fn AG_CopyString
copies the string directly into a fixed-size buffer
.Fa buf
of
.Fa buf_size
bytes and NUL-terminates it.
.Fn AG_CopyString
returns the number of bytes that would have been copied were
.Fa buf_size
unlimited.
.Pp
The
.Fn AG_ReadNulString ,
.Fn AG_ReadNulStringLen
and
.Fn AG_CopyNulString
variants handle the case where the encoding of the string is NUL-terminated.
.Pp
The
.Fn AG_SkipString
routine skips over the string at the current position in the buffer.
.Pp
The
.Fn AG_WriteString
function writes a string to a data source, where the encoding is not
NUL-terminated.
If an error occurs, a data source exception is raised.
The
.Fn AG_WriteStringv
variant returns 0 on success and -1 on failure, without raising exceptions.
.Sh SEE ALSO
.Xr AG_Intro 3 ,
.Xr AG_Version 3 ,
.Xr AG_ByteSwap 3
.Sh HISTORY
A similar interface called
.Sq AG_Netbuf
first appeared in Agar 1.0.
The current
.Nm
interface appeared in Agar 1.3.
Exception handling and error-checking variants of the primitive I/O routines
appeared in Agar 1.3.3.