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