--> Paul Druggitt wrote to Cliff Rhodes <--
PD> This I have managed to do, but the method I have used is specific
PD> to this type of structure. Elsewhere in the program I have
PD> different structures for other reports, eg standing orders which
PD> keeps a record of how many payments are still left etc etc,
PD> stored alphabetically.
PD> I was trying to write a single function that would add records of
OK, Paul, this is a variable length record (VLR)problem. The most
straight forward approach (in C) would be to add a type member to the
top of each of your structures. Then you can read records, modify
records, append records etc, with little problem. Here is some code
that should give you a reasonable start:
#include
#include
typedef enum { ShortRecord, LongRecord, HugeRecord } Rtype;
struct Data {
Rtype type; /* This would be set to ShortRecord */
/* ... */
long pos;
};
struct BigData {
Rtype type; /* This would be set to LongRecord */
/* ... */
long pos;
char name[16];
};
struct HugeData {
Rtype type; /* This would be set to HugeRecord */
/* ... */
long pos;
char name[16];
float value;
};
int WriteStruct(void *s, FILE *fp)
{
/* Write the struct pointed to by s into the file stream at the
* current file position.
*/
size_t rsize = sizeof(struct Data); /* Default size */
/* Get the size of the struct based on its type */
if(*(Rtype *)s == LongRecord)
rsize = sizeof(struct BigData);
else if(*(Rtype *)s == HugeRecord)
rsize = sizeof(struct HugeData);
return fwrite(s, rsize, 1, fp);
}
void * ReadNextRecord(FILE *fp)
{
/* Returns a pointer to a record, type can be determined from
* type member. Returns NULL if no record found.
*/
static struct Data d;
static struct BigData bd;
static struct HugeData hd;
if(!fread(&d, sizeof(struct Data), 1, fp))
return NULL; /* No record read */
if(d.type == ShortRecord) /* If Short, we are done */
return &d;
/* If not Short, set file pointer back */
fseek(fp, -((long) sizeof(struct Data)), SEEK_CUR);
if(d.type == LongRecord)
{
fread(&bd, sizeof(struct BigData), 1, fp);
return &bd;
}
/* Must be HugeRecord if here */
fread(&hd, sizeof(struct HugeData), 1, fp);
return &hd;
}
void ModifyRec(FILE *fp)
{
/* This function demonstrates how to use the value returned by
* ReadNextRecord(). You just switch on the record type. The shell
* will allow you to read, modify and write back any record type.
* NOTE: you cannot CHANGE the record type to be written back! That
* would corrupt your data file.
*/
void *pv;
pv = ReadNextRecord(fp);
if(pv != NULL)
{
switch(*(Rtype *)pv) /* Since type is 1st record, this is OK */
{
case ShortRecord:
{
/* Do whatever with the returned record by casting it */
struct Data *d = (struct Data *) pv;
/* Whatever code to work on d-> members goes here
* Then you can back up to the start of the record with the
* following if you need to write back a modified copy.
*/
fseek(fp, d->pos, SEEK_SET);
WriteStruct(d, fp);
}
break;
case LongRecord:
/* ... */
break;
case HugeRecord:
/* ... */
break;
default:
puts("Error in record type");
break;
}
}
}
int main(void)
{
/* Just a simple, quick and dirty test */
#define FILENAME "file.tmp"
struct Data d;
struct BigData bd;
struct HugeData hd;
FILE *fp;
void *p;
/* Initialize some structures */
d.type = ShortRecord; bd.type = LongRecord; hd.type = HugeRecord;
strcpy(bd.name, "BigData");
strcpy(hd.name, "HugeData");
hd.value = 100.0;
/* Write the structures to a file in Long, Huge, Short order */
fp = fopen(FILENAME, "wb");
bd.pos = 0L; /* First record at file position 0 */
WriteStruct(&bd, fp);
hd.pos = ftell(fp); /* Current position in file */
WriteStruct(&hd, fp);
d.pos = ftell(fp);
WriteStruct(&d, fp);
fclose(fp);
/* Read back the structs and see if type are correct */
fp = fopen(FILENAME, "rb");
p = ReadNextRecord(fp);
if(*(Rtype *)p != LongRecord)
puts("Error in first record type...");
p = ReadNextRecord(fp);
if(*(Rtype *)p != HugeRecord)
puts("Error in second record type...");
p = ReadNextRecord(fp);
if(*(Rtype *)p != ShortRecord)
puts("Error in third record type...");
fclose(fp);
return 0;
}
Cliff Rhodes
cliff.rhodes@juge.com
X CMPQwk 1.42 1692 X"Turn about is fair play." - English Proverb
--- Maximus/2 3.01
---------------
* Origin: COMM Port OS/2 juge.com 204.89.247.1 (281) 980-9671 (1:106/2000)
|