DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T i

⟦c496531f8⟧ TextFile

    Length: 10485 (0x28f5)
    Types: TextFile
    Names: »info.c«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦e7f64e0c0⟧ »EurOpenD3/mail/vmh.tar.Z« 
        └─⟦dcb95597f⟧ 
            └─⟦this⟧ »info.c« 

TextFile

#ifndef lint
static char rcsid[] =
	"$Header: info.c,v 2.9 88/01/13 19:00:56 deboor Exp $";

static char notice[] =
	"This program is in the public domain and is available for unlimited \
distribution as long as this notice is enclosed.";
#endif

/*
 * Routines for manipulating the lists of INFO structures attached to each
 * folder.
 *
 * $Source: /c/support/deboor/usr/src/old/vmh/RCS/info.c,v $
 * $Revision: 2.9 $
 * $Author: deboor $
 * 
 * FUNCTIONS:
 *	findinfo	find INFO structure by linear search
 *	findinfoR	find INFO structure relative to another
 *	findinfoS	same but stop when it's clear INFO structure isn't there
 *	flushinfo	write INFO list out to disk
 *	i_diff		find # of structures between two INFO structures
 *	i_post		return nth INFO structure after a given one
 *	i_pre		return nth INFO structure before a given one
 *	linkinfo	link an INFO structure into a list
 *	readinfo	read/rebuild INFO list
 *	unlinkinfo	unlink and INFO structure from its list
 */

# include "vmh.h"
# include <sys/file.h>

/*
 * INFO *
 * findinfo (mno, f) register mno; FLDR *f;
 *	look for mno in the info list of folder f. Starts
 *	at f->f_head and continues until either the message is found
 *	or the end of the list is reached. The final record examined
 *	(which is either the record or the tail of the list) is returned
 */
INFO *
findinfo (mno, f)
	Reg2 int mno;
	FLDR	*f;
{
	Reg1	INFO	*ss;

	for (ss = f->f_head; ss && ss->i_next && ss->i_mnum != mno; ss = ss->i_next)
		;
	return ss;
}

/*
 * INFO *
 * findinfoS (mno, f) register mno; FLDR *f;
 *	looks for the message  mno  in folder  f . It does an absolute
 *	search starting from the head. If it finds the message, its INFO
 *	structure is returned. If it doesn't find the message, the INFO
 *	structure AFTER where it should have been is returned. The 'S' stands
 *	for "Stop", as in, stop when its impossible for the message to be there.
 */
INFO *
findinfoS (mno, f)
	Reg2 int mno;
	FLDR	*f;
{
	Reg1	INFO	*ss;

	for (ss = f->f_head; ss && ss->i_next && mno > ss->i_mnum; ss = ss->i_next)
		;

	return (ss);
}

/*
 * INFO *
 * findinfoR (mno, sp) register mno; INFO *sp;
 *	look for info on message number mno beginning at record *sp.
 *	if  mno  is below the number of *sp, search occurs backwards;
 *	if it is above it, search occurs forwards. If mno is not found,
 *	the final record examined is returned. If sp is NULL, NULL is returned.
 */
INFO *
findinfoR (mno, sp)
	Reg2 int mno;
	INFO	*sp;
{
	Reg1	INFO	*ss;

	if (!sp)
		return ((INFO *) NULL);
	if (mno < sp->i_mnum && sp->i_prev) {
		for (ss = sp->i_prev; ss->i_prev && ss->i_mnum != mno; ss = ss->i_prev)
			;
	} else if (mno > sp->i_mnum && sp->i_next) {
		for (ss = sp->i_next; ss->i_next && ss->i_mnum != mno; ss = ss->i_next)
			;
	} else
		ss = sp;
	return (ss);
}

/*
 * INFO *
 * i_pre (sp, n) INFO *sp; register n;
 *	returns the nth info structure before sp, or the previous-most
 *	(say what?) structure on the list if there aren't n structures before
 *	it. if n is negative, just calls i_post with -n.
 *	NULL is returned on an error. Note that only valid info structures
 *	are examined.
 */
INFO *
i_pre (sp, n)
	INFO	*sp;
	Reg3 int n;
{
	Reg1	int	i;
	Reg2	INFO	*ss;

	if (n < 0)
		return (i_post(sp, -n));
	if (!sp)
		return (sp);

	for (i = 0, ss = sp; i < n && ss->i_prev; ss = ss->i_prev)
		if (!ss->i_invalid)
		    i++;
	
	return (ss);
}

/*
 * INFO *
 * i_post(sp, n) INFO *sp; register n;
 *	returns the nth info record after sp. If there aren't that many,
 *	returns the last record on the list following sp. If n is negative,
 *	just calls i_pre to search before sp. Again, only valid info
 *	structures are counted.
 *	NULL is returned on any error.
 */
INFO *
i_post (sp, n)
	INFO	*sp;
	Reg3 int n;
{
	Reg1	int	i;
	Reg2	INFO	*ss;

	if (n < 0)
		return (i_pre(sp, -n));
	if (!sp)
		return (sp);
	for (i = 0, ss = sp; i < n && ss->i_next; ss = ss->i_next)
		if (!ss->i_invalid)
		    i++;
	return (ss);
}

/*
 * i_diff (ss1, ss2) register INFO *ss1, *ss2;
 *	returns the number of valid records between ss1 and ss2.
 *	i.e. if ss1 == ss2, returns 0; if ss1->ss3->ss4->ss2,
 *	returns 3, etc.
 */
i_diff (ss1, ss2)
	Reg1	INFO	*ss1;
	Reg3	INFO	*ss2;
{
	Reg2	int	i;

	if (!ss1 || !ss2)		/* if either is null, return 0 */
		return (0);
	if (ss1->i_mnum < ss2->i_mnum) {	/* move down the list if we're below it */
		for (i = 0; ss1 != ss2; ss1 = ss1->i_next) {
		    if (ss1 == 0) {
			break;
		    } else if (!ss1->i_invalid) {
			i++;
		    }
		}
	} else {				/* else move up the list */
		for (i = 0; ss1 != ss2; ss1 = ss1->i_prev) {
		    if (!ss1) {
			break;
		    } else if (!ss1->i_invalid) {
			i--;
		    }
		}
	}
	return (i);
}

/*
 * linkinfo (sp, f) INFO *sp; FLDR *f;
 *	links the record  *sp  into the info structure list for the
 *	folder  f . If this list is empty, the head and tail are set
 *	equal to sp; if sp's message number is greater than the tail's
 *	sp is linked after the tail and becomes the new tail (structures
 *	go from low numbers at the head to high numbers at the tail);
 *	if sp's mnum is less than the head's, sp becomes the new head;
 *	if it's between the head and the tail, searching begins at either
 *	the head or the tail depending on whether sp's mnum is less than
 *	or greater than the average of the two numbers, respectively.
 */
linkinfo (sp, f)
	INFO	*sp;
	FLDR	*f;
{
	Reg2	INFO	*tail = f->f_tail;
	Reg3	INFO	*head = f->f_head;
	Reg1	int	mno = sp->i_mnum;
	INFO		*r_prev, *r_next;	/* save places for prev and next when replacing */

	if (!tail) {				/* no structures */
		f->f_tail = f->f_head = sp;	/* set sp as the first one */
		sp->i_prev = sp->i_next = (INFO *)0;
	} else if (mno > tail->i_mnum) {	/* after tail */
		tail->i_next = sp;		/* link it to end */
		sp->i_prev = tail;
		sp->i_next = (INFO *) 0;
		f->f_tail = sp;			/* and make it the tail */
	} else if (mno < head->i_mnum) {	/* before head */
		head->i_prev = sp;		/* link sp at beginning */
		sp->i_next = head;
		sp->i_prev = (INFO *) 0;
		f->f_head = sp;			/* and make it the head */
	} else {				/* nowhere easy. look for the thing */
		if (mno < (head->i_mnum + tail->i_mnum) / 2) {
		/*
		 * loop terminates when it hits the end of the list (something
		 * is wrong), it finds itself in the list (this is a replace) or
		 * it finds the element before which it should be inserted.
		 */
			for (;head && head->i_mnum < mno; head = head->i_next)
				;
		} else {
			for (;tail && tail->i_mnum > mno; tail = tail->i_prev)
				;
			if (! tail)
				punt ("Couldn't link in info record!");
			if (tail->i_mnum == mno) {	/* if found */
				head = tail;		/* set the ptr app. */
				goto replace;		/* and do the replace */
			}
			head = tail->i_next;	/* set ptr after where sp should be */
		}
		if (head && head->i_mnum == mno) {	/* found itself */
replace:
			r_prev = head->i_prev;
			r_next = head->i_next;
			*head = *sp;
			head->i_prev = r_prev;
			head->i_next = r_next;
		} else if (!head) {	/* couldn't find where to put it */
			punt("Couldn't link in info record!");	/* major program bug */
		} else {			/* found where to stick it */
			sp->i_prev = head->i_prev;	/* link it to previous element */
			sp->i_next = head;		/* then to next */
			head->i_prev->i_next = sp;	/* then previous to it*/
			head->i_prev = sp;		/* then next to it */
		}
	}
	f->f_modified = 1;
}

/*
 * unlinkinfo (sp, f) register INFO *sp; FLDR *f;
 *	unlinks the structure pointed to by sp. IT DOESN'T FREE IT.
 */
unlinkinfo (sp, f)
	register INFO	*sp;
	FLDR		*f;
{
	if (sp->i_prev)		/* unlink from previous */
		sp->i_prev->i_next = sp->i_next;
	else			/* must be the head of the list */
		f->f_head = sp->i_next;

	if (sp->i_next)		/* unlink from next */
		sp->i_next->i_prev = sp->i_prev;
	else			/* must be tail of list */
		f->f_tail = sp->i_prev;

	/*
	 * if it's any of the display pointers, advance them to next
	 * one, if it exists. If the next doesn't exist, move
	 * them to the previous one.
	 */
	if (sp == f->f_cur)
		f->f_cur = (sp->i_next) ? sp->i_next : sp->i_prev;
	if (sp == f->f_top)
		f->f_top = (sp->i_next) ? sp->i_next : sp->i_prev;
	if (sp == f->f_bot)
		f->f_bot = (sp->i_next) ? sp->i_next : sp->i_prev;
}
/*
 * readinfo (f) register FLDR *f;
 *	reads in the info file for the folder f. reads in an enormous
 *	block of records and then uses linkinfo to link them all up.
 */
readinfo (f)
	Reg3	FLDR *f;
{
	char		infopath[PATHLENGTH];
	Reg1	INFO	*sp;
	int		nrecs;
	Reg2	int	i;
	int		ifile;

	(void) strcat (strcpy (infopath, f->f_name), "/.info");
	if ((ifile = open (infopath, O_RDONLY, 0)) < 0) {
		makeinfo(f);	/* can't find it. build new one */
		return;
	}
	if (read (ifile, (char *) &nrecs, sizeof(nrecs)) < sizeof(nrecs)) {
		errormsg ("bad .info format", 1);	/* empty file */
		makeinfo (f);				/* build new one */
		(void) close (ifile);
		return;
	}
	sp = (INFO *) Calloc (nrecs, sizeof(INFO));
	if (read (ifile, (char *)sp, sizeof(INFO) * nrecs) !=
		nrecs * sizeof(INFO)) {
		errormsg ("error in .info file", 1);	/* munged file */
		Free ((char *)sp);			/* recover memory */
		makeinfo (f);				/* build new file */
		(void) close (ifile);
		return;
	}
	(void) close (ifile);
	for (i = nrecs;i; i--,sp++)
		linkinfo (sp, f);
	if (checkinfo (f))		/* see if what we read was up to date */
		makeinfo (f);		/* no. remake it */
}

/*
 * flushinfo (fd, f) int fd; register FLDR *f;
 *	(void) writes the info structures for the folder f out to the file
 *	w/descriptor fd.
 */
flushinfo (fd, f)
	int		fd;
	register FLDR	*f;
{
	register INFO	*ss;
	
	(void) write (fd, (char *) &f->f_msgs.m_nummsg, sizeof(int));
	for (ss = f->f_head; ss; ss = ss->i_next) {
	    if (!ss->i_invalid) {
		(void) write (fd, (char *) ss, sizeof(INFO));
	    }
	}
}

/*
 * invalfldr (f)
 *	Invalidate all the info structures for the given folder. Used
 *	just before rebuilding so any structures which describe non-existent
 *	messages are prevented from being written out.
 */
invalfldr (f)
    FLDR	*f;
{
    register INFO	*ss;

    for (ss = f->f_head; ss; ss = ss->i_next) {
	ss->i_invalid = 1;
    }
}

/*
 * invalmsg (ss, f)
 *	invalidate the given message for the given folder. If the message
 *	number is listed as existing in the MSGS structure, it is removed
 *	and the number of messages in the folder is reduced by one.
 */
invalmsg (ss, f)
    INFO	*ss;
    FLDR	*f;
{
    ss->i_invalid = 1;
    if (Exists (ss->i_mnum, &f->f_msgs)) {
	f->f_msgs.m_nummsg -= 1;
	Del_Msg (ss->i_mnum, &f->f_msgs);
    }
}