1 /* $NetBSD: history.c,v 1.66 2026/10/03 12:54:12 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.66 2026/10/03 12:54:12 christos Exp $"); 41 #endif 42 #endif /* not lint && not SCCSID */ 43 44 /* 45 * hist.c: TYPE(History) access functions 46 */ 47 #include <sys/stat.h> 48 #include <fcntl.h> 49 #include <stdarg.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <vis.h> 53 54 static const char hist_cookie[] = "_HiStOrY_V2_\n"; 55 56 #include "histedit.h" 57 #include "history.h" 58 59 60 #ifdef NARROWCHAR 61 62 #define Char char 63 #define FUN(prefix, rest) prefix ## _ ## rest 64 #define FUNW(type) type 65 #define TYPE(type) type 66 #define STR(x) x 67 68 #define Strlen(s) strlen(s) 69 #define Strdup(s) strdup(s) 70 #define Strcmp(d, s) strcmp(d, s) 71 #define Strncmp(d, s, n) strncmp(d, s, n) 72 #define Strncpy(d, s, n) strncpy(d, s, n) 73 #define Strncat(d, s, n) strncat(d, s, n) 74 #define ct_decode_string(s, b) (s) 75 #define ct_encode_string(s, b) (s) 76 77 #else 78 #include "chartype.h" 79 80 #define Char wchar_t 81 #define FUN(prefix, rest) prefix ## _w ## rest 82 #define FUNW(type) type ## _w 83 #define TYPE(type) type ## W 84 #define STR(x) L ## x 85 86 #define Strlen(s) wcslen(s) 87 #define Strdup(s) wcsdup(s) 88 #define Strcmp(d, s) wcscmp(d, s) 89 #define Strncmp(d, s, n) wcsncmp(d, s, n) 90 #define Strncpy(d, s, n) wcsncpy(d, s, n) 91 #define Strncat(d, s, n) wcsncat(d, s, n) 92 93 libedit_private size_t hist_cookie_len = sizeof(hist_cookie) - 1; 94 95 #endif 96 97 98 typedef int (*history_gfun_t)(void *, TYPE(HistEvent) *); 99 typedef int (*history_efun_t)(void *, TYPE(HistEvent) *, const Char *); 100 typedef void (*history_vfun_t)(void *, TYPE(HistEvent) *); 101 typedef int (*history_sfun_t)(void *, TYPE(HistEvent) *, const int); 102 103 struct TYPE(history) { 104 void *h_ref; /* Argument for history fcns */ 105 int h_ent; /* Last entry point for history */ 106 history_gfun_t h_first; /* Get the first element */ 107 history_gfun_t h_next; /* Get the next element */ 108 history_gfun_t h_last; /* Get the last element */ 109 history_gfun_t h_prev; /* Get the previous element */ 110 history_gfun_t h_curr; /* Get the current element */ 111 history_sfun_t h_set; /* Set the current element */ 112 history_sfun_t h_del; /* Set the given element */ 113 history_vfun_t h_clear; /* Clear the history list */ 114 history_efun_t h_enter; /* Add an element */ 115 history_efun_t h_add; /* Append to an element */ 116 }; 117 118 #define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev) 119 #define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev) 120 #define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev) 121 #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev) 122 #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev) 123 #define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) 124 #define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev) 125 #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) 126 #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) 127 #define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) 128 129 #define h_strdup(a) Strdup(a) 130 #define h_malloc(a) malloc(a) 131 #define h_realloc(a, b) realloc((a), (b)) 132 #define h_free(a) free(a) 133 134 typedef struct { 135 int num; 136 Char *str; 137 } HistEventPrivate; 138 139 140 static int history_setsize(TYPE(History) *, TYPE(HistEvent) *, int); 141 static int history_getsize(TYPE(History) *, TYPE(HistEvent) *); 142 static int history_setunique(TYPE(History) *, TYPE(HistEvent) *, int); 143 static int history_getunique(TYPE(History) *, TYPE(HistEvent) *); 144 static int history_set_fun(TYPE(History) *, TYPE(History) *); 145 static int history_load(TYPE(History) *, const char *); 146 static int history_save(TYPE(History) *, const char *); 147 static int history_save_fp(TYPE(History) *, size_t, FILE *); 148 static int history_prev_event(TYPE(History) *, TYPE(HistEvent) *, int); 149 static int history_next_event(TYPE(History) *, TYPE(HistEvent) *, int); 150 static int history_next_string(TYPE(History) *, TYPE(HistEvent) *, 151 const Char *); 152 static int history_prev_string(TYPE(History) *, TYPE(HistEvent) *, 153 const Char *); 154 155 156 /***********************************************************************/ 157 158 /* 159 * Builtin- history implementation 160 */ 161 typedef struct hentry_t { 162 TYPE(HistEvent) ev; /* What we return */ 163 void *data; /* data */ 164 struct hentry_t *next; /* Next entry */ 165 struct hentry_t *prev; /* Previous entry */ 166 } hentry_t; 167 168 typedef struct history_t { 169 hentry_t list; /* Fake list header element */ 170 hentry_t *cursor; /* Current element in the list */ 171 int max; /* Maximum number of events */ 172 int cur; /* Current number of events */ 173 int eventid; /* For generation of unique event id */ 174 int flags; /* TYPE(History) flags */ 175 #define H_UNIQUE 1 /* Store only unique elements */ 176 } history_t; 177 178 static int history_def_next(void *, TYPE(HistEvent) *); 179 static int history_def_first(void *, TYPE(HistEvent) *); 180 static int history_def_prev(void *, TYPE(HistEvent) *); 181 static int history_def_last(void *, TYPE(HistEvent) *); 182 static int history_def_curr(void *, TYPE(HistEvent) *); 183 static int history_def_set(void *, TYPE(HistEvent) *, const int); 184 static void history_def_clear(void *, TYPE(HistEvent) *); 185 static int history_def_enter(void *, TYPE(HistEvent) *, const Char *); 186 static int history_def_add(void *, TYPE(HistEvent) *, const Char *); 187 static int history_def_del(void *, TYPE(HistEvent) *, const int); 188 189 static int history_def_init(void **, TYPE(HistEvent) *, int); 190 static int history_def_insert(history_t *, TYPE(HistEvent) *, const Char *); 191 static void history_def_delete(history_t *, TYPE(HistEvent) *, hentry_t *); 192 193 static int history_deldata_nth(history_t *, TYPE(HistEvent) *, int, void **); 194 static int history_set_nth(void *, TYPE(HistEvent) *, int); 195 196 #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num)) 197 #define history_def_getsize(p) (((history_t *)p)->cur) 198 #define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0) 199 #define history_def_setunique(p, uni) \ 200 if (uni) \ 201 (((history_t *)p)->flags) |= H_UNIQUE; \ 202 else \ 203 (((history_t *)p)->flags) &= ~H_UNIQUE 204 205 #define he_strerror(code) he_errlist[code] 206 #define he_seterrev(evp, code) {\ 207 evp->num = code;\ 208 evp->str = he_strerror(code);\ 209 } 210 211 /* error messages */ 212 static const Char *const he_errlist[] = { 213 STR("OK"), 214 STR("unknown error"), 215 STR("malloc() failed"), 216 STR("first event not found"), 217 STR("last event not found"), 218 STR("empty list"), 219 STR("no next event"), 220 STR("no previous event"), 221 STR("current event is invalid"), 222 STR("event not found"), 223 STR("can't read history from file"), 224 STR("can't write history"), 225 STR("required parameter(s) not supplied"), 226 STR("history size negative"), 227 STR("function not allowed with other history-functions-set the default"), 228 STR("bad parameters") 229 }; 230 /* error codes */ 231 #define _HE_OK 0 232 #define _HE_UNKNOWN 1 233 #define _HE_MALLOC_FAILED 2 234 #define _HE_FIRST_NOTFOUND 3 235 #define _HE_LAST_NOTFOUND 4 236 #define _HE_EMPTY_LIST 5 237 #define _HE_END_REACHED 6 238 #define _HE_START_REACHED 7 239 #define _HE_CURR_INVALID 8 240 #define _HE_NOT_FOUND 9 241 #define _HE_HIST_READ 10 242 #define _HE_HIST_WRITE 11 243 #define _HE_PARAM_MISSING 12 244 #define _HE_SIZE_NEGATIVE 13 245 #define _HE_NOT_ALLOWED 14 246 #define _HE_BAD_PARAM 15 247 248 /* history_def_first(): 249 * Default function to return the first event in the history. 250 */ 251 static int 252 history_def_first(void *p, TYPE(HistEvent) *ev) 253 { 254 history_t *h = (history_t *) p; 255 256 h->cursor = h->list.next; 257 if (h->cursor != &h->list) 258 *ev = h->cursor->ev; 259 else { 260 he_seterrev(ev, _HE_FIRST_NOTFOUND); 261 return -1; 262 } 263 264 return 0; 265 } 266 267 268 /* history_def_last(): 269 * Default function to return the last event in the history. 270 */ 271 static int 272 history_def_last(void *p, TYPE(HistEvent) *ev) 273 { 274 history_t *h = (history_t *) p; 275 276 h->cursor = h->list.prev; 277 if (h->cursor != &h->list) 278 *ev = h->cursor->ev; 279 else { 280 he_seterrev(ev, _HE_LAST_NOTFOUND); 281 return -1; 282 } 283 284 return 0; 285 } 286 287 288 /* history_def_next(): 289 * Default function to return the next event in the history. 290 */ 291 static int 292 history_def_next(void *p, TYPE(HistEvent) *ev) 293 { 294 history_t *h = (history_t *) p; 295 296 if (h->cursor == &h->list) { 297 he_seterrev(ev, _HE_EMPTY_LIST); 298 return -1; 299 } 300 301 if (h->cursor->next == &h->list) { 302 he_seterrev(ev, _HE_END_REACHED); 303 return -1; 304 } 305 306 h->cursor = h->cursor->next; 307 *ev = h->cursor->ev; 308 309 return 0; 310 } 311 312 313 /* history_def_prev(): 314 * Default function to return the previous event in the history. 315 */ 316 static int 317 history_def_prev(void *p, TYPE(HistEvent) *ev) 318 { 319 history_t *h = (history_t *) p; 320 321 if (h->cursor == &h->list) { 322 he_seterrev(ev, 323 (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); 324 return -1; 325 } 326 327 if (h->cursor->prev == &h->list) { 328 he_seterrev(ev, _HE_START_REACHED); 329 return -1; 330 } 331 332 h->cursor = h->cursor->prev; 333 *ev = h->cursor->ev; 334 335 return 0; 336 } 337 338 339 /* history_def_curr(): 340 * Default function to return the current event in the history. 341 */ 342 static int 343 history_def_curr(void *p, TYPE(HistEvent) *ev) 344 { 345 history_t *h = (history_t *) p; 346 347 if (h->cursor != &h->list) 348 *ev = h->cursor->ev; 349 else { 350 he_seterrev(ev, 351 (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST); 352 return -1; 353 } 354 355 return 0; 356 } 357 358 359 /* history_def_set(): 360 * Default function to set the current event in the history to the 361 * given one. 362 */ 363 static int 364 history_def_set(void *p, TYPE(HistEvent) *ev, const int n) 365 { 366 history_t *h = (history_t *) p; 367 368 if (h->cur == 0) { 369 he_seterrev(ev, _HE_EMPTY_LIST); 370 return -1; 371 } 372 if (h->cursor == &h->list || h->cursor->ev.num != n) { 373 for (h->cursor = h->list.next; h->cursor != &h->list; 374 h->cursor = h->cursor->next) 375 if (h->cursor->ev.num == n) 376 break; 377 } 378 if (h->cursor == &h->list) { 379 he_seterrev(ev, _HE_NOT_FOUND); 380 return -1; 381 } 382 return 0; 383 } 384 385 386 /* history_set_nth(): 387 * Default function to set the current event in the history to the 388 * n-th one. 389 */ 390 static int 391 history_set_nth(void *p, TYPE(HistEvent) *ev, int n) 392 { 393 history_t *h = (history_t *) p; 394 395 if (h->cur == 0) { 396 he_seterrev(ev, _HE_EMPTY_LIST); 397 return -1; 398 } 399 for (h->cursor = h->list.prev; h->cursor != &h->list; 400 h->cursor = h->cursor->prev) 401 if (n-- <= 0) 402 break; 403 if (h->cursor == &h->list) { 404 he_seterrev(ev, _HE_NOT_FOUND); 405 return -1; 406 } 407 return 0; 408 } 409 410 411 /* history_def_add(): 412 * Append string to element 413 */ 414 static int 415 history_def_add(void *p, TYPE(HistEvent) *ev, const Char *str) 416 { 417 history_t *h = (history_t *) p; 418 size_t len, elen, slen; 419 Char *s; 420 HistEventPrivate *evp = (void *)&h->cursor->ev; 421 422 if (h->cursor == &h->list) 423 return history_def_enter(p, ev, str); 424 elen = Strlen(evp->str); 425 slen = Strlen(str); 426 len = elen + slen + 1; 427 s = h_malloc(len * sizeof(*s)); 428 if (s == NULL) { 429 he_seterrev(ev, _HE_MALLOC_FAILED); 430 return -1; 431 } 432 memcpy(s, evp->str, elen * sizeof(*s)); 433 memcpy(s + elen, str, slen * sizeof(*s)); 434 s[len - 1] = '\0'; 435 h_free(evp->str); 436 evp->str = s; 437 *ev = h->cursor->ev; 438 return 0; 439 } 440 441 442 static int 443 history_deldata_nth(history_t *h, TYPE(HistEvent) *ev, 444 int num, void **data) 445 { 446 if (history_set_nth(h, ev, num) != 0) 447 return -1; 448 /* magic value to skip delete (just set to n-th history) */ 449 if (data == (void **)-1) 450 return 0; 451 ev->str = Strdup(h->cursor->ev.str); 452 ev->num = h->cursor->ev.num; 453 if (data) 454 *data = h->cursor->data; 455 history_def_delete(h, ev, h->cursor); 456 return 0; 457 } 458 459 460 /* history_def_del(): 461 * Delete element hp of the h list 462 */ 463 /* ARGSUSED */ 464 static int 465 history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)), 466 const int num) 467 { 468 history_t *h = (history_t *) p; 469 if (history_def_set(h, ev, num) != 0) 470 return -1; 471 ev->str = Strdup(h->cursor->ev.str); 472 ev->num = h->cursor->ev.num; 473 history_def_delete(h, ev, h->cursor); 474 return 0; 475 } 476 477 478 /* history_def_delete(): 479 * Delete element hp of the h list 480 */ 481 /* ARGSUSED */ 482 static void 483 history_def_delete(history_t *h, 484 TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp) 485 { 486 HistEventPrivate *evp = (void *)&hp->ev; 487 if (hp == &h->list) 488 abort(); 489 if (h->cursor == hp) { 490 h->cursor = hp->prev; 491 if (h->cursor == &h->list) 492 h->cursor = hp->next; 493 } 494 hp->prev->next = hp->next; 495 hp->next->prev = hp->prev; 496 h_free(evp->str); 497 h_free(hp); 498 h->cur--; 499 } 500 501 502 /* history_def_insert(): 503 * Insert element with string str in the h list 504 */ 505 static int 506 history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str) 507 { 508 hentry_t *c; 509 510 c = h_malloc(sizeof(*c)); 511 if (c == NULL) 512 goto oomem; 513 if ((c->ev.str = h_strdup(str)) == NULL) { 514 h_free(c); 515 goto oomem; 516 } 517 c->data = NULL; 518 c->ev.num = ++h->eventid; 519 c->next = h->list.next; 520 c->prev = &h->list; 521 h->list.next->prev = c; 522 h->list.next = c; 523 h->cur++; 524 h->cursor = c; 525 526 *ev = c->ev; 527 return 0; 528 oomem: 529 he_seterrev(ev, _HE_MALLOC_FAILED); 530 return -1; 531 } 532 533 534 /* history_def_enter(): 535 * Default function to enter an item in the history 536 */ 537 static int 538 history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str) 539 { 540 history_t *h = (history_t *) p; 541 542 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && 543 Strcmp(h->list.next->ev.str, str) == 0) 544 return 0; 545 546 if (history_def_insert(h, ev, str) == -1) 547 return -1; /* error, keep error message */ 548 549 /* 550 * Always keep at least one entry. 551 * This way we don't have to check for the empty list. 552 */ 553 while (h->cur > h->max && h->cur > 0) 554 history_def_delete(h, ev, h->list.prev); 555 556 return 1; 557 } 558 559 560 /* history_def_init(): 561 * Default history initialization function 562 */ 563 /* ARGSUSED */ 564 static int 565 history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n) 566 { 567 history_t *h = (history_t *) h_malloc(sizeof(*h)); 568 if (h == NULL) 569 return -1; 570 571 if (n <= 0) 572 n = 0; 573 h->eventid = 0; 574 h->cur = 0; 575 h->max = n; 576 h->list.next = h->list.prev = &h->list; 577 h->list.ev.str = NULL; 578 h->list.ev.num = 0; 579 h->cursor = &h->list; 580 h->flags = 0; 581 *p = h; 582 return 0; 583 } 584 585 586 /* history_def_clear(): 587 * Default history cleanup function 588 */ 589 static void 590 history_def_clear(void *p, TYPE(HistEvent) *ev) 591 { 592 history_t *h = (history_t *) p; 593 594 while (h->list.prev != &h->list) 595 history_def_delete(h, ev, h->list.prev); 596 h->cursor = &h->list; 597 h->eventid = 0; 598 h->cur = 0; 599 } 600 601 602 603 604 /************************************************************************/ 605 606 /* history_init(): 607 * Initialization function. 608 */ 609 TYPE(History) * 610 FUN(history,init)(void) 611 { 612 TYPE(HistEvent) ev; 613 TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h)); 614 if (h == NULL) 615 return NULL; 616 617 if (history_def_init(&h->h_ref, &ev, 0) == -1) { 618 h_free(h); 619 return NULL; 620 } 621 h->h_ent = -1; 622 h->h_next = history_def_next; 623 h->h_first = history_def_first; 624 h->h_last = history_def_last; 625 h->h_prev = history_def_prev; 626 h->h_curr = history_def_curr; 627 h->h_set = history_def_set; 628 h->h_clear = history_def_clear; 629 h->h_enter = history_def_enter; 630 h->h_add = history_def_add; 631 h->h_del = history_def_del; 632 633 return h; 634 } 635 636 637 /* history_end(): 638 * clean up history; 639 */ 640 void 641 FUN(history,end)(TYPE(History) *h) 642 { 643 TYPE(HistEvent) ev; 644 645 if (h->h_next == history_def_next) 646 history_def_clear(h->h_ref, &ev); 647 h_free(h->h_ref); 648 h_free(h); 649 } 650 651 652 653 /* history_setsize(): 654 * Set history number of events 655 */ 656 static int 657 history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num) 658 { 659 660 if (h->h_next != history_def_next) { 661 he_seterrev(ev, _HE_NOT_ALLOWED); 662 return -1; 663 } 664 if (num < 0) { 665 he_seterrev(ev, _HE_BAD_PARAM); 666 return -1; 667 } 668 history_def_setsize(h->h_ref, num); 669 return 0; 670 } 671 672 673 /* history_getsize(): 674 * Get number of events currently in history 675 */ 676 static int 677 history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev) 678 { 679 if (h->h_next != history_def_next) { 680 he_seterrev(ev, _HE_NOT_ALLOWED); 681 return -1; 682 } 683 ev->num = history_def_getsize(h->h_ref); 684 if (ev->num < -1) { 685 he_seterrev(ev, _HE_SIZE_NEGATIVE); 686 return -1; 687 } 688 return 0; 689 } 690 691 692 /* history_setunique(): 693 * Set if adjacent equal events should not be entered in history. 694 */ 695 static int 696 history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni) 697 { 698 699 if (h->h_next != history_def_next) { 700 he_seterrev(ev, _HE_NOT_ALLOWED); 701 return -1; 702 } 703 history_def_setunique(h->h_ref, uni); 704 return 0; 705 } 706 707 708 /* history_getunique(): 709 * Get if adjacent equal events should not be entered in history. 710 */ 711 static int 712 history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev) 713 { 714 if (h->h_next != history_def_next) { 715 he_seterrev(ev, _HE_NOT_ALLOWED); 716 return -1; 717 } 718 ev->num = history_def_getunique(h->h_ref); 719 return 0; 720 } 721 722 723 /* history_set_fun(): 724 * Set history functions 725 */ 726 static int 727 history_set_fun(TYPE(History) *h, TYPE(History) *nh) 728 { 729 TYPE(HistEvent) ev; 730 731 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || 732 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || 733 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || 734 nh->h_del == NULL || nh->h_ref == NULL) { 735 if (h->h_next != history_def_next) { 736 if (history_def_init(&h->h_ref, &ev, 0) == -1) 737 return -1; 738 h->h_first = history_def_first; 739 h->h_next = history_def_next; 740 h->h_last = history_def_last; 741 h->h_prev = history_def_prev; 742 h->h_curr = history_def_curr; 743 h->h_set = history_def_set; 744 h->h_clear = history_def_clear; 745 h->h_enter = history_def_enter; 746 h->h_add = history_def_add; 747 h->h_del = history_def_del; 748 } 749 return -1; 750 } 751 if (h->h_next == history_def_next) 752 history_def_clear(h->h_ref, &ev); 753 754 h->h_ent = -1; 755 h->h_first = nh->h_first; 756 h->h_next = nh->h_next; 757 h->h_last = nh->h_last; 758 h->h_prev = nh->h_prev; 759 h->h_curr = nh->h_curr; 760 h->h_set = nh->h_set; 761 h->h_clear = nh->h_clear; 762 h->h_enter = nh->h_enter; 763 h->h_add = nh->h_add; 764 h->h_del = nh->h_del; 765 766 return 0; 767 } 768 769 770 /* history_load(): 771 * TYPE(History) load function 772 */ 773 static int 774 history_load(TYPE(History) *h, const char *fname) 775 { 776 FILE *fp; 777 char *line; 778 size_t llen; 779 ssize_t sz; 780 size_t max_size; 781 char *ptr; 782 int i = -1; 783 TYPE(HistEvent) ev; 784 Char *decode_result; 785 #ifndef NARROWCHAR 786 static ct_buffer_t conv; 787 #endif 788 789 if ((fp = fopen(fname, "r")) == NULL) 790 return i; 791 792 line = NULL; 793 llen = 0; 794 if ((sz = getline(&line, &llen, fp)) == -1) 795 goto done; 796 797 if (strncmp(line, hist_cookie, (size_t)sz) != 0) 798 goto done; 799 800 ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); 801 if (ptr == NULL) 802 goto done; 803 for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) { 804 if (sz > 0 && line[sz - 1] == '\n') 805 line[--sz] = '\0'; 806 if (max_size <= (size_t)sz) { 807 char *nptr; 808 max_size = ((size_t)sz + 1024) & (size_t)~1023; 809 nptr = h_realloc(ptr, max_size * sizeof(*ptr)); 810 if (nptr == NULL) { 811 i = -1; 812 goto oomem; 813 } 814 ptr = nptr; 815 } 816 (void) strunvis(ptr, line); 817 decode_result = ct_decode_string(ptr, &conv); 818 if (decode_result == NULL) 819 continue; 820 if (HENTER(h, &ev, decode_result) == -1) { 821 i = -1; 822 goto oomem; 823 } 824 } 825 oomem: 826 h_free(ptr); 827 done: 828 free(line); 829 (void) fclose(fp); 830 return i; 831 } 832 833 834 /* history_save_fp(): 835 * TYPE(History) save function 836 */ 837 static int 838 history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp) 839 { 840 TYPE(HistEvent) ev; 841 int i = -1, retval; 842 size_t len, max_size; 843 char *ptr; 844 const char *str; 845 #ifndef NARROWCHAR 846 static ct_buffer_t conv; 847 #endif 848 849 if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF) 850 goto done; 851 ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); 852 if (ptr == NULL) 853 goto done; 854 if (nelem != (size_t)-1) { 855 for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0; 856 retval = HNEXT(h, &ev)) 857 continue; 858 } else 859 retval = -1; 860 861 if (retval == -1) 862 retval = HLAST(h, &ev); 863 864 for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) { 865 str = ct_encode_string(ev.str, &conv); 866 len = strlen(str) * 4 + 1; 867 if (len > max_size) { 868 char *nptr; 869 max_size = (len + 1024) & (size_t)~1023; 870 nptr = h_realloc(ptr, max_size * sizeof(*ptr)); 871 if (nptr == NULL) { 872 i = -1; 873 goto oomem; 874 } 875 ptr = nptr; 876 } 877 (void) strvis(ptr, str, VIS_WHITE); 878 (void) fprintf(fp, "%s\n", ptr); 879 } 880 oomem: 881 h_free(ptr); 882 done: 883 return i; 884 } 885 886 887 /* history_save(): 888 * History save function 889 */ 890 static int 891 history_save(TYPE(History) *h, const char *fname) 892 { 893 FILE *fp; 894 int i; 895 896 if ((i = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 897 S_IRUSR|S_IWUSR)) == -1) 898 return -1; 899 900 if ((fp = fdopen(i, "w")) == NULL) 901 return -1; 902 903 i = history_save_fp(h, (size_t)-1, fp); 904 905 (void) fclose(fp); 906 return i; 907 } 908 909 910 /* history_prev_event(): 911 * Find the previous event, with number given 912 */ 913 static int 914 history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) 915 { 916 int retval; 917 918 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 919 if (ev->num == num) 920 return 0; 921 922 he_seterrev(ev, _HE_NOT_FOUND); 923 return -1; 924 } 925 926 927 static int 928 history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d) 929 { 930 int retval; 931 932 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 933 if (ev->num == num) { 934 if (d) 935 *d = ((history_t *)h->h_ref)->cursor->data; 936 return 0; 937 } 938 939 he_seterrev(ev, _HE_NOT_FOUND); 940 return -1; 941 } 942 943 944 /* history_next_event(): 945 * Find the next event, with number given 946 */ 947 static int 948 history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) 949 { 950 int retval; 951 952 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 953 if (ev->num == num) 954 return 0; 955 956 he_seterrev(ev, _HE_NOT_FOUND); 957 return -1; 958 } 959 960 961 /* history_prev_string(): 962 * Find the previous event beginning with string 963 */ 964 static int 965 history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) 966 { 967 size_t len = Strlen(str); 968 int retval; 969 970 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 971 if (Strncmp(str, ev->str, len) == 0) 972 return 0; 973 974 he_seterrev(ev, _HE_NOT_FOUND); 975 return -1; 976 } 977 978 979 /* history_next_string(): 980 * Find the next event beginning with string 981 */ 982 static int 983 history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) 984 { 985 size_t len = Strlen(str); 986 int retval; 987 988 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 989 if (Strncmp(str, ev->str, len) == 0) 990 return 0; 991 992 he_seterrev(ev, _HE_NOT_FOUND); 993 return -1; 994 } 995 996 997 /* history(): 998 * User interface to history functions. 999 */ 1000 int 1001 FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...) 1002 { 1003 va_list va; 1004 const Char *str; 1005 int retval; 1006 1007 va_start(va, fun); 1008 1009 he_seterrev(ev, _HE_OK); 1010 1011 switch (fun) { 1012 case H_GETSIZE: 1013 retval = history_getsize(h, ev); 1014 break; 1015 1016 case H_SETSIZE: 1017 retval = history_setsize(h, ev, va_arg(va, int)); 1018 break; 1019 1020 case H_GETUNIQUE: 1021 retval = history_getunique(h, ev); 1022 break; 1023 1024 case H_SETUNIQUE: 1025 retval = history_setunique(h, ev, va_arg(va, int)); 1026 break; 1027 1028 case H_ADD: 1029 str = va_arg(va, const Char *); 1030 retval = HADD(h, ev, str); 1031 break; 1032 1033 case H_DEL: 1034 retval = HDEL(h, ev, va_arg(va, const int)); 1035 break; 1036 1037 case H_ENTER: 1038 str = va_arg(va, const Char *); 1039 if ((retval = HENTER(h, ev, str)) != -1) 1040 h->h_ent = ev->num; 1041 break; 1042 1043 case H_APPEND: 1044 str = va_arg(va, const Char *); 1045 if ((retval = HSET(h, ev, h->h_ent)) != -1) 1046 retval = HADD(h, ev, str); 1047 break; 1048 1049 case H_FIRST: 1050 retval = HFIRST(h, ev); 1051 break; 1052 1053 case H_NEXT: 1054 retval = HNEXT(h, ev); 1055 break; 1056 1057 case H_LAST: 1058 retval = HLAST(h, ev); 1059 break; 1060 1061 case H_PREV: 1062 retval = HPREV(h, ev); 1063 break; 1064 1065 case H_CURR: 1066 retval = HCURR(h, ev); 1067 break; 1068 1069 case H_SET: 1070 retval = HSET(h, ev, va_arg(va, const int)); 1071 break; 1072 1073 case H_CLEAR: 1074 HCLEAR(h, ev); 1075 retval = 0; 1076 break; 1077 1078 case H_LOAD: 1079 retval = history_load(h, va_arg(va, const char *)); 1080 if (retval == -1) 1081 he_seterrev(ev, _HE_HIST_READ); 1082 break; 1083 1084 case H_SAVE: 1085 retval = history_save(h, va_arg(va, const char *)); 1086 if (retval == -1) 1087 he_seterrev(ev, _HE_HIST_WRITE); 1088 break; 1089 1090 case H_SAVE_FP: 1091 retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *)); 1092 if (retval == -1) 1093 he_seterrev(ev, _HE_HIST_WRITE); 1094 break; 1095 1096 case H_NSAVE_FP: 1097 { 1098 size_t sz = va_arg(va, size_t); 1099 retval = history_save_fp(h, sz, va_arg(va, FILE *)); 1100 if (retval == -1) 1101 he_seterrev(ev, _HE_HIST_WRITE); 1102 break; 1103 } 1104 1105 case H_PREV_EVENT: 1106 retval = history_prev_event(h, ev, va_arg(va, int)); 1107 break; 1108 1109 case H_NEXT_EVENT: 1110 retval = history_next_event(h, ev, va_arg(va, int)); 1111 break; 1112 1113 case H_PREV_STR: 1114 retval = history_prev_string(h, ev, va_arg(va, const Char *)); 1115 break; 1116 1117 case H_NEXT_STR: 1118 retval = history_next_string(h, ev, va_arg(va, const Char *)); 1119 break; 1120 1121 case H_FUNC: 1122 { 1123 TYPE(History) hf; 1124 1125 hf.h_ref = va_arg(va, void *); 1126 h->h_ent = -1; 1127 hf.h_first = va_arg(va, history_gfun_t); 1128 hf.h_next = va_arg(va, history_gfun_t); 1129 hf.h_last = va_arg(va, history_gfun_t); 1130 hf.h_prev = va_arg(va, history_gfun_t); 1131 hf.h_curr = va_arg(va, history_gfun_t); 1132 hf.h_set = va_arg(va, history_sfun_t); 1133 hf.h_clear = va_arg(va, history_vfun_t); 1134 hf.h_enter = va_arg(va, history_efun_t); 1135 hf.h_add = va_arg(va, history_efun_t); 1136 hf.h_del = va_arg(va, history_sfun_t); 1137 1138 if ((retval = history_set_fun(h, &hf)) == -1) 1139 he_seterrev(ev, _HE_PARAM_MISSING); 1140 break; 1141 } 1142 1143 case H_END: 1144 FUN(history,end)(h); 1145 retval = 0; 1146 break; 1147 1148 case H_NEXT_EVDATA: 1149 { 1150 int num = va_arg(va, int); 1151 void **d = va_arg(va, void **); 1152 retval = history_next_evdata(h, ev, num, d); 1153 break; 1154 } 1155 1156 case H_DELDATA: 1157 { 1158 int num = va_arg(va, int); 1159 void **d = va_arg(va, void **); 1160 retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d); 1161 break; 1162 } 1163 1164 case H_REPLACE: /* only use after H_NEXT_EVDATA */ 1165 { 1166 const Char *line = va_arg(va, const Char *); 1167 void *d = va_arg(va, void *); 1168 const Char *s; 1169 if(!line || !(s = Strdup(line))) { 1170 retval = -1; 1171 break; 1172 } 1173 ((history_t *)h->h_ref)->cursor->ev.str = s; 1174 ((history_t *)h->h_ref)->cursor->data = d; 1175 retval = 0; 1176 break; 1177 } 1178 1179 default: 1180 retval = -1; 1181 he_seterrev(ev, _HE_UNKNOWN); 1182 break; 1183 } 1184 va_end(va); 1185 return retval; 1186 } 1187