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