363 lines
9.1 KiB
C
363 lines
9.1 KiB
C
/************************************************************************
|
|
* Copyright (C) 2000 Thomas Schulz *
|
|
* */
|
|
static char rcsid[] =
|
|
"$Id: databin.c,v 1.35 2001/03/02 02:09:59 tsch Rel $"; /*
|
|
* *
|
|
* IC35 synchronize data import/export: binary IC35 record format *
|
|
* *
|
|
*************************************************************************
|
|
* *
|
|
* ??? is "fixme" mark: sections of code needing fixes *
|
|
* *
|
|
************************************************************************/
|
|
|
|
#include <stdio.h> /* fprintf(), .. */
|
|
#include <string.h> /* strcpy(), .. */
|
|
#include <ctype.h> /* isprint(), .. */
|
|
#include <unistd.h> /* access() */
|
|
#include <sys/types.h> /* size_t, .. */
|
|
#include <time.h> /* struct tm, time() .. */
|
|
|
|
#include "vcc.h" /* VObject, .. */
|
|
#include "util.h" /* ERR, uchar, .. */
|
|
#include "ic35frec.h" /* IC35 record fields.. */
|
|
#include "dataio.h"
|
|
NOTUSED(rcsid);
|
|
|
|
|
|
#pragma pack(1)
|
|
struct binrec { /* IC35 binary record data */
|
|
size_t len; /* length of this record */
|
|
ulong rid; /* record id on IC35 */
|
|
uchar chg; /* changeflag on IC35 */
|
|
}; /* flengths,fdata (dyn.length) */
|
|
#pragma pack()
|
|
struct binelmt { /* IC35 binrec list element */
|
|
struct binelmt * next; /* next element in list */
|
|
IC35REC * rec; /* IC35 record */
|
|
};
|
|
|
|
static struct binelmt * binlist;
|
|
static struct binelmt * binget;
|
|
|
|
/* internal: write IC35 binary record to file
|
|
* ------------------------------------------
|
|
*/
|
|
static int
|
|
_bin_writerec( FILE * outfp, IC35REC * rec )
|
|
{
|
|
uchar * recdata;
|
|
size_t reclen;
|
|
struct binrec brec;
|
|
|
|
get_ic35recdata( rec, &recdata, &reclen );
|
|
brec.len = sizeof(brec) + reclen;
|
|
brec.rid = ic35recid( rec );
|
|
brec.chg = ic35recchg( rec );
|
|
if ( fwrite( &brec, sizeof(brec), 1, outfp ) != 1
|
|
|| fwrite( recdata, reclen, 1, outfp ) != 1 )
|
|
return ERR;
|
|
return OK;
|
|
}
|
|
/* internal: read IC35 binary record from file
|
|
* -------------------------------------------
|
|
*/
|
|
static int
|
|
_bin_readrec( FILE * infp, IC35REC * rec )
|
|
{
|
|
struct binrec brec;
|
|
uchar * rbuff;
|
|
size_t rlen, i;
|
|
|
|
if ( fread( &brec, sizeof(brec), 1, infp ) != 1 )
|
|
return -1;
|
|
set_ic35recid( rec, brec.rid );
|
|
set_ic35recchg( rec, brec.chg );
|
|
rlen = brec.len - sizeof(brec);
|
|
if ( rlen > 0
|
|
&& (rbuff = malloc( rlen )) != NULL ) {
|
|
if ( fread( rbuff, rlen, 1, infp ) == 1 )
|
|
set_ic35recdata( rec, rbuff, rlen );
|
|
else
|
|
rlen = ERR;
|
|
free( rbuff );
|
|
} else {
|
|
for ( i = 0; i < rlen; ++i )
|
|
(void)fgetc( infp );
|
|
}
|
|
return rlen;
|
|
}
|
|
|
|
/* open IC35 binary record file
|
|
* ----------------------------
|
|
* read input file into internal record list
|
|
*/
|
|
static char * iomode;
|
|
static char * addr_fname;
|
|
|
|
static int
|
|
bin_open( char * mode, char * addrfname, char * vcalfname, char * memofname )
|
|
{
|
|
FILE * infp;
|
|
IC35REC * ic35rec;
|
|
struct binelmt * newelmt;
|
|
struct binelmt * pelmt;
|
|
|
|
LPRINTF(( L_INFO, "bin_open(%s,%s,%s)",
|
|
addrfname ? addrfname : "NULL",
|
|
vcalfname ? vcalfname : "NULL",
|
|
memofname ? memofname : "NULL" ));
|
|
iomode = mode; /* note input/output for close */
|
|
addr_fname = addrfname; /* note filename for close */
|
|
binlist = binget = NULL; /* reset record list */
|
|
if ( !( addrfname && *addrfname )
|
|
|| iomode[0] != 'r' ) /* open for output only */
|
|
return OK;
|
|
if ( strcmp( addrfname, "-" ) == 0 )
|
|
infp = stdin;
|
|
else if ( (infp = fopen( addrfname, "r" )) == NULL )
|
|
return access( addrfname, F_OK ) == 0 ? ERR : OK;
|
|
LPRINTF(( L_INFO, "bin_open: read %s ..", addrfname ));
|
|
pelmt = NULL;
|
|
for ( ; ; ) {
|
|
if ( (ic35rec = new_ic35rec()) == NULL
|
|
|| _bin_readrec( infp, ic35rec ) < 0 )
|
|
break;
|
|
if ( (newelmt = malloc( sizeof(*newelmt) )) != NULL ) {
|
|
newelmt->next = NULL;
|
|
newelmt->rec = ic35rec;
|
|
if ( pelmt == NULL )
|
|
binlist = pelmt = newelmt;
|
|
else
|
|
pelmt = pelmt->next = newelmt;
|
|
}
|
|
}
|
|
if ( infp != stdin )
|
|
fclose( infp );
|
|
del_ic35rec( ic35rec );
|
|
LPRINTF(( L_INFO, "bin_open: read %s done", addrfname ));
|
|
return OK;
|
|
}
|
|
/* close IC35 binary record file
|
|
* -----------------------------
|
|
* write internal record list to output file
|
|
* if closing input file only release record list
|
|
*/
|
|
static void
|
|
bin_close( void )
|
|
{
|
|
FILE * outfp = NULL;
|
|
struct binelmt * delelmt;
|
|
|
|
if ( addr_fname && *addr_fname
|
|
&& (iomode[0] == 'w' || iomode[1] == '+')
|
|
&& (outfp = backup_and_openwr( addr_fname )) == NULL )
|
|
return;
|
|
LPRINTF(( L_INFO, "bin_close: %s",
|
|
outfp && binlist ? "write .." : "no output" ));
|
|
LPRINTF(( L_INFO, "bin_close: write %s ..", addr_fname ));
|
|
while ( binlist ) {
|
|
if ( outfp )
|
|
_bin_writerec( outfp, binlist->rec );
|
|
delelmt = binlist;
|
|
binlist = binlist->next;
|
|
del_ic35rec( delelmt->rec );
|
|
free( delelmt );
|
|
}
|
|
binget = NULL; /* sanity for bin_getrec() */
|
|
if ( outfp && outfp != stdout )
|
|
fclose( outfp );
|
|
LPRINTF(( L_INFO, "bin_close: done" ));
|
|
}
|
|
|
|
/* rewind list of binary records
|
|
* -----------------------------
|
|
*/
|
|
static void
|
|
bin_rewind( void )
|
|
{
|
|
binget = NULL;
|
|
}
|
|
|
|
/* get binary record for fileid
|
|
* ----------------------------
|
|
*/
|
|
static IC35REC *
|
|
bin_getrec( int fileid )
|
|
{
|
|
if ( binget == NULL )
|
|
binget = binlist;
|
|
else
|
|
binget = binget->next;
|
|
while ( binget ) {
|
|
if ( fileid == FILE_ANY /* next record with any fileid */
|
|
|| FileId( ic35recid( binget->rec ) ) == fileid )
|
|
return binget->rec;
|
|
binget = binget->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/* get binary record by record-ID
|
|
* ------------------------------
|
|
*/
|
|
static IC35REC *
|
|
bin_getrec_byID( ulong recid )
|
|
{
|
|
struct binelmt * pelmt;
|
|
|
|
if ( RecId( recid ) == 0 )
|
|
return NULL;
|
|
for ( pelmt = binlist; pelmt; pelmt = pelmt->next )
|
|
if ( ic35recid( pelmt->rec ) == recid )
|
|
return pelmt->rec;
|
|
return NULL;
|
|
}
|
|
|
|
/* compare IC35 record with binary record
|
|
* --------------------------------------
|
|
*/
|
|
static int
|
|
bin_cmpic35rec( IC35REC * ic35rec, IC35REC * binrec )
|
|
{
|
|
return cmp_ic35rec( ic35rec, binrec );
|
|
}
|
|
|
|
/* update IC35 record with binary record
|
|
* -------------------------------------
|
|
*/
|
|
static IC35REC *
|
|
bin_updic35rec( IC35REC * ic35rec, IC35REC * rec )
|
|
{
|
|
uchar * data;
|
|
size_t dlen;
|
|
|
|
if ( ic35rec == NULL
|
|
&& (ic35rec = new_ic35rec()) == NULL )
|
|
return NULL;
|
|
set_ic35recid( ic35rec, ic35recid( rec ) );
|
|
get_ic35recdata( rec, &data, &dlen );
|
|
set_ic35recdata( ic35rec, data, dlen );
|
|
return ic35rec;
|
|
}
|
|
|
|
/* put IC35 record to (new) binary record
|
|
* --------------------------------------
|
|
*/
|
|
static IC35REC *
|
|
bin_putic35rec( IC35REC * ic35rec )
|
|
{
|
|
struct binelmt * pelmt;
|
|
struct binelmt * newelmt;
|
|
struct binelmt * lastinfile;
|
|
struct binelmt * last;
|
|
IC35REC * rec;
|
|
uchar * data;
|
|
size_t dlen;
|
|
|
|
if ( (rec = bin_getrec_byID( ic35recid( ic35rec ) )) == NULL ) {
|
|
if ( (newelmt = malloc( sizeof(*newelmt) )) == NULL
|
|
|| (rec = newelmt->rec = new_ic35rec()) == NULL ) {
|
|
free( newelmt );
|
|
return NULL;
|
|
}
|
|
last = lastinfile = NULL;
|
|
for ( pelmt = binlist; pelmt; pelmt = pelmt->next ) {
|
|
if ( FileId( ic35recid( pelmt->rec ) )
|
|
== FileId( ic35recid( ic35rec ) ) )
|
|
lastinfile = pelmt;
|
|
last = pelmt;
|
|
}
|
|
if ( lastinfile ) last = lastinfile;
|
|
if ( last == NULL ) {
|
|
binlist = newelmt;
|
|
newelmt->next = NULL;
|
|
} else {
|
|
newelmt->next = last->next;
|
|
last->next = newelmt;
|
|
}
|
|
}
|
|
set_ic35recid( rec, ic35recid( ic35rec ) );
|
|
get_ic35recdata( ic35rec, &data, &dlen );
|
|
set_ic35recdata( rec, data, dlen );
|
|
return rec;
|
|
}
|
|
|
|
/* delete binary record
|
|
* --------------------
|
|
*/
|
|
static void
|
|
bin_delrec( IC35REC * delrec )
|
|
{
|
|
struct binelmt ** pnext;
|
|
struct binelmt * pelmt;
|
|
|
|
for ( pnext = &binlist, pelmt = *pnext; pelmt != NULL;
|
|
pnext = &pelmt->next, pelmt = *pnext )
|
|
if ( pelmt->rec == delrec ) {
|
|
*pnext = pelmt->next;
|
|
del_ic35rec( pelmt->rec );
|
|
free( pelmt );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* get,set binary record-ID
|
|
* ------------------------
|
|
*/
|
|
static ulong
|
|
bin_recid( IC35REC * rec )
|
|
{
|
|
return ic35recid( rec );
|
|
}
|
|
static void
|
|
bin_set_recid( IC35REC * rec, ulong recid )
|
|
{
|
|
set_ic35recid( rec, recid );
|
|
}
|
|
|
|
/* get,set binary record status
|
|
* ----------------------------
|
|
*/
|
|
static int
|
|
bin_recstat( IC35REC * rec )
|
|
{
|
|
switch ( ic35recchg( rec ) ) {
|
|
case IC35_CLEAN: return PIM_CLEAN;
|
|
case IC35_NEW:
|
|
case IC35_MOD: return PIM_DIRTY;
|
|
case IC35_DEL: return PIM_DEL;
|
|
}
|
|
return PIM_DIRTY;
|
|
}
|
|
static void
|
|
bin_set_recstat( IC35REC * rec, int stat )
|
|
{
|
|
switch ( stat ) {
|
|
case PIM_CLEAN: set_ic35recchg( rec, IC35_CLEAN ); break;
|
|
case PIM_DIRTY: set_ic35recchg( rec, IC35_NEW ); break;
|
|
case PIM_DEL: set_ic35recchg( rec, IC35_DEL ); break;
|
|
}
|
|
}
|
|
|
|
|
|
/* binary format operations
|
|
* ------------------------
|
|
*/
|
|
struct pim_oper bin_oper = {
|
|
bin_open,
|
|
bin_close,
|
|
bin_rewind,
|
|
(void*(*)(int))bin_getrec,
|
|
(void*(*)(ulong))bin_getrec_byID,
|
|
(int(*)(IC35REC*,void*))bin_cmpic35rec,
|
|
(IC35REC*(*)(IC35REC*,void*))bin_updic35rec,
|
|
(void*(*)(IC35REC*))bin_putic35rec,
|
|
(void(*)(void*))bin_delrec,
|
|
(ulong(*)(void*))bin_recid,
|
|
(void(*)(void*,ulong))bin_set_recid,
|
|
(int(*)(void*))bin_recstat,
|
|
(void(*)(void*,int))bin_set_recstat,
|
|
};
|
|
|