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