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