home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / TIMEXSRC.ZIP / EVPACK.C < prev    next >
C/C++ Source or Header  |  1990-03-29  |  18KB  |  696 lines

  1. /* evpack.c -- Event packing and unpacking
  2.  
  3.     February 1990    Mark E. Mallett, Personal Workstation Magazine
  4.  
  5. This module contains routines to pack and unpack event data for purposes
  6. of interprocess communication, and to construct an event struct from the
  7. pieces that make up the event.  The routines in this module can be used
  8. by the timex background agent (TIMEXBA) or by any client that wants to
  9. communicate to TIMEXBA.
  10.  
  11. Included are the following routines:
  12.  
  13.         event_action    Specify event action
  14.         event_acttype   Specify event action type
  15.         event_clear     Clear the current event information
  16.         event_dayofmon  Add day-of-month to event definition
  17.         event_dayofwk   Add day-of-week to event definition
  18.         event_hour      Add hour to event definition
  19.         event_make      Make an event struct from current definition
  20.         event_min       Add minute to event definition
  21.         event_month     Add month(s) to an event definition
  22.         event_name      Specify the name of the event
  23.         event_pack      Pack an event into a message buffer
  24.         event_pri       Specify event priority
  25.         event_year      Add year(s) to event definition
  26.         event_unpack    Unpack an event from a message buffer
  27.  
  28. The routines in this module require the existence of various routines
  29. in the application.  The routines are those for which prototypes are
  30. specified in the file "timex.h"; look further for more details.
  31.  
  32. Note: in regard to event packing and unpacking, the event is stored in
  33. a buffer in a tagged byte-string format.  Each item begins with an
  34. identifying tag, which is followed by the bytes that compose that
  35. event value.  This allows for future expansion of the data while still
  36. allowing for old packing formats to be used (i.e., missing tags can
  37. be defaulted); it also ignores any byte-ordering considerations.
  38.  
  39. */
  40.  
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include <memory.h>
  44. #include <os2.h>
  45.  
  46. #include "timex.h"
  47. #include "evpack.h"
  48.  
  49.  
  50. /* Local definitions */
  51.  
  52. #ifndef NUL
  53. #define NUL     '\0'
  54. #endif  /* NUL */
  55.  
  56. /* External data referenced */
  57.  
  58.  
  59. /* External routines used */
  60.  
  61.  
  62. /* Local data publicly available */
  63.  
  64.  
  65. /* Local routines and forward declarations */
  66.  
  67. static  void    pack_byte( char **bufPP, int *bufLP, BYTE val );
  68. static  void    pack_long( char **bufPP, int *bufLP, ULONG val );
  69. static  void    pack_string( char **bufPP, int *bufLP, char *strP );
  70. static  void    pack_tag( char **bufPP, int *bufLP, int tag );
  71. static  void    pack_word( char **bufPP, int *bufLP, UWORD val );
  72.  
  73. static  UBYTE   unpack_byte( char **bufPP );
  74. static  ULONG   unpack_long( char **bufPP );
  75. static  UWORD   unpack_word( char **bufPP );
  76.  
  77.  
  78. /* Private data */
  79.  
  80. static  char    Action[100];            /* Action spec */
  81. static  char    Name[100];              /* Event name */
  82. static  UBYTE   *TagLP;                 /* Ptr to tag length byte */
  83. static  EVENT   Tevent;                 /* Template event */
  84. static  int     YearC;                  /* Number of years */
  85. static  int     YearS;                  /* Size of years table */
  86. static  YEARSPEC *Yeartbl;              /* Years table */
  87.  
  88. /*
  89.  
  90. *//* event_pack( eventP, bufP, bufL )
  91.  
  92.         Pack an event into a buffer.
  93.  
  94. Accepts:
  95.  
  96.         eventP          Ptr to an EVENT struct.
  97.         bufP            Address to pack the event into.
  98.         bufL            Number of bytes available in the buffer.
  99.  
  100. Returns :
  101.  
  102.         < value >       Number of bytes used
  103.  
  104. Notes :
  105.  
  106.         Error return is taken if the pack fails (e.g., for memory
  107.          allocation problem or if the buffer is not large enough).
  108.  
  109.         See the module introduction for notes about the packing format.
  110.  
  111. */
  112.  
  113. int
  114. event_pack(
  115.         EVENT           *eventP,        /* Event to pack */
  116.         char            *bufP,          /* Where to pack it */
  117.         int             bufL            /* Size of the buffer */
  118. ) {
  119.  
  120.         int             i;              /* Scratch */
  121.         int             len;            /* Running length */
  122.  
  123.  
  124.     /* Go through the event and pack it, tag-wize */
  125.     len = bufL;                         /* Get copy of length */
  126.     TagLP = NULL;                       /* No tag length slot */
  127.  
  128.     /* Name */
  129.     pack_tag( &bufP, &len, ETAG_NAME );
  130.     pack_string( &bufP, &len, eventP->ev_nameP );
  131.  
  132.     /* List of years */
  133.     pack_tag( &bufP, &len, ETAG_YEARS );
  134.     pack_word( &bufP, &len, eventP->ev_yearC );
  135.     for( i = 0; i < eventP->ev_yearC; ++i ) {
  136.         pack_word( &bufP, &len, eventP->ev_yearP[i].y_first );
  137.         pack_word( &bufP, &len, eventP->ev_yearP[i].y_last );
  138.     }
  139.  
  140.     /* Months */
  141.     pack_tag( &bufP, &len, ETAG_MONTHS );
  142.     pack_word( &bufP, &len, eventP->ev_months );
  143.  
  144.     /* Day-of stuff */
  145.     pack_tag( &bufP, &len, ETAG_DAYOF );
  146.     pack_byte( &bufP, &len, (BYTE)eventP->ev_dayof );
  147.     pack_long( &bufP, &len, eventP->ev_dayofs );
  148.  
  149.     /* Hours */
  150.     pack_tag( &bufP, &len, ETAG_HOURS );
  151.     pack_long( &bufP, &len, eventP->ev_hours );
  152.  
  153.     /* Minutes */
  154.     pack_tag( &bufP, &len, ETAG_MINS );
  155.     pack_long( &bufP, &len, eventP->ev_mins[0] );
  156.     pack_long( &bufP, &len, eventP->ev_mins[1] );
  157.  
  158.     /* Priority */
  159.     pack_tag( &bufP, &len, ETAG_PRIO );
  160.     pack_byte( &bufP, &len, eventP->ev_priclass );
  161.     pack_byte( &bufP, &len, eventP->ev_prival );
  162.  
  163.     /* Action type */
  164.     pack_tag( &bufP, &len, ETAG_ACTTYPE );
  165.     pack_byte( &bufP, &len, (BYTE)eventP->ev_acttype );
  166.  
  167.     /* Action value */
  168.     pack_tag( &bufP, &len, ETAG_ACTARG );
  169.     pack_string( &bufP, &len, eventP->ev_actargP );
  170.  
  171.     /* End of packing */
  172.     pack_tag( &bufP, &len, ETAG_END );
  173.  
  174.  
  175.     /* Return the number of bytes used */
  176.     return( bufL - len );
  177. }
  178. /*
  179.  
  180. *//* event_unpack( bufP )
  181.  
  182.         Unpack an event.
  183.  
  184. Accepts :
  185.  
  186.         bufP            Address of a buffer containing a packed event.
  187.  
  188. Returns :
  189.  
  190.         < value >       Ptr to an event struct.
  191.  
  192. Notes :
  193.  
  194.         See the module introduction for notes about the packing format.
  195.  
  196.         See the note in event_make() about the construction
  197.         of event memory.
  198.  
  199. */
  200.  
  201. EVENT *
  202. event_unpack(
  203.         char            *bufP,          /* Ptr to packed event */
  204.         int             bufL            /* Bytes in the buffer */
  205. ) {
  206.         int             i;              /* Scratch */
  207.         int             tag;            /* Tag */
  208.         char            *nbufP;         /* Ptr to next tag */
  209.         UWORD           fyear, lyear;   /* First/last years */
  210.  
  211.  
  212.     /* Initialize a new event */
  213.     event_clear();
  214.  
  215.     /* Go through the tagged event data */
  216.     for( tag = -1; ( bufL > 0 ) && ( tag = *bufP ) != ETAG_END;
  217.                  bufP = nbufP ) {
  218.         if ( bufP[1] < 2 )              /* Bad offset? */
  219.             break;
  220.  
  221.         nbufP = bufP + bufP[1];         /* Offset to next tag item */
  222.         bufL -= (nbufP - bufP );        /* Decrement buffer count */
  223.         if ( bufL < 0 )
  224.             break;
  225.  
  226.         bufP += 2;                      /* Skip past tag & length */
  227.  
  228.         switch( tag ) {
  229.             case ETAG_NAME:             /* Event name */
  230.                 event_name( bufP );
  231.                 bufP += strlen( bufP ) +1;
  232.                 break;
  233.  
  234.             case ETAG_YEARS:            /* List of years */
  235.                 i = unpack_word( &bufP );
  236.                 while( i-- > 0 ) {
  237.                     fyear = unpack_word( &bufP );
  238.                     lyear = unpack_word( &bufP );
  239.                     event_year( fyear, lyear );
  240.                 }
  241.                 break;
  242.  
  243.  
  244.             case ETAG_MONTHS:           /* Months mask */
  245.                 Tevent.ev_months = unpack_word( &bufP );
  246.                 break;
  247.  
  248.  
  249.             case ETAG_DAYOF:            /* Day-of info */
  250.                 Tevent.ev_dayof = *bufP++;
  251.                 Tevent.ev_dayofs = unpack_long( &bufP );
  252.                 break;
  253.  
  254.             case ETAG_HOURS:            /* Hours info */
  255.                 Tevent.ev_hours = unpack_long( &bufP );
  256.                 break;
  257.  
  258.             case ETAG_MINS:             /* Minutes info */
  259.                 Tevent.ev_mins[0] = unpack_long( &bufP );
  260.                 Tevent.ev_mins[1] = unpack_long( &bufP );
  261.                 break;
  262.  
  263.             case ETAG_PRIO:             /* Priority info */
  264.                 Tevent.ev_priclass = *bufP++;
  265.                 Tevent.ev_prival = *bufP++;
  266.                 break;
  267.  
  268.             case ETAG_ACTTYPE:          /* Action type */
  269.                 Tevent.ev_acttype = *bufP++;
  270.                 break;
  271.  
  272.             case ETAG_ACTARG:           /* Action arg */
  273.                 event_action( bufP );
  274.                 break;
  275.  
  276.             default:
  277.                 /* Ignore unknown tags. */
  278.                 break;
  279.         }
  280.     }
  281.  
  282.     /* Make event */
  283.     return( event_make() );
  284. }
  285. /*
  286.  
  287. *//* event_action( actP )
  288.  
  289.         Store an action for an event under construction
  290.  
  291. */
  292.  
  293. void
  294. event_action( char *actP ) {
  295.     strcpy( &Action[0], actP );
  296. }
  297. /*
  298.  
  299. *//* event_acttype( atype )
  300.  
  301.         Store an action type for event under construction
  302.  
  303. */
  304.  
  305. void
  306. event_acttype( ACTTYPE atype ) {
  307.     Tevent.ev_acttype = atype;
  308. }
  309. /*
  310.  
  311. *//* event_clear()
  312.  
  313.         Clear the event currently under construction
  314.  
  315. */
  316.  
  317. void
  318. event_clear() {
  319.     Action[0] = NUL;
  320.     Name[0] = NUL;
  321.     YearC = 0;
  322.  
  323.     memset( &Tevent, 0, sizeof(Tevent) );
  324. }
  325. /*
  326.  
  327. *//* event_dayofmon( dom )
  328.  
  329.         Add day-of-month to event under construction
  330.  
  331. Note: day of month is 1-based.
  332.  
  333. */
  334.  
  335. void
  336. event_dayofmon( int dom ) {
  337.     Tevent.ev_dayof = DAYOF_MONTH;
  338.     Tevent.ev_dayofs |= 1L << (dom -1);
  339. }
  340. /*
  341.  
  342. *//* event_dayofwk( dow )
  343.  
  344.         Add day-of-week to event under construction
  345.  
  346. Note: Day-of-week is 0-based
  347.  
  348. */
  349.  
  350. void
  351. event_dayofwk( int dow ) {
  352.     Tevent.ev_dayof = DAYOF_WEEK;
  353.     Tevent.ev_dayofs |= 1L << dow;
  354. }
  355. /*
  356.  
  357. *//* event_hour( hour )
  358.  
  359.         Add an hour to the event under construction
  360.  
  361. */
  362.  
  363. void
  364. event_hour( int hour ) {
  365.     Tevent.ev_hours |= 1L << hour;
  366. }
  367. /*
  368.  
  369. *//* event_make()
  370.  
  371.         Make an event as previously defined via event construction calls
  372.  
  373. Accepts :
  374.  
  375.  
  376. Returns :
  377.  
  378.         < value >       Ptr to an event struct
  379.  
  380. Notes :
  381.  
  382.         The event struct is constructed from a single chunk of memory.
  383.         Even though the struct has pointers which point to data items,
  384.         those data items are allocated, along with the event struct,
  385.         all in one unit.  Thus to free an event struct, it is not
  386.         necessary to chase down and free all the memory pointed to.
  387.  
  388. */
  389.  
  390. EVENT *
  391. event_make() {
  392.  
  393.         int             evsize;         /* Size of the event */
  394.         char            *strP;          /* Ptr to string in event block */
  395.         EVENT           *eventP;        /* PTr to new event made */
  396.  
  397.     /* Calculate size required */
  398.     evsize = sizeof( EVENT );
  399.     evsize += YearC * sizeof(YEARSPEC);
  400.     evsize += strlen( &Name[0] ) +1;
  401.     evsize += strlen( &Action[0] ) +1;
  402.  
  403.     eventP = (EVENT *)emalloc( "event_make", "event", evsize );
  404.     memcpy( eventP, &Tevent, sizeof( EVENT ) );
  405.  
  406.     strP = (char *)&eventP[1];
  407.  
  408.     eventP->ev_yearC = YearC;
  409.     eventP->ev_yearP = (YEARSPEC *)strP;
  410.     memcpy( strP, Yeartbl, YearC * sizeof(YEARSPEC) );
  411.     strP += YearC * sizeof(YEARSPEC);
  412.  
  413.     eventP->ev_nameP = strP;
  414.     strcpy( strP, &Name[0] );
  415.     strP += strlen( strP ) +1;
  416.  
  417.     eventP->ev_actargP = strP;
  418.     strcpy( strP, &Action[0] );
  419.     strP += strlen( strP ) +1;
  420.  
  421.     return( eventP );
  422. }
  423. /*
  424.  
  425. *//* event_min( min )
  426.  
  427.         Add a minute to the event under construction
  428.  
  429. */
  430.  
  431. void
  432. event_min( int min ) {
  433.  
  434.         int             minX;           /* Minute index */
  435.         int             minoffs;        /* Minute offset */
  436.  
  437.     /* Get minute's index and bit number */
  438.     minX = min/32;
  439.     minoffs = min%32;
  440.  
  441.     /* Update the bitmask */
  442.     Tevent.ev_mins[minX] |= 1L << minoffs;
  443. }
  444. /*
  445.  
  446. *//* event_month( mon )
  447.  
  448.         Add a month to the event under construction
  449.  
  450. Note: day of month is 0-based.
  451.  
  452. */
  453.  
  454. void
  455. event_month( int mon ) {
  456.  
  457.     Tevent.ev_months |= 1L << mon;
  458. }
  459. /*
  460.  
  461. *//* event_name( nameP )
  462.  
  463.         Set the name for the event under construction
  464.  
  465. */
  466.  
  467. void
  468. event_name( char *nameP ) {
  469.  
  470.     strcpy( &Name[0], nameP );
  471. }
  472. /*
  473.  
  474. *//* event_pri( class, value )
  475.  
  476.         Set the priority for the event under construction
  477.  
  478. */
  479.  
  480. void
  481. event_pri( int class, int value ) {
  482.  
  483.     Tevent.ev_priclass = (BYTE)class;
  484.     Tevent.ev_prival = (BYTE)value;
  485. }
  486. /*
  487.  
  488. *//* event_year( fyear, lyear )
  489.  
  490.         Set a range of years for the event under construction
  491.  
  492. */
  493.  
  494. void
  495. event_year( int fyear, int lyear ) {
  496.  
  497.         int             yearX;          /* Index into years table */
  498.         int             sX;             /* Swap index */
  499.  
  500.     /* Look through the years table to see if we can use a slot there */
  501.     for( yearX = 0; yearX < YearC; ++yearX ) {
  502.         if ( ( Yeartbl[yearX].y_first > fyear ) &&
  503.              ( Yeartbl[yearX].y_first <= lyear ) )
  504.             /* Can extend this slot in the lower direction */
  505.             Yeartbl[yearX].y_first = fyear;
  506.  
  507.         if ( ( Yeartbl[yearX].y_last < lyear ) &&
  508.              ( Yeartbl[yearX].y_last >= fyear ) )
  509.             /* Can extent this slot in the upper direction */
  510.             Yeartbl[yearX].y_first = lyear;
  511.  
  512.         if ( ( Yeartbl[yearX].y_first <= fyear ) &&
  513.              ( Yeartbl[yearX].y_last >= lyear ) )
  514.             /* Slot covers the range; look no further. */
  515.             break;
  516.     }
  517.  
  518.     /* Expand the table if necessary */
  519.     if ( yearX == YearC ) {
  520.         if ( YearC == YearS ) {
  521.             YearS += 5;
  522.             Yeartbl = erealloc( "event_year", "year table",
  523.                                 (char *)Yeartbl, YearS * sizeof(YEARSPEC) );
  524.         }
  525.  
  526.         /* Find the slot for the new range */
  527.         for( yearX = YearC; yearX > 0; --yearX ) {
  528.             if ( fyear > Yeartbl[yearX-1].y_last )
  529.                 break;
  530.             Yeartbl[yearX].y_first = Yeartbl[yearX-1].y_first;
  531.             Yeartbl[yearX].y_last = Yeartbl[yearX-1].y_last;
  532.         }
  533.         Yeartbl[yearX].y_first = fyear;
  534.         Yeartbl[yearX].y_last = lyear;
  535.         ++YearC;
  536.     }
  537.  
  538.     /* Combine adjacent and overlapping year entries */
  539.     for( yearX = 0; yearX < YearC-1; ++yearX ) {
  540.         if ( Yeartbl[yearX].y_last >= ( Yeartbl[yearX+1].y_first -1 ) ) {
  541.             /* Combine these two */
  542.             Yeartbl[yearX].y_last = Yeartbl[yearX+1].y_last;
  543.             --YearC;
  544.             for( sX = yearX+1; sX < YearC-1; ++sX ) {
  545.                 Yeartbl[sX].y_first = Yeartbl[sX+1].y_first;
  546.                 Yeartbl[sX].y_last = Yeartbl[sX+1].y_last;
  547.             }
  548.             --yearX;
  549.         }
  550.     }
  551. }
  552.  
  553.  
  554. /*
  555.  
  556. *//* pack_xxx( bufPP, bufLP, val )
  557.  
  558.         Packing routines.  Each routine puts some information into
  559. a buffer being packed.  Calling is :
  560.  
  561. Accepts :
  562.  
  563.         bufPP           Ptr to buffer pointer variable
  564.         bufLP           Ptr to buffer length variable
  565.         val             Value to insert
  566.  
  567. Returns :
  568.  
  569.         *bufPP          updated
  570.         *bufLP          updated
  571.  
  572. Notes :
  573.  
  574.         Error return is taken if there isn't enough buffer space.
  575.  
  576. Specific routines are:
  577.  
  578.         pack_byte       Insert a byte
  579.         pack_long       Insert a LONG
  580.         pack_string     Insert a string
  581.         pack_tag        Insert a tag
  582.         pack_word       Insert a WORD
  583.  
  584. */
  585.  
  586. static void
  587. pack_byte( char **bufPP, int *bufLP, BYTE val ) {
  588.     if ( *bufLP < 1 )
  589.         error( EC_NOTOK, "pack: not enough room to pack event." );
  590.  
  591.     --(*bufLP);
  592.     *(*bufPP)++ = val;
  593. }
  594.  
  595. static void
  596. pack_long( char **bufPP, int *bufLP, ULONG val ) {
  597.     pack_byte( bufPP, bufLP, (BYTE) ( val >> 24 ) & 0xff );
  598.     pack_byte( bufPP, bufLP, (BYTE) ( val >> 16 ) & 0xff );
  599.     pack_byte( bufPP, bufLP, (BYTE) ( val >> 8 ) & 0xff );
  600.     pack_byte( bufPP, bufLP, (BYTE) val & 0xff );
  601. }
  602.  
  603. static void
  604. pack_string( char **bufPP, int *bufLP, char *strP ) {
  605.     do
  606.         pack_byte( bufPP, bufLP, *strP );
  607.     while ( *strP++ != NUL );
  608. }
  609.  
  610. static void
  611. pack_tag( char **bufPP, int *bufLP, int tag ) {
  612.     pack_byte( bufPP, bufLP, (BYTE)tag );
  613.  
  614.     /* If any last tag, update the offset. */
  615.     if ( TagLP != NULL )
  616.         *TagLP = (UBYTE) ((*bufPP) - TagLP);
  617.  
  618.     /* Remember this offset position */
  619.     TagLP = *bufPP;
  620.  
  621.     /* Create a hole for the offset */
  622.     pack_byte( bufPP, bufLP, 0 );
  623. }
  624.  
  625.  
  626.  
  627. static void
  628. pack_word( char **bufPP, int *bufLP, UWORD val ) {
  629.     pack_byte( bufPP, bufLP, (BYTE) ( val >> 8 ) & 0xff );
  630.     pack_byte( bufPP, bufLP, (BYTE) val & 0xff );
  631. }
  632.  
  633.  
  634.  
  635. /*
  636.  
  637. *//* unpack_xxx( bufPP )
  638.  
  639.         Unpacking routines.  Each routine extracts some information
  640. from a buffer from which an event is being unpacked.  Calling is:
  641.  
  642.  
  643. Accepts :
  644.  
  645.         bufPP           Ptr to buffer pointer variable
  646.  
  647. Returns :
  648.  
  649.         < value >       The thing retrieved
  650.         *bufPP          updated
  651.  
  652. Specific routines are:
  653.  
  654.         unpack_byte     Retrieve an unsigned byte
  655.         unpack_word     Retrieve an unsigned word
  656.         unpack_long     Retrieve an unsigned long
  657.  
  658. */
  659.  
  660. static UBYTE
  661. unpack_byte( char **bufPP ) {
  662.  
  663.     return( (UBYTE)( *(*bufPP)++ ) );
  664. }
  665.  
  666.  
  667. static UWORD
  668. unpack_word( char **bufPP ) {
  669.  
  670.         UBYTE   b1, b2;
  671.  
  672.     b1 = (UBYTE) ( *(*bufPP)++ );
  673.     b2 = (UBYTE) ( *(*bufPP)++ );
  674.  
  675.     return( ( b1 << 8 ) | b2 );
  676. }
  677.  
  678.  
  679. static ULONG
  680. unpack_long( char **bufPP ) {
  681.  
  682.         UBYTE   b1, b2, b3, b4;
  683.  
  684.     b1 = (UBYTE) ( *(*bufPP)++ );
  685.     b2 = (UBYTE) ( *(*bufPP)++ );
  686.     b3 = (UBYTE) ( *(*bufPP)++ );
  687.     b4 = (UBYTE) ( *(*bufPP)++ );
  688.  
  689.     return( ( (ULONG)b1 << 24 ) |
  690.             ( (ULONG)b2 << 16 ) |
  691.             ( (ULONG)b3 << 8 )  |
  692.               (ULONG)b4
  693.           );
  694. }
  695.  
  696.