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