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