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