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