whio  Update of "whio_dev_HOWTO"

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.


Artifact ID: d5a3eff8e8ac8cb193253ab93a41f7177bdbe74e
Page Name:whio_dev_HOWTO
Date: 2011-05-23 18:50:54
Original User: stephan
Parent: e198b79d013ff67ea873312743d974d2711af63d

ACHTUNG: AS OF 20110523, THIS PAGE IS NOW MAINTAINED IN THE NEW WIKI: http://whiki.wanderinghorse.net/wikis/whio/?page=whio_dev_HOWTO

See also: TipsAndTricks, whio_rc

whio_dev HOWTO

This page gives an overview of how to do common things with whio_dev objects.

Opening a device requires using device-specific constructor functions, but closing devices is uniform for all device types:

// or:

There are some cases involving custom allocation where one must use close() instead of finalize(). Those details are explained in the whio_dev class' API docs. Such cases are client-specific, and not demonstrated here.

Opening a file

There are several options.

Wrap an opened FILE handle:

whio_dev * dev =
  whio_dev_for_FILE( fp, true /*true==take ownership*/);

By filename:

whio_dev * dev =
  whio_dev_for_filename( "my.file", "r+"/*fopen()-compatible mode*/);

Wrap an opened file descriptor (e.g. from open(2)):

whio_dev * dev =
  whio_dev_for_fileno( fd, "r+" /* see API docs */ );

Finally, the next function allows fine-grained control over whether a file may exist, must be created by this call, and file permissions:

whio_dev * dev = NULL;
int rc =
  whio_dev_posix_open2( &dev, "my.file",
                        WHIO_MODE_RWC /*see API docs*/, 0644 );

Using a popen()'ed pipe:

/* Custom destructor function. */
static void popen_dtor( void * x )
    pclose( (FILE*)x );


FILE * p = popen("/bin/ls", "r" );
whio_dev * dev = 
  whio_dev_for_FILE( p, false /*keep ownership*/ );
dev->client.data = p;
dev->client.dtor = popen_dtor;

After that we can stream the popen()'d handle using dev->api->read(). When we close the device (using dev->api->finalize(dev)) our custom destructor will be called, which will call pclose(). If we popen in write mode then we can write to the opened stream.

In-memory devices

Again, we have several options:

A dynamically-expanding buffer:

whio_dev * memDev =
  whio_dev_for_membuf( 1024 /*starting size*/, 1.5 /*growth factor*/ );

The growth factor specifies the amount by which the memory should be increased when the buffer needs to expand. e.g. 1.5 means to grow by 50%. A growth factor of 1.0 or less means the memory will never expand automatically, but truncate() may be used to manually expand it. (See the API docs for many more details.)

Wrap client-provided memory in read/write mode:

whio_dev * memDev =
  whio_dev_for_memmap_rw( clientMemory, memorySize );

Wrap client-provided const memory in read-only mode:

whio_dev * memDev =
  whio_dev_for_memmap_ro( clientMemory, memorySize );

For client-provided memory, we can also re-map a device to a different memory range:

// For read/write:
int rc =
  whio_dev_memmap_remap( memDev, clientMem, NULL, memSize );
// For const/read-only memory:
rc =
  whio_dev_memmap_remap( memDev, NULL, clientConstMem, memSize );


Subdevices allow one to proxy a given byte range inside of a parent device. The subdevice's cursor position and ranges are all relative to the parent device, and subdevices can be embedded in other subdevices. Reads and writes from/to subdevices will not allow the caller to leave the byte range specified for the subdevice.

Despite their utility, subdevices do have a few notable limitations and corner cases, so be sure to read the API docs before deciding to use them. (For example, their truncate() operation is very limited and device locking might not behave exactly as expected.)

Basic usage:

whio_size_t lowerBound = 10 /* starting offset */ ;
whio_size_t upperBound = 20 /*the virtual EOF/one-past-the-end position*/;
whio_dev * sub =
  whio_dev_subdev_create( parentDev, lowerBound, upperBound );

(The function should take a byte count as the third parameter, but the current semantics are already used heavily within client code, so it is not easy to change.)

An upper bound value of 0 means "unbounded", giving the subdevice access to all bytes in the parent device, starting at the given lower bounds.

The parent device must outlive the subdevice. Destroying a subdevice after its parent is destroyed leads to undefined behaviour.

A subdevice can be "re-bound" to a new range within its parent device:

int rc = whio_dev_subdev_rebound( sub, newLowerBound, newUpperBound );