
/*
 * m_seqnew.c -- manage sequences
 *
 * $Id$
 */

#include <h/mh.h>

/*
 * static prototypes
 */
static int m_seqok (char *);


int
m_seqnew (struct msgs *mp, char *cp, int public)
{
    int i, j;

    if (!m_seqok (cp))
	return 0;

    if (public == -1)
	public = !(mp->msgflags & READONLY);

    for (i = 0; mp->msgattrs[i]; i++)
	if (!strcmp (mp->msgattrs[i], cp)) {
	    for (j = mp->lowmsg; j <= mp->hghmsg; j++)
		mp->msgstats[j] &= ~(1 << (FFATTRSLOT + i));
	    if (public)
		mp->attrstats &= ~(1 << (FFATTRSLOT + i));
	    else
		mp->attrstats |= 1 << (FFATTRSLOT + i);
	    mp->msgflags |= SEQMOD;

	    return 1;
	}

    if (i >= NUMATTRS) {
	advise (NULL, "only %d sequences allowed (no room for %s)!",
		NUMATTRS, cp);
	return 0;
    }

    mp->msgattrs[i] = getcpy (cp);
    for (j = mp->lowmsg; j <= mp->hghmsg; j++)
	mp->msgstats[j] &= ~(1 << (FFATTRSLOT + i));
    if (public)
	mp->attrstats &= ~(1 << (FFATTRSLOT + i));
    else
	mp->attrstats |= 1 << (FFATTRSLOT + i);
    mp->msgflags |= SEQMOD;

    mp->msgattrs[++i] = NULL;

    return 1;
}


int
m_seqadd (struct msgs *mp, char *cp, int j, int public)
{
    int i, k;

    if (!m_seqok (cp))
	return 0;

    /* keep mp->curmsg & msgattrs["cur"] in sync - see m_seq() */
    if (!strcmp (current,cp))
	mp->curmsg = j;	

    if (public == -1)		/* XXX */
	public = !(mp->msgflags & READONLY);

    for (i = 0; mp->msgattrs[i]; i++)
	if (!strcmp (mp->msgattrs[i], cp)) {
	    mp->msgstats[j] |= 1 << (FFATTRSLOT + i);
	    if (public)
		mp->attrstats &= ~(1 << (FFATTRSLOT + i));
	    else
		mp->attrstats |= 1 << (FFATTRSLOT + i);
	    mp->msgflags |= SEQMOD;

	    return 1;
	}

    if (i >= NUMATTRS) {
	advise (NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp);
	return 0;
    }

    mp->msgattrs[i] = getcpy (cp);
    for (k = mp->lowmsg; k <= mp->hghmsg; k++)
	mp->msgstats[k] &= ~(1 << (FFATTRSLOT + i));
    mp->msgstats[j] |= 1 << (FFATTRSLOT + i);
    if (public)
	mp->attrstats &= ~(1 << (FFATTRSLOT + i));
    else
	mp->attrstats |= 1 << (FFATTRSLOT + i);
    mp->msgflags |= SEQMOD;

    mp->msgattrs[++i] = NULL;

    return 1;
}


int
m_seqdel (struct msgs *mp, char *cp, int j)
{
    int i;

    if (!m_seqok (cp))
	return 0;

    for (i = 0; mp->msgattrs[i]; i++)
	if (!strcmp (mp->msgattrs[i], cp)) {
	    mp->msgstats[j] &= ~(1 << (FFATTRSLOT + i));
	    mp->msgflags |= SEQMOD;

	    return 1;
	}

    advise (NULL, "no such sequence as %s", cp);
    return 0;
}


/*
 * check if a sequence name is ok
 */

static int
m_seqok (char *s)
{
    char *pp;

    if (!s || !*s) {
	advise (NULL, "empty sequence name");
	return 0;
    }

    /*
     * Make sure sequence name doesn't clash with one
     * of the `reserved' sequence names.
     */
    if (!(strcmp (s, "new")
#if 0
	    && strcmp (s, "cur")
#endif
	    && strcmp (s, "all")
	    && strcmp (s, "first")
	    && strcmp (s, "last")
	    && strcmp (s, "prev")
	    && strcmp (s, "next"))) {
	advise (NULL, "illegal sequence name: %s", s);
	return 0;
    }

    /*
     * First character in a sequence name must be
     * an alphabetic character ...
     */
    if (!isalpha (*s)) {
	advise (NULL, "illegal sequence name: %s", s);
	return 0;
    }

    /*
     * and can be followed by zero or more alphanumeric characters
     */
    for (pp = s + 1; *pp; pp++)
	if (!isalnum (*pp)) {
	    advise (NULL, "illegal sequence name: %s", s);
	    return 0;
	}

    return 1;
}
