1 /* $NetBSD: history.c,v 1.28 2004/11/27 18:31:45 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Christos Zoulas of Cornell University. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "config.h" 36 #if !defined(lint) && !defined(SCCSID) 37 #if 0 38 static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; 39 #else 40 __RCSID("$NetBSD: history.c,v 1.28 2004/11/27 18:31:45 christos Exp $"); 41 #endif 42 #endif /* not lint && not SCCSID */ 43 44 /* 45 * hist.c: History access functions 46 */ 47 #include <string.h> 48 #include <stdlib.h> 49 #include <stdarg.h> 50 #ifdef HAVE_VIS_H 51 #include <vis.h> 52 #else 53 #include "np/vis.h" 54 #endif 55 #include <sys/stat.h> 56 57 static const char hist_cookie[] = "_HiStOrY_V2_\n"; 58 59 #include "histedit.h" 60 61 typedef int (*history_gfun_t)(ptr_t, HistEvent *); 62 typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *); 63 typedef void (*history_vfun_t)(ptr_t, HistEvent *); 64 typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int); 65 66 struct history { 67 ptr_t h_ref; /* Argument for history fcns */ 68 int h_ent; /* Last entry point for history */ 69 history_gfun_t h_first; /* Get the first element */ 70 history_gfun_t h_next; /* Get the next element */ 71 history_gfun_t h_last; /* Get the last element */ 72 history_gfun_t h_prev; /* Get the previous element */ 73 history_gfun_t h_curr; /* Get the current element */ 74 history_sfun_t h_set; /* Set the current element */ 75 history_vfun_t h_clear; /* Clear the history list */ 76 history_efun_t h_enter; /* Add an element */ 77 history_efun_t h_add; /* Append to an element */ 78 }; 79 80 #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev) 81 #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev) 82 #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev) 83 #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev) 84 #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev) 85 #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) 86 #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev) 87 #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) 88 #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) 89 90 #define h_strdup(a) strdup(a) 91 #define h_malloc(a) malloc(a) 92 #define h_realloc(a, b) realloc((a), (b)) 93 #define h_free(a) free(a) 94 95 typedef struct { 96 int num; 97 char *str; 98 } HistEventPrivate; 99 100 101 102 private int history_setsize(History *, HistEvent *, int); 103 private int history_getsize(History *, HistEvent *); 104 private int history_setunique(History *, HistEvent *, int); 105 private int history_getunique(History *, HistEvent *); 106 private int history_set_fun(History *, History *); 107 private int history_load(History *, const char *); 108 private int history_save(History *, const char *); 109 private int history_prev_event(History *, HistEvent *, int); 110 private int history_next_event(History *, HistEvent *, int); 111 private int history_next_string(History *, HistEvent *, const char *); 112 private int history_prev_string(History *, HistEvent *, const char *); 113 114 115 /***********************************************************************/ 116 117 /* 118 * Builtin- history implementation 119 */ 120 typedef struct hentry_t { 121 HistEvent ev; /* What we return */ 122 struct hentry_t *next; /* Next entry */ 123 struct hentry_t *prev; /* Previous entry */ 124 } hentry_t; 125 126 typedef struct history_t { 127 hentry_t list; /* Fake list header element */ 128 hentry_t *cursor; /* Current element in the list */ 129 int max; /* Maximum number of events */ 130 int cur; /* Current number of events */ 131 int eventid; /* For generation of unique event id */ 132 int flags; /* History flags */ 133 #define H_UNIQUE 1 /* Store only unique elements */ 134 } history_t; 135 136 private int history_def_first(ptr_t, HistEvent *); 137 private int history_def_last(ptr_t, HistEvent *); 138 private int history_def_next(ptr_t, HistEvent *); 139 private int history_def_prev(ptr_t, HistEvent *); 140 private int history_def_curr(ptr_t, HistEvent *); 141 private int history_def_set(ptr_t, HistEvent *, const int n); 142 private int history_def_enter(ptr_t, HistEvent *, const char *); 143 private int history_def_add(ptr_t, HistEvent *, const char *); 144 private int history_def_init(ptr_t *, HistEvent *, int); 145 private void history_def_clear(ptr_t, HistEvent *); 146 private int history_def_insert(history_t *, HistEvent *, const char *); 147 private void history_def_delete(history_t *, HistEvent *, hentry_t *); 148 149 #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num)) 150 #define history_def_getsize(p) (((history_t *)p)->cur) 151 #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0) 152 #define history_def_setunique(p, uni) \ 153 if (uni) \ 154 (((history_t *)p)->flags) |= H_UNIQUE; \ 155 else \ 156 (((history_t *)p)->flags) &= ~H_UNIQUE 157 158 #define he_strerror(code) he_errlist[code] 159 #define he_seterrev(evp, code) {\ 160 evp->num = code;\ 161 evp->str = he_strerror(code);\ 162 } 163 164 /* error messages */ 165 static const char *const he_errlist[] = { 166 "OK", 167 "unknown error", 168 "malloc() failed", 169 "first event not found", 170 "last event not found", 171 "empty list", 172 "no next event", 173 "no previous event", 174 "current event is invalid", 175 "event not found", 176 "can't read history from file", 177 "can't write history", 178 "required parameter(s) not supplied", 179 "history size negative", 180 "function not allowed with other history-functions-set the default", 181 "bad parameters" 182 }; 183 /* error codes */ 184 #define _HE_OK 0 185 #define _HE_UNKNOWN 1 186 #define _HE_MALLOC_FAILED 2 187 #define _HE_FIRST_NOTFOUND 3 188 #define _HE_LAST_NOTFOUND 4 189 #define _HE_EMPTY_LIST 5 190 #define _HE_END_REACHED 6 191 #define _HE_START_REACHED 7 192 #define _HE_CURR_INVALID 8 193 #define _HE_NOT_FOUND 9 194 #define _HE_HIST_READ 10 195 #define _HE_HIST_WRITE 11 196 #define _HE_PARAM_MISSING 12 197 #define _HE_SIZE_NEGATIVE 13 198 #define _HE_NOT_ALLOWED 14 199 #define _HE_BAD_PARAM 15 200 201 /* history_def_first(): 202 * Default function to return the first event in the history. 203 */ 204 private int 205 history_def_first(ptr_t p, HistEvent *ev) 206 { 207 history_t *h = (history_t *) p; 208 209 h->cursor = h->list.next; 210 if (h->cursor != &h->list) 211 *ev = h->cursor->ev; 212 else { 213 he_seterrev(ev, _HE_FIRST_NOTFOUND); 214 return (-1); 215 } 216 217 return (0); 218 } 219 220 221 /* history_def_last(): 222 * Default function to return the last event in the history. 223 */ 224 private int 225 history_def_last(ptr_t p, HistEvent *ev) 226 { 227 history_t *h = (history_t *) p; 228 229 h->cursor = h->list.prev; 230 if (h->cursor != &h->list) 231 *ev = h->cursor->ev; 232 else { 233 he_seterrev(ev, _HE_LAST_NOTFOUND); 234 return (-1); 235 } 236 237 return (0); 238 } 239 240 241 /* history_def_next(): 242 * Default function to return the next event in the history. 243 */ 244 private int 245 history_def_next(ptr_t p, HistEvent *ev) 246 { 247 history_t *h = (history_t *) p; 248 249 if (h->cursor == &h->list) { 250 he_seterrev(ev, _HE_EMPTY_LIST); 251 return (-1); 252 } 253 254 if (h->cursor->next == &h->list) { 255 he_seterrev(ev, _HE_END_REACHED); 256 return (-1); 257 } 258 259 h->cursor = h->cursor->next; 260 *ev = h->cursor->ev; 261 262 return (0); 263 } 264 265 266 /* history_def_prev(): 267 * Default function to return the previous event in the history. 268 */ 269 private int 270 history_def_prev(ptr_t p, HistEvent *ev) 271 { 272 history_t *h = (history_t *) p; 273 274 if (h->cursor == &h->list) { 275 he_seterrev(ev, 276 (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); 277 return (-1); 278 } 279 280 if (h->cursor->prev == &h->list) { 281 he_seterrev(ev, _HE_START_REACHED); 282 return (-1); 283 } 284 285 h->cursor = h->cursor->prev; 286 *ev = h->cursor->ev; 287 288 return (0); 289 } 290 291 292 /* history_def_curr(): 293 * Default function to return the current event in the history. 294 */ 295 private int 296 history_def_curr(ptr_t p, HistEvent *ev) 297 { 298 history_t *h = (history_t *) p; 299 300 if (h->cursor != &h->list) 301 *ev = h->cursor->ev; 302 else { 303 he_seterrev(ev, 304 (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST); 305 return (-1); 306 } 307 308 return (0); 309 } 310 311 312 /* history_def_set(): 313 * Default function to set the current event in the history to the 314 * given one. 315 */ 316 private int 317 history_def_set(ptr_t p, HistEvent *ev, const int n) 318 { 319 history_t *h = (history_t *) p; 320 321 if (h->cur == 0) { 322 he_seterrev(ev, _HE_EMPTY_LIST); 323 return (-1); 324 } 325 if (h->cursor == &h->list || h->cursor->ev.num != n) { 326 for (h->cursor = h->list.next; h->cursor != &h->list; 327 h->cursor = h->cursor->next) 328 if (h->cursor->ev.num == n) 329 break; 330 } 331 if (h->cursor == &h->list) { 332 he_seterrev(ev, _HE_NOT_FOUND); 333 return (-1); 334 } 335 return (0); 336 } 337 338 339 /* history_def_add(): 340 * Append string to element 341 */ 342 private int 343 history_def_add(ptr_t p, HistEvent *ev, const char *str) 344 { 345 history_t *h = (history_t *) p; 346 size_t len; 347 char *s; 348 HistEventPrivate *evp = (void *)&h->cursor->ev; 349 350 if (h->cursor == &h->list) 351 return (history_def_enter(p, ev, str)); 352 len = strlen(evp->str) + strlen(str) + 1; 353 s = (char *) h_malloc(len); 354 if (s == NULL) { 355 he_seterrev(ev, _HE_MALLOC_FAILED); 356 return (-1); 357 } 358 (void) strlcpy(s, h->cursor->ev.str, len); 359 (void) strlcat(s, str, len); 360 h_free((ptr_t)evp->str); 361 evp->str = s; 362 *ev = h->cursor->ev; 363 return (0); 364 } 365 366 367 /* history_def_delete(): 368 * Delete element hp of the h list 369 */ 370 /* ARGSUSED */ 371 private void 372 history_def_delete(history_t *h, 373 HistEvent *ev __attribute__((__unused__)), hentry_t *hp) 374 { 375 HistEventPrivate *evp = (void *)&hp->ev; 376 if (hp == &h->list) 377 abort(); 378 hp->prev->next = hp->next; 379 hp->next->prev = hp->prev; 380 h_free((ptr_t) evp->str); 381 h_free(hp); 382 h->cur--; 383 } 384 385 386 /* history_def_insert(): 387 * Insert element with string str in the h list 388 */ 389 private int 390 history_def_insert(history_t *h, HistEvent *ev, const char *str) 391 { 392 393 h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); 394 if (h->cursor == NULL) 395 goto oomem; 396 if ((h->cursor->ev.str = h_strdup(str)) == NULL) { 397 h_free((ptr_t)h->cursor); 398 goto oomem; 399 } 400 h->cursor->ev.num = ++h->eventid; 401 h->cursor->next = h->list.next; 402 h->cursor->prev = &h->list; 403 h->list.next->prev = h->cursor; 404 h->list.next = h->cursor; 405 h->cur++; 406 407 *ev = h->cursor->ev; 408 return (0); 409 oomem: 410 he_seterrev(ev, _HE_MALLOC_FAILED); 411 return (-1); 412 } 413 414 415 /* history_def_enter(): 416 * Default function to enter an item in the history 417 */ 418 private int 419 history_def_enter(ptr_t p, HistEvent *ev, const char *str) 420 { 421 history_t *h = (history_t *) p; 422 423 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && 424 strcmp(h->list.next->ev.str, str) == 0) 425 return (0); 426 427 if (history_def_insert(h, ev, str) == -1) 428 return (-1); /* error, keep error message */ 429 430 /* 431 * Always keep at least one entry. 432 * This way we don't have to check for the empty list. 433 */ 434 while (h->cur > h->max && h->cur > 0) 435 history_def_delete(h, ev, h->list.prev); 436 437 return (1); 438 } 439 440 441 /* history_def_init(): 442 * Default history initialization function 443 */ 444 /* ARGSUSED */ 445 private int 446 history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n) 447 { 448 history_t *h = (history_t *) h_malloc(sizeof(history_t)); 449 if (h == NULL) 450 return -1; 451 452 if (n <= 0) 453 n = 0; 454 h->eventid = 0; 455 h->cur = 0; 456 h->max = n; 457 h->list.next = h->list.prev = &h->list; 458 h->list.ev.str = NULL; 459 h->list.ev.num = 0; 460 h->cursor = &h->list; 461 h->flags = 0; 462 *p = (ptr_t) h; 463 return 0; 464 } 465 466 467 /* history_def_clear(): 468 * Default history cleanup function 469 */ 470 private void 471 history_def_clear(ptr_t p, HistEvent *ev) 472 { 473 history_t *h = (history_t *) p; 474 475 while (h->list.prev != &h->list) 476 history_def_delete(h, ev, h->list.prev); 477 h->eventid = 0; 478 h->cur = 0; 479 } 480 481 482 483 484 /************************************************************************/ 485 486 /* history_init(): 487 * Initialization function. 488 */ 489 public History * 490 history_init(void) 491 { 492 HistEvent ev; 493 History *h = (History *) h_malloc(sizeof(History)); 494 if (h == NULL) 495 return NULL; 496 497 if (history_def_init(&h->h_ref, &ev, 0) == -1) { 498 h_free((ptr_t)h); 499 return NULL; 500 } 501 h->h_ent = -1; 502 h->h_next = history_def_next; 503 h->h_first = history_def_first; 504 h->h_last = history_def_last; 505 h->h_prev = history_def_prev; 506 h->h_curr = history_def_curr; 507 h->h_set = history_def_set; 508 h->h_clear = history_def_clear; 509 h->h_enter = history_def_enter; 510 h->h_add = history_def_add; 511 512 return (h); 513 } 514 515 516 /* history_end(): 517 * clean up history; 518 */ 519 public void 520 history_end(History *h) 521 { 522 HistEvent ev; 523 524 if (h->h_next == history_def_next) 525 history_def_clear(h->h_ref, &ev); 526 } 527 528 529 530 /* history_setsize(): 531 * Set history number of events 532 */ 533 private int 534 history_setsize(History *h, HistEvent *ev, int num) 535 { 536 537 if (h->h_next != history_def_next) { 538 he_seterrev(ev, _HE_NOT_ALLOWED); 539 return (-1); 540 } 541 if (num < 0) { 542 he_seterrev(ev, _HE_BAD_PARAM); 543 return (-1); 544 } 545 history_def_setsize(h->h_ref, num); 546 return (0); 547 } 548 549 550 /* history_getsize(): 551 * Get number of events currently in history 552 */ 553 private int 554 history_getsize(History *h, HistEvent *ev) 555 { 556 if (h->h_next != history_def_next) { 557 he_seterrev(ev, _HE_NOT_ALLOWED); 558 return (-1); 559 } 560 ev->num = history_def_getsize(h->h_ref); 561 if (ev->num < -1) { 562 he_seterrev(ev, _HE_SIZE_NEGATIVE); 563 return (-1); 564 } 565 return (0); 566 } 567 568 569 /* history_setunique(): 570 * Set if adjacent equal events should not be entered in history. 571 */ 572 private int 573 history_setunique(History *h, HistEvent *ev, int uni) 574 { 575 576 if (h->h_next != history_def_next) { 577 he_seterrev(ev, _HE_NOT_ALLOWED); 578 return (-1); 579 } 580 history_def_setunique(h->h_ref, uni); 581 return (0); 582 } 583 584 585 /* history_getunique(): 586 * Get if adjacent equal events should not be entered in history. 587 */ 588 private int 589 history_getunique(History *h, HistEvent *ev) 590 { 591 if (h->h_next != history_def_next) { 592 he_seterrev(ev, _HE_NOT_ALLOWED); 593 return (-1); 594 } 595 ev->num = history_def_getunique(h->h_ref); 596 return (0); 597 } 598 599 600 /* history_set_fun(): 601 * Set history functions 602 */ 603 private int 604 history_set_fun(History *h, History *nh) 605 { 606 HistEvent ev; 607 608 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || 609 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || 610 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || 611 nh->h_ref == NULL) { 612 if (h->h_next != history_def_next) { 613 history_def_init(&h->h_ref, &ev, 0); 614 h->h_first = history_def_first; 615 h->h_next = history_def_next; 616 h->h_last = history_def_last; 617 h->h_prev = history_def_prev; 618 h->h_curr = history_def_curr; 619 h->h_set = history_def_set; 620 h->h_clear = history_def_clear; 621 h->h_enter = history_def_enter; 622 h->h_add = history_def_add; 623 } 624 return (-1); 625 } 626 if (h->h_next == history_def_next) 627 history_def_clear(h->h_ref, &ev); 628 629 h->h_ent = -1; 630 h->h_first = nh->h_first; 631 h->h_next = nh->h_next; 632 h->h_last = nh->h_last; 633 h->h_prev = nh->h_prev; 634 h->h_curr = nh->h_curr; 635 h->h_set = nh->h_set; 636 h->h_clear = nh->h_clear; 637 h->h_enter = nh->h_enter; 638 h->h_add = nh->h_add; 639 640 return (0); 641 } 642 643 644 /* history_load(): 645 * History load function 646 */ 647 private int 648 history_load(History *h, const char *fname) 649 { 650 FILE *fp; 651 char *line; 652 size_t sz, max_size; 653 char *ptr; 654 int i = -1; 655 HistEvent ev; 656 657 if ((fp = fopen(fname, "r")) == NULL) 658 return (i); 659 660 if ((line = fgetln(fp, &sz)) == NULL) 661 goto done; 662 663 if (strncmp(line, hist_cookie, sz) != 0) 664 goto done; 665 666 ptr = h_malloc(max_size = 1024); 667 if (ptr == NULL) 668 goto done; 669 for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) { 670 char c = line[sz]; 671 672 if (sz != 0 && line[sz - 1] == '\n') 673 line[--sz] = '\0'; 674 else 675 line[sz] = '\0'; 676 677 if (max_size < sz) { 678 char *nptr; 679 max_size = (sz + 1024) & ~1023; 680 nptr = h_realloc(ptr, max_size); 681 if (nptr == NULL) { 682 i = -1; 683 goto oomem; 684 } 685 ptr = nptr; 686 } 687 (void) strunvis(ptr, line); 688 line[sz] = c; 689 if (HENTER(h, &ev, ptr) == -1) { 690 h_free((ptr_t)ptr); 691 return -1; 692 } 693 } 694 oomem: 695 h_free((ptr_t)ptr); 696 done: 697 (void) fclose(fp); 698 return (i); 699 } 700 701 702 /* history_save(): 703 * History save function 704 */ 705 private int 706 history_save(History *h, const char *fname) 707 { 708 FILE *fp; 709 HistEvent ev; 710 int i = -1, retval; 711 size_t len, max_size; 712 char *ptr; 713 714 if ((fp = fopen(fname, "w")) == NULL) 715 return (-1); 716 717 if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) 718 goto done; 719 if (fputs(hist_cookie, fp) == EOF) 720 goto done; 721 ptr = h_malloc(max_size = 1024); 722 if (ptr == NULL) 723 goto done; 724 for (i = 0, retval = HLAST(h, &ev); 725 retval != -1; 726 retval = HPREV(h, &ev), i++) { 727 len = strlen(ev.str) * 4; 728 if (len >= max_size) { 729 char *nptr; 730 max_size = (len + 1024) & ~1023; 731 nptr = h_realloc(ptr, max_size); 732 if (nptr == NULL) { 733 i = -1; 734 goto oomem; 735 } 736 ptr = nptr; 737 } 738 (void) strvis(ptr, ev.str, VIS_WHITE); 739 (void) fprintf(fp, "%s\n", ptr); 740 } 741 oomem: 742 h_free((ptr_t)ptr); 743 done: 744 (void) fclose(fp); 745 return (i); 746 } 747 748 749 /* history_prev_event(): 750 * Find the previous event, with number given 751 */ 752 private int 753 history_prev_event(History *h, HistEvent *ev, int num) 754 { 755 int retval; 756 757 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 758 if (ev->num == num) 759 return (0); 760 761 he_seterrev(ev, _HE_NOT_FOUND); 762 return (-1); 763 } 764 765 766 /* history_next_event(): 767 * Find the next event, with number given 768 */ 769 private int 770 history_next_event(History *h, HistEvent *ev, int num) 771 { 772 int retval; 773 774 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 775 if (ev->num == num) 776 return (0); 777 778 he_seterrev(ev, _HE_NOT_FOUND); 779 return (-1); 780 } 781 782 783 /* history_prev_string(): 784 * Find the previous event beginning with string 785 */ 786 private int 787 history_prev_string(History *h, HistEvent *ev, const char *str) 788 { 789 size_t len = strlen(str); 790 int retval; 791 792 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 793 if (strncmp(str, ev->str, len) == 0) 794 return (0); 795 796 he_seterrev(ev, _HE_NOT_FOUND); 797 return (-1); 798 } 799 800 801 /* history_next_string(): 802 * Find the next event beginning with string 803 */ 804 private int 805 history_next_string(History *h, HistEvent *ev, const char *str) 806 { 807 size_t len = strlen(str); 808 int retval; 809 810 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 811 if (strncmp(str, ev->str, len) == 0) 812 return (0); 813 814 he_seterrev(ev, _HE_NOT_FOUND); 815 return (-1); 816 } 817 818 819 /* history(): 820 * User interface to history functions. 821 */ 822 int 823 history(History *h, HistEvent *ev, int fun, ...) 824 { 825 va_list va; 826 const char *str; 827 int retval; 828 829 va_start(va, fun); 830 831 he_seterrev(ev, _HE_OK); 832 833 switch (fun) { 834 case H_GETSIZE: 835 retval = history_getsize(h, ev); 836 break; 837 838 case H_SETSIZE: 839 retval = history_setsize(h, ev, va_arg(va, int)); 840 break; 841 842 case H_GETUNIQUE: 843 retval = history_getunique(h, ev); 844 break; 845 846 case H_SETUNIQUE: 847 retval = history_setunique(h, ev, va_arg(va, int)); 848 break; 849 850 case H_ADD: 851 str = va_arg(va, const char *); 852 retval = HADD(h, ev, str); 853 break; 854 855 case H_ENTER: 856 str = va_arg(va, const char *); 857 if ((retval = HENTER(h, ev, str)) != -1) 858 h->h_ent = ev->num; 859 break; 860 861 case H_APPEND: 862 str = va_arg(va, const char *); 863 if ((retval = HSET(h, ev, h->h_ent)) != -1) 864 retval = HADD(h, ev, str); 865 break; 866 867 case H_FIRST: 868 retval = HFIRST(h, ev); 869 break; 870 871 case H_NEXT: 872 retval = HNEXT(h, ev); 873 break; 874 875 case H_LAST: 876 retval = HLAST(h, ev); 877 break; 878 879 case H_PREV: 880 retval = HPREV(h, ev); 881 break; 882 883 case H_CURR: 884 retval = HCURR(h, ev); 885 break; 886 887 case H_SET: 888 retval = HSET(h, ev, va_arg(va, const int)); 889 break; 890 891 case H_CLEAR: 892 HCLEAR(h, ev); 893 retval = 0; 894 break; 895 896 case H_LOAD: 897 retval = history_load(h, va_arg(va, const char *)); 898 if (retval == -1) 899 he_seterrev(ev, _HE_HIST_READ); 900 break; 901 902 case H_SAVE: 903 retval = history_save(h, va_arg(va, const char *)); 904 if (retval == -1) 905 he_seterrev(ev, _HE_HIST_WRITE); 906 break; 907 908 case H_PREV_EVENT: 909 retval = history_prev_event(h, ev, va_arg(va, int)); 910 break; 911 912 case H_NEXT_EVENT: 913 retval = history_next_event(h, ev, va_arg(va, int)); 914 break; 915 916 case H_PREV_STR: 917 retval = history_prev_string(h, ev, va_arg(va, const char *)); 918 break; 919 920 case H_NEXT_STR: 921 retval = history_next_string(h, ev, va_arg(va, const char *)); 922 break; 923 924 case H_FUNC: 925 { 926 History hf; 927 928 hf.h_ref = va_arg(va, ptr_t); 929 h->h_ent = -1; 930 hf.h_first = va_arg(va, history_gfun_t); 931 hf.h_next = va_arg(va, history_gfun_t); 932 hf.h_last = va_arg(va, history_gfun_t); 933 hf.h_prev = va_arg(va, history_gfun_t); 934 hf.h_curr = va_arg(va, history_gfun_t); 935 hf.h_set = va_arg(va, history_sfun_t); 936 hf.h_clear = va_arg(va, history_vfun_t); 937 hf.h_enter = va_arg(va, history_efun_t); 938 hf.h_add = va_arg(va, history_efun_t); 939 940 if ((retval = history_set_fun(h, &hf)) == -1) 941 he_seterrev(ev, _HE_PARAM_MISSING); 942 break; 943 } 944 945 case H_END: 946 history_end(h); 947 retval = 0; 948 break; 949 950 default: 951 retval = -1; 952 he_seterrev(ev, _HE_UNKNOWN); 953 break; 954 } 955 va_end(va); 956 return (retval); 957 } 958