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