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