1 /* $NetBSD: history.c,v 1.16 2000/09/04 22:06:30 lukem 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.16 2000/09/04 22:06:30 lukem 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 58 static const char hist_cookie[] = "_HiStOrY_V2_\n"; 59 60 #include "histedit.h" 61 62 typedef int (*history_gfun_t)(ptr_t, HistEvent *); 63 typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *); 64 typedef void (*history_vfun_t)(ptr_t, HistEvent *); 65 typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int); 66 67 struct 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 95 private int history_setsize(History *, HistEvent *, int); 96 private int history_getsize(History *, HistEvent *); 97 private int history_set_fun(History *, History *); 98 private int history_load(History *, const char *); 99 private int history_save(History *, const char *); 100 private int history_prev_event(History *, HistEvent *, int); 101 private int history_next_event(History *, HistEvent *, int); 102 private int history_next_string(History *, HistEvent *, const char *); 103 private int history_prev_string(History *, HistEvent *, const char *); 104 105 106 /***********************************************************************/ 107 108 /* 109 * Builtin- history implementation 110 */ 111 typedef 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 117 typedef 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 125 private int history_def_first(ptr_t, HistEvent *); 126 private int history_def_last(ptr_t, HistEvent *); 127 private int history_def_next(ptr_t, HistEvent *); 128 private int history_def_prev(ptr_t, HistEvent *); 129 private int history_def_curr(ptr_t, HistEvent *); 130 private int history_def_set(ptr_t, HistEvent *, const int n); 131 private int history_def_enter(ptr_t, HistEvent *, const char *); 132 private int history_def_add(ptr_t, HistEvent *, const char *); 133 private void history_def_init(ptr_t *, HistEvent *, int); 134 private void history_def_clear(ptr_t, HistEvent *); 135 private int history_def_insert(history_t *, HistEvent *, const char *); 136 private 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 */ 148 static 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 */ 187 private int 188 history_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 */ 207 private int 208 history_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 */ 227 private int 228 history_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 */ 253 private int 254 history_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 */ 280 private int 281 history_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 */ 301 private int 302 history_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 */ 327 private int 328 history_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 */ 356 private void 357 history_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 */ 374 private int 375 history_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 */ 400 private int 401 history_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 */ 423 private void 424 history_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 */ 444 private void 445 history_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 */ 463 public History * 464 history_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 */ 488 public void 489 history_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 */ 502 private int 503 history_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 */ 522 private int 523 history_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 */ 544 private int 545 history_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 */ 588 private int 589 history_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 626 done: 627 (void) fclose(fp); 628 return (i); 629 } 630 631 632 /* history_save(): 633 * History save function 634 */ 635 private int 636 history_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) fputs(hist_cookie, fp); 648 ptr = h_malloc(max_size = 1024); 649 for (retval = HLAST(h, &ev); 650 retval != -1; 651 retval = HPREV(h, &ev), i++) { 652 len = strlen(ev.str) * 4; 653 if (len >= max_size) { 654 max_size = (len + 1023) & 1023; 655 ptr = h_realloc(ptr, max_size); 656 } 657 (void) strvis(ptr, ev.str, VIS_WHITE); 658 (void) fprintf(fp, "%s\n", ev.str); 659 } 660 h_free(ptr); 661 (void) fclose(fp); 662 return (i); 663 } 664 665 666 /* history_prev_event(): 667 * Find the previous event, with number given 668 */ 669 private int 670 history_prev_event(History *h, HistEvent *ev, int num) 671 { 672 int retval; 673 674 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 675 if (ev->num == num) 676 return (0); 677 678 he_seterrev(ev, _HE_NOT_FOUND); 679 return (-1); 680 } 681 682 683 /* history_next_event(): 684 * Find the next event, with number given 685 */ 686 private int 687 history_next_event(History *h, HistEvent *ev, int num) 688 { 689 int retval; 690 691 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 692 if (ev->num == num) 693 return (0); 694 695 he_seterrev(ev, _HE_NOT_FOUND); 696 return (-1); 697 } 698 699 700 /* history_prev_string(): 701 * Find the previous event beginning with string 702 */ 703 private int 704 history_prev_string(History *h, HistEvent *ev, const char *str) 705 { 706 size_t len = strlen(str); 707 int retval; 708 709 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 710 if (strncmp(str, ev->str, len) == 0) 711 return (0); 712 713 he_seterrev(ev, _HE_NOT_FOUND); 714 return (-1); 715 } 716 717 718 /* history_next_string(): 719 * Find the next event beginning with string 720 */ 721 private int 722 history_next_string(History *h, HistEvent *ev, const char *str) 723 { 724 size_t len = strlen(str); 725 int retval; 726 727 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 728 if (strncmp(str, ev->str, len) == 0) 729 return (0); 730 731 he_seterrev(ev, _HE_NOT_FOUND); 732 return (-1); 733 } 734 735 736 /* history(): 737 * User interface to history functions. 738 */ 739 int 740 history(History *h, HistEvent *ev, int fun, ...) 741 { 742 va_list va; 743 const char *str; 744 int retval; 745 746 va_start(va, fun); 747 748 he_seterrev(ev, _HE_OK); 749 750 switch (fun) { 751 case H_GETSIZE: 752 retval = history_getsize(h, ev); 753 break; 754 755 case H_SETSIZE: 756 retval = history_setsize(h, ev, va_arg(va, int)); 757 break; 758 759 case H_ADD: 760 str = va_arg(va, const char *); 761 retval = HADD(h, ev, str); 762 break; 763 764 case H_ENTER: 765 str = va_arg(va, const char *); 766 if ((retval = HENTER(h, ev, str)) != -1) 767 h->h_ent = ev->num; 768 break; 769 770 case H_APPEND: 771 str = va_arg(va, const char *); 772 if ((retval = HSET(h, ev, h->h_ent)) != -1) 773 retval = HADD(h, ev, str); 774 break; 775 776 case H_FIRST: 777 retval = HFIRST(h, ev); 778 break; 779 780 case H_NEXT: 781 retval = HNEXT(h, ev); 782 break; 783 784 case H_LAST: 785 retval = HLAST(h, ev); 786 break; 787 788 case H_PREV: 789 retval = HPREV(h, ev); 790 break; 791 792 case H_CURR: 793 retval = HCURR(h, ev); 794 break; 795 796 case H_SET: 797 retval = HSET(h, ev, va_arg(va, const int)); 798 break; 799 800 case H_CLEAR: 801 HCLEAR(h, ev); 802 retval = 0; 803 break; 804 805 case H_LOAD: 806 retval = history_load(h, va_arg(va, const char *)); 807 if (retval == -1) 808 he_seterrev(ev, _HE_HIST_READ); 809 break; 810 811 case H_SAVE: 812 retval = history_save(h, va_arg(va, const char *)); 813 if (retval == -1) 814 he_seterrev(ev, _HE_HIST_WRITE); 815 break; 816 817 case H_PREV_EVENT: 818 retval = history_prev_event(h, ev, va_arg(va, int)); 819 break; 820 821 case H_NEXT_EVENT: 822 retval = history_next_event(h, ev, va_arg(va, int)); 823 break; 824 825 case H_PREV_STR: 826 retval = history_prev_string(h, ev, va_arg(va, const char *)); 827 break; 828 829 case H_NEXT_STR: 830 retval = history_next_string(h, ev, va_arg(va, const char *)); 831 break; 832 833 case H_FUNC: 834 { 835 History hf; 836 837 hf.h_ref = va_arg(va, ptr_t); 838 h->h_ent = -1; 839 hf.h_first = va_arg(va, history_gfun_t); 840 hf.h_next = va_arg(va, history_gfun_t); 841 hf.h_last = va_arg(va, history_gfun_t); 842 hf.h_prev = va_arg(va, history_gfun_t); 843 hf.h_curr = va_arg(va, history_gfun_t); 844 hf.h_set = va_arg(va, history_sfun_t); 845 hf.h_clear = va_arg(va, history_vfun_t); 846 hf.h_enter = va_arg(va, history_efun_t); 847 hf.h_add = va_arg(va, history_efun_t); 848 849 if ((retval = history_set_fun(h, &hf)) == -1) 850 he_seterrev(ev, _HE_PARAM_MISSING); 851 break; 852 } 853 854 case H_END: 855 history_end(h); 856 retval = 0; 857 break; 858 859 default: 860 retval = -1; 861 he_seterrev(ev, _HE_UNKNOWN); 862 break; 863 } 864 va_end(va); 865 return (retval); 866 } 867