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