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