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