1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31 /* All Rights Reserved */ 32 33 /* 34 * University Copyright- Copyright (c) 1982, 1986, 1988 35 * The Regents of the University of California 36 * All Rights Reserved 37 * 38 * University Acknowledgment- Portions of this document are derived from 39 * software developed by the University of California, Berkeley, and its 40 * contributors. 41 */ 42 43 #pragma ident "%Z%%M% %I% %E% SMI" 44 45 /* 46 * @(#) more.c 1.1 88/03/29 more:more.c 47 */ 48 49 /* 50 ** more.c - General purpose tty output filter and file perusal program 51 ** 52 ** by Eric Shienbrood, UC Berkeley 53 ** 54 ** modified by Geoff Peck, UCB to add underlining, single spacing 55 ** modified by John Foderaro, UCB to add -c and MORE environment variable 56 ** modified by Hans Spiller, Microsoft to handle \r better July 23, 82 57 ** added ? help command, and -w 58 ** 59 ** vwh 11 Jan 83 M001 60 ** modified to handle x.out magic number and magic number 61 ** byte ordering OTHER than the vax and pdp11. 62 ** JJD 19 Jan 83 M002 63 ** - fix distributed on USENET 64 ** From decvax!ucbvax!dist2 Sun Dec 6 02:58:31 1981 65 ** Subject: FIXED: bug in src/more/more.c 66 ** - fixed bug on terminal with "magic cookie" standout 67 ** sequences. 68 ** JJD 14 Feb 83 M003 69 ** - fix exit status of more 70 ** - Made first letter of "no more" message uppercase 71 ** andyp 03 Aug 83 M004 3.0 upgrade 72 ** - moved <local/uparm.h> to cmd/include. 73 ** - use UCB, rather than XENIX, stty(2). 74 ** andyp 30 Nov 83 M005 75 ** - (thanks to reubenb). Changed frame variable to static, it is 76 ** used as a global buffer. We never saw the bug before because 77 ** of the depth of the stack. 78 ** barrys 03 Jul 84 M006 79 ** - Updated the usage message to include the 's' and 'w' options 80 ** and to make the 'n' option a separate entry (uncommented). 81 ** ericc 26 Dec 84 M007 82 ** - Replaced the constant 0x7fffffffffffffffL with MAXLONG. 83 ** ericc 25 Jul 85 M008 84 ** - made "-r" option display control characters as '^x', as documented. 85 ** - fixed processing of '\b' so that more doesn't terminate when 86 ** the sequence "\b\n" is encountered. 87 ** - changed "Hit Rubout ..." to "Hit Del ...", for ibm keyboards. 88 ** davidby 9 March 1988 Unmarked 89 ** - replaced all locally defined functions with library equivalents, 90 ** - changed from termcap to terminfo 91 ** - included <values.h> for MAXLONG value 92 ** - removed most ifdef code for V6, V7, and BSD 93 ** - added /etc/magic support for file type checking 94 */ 95 96 #include <ctype.h> 97 #include <signal.h> 98 #include <errno.h> 99 #include <sys/types.h> 100 #include <sys/wait.h> 101 #include <curses.h> 102 #include <term.h> 103 #include <sys/ioctl.h> 104 #include <setjmp.h> 105 #include <sys/stat.h> 106 #include <values.h> 107 #include <stdlib.h> 108 #include <stdarg.h> 109 #include <string.h> 110 #include <unistd.h> 111 #include <libgen.h> 112 #include <euc.h> 113 #include <getwidth.h> 114 #include <locale.h> 115 #include <widec.h> 116 #include <wctype.h> 117 #include <limits.h> 118 eucwidth_t wp; 119 int cw[4]; 120 int scw[4]; 121 #include <locale.h> 122 123 /* Help file will eventually go in libpath(more.help) on all systems */ 124 125 #ifdef INGRES 126 #define VI "/usr/bin/vi" 127 #define HELPFILE "/mntp/doucette/more/more.help" 128 #define LOCAL_HELP "/usr/lib/locale/%s/LC_MESSAGES/more.help" 129 #endif 130 131 #ifndef INGRES 132 #ifndef HELPFILE 133 #define HELPFILE "/usr/lib/more.help" 134 #define LOCAL_HELP "/usr/lib/locale/%s/LC_MESSAGES/more.help" 135 #endif 136 #define VI "vi" 137 #endif 138 139 #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 140 #define Ftell(f) file_pos 141 #define Fseek(f,off) (file_pos=off,fseeko(f,off,0)) 142 #define Getc(f) (++file_pos, getc(f)) 143 #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 144 145 #define pr(s1) fputs(s1, stdout) 146 #define clreos() putp(clr_eos) 147 #define cleareol() putp(clr_eol) 148 #define home() putp(cursor_home) 149 150 #define LINSIZ 512 151 #define ctrl(letter) ((letter) & 077) 152 #define RUBOUT '\177' 153 #define ESC '\033' 154 #define QUIT '\034' 155 156 struct termio otty; /* old tty modes */ 157 struct termio ntty; /* new tty modes */ 158 off_t file_pos, file_size; 159 int fnum, no_intty, no_tty; 160 int dum_opt; 161 off_t dlines; 162 void end_it(int sig); 163 void onquit(int sig); 164 void chgwinsz(int sig); 165 #ifdef SIGTSTP 166 void onsusp(int sig); 167 #endif 168 int nscroll = 11; /* Number of lines scrolled by 'd' */ 169 int fold_opt = 1; /* Fold long lines */ 170 int stop_opt = 1; /* Stop after form feeds */ 171 int ssp_opt = 0; /* Suppress white space */ 172 int ul_opt = 1; /* Underline as best we can */ 173 int cr_opt = 0; /* show ctrl characters as '^c' */ 174 int wait_opt = 0; /* prompt for exit at eof */ 175 int promptlen; 176 off_t Currline; /* Line we are currently at */ 177 int startup = 1; 178 int firstf = 1; 179 int notell = 1; 180 int inwait, Pause, errors; 181 int within; /* true if we are within a file, 182 false if we are between files */ 183 int hard, dumb, noscroll, hardtabs, clreol; 184 int catch_susp; /* We should catch the SIGTSTP signal */ 185 char **fnames; /* The list of file names */ 186 int nfiles; /* Number of files left to process */ 187 char *shell; /* The name of the shell to use */ 188 int shellp; /* A previous shell command exists */ 189 char ch; 190 jmp_buf restore; 191 char obuf[BUFSIZ]; /* stdout buffer */ 192 char Line[LINSIZ]; /* Line buffer */ 193 int Lpp = 24; /* lines per page */ 194 char *ULenter, *ULexit; /* enter and exit underline mode */ 195 int Mcol = 80; /* number of columns */ 196 int Wrap = 1; /* set if automargins */ 197 int fseeko(); 198 struct { 199 off_t chrctr, line; 200 } context, screen_start; 201 int exitstat = 0; /* status to use when exiting more */ /*M003*/ 202 203 static void execute(char *filename, char *cmd, ...); 204 static void error(char *mess); 205 static void wait_eof(void); 206 static void prompt(char *filename); 207 static void argscan(char *s); 208 static void copy_file(register FILE *f); 209 static void initterm(void); 210 static void do_shell(char *filename); 211 static FILE *checkf(register char *fs, int *clearfirst); 212 static void screen(register FILE *f, register off_t num_lines); 213 static void skiplns(register off_t n, register FILE *f); 214 static void skipf(register int nskip); 215 static int readch(void); 216 static void prmpt_erase(register int col); 217 static void kill_line(void); 218 static void prbuf(register char *s, register int n); 219 static void search(char buf[], FILE *file, register off_t n); 220 static void doclear(void); 221 static void ttyin(char buf[], register int nmax, char pchar); 222 static int expand(char *outbuf, char *inbuf); 223 static void show(register char ch); 224 static void set_tty(void); 225 static void reset_tty(void); 226 static void rdline(register FILE *f); 227 static off_t command(char *filename, register FILE *f); 228 static int getline(register FILE *f, int *length); 229 static int number(char *cmd); 230 static int colon(char *filename, int cmd, off_t nlines); 231 232 int 233 main(int argc, char *argv[]) 234 { 235 register FILE *f; 236 register char *s; 237 register char *p; 238 register int ch; 239 register off_t left; 240 int prnames = 0; 241 int initopt = 0; 242 int srchopt = 0; 243 int clearit = 0; 244 off_t initline; 245 char initbuf[80]; 246 247 setlocale( LC_ALL, "" ); 248 getwidth(&wp); 249 cw[0] = 1; 250 cw[1] = wp._eucw1; 251 cw[2] = wp._eucw2+1; 252 cw[3] = wp._eucw3+1; 253 scw[0] = 1; 254 scw[1] = wp._scrw1; 255 scw[2] = wp._scrw2; 256 scw[3] = wp._scrw3; 257 258 nfiles = argc; 259 fnames = argv; 260 261 (void) setlocale(LC_ALL,""); 262 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 263 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 264 #endif 265 (void) textdomain(TEXT_DOMAIN); 266 267 initterm (); 268 if(s = getenv("MORE")) argscan(s); 269 while (--nfiles > 0) { 270 if ((ch = (*++fnames)[0]) == '-') { 271 argscan(*fnames+1); 272 } 273 else if (ch == '+') { 274 s = *fnames; 275 if (*++s == '/') { 276 srchopt++; 277 for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 278 *p++ = *s++; 279 *p = '\0'; 280 } 281 else { 282 initopt++; 283 for (initline = 0; *s != '\0'; s++) 284 if (isdigit (*s)) 285 initline = initline*10 + *s -'0'; 286 --initline; 287 } 288 } 289 else break; 290 } 291 /* allow clreol only if cursor_home and clr_eol and clr_eos strings are 292 * defined, and in that case, make sure we are in noscroll mode 293 */ 294 if(clreol) 295 { 296 if (!cursor_home || !clr_eol || !clr_eos) { 297 clreol = 0; 298 } 299 else noscroll = 1; 300 } 301 302 if (dlines == 0) 303 dlines =(off_t) (Lpp - (noscroll ? 1 : 2)); 304 left = dlines; 305 if (nfiles > 1) 306 prnames++; 307 if (!no_intty && nfiles == 0) { 308 fprintf(stderr, gettext("Usage: %s\ 309 [-cdflrsuw] [-lines] [+linenumber] [+/pattern] [filename ...].\n") 310 , argv[0]); 311 exit(1); 312 } 313 else 314 f = stdin; 315 if (!no_tty) { 316 signal(SIGQUIT, onquit); 317 signal(SIGINT, end_it); 318 signal(SIGWINCH, chgwinsz); 319 #ifdef SIGTSTP 320 if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 321 signal(SIGTSTP, onsusp); 322 catch_susp++; 323 } 324 #endif 325 set_tty(); 326 } 327 if (no_intty) { 328 if (no_tty) 329 copy_file (stdin); 330 else { 331 if ((ch = Getc (f)) == '\f') 332 doclear(); 333 else { 334 Ungetc (ch, f); 335 if (noscroll && (ch != EOF)) { 336 if (clreol) 337 home (); 338 else 339 doclear (); 340 } 341 } 342 if (!setjmp(restore)) { 343 if (srchopt) { 344 search (initbuf, stdin,(off_t) 1); 345 if (noscroll) 346 left--; 347 } 348 else if (initopt) 349 skiplns (initline, stdin); 350 } 351 else 352 left = command(NULL, f); 353 screen (stdin, left); 354 } 355 no_intty = 0; 356 prnames++; 357 firstf = 0; 358 } 359 360 while (fnum < nfiles) { 361 if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 362 context.line = context.chrctr = 0; 363 Currline = 0; 364 if (firstf) setjmp (restore); 365 if (firstf) { 366 firstf = 0; 367 if (srchopt) 368 { 369 search (initbuf, f,(off_t) 1); 370 if (noscroll) 371 left--; 372 } 373 else if (initopt) 374 skiplns (initline, f); 375 } 376 else if (fnum < nfiles && !no_tty) { 377 setjmp (restore); 378 left = command (fnames[fnum], f); 379 } 380 if (left != 0) { 381 if ((noscroll || clearit) && (file_size != LLONG_MAX)) 382 if (clreol) 383 home (); 384 else 385 doclear (); 386 if (prnames) { 387 if (ceol_standout_glitch) 388 prmpt_erase (0); 389 if (clreol) 390 cleareol (); 391 pr("::::::::::::::"); 392 if (promptlen > 14) 393 prmpt_erase (14); 394 printf ("\n"); 395 if(clreol) cleareol(); 396 printf("%s\n", fnames[fnum]); 397 if(clreol) cleareol(); 398 pr("::::::::::::::\n"); 399 if (left > (off_t)(Lpp - 4)) 400 left =(off_t)(Lpp - 4); 401 } 402 if (no_tty) 403 copy_file (f); 404 else { 405 within++; 406 screen(f, left); 407 within = 0; 408 } 409 } 410 setjmp (restore); 411 fflush(stdout); 412 fclose(f); 413 screen_start.line = screen_start.chrctr = 0LL; 414 context.line = context.chrctr = 0LL; 415 } else 416 exitstat |= 1; /*M003*/ 417 fnum++; 418 firstf = 0; 419 } 420 if (wait_opt) wait_eof(); 421 reset_tty (); 422 return (exitstat); /*M003*/ 423 } 424 425 static void 426 argscan(char *s) 427 { 428 for (dlines = 0; *s != '\0'; s++) 429 if (isdigit(*s)) 430 dlines = dlines*10 + *s - '0'; 431 else if (*s == 'd') 432 dum_opt = 1; 433 else if (*s == 'l') 434 stop_opt = 0; 435 else if (*s == 'f') 436 fold_opt = 0; 437 else if (*s == 'p') 438 noscroll++; 439 else if (*s == 'c') 440 clreol++; 441 else if (*s == 's') 442 ssp_opt = 1; 443 else if (*s == 'u') 444 ul_opt = 0; 445 else if (*s == 'r') 446 cr_opt = 1; 447 else if (*s == 'w') 448 wait_opt = 1; 449 } 450 451 452 /* 453 ** Check whether the file named by fs is a file which the user may 454 ** access. If it is, return the opened file. Otherwise return NULL. 455 */ 456 457 static FILE * 458 checkf(register char *fs, int *clearfirst) 459 { 460 struct stat stbuf; 461 register FILE *f; 462 int c; 463 464 if (stat (fs, &stbuf) == -1) { 465 fflush(stdout); 466 if (clreol) 467 cleareol (); 468 perror(fs); 469 return (NULL); 470 } 471 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 472 printf(gettext("\n*** %s: directory ***\n\n"), fs); 473 return (NULL); 474 } 475 if ((f=Fopen(fs, "r")) == NULL) { 476 fflush(stdout); 477 perror(fs); 478 return (NULL); 479 } 480 481 if ((c = Getc(f)) == '\f') /* end M001 */ 482 *clearfirst = 1; 483 else { 484 *clearfirst = 0; 485 Ungetc (c, f); 486 } 487 if ((file_size = (off_t)stbuf.st_size) == 0) 488 file_size = LLONG_MAX; 489 return (f); 490 } 491 492 /* 493 ** Print out the contents of the file f, one screenful at a time. 494 */ 495 496 #define STOP -10 497 498 static void 499 screen(register FILE *f, register off_t num_lines) 500 { 501 register int c; 502 register int nchars; 503 int length; /* length of current line */ 504 static int prev_len = 1; /* length of previous line */ 505 506 for (;;) { 507 while (num_lines > 0 && !Pause) { 508 if ((nchars = getline (f, &length)) == EOF) 509 { 510 if (clreol) clreos(); 511 return; 512 } 513 if (ssp_opt && length == 0 && prev_len == 0) 514 continue; 515 prev_len = length; 516 if (ceol_standout_glitch || 517 (enter_standout_mode && *enter_standout_mode == ' ') 518 && promptlen > 0) 519 prmpt_erase (0); 520 /* must clear before drawing line since tabs on some terminals 521 * do not erase what they tab over. 522 */ 523 if (clreol) 524 cleareol (); 525 prbuf (Line, length); 526 if (nchars < promptlen) 527 prmpt_erase (nchars); /* prmpt_erase () sets promptlen to 0 */ 528 else promptlen = 0; 529 /* is this needed? 530 * if (clreol) 531 * cleareol(); */ /* must clear again in case we wrapped */ 532 533 if (nchars < Mcol || !fold_opt) 534 putchar('\n'); 535 if (nchars == STOP) 536 break; 537 num_lines--; 538 } 539 fflush(stdout); 540 if ((c = Getc(f)) == EOF) 541 { 542 if (clreol) clreos (); 543 return; 544 } 545 546 if (Pause && clreol) 547 clreos (); 548 Ungetc (c, f); 549 setjmp (restore); 550 Pause = 0; startup = 0; 551 if ((num_lines = command (NULL, f)) == 0) 552 return; 553 if (hard && promptlen > 0) 554 prmpt_erase (0); 555 if (noscroll && num_lines == dlines) { 556 if (clreol) 557 home(); 558 else 559 doclear (); 560 } 561 screen_start.line = Currline; 562 screen_start.chrctr = Ftell (f); 563 } 564 } 565 566 /* 567 ** Come here if a quit signal is received 568 */ 569 /* 570 * sig is put in as a dummy arg to have the compiler not to complain 571 */ 572 573 /* ARGSUSED */ 574 void 575 onquit(int sig) 576 { 577 signal(SIGQUIT, SIG_IGN); 578 if (!inwait) { 579 putchar ('\n'); 580 if (!startup) { 581 signal(SIGQUIT, onquit); 582 longjmp (restore, 1); 583 } 584 else 585 Pause++; 586 } 587 else if (!dum_opt && notell) { 588 write (2, gettext("[Use q or Q to quit]"), 20); 589 promptlen += 20; 590 notell = 0; 591 } 592 signal(SIGQUIT, onquit); 593 } 594 595 /* 596 ** Come here if a signal for a window size change is received 597 */ 598 /*ARGSUSED*/ 599 void 600 chgwinsz(int sig) 601 { 602 struct winsize win; 603 604 (void) signal(SIGWINCH, SIG_IGN); 605 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { 606 if (win.ws_row != 0) { 607 Lpp = win.ws_row; 608 nscroll = Lpp/2 - 1; 609 if (nscroll <= 0) 610 nscroll = 1; 611 dlines = (off_t)(Lpp - (noscroll ? 1 : 2)); 612 } 613 if (win.ws_col != 0) 614 Mcol = win.ws_col; 615 } 616 (void) signal(SIGWINCH, chgwinsz); 617 } 618 619 /* 620 ** Clean up terminal state and exit. Also come here if interrupt signal received 621 */ 622 623 /* 624 * sig is put in as a dummy arg to have the compiler not to complain 625 */ 626 627 /* ARGSUSED */ 628 void 629 end_it(int sig) 630 { 631 632 reset_tty (); 633 if (clreol) { 634 putchar ('\r'); 635 clreos (); 636 fflush (stdout); 637 } 638 else if (!clreol && (promptlen > 0)) { 639 kill_line (); 640 fflush (stdout); 641 } 642 else 643 write (2, "\n", 1); 644 _exit(exitstat); /*M003*/ 645 } 646 647 static void 648 copy_file(register FILE *f) 649 { 650 register int c; 651 652 while ((c = getc(f)) != EOF) 653 putchar(c); 654 } 655 656 static char Bell = ctrl('G'); 657 658 659 /* See whether the last component of the path name "path" is equal to the 660 ** string "string" 661 */ 662 663 int 664 tailequ(char *path, char *string) 665 { 666 return (!strcmp(basename(path), string)); 667 } 668 669 static void 670 prompt(char *filename) 671 { 672 if (clreol) 673 cleareol (); 674 else if (promptlen > 0) 675 kill_line (); 676 if (!hard) { 677 promptlen = 8; 678 if (enter_standout_mode && exit_standout_mode) 679 putp (enter_standout_mode); 680 if (clreol) 681 cleareol (); 682 pr(gettext("--More--")); 683 if (filename != NULL) { 684 promptlen += printf (gettext("(Next file: %s)"), filename); 685 } 686 else if (!no_intty) { 687 promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 688 } 689 if (dum_opt) { 690 promptlen += pr(gettext("[Hit space to continue, Del to abort]")); 691 } 692 if (enter_standout_mode && exit_standout_mode) 693 putp (exit_standout_mode); 694 if (clreol) clreos (); 695 fflush(stdout); 696 } 697 else 698 write (2, &Bell, 1); 699 inwait++; 700 } 701 702 /* 703 * when run from another program or a shell script, it is 704 * sometimes useful to prevent the next program from scrolling 705 * us off the screen before we get a chance to read this page. 706 * -Hans, July 24, 1982 707 */ 708 static void 709 wait_eof(void) 710 { 711 if (enter_standout_mode && exit_standout_mode) 712 putp (enter_standout_mode); 713 promptlen = pr(gettext("--No more--")); /*M003*/ 714 if (dum_opt) 715 promptlen += pr(gettext("[Hit any key to continue]")); 716 if (enter_standout_mode && exit_standout_mode) 717 putp(exit_standout_mode); 718 if (clreol) clreos(); 719 fflush(stdout); 720 readch(); 721 prmpt_erase (0); 722 fflush(stdout); 723 } 724 725 /* 726 ** Get a logical line 727 */ 728 729 static int 730 getline(register FILE *f, int *length) 731 { 732 register int c; 733 register char *p; 734 register int column; 735 static int colflg; 736 register int oldcolumn; 737 int csno; 738 739 p = Line; 740 column = 0; 741 oldcolumn = 0; 742 c = Getc (f); 743 if (colflg && c == '\n') { 744 Currline++; 745 c = Getc (f); 746 } 747 while (p < &Line[LINSIZ - 1]) { 748 csno = csetno(c); 749 if (c == EOF) { 750 if (p > Line) { 751 *p = '\0'; 752 *length = p - Line; 753 return (column); 754 } 755 *length = p - Line; 756 return (EOF); 757 } 758 if (!csno) { 759 if (c == '\n') { 760 /* detect \r\n. -Hans */ 761 if (p>Line && p[-1] == '\r') { 762 column = oldcolumn; 763 p--; 764 } 765 Currline++; 766 break; 767 } 768 *p++ = c; 769 if (c == '\t') 770 if (hardtabs && column < promptlen && !hard) { 771 if (clr_eol && !dumb) { 772 column = 1 + (column | 7); 773 putp (clr_eol); 774 promptlen = 0; 775 } 776 else { 777 for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 778 *p++ = ' '; 779 } 780 if (column >= promptlen) promptlen = 0; 781 } 782 } 783 else 784 column = 1 + (column | 7); 785 else if ((c == '\b') && (ul_opt || !cr_opt) && (column > 0)) /* M008 */ 786 column--; 787 788 /* this is sort of strange. what was here before was that 789 \r always set column to zero, and the hack above to 790 detect \r\n didnt exist. the net effect is to make 791 the current line be overwritten by the prompt if it 792 had a \r at the end, and the line start after the \r 793 otherwise. I suppose this is useful for overstriking 794 on hard copy terminals, but not on anything glass 795 -Hans */ 796 797 else if ((c == '\r') && !cr_opt) { 798 oldcolumn = column; 799 column = 0; 800 } 801 else if (c == '\f' && stop_opt) { 802 p[-1] = '^'; 803 *p++ = 'L'; 804 column += 2; 805 Pause++; 806 } 807 else if (c == EOF) { 808 *length = p - Line; 809 return (column); 810 } 811 else if (c < ' ' && cr_opt){ /* M008 begin */ 812 p[-1] = '^'; 813 *p++ = c | ('A' - 1); 814 column += 2; 815 } /* M008 end */ 816 else if (c >= ' ' && c != RUBOUT) 817 column++; 818 } /* end of code set 0 */ 819 else { 820 column += scw[csno]; 821 if ( column > Mcol && fold_opt ) { 822 column -= scw[csno]; 823 while ( column < Mcol ) { 824 column++; 825 *p++ = ' '; 826 } 827 column = Mcol; 828 Ungetc(c,f); 829 } else { 830 int i; 831 *p++ = c; 832 for(i=1; i<cw[csno];i++) 833 *p++ = Getc(f); 834 } 835 } /* end of codeset 1 ~ 3 */ 836 if (column >= Mcol && fold_opt) break; 837 c = Getc (f); 838 } 839 if (column >= Mcol && Mcol > 0) { 840 if (!Wrap) { 841 *p++ = '\n'; 842 } 843 } 844 colflg = column == Mcol && fold_opt; 845 if (colflg && eat_newline_glitch && Wrap) { 846 *p++ = '\n'; /* simulate normal wrap */ 847 } 848 *length = p - Line; 849 *p = 0; 850 return (column); 851 } 852 853 /* 854 ** Erase the rest of the prompt, assuming we are starting at column col. 855 */ 856 857 static void 858 prmpt_erase(register int col) 859 { 860 861 if (promptlen == 0) 862 return; 863 if (hard) { 864 putchar ('\n'); 865 } 866 else { 867 if (col == 0) 868 putchar ('\r'); 869 if (!dumb && clr_eol) 870 putp (clr_eol); 871 else 872 for (col = promptlen - col; col > 0; col--) 873 putchar (' '); 874 } 875 promptlen = 0; 876 } 877 878 /* 879 ** Erase the current line entirely 880 */ 881 882 static void 883 kill_line(void) 884 { 885 prmpt_erase (0); 886 if (!clr_eol || dumb) putchar ('\r'); 887 } 888 889 /* Print a buffer of n characters */ 890 891 static void 892 prbuf(register char *s, register int n) 893 { 894 char c; /* next ouput character */ 895 register int state = 0; /* next output char's UL state */ 896 static int pstate = 0; /* current terminal UL state (off) */ 897 898 while (--n >= 0) 899 if (!ul_opt) 900 putchar (*s++); 901 else { 902 if (n >= 2 && s[0] == '_' && s[1] == '\b') { 903 n -= 2; 904 s += 2; 905 c = *s++; 906 state = 1; 907 } else if (n >= 2 && s[1] == '\b' && s[2] == '_') { 908 n -= 2; 909 c = *s++; 910 s += 2; 911 state = 1; 912 } else { 913 c = *s++; 914 state = 0; 915 } 916 if (state != pstate) 917 putp(state ? ULenter : ULexit); 918 pstate = state; 919 putchar(c); 920 if (state && underline_char) { 921 putp(cursor_left); 922 putp(underline_char); 923 } 924 } 925 /* 926 * M002 927 * You don't want to stay in standout mode at the end of the line; 928 * on some terminals, this will leave all of the remaining blank 929 * space on the line in standout mode. 930 */ 931 if (state && !underline_char) { /*M002*/ 932 putp(ULexit); /*M002*/ 933 pstate = 0; /*M002*/ 934 } /*M002*/ 935 } 936 937 /* 938 ** Clear the screen 939 */ 940 941 static void 942 doclear(void) 943 { 944 if (clear_screen && !hard) { 945 putp(clear_screen); 946 947 /* Put out carriage return so that system doesn't 948 ** get confused by escape sequences when expanding tabs 949 */ 950 putchar ('\r'); 951 promptlen = 0; 952 } 953 } 954 955 956 static int lastcmd, lastp; 957 static off_t lastarg; 958 static int lastcolon; 959 char shell_line[132]; 960 961 /* 962 ** Read a command and do it. A command consists of an optional integer 963 ** argument followed by the command character. Return the number of lines 964 ** to display in the next screenful. If there is nothing more to display 965 ** in the current file, zero is returned. 966 */ 967 968 static off_t 969 command(char *filename, register FILE *f) 970 { 971 register off_t nlines; 972 register off_t retval; 973 register int c; 974 char colonch; 975 FILE *helpf; 976 int done; 977 char comchar, cmdbuf[80]; 978 char filebuf[128]; 979 char *loc; 980 981 #define ret(val) retval=val;done++;break 982 983 done = 0; 984 if (!errors) 985 prompt (filename); 986 else 987 errors = 0; 988 for (;;) { 989 nlines = number (&comchar); 990 lastp = colonch = 0; 991 if (comchar == '.') { /* Repeat last command */ 992 lastp++; 993 comchar = lastcmd; 994 nlines = lastarg; 995 if (lastcmd == ':') 996 colonch = lastcolon; 997 } 998 lastcmd = comchar; 999 lastarg = nlines; 1000 if((comchar != RUBOUT) && !dum_opt) { 1001 if (comchar == otty.c_cc[VERASE]) { 1002 kill_line (); 1003 prompt (filename); 1004 continue; 1005 } 1006 } 1007 switch (comchar) { 1008 case ':': 1009 retval = colon (filename, colonch, nlines); 1010 if (retval >= 0) 1011 done++; 1012 break; 1013 case 'b': 1014 case ctrl('B'): 1015 { 1016 register off_t initline; 1017 1018 if (no_intty) { 1019 write(2, &bell, 1); 1020 return (-1); 1021 } 1022 1023 if (nlines == 0) nlines++; 1024 1025 putchar ('\r'); 1026 prmpt_erase (0); 1027 printf ("\n"); 1028 if (clreol) 1029 cleareol (); 1030 printf (gettext("...back %lld page"), nlines); 1031 if (nlines > 1) 1032 pr ("s\n"); 1033 else 1034 pr ("\n"); 1035 1036 if (clreol) 1037 cleareol (); 1038 pr ("\n"); 1039 1040 initline = Currline - dlines * (nlines + 1); 1041 if (! noscroll) 1042 --initline; 1043 if (initline < 0) initline = 0; 1044 Fseek(f, 0LL); 1045 Currline = 0; /* skiplns() will make Currline correct */ 1046 skiplns(initline, f); 1047 if (! noscroll) { 1048 ret(dlines + 1); 1049 } 1050 else { 1051 ret(dlines); 1052 } 1053 } 1054 case ' ': 1055 case 'z': 1056 if (nlines == 0) nlines = dlines; 1057 else if (comchar == 'z') dlines = nlines; 1058 ret (nlines); 1059 case 'd': 1060 case ctrl('D'): 1061 if (nlines != 0) nscroll = nlines; 1062 ret (nscroll); 1063 case RUBOUT: 1064 case 'q': 1065 case 'Q': 1066 end_it(0); 1067 /*NOTREACHED*/ 1068 case 's': 1069 case 'f': 1070 if (nlines == 0) nlines++; 1071 if (comchar == 'f') 1072 nlines *= dlines; 1073 putchar ('\r'); 1074 prmpt_erase (0); 1075 printf ("\n"); 1076 if (clreol) 1077 cleareol (); 1078 printf (gettext("...skipping %lld line"), nlines); 1079 if (nlines > 1) 1080 pr ("s\n"); 1081 else 1082 pr ("\n"); 1083 1084 if (clreol) 1085 cleareol (); 1086 pr ("\n"); 1087 1088 while (nlines > 0) { 1089 while ((c = Getc (f)) != '\n') 1090 if (c == EOF) { 1091 retval = 0; 1092 done++; 1093 goto endsw; 1094 } 1095 Currline++; 1096 nlines--; 1097 } 1098 ret (dlines); 1099 case '\n': 1100 if (nlines != 0) 1101 dlines = nlines; 1102 else 1103 nlines = 1; 1104 ret (nlines); 1105 case '\f': 1106 if (!no_intty) { 1107 doclear (); 1108 Fseek (f, screen_start.chrctr); 1109 Currline = screen_start.line; 1110 ret (dlines); 1111 } 1112 else { 1113 write (2, &Bell, 1); 1114 break; 1115 } 1116 case '\'': 1117 if (!no_intty) { 1118 kill_line (); 1119 pr (gettext("\n***Back***\n\n")); 1120 Fseek (f, context.chrctr); 1121 Currline = context.line; 1122 ret (dlines); 1123 } 1124 else { 1125 write (2, &Bell, 1); 1126 break; 1127 } 1128 case '=': 1129 kill_line (); 1130 promptlen = printf ("%lld", Currline); 1131 fflush (stdout); 1132 break; 1133 case 'n': 1134 lastp++; 1135 /*FALLTHROUGH*/ 1136 case '/': 1137 if (nlines == 0) nlines++; 1138 kill_line (); 1139 pr ("/"); 1140 promptlen = 1; 1141 fflush (stdout); 1142 if (lastp) { 1143 write (2,"\r", 1); 1144 search (NULL, f, nlines); /* Use previous r.e. */ 1145 } 1146 else { 1147 ttyin (cmdbuf, 78, '/'); 1148 write (2, "\r", 1); 1149 search (cmdbuf, f, nlines); 1150 } 1151 ret (dlines-1); 1152 case '!': 1153 do_shell (filename); 1154 break; 1155 case 'h': 1156 case '?': 1157 /* 1158 * First get local help file. 1159 */ 1160 loc = setlocale(LC_MESSAGES, 0); 1161 sprintf(filebuf, LOCAL_HELP, loc); 1162 1163 if ((strcmp(loc, "C") == 0) || (helpf = fopen (filebuf, "r")) == NULL) { 1164 if ((helpf = fopen (HELPFILE, "r")) == NULL) 1165 error (gettext("Can't open help file")); 1166 } 1167 if (noscroll) doclear (); 1168 copy_file (helpf); 1169 fclose (helpf); 1170 prompt (filename); 1171 break; 1172 case 'v': /* This case should go right before default */ 1173 if (!no_intty) { 1174 kill_line (); 1175 cmdbuf[0] = '+'; 1176 sprintf(&cmdbuf[1], "%lld", Currline); 1177 pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 1178 execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 1179 break; 1180 } 1181 default: 1182 if (dum_opt) { 1183 kill_line (); 1184 promptlen = pr(gettext("[Press 'h' for instructions.]")); 1185 fflush (stdout); 1186 } 1187 else 1188 write (2, &Bell, 1); 1189 break; 1190 } 1191 if (done) break; 1192 } 1193 putchar ('\r'); 1194 endsw: 1195 inwait = 0; 1196 notell++; 1197 return (retval); 1198 } 1199 1200 char ch; 1201 1202 /* 1203 * Execute a colon-prefixed command. 1204 * Returns <0 if not a command that should cause 1205 * more of the file to be printed. 1206 */ 1207 1208 static int 1209 colon(char *filename, int cmd, off_t nlines) 1210 { 1211 if (cmd == 0) 1212 ch = readch (); 1213 else 1214 ch = cmd; 1215 lastcolon = ch; 1216 switch (ch) { 1217 case 'f': 1218 kill_line (); 1219 if (!no_intty) 1220 promptlen = printf (gettext("\"%s\" line %lld"), 1221 fnames[fnum], Currline); 1222 else 1223 promptlen = printf( 1224 gettext("[Not a file] line %lld"), Currline); 1225 fflush (stdout); 1226 return (-1); 1227 case 'n': 1228 if (nlines == 0) { 1229 if (fnum >= nfiles - 1) 1230 end_it(0); 1231 nlines++; 1232 } 1233 putchar ('\r'); 1234 prmpt_erase (0); 1235 skipf ((int)nlines); 1236 return (0); 1237 case 'p': 1238 if (no_intty) { 1239 write (2, &Bell, 1); 1240 return (-1); 1241 } 1242 putchar ('\r'); 1243 prmpt_erase (0); 1244 if (nlines == 0) 1245 nlines++; 1246 skipf ((int)-nlines); 1247 return (0); 1248 case '!': 1249 do_shell (filename); 1250 return (-1); 1251 case 'q': 1252 case 'Q': 1253 end_it(0); 1254 default: 1255 write (2, &Bell, 1); 1256 return (-1); 1257 } 1258 } 1259 1260 /* 1261 ** Read a decimal number from the terminal. Set cmd to the non-digit which 1262 ** terminates the number. 1263 */ 1264 1265 static int 1266 number(char *cmd) 1267 { 1268 register int i; 1269 1270 i = 0; ch = otty.c_cc[VKILL]; 1271 for (;;) { 1272 ch = readch (); 1273 if (ch >= '0' && ch <= '9') { 1274 i = i*10 + ch - '0'; 1275 } else if (ch == RUBOUT) { 1276 i = 0; 1277 *cmd = ch; 1278 break; 1279 } else if (ch == otty.c_cc[VKILL]) { 1280 i = 0; 1281 } else { 1282 *cmd = ch; 1283 break; 1284 } 1285 } 1286 return (i); 1287 } 1288 1289 static void 1290 do_shell(char *filename) 1291 { 1292 char cmdbuf[80]; 1293 1294 kill_line (); 1295 pr ("!"); 1296 fflush (stdout); 1297 promptlen = 1; 1298 if (lastp) 1299 pr (shell_line); 1300 else { 1301 ttyin (cmdbuf, 78, '!'); 1302 if (expand (shell_line, cmdbuf)) { 1303 kill_line (); 1304 promptlen = printf ("!%s", shell_line); 1305 } 1306 } 1307 fflush (stdout); 1308 write (2, "\n", 1); 1309 promptlen = 0; 1310 shellp = 1; 1311 execute (filename, shell, shell, "-c", shell_line, 0); 1312 } 1313 1314 /* 1315 ** Search for nth ocurrence of regular expression contained in buf in the file 1316 */ 1317 1318 static void 1319 search(char buf[], FILE *file, register off_t n) 1320 { 1321 off_t startline = Ftell (file); 1322 register off_t line1 = startline; 1323 register off_t line2 = startline; 1324 register off_t line3 = startline; 1325 register off_t lncount; 1326 off_t saveln; 1327 static char *s = NULL; 1328 static char lastbuf[80]; 1329 1330 if (buf != NULL) { 1331 if (s != NULL) 1332 free(s); 1333 if (*buf != '\0') { 1334 if ((s = regcmp(buf, (char *) NULL)) == NULL) 1335 error(gettext("Regular expression botch")); 1336 else 1337 strcpy(lastbuf, buf); 1338 } else { 1339 if ((s = regcmp(lastbuf, (char *) NULL)) == NULL) 1340 error(gettext("No previous regular expression")); 1341 } 1342 } else { 1343 if (s == NULL) 1344 error(gettext("No previous regular expression")); 1345 } 1346 context.line = saveln = Currline; 1347 context.chrctr = startline; 1348 lncount = 0; 1349 while (!feof (file)) { 1350 line3 = line2; 1351 line2 = line1; 1352 line1 = Ftell (file); 1353 rdline (file); 1354 lncount++; 1355 if (regex(s, Line) != NULL) 1356 if (--n == 0) { 1357 if (lncount > 3 || (lncount > 1 && no_intty)) 1358 { 1359 pr ("\n"); 1360 if (clreol) 1361 cleareol (); 1362 pr(gettext("...skipping\n")); 1363 } 1364 if (!no_intty) { 1365 Currline -= (lncount >= 3 ? 3 : lncount); 1366 Fseek (file, line3); 1367 if (noscroll) 1368 if (clreol) { 1369 home (); 1370 cleareol (); 1371 } 1372 else 1373 doclear (); 1374 } 1375 else { 1376 kill_line (); 1377 if (noscroll) 1378 if (clreol) { 1379 home (); 1380 cleareol (); 1381 } else 1382 doclear (); 1383 pr (Line); 1384 putchar ('\n'); 1385 } 1386 break; 1387 } 1388 } 1389 if (feof (file)) { 1390 if (!no_intty) { 1391 Currline = saveln; 1392 Fseek (file, startline); 1393 } 1394 else { 1395 pr (gettext("\nPattern not found\n")); 1396 end_it (0); 1397 } 1398 error (gettext("Pattern not found")); 1399 } 1400 } 1401 1402 #define MAXARGS 10 /* enough for 9 args. We are only passed 4 now */ 1403 1404 static void 1405 execute (char *filename, char *cmd, ...) 1406 { 1407 pid_t id; 1408 va_list ap; 1409 char *argp[MAXARGS]; 1410 int count; 1411 1412 fflush (stdout); 1413 reset_tty (); 1414 while ((id = fork ()) < 0) 1415 sleep (5); 1416 if (id == 0) { 1417 if (no_intty) { /*M002*/ 1418 close(0); /*M002*/ 1419 dup(2); /*M002*/ 1420 } /*M002*/ 1421 va_start(ap, cmd); 1422 count = 0; 1423 do { 1424 #ifndef lint 1425 argp[count] = va_arg(ap, char *); 1426 #else 1427 ap = ap; 1428 #endif 1429 count++; 1430 if (count > MAXARGS) 1431 error (gettext("Too many arguments in execute()\n")); 1432 } while (argp[count - 1] != NULL); 1433 va_end(ap); 1434 execvp(cmd, argp); 1435 write (2, "exec failed\n", 12); 1436 exit (1); 1437 } 1438 signal (SIGINT, SIG_IGN); 1439 signal (SIGQUIT, SIG_IGN); 1440 signal (SIGWINCH, SIG_IGN); 1441 #ifdef SIGTSTP 1442 if (catch_susp) 1443 signal(SIGTSTP, SIG_DFL); 1444 #endif 1445 wait ((pid_t)0); 1446 signal (SIGINT, end_it); 1447 signal (SIGQUIT, onquit); 1448 signal (SIGWINCH, chgwinsz); 1449 #ifdef SIGTSTP 1450 if (catch_susp) 1451 signal(SIGTSTP, onsusp); 1452 #endif 1453 /* 1454 * Since we were ignoring window change signals while we executed 1455 * the command, we must assume the window changed. 1456 */ 1457 (void) chgwinsz(0); 1458 set_tty (); 1459 1460 pr ("------------------------\n"); 1461 prompt (filename); 1462 } 1463 /* 1464 ** Skip n lines in the file f 1465 */ 1466 1467 static void 1468 skiplns(register off_t n, register FILE *f) 1469 { 1470 register int c; 1471 1472 while (n > 0) { 1473 while ((c = Getc (f)) != '\n') 1474 if (c == EOF) 1475 return; 1476 n--; 1477 Currline++; 1478 } 1479 } 1480 1481 /* 1482 ** Skip nskip files in the file list (from the command line). Nskip may be 1483 ** negative. 1484 */ 1485 1486 static void 1487 skipf(register int nskip) 1488 { 1489 if (nskip == 0) return; 1490 if (nskip > 0) { 1491 if (fnum + nskip > nfiles - 1) 1492 nskip = nfiles - fnum - 1; 1493 } 1494 else if (within) 1495 ++fnum; 1496 fnum += nskip; 1497 if (fnum < 0) 1498 fnum = 0; 1499 pr (gettext("\n...Skipping ")); 1500 pr ("\n"); 1501 if (clreol) 1502 cleareol (); 1503 if (nskip > 0) 1504 printf(gettext("...Skipping to file %s\n"), fnames[fnum]); 1505 else 1506 printf(gettext("...Skipping back to file %s\n"), fnames[fnum]); 1507 if (clreol) 1508 cleareol (); 1509 pr ("\n"); 1510 --fnum; 1511 } 1512 1513 /*----------------------------- Terminal I/O -------------------------------*/ 1514 1515 static void 1516 initterm(void) 1517 { 1518 int erret = 0; 1519 1520 setbuf(stdout, obuf); 1521 if (!(no_tty = ioctl(1, TCGETA, &otty))) { 1522 if (setupterm(NULL, 1, &erret) != OK) { 1523 dumb++; ul_opt = 0; 1524 } 1525 else { 1526 reset_shell_mode(); 1527 if (((Lpp = lines) < 0) || hard_copy) { 1528 hard++; /* Hard copy terminal */ 1529 Lpp = 24; 1530 } 1531 if (tailequ(fnames[0], "page") || !hard && (scroll_forward == NULL)) 1532 noscroll++; 1533 if ((Mcol = columns) < 0) 1534 Mcol = 80; 1535 Wrap = tigetflag("am"); 1536 /* 1537 * Set up for underlining: some terminals don't need it; 1538 * others have start/stop sequences, still others have an 1539 * underline char sequence which is assumed to move the 1540 * cursor forward one character. If underline sequence 1541 * isn't available, settle for standout sequence. 1542 */ 1543 1544 if (transparent_underline || over_strike) 1545 ul_opt = 0; 1546 if ((ULenter = tigetstr("smul")) == NULL && 1547 (!underline_char) && (ULenter = tigetstr("smso")) == NULL) 1548 ULenter = ""; 1549 if ((ULexit = tigetstr("rmul")) == NULL && 1550 (!underline_char) && (ULexit = tigetstr("rmso")) == NULL) 1551 ULexit = ""; 1552 } 1553 if ((shell = getenv("SHELL")) == NULL) 1554 shell = "/usr/bin/sh"; 1555 } 1556 no_intty = ioctl(0, TCGETA, &otty); 1557 ioctl(2, TCGETA, &otty); 1558 hardtabs = !(otty.c_oflag & TAB3); 1559 } 1560 1561 static int 1562 readch(void) 1563 { 1564 char ch; 1565 extern int errno; 1566 1567 if (read (2, &ch, 1) <= 0) 1568 if (errno != EINTR) 1569 end_it(0); /* clean up before exiting */ 1570 else 1571 ch = otty.c_cc[VKILL]; 1572 return (ch); 1573 } 1574 1575 static char BS = '\b'; 1576 static char CARAT = '^'; 1577 1578 static void 1579 ttyin(char buf[], register int nmax, char pchar) 1580 { 1581 register char *sptr; 1582 register unsigned char ch; 1583 int LengthBuffer[80]; 1584 int *BufferPointer; 1585 int csno; 1586 register int slash = 0; 1587 int maxlen; 1588 char cbuf; 1589 1590 BufferPointer = LengthBuffer; 1591 sptr = buf; 1592 maxlen = 0; 1593 while (sptr - buf < nmax) { 1594 if (promptlen > maxlen) 1595 maxlen = promptlen; 1596 ch = readch (); 1597 csno = csetno(ch); 1598 if (!csno) { 1599 if (ch == '\\') { 1600 slash++; 1601 } else if ((ch == otty.c_cc[VERASE]) && !slash) { 1602 if (sptr > buf) { 1603 --promptlen; 1604 write (2, &BS, 1); 1605 sptr -= (*--BufferPointer); 1606 if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 1607 --promptlen; 1608 write (2, &BS, 1); 1609 } 1610 continue; 1611 } else { 1612 if (!clr_eol) 1613 promptlen = maxlen; 1614 longjmp (restore, 1); 1615 } 1616 } else if ((ch == otty.c_cc[VKILL]) && !slash) { 1617 if (hard) { 1618 show(ch); 1619 putchar ('\n'); 1620 putchar (pchar); 1621 } else { 1622 putchar ('\r'); 1623 putchar (pchar); 1624 if (clr_eol) 1625 prmpt_erase (1); 1626 promptlen = 1; 1627 } 1628 sptr = buf; 1629 fflush (stdout); 1630 continue; 1631 } 1632 if (slash && (ch == otty.c_cc[VKILL] || ch == otty.c_cc[VERASE])) { 1633 write (2, &BS, 1); 1634 sptr -= (*--BufferPointer); 1635 } 1636 if (ch != '\\') 1637 slash = 0; 1638 *BufferPointer++ = 1; 1639 *sptr++ = ch; 1640 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 1641 ch += ch == RUBOUT ? -0100 : 0100; 1642 write (2, &CARAT, 1); 1643 promptlen++; 1644 } 1645 cbuf = ch; 1646 if (ch != '\n' && ch != ESC) { 1647 write (2, &cbuf, 1); 1648 promptlen++; 1649 } else 1650 break; 1651 /* end of code set 0 */ 1652 } else { 1653 int i; 1654 u_char buffer[5]; 1655 1656 *BufferPointer++ = cw[csno]; 1657 buffer[0] = *sptr++ = ch; 1658 for(i=1; i<cw[csno]; i++) { 1659 buffer[i] = *sptr++ = readch(); 1660 } 1661 buffer[i]='\0'; 1662 write(2, buffer, strlen((char *)buffer)); 1663 } 1664 } 1665 *--sptr = '\0'; 1666 if (!clr_eol) promptlen = maxlen; 1667 if (sptr - buf >= nmax - 1) 1668 error (gettext("Line too long")); 1669 } 1670 1671 static int 1672 expand(char *outbuf, char *inbuf) 1673 { 1674 register char *in_str; 1675 register char *out_str; 1676 register char ch; 1677 char temp[200]; 1678 int changed = 0; 1679 1680 in_str = inbuf; 1681 out_str = temp; 1682 while ((ch = *in_str++) != '\0') 1683 switch (ch) { 1684 case '%': 1685 if (!no_intty) { 1686 strcpy (out_str, fnames[fnum]); 1687 out_str += strlen (fnames[fnum]); 1688 changed++; 1689 } 1690 else 1691 *out_str++ = ch; 1692 break; 1693 case '!': 1694 if (!shellp) 1695 error (gettext("No previous command to substitute for")); 1696 strcpy (out_str, shell_line); 1697 out_str += strlen (shell_line); 1698 changed++; 1699 break; 1700 case '\\': 1701 if (*in_str == '%' || *in_str == '!') { 1702 *out_str++ = *in_str++; 1703 break; 1704 } 1705 default: 1706 *out_str++ = ch; 1707 } 1708 *out_str++ = '\0'; 1709 strcpy (outbuf, temp); 1710 return (changed); 1711 } 1712 1713 static void 1714 show(register char ch) 1715 { 1716 char cbuf; 1717 1718 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 1719 ch += ch == RUBOUT ? -0100 : 0100; 1720 write (2, &CARAT, 1); 1721 promptlen++; 1722 } 1723 cbuf = ch; 1724 write (2, &cbuf, 1); 1725 promptlen++; 1726 } 1727 1728 static void 1729 error (char *mess) 1730 { 1731 if (clreol) 1732 cleareol (); 1733 else 1734 kill_line (); 1735 promptlen += strlen (mess); 1736 if (enter_standout_mode && exit_standout_mode) { 1737 putp (enter_standout_mode); 1738 pr(mess); 1739 putp (exit_standout_mode); 1740 } 1741 else 1742 pr (mess); 1743 fflush(stdout); 1744 errors++; 1745 longjmp (restore, 1); 1746 } 1747 1748 1749 static void 1750 set_tty(void) 1751 { 1752 ioctl(2, TCGETA, &otty); /* save old tty modes */ 1753 ioctl(2, TCGETA, &ntty); 1754 ntty.c_lflag &= ~ECHO & ~ICANON; 1755 ntty.c_cc[VMIN] = (char)1; 1756 ntty.c_cc[VTIME] = (char)0; 1757 ioctl (2, TCSETAF, &ntty); /* set new tty modes */ 1758 } 1759 1760 static void 1761 reset_tty(void) 1762 { 1763 ioctl (2, TCSETAF, &otty); /* reset tty modes */ 1764 } 1765 1766 static void 1767 rdline(register FILE *f) 1768 { 1769 register int c; 1770 register char *p; 1771 1772 p = Line; 1773 while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 1774 *p++ = c; 1775 if (c == '\n') 1776 Currline++; 1777 *p = '\0'; 1778 } 1779 1780 /* Come here when we get a suspend signal from the terminal */ 1781 1782 /* 1783 * sig is put in as a dummy arg to have the compiler not to complain 1784 */ 1785 #ifdef SIGTSTP 1786 /* ARGSUSED */ 1787 void 1788 onsusp(int sig) 1789 { 1790 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 1791 signal(SIGTTOU, SIG_IGN); 1792 reset_tty (); 1793 fflush (stdout); 1794 signal(SIGTTOU, SIG_DFL); 1795 1796 /* Send the TSTP signal to suspend our process group */ 1797 kill (0, SIGTSTP); 1798 /* Pause for station break */ 1799 1800 /* We're back */ 1801 signal (SIGTSTP, onsusp); 1802 set_tty (); 1803 if (inwait) 1804 longjmp (restore, 1); 1805 } 1806 #endif 1807