|
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; } }