home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 11 Util
/
11-Util.zip
/
TIMEXSRC.ZIP
/
EVPACK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-29
|
18KB
|
696 lines
/* evpack.c -- Event packing and unpacking
February 1990 Mark E. Mallett, Personal Workstation Magazine
This module contains routines to pack and unpack event data for purposes
of interprocess communication, and to construct an event struct from the
pieces that make up the event. The routines in this module can be used
by the timex background agent (TIMEXBA) or by any client that wants to
communicate to TIMEXBA.
Included are the following routines:
event_action Specify event action
event_acttype Specify event action type
event_clear Clear the current event information
event_dayofmon Add day-of-month to event definition
event_dayofwk Add day-of-week to event definition
event_hour Add hour to event definition
event_make Make an event struct from current definition
event_min Add minute to event definition
event_month Add month(s) to an event definition
event_name Specify the name of the event
event_pack Pack an event into a message buffer
event_pri Specify event priority
event_year Add year(s) to event definition
event_unpack Unpack an event from a message buffer
The routines in this module require the existence of various routines
in the application. The routines are those for which prototypes are
specified in the file "timex.h"; look further for more details.
Note: in regard to event packing and unpacking, the event is stored in
a buffer in a tagged byte-string format. Each item begins with an
identifying tag, which is followed by the bytes that compose that
event value. This allows for future expansion of the data while still
allowing for old packing formats to be used (i.e., missing tags can
be defaulted); it also ignores any byte-ordering considerations.
*/
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <os2.h>
#include "timex.h"
#include "evpack.h"
/* Local definitions */
#ifndef NUL
#define NUL '\0'
#endif /* NUL */
/* External data referenced */
/* External routines used */
/* Local data publicly available */
/* Local routines and forward declarations */
static void pack_byte( char **bufPP, int *bufLP, BYTE val );
static void pack_long( char **bufPP, int *bufLP, ULONG val );
static void pack_string( char **bufPP, int *bufLP, char *strP );
static void pack_tag( char **bufPP, int *bufLP, int tag );
static void pack_word( char **bufPP, int *bufLP, UWORD val );
static UBYTE unpack_byte( char **bufPP );
static ULONG unpack_long( char **bufPP );
static UWORD unpack_word( char **bufPP );
/* Private data */
static char Action[100]; /* Action spec */
static char Name[100]; /* Event name */
static UBYTE *TagLP; /* Ptr to tag length byte */
static EVENT Tevent; /* Template event */
static int YearC; /* Number of years */
static int YearS; /* Size of years table */
static YEARSPEC *Yeartbl; /* Years table */
/*
*//* event_pack( eventP, bufP, bufL )
Pack an event into a buffer.
Accepts:
eventP Ptr to an EVENT struct.
bufP Address to pack the event into.
bufL Number of bytes available in the buffer.
Returns :
< value > Number of bytes used
Notes :
Error return is taken if the pack fails (e.g., for memory
allocation problem or if the buffer is not large enough).
See the module introduction for notes about the packing format.
*/
int
event_pack(
EVENT *eventP, /* Event to pack */
char *bufP, /* Where to pack it */
int bufL /* Size of the buffer */
) {
int i; /* Scratch */
int len; /* Running length */
/* Go through the event and pack it, tag-wize */
len = bufL; /* Get copy of length */
TagLP = NULL; /* No tag length slot */
/* Name */
pack_tag( &bufP, &len, ETAG_NAME );
pack_string( &bufP, &len, eventP->ev_nameP );
/* List of years */
pack_tag( &bufP, &len, ETAG_YEARS );
pack_word( &bufP, &len, eventP->ev_yearC );
for( i = 0; i < eventP->ev_yearC; ++i ) {
pack_word( &bufP, &len, eventP->ev_yearP[i].y_first );
pack_word( &bufP, &len, eventP->ev_yearP[i].y_last );
}
/* Months */
pack_tag( &bufP, &len, ETAG_MONTHS );
pack_word( &bufP, &len, eventP->ev_months );
/* Day-of stuff */
pack_tag( &bufP, &len, ETAG_DAYOF );
pack_byte( &bufP, &len, (BYTE)eventP->ev_dayof );
pack_long( &bufP, &len, eventP->ev_dayofs );
/* Hours */
pack_tag( &bufP, &len, ETAG_HOURS );
pack_long( &bufP, &len, eventP->ev_hours );
/* Minutes */
pack_tag( &bufP, &len, ETAG_MINS );
pack_long( &bufP, &len, eventP->ev_mins[0] );
pack_long( &bufP, &len, eventP->ev_mins[1] );
/* Priority */
pack_tag( &bufP, &len, ETAG_PRIO );
pack_byte( &bufP, &len, eventP->ev_priclass );
pack_byte( &bufP, &len, eventP->ev_prival );
/* Action type */
pack_tag( &bufP, &len, ETAG_ACTTYPE );
pack_byte( &bufP, &len, (BYTE)eventP->ev_acttype );
/* Action value */
pack_tag( &bufP, &len, ETAG_ACTARG );
pack_string( &bufP, &len, eventP->ev_actargP );
/* End of packing */
pack_tag( &bufP, &len, ETAG_END );
/* Return the number of bytes used */
return( bufL - len );
}
/*
*//* event_unpack( bufP )
Unpack an event.
Accepts :
bufP Address of a buffer containing a packed event.
Returns :
< value > Ptr to an event struct.
Notes :
See the module introduction for notes about the packing format.
See the note in event_make() about the construction
of event memory.
*/
EVENT *
event_unpack(
char *bufP, /* Ptr to packed event */
int bufL /* Bytes in the buffer */
) {
int i; /* Scratch */
int tag; /* Tag */
char *nbufP; /* Ptr to next tag */
UWORD fyear, lyear; /* First/last years */
/* Initialize a new event */
event_clear();
/* Go through the tagged event data */
for( tag = -1; ( bufL > 0 ) && ( tag = *bufP ) != ETAG_END;
bufP = nbufP ) {
if ( bufP[1] < 2 ) /* Bad offset? */
break;
nbufP = bufP + bufP[1]; /* Offset to next tag item */
bufL -= (nbufP - bufP ); /* Decrement buffer count */
if ( bufL < 0 )
break;
bufP += 2; /* Skip past tag & length */
switch( tag ) {
case ETAG_NAME: /* Event name */
event_name( bufP );
bufP += strlen( bufP ) +1;
break;
case ETAG_YEARS: /* List of years */
i = unpack_word( &bufP );
while( i-- > 0 ) {
fyear = unpack_word( &bufP );
lyear = unpack_word( &bufP );
event_year( fyear, lyear );
}
break;
case ETAG_MONTHS: /* Months mask */
Tevent.ev_months = unpack_word( &bufP );
break;
case ETAG_DAYOF: /* Day-of info */
Tevent.ev_dayof = *bufP++;
Tevent.ev_dayofs = unpack_long( &bufP );
break;
case ETAG_HOURS: /* Hours info */
Tevent.ev_hours = unpack_long( &bufP );
break;
case ETAG_MINS: /* Minutes info */
Tevent.ev_mins[0] = unpack_long( &bufP );
Tevent.ev_mins[1] = unpack_long( &bufP );
break;
case ETAG_PRIO: /* Priority info */
Tevent.ev_priclass = *bufP++;
Tevent.ev_prival = *bufP++;
break;
case ETAG_ACTTYPE: /* Action type */
Tevent.ev_acttype = *bufP++;
break;
case ETAG_ACTARG: /* Action arg */
event_action( bufP );
break;
default:
/* Ignore unknown tags. */
break;
}
}
/* Make event */
return( event_make() );
}
/*
*//* event_action( actP )
Store an action for an event under construction
*/
void
event_action( char *actP ) {
strcpy( &Action[0], actP );
}
/*
*//* event_acttype( atype )
Store an action type for event under construction
*/
void
event_acttype( ACTTYPE atype ) {
Tevent.ev_acttype = atype;
}
/*
*//* event_clear()
Clear the event currently under construction
*/
void
event_clear() {
Action[0] = NUL;
Name[0] = NUL;
YearC = 0;
memset( &Tevent, 0, sizeof(Tevent) );
}
/*
*//* event_dayofmon( dom )
Add day-of-month to event under construction
Note: day of month is 1-based.
*/
void
event_dayofmon( int dom ) {
Tevent.ev_dayof = DAYOF_MONTH;
Tevent.ev_dayofs |= 1L << (dom -1);
}
/*
*//* event_dayofwk( dow )
Add day-of-week to event under construction
Note: Day-of-week is 0-based
*/
void
event_dayofwk( int dow ) {
Tevent.ev_dayof = DAYOF_WEEK;
Tevent.ev_dayofs |= 1L << dow;
}
/*
*//* event_hour( hour )
Add an hour to the event under construction
*/
void
event_hour( int hour ) {
Tevent.ev_hours |= 1L << hour;
}
/*
*//* event_make()
Make an event as previously defined via event construction calls
Accepts :
Returns :
< value > Ptr to an event struct
Notes :
The event struct is constructed from a single chunk of memory.
Even though the struct has pointers which point to data items,
those data items are allocated, along with the event struct,
all in one unit. Thus to free an event struct, it is not
necessary to chase down and free all the memory pointed to.
*/
EVENT *
event_make() {
int evsize; /* Size of the event */
char *strP; /* Ptr to string in event block */
EVENT *eventP; /* PTr to new event made */
/* Calculate size required */
evsize = sizeof( EVENT );
evsize += YearC * sizeof(YEARSPEC);
evsize += strlen( &Name[0] ) +1;
evsize += strlen( &Action[0] ) +1;
eventP = (EVENT *)emalloc( "event_make", "event", evsize );
memcpy( eventP, &Tevent, sizeof( EVENT ) );
strP = (char *)&eventP[1];
eventP->ev_yearC = YearC;
eventP->ev_yearP = (YEARSPEC *)strP;
memcpy( strP, Yeartbl, YearC * sizeof(YEARSPEC) );
strP += YearC * sizeof(YEARSPEC);
eventP->ev_nameP = strP;
strcpy( strP, &Name[0] );
strP += strlen( strP ) +1;
eventP->ev_actargP = strP;
strcpy( strP, &Action[0] );
strP += strlen( strP ) +1;
return( eventP );
}
/*
*//* event_min( min )
Add a minute to the event under construction
*/
void
event_min( int min ) {
int minX; /* Minute index */
int minoffs; /* Minute offset */
/* Get minute's index and bit number */
minX = min/32;
minoffs = min%32;
/* Update the bitmask */
Tevent.ev_mins[minX] |= 1L << minoffs;
}
/*
*//* event_month( mon )
Add a month to the event under construction
Note: day of month is 0-based.
*/
void
event_month( int mon ) {
Tevent.ev_months |= 1L << mon;
}
/*
*//* event_name( nameP )
Set the name for the event under construction
*/
void
event_name( char *nameP ) {
strcpy( &Name[0], nameP );
}
/*
*//* event_pri( class, value )
Set the priority for the event under construction
*/
void
event_pri( int class, int value ) {
Tevent.ev_priclass = (BYTE)class;
Tevent.ev_prival = (BYTE)value;
}
/*
*//* event_year( fyear, lyear )
Set a range of years for the event under construction
*/
void
event_year( int fyear, int lyear ) {
int yearX; /* Index into years table */
int sX; /* Swap index */
/* Look through the years table to see if we can use a slot there */
for( yearX = 0; yearX < YearC; ++yearX ) {
if ( ( Yeartbl[yearX].y_first > fyear ) &&
( Yeartbl[yearX].y_first <= lyear ) )
/* Can extend this slot in the lower direction */
Yeartbl[yearX].y_first = fyear;
if ( ( Yeartbl[yearX].y_last < lyear ) &&
( Yeartbl[yearX].y_last >= fyear ) )
/* Can extent this slot in the upper direction */
Yeartbl[yearX].y_first = lyear;
if ( ( Yeartbl[yearX].y_first <= fyear ) &&
( Yeartbl[yearX].y_last >= lyear ) )
/* Slot covers the range; look no further. */
break;
}
/* Expand the table if necessary */
if ( yearX == YearC ) {
if ( YearC == YearS ) {
YearS += 5;
Yeartbl = erealloc( "event_year", "year table",
(char *)Yeartbl, YearS * sizeof(YEARSPEC) );
}
/* Find the slot for the new range */
for( yearX = YearC; yearX > 0; --yearX ) {
if ( fyear > Yeartbl[yearX-1].y_last )
break;
Yeartbl[yearX].y_first = Yeartbl[yearX-1].y_first;
Yeartbl[yearX].y_last = Yeartbl[yearX-1].y_last;
}
Yeartbl[yearX].y_first = fyear;
Yeartbl[yearX].y_last = lyear;
++YearC;
}
/* Combine adjacent and overlapping year entries */
for( yearX = 0; yearX < YearC-1; ++yearX ) {
if ( Yeartbl[yearX].y_last >= ( Yeartbl[yearX+1].y_first -1 ) ) {
/* Combine these two */
Yeartbl[yearX].y_last = Yeartbl[yearX+1].y_last;
--YearC;
for( sX = yearX+1; sX < YearC-1; ++sX ) {
Yeartbl[sX].y_first = Yeartbl[sX+1].y_first;
Yeartbl[sX].y_last = Yeartbl[sX+1].y_last;
}
--yearX;
}
}
}
/*
*//* pack_xxx( bufPP, bufLP, val )
Packing routines. Each routine puts some information into
a buffer being packed. Calling is :
Accepts :
bufPP Ptr to buffer pointer variable
bufLP Ptr to buffer length variable
val Value to insert
Returns :
*bufPP updated
*bufLP updated
Notes :
Error return is taken if there isn't enough buffer space.
Specific routines are:
pack_byte Insert a byte
pack_long Insert a LONG
pack_string Insert a string
pack_tag Insert a tag
pack_word Insert a WORD
*/
static void
pack_byte( char **bufPP, int *bufLP, BYTE val ) {
if ( *bufLP < 1 )
error( EC_NOTOK, "pack: not enough room to pack event." );
--(*bufLP);
*(*bufPP)++ = val;
}
static void
pack_long( char **bufPP, int *bufLP, ULONG val ) {
pack_byte( bufPP, bufLP, (BYTE) ( val >> 24 ) & 0xff );
pack_byte( bufPP, bufLP, (BYTE) ( val >> 16 ) & 0xff );
pack_byte( bufPP, bufLP, (BYTE) ( val >> 8 ) & 0xff );
pack_byte( bufPP, bufLP, (BYTE) val & 0xff );
}
static void
pack_string( char **bufPP, int *bufLP, char *strP ) {
do
pack_byte( bufPP, bufLP, *strP );
while ( *strP++ != NUL );
}
static void
pack_tag( char **bufPP, int *bufLP, int tag ) {
pack_byte( bufPP, bufLP, (BYTE)tag );
/* If any last tag, update the offset. */
if ( TagLP != NULL )
*TagLP = (UBYTE) ((*bufPP) - TagLP);
/* Remember this offset position */
TagLP = *bufPP;
/* Create a hole for the offset */
pack_byte( bufPP, bufLP, 0 );
}
static void
pack_word( char **bufPP, int *bufLP, UWORD val ) {
pack_byte( bufPP, bufLP, (BYTE) ( val >> 8 ) & 0xff );
pack_byte( bufPP, bufLP, (BYTE) val & 0xff );
}
/*
*//* unpack_xxx( bufPP )
Unpacking routines. Each routine extracts some information
from a buffer from which an event is being unpacked. Calling is:
Accepts :
bufPP Ptr to buffer pointer variable
Returns :
< value > The thing retrieved
*bufPP updated
Specific routines are:
unpack_byte Retrieve an unsigned byte
unpack_word Retrieve an unsigned word
unpack_long Retrieve an unsigned long
*/
static UBYTE
unpack_byte( char **bufPP ) {
return( (UBYTE)( *(*bufPP)++ ) );
}
static UWORD
unpack_word( char **bufPP ) {
UBYTE b1, b2;
b1 = (UBYTE) ( *(*bufPP)++ );
b2 = (UBYTE) ( *(*bufPP)++ );
return( ( b1 << 8 ) | b2 );
}
static ULONG
unpack_long( char **bufPP ) {
UBYTE b1, b2, b3, b4;
b1 = (UBYTE) ( *(*bufPP)++ );
b2 = (UBYTE) ( *(*bufPP)++ );
b3 = (UBYTE) ( *(*bufPP)++ );
b4 = (UBYTE) ( *(*bufPP)++ );
return( ( (ULONG)b1 << 24 ) |
( (ULONG)b2 << 16 ) |
( (ULONG)b3 << 8 ) |
(ULONG)b4
);
}