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