.\" 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.