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