ic35link/src/ic35frec.c

385 lines
9.5 KiB
C

/************************************************************************
* Copyright (C) 2000 Thomas Schulz *
* */
static char rcsid[] =
"$Id: ic35frec.c,v 1.8 2001/03/02 02:09:59 tsch Rel $"; /*
* *
* IC35 record access *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
************************************************************************/
#include <stdlib.h> /* calloc(), .. */
#include <string.h> /* strcmp(), .. */
#include "util.h" /* ERR,OK, uchar, .. */
#include "ic35frec.h"
NOTUSED(rcsid);
struct ic35file { /* IC35 file description */
int id; /* id on IC35 */
int nfld; /* number of fields in record */
char * name; /* filename */
};
struct ic35rec { /* internal IC35 record for field access */
ulong id; /* record-id on IC35: recid[3],fileid[1]*/
uchar chg; /* change-flag on IC35 */
size_t dlen; /* length of IC35 record data buffer */
uchar * data; /* record data buffer: flens, fdata */
int nflds; /* number of fields in record */
struct {
size_t len; /* length of field */
uchar * ptr; /* pointer to field data */
} flds[MAXFLDS]; /* vector of record fields */
size_t fblen; /* length of field data buffer */
uchar * fbuff; /* field data buffer */
};
/* lookup IC35 fileid
* ------------------
*/
static struct ic35file ic35files[] = {
{ FILEADDR, 21, "Addresses" },
{ FILEMEMO, 4, "Memo" },
{ FILESCHED, 10, "Schedule" },
{ FILETODO, 8, "To Do List" },
{ 0, 0, NULL }
};
static struct ic35file *
_ic35fdesc( int fileid )
{
struct ic35file * pfile;
for ( pfile = ic35files; pfile->name != NULL; ++pfile )
if ( pfile->id == fileid )
return pfile;
return NULL;
}
/* get number of record fields acc.to file-id
* ------------------------------------------
*/
int
ic35fnflds( int fileid )
{
struct ic35file * pfile;
pfile = _ic35fdesc( fileid );
if ( pfile == NULL ) /* unknown file id */
return 0;
return pfile->nfld;
}
static int
_nrecflds( int fldid )
{
int nflds;
if ( (nflds = ic35fnflds( FldFile(fldid) )) == 0 /* unkwown file id */
|| FldIdx(fldid) >= nflds /* bad field index */
|| FldIdx(fldid) >= alenof(((IC35REC*)0)->flds) )
return 0;
return nflds;
}
/* get filename acc.to file-id
* ---------------------------
*/
char *
ic35fname( int fileid )
{
struct ic35file * pfile;
pfile = _ic35fdesc( fileid );
if ( pfile == NULL ) /* unknown file id */
return NULL;
return pfile->name;
}
/* constructur: create new IC35 record
* -----------------------------------
*/
IC35REC *
new_ic35rec( void )
{
return calloc( 1, sizeof(IC35REC) );
}
/* destructor: delete IC35 record
* ------------------------------
*/
static void
_del_ic35recbuffs( IC35REC * rec )
{
int fi;
for ( fi = 0; fi < alenof(rec->flds); ++fi ) {
if ( !( rec->fbuff <= rec->flds[fi].ptr
&& rec->flds[fi].ptr < rec->fbuff+rec->fblen ) )
free( rec->flds[fi].ptr );
rec->flds[fi].ptr = NULL;
rec->flds[fi].len = 0;
}
rec->nflds = 0;
if ( rec->fbuff != NULL ) {
free( rec->fbuff );
rec->fbuff = NULL;
rec->fblen = 0;
}
if ( rec->data != NULL ) {
free( rec->data );
rec->data = NULL;
rec->dlen = 0;
}
}
void
del_ic35rec( IC35REC * rec )
{
_del_ic35recbuffs( rec );
free( rec );
}
/* set,get special field in IC35 record
* ------------------------------------
*/
void
set_ic35recid( IC35REC * rec, ulong recid )
{
int nflds;
rec->id = recid;
if ( (nflds = ic35fnflds( FileId(recid) )) != 0 )
rec->nflds = nflds;
}
ulong
ic35recid( IC35REC * rec )
{
return rec->id;
}
void
set_ic35recchg( IC35REC * rec, uchar chgflag )
{
rec->chg = chgflag;
}
uchar
ic35recchg( IC35REC * rec )
{
return rec->chg;
}
/* set,get IC35 record raw data
* ----------------------------
*/
void
set_ic35recdata( IC35REC * rec, uchar * data, size_t dlen )
{
uchar * fptr;
uchar * fbptr;
int fi;
size_t nflds, flensum;
_del_ic35recbuffs( rec );
if ( data == NULL || dlen == 0 )
return;
if ( (rec->data = malloc( dlen )) == NULL )
return;
memcpy( rec->data, data, rec->dlen = dlen );
memset( rec->flds, 0, sizeof(rec->flds) );
for ( nflds = flensum = 0; nflds < alenof(rec->flds); ++nflds ) {
flensum += rec->data[nflds] + 1;
if ( flensum > dlen )
break;
}
if ( (rec->fbuff = malloc( dlen )) == NULL )
return;
rec->fblen = dlen;
rec->nflds = nflds;
fbptr = rec->fbuff;
fptr = rec->data + nflds;
for ( fi = 0; fi < nflds; ++fi ) {
rec->flds[fi].len = rec->data[fi];
rec->flds[fi].ptr = fbptr;
memcpy( rec->flds[fi].ptr, fptr, rec->flds[fi].len );
fbptr += rec->flds[fi].len;
*fbptr++ = '\0'; /* append end-of-string */
fptr += rec->data[fi];
}
}
void
get_ic35recdata( IC35REC * rec, uchar ** pdata, size_t * pdlen )
{
uchar * fptr;
int fi;
size_t dlen;
if ( rec->data == NULL ) { /* rebuild record data */
for ( fi = 0, dlen = 0; fi < rec->nflds; ++fi )
dlen += rec->flds[fi].len + 1;
if ( (rec->data = malloc( dlen )) != NULL ) {
rec->dlen = dlen;
fptr = rec->data + rec->nflds;
for ( fi = 0; fi < rec->nflds; ++fi ) {
if ( rec->flds[fi].ptr != NULL )
memcpy( fptr, rec->flds[fi].ptr, rec->flds[fi].len );
else
rec->flds[fi].len = 0;
fptr += (rec->data[fi] = rec->flds[fi].len);
}
}
}
if ( pdata )
*pdata = rec->data;
if ( pdlen )
*pdlen = rec->dlen;
}
/* set,get string field from IC35 record
* -------------------------------------
*/
void
set_ic35recfld( IC35REC * rec, int fldid, char * data )
{
int fi, nflds;
size_t flen;
char * fbuff;
if ( (nflds = _nrecflds( fldid )) <= 0 )
return; /* bad field id */
if ( rec->nflds == 0 )
rec->nflds = nflds;
if ( (fi = FldIdx(fldid)) >= rec->nflds )
return;
if ( data == NULL )
data = "";
switch ( fldid ) {
case A_CategoryID:
case S_AlarmBefore:
case S_Alarm_Repeat:
case S_RepCount:
case T_Completed:
case T_Priority:
case T_CategoryID:
case M_CategoryID: /* 1-byte binary fields */
flen = 1;
break;
default:
flen = strlen( data );
}
if ( flen > 255 ) flen = 255; /* truncate to max.field length */
if ( flen > rec->flds[fi].len ) { /* new field bigger old content */
if ( (fbuff = malloc( flen + 1 )) == NULL )
return; /* no memory */
if ( !( rec->fbuff <= rec->flds[fi].ptr
&& rec->flds[fi].ptr < rec->fbuff+rec->fblen ) )
free( rec->flds[fi].ptr ); /* old field outside buffer */
rec->flds[fi].ptr = fbuff;
}
if ( flen ) {
memcpy( rec->flds[fi].ptr, data, flen );
rec->flds[fi].ptr[flen] = '\0';
}
rec->flds[fi].len = flen;
if ( rec->data != NULL ) {
free( rec->data );
rec->data = NULL; /* record data must be rebuilt */
rec->dlen = 0;
}
}
void
get_ic35recfld( IC35REC * rec, int fldid, uchar ** pfld, size_t * plen )
{
if ( _nrecflds( fldid ) <= 0 /* bad field id */
|| rec->flds[FldIdx(fldid)].ptr == NULL ) { /* empty field */
if ( pfld ) *pfld = "";
if ( plen ) *plen = 0;
} else {
if ( pfld ) *pfld = rec->flds[FldIdx(fldid)].ptr;
if ( plen ) *plen = rec->flds[FldIdx(fldid)].len;
}
}
char *
ic35recfld( IC35REC * rec, int fldid )
{
uchar * fld;
get_ic35recfld( rec, fldid, &fld, NULL );
return fld;
}
/* compare 2 IC35 records
* ----------------------
* records are compared field by field, because some fields need
* special handling, i.e. difference ignored.
* returns
* 0 both IC35 records are (regarded) same
* 1 IC35 records differ
* -1 IC35 records differ strangely:
* either one is NULL or fileids mismatch
*/
int
cmp_ic35rec( IC35REC * rec1, IC35REC * rec2 )
{
int fileid;
int fi, nflds, fldid;
uchar * ic35fld;
uchar * binfld;
char ic35tfld[6+1];
if ( rec1 == NULL && rec2 == NULL )
return 0;
if ( rec1 == NULL || rec2 == NULL )
return -1;
if ( (fileid = FileId( ic35recid( rec1 ) ))
!= FileId( ic35recid( rec2 ) ) )
return -1;
nflds = ic35fnflds( fileid );
for ( fi = 0; fi < nflds; ++fi ) {
fldid = FILEfld(fileid,fi);
ic35fld = ic35recfld( rec1, fldid );
binfld = ic35recfld( rec2, fldid );
if ( strcmp( binfld, ic35fld ) == 0 )
continue;
switch ( fldid ) {
case A_CategoryID:
case M_CategoryID:
case T_CategoryID:
continue; /* ignore category-ID difference */
case S_StartTime:
case S_EndTime:
ic35fld = strncat( strcpy( ic35tfld, "" ),
ic35fld, sizeof(ic35tfld)-1 );
if ( ( fldid == S_StartTime && ic35fld[4] == ':' )
|| ( fldid == S_EndTime && ic35fld[4] == '<' ) )
ic35fld[4] = ic35fld[5] = '0';
if ( strcmp( ic35fld, binfld ) == 0 )
continue; /* ignore strange IC35 Start/EndTime */
break;
case S_RepEndDate:
case S_RepCount:
if ( (*ic35recfld( rec2, S_Alarm_Repeat ) & RepeatMASK) == 0 )
continue; /* ignore difference if not repeat */
break;
case S_Alarm_Repeat:
if ( ((*binfld ^ *ic35fld) & ~(AlarmNoLED|AlarmNoBeep)) == 0
&& *ic35recfld( rec2, S_AlarmBefore ) == AlarmBefNone )
continue; /* ignore LED,Beep diff if no alarm */
break;
}
LPRINTF(( L_DEBUG, "cmp_ic35rec: rid=%08lX fi=%d diff",
ic35recid(rec1), fi ));
LDUMP(( L_DEBUG, binfld, strlen(binfld),
"cmp_ic35rec: rec2 len=%d", strlen(binfld) ));
LDUMP(( L_DEBUG, ic35fld, strlen(ic35fld),
"cmp_ic35rec: rec1 len=%d", strlen(ic35fld) ));
return 1;
}
return 0;
}