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