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