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