|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 19808 (0x4d60)
Types: TextFile
Names: »sequence.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦e7f64e0c0⟧ »EurOpenD3/mail/vmh.tar.Z«
└─⟦dcb95597f⟧
└─⟦this⟧ »sequence.c«
#ifndef lint
static char rcsid[] =
"$Header: sequence.c,v 2.10 88/01/13 19:17:03 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 handling sequences.
*
* $Source: /c/support/deboor/usr/src/old/vmh/RCS/sequence.c,v $
* $Revision: 2.10 $
* $Author: deboor $
*
* FUNCTIONS:
* add_to_sequence add array of messages to a given sequence in
* a given folder.
* cmdMark primitive 'mark' command: just prints out a
* sequence (DEBUG)
* del_from_sequence remove array of messages from a given sequence
* in a given folder
* delete_sequence delete an entire sequence from a folder
* dump_sequences refresh sequences file of a folder
* free_sequences free all the sequences of a folder (w/o refresh)
* init_sequences read sequences file to create in-core list
* of sequences for a folder
* is_pre_def returns one of the PD_ constants or 0 based on
* whether the passed sequence is a pre-defined one
* readsequence "read" a sequence from a folder
* set_sequence set the value of a sequence for a folder
*/
# include "vmh.h"
/* the structure for the sequences list. one structure kept per sequence */
struct seq {
char *se_name; /* name of sequence */
int se_length; /* length of " */
int *se_msgs; /* the messages in " */
struct seq *se_next; /* the next " */
};
/* number of bits in an int */
# define nbits (sizeof(int)*8)
/* Functions for manipulating bit arrays for messages */
# define mark(num) letters[num/nbits]|=(1<<(num%nbits))
# define unmark(num) letters[num/nbits]&=~(1<<(num%nbits))
# define marked(num) letters[num/nbits]&(1<<(num%nbits))
static int seq_length; /* the length of the current sequence */
/*
** static
** sequence_ok (seq_name) register char *seq_name;
** returns true if the passed name is a valid MH sequence name
** (all alphanumeric characters), false otherwise.
*/
static
sequence_ok (seq_name)
register char *seq_name;
{
if (! isalpha (*seq_name++))
return (0);
while (*seq_name && isalnum (*seq_name++))
;
return ( ! *seq_name );
}
/*
** static int *
** form_sequence (seq, negate, m) int *seq, negate; struct msgs *m;
** takes a sequence (seq) in the folder with the msgs struct m
** and compacts it (removes duplicated message numbers) and copies
** the sequence to a new location. If negate is true, it copies
** the complement of the sequence (that's what 'm' is used for).
** It is used for two things: to negate a sequence and to compact/copy
** it, for obvious reasons.
*/
static int *
form_sequence (seq, negate, m)
int *seq,
negate;
struct msgs *m;
{
u_char letters[MAXFOLDER];
Reg1 int i;
Reg2 int j; /* a counter for counting */
Reg4 int *cq; /* the new sequence location */
Reg3 int nseq; /* the number of messages in the sequence */
/* initialize the array */
Bzero ((char *)letters, sizeof(letters));
/* mark the messages in the sequence in the letters[] */
for (i = 0, nseq = 0; seq[i]; i++)
if (letters[seq[i]-1] == 0) {
letters[seq[i]-1] = 1;
nseq++;
}
seq_length = nseq + 1;
if ( ! negate) {
/* no negation necessary, so make room for the sequence */
cq = (int *) Calloc (seq_length + 1, sizeof (int));
/* now go through letters[] looking for marked msgs */
for (j = 0, i = m->m_lowmsg; i <= m->m_hghmsg; i++) {
/* go until we have one which exists */
while ( i <= m->m_hghmsg && ! Exists(i,m))
i++;
/* if it's marked, put it in the new sequence */
if (letters [i-1])
cq[j++] = i;
}
cq[j] = 0;
} else {
/*
* need negation. get space for all but the messages in
* the sequence. (plus the null word)
* seq_length is the number of words.
*/
cq = (int *) Calloc((m->m_nummsg - (seq_length-1)) + 1,sizeof(int));
/* go through the array looking for unmarked messages */
for (j = 0, i = m->m_lowmsg; i <= m->m_hghmsg; i++) {
/* get to an existing message */
while ( ! Exists(i,m) && i <= m->m_hghmsg)
i++;
/* if it's unmarked, put it in the sequence */
if (! letters[i-1])
cq[j++] = i;
}
cq[j] = 0;
seq_length = j;
}
return (cq);
}
static char *pre_defs[] = {
"all", "first", "last", "prev", "next", "cur", (char *)0
};
/*
** is_pre_def (name) register char *name;
** checks to see if the given name is one of the standard MH pre-defined
** sequences. If it is, it returns its number, otherwise it returns 0.
*/
is_pre_def (name)
register char *name;
{
register pre_def_num;
for (pre_def_num = 0; pre_defs[pre_def_num]; pre_def_num++)
if ( ! strcmp (name, pre_defs[pre_def_num]))
return (pre_def_num + 1);
return (0);
}
/*
** static int *
** get_pre_def (pre_def_num, negate, f) register pre_def_num; int negate;
** register struct fldr *f;
** Checks name for being a pre-defined sequence (one of all, first,
** first, prev, next, or last) and, if it is, returns the appropriate
** value, after sending it to form_sequence to be negated, if nec'y.
*/
static int *
get_pre_def (pre_def_num, negate, f)
Reg5 int pre_def_num;
int negate;
Reg4 FLDR *f;
{
Reg3 int *sequence; /* the sequence value */
int *tsequence;
Reg1 int i;
Reg2 int msg;
if (f->f_tail == (INFO *) NULL)
return ((int *) NULL);
switch (pre_def_num) {
case PD_ALL:
if (negate) {
/* this is the NULL sequence */
sequence = (int *) Malloc (sizeof(int));
*sequence = 0;
seq_length = 0;
return (sequence);
} else {
if (f->f_msgs.m_lowmsg > f->f_msgs.m_hghmsg) {
punt ("data space corrupted");
}
/* need room for everybody */
sequence = (int *)Calloc(f->f_msgs.m_nummsg + 1, sizeof(int));
/* put all the messages which exist into the sequence */
for (i=0, msg=f->f_msgs.m_lowmsg; msg <= f->f_msgs.m_hghmsg; msg++)
if (Exists (msg, &f->f_msgs))
sequence[i++] = msg;
seq_length = i;
return (sequence);
}
case PD_FIRST:
sequence = (int *)Calloc (2,sizeof(int));
*sequence = f->f_msgs.m_lowmsg;
seq_length = 1;
if (! negate)
return (sequence);
break;
case PD_LAST:
sequence = (int *)Calloc(2,sizeof(int));
*sequence = f->f_msgs.m_hghmsg;
seq_length = 1;
if (! negate)
return (sequence);
break;
case PD_PREV:
sequence = (int *)Calloc(2,sizeof(int));
if (f->f_cur != f->f_head)
*sequence = f->f_cur->i_prev->i_mnum;
else
return ((int *)NULL);
seq_length = 1;
if (! negate)
return (sequence);
break;
case PD_NEXT:
sequence = (int *)Calloc(2,sizeof(int));
if (f->f_cur != f->f_tail)
*sequence = f->f_cur->i_next->i_mnum;
else
return ((int *) NULL);
seq_length = 1;
if (!negate)
return (sequence);
break;
case PD_CUR:
sequence = (int *)Calloc(2,sizeof(int));
*sequence = f->f_cur->i_mnum;
seq_length = 1;
if (!negate)
return (sequence);
break;
default:
prt_action (" pdn = %d. I don't know what's happening! ",
pre_def_num);
sleep(2);
punt ("Dying in a big way");
}
/* have gotten a sequence and found it needs negation */
tsequence = form_sequence (sequence, 1, &f->f_msgs);
Free ((char *)sequence);
sequence = tsequence;
return (sequence);
}
/*
** int *
** readsequence (seq, f) char *seq; struct fldr *f;
** reads the given sequence seq from the folder f .
*/
int *
readsequence (seq, f)
char *seq;
Reg3 FLDR *f;
{
int do_negate = 0;
Reg2 struct seq *s;
Reg1 int i;
if ( ! *seq || f->f_cur == (INFO *) 0) /* guard against null sequence names */
return NULL; /* and empty folders */
if (strncmp (seq, SeqNegate, strlen(SeqNegate)))
do_negate = 0;
else {
do_negate = 1;
seq += strlen(SeqNegate);
}
/* see if it's pre-defined sequence */
if (i = is_pre_def (seq))
/* form the proper negation and return it */
return (get_pre_def (i, do_negate, f));
/* see if the sequence is there */
for (s = f->f_sequences; s ; s = s->se_next)
/* is this the one? */
if (! strcmp (s->se_name, seq)) {
/* yes. set seq_length from here */
seq_length = s->se_length;
/* and get the sequence from it, negating as nec'y */
return (form_sequence(s->se_msgs, do_negate, &f->f_msgs));
}
/*
* neither existent nor pre-defined. bitch.
*/
/* BITCH BITCH BITCH BITCH that good enough? */
return (NULL);
}
/*
** init_sequences (f) FLDR *f;
** initializes the sequence list for the passed folder from the
** .mh_sequences file.
*/
init_sequences (f)
Reg8 FLDR *f;
{
char seq_file[PATHLENGTH];
Reg7 FILE *sfile;
char line[256];
char moremsgs[256];
int letters[MAXFOLDER/nbits + 1];
int need_more;
int nseq = 0;
Reg4 char *cp;
Reg5 char *c2p;
Reg1 int seqStart;
Reg2 int seqEnd;
Reg3 int i;
Reg6 int *sequence;
f->f_cur = (INFO *) 0; /* so we know if we've done "cur" */
/* get the file name */
(void) sprintf (seq_file, "%s/%s", f->f_name, mh_seq);
if ((sfile = fopen (seq_file, "r")) == NULL) {
#ifdef DEBUG
DeBuG("Couldn't open sequences file %s\n", seq_file);
#endif
f->f_cur = f->f_tail;
return;
}
while (cp = fgets (line, sizeof (line), sfile)) {
/* initialize the marked messages array */
Bzero ((char *)letters, sizeof (letters));
/* get the offset to the start of the sequence */
if ((cp = index (line, ':')) == (char *) 0) {
punt ("Badly formatted sequences file");
}
*cp++ = '\0';
/*
* keep reading in lines and processing the message numbers
* until we get a line ending in '\n' or we hit EOF
*/
for (need_more = 1;cp && need_more;) {
if (c2p = index (cp, '\n')) {
*c2p = '\0';
need_more = 0;
} else
need_more = 1;
while (*cp) {
/* skip leading spaces */
while (isspace (*cp))
cp++;
/* get start of sequence */
for (seqStart = 0; isdigit (*cp); cp++)
seqStart = 10*seqStart + *cp - '0';
if (seqStart > MAXFOLDER)
punt ("Badly formatted sequences file");
/* if the next char is a '-' => it's a range */
if (*cp == '-') {
/* get end of sequence */
for (seqEnd =0, cp++; isdigit (*cp); cp++)
seqEnd = 10*seqEnd + *cp - '0';
if (seqEnd > MAXFOLDER)
punt ("Badly formatted sequences file");
/* now mark all the messages which exist */
for (i = seqStart; i <= seqEnd; i++, nseq++)
if (Exists (i, &f->f_msgs))
mark(i);
} else {
/* it's a single message, so mark it */
if (Exists (seqStart, &f->f_msgs)) {
nseq++;
mark(seqStart);
}
}
}
if(need_more)
cp=fgets(moremsgs, sizeof(moremsgs), sfile);
}
/* if it's not "cur", form structure and set it in the list */
if (strcmp (line, current)) {
/* get room for the sequence numbers */
sequence = (int *) Calloc (nseq + 1, sizeof (int));
/* set in the actual numbers */
for (i=0, seqStart=f->f_msgs.m_lowmsg;seqStart<= f->f_msgs.m_hghmsg; seqStart++)
if (marked(seqStart))
sequence[i++] = seqStart;
sequence[i] = 0;
seq_length = i;
set_sequence (line, sequence, f); /* install the value */
Free ((char *) sequence); /* free that memory */
} else {
/*
* if the sequence *is* "cur", we must treat it
* specially. go through the letters[] looking for the first
* marked letter. while doing this, keep track of the number
* of existent messages. this is the line number.
* once the first marked message is found, j will be the
* line number of that message.
* if no marked letter, default cur to m_hghmsg.
*/
for (i = f->f_msgs.m_lowmsg; i < f->f_msgs.m_hghmsg; i++) {
if (marked(i))
break;
}
f->f_cur = findinfo(i, f);
}
}
if (! f->f_cur) /* set it to eof */
f->f_cur = f->f_tail; /* if not set already */
(void) fclose (sfile);
}
/*
** dump_sequences (fold) register FLDR *fold;
** dumps all the sequences in structure fold into the .mh_sequences
** file for that folder. Including 'cur'.
*/
dump_sequences (fold)
Reg4 FLDR *fold;
{
char seq_file[PATHLENGTH];
Reg3 FILE *sfile;
Reg1 int i;
Reg2 SEQ *s;
(void) sprintf (seq_file, "%s/%s", fold->f_name, mh_seq);
/***** (void) (void) unlink (seq_file); just zero this thing with fopen *****/
if ((sfile = fopen (seq_file, "w")) == NULL) {
errormsg ("Cannot open sequence file?!", 1);
return;
}
for (s = fold->f_sequences; s; s = s->se_next) {
if (! sequence_ok (s->se_name))
continue;
fprintf (sfile, "%s: ", s->se_name);
for (i = 0; s->se_msgs[i];) {
if (s->se_msgs[i+1] - s->se_msgs[i] == 1) {
fprintf (sfile, "%d-", s->se_msgs[i++]);
while (s->se_msgs[i+1] - s->se_msgs[i] == 1)
i++;
fprintf (sfile, "%d ", s->se_msgs[i++]);
} else
fprintf (sfile, "%d ", s->se_msgs[i++]);
}
fprintf (sfile, "\n");
}
if (! FEmpty(fold)) /* if non-empty */
fprintf (sfile, "%s: %d\n", current, fold->f_cur->i_mnum);
/* output cur finally */
(void) fclose (sfile);
}
/*
** set_sequence (seq, msgs, f) char *seq; register int *msgs; register FLDR *f;
** Sets the given msgs to be the value of the sequence seq in the
** folder f .
*/
set_sequence (seq, msgs, f)
char *seq;
Reg4 int *msgs;
Reg5 FLDR *f;
{
Reg3 SEQ *s;
Reg1 int i;
Reg2 int j;
for (i=0; msgs[i]; i++) /* get the number of messages */
;
seq_length = i; /* set it in seq_length */
if (is_pre_def (seq)) { /* this is a no-no */
errormsg ("Cannot set the value of a pre-defined sequence",1);
return;
}
/* look for the sequence in the current list */
for (s = f->f_sequences; s; s = s->se_next)
if ( ! strcmp (seq, s->se_name)) { /* there it is */
Free ((char *)s->se_msgs); /* free old sequence */
/* make room for new one */
s->se_msgs = (int *) Calloc (i+1, sizeof (int));
/* copy the new one in */
for (j = 0; j < seq_length; j++)
s->se_msgs[j] = msgs[j];
s->se_msgs[j] = 0;
s->se_length = seq_length; /* set the length */
break;
}
if (s == NULL) { /* not there already */
/* get room for the structure */
s = (struct seq *) Malloc (sizeof (struct seq));
/* install the name */
s->se_name = (char *) Malloc (strlen (seq) + 1);
(void) strcpy (s->se_name, seq);
/* and the length */
s->se_length = seq_length;
/* then get room for and install the sequence itself */
s->se_msgs = (int *) Calloc (seq_length+1, sizeof (int));
for (j = 0; j < seq_length; j++)
s->se_msgs[j] = msgs[j];
s->se_msgs[j] = 0;
/* link in the new structure */
s->se_next = f->f_sequences;
f->f_sequences = s;
}
}
/*
** delete_sequence (seq, f) register char *seq; register FLDR *f;
** removes the sequence seq from the sequence list of folder f .
*/
delete_sequence (seq, f)
Reg4 char *seq;
Reg3 FLDR *f;
{
Reg1 SEQ *sc; /* the current sequence */
Reg2 SEQ *sp; /* the previous sequence */
/*
* first find the sequence, keeping track of the previous
* structure. don't need to worry about pre-defs since they
* aren't on the list anyway.
*/
for (sc = f->f_sequences, sp = (struct seq *)0;
sc && strcmp (sc->se_name, seq);
sc = sc->se_next)
sp = sc;
if (sc) {
/* re-link the sequence list */
if (sp) {
sp->se_next = sc->se_next;
} else {
f->f_sequences = sc->se_next;
}
Free (sc->se_name); /* free the name */
Free ((char *) sc->se_msgs); /* and the sequence */
Free ((char *) sc); /* and the Sequence */
} /* if not there, do nothing */
}
/*
** add_to_sequence (seq, msgs, f) register char *seq; register int *msgs;
** register FLDR *f;
** adds the passed msgs to the sequence seq in the folder f .
*/
add_to_sequence (seq, msgs, f)
Reg6 char *seq;
Reg4 int *msgs;
Reg5 FLDR *f;
{
int *nmsgs;
int *tmsgs;
Reg3 int i;
Reg2 int j;
Reg1 int k;
if (is_pre_def (seq)) {
errormsg ("can't add to a predefined sequence, bub", 1);
longjmp (CommandLevel, 1);
}
tmsgs = readsequence (seq, f);
if (tmsgs == (int *) NULL) {
tmsgs = (int *) Calloc (1, sizeof(int));
}
for (j = 0; msgs[j]; j++)
;
#ifdef DEBUG
if (Dbg) {
DeBuG ("+2seq: j = %d len = %d\nmsgs: ", j, seq_length);
for(i=0; i < j; i++)
DeBuG (" %d", msgs[i]);
if (msgs[i])
DeBuG ("\nnon null at end of msgs\ntmsgs: ");
else
DeBuG ("\ntmsgs: ");
for (i=0;i<seq_length;i++)
DeBuG (" %d",tmsgs[i]);
if(tmsgs[i])
DeBuG("\nnonnull at end of tmsgs\n");
else
DeBuG("\n");
}
#endif
nmsgs = (int *) Calloc (j + seq_length + 1, sizeof (int));
for (i = 0; tmsgs[i]; i++)
nmsgs[i] = tmsgs[i];
for (k = 0; msgs[k]; nmsgs[i++] = msgs[k++])
;
seq_length += j;
tmsgs = form_sequence (nmsgs, 0, &f->f_msgs);
Free ((char *)nmsgs);
set_sequence (seq, tmsgs, f);
Free ((char *)tmsgs);
}
#ifdef DEBUG
/*
* comparison routine for qsort() call in del_from_sequence
*/
static int
icmp (i1, i2) int *i1, *i2;
{
return (*i2 - *i1);
}
#endif DEBUG
/*
** del_from_sequence (seq, msgs, f) register char *seq;
** register int *msgs; register FLDR *f;
** removes the messages in msgs from the sequence seq
** in the folder f .
*/
del_from_sequence (seq, msgs, f)
Reg7 char *seq;
Reg5 int *msgs;
Reg6 FLDR *f;
{
Reg4 int *cseq;
Reg3 int i;
Reg2 int k;
Reg1 int j;
int icmp();
if ((cseq = readsequence (seq, f)) == (int *) 0) {
return;
}
#ifdef DEBUG
DeBuG ("seq: ");
for (i = 0; cseq[i]; i++)
DeBuG ("%d ", cseq[i]);
DeBuG ("(%d items)\n", i);
#endif
for (i = 0; msgs[i]; i++)
;
/*
* sort incoming messages. do 'i' rather than 'i+1' 'cause we
* don't want the thing to move the ending 0 word.
*/
#ifdef DEBUG
DeBuG ("bs: ");
for (j = 0; j < i; j++)
DeBuG ("%d ", msgs[j]);
qsort ((char *) msgs, i, sizeof(int), icmp);
DeBuG ("as: ");
for (j = 0; j < i; j++)
DeBuG ("%d ", msgs[j]);
#endif
/*
* i travels through the list of messages to delete, j travels
* through the current sequence and always advances, k travels
* through the new version of the sequence and advances only
* when a message # is copied.
*/
for (i = k = j = 0; msgs[i] && cseq[j]; j++) {
if (cseq[j] == msgs[i]) { /* if this is to be nuked, advance i */
i++;
continue;
} else if (msgs[i] < cseq[j]) { /* if past current msg-to-delete, advance to next possible one */
while (msgs[++i] && msgs[i] < cseq[j]) /* i.e. next which is greater than current message number */
;
if (msgs[i] == cseq[j]) { /* hit one to delete */
i++; /* so advance to next and don't copy */
continue;
}
}
cseq[k++] = cseq[j]; /* copy to new position */
}
while (cseq[j]) /* copy the rest */
cseq[k++] = cseq[j++];
cseq[k] = 0; /* null-terminate it */
set_sequence (seq, cseq, f); /* put in new value */
}
/*
** static
** print_sequence (seq, f, win) char *seq; FLDR *f; WINDOW *win;
** prints the members of the specified sequence, seq, of the
** given folder, f, to the passed window, win.
*/
static
print_sequence (seq, f, win)
Reg4 char *seq;
Reg3 FLDR *f;
WINDOW *win;
{
Reg2 int *q;
Reg1 int i;
wprintw (win, "Sequence |%s|: ", seq);
q = readsequence (seq, f);
if (q) {
for (i = 0; q[i]; i++)
wprintw (win, "%d ", q[i]);
} else {
waddstr (win, "<<No such sequence>>");
}
waddch (win, '\n');
}
/*
** cmdMark (count, undo, argc, argv) int count, undo, argc; char **argv;
** a debugging function for looking at sequence values.
*/
/*ARGSUSED*/
cmdMark(count, undo, argc, argv)
int count,
undo,
argc;
char **argv;
{
char seq[50];
struct seq *s;
wclear (botWin);
prt_action (" Enter a sequence name ");
*seq = '\0';
wclear (cmdWin);
if (mywgetstr (cmdWin, seq, 0) == 0)
return;
if (strcmp (seq, "All"))
print_sequence (seq, F, botWin);
else {
for (s = F->f_sequences; s; s = s->se_next)
print_sequence (s->se_name, F, botWin);
}
wrefresh (botWin);
}
free_sequences (f)
Reg3 FLDR *f;
{
Reg1 SEQ *sp;
Reg2 SEQ *tsp;
for (sp = f->f_sequences; sp;) {
Free ((char *)sp->se_msgs);
Free ((char *)sp->se_name);
tsp = sp->se_next;
Free ((char *)sp);
sp = tsp;
}
}