119304Speter/*-
219304Speter * Copyright (c) 1992, 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
13254225Speterstatic const char sccsid[] = "$Id: seq.c,v 10.18 2011/12/11 23:13:00 zy Exp $";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
18254225Speter#include <sys/time.h>
1919304Speter
2019304Speter#include <bitstring.h>
2119304Speter#include <ctype.h>
2219304Speter#include <errno.h>
2319304Speter#include <limits.h>
2419304Speter#include <stdio.h>
2519304Speter#include <stdlib.h>
2619304Speter#include <string.h>
2719304Speter
2819304Speter#include "common.h"
2919304Speter
3019304Speter/*
3119304Speter * seq_set --
3219304Speter *	Internal version to enter a sequence.
3319304Speter *
3419304Speter * PUBLIC: int seq_set __P((SCR *, CHAR_T *,
3519304Speter * PUBLIC:    size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
3619304Speter */
3719304Speterint
38254225Speterseq_set(
39254225Speter	SCR *sp,
40254225Speter	CHAR_T *name,
41254225Speter	size_t nlen,
42254225Speter	CHAR_T *input,
43254225Speter	size_t ilen,
44254225Speter	CHAR_T *output,
45254225Speter	size_t olen,
46254225Speter	seq_t stype,
47254225Speter	int flags)
4819304Speter{
4919304Speter	CHAR_T *p;
5019304Speter	SEQ *lastqp, *qp;
5119304Speter	int sv_errno;
5219304Speter
5319304Speter	/*
5419304Speter	 * An input string must always be present.  The output string
5519304Speter	 * can be NULL, when set internally, that's how we throw away
5619304Speter	 * input.
5719304Speter	 *
5819304Speter	 * Just replace the output field if the string already set.
5919304Speter	 */
6019304Speter	if ((qp =
6119304Speter	    seq_find(sp, &lastqp, NULL, input, ilen, stype, NULL)) != NULL) {
6219304Speter		if (LF_ISSET(SEQ_NOOVERWRITE))
6319304Speter			return (0);
6419304Speter		if (output == NULL || olen == 0) {
6519304Speter			p = NULL;
6619304Speter			olen = 0;
67254225Speter		} else if ((p = v_wstrdup(sp, output, olen)) == NULL) {
6819304Speter			sv_errno = errno;
6919304Speter			goto mem1;
7019304Speter		}
7119304Speter		if (qp->output != NULL)
7219304Speter			free(qp->output);
7319304Speter		qp->olen = olen;
7419304Speter		qp->output = p;
7519304Speter		return (0);
7619304Speter	}
7719304Speter
7819304Speter	/* Allocate and initialize SEQ structure. */
7919304Speter	CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ));
8019304Speter	if (qp == NULL) {
8119304Speter		sv_errno = errno;
8219304Speter		goto mem1;
8319304Speter	}
8419304Speter
8519304Speter	/* Name. */
8619304Speter	if (name == NULL || nlen == 0)
8719304Speter		qp->name = NULL;
88254225Speter	else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) {
8919304Speter		sv_errno = errno;
9019304Speter		goto mem2;
9119304Speter	}
9219304Speter	qp->nlen = nlen;
9319304Speter
9419304Speter	/* Input. */
95254225Speter	if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) {
9619304Speter		sv_errno = errno;
9719304Speter		goto mem3;
9819304Speter	}
9919304Speter	qp->ilen = ilen;
10019304Speter
10119304Speter	/* Output. */
10219304Speter	if (output == NULL) {
10319304Speter		qp->output = NULL;
10419304Speter		olen = 0;
105254225Speter	} else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) {
10619304Speter		sv_errno = errno;
10719304Speter		free(qp->input);
10819304Spetermem3:		if (qp->name != NULL)
10919304Speter			free(qp->name);
11019304Spetermem2:		free(qp);
11119304Spetermem1:		errno = sv_errno;
11219304Speter		msgq(sp, M_SYSERR, NULL);
11319304Speter		return (1);
11419304Speter	}
11519304Speter	qp->olen = olen;
11619304Speter
11719304Speter	/* Type, flags. */
11819304Speter	qp->stype = stype;
11919304Speter	qp->flags = flags;
12019304Speter
12119304Speter	/* Link into the chain. */
12219304Speter	if (lastqp == NULL) {
123254225Speter		SLIST_INSERT_HEAD(sp->gp->seqq, qp, q);
12419304Speter	} else {
125254225Speter		SLIST_INSERT_AFTER(lastqp, qp, q);
12619304Speter	}
12719304Speter
12819304Speter	/* Set the fast lookup bit. */
129254225Speter	if ((qp->input[0] & ~MAX_BIT_SEQ) == 0)
13019304Speter		bit_set(sp->gp->seqb, qp->input[0]);
13119304Speter
13219304Speter	return (0);
13319304Speter}
13419304Speter
13519304Speter/*
13619304Speter * seq_delete --
13719304Speter *	Delete a sequence.
13819304Speter *
13919304Speter * PUBLIC: int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
14019304Speter */
14119304Speterint
142254225Speterseq_delete(
143254225Speter	SCR *sp,
144254225Speter	CHAR_T *input,
145254225Speter	size_t ilen,
146254225Speter	seq_t stype)
14719304Speter{
148254225Speter	SEQ *qp, *pre_qp = NULL;
149254225Speter	int diff;
15019304Speter
151254225Speter	SLIST_FOREACH(qp, sp->gp->seqq, q) {
152254225Speter		if (qp->stype == stype && qp->ilen == ilen) {
153254225Speter			diff = MEMCMP(qp->input, input, ilen);
154254225Speter			if (!diff) {
155254225Speter				if (F_ISSET(qp, SEQ_FUNCMAP))
156254225Speter					break;
157254225Speter				if (qp == SLIST_FIRST(sp->gp->seqq))
158254225Speter					SLIST_REMOVE_HEAD(sp->gp->seqq, q);
159254225Speter				else
160254225Speter					SLIST_REMOVE_AFTER(pre_qp, q);
161254225Speter				return (seq_free(qp));
162254225Speter			}
163254225Speter			if (diff > 0)
164254225Speter				break;
165254225Speter		}
166254225Speter		pre_qp = qp;
167254225Speter	}
168254225Speter	return (1);
16919304Speter}
17019304Speter
17119304Speter/*
172254225Speter * seq_free --
173254225Speter *	Free a map entry.
17419304Speter *
175254225Speter * PUBLIC: int seq_free __P((SEQ *));
17619304Speter */
17719304Speterint
178254225Speterseq_free(SEQ *qp)
17919304Speter{
18019304Speter	if (qp->name != NULL)
18119304Speter		free(qp->name);
182254225Speter	if (qp->input != NULL)
183254225Speter		free(qp->input);
18419304Speter	if (qp->output != NULL)
18519304Speter		free(qp->output);
18619304Speter	free(qp);
18719304Speter	return (0);
18819304Speter}
18919304Speter
19019304Speter/*
19119304Speter * seq_find --
19219304Speter *	Search the sequence list for a match to a buffer, if ispartial
19319304Speter *	isn't NULL, partial matches count.
19419304Speter *
19519304Speter * PUBLIC: SEQ *seq_find
19619304Speter * PUBLIC:    __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
19719304Speter */
19819304SpeterSEQ *
199254225Speterseq_find(
200254225Speter	SCR *sp,
201254225Speter	SEQ **lastqp,
202254225Speter	EVENT *e_input,
203254225Speter	CHAR_T *c_input,
204254225Speter	size_t ilen,
205254225Speter	seq_t stype,
206254225Speter	int *ispartialp)
20719304Speter{
208254225Speter	SEQ *lqp = NULL, *qp;
20919304Speter	int diff;
21019304Speter
21119304Speter	/*
21219304Speter	 * Ispartialp is a location where we return if there was a
21319304Speter	 * partial match, i.e. if the string were extended it might
21419304Speter	 * match something.
21519304Speter	 *
21619304Speter	 * XXX
21719304Speter	 * Overload the meaning of ispartialp; only the terminal key
21819304Speter	 * search doesn't want the search limited to complete matches,
21919304Speter	 * i.e. ilen may be longer than the match.
22019304Speter	 */
22119304Speter	if (ispartialp != NULL)
22219304Speter		*ispartialp = 0;
223254225Speter	for (qp = SLIST_FIRST(sp->gp->seqq); qp != NULL;
224254225Speter	    lqp = qp, qp = SLIST_NEXT(qp, q)) {
22519304Speter		/*
22619304Speter		 * Fast checks on the first character and type, and then
22719304Speter		 * a real comparison.
22819304Speter		 */
22919304Speter		if (e_input == NULL) {
23019304Speter			if (qp->input[0] > c_input[0])
23119304Speter				break;
23219304Speter			if (qp->input[0] < c_input[0] ||
23319304Speter			    qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
23419304Speter				continue;
235254225Speter			diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen));
23619304Speter		} else {
23719304Speter			if (qp->input[0] > e_input->e_c)
23819304Speter				break;
23919304Speter			if (qp->input[0] < e_input->e_c ||
24019304Speter			    qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
24119304Speter				continue;
24219304Speter			diff =
24319304Speter			    e_memcmp(qp->input, e_input, MIN(qp->ilen, ilen));
24419304Speter		}
24519304Speter		if (diff > 0)
24619304Speter			break;
24719304Speter		if (diff < 0)
24819304Speter			continue;
24919304Speter		/*
25019304Speter		 * If the entry is the same length as the string, return a
25119304Speter		 * match.  If the entry is shorter than the string, return a
25219304Speter		 * match if called from the terminal key routine.  Otherwise,
25319304Speter		 * keep searching for a complete match.
25419304Speter		 */
25519304Speter		if (qp->ilen <= ilen) {
25619304Speter			if (qp->ilen == ilen || ispartialp != NULL) {
25719304Speter				if (lastqp != NULL)
25819304Speter					*lastqp = lqp;
25919304Speter				return (qp);
26019304Speter			}
26119304Speter			continue;
26219304Speter		}
26319304Speter		/*
26419304Speter		 * If the entry longer than the string, return partial match
26519304Speter		 * if called from the terminal key routine.  Otherwise, no
26619304Speter		 * match.
26719304Speter		 */
26819304Speter		if (ispartialp != NULL)
26919304Speter			*ispartialp = 1;
27019304Speter		break;
27119304Speter	}
27219304Speter	if (lastqp != NULL)
27319304Speter		*lastqp = lqp;
27419304Speter	return (NULL);
27519304Speter}
27619304Speter
27719304Speter/*
27819304Speter * seq_close --
27919304Speter *	Discard all sequences.
28019304Speter *
28119304Speter * PUBLIC: void seq_close __P((GS *));
28219304Speter */
28319304Spetervoid
284254225Speterseq_close(GS *gp)
28519304Speter{
28619304Speter	SEQ *qp;
28719304Speter
288254225Speter	while ((qp = SLIST_FIRST(gp->seqq)) != NULL) {
289254225Speter		SLIST_REMOVE_HEAD(gp->seqq, q);
290254225Speter		(void)seq_free(qp);
29119304Speter	}
29219304Speter}
29319304Speter
29419304Speter/*
29519304Speter * seq_dump --
29619304Speter *	Display the sequence entries of a specified type.
29719304Speter *
29819304Speter * PUBLIC: int seq_dump __P((SCR *, seq_t, int));
29919304Speter */
30019304Speterint
301254225Speterseq_dump(
302254225Speter	SCR *sp,
303254225Speter	seq_t stype,
304254225Speter	int isname)
30519304Speter{
30619304Speter	CHAR_T *p;
30719304Speter	GS *gp;
30819304Speter	SEQ *qp;
30919304Speter	int cnt, len, olen;
31019304Speter
31119304Speter	cnt = 0;
31219304Speter	gp = sp->gp;
313254225Speter	SLIST_FOREACH(qp, sp->gp->seqq, q) {
31419304Speter		if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
31519304Speter			continue;
31619304Speter		++cnt;
31719304Speter		for (p = qp->input,
31819304Speter		    olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
31919304Speter			len += ex_puts(sp, KEY_NAME(sp, *p));
32019304Speter		for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
32119304Speter			len -= ex_puts(sp, " ");
32219304Speter
32319304Speter		if (qp->output != NULL)
32419304Speter			for (p = qp->output,
32519304Speter			    olen = qp->olen, len = 0; olen > 0; --olen, ++p)
32619304Speter				len += ex_puts(sp, KEY_NAME(sp, *p));
32719304Speter		else
32819304Speter			len = 0;
32919304Speter
33019304Speter		if (isname && qp->name != NULL) {
33119304Speter			for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
33219304Speter				len -= ex_puts(sp, " ");
33319304Speter			for (p = qp->name,
33419304Speter			    olen = qp->nlen; olen > 0; --olen, ++p)
33519304Speter				(void)ex_puts(sp, KEY_NAME(sp, *p));
33619304Speter		}
33719304Speter		(void)ex_puts(sp, "\n");
33819304Speter	}
33919304Speter	return (cnt);
34019304Speter}
34119304Speter
34219304Speter/*
34319304Speter * seq_save --
34419304Speter *	Save the sequence entries to a file.
34519304Speter *
34619304Speter * PUBLIC: int seq_save __P((SCR *, FILE *, char *, seq_t));
34719304Speter */
34819304Speterint
349254225Speterseq_save(
350254225Speter	SCR *sp,
351254225Speter	FILE *fp,
352254225Speter	char *prefix,
353254225Speter	seq_t stype)
35419304Speter{
35519304Speter	CHAR_T *p;
35619304Speter	SEQ *qp;
35719304Speter	size_t olen;
35819304Speter	int ch;
35919304Speter
36019304Speter	/* Write a sequence command for all keys the user defined. */
361254225Speter	SLIST_FOREACH(qp, sp->gp->seqq, q) {
36219304Speter		if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF))
36319304Speter			continue;
36419304Speter		if (prefix)
36519304Speter			(void)fprintf(fp, "%s", prefix);
36619304Speter		for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
36719304Speter			ch = *p++;
36819304Speter			if (ch == CH_LITERAL || ch == '|' ||
369254225Speter			    cmdskip(ch) || KEY_VAL(sp, ch) == K_NL)
37019304Speter				(void)putc(CH_LITERAL, fp);
37119304Speter			(void)putc(ch, fp);
37219304Speter		}
37319304Speter		(void)putc(' ', fp);
37419304Speter		if (qp->output != NULL)
37519304Speter			for (p = qp->output,
37619304Speter			    olen = qp->olen; olen > 0; --olen) {
37719304Speter				ch = *p++;
37819304Speter				if (ch == CH_LITERAL || ch == '|' ||
37919304Speter				    KEY_VAL(sp, ch) == K_NL)
38019304Speter					(void)putc(CH_LITERAL, fp);
38119304Speter				(void)putc(ch, fp);
38219304Speter			}
38319304Speter		(void)putc('\n', fp);
38419304Speter	}
38519304Speter	return (0);
38619304Speter}
38719304Speter
38819304Speter/*
38919304Speter * e_memcmp --
39019304Speter *	Compare a string of EVENT's to a string of CHAR_T's.
39119304Speter *
39219304Speter * PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t));
39319304Speter */
39419304Speterint
395254225Spetere_memcmp(
396254225Speter	CHAR_T *p1,
397254225Speter	EVENT *ep,
398254225Speter	size_t n)
39919304Speter{
40019304Speter	if (n != 0) {
40119304Speter                do {
40219304Speter                        if (*p1++ != ep->e_c)
40319304Speter                                return (*--p1 - ep->e_c);
40419304Speter			++ep;
40519304Speter                } while (--n != 0);
40619304Speter        }
40719304Speter        return (0);
40819304Speter}
409