Custom-driver code for MYDRIVER
The following driver code supports MYDRIVER:
#include <plcstdrv.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/fcntl.h>
extern char *malloc();
externerrno;
static int DrOpen();
static int DrRead();
static int DrWrite();
static int DrClose();
#define CTRLDELIM 0x01/* fake delimiter (CTRL-A) */
#define REALDELIM 0x7c/* real delimiter (|) */
#define ESCAPSIGN 0x5c/* escape sign(\) */
#define ENDRECORD 0x0a/* end of record (\n) */
int fd;
/*---------------------------------------------------------------------
* DrConfig()
*
* Input : (char *)driver name
* (void *)method table
*
* Return : PL_RTN_OK
*
* Schema : Fills in the driver table
*-------------------------------------------------------------------*/
int
DrConfig(driver,methodtable)
char*driver;
void*methodtable;
{
pl_inherit_methods("Delimited", methodtable);
pl_set_method_function(methodtable, PL_MTH_OPEN, DrOpen);
pl_set_method_function(methodtable, PL_MTH_RAWREAD, DrRead);
pl_set_method_function(methodtable, PL_MTH_RAWWRITE, DrWrite);
pl_set_method_function(methodtable, PL_MTH_CLOSE, DrClose);
pl_lock_globals();
return PL_RTN_OK;
}
/*--------------------------------------------------------------------
* DrOpen()
*
* Input : (devicearray *) devdevice array structure
*
* Return : PL_RTN_FAILerror
* PL_RTN_OK open succeeded
*
* Schema : Open the specific file for that driver thread
* Note that the custom driver thread is bound to its
* own CPU VP, therefore it is safe to have globals like fd
*------------------------------------------------------------------*/
static int
DrOpen(dev)
devicearray*dev;
{
fd = open(dev->filename, O_RDONLY);
if (fd < 0)
{
return PL_RTN_FAIL;
}
return PL_RTN_OK;
}
/*--------------------------------------------------------------------
* DrRead()
*
* Input : (char *) bfoutput buffer to write record to
* (int)size size of output buffer
* (int *) countnumber of bytes written to output buffer
*
* Return : PL_RTN_FAILerror
* PL_RTN_OK returning buffer
* PL_RTN_EOFreturning the last buffer, no more data
*
*
* Schema : Reads from input and fill up data buffer provided by the
* caller. Here, the caller expect a record where the delimiter
* is |. Our custom driver changes all CTRL-A into | and
* escapes the already existing | from input.
*------------------------------------------------------------------*/
static int
DrRead(bf, size, count)
char*bf;
int size;
int*count;
{
int rtn;/* return value */
int n; /* bytes read in */
static char*bftemp = 0;/* temp buffer*/
char*p; /* pointer to temp buff */
char*start; /* start of output buffer*/
static off_tcurrseek = 0; /* current seek in input */
int escaped = 0;/* did we escape last character */
start = bf;
if (bftemp == 0)
{
if ( (bftemp = malloc(size)) == 0 )
{
return PL_RTN_FAIL;
}
}
/*
* read data in
*/
errno = 0;
do
{
n = read(fd, bftemp, size);
} while (n == -1 && errno == 4);
rtn = (n < 0) ? PL_RTN_FAIL : (n == size) ? PL_RTN_OK : PL_RTN_EOF;
currseek += n;
p = bftemp;
/*
* format output buffer
*/
while (size)
{
if (*p == REALDELIM)
{
*bf = ESCAPSIGN;
escaped = 1;
}
else if (*p == CTRLDELIM)
{
*bf = REALDELIM;
}
else
{
*bf = *p;
}
size--;
bf++;
if (escaped && size)
{
*bf++ = *p;
escaped = 0;
size--;
}
p++;
if ((int) (p - bftemp) == n)
break;
}
if (escaped)
{
p--;
rtn = PL_RTN_OK;
}
if ((int) (p - bftemp) != n)
{
currseek -= (off_t) (n - (p - bftemp));
lseek(fd, currseek, SEEK_SET);
}
if (rtn == PL_RTN_EOF)
{
*bf = 0;
}
*count = (int) (bf - start);
return rtn;
}
static int
DrWrite(bf, size)
char*bf;
int size;
{
return PL_RTN_OK;
}
static int
DrClose(device)
devicearray *device;
{
close(fd);
return PL_RTN_OK;
}