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