4.6 Sequential File Processing



Dfind(C-3) and dfindn(C-3) read an RMSfile sequentially from the beginning to the end. Dfind returns the first active record of an RMSfile. Each call to dfindn returns the next successive active record in the file. When an RMSfile is opened, it is positioned at the first record. Records that are empty or logically deleted are inactive and dfind and dfindn skip them. A sample call to dfind might look like:

recno = dfind (&scriptbuf, sfp);

Notice that the address of scriptbuf is passed, not the actual structure. The pointer passed to dfind can be a pointer to a structure, or it can be a pointer to a character array large enough to hold the user record. If there are no active records in the RMSfile, dfind returns a minus one (-1) as the record number. A sample call to dfindn might look like:

recno = dfindn (&scriptbuf, sfp);

Upon reaching the end of the RMSfile, -1 is returned as the record number. The following example reads each active record from the subscription file and produces a listing of subscriptions:

#include <stdio.h>

#include <cbase/dtypes.h>

#include <cbase/dirio.h>

#define SZ(s,m) (sizeof(((s *)0)->m))

typedef struct scriptrec {

STRING subscriber[16]; /* code from subscriber master */

STRING magazine[16]; /* code from magazine master */

short issues; /* number of issues left */

DATE started; /* date subscription was started */

} ScriptRec;

ScriptRec scriptbuf;

DR scriptlist[] = {

{"subscriber", STRING_TYPE, SZ(ScriptRec,subscriber), 1, DRCONVPRE}, {"magazine", STRING_TYPE, SZ(ScriptRec,magazine), 1, DRCONVPRE}, {"issues", INT_TYPE, SZ(ScriptRec,issues), 1, DRCONVPRE}, {"started", DATE_TYPE, SZ(ScriptRec,started), 1, DRCONVPRE},

{0}

};

DFILE *sfp = NULL;

main (argc, argv)

int argc;

char *argv[];

{

long recno;

if ((sfp = dlopen ("script", "r")) == NULL) {

puts (derrmsg());

puts ("can't open subscription file");

exit (1);

}

if (drlist (scriptlist, sfp) < 0L) {

puts (derrmsg());

puts ("bad field list for subscription file");

dclose (sfp);

exit (1);

}

recno = dfind (&scriptbuf, sfp);

while (recno > 0L) {

do_details (&scriptbuf);

recno = dfindn (&scriptbuf, sfp);

}

dclose (sfp);

}

do_details (sc)

struct scriptrec *sc;

{

static int linecount = 0;

if (linecount == 0) {

puts ("\n Subscription List");

puts ("Subscriber Magazine Issues Started\n");

linecount = 4;

}

printf ("%-14s%-12s %3d %s\n",

sc->subscriber, sc->magazine,

sc->issues, datetoa (sc->started));

if (linecount++ > 63) {

printf ("\f");

linecount = 0;

}

}

Thus far, the examples have been reading RMSfiles from the beginning of the file to the end. It is also possible to read an RMSfile in reverse order: from the end of the file to the beginning. To do this, call the functions dfindl(C-3) and dfindp(C-3).

Dfindl returns the last active record of an RMSfile. Each call to dfindp returns previous active records of the RMSfile. Like dfind and dfindn, dfindl and dfindp skip empty or logically deleted records. A sample call to dfindl looks like:

recno = dfindl (&scriptbuf, sfp);

If there are no active records in the file, dfindl returns -1. The pointer passed to dfindl can be the same pointer passed to dfind or dfindn. A sample call to dfindp looks like:

recno = dfindp (&scriptbuf, sfp);

Upon reaching the beginning of the RMSfile, dfindp returns -1. The previous example program can be changed to read the subscription file in reverse order by changing the call dfind to dfindl, and changing the call dfindn to dfindp.

Calls to dfindn and dfindp can be mixed. The only restriction is that the preceding function call returned an active record. If not, the function returns an error: "previous call canceled sequence". This error indicates that the functions dfindn and dfindp are reading a sequence of records. When an error is encountered while reading records in this sequence (beginning of file, end of file, etc.), RMS abandons the current sequence. Your program must call dfind or dfindl to restart the sequence.