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