Home | History | Annotate | Line # | Download | only in common
      1 /*	$NetBSD: seq.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */
      2 /*-
      3  * Copyright (c) 1992, 1993, 1994
      4  *	The Regents of the University of California.  All rights reserved.
      5  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  *	Keith Bostic.  All rights reserved.
      7  *
      8  * See the LICENSE file for redistribution information.
      9  */
     10 
     11 #include "config.h"
     12 
     13 #include <sys/cdefs.h>
     14 #if 0
     15 #ifndef lint
     16 static const char sccsid[] = "Id: seq.c,v 10.15 2001/06/25 15:19:12 skimo Exp  (Berkeley) Date: 2001/06/25 15:19:12 ";
     17 #endif /* not lint */
     18 #else
     19 __RCSID("$NetBSD: seq.c,v 1.4 2014/01/26 21:43:45 christos Exp $");
     20 #endif
     21 
     22 #include <sys/types.h>
     23 #include <sys/queue.h>
     24 
     25 #include <bitstring.h>
     26 #include <ctype.h>
     27 #include <errno.h>
     28 #include <limits.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 
     33 #include "common.h"
     34 
     35 /*
     36  * seq_set --
     37  *	Internal version to enter a sequence.
     38  *
     39  * PUBLIC: int seq_set __P((SCR *, CHAR_T *,
     40  * PUBLIC:    size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int));
     41  */
     42 int
     43 seq_set(SCR *sp, CHAR_T *name, size_t nlen, CHAR_T *input, size_t ilen, CHAR_T *output, size_t olen, seq_t stype, int flags)
     44 {
     45 	CHAR_T *p;
     46 	SEQ *lastqp, *qp;
     47 	int sv_errno;
     48 
     49 	/*
     50 	 * An input string must always be present.  The output string
     51 	 * can be NULL, when set internally, that's how we throw away
     52 	 * input.
     53 	 *
     54 	 * Just replace the output field if the string already set.
     55 	 */
     56 	if ((qp =
     57 	    seq_find(sp, &lastqp, NULL, input, ilen, stype, NULL)) != NULL) {
     58 		if (LF_ISSET(SEQ_NOOVERWRITE))
     59 			return (0);
     60 		if (output == NULL || olen == 0) {
     61 			p = NULL;
     62 			olen = 0;
     63 		} else if ((p = v_wstrdup(sp, output, olen)) == NULL) {
     64 			sv_errno = errno;
     65 			goto mem1;
     66 		}
     67 		if (qp->output != NULL)
     68 			free(qp->output);
     69 		qp->olen = olen;
     70 		qp->output = p;
     71 		return (0);
     72 	}
     73 
     74 	/* Allocate and initialize SEQ structure. */
     75 	CALLOC(sp, qp, SEQ *, 1, sizeof(SEQ));
     76 	if (qp == NULL) {
     77 		sv_errno = errno;
     78 		goto mem1;
     79 	}
     80 
     81 	/* Name. */
     82 	if (name == NULL || nlen == 0)
     83 		qp->name = NULL;
     84 	else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) {
     85 		sv_errno = errno;
     86 		goto mem2;
     87 	}
     88 	qp->nlen = nlen;
     89 
     90 	/* Input. */
     91 	if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) {
     92 		sv_errno = errno;
     93 		goto mem3;
     94 	}
     95 	qp->ilen = ilen;
     96 
     97 	/* Output. */
     98 	if (output == NULL) {
     99 		qp->output = NULL;
    100 		olen = 0;
    101 	} else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) {
    102 		sv_errno = errno;
    103 		free(qp->input);
    104 mem3:		if (qp->name != NULL)
    105 			free(qp->name);
    106 mem2:		free(qp);
    107 mem1:		errno = sv_errno;
    108 		msgq(sp, M_SYSERR, NULL);
    109 		return (1);
    110 	}
    111 	qp->olen = olen;
    112 
    113 	/* Type, flags. */
    114 	qp->stype = stype;
    115 	qp->flags = flags;
    116 
    117 	/* Link into the chain. */
    118 	if (lastqp == NULL) {
    119 		LIST_INSERT_HEAD(&sp->gp->seqq, qp, q);
    120 	} else {
    121 		LIST_INSERT_AFTER(lastqp, qp, q);
    122 	}
    123 
    124 	/* Set the fast lookup bit. */
    125 	if ((qp->input[0] & ~MAX_BIT_SEQ) == 0)
    126 		bit_set(sp->gp->seqb, qp->input[0]);
    127 
    128 	return (0);
    129 }
    130 
    131 /*
    132  * seq_delete --
    133  *	Delete a sequence.
    134  *
    135  * PUBLIC: int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t));
    136  */
    137 int
    138 seq_delete(SCR *sp, CHAR_T *input, size_t ilen, seq_t stype)
    139 {
    140 	SEQ *qp;
    141 
    142 	if ((qp = seq_find(sp, NULL, NULL, input, ilen, stype, NULL)) == NULL)
    143 		return (1);
    144 	return (seq_mdel(qp));
    145 }
    146 
    147 /*
    148  * seq_mdel --
    149  *	Delete a map entry, without lookup.
    150  *
    151  * PUBLIC: int seq_mdel __P((SEQ *));
    152  */
    153 int
    154 seq_mdel(SEQ *qp)
    155 {
    156 	LIST_REMOVE(qp, q);
    157 	if (qp->name != NULL)
    158 		free(qp->name);
    159 	free(qp->input);
    160 	if (qp->output != NULL)
    161 		free(qp->output);
    162 	free(qp);
    163 	return (0);
    164 }
    165 
    166 /*
    167  * seq_find --
    168  *	Search the sequence list for a match to a buffer, if ispartial
    169  *	isn't NULL, partial matches count.
    170  *
    171  * PUBLIC: SEQ *seq_find
    172  * PUBLIC:    __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *));
    173  */
    174 SEQ *
    175 seq_find(SCR *sp, SEQ **lastqp, EVENT *e_input, CHAR_T *c_input, size_t ilen, seq_t stype, int *ispartialp)
    176 {
    177 	SEQ *lqp, *qp;
    178 	int diff;
    179 
    180 	/*
    181 	 * Ispartialp is a location where we return if there was a
    182 	 * partial match, i.e. if the string were extended it might
    183 	 * match something.
    184 	 *
    185 	 * XXX
    186 	 * Overload the meaning of ispartialp; only the terminal key
    187 	 * search doesn't want the search limited to complete matches,
    188 	 * i.e. ilen may be longer than the match.
    189 	 */
    190 	if (ispartialp != NULL)
    191 		*ispartialp = 0;
    192 
    193 	for (lqp = NULL, qp = LIST_FIRST(&sp->gp->seqq);
    194 	    qp != NULL;
    195 	    lqp = qp, qp = LIST_NEXT(qp, q)) {
    196 		/*
    197 		 * Fast checks on the first character and type, and then
    198 		 * a real comparison.
    199 		 */
    200 		if (e_input == NULL) {
    201 			if (qp->input[0] > c_input[0])
    202 				break;
    203 			if (qp->input[0] < c_input[0] ||
    204 			    qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
    205 				continue;
    206 			diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen));
    207 		} else {
    208 			if (qp->input[0] > e_input->e_c)
    209 				break;
    210 			if (qp->input[0] < e_input->e_c ||
    211 			    qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP))
    212 				continue;
    213 			diff =
    214 			    e_memcmp(qp->input, e_input, MIN(qp->ilen, ilen));
    215 		}
    216 		if (diff > 0)
    217 			break;
    218 		if (diff < 0)
    219 			continue;
    220 		/*
    221 		 * If the entry is the same length as the string, return a
    222 		 * match.  If the entry is shorter than the string, return a
    223 		 * match if called from the terminal key routine.  Otherwise,
    224 		 * keep searching for a complete match.
    225 		 */
    226 		if (qp->ilen <= ilen) {
    227 			if (qp->ilen == ilen || ispartialp != NULL) {
    228 				if (lastqp != NULL)
    229 					*lastqp = lqp;
    230 				return (qp);
    231 			}
    232 			continue;
    233 		}
    234 		/*
    235 		 * If the entry longer than the string, return partial match
    236 		 * if called from the terminal key routine.  Otherwise, no
    237 		 * match.
    238 		 */
    239 		if (ispartialp != NULL)
    240 			*ispartialp = 1;
    241 		break;
    242 	}
    243 	if (lastqp != NULL)
    244 		*lastqp = lqp;
    245 	return (NULL);
    246 }
    247 
    248 /*
    249  * seq_close --
    250  *	Discard all sequences.
    251  *
    252  * PUBLIC: void seq_close __P((GS *));
    253  */
    254 void
    255 seq_close(GS *gp)
    256 {
    257 	SEQ *qp;
    258 
    259 	while ((qp = LIST_FIRST(&gp->seqq)) != NULL) {
    260 		if (qp->name != NULL)
    261 			free(qp->name);
    262 		if (qp->input != NULL)
    263 			free(qp->input);
    264 		if (qp->output != NULL)
    265 			free(qp->output);
    266 		LIST_REMOVE(qp, q);
    267 		free(qp);
    268 	}
    269 }
    270 
    271 /*
    272  * seq_dump --
    273  *	Display the sequence entries of a specified type.
    274  *
    275  * PUBLIC: int seq_dump __P((SCR *, seq_t, int));
    276  */
    277 int
    278 seq_dump(SCR *sp, seq_t stype, int isname)
    279 {
    280 	CHAR_T *p;
    281 	GS *gp;
    282 	SEQ *qp;
    283 	int cnt, len, olen;
    284 
    285 	cnt = 0;
    286 	gp = sp->gp;
    287 	LIST_FOREACH(qp, &gp->seqq, q) {
    288 		if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP))
    289 			continue;
    290 		++cnt;
    291 		for (p = qp->input,
    292 		    olen = qp->ilen, len = 0; olen > 0; --olen, ++p)
    293 			len += ex_puts(sp, (char *)KEY_NAME(sp, *p));
    294 		for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
    295 			len -= ex_puts(sp, " ");
    296 
    297 		if (qp->output != NULL)
    298 			for (p = qp->output,
    299 			    olen = qp->olen, len = 0; olen > 0; --olen, ++p)
    300 				len += ex_puts(sp, (char *)KEY_NAME(sp, *p));
    301 		else
    302 			len = 0;
    303 
    304 		if (isname && qp->name != NULL) {
    305 			for (len = STANDARD_TAB - len % STANDARD_TAB; len > 0;)
    306 				len -= ex_puts(sp, " ");
    307 			for (p = qp->name,
    308 			    olen = qp->nlen; olen > 0; --olen, ++p)
    309 				(void)ex_puts(sp, (char *)KEY_NAME(sp, *p));
    310 		}
    311 		(void)ex_puts(sp, "\n");
    312 	}
    313 	return (cnt);
    314 }
    315 
    316 /*
    317  * seq_save --
    318  *	Save the sequence entries to a file.
    319  *
    320  * PUBLIC: int seq_save __P((SCR *, FILE *, const char *, seq_t));
    321  */
    322 int
    323 seq_save(SCR *sp, FILE *fp, const char *prefix, seq_t stype)
    324 {
    325 	CHAR_T *p;
    326 	SEQ *qp;
    327 	size_t olen;
    328 	ARG_CHAR_T ch;
    329 
    330 	/* Write a sequence command for all keys the user defined. */
    331 	LIST_FOREACH(qp, &sp->gp->seqq, q) {
    332 		if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF))
    333 			continue;
    334 		if (prefix)
    335 			(void)fprintf(fp, "%s", prefix);
    336 		for (p = qp->input, olen = qp->ilen; olen > 0; --olen) {
    337 			ch = (UCHAR_T)*p++;
    338 			if (ch == CH_LITERAL || ch == '|' ||
    339 			    ISBLANK(ch) || KEY_VAL(sp, ch) == K_NL)
    340 				(void)putc(CH_LITERAL, fp);
    341 			(void)fprintf(fp, WC, ch);
    342 		}
    343 		(void)putc(' ', fp);
    344 		if (qp->output != NULL)
    345 			for (p = qp->output,
    346 			    olen = qp->olen; olen > 0; --olen) {
    347 				ch = (UCHAR_T)*p++;
    348 				if (ch == CH_LITERAL || ch == '|' ||
    349 				    KEY_VAL(sp, ch) == K_NL)
    350 					(void)putc(CH_LITERAL, fp);
    351 				(void)fprintf(fp, WC, ch);
    352 			}
    353 		(void)putc('\n', fp);
    354 	}
    355 	return (0);
    356 }
    357 
    358 /*
    359  * e_memcmp --
    360  *	Compare a string of EVENT's to a string of CHAR_T's.
    361  *
    362  * PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t));
    363  */
    364 int
    365 e_memcmp(CHAR_T *p1, EVENT *ep, size_t n)
    366 {
    367 	if (n != 0) {
    368                 do {
    369                         if (*p1++ != ep->e_c)
    370                                 return (*--p1 - ep->e_c);
    371 			++ep;
    372                 } while (--n != 0);
    373         }
    374         return (0);
    375 }
    376