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