1 /* $OpenBSD: echo.c,v 1.46 2006/04/02 17:18:58 kjell Exp $ */ 2 3 /* This file is in the public domain. */ 4 5 /* 6 * Echo line reading and writing. 7 * 8 * Common routines for reading and writing characters in the echo line area 9 * of the display screen. Used by the entire known universe. 10 */ 11 12 #include "def.h" 13 #include "key.h" 14 #ifndef NO_MACRO 15 #include "macro.h" 16 #endif /* !NO_MACRO */ 17 18 #include "funmap.h" 19 20 #include <stdarg.h> 21 #include <term.h> 22 23 static char *veread(const char *, char *, size_t, int, va_list); 24 static int complt(int, int, char *, size_t, int, int *); 25 static int complt_list(int, char *, int); 26 static void eformat(const char *, va_list); 27 static void eputi(int, int); 28 static void eputl(long, int); 29 static void eputs(const char *); 30 static void eputc(char); 31 static struct list *copy_list(struct list *); 32 33 int epresf = FALSE; /* stuff in echo line flag */ 34 35 /* 36 * Erase the echo line. 37 */ 38 void 39 eerase(void) 40 { 41 ttcolor(CTEXT); 42 ttmove(nrow - 1, 0); 43 tteeol(); 44 ttflush(); 45 epresf = FALSE; 46 } 47 48 /* 49 * Ask a "yes" or "no" question. Return ABORT if the user answers the 50 * question with the abort ("^G") character. Return FALSE for "no" and 51 * TRUE for "yes". No formatting services are available. No newline 52 * required. 53 */ 54 int 55 eyorn(const char *sp) 56 { 57 int s; 58 59 #ifndef NO_MACRO 60 if (inmacro) 61 return (TRUE); 62 #endif /* !NO_MACRO */ 63 ewprintf("%s? (y or n) ", sp); 64 for (;;) { 65 s = getkey(FALSE); 66 if (s == 'y' || s == 'Y' || s == ' ') 67 return (TRUE); 68 if (s == 'n' || s == 'N' || s == CCHR('M')) 69 return (FALSE); 70 if (s == CCHR('G')) 71 return (ctrlg(FFRAND, 1)); 72 ewprintf("Please answer y or n. %s? (y or n) ", sp); 73 } 74 /* NOTREACHED */ 75 } 76 77 /* 78 * Like eyorn, but for more important questions. User must type all of 79 * "yes" or "no" and the trailing newline. 80 */ 81 int 82 eyesno(const char *sp) 83 { 84 char buf[64], *rep; 85 86 #ifndef NO_MACRO 87 if (inmacro) 88 return (TRUE); 89 #endif /* !NO_MACRO */ 90 rep = eread("%s? (yes or no) ", buf, sizeof(buf), 91 EFNUL | EFNEW | EFCR, sp); 92 for (;;) { 93 if (rep == NULL) 94 return (ABORT); 95 if (rep[0] != '\0') { 96 #ifndef NO_MACRO 97 if (macrodef) { 98 struct line *lp = maclcur; 99 100 maclcur = lp->l_bp; 101 maclcur->l_fp = lp->l_fp; 102 free(lp); 103 } 104 #endif /* !NO_MACRO */ 105 if ((rep[0] == 'y' || rep[0] == 'Y') && 106 (rep[1] == 'e' || rep[1] == 'E') && 107 (rep[2] == 's' || rep[2] == 'S') && 108 (rep[3] == '\0')) 109 return (TRUE); 110 if ((rep[0] == 'n' || rep[0] == 'N') && 111 (rep[1] == 'o' || rep[0] == 'O') && 112 (rep[2] == '\0')) 113 return (FALSE); 114 } 115 rep = eread("Please answer yes or no. %s? (yes or no) ", 116 buf, sizeof(buf), EFNUL | EFNEW | EFCR, sp); 117 } 118 /* NOTREACHED */ 119 } 120 121 /* 122 * This is the general "read input from the echo line" routine. The basic 123 * idea is that the prompt string "prompt" is written to the echo line, and 124 * a one line reply is read back into the supplied "buf" (with maximum 125 * length "len"). 126 * XXX: When checking for an empty return value, always check rep, *not* buf 127 * as buf may be freed in pathological cases. 128 */ 129 /* VARARGS */ 130 char * 131 eread(const char *fmt, char *buf, size_t nbuf, int flag, ...) 132 { 133 va_list ap; 134 char *rep; 135 136 va_start(ap, flag); 137 rep = veread(fmt, buf, nbuf, flag, ap); 138 va_end(ap); 139 return (rep); 140 } 141 142 static char * 143 veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap) 144 { 145 int dynbuf = (buf == NULL); 146 int cpos, epos; /* cursor, end position in buf */ 147 int c, i, y; 148 int cplflag = FALSE; /* display completion list */ 149 int cwin = FALSE; /* completion list created */ 150 int mr = 0; /* match left arrow */ 151 int ml = 0; /* match right arrow */ 152 int esc = 0; /* position in esc pattern */ 153 struct buffer *bp; /* completion list buffer */ 154 struct mgwin *wp; /* window for compl list */ 155 int match; /* esc match found */ 156 int cc, rr; /* saved ttcol, ttrow */ 157 char *ret; /* return value */ 158 159 #ifndef NO_MACRO 160 if (inmacro) { 161 if (dynbuf) { 162 if ((buf = malloc(maclcur->l_used + 1)) == NULL) 163 return (NULL); 164 } else if (maclcur->l_used >= nbuf) 165 return (NULL); 166 bcopy(maclcur->l_text, buf, maclcur->l_used); 167 buf[maclcur->l_used] = '\0'; 168 maclcur = maclcur->l_fp; 169 return (buf); 170 } 171 #endif /* !NO_MACRO */ 172 epos = cpos = 0; 173 ml = mr = esc = 0; 174 cplflag = FALSE; 175 176 if ((flag & EFNEW) != 0 || ttrow != nrow - 1) { 177 ttcolor(CTEXT); 178 ttmove(nrow - 1, 0); 179 epresf = TRUE; 180 } else 181 eputc(' '); 182 eformat(fp, ap); 183 if ((flag & EFDEF) != 0) { 184 if (buf == NULL) 185 return (NULL); 186 eputs(buf); 187 epos = cpos += strlen(buf); 188 } 189 tteeol(); 190 ttflush(); 191 for (;;) { 192 c = getkey(FALSE); 193 if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) { 194 if (cplflag == TRUE) { 195 complt_list(flag, buf, cpos); 196 cwin = TRUE; 197 } else if (complt(flag, c, buf, nbuf, epos, &i) == TRUE) { 198 cplflag = TRUE; 199 epos += i; 200 cpos = epos; 201 } 202 continue; 203 } 204 cplflag = FALSE; 205 206 if (esc > 0) { /* ESC sequence started */ 207 match = 0; 208 if (ml == esc && key_left[ml] && c == key_left[ml]) { 209 match++; 210 if (key_left[++ml] == '\0') { 211 c = CCHR('B'); 212 esc = 0; 213 } 214 } 215 if (mr == esc && key_right[mr] && c == key_right[mr]) { 216 match++; 217 if (key_right[++mr] == '\0') { 218 c = CCHR('F'); 219 esc = 0; 220 } 221 } 222 if (match == 0) { 223 esc = 0; 224 continue; 225 /* hack. how do we know esc pattern is done? */ 226 } 227 if (esc > 0) { 228 esc++; 229 continue; 230 } 231 } 232 switch (c) { 233 case CCHR('A'): /* start of line */ 234 while (cpos > 0) { 235 if (ISCTRL(buf[--cpos]) != FALSE) { 236 ttputc('\b'); 237 --ttcol; 238 } 239 ttputc('\b'); 240 --ttcol; 241 } 242 ttflush(); 243 break; 244 case CCHR('D'): 245 if (cpos != epos) { 246 tteeol(); 247 y = buf[cpos]; 248 epos--; 249 rr = ttrow; 250 cc = ttcol; 251 for (i = cpos; i < epos; i++) { 252 buf[i] = buf[i + 1]; 253 eputc(buf[i]); 254 } 255 ttmove(rr, cc); 256 ttflush(); 257 } 258 break; 259 case CCHR('E'): /* end of line */ 260 while (cpos < epos) { 261 eputc(buf[cpos++]); 262 } 263 ttflush(); 264 break; 265 case CCHR('B'): /* back */ 266 if (cpos > 0) { 267 if (ISCTRL(buf[--cpos]) != FALSE) { 268 ttputc('\b'); 269 --ttcol; 270 } 271 ttputc('\b'); 272 --ttcol; 273 ttflush(); 274 } 275 break; 276 case CCHR('F'): /* forw */ 277 if (cpos < epos) { 278 eputc(buf[cpos++]); 279 ttflush(); 280 } 281 break; 282 case CCHR('Y'): /* yank from kill buffer */ 283 i = 0; 284 while ((y = kremove(i++)) >= 0 && y != '\n') { 285 int t; 286 if (dynbuf && epos + 1 >= nbuf) { 287 void *newp; 288 size_t newsize = epos + epos + 16; 289 if ((newp = realloc(buf, newsize)) 290 == NULL) 291 goto fail; 292 buf = newp; 293 nbuf = newsize; 294 } 295 for (t = epos; t > cpos; t--) 296 buf[t] = buf[t - 1]; 297 buf[cpos++] = (char)y; 298 epos++; 299 eputc((char)y); 300 cc = ttcol; 301 rr = ttrow; 302 for (t = cpos; t < epos; t++) 303 eputc(buf[t]); 304 ttmove(rr, cc); 305 } 306 ttflush(); 307 break; 308 case CCHR('K'): /* copy here-EOL to kill buffer */ 309 kdelete(); 310 for (i = cpos; i < epos; i++) 311 kinsert(buf[i], KFORW); 312 tteeol(); 313 epos = cpos; 314 ttflush(); 315 break; 316 case CCHR('['): 317 ml = mr = esc = 1; 318 break; 319 case CCHR('J'): 320 c = CCHR('M'); 321 /* FALLTHROUGH */ 322 case CCHR('M'): /* return, done */ 323 /* if there's nothing in the minibuffer, abort */ 324 if (epos == 0 && !(flag & EFNUL)) { 325 (void)ctrlg(FFRAND, 0); 326 ttflush(); 327 return (NULL); 328 } 329 if ((flag & EFFUNC) != 0) { 330 if (complt(flag, c, buf, nbuf, epos, &i) 331 == FALSE) 332 continue; 333 if (i > 0) 334 epos += i; 335 } 336 buf[epos] = '\0'; 337 if ((flag & EFCR) != 0) { 338 ttputc(CCHR('M')); 339 ttflush(); 340 } 341 #ifndef NO_MACRO 342 if (macrodef) { 343 struct line *lp; 344 345 if ((lp = lalloc(cpos)) == NULL) { 346 static char falseval[] = ""; 347 /* XXX hackish */ 348 if (dynbuf && buf != NULL) 349 free(buf); 350 return (falseval); 351 } 352 lp->l_fp = maclcur->l_fp; 353 maclcur->l_fp = lp; 354 lp->l_bp = maclcur; 355 maclcur = lp; 356 bcopy(buf, lp->l_text, cpos); 357 } 358 #endif /* !NO_MACRO */ 359 ret = buf; 360 goto done; 361 case CCHR('G'): /* bell, abort */ 362 eputc(CCHR('G')); 363 (void)ctrlg(FFRAND, 0); 364 ttflush(); 365 ret = NULL; 366 goto done; 367 case CCHR('H'): /* rubout, erase */ 368 case CCHR('?'): 369 if (cpos != 0) { 370 y = buf[--cpos]; 371 epos--; 372 ttputc('\b'); 373 ttcol--; 374 if (ISCTRL(y) != FALSE) { 375 ttputc('\b'); 376 ttcol--; 377 } 378 rr = ttrow; 379 cc = ttcol; 380 for (i = cpos; i < epos; i++) { 381 buf[i] = buf[i + 1]; 382 eputc(buf[i]); 383 } 384 ttputc(' '); 385 if (ISCTRL(y) != FALSE) { 386 ttputc(' '); 387 ttputc('\b'); 388 } 389 ttputc('\b'); 390 ttmove(rr, cc); 391 ttflush(); 392 } 393 break; 394 case CCHR('X'): /* kill line */ 395 case CCHR('U'): 396 while (cpos != 0) { 397 ttputc('\b'); 398 ttputc(' '); 399 ttputc('\b'); 400 --ttcol; 401 if (ISCTRL(buf[--cpos]) != FALSE) { 402 ttputc('\b'); 403 ttputc(' '); 404 ttputc('\b'); 405 --ttcol; 406 } 407 epos--; 408 } 409 ttflush(); 410 break; 411 case CCHR('W'): /* kill to beginning of word */ 412 while ((cpos > 0) && !ISWORD(buf[cpos - 1])) { 413 ttputc('\b'); 414 ttputc(' '); 415 ttputc('\b'); 416 --ttcol; 417 if (ISCTRL(buf[--cpos]) != FALSE) { 418 ttputc('\b'); 419 ttputc(' '); 420 ttputc('\b'); 421 --ttcol; 422 } 423 epos--; 424 } 425 while ((cpos > 0) && ISWORD(buf[cpos - 1])) { 426 ttputc('\b'); 427 ttputc(' '); 428 ttputc('\b'); 429 --ttcol; 430 if (ISCTRL(buf[--cpos]) != FALSE) { 431 ttputc('\b'); 432 ttputc(' '); 433 ttputc('\b'); 434 --ttcol; 435 } 436 epos--; 437 } 438 ttflush(); 439 break; 440 case CCHR('\\'): 441 case CCHR('Q'): /* quote next */ 442 c = getkey(FALSE); 443 /* FALLTHROUGH */ 444 default: 445 if (dynbuf && epos + 1 >= nbuf) { 446 void *newp; 447 size_t newsize = epos + epos + 16; 448 if ((newp = realloc(buf, newsize)) == NULL) 449 goto fail; 450 buf = newp; 451 nbuf = newsize; 452 } 453 for (i = epos; i > cpos; i--) 454 buf[i] = buf[i - 1]; 455 buf[cpos++] = (char)c; 456 epos++; 457 eputc((char)c); 458 cc = ttcol; 459 rr = ttrow; 460 for (i = cpos; i < epos; i++) 461 eputc(buf[i]); 462 ttmove(rr, cc); 463 ttflush(); 464 } 465 } 466 done: 467 if (cwin == TRUE) { 468 /* blow away cpltion window */ 469 bp = bfind("*Completions*", TRUE); 470 if ((wp = popbuf(bp)) != NULL) { 471 curwp = wp; 472 delwind(FFRAND, 1); 473 } 474 } 475 return (ret); 476 fail: 477 ewprintf("Out of memory"); 478 free(buf); 479 return (NULL); 480 } 481 482 /* 483 * Do completion on a list of objects. 484 * c is SPACE, TAB, or CR 485 * return TRUE if matched (or partially matched) 486 * FALSE is result is ambiguous, 487 * ABORT on error. 488 */ 489 static int 490 complt(int flags, int c, char *buf, size_t nbuf, int cpos, int *nx) 491 { 492 struct list *lh, *lh2; 493 struct list *wholelist = NULL; 494 int i, nxtra, nhits, bxtra, msglen, nshown; 495 int wflag = FALSE; 496 char *msg; 497 498 lh = lh2 = NULL; 499 500 if ((flags & EFFUNC) != 0) { 501 buf[cpos] = '\0'; 502 wholelist = lh = complete_function_list(buf); 503 } else if ((flags & EFBUF) != 0) { 504 lh = &(bheadp->b_list); 505 } else if ((flags & EFFILE) != 0) { 506 buf[cpos] = '\0'; 507 wholelist = lh = make_file_list(buf); 508 } else 509 panic("broken complt call: flags"); 510 511 if (c == ' ') 512 wflag = TRUE; 513 else if (c != '\t' && c != CCHR('M')) 514 panic("broken complt call: c"); 515 516 nhits = 0; 517 nxtra = HUGE; 518 519 for (; lh != NULL; lh = lh->l_next) { 520 if (memcmp(buf, lh->l_name, cpos) != 0) 521 continue; 522 if (nhits == 0) 523 lh2 = lh; 524 ++nhits; 525 if (lh->l_name[cpos] == '\0') 526 nxtra = -1; /* exact match */ 527 else { 528 bxtra = getxtra(lh, lh2, cpos, wflag); 529 if (bxtra < nxtra) 530 nxtra = bxtra; 531 lh2 = lh; 532 } 533 } 534 if (nhits == 0) 535 msg = " [No match]"; 536 else if (nhits > 1 && nxtra == 0) 537 msg = " [Ambiguous. Ctrl-G to cancel]"; 538 else { 539 /* 540 * Being lazy - ought to check length, but all things 541 * autocompleted have known types/lengths. 542 */ 543 if (nxtra < 0 && nhits > 1 && c == ' ') 544 nxtra = 1; /* ??? */ 545 for (i = 0; i < nxtra && cpos < nbuf; ++i) { 546 buf[cpos] = lh2->l_name[cpos]; 547 eputc(buf[cpos++]); 548 } 549 /* XXX should grow nbuf */ 550 ttflush(); 551 free_file_list(wholelist); 552 *nx = nxtra; 553 if (nxtra < 0 && c != CCHR('M')) /* exact */ 554 *nx = 0; 555 return (TRUE); 556 } 557 558 /* 559 * wholelist is NULL if we are doing buffers. Want to free lists 560 * that were created for us, but not the buffer list! 561 */ 562 free_file_list(wholelist); 563 564 /* Set up backspaces, etc., being mindful of echo line limit. */ 565 msglen = strlen(msg); 566 nshown = (ttcol + msglen + 2 > ncol) ? 567 ncol - ttcol - 2 : msglen; 568 eputs(msg); 569 ttcol -= (i = nshown); /* update ttcol! */ 570 while (i--) /* move back before msg */ 571 ttputc('\b'); 572 ttflush(); /* display to user */ 573 i = nshown; 574 while (i--) /* blank out on next flush */ 575 eputc(' '); 576 ttcol -= (i = nshown); /* update ttcol on BS's */ 577 while (i--) 578 ttputc('\b'); /* update ttcol again! */ 579 *nx = nxtra; 580 return ((nhits > 0) ? TRUE : FALSE); 581 } 582 583 /* 584 * Do completion on a list of objects, listing instead of completing. 585 */ 586 static int 587 complt_list(int flags, char *buf, int cpos) 588 { 589 struct list *lh, *lh2, *lh3; 590 struct list *wholelist = NULL; 591 struct buffer *bp; 592 int i, maxwidth, width; 593 int preflen = 0; 594 int oldrow = ttrow; 595 int oldcol = ttcol; 596 int oldhue = tthue; 597 char *linebuf; 598 size_t linesize, len; 599 char *cp; 600 601 lh = NULL; 602 603 ttflush(); 604 605 /* The results are put into a completion buffer. */ 606 bp = bfind("*Completions*", TRUE); 607 if (bclear(bp) == FALSE) 608 return (FALSE); 609 610 /* 611 * First get the list of objects. This list may contain only 612 * the ones that complete what has been typed, or may be the 613 * whole list of all objects of this type. They are filtered 614 * later in any case. Set wholelist if the list has been 615 * cons'ed up just for us, so we can free it later. We have 616 * to copy the buffer list for this function even though we 617 * didn't for complt. The sorting code does destructive 618 * changes to the list, which we don't want to happen to the 619 * main buffer list! 620 */ 621 if ((flags & EFBUF) != 0) 622 wholelist = lh = copy_list(&(bheadp->b_list)); 623 else if ((flags & EFFUNC) != 0) { 624 buf[cpos] = '\0'; 625 wholelist = lh = complete_function_list(buf); 626 } else if ((flags & EFFILE) != 0) { 627 buf[cpos] = '\0'; 628 wholelist = lh = make_file_list(buf); 629 /* 630 * We don't want to display stuff up to the / for file 631 * names preflen is the list of a prefix of what the 632 * user typed that should not be displayed. 633 */ 634 cp = strrchr(buf, '/'); 635 if (cp) 636 preflen = cp - buf + 1; 637 } else 638 panic("broken complt call: flags"); 639 640 /* 641 * Sort the list, since users expect to see it in alphabetic 642 * order. 643 */ 644 lh2 = lh; 645 while (lh2 != NULL) { 646 lh3 = lh2->l_next; 647 while (lh3 != NULL) { 648 if (strcmp(lh2->l_name, lh3->l_name) > 0) { 649 cp = lh2->l_name; 650 lh2->l_name = lh3->l_name; 651 lh3->l_name = cp; 652 } 653 lh3 = lh3->l_next; 654 } 655 lh2 = lh2->l_next; 656 } 657 658 /* 659 * First find max width of object to be displayed, so we can 660 * put several on a line. 661 */ 662 maxwidth = 0; 663 lh2 = lh; 664 while (lh2 != NULL) { 665 for (i = 0; i < cpos; ++i) { 666 if (buf[i] != lh2->l_name[i]) 667 break; 668 } 669 if (i == cpos) { 670 width = strlen(lh2->l_name); 671 if (width > maxwidth) 672 maxwidth = width; 673 } 674 lh2 = lh2->l_next; 675 } 676 maxwidth += 1 - preflen; 677 678 /* 679 * Now do the display. Objects are written into linebuf until 680 * it fills, and then put into the help buffer. 681 */ 682 linesize = MAX(ncol, maxwidth) + 1; 683 if ((linebuf = malloc(linesize)) == NULL) 684 return (FALSE); 685 width = 0; 686 687 /* 688 * We're going to strlcat() into the buffer, so it has to be 689 * NUL terminated. 690 */ 691 linebuf[0] = '\0'; 692 for (lh2 = lh; lh2 != NULL; lh2 = lh2->l_next) { 693 for (i = 0; i < cpos; ++i) { 694 if (buf[i] != lh2->l_name[i]) 695 break; 696 } 697 /* if we have a match */ 698 if (i == cpos) { 699 /* if it wraps */ 700 if ((width + maxwidth) > ncol) { 701 addline(bp, linebuf); 702 linebuf[0] = '\0'; 703 width = 0; 704 } 705 len = strlcat(linebuf, lh2->l_name + preflen, 706 linesize); 707 width += maxwidth; 708 if (len < width && width < linesize) { 709 /* pad so the objects nicely line up */ 710 memset(linebuf + len, ' ', 711 maxwidth - strlen(lh2->l_name + preflen)); 712 linebuf[width] = '\0'; 713 } 714 } 715 } 716 if (width > 0) 717 addline(bp, linebuf); 718 free(linebuf); 719 720 /* 721 * Note that we free lists only if they are put in wholelist lists 722 * that were built just for us should be freed. However when we use 723 * the buffer list, obviously we don't want it freed. 724 */ 725 free_file_list(wholelist); 726 popbuftop(bp); /* split the screen and put up the help 727 * buffer */ 728 update(); /* needed to make the new stuff actually 729 * appear */ 730 ttmove(oldrow, oldcol); /* update leaves cursor in arbitrary place */ 731 ttcolor(oldhue); /* with arbitrary color */ 732 ttflush(); 733 return (0); 734 } 735 736 /* 737 * The "lp1" and "lp2" point to list structures. The "cpos" is a horizontal 738 * position in the name. Return the longest block of characters that can be 739 * autocompleted at this point. Sometimes the two symbols are the same, but 740 * this is normal. 741 */ 742 int 743 getxtra(struct list *lp1, struct list *lp2, int cpos, int wflag) 744 { 745 int i; 746 747 i = cpos; 748 for (;;) { 749 if (lp1->l_name[i] != lp2->l_name[i]) 750 break; 751 if (lp1->l_name[i] == '\0') 752 break; 753 ++i; 754 if (wflag && !ISWORD(lp1->l_name[i - 1])) 755 break; 756 } 757 return (i - cpos); 758 } 759 760 /* 761 * Special "printf" for the echo line. Each call to "ewprintf" starts a 762 * new line in the echo area, and ends with an erase to end of the echo 763 * line. The formatting is done by a call to the standard formatting 764 * routine. 765 */ 766 /* VARARGS */ 767 void 768 ewprintf(const char *fmt, ...) 769 { 770 va_list ap; 771 772 #ifndef NO_MACRO 773 if (inmacro) 774 return; 775 #endif /* !NO_MACRO */ 776 va_start(ap, fmt); 777 ttcolor(CTEXT); 778 ttmove(nrow - 1, 0); 779 eformat(fmt, ap); 780 va_end(ap); 781 tteeol(); 782 ttflush(); 783 epresf = TRUE; 784 } 785 786 /* 787 * Printf style formatting. This is called by both "ewprintf" and "ereply" 788 * to provide formatting services to their clients. The move to the start 789 * of the echo line, and the erase to the end of the echo line, is done by 790 * the caller. 791 * Note: %c works, and prints the "name" of the character. 792 * %k prints the name of a key (and takes no arguments). 793 */ 794 static void 795 eformat(const char *fp, va_list ap) 796 { 797 char kname[NKNAME], tmp[100], *cp; 798 int c; 799 800 while ((c = *fp++) != '\0') { 801 if (c != '%') 802 eputc(c); 803 else { 804 c = *fp++; 805 switch (c) { 806 case 'c': 807 getkeyname(kname, sizeof(kname), va_arg(ap, int)); 808 eputs(kname); 809 break; 810 811 case 'k': 812 for (cp = kname, c = 0; c < key.k_count; c++) { 813 if (c) 814 *cp++ = ' '; 815 cp = getkeyname(cp, sizeof(kname) - 816 (cp - kname) - 1, key.k_chars[c]); 817 } 818 eputs(kname); 819 break; 820 821 case 'd': 822 eputi(va_arg(ap, int), 10); 823 break; 824 825 case 'o': 826 eputi(va_arg(ap, int), 8); 827 break; 828 829 case 'p': 830 snprintf(tmp, sizeof(tmp), "%p", 831 va_arg(ap, void *)); 832 eputs(tmp); 833 break; 834 835 case 's': 836 eputs(va_arg(ap, char *)); 837 break; 838 839 case 'l': 840 /* explicit longword */ 841 c = *fp++; 842 switch (c) { 843 case 'd': 844 eputl(va_arg(ap, long), 10); 845 break; 846 default: 847 eputc(c); 848 break; 849 } 850 break; 851 852 default: 853 eputc(c); 854 } 855 } 856 } 857 } 858 859 /* 860 * Put integer, in radix "r". 861 */ 862 static void 863 eputi(int i, int r) 864 { 865 int q; 866 867 if (i < 0) { 868 eputc('-'); 869 i = -i; 870 } 871 if ((q = i / r) != 0) 872 eputi(q, r); 873 eputc(i % r + '0'); 874 } 875 876 /* 877 * Put long, in radix "r". 878 */ 879 static void 880 eputl(long l, int r) 881 { 882 long q; 883 884 if (l < 0) { 885 eputc('-'); 886 l = -l; 887 } 888 if ((q = l / r) != 0) 889 eputl(q, r); 890 eputc((int)(l % r) + '0'); 891 } 892 893 /* 894 * Put string. 895 */ 896 static void 897 eputs(const char *s) 898 { 899 int c; 900 901 while ((c = *s++) != '\0') 902 eputc(c); 903 } 904 905 /* 906 * Put character. Watch for control characters, and for the line getting 907 * too long. 908 */ 909 static void 910 eputc(char c) 911 { 912 if (ttcol + 2 < ncol) { 913 if (ISCTRL(c)) { 914 eputc('^'); 915 c = CCHR(c); 916 } 917 ttputc(c); 918 ++ttcol; 919 } 920 } 921 922 void 923 free_file_list(struct list *lp) 924 { 925 struct list *next; 926 927 while (lp) { 928 next = lp->l_next; 929 free(lp->l_name); 930 free(lp); 931 lp = next; 932 } 933 } 934 935 static struct list * 936 copy_list(struct list *lp) 937 { 938 struct list *current, *last, *nxt; 939 940 last = NULL; 941 while (lp) { 942 current = malloc(sizeof(struct list)); 943 if (current == NULL) { 944 /* Free what we have allocated so far */ 945 for (current = last; current; current = nxt) { 946 nxt = current->l_next; 947 free(current->l_name); 948 free(current); 949 } 950 return (NULL); 951 } 952 current->l_next = last; 953 current->l_name = strdup(lp->l_name); 954 last = current; 955 lp = lp->l_next; 956 } 957 return (last); 958 } 959