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