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 2000 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 tailequ (path, string) 664 char *path; 665 register char *string; 666 { 667 return (!strcmp(basename(path), string)); 668 } 669 670 static void 671 prompt(char *filename) 672 { 673 if (clreol) 674 cleareol (); 675 else if (promptlen > 0) 676 kill_line (); 677 if (!hard) { 678 promptlen = 8; 679 if (enter_standout_mode && exit_standout_mode) 680 putp (enter_standout_mode); 681 if (clreol) 682 cleareol (); 683 pr(gettext("--More--")); 684 if (filename != NULL) { 685 promptlen += printf (gettext("(Next file: %s)"), filename); 686 } 687 else if (!no_intty) { 688 promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 689 } 690 if (dum_opt) { 691 promptlen += pr(gettext("[Hit space to continue, Del to abort]")); 692 } 693 if (enter_standout_mode && exit_standout_mode) 694 putp (exit_standout_mode); 695 if (clreol) clreos (); 696 fflush(stdout); 697 } 698 else 699 write (2, &Bell, 1); 700 inwait++; 701 } 702 703 /* 704 * when run from another program or a shell script, it is 705 * sometimes useful to prevent the next program from scrolling 706 * us off the screen before we get a chance to read this page. 707 * -Hans, July 24, 1982 708 */ 709 static void 710 wait_eof(void) 711 { 712 if (enter_standout_mode && exit_standout_mode) 713 putp (enter_standout_mode); 714 promptlen = pr(gettext("--No more--")); /*M003*/ 715 if (dum_opt) 716 promptlen += pr(gettext("[Hit any key to continue]")); 717 if (enter_standout_mode && exit_standout_mode) 718 putp(exit_standout_mode); 719 if (clreol) clreos(); 720 fflush(stdout); 721 readch(); 722 prmpt_erase (0); 723 fflush(stdout); 724 } 725 726 /* 727 ** Get a logical line 728 */ 729 730 static int 731 getline(register FILE *f, int *length) 732 { 733 register int c; 734 register char *p; 735 register int column; 736 static int colflg; 737 register int oldcolumn; 738 int csno; 739 740 p = Line; 741 column = 0; 742 oldcolumn = 0; 743 c = Getc (f); 744 if (colflg && c == '\n') { 745 Currline++; 746 c = Getc (f); 747 } 748 while (p < &Line[LINSIZ - 1]) { 749 csno = csetno(c); 750 if (c == EOF) { 751 if (p > Line) { 752 *p = '\0'; 753 *length = p - Line; 754 return (column); 755 } 756 *length = p - Line; 757 return (EOF); 758 } 759 if (!csno) { 760 if (c == '\n') { 761 /* detect \r\n. -Hans */ 762 if (p>Line && p[-1] == '\r') { 763 column = oldcolumn; 764 p--; 765 } 766 Currline++; 767 break; 768 } 769 *p++ = c; 770 if (c == '\t') 771 if (hardtabs && column < promptlen && !hard) { 772 if (clr_eol && !dumb) { 773 column = 1 + (column | 7); 774 putp (clr_eol); 775 promptlen = 0; 776 } 777 else { 778 for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 779 *p++ = ' '; 780 } 781 if (column >= promptlen) promptlen = 0; 782 } 783 } 784 else 785 column = 1 + (column | 7); 786 else if ((c == '\b') && (ul_opt || !cr_opt) && (column > 0)) /* M008 */ 787 column--; 788 789 /* this is sort of strange. what was here before was that 790 \r always set column to zero, and the hack above to 791 detect \r\n didnt exist. the net effect is to make 792 the current line be overwritten by the prompt if it 793 had a \r at the end, and the line start after the \r 794 otherwise. I suppose this is useful for overstriking 795 on hard copy terminals, but not on anything glass 796 -Hans */ 797 798 else if ((c == '\r') && !cr_opt) { 799 oldcolumn = column; 800 column = 0; 801 } 802 else if (c == '\f' && stop_opt) { 803 p[-1] = '^'; 804 *p++ = 'L'; 805 column += 2; 806 Pause++; 807 } 808 else if (c == EOF) { 809 *length = p - Line; 810 return (column); 811 } 812 else if (c < ' ' && cr_opt){ /* M008 begin */ 813 p[-1] = '^'; 814 *p++ = c | ('A' - 1); 815 column += 2; 816 } /* M008 end */ 817 else if (c >= ' ' && c != RUBOUT) 818 column++; 819 } /* end of code set 0 */ 820 else { 821 column += scw[csno]; 822 if ( column > Mcol && fold_opt ) { 823 column -= scw[csno]; 824 while ( column < Mcol ) { 825 column++; 826 *p++ = ' '; 827 } 828 column = Mcol; 829 Ungetc(c,f); 830 } else { 831 int i; 832 *p++ = c; 833 for(i=1; i<cw[csno];i++) 834 *p++ = Getc(f); 835 } 836 } /* end of codeset 1 ~ 3 */ 837 if (column >= Mcol && fold_opt) break; 838 c = Getc (f); 839 } 840 if (column >= Mcol && Mcol > 0) { 841 if (!Wrap) { 842 *p++ = '\n'; 843 } 844 } 845 colflg = column == Mcol && fold_opt; 846 if (colflg && eat_newline_glitch && Wrap) { 847 *p++ = '\n'; /* simulate normal wrap */ 848 } 849 *length = p - Line; 850 *p = 0; 851 return (column); 852 } 853 854 /* 855 ** Erase the rest of the prompt, assuming we are starting at column col. 856 */ 857 858 static void 859 prmpt_erase(register int col) 860 { 861 862 if (promptlen == 0) 863 return; 864 if (hard) { 865 putchar ('\n'); 866 } 867 else { 868 if (col == 0) 869 putchar ('\r'); 870 if (!dumb && clr_eol) 871 putp (clr_eol); 872 else 873 for (col = promptlen - col; col > 0; col--) 874 putchar (' '); 875 } 876 promptlen = 0; 877 } 878 879 /* 880 ** Erase the current line entirely 881 */ 882 883 static void 884 kill_line(void) 885 { 886 prmpt_erase (0); 887 if (!clr_eol || dumb) putchar ('\r'); 888 } 889 890 /* Print a buffer of n characters */ 891 892 static void 893 prbuf(register char *s, register int n) 894 { 895 char c; /* next ouput character */ 896 register int state = 0; /* next output char's UL state */ 897 static int pstate = 0; /* current terminal UL state (off) */ 898 899 while (--n >= 0) 900 if (!ul_opt) 901 putchar (*s++); 902 else { 903 if (n >= 2 && s[0] == '_' && s[1] == '\b') { 904 n -= 2; 905 s += 2; 906 c = *s++; 907 state = 1; 908 } else if (n >= 2 && s[1] == '\b' && s[2] == '_') { 909 n -= 2; 910 c = *s++; 911 s += 2; 912 state = 1; 913 } else { 914 c = *s++; 915 state = 0; 916 } 917 if (state != pstate) 918 putp(state ? ULenter : ULexit); 919 pstate = state; 920 putchar(c); 921 if (state && underline_char) { 922 putp(cursor_left); 923 putp(underline_char); 924 } 925 } 926 /* 927 * M002 928 * You don't want to stay in standout mode at the end of the line; 929 * on some terminals, this will leave all of the remaining blank 930 * space on the line in standout mode. 931 */ 932 if (state && !underline_char) { /*M002*/ 933 putp(ULexit); /*M002*/ 934 pstate = 0; /*M002*/ 935 } /*M002*/ 936 } 937 938 /* 939 ** Clear the screen 940 */ 941 942 static void 943 doclear(void) 944 { 945 if (clear_screen && !hard) { 946 putp(clear_screen); 947 948 /* Put out carriage return so that system doesn't 949 ** get confused by escape sequences when expanding tabs 950 */ 951 putchar ('\r'); 952 promptlen = 0; 953 } 954 } 955 956 957 static int lastcmd, lastp; 958 static off_t lastarg; 959 static int lastcolon; 960 char shell_line[132]; 961 962 /* 963 ** Read a command and do it. A command consists of an optional integer 964 ** argument followed by the command character. Return the number of lines 965 ** to display in the next screenful. If there is nothing more to display 966 ** in the current file, zero is returned. 967 */ 968 969 static off_t 970 command(char *filename, register FILE *f) 971 { 972 register off_t nlines; 973 register off_t retval; 974 register int c; 975 char colonch; 976 FILE *helpf; 977 int done; 978 char comchar, cmdbuf[80]; 979 char filebuf[128]; 980 char *loc; 981 982 #define ret(val) retval=val;done++;break 983 984 done = 0; 985 if (!errors) 986 prompt (filename); 987 else 988 errors = 0; 989 for (;;) { 990 nlines = number (&comchar); 991 lastp = colonch = 0; 992 if (comchar == '.') { /* Repeat last command */ 993 lastp++; 994 comchar = lastcmd; 995 nlines = lastarg; 996 if (lastcmd == ':') 997 colonch = lastcolon; 998 } 999 lastcmd = comchar; 1000 lastarg = nlines; 1001 if((comchar != RUBOUT) && !dum_opt) { 1002 if (comchar == otty.c_cc[VERASE]) { 1003 kill_line (); 1004 prompt (filename); 1005 continue; 1006 } 1007 } 1008 switch (comchar) { 1009 case ':': 1010 retval = colon (filename, colonch, nlines); 1011 if (retval >= 0) 1012 done++; 1013 break; 1014 case 'b': 1015 case ctrl('B'): 1016 { 1017 register off_t initline; 1018 1019 if (no_intty) { 1020 write(2, &bell, 1); 1021 return (-1); 1022 } 1023 1024 if (nlines == 0) nlines++; 1025 1026 putchar ('\r'); 1027 prmpt_erase (0); 1028 printf ("\n"); 1029 if (clreol) 1030 cleareol (); 1031 printf (gettext("...back %lld page"), nlines); 1032 if (nlines > 1) 1033 pr ("s\n"); 1034 else 1035 pr ("\n"); 1036 1037 if (clreol) 1038 cleareol (); 1039 pr ("\n"); 1040 1041 initline = Currline - dlines * (nlines + 1); 1042 if (! noscroll) 1043 --initline; 1044 if (initline < 0) initline = 0; 1045 Fseek(f, 0LL); 1046 Currline = 0; /* skiplns() will make Currline correct */ 1047 skiplns(initline, f); 1048 if (! noscroll) { 1049 ret(dlines + 1); 1050 } 1051 else { 1052 ret(dlines); 1053 } 1054 } 1055 case ' ': 1056 case 'z': 1057 if (nlines == 0) nlines = dlines; 1058 else if (comchar == 'z') dlines = nlines; 1059 ret (nlines); 1060 case 'd': 1061 case ctrl('D'): 1062 if (nlines != 0) nscroll = nlines; 1063 ret (nscroll); 1064 case RUBOUT: 1065 case 'q': 1066 case 'Q': 1067 end_it(0); 1068 /*NOTREACHED*/ 1069 case 's': 1070 case 'f': 1071 if (nlines == 0) nlines++; 1072 if (comchar == 'f') 1073 nlines *= dlines; 1074 putchar ('\r'); 1075 prmpt_erase (0); 1076 printf ("\n"); 1077 if (clreol) 1078 cleareol (); 1079 printf (gettext("...skipping %lld line"), nlines); 1080 if (nlines > 1) 1081 pr ("s\n"); 1082 else 1083 pr ("\n"); 1084 1085 if (clreol) 1086 cleareol (); 1087 pr ("\n"); 1088 1089 while (nlines > 0) { 1090 while ((c = Getc (f)) != '\n') 1091 if (c == EOF) { 1092 retval = 0; 1093 done++; 1094 goto endsw; 1095 } 1096 Currline++; 1097 nlines--; 1098 } 1099 ret (dlines); 1100 case '\n': 1101 if (nlines != 0) 1102 dlines = nlines; 1103 else 1104 nlines = 1; 1105 ret (nlines); 1106 case '\f': 1107 if (!no_intty) { 1108 doclear (); 1109 Fseek (f, screen_start.chrctr); 1110 Currline = screen_start.line; 1111 ret (dlines); 1112 } 1113 else { 1114 write (2, &Bell, 1); 1115 break; 1116 } 1117 case '\'': 1118 if (!no_intty) { 1119 kill_line (); 1120 pr (gettext("\n***Back***\n\n")); 1121 Fseek (f, context.chrctr); 1122 Currline = context.line; 1123 ret (dlines); 1124 } 1125 else { 1126 write (2, &Bell, 1); 1127 break; 1128 } 1129 case '=': 1130 kill_line (); 1131 promptlen = printf ("%lld", Currline); 1132 fflush (stdout); 1133 break; 1134 case 'n': 1135 lastp++; 1136 /*FALLTHROUGH*/ 1137 case '/': 1138 if (nlines == 0) nlines++; 1139 kill_line (); 1140 pr ("/"); 1141 promptlen = 1; 1142 fflush (stdout); 1143 if (lastp) { 1144 write (2,"\r", 1); 1145 search (NULL, f, nlines); /* Use previous r.e. */ 1146 } 1147 else { 1148 ttyin (cmdbuf, 78, '/'); 1149 write (2, "\r", 1); 1150 search (cmdbuf, f, nlines); 1151 } 1152 ret (dlines-1); 1153 case '!': 1154 do_shell (filename); 1155 break; 1156 case 'h': 1157 case '?': 1158 /* 1159 * First get local help file. 1160 */ 1161 loc = setlocale(LC_MESSAGES, 0); 1162 sprintf(filebuf, LOCAL_HELP, loc); 1163 1164 if ((strcmp(loc, "C") == 0) || (helpf = fopen (filebuf, "r")) == NULL) { 1165 if ((helpf = fopen (HELPFILE, "r")) == NULL) 1166 error (gettext("Can't open help file")); 1167 } 1168 if (noscroll) doclear (); 1169 copy_file (helpf); 1170 fclose (helpf); 1171 prompt (filename); 1172 break; 1173 case 'v': /* This case should go right before default */ 1174 if (!no_intty) { 1175 kill_line (); 1176 cmdbuf[0] = '+'; 1177 sprintf(&cmdbuf[1], "%lld", Currline); 1178 pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 1179 execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 1180 break; 1181 } 1182 default: 1183 if (dum_opt) { 1184 kill_line (); 1185 promptlen = pr(gettext("[Press 'h' for instructions.]")); 1186 fflush (stdout); 1187 } 1188 else 1189 write (2, &Bell, 1); 1190 break; 1191 } 1192 if (done) break; 1193 } 1194 putchar ('\r'); 1195 endsw: 1196 inwait = 0; 1197 notell++; 1198 return (retval); 1199 } 1200 1201 char ch; 1202 1203 /* 1204 * Execute a colon-prefixed command. 1205 * Returns <0 if not a command that should cause 1206 * more of the file to be printed. 1207 */ 1208 1209 static int 1210 colon(char *filename, int cmd, off_t nlines) 1211 { 1212 if (cmd == 0) 1213 ch = readch (); 1214 else 1215 ch = cmd; 1216 lastcolon = ch; 1217 switch (ch) { 1218 case 'f': 1219 kill_line (); 1220 if (!no_intty) 1221 promptlen = printf (gettext("\"%s\" line %lld"), 1222 fnames[fnum], Currline); 1223 else 1224 promptlen = printf( 1225 gettext("[Not a file] line %lld"), Currline); 1226 fflush (stdout); 1227 return (-1); 1228 case 'n': 1229 if (nlines == 0) { 1230 if (fnum >= nfiles - 1) 1231 end_it(0); 1232 nlines++; 1233 } 1234 putchar ('\r'); 1235 prmpt_erase (0); 1236 skipf ((int)nlines); 1237 return (0); 1238 case 'p': 1239 if (no_intty) { 1240 write (2, &Bell, 1); 1241 return (-1); 1242 } 1243 putchar ('\r'); 1244 prmpt_erase (0); 1245 if (nlines == 0) 1246 nlines++; 1247 skipf ((int)-nlines); 1248 return (0); 1249 case '!': 1250 do_shell (filename); 1251 return (-1); 1252 case 'q': 1253 case 'Q': 1254 end_it(0); 1255 default: 1256 write (2, &Bell, 1); 1257 return (-1); 1258 } 1259 } 1260 1261 /* 1262 ** Read a decimal number from the terminal. Set cmd to the non-digit which 1263 ** terminates the number. 1264 */ 1265 1266 static int 1267 number(char *cmd) 1268 { 1269 register int i; 1270 1271 i = 0; ch = otty.c_cc[VKILL]; 1272 for (;;) { 1273 ch = readch (); 1274 if (ch >= '0' && ch <= '9') { 1275 i = i*10 + ch - '0'; 1276 } else if (ch == RUBOUT) { 1277 i = 0; 1278 *cmd = ch; 1279 break; 1280 } else if (ch == otty.c_cc[VKILL]) { 1281 i = 0; 1282 } else { 1283 *cmd = ch; 1284 break; 1285 } 1286 } 1287 return (i); 1288 } 1289 1290 static void 1291 do_shell(char *filename) 1292 { 1293 char cmdbuf[80]; 1294 1295 kill_line (); 1296 pr ("!"); 1297 fflush (stdout); 1298 promptlen = 1; 1299 if (lastp) 1300 pr (shell_line); 1301 else { 1302 ttyin (cmdbuf, 78, '!'); 1303 if (expand (shell_line, cmdbuf)) { 1304 kill_line (); 1305 promptlen = printf ("!%s", shell_line); 1306 } 1307 } 1308 fflush (stdout); 1309 write (2, "\n", 1); 1310 promptlen = 0; 1311 shellp = 1; 1312 execute (filename, shell, shell, "-c", shell_line, 0); 1313 } 1314 1315 /* 1316 ** Search for nth ocurrence of regular expression contained in buf in the file 1317 */ 1318 1319 static void 1320 search(char buf[], FILE *file, register off_t n) 1321 { 1322 off_t startline = Ftell (file); 1323 register off_t line1 = startline; 1324 register off_t line2 = startline; 1325 register off_t line3 = startline; 1326 register off_t lncount; 1327 off_t saveln; 1328 static char *s = NULL; 1329 static char lastbuf[80]; 1330 1331 if (buf != NULL) { 1332 if (s != NULL) 1333 free(s); 1334 if (*buf != '\0') { 1335 if ((s = regcmp(buf, (char *) NULL)) == NULL) 1336 error(gettext("Regular expression botch")); 1337 else 1338 strcpy(lastbuf, buf); 1339 } else { 1340 if ((s = regcmp(lastbuf, (char *) NULL)) == NULL) 1341 error(gettext("No previous regular expression")); 1342 } 1343 } else { 1344 if (s == NULL) 1345 error(gettext("No previous regular expression")); 1346 } 1347 context.line = saveln = Currline; 1348 context.chrctr = startline; 1349 lncount = 0; 1350 while (!feof (file)) { 1351 line3 = line2; 1352 line2 = line1; 1353 line1 = Ftell (file); 1354 rdline (file); 1355 lncount++; 1356 if (regex(s, Line) != NULL) 1357 if (--n == 0) { 1358 if (lncount > 3 || (lncount > 1 && no_intty)) 1359 { 1360 pr ("\n"); 1361 if (clreol) 1362 cleareol (); 1363 pr(gettext("...skipping\n")); 1364 } 1365 if (!no_intty) { 1366 Currline -= (lncount >= 3 ? 3 : lncount); 1367 Fseek (file, line3); 1368 if (noscroll) 1369 if (clreol) { 1370 home (); 1371 cleareol (); 1372 } 1373 else 1374 doclear (); 1375 } 1376 else { 1377 kill_line (); 1378 if (noscroll) 1379 if (clreol) { 1380 home (); 1381 cleareol (); 1382 } else 1383 doclear (); 1384 pr (Line); 1385 putchar ('\n'); 1386 } 1387 break; 1388 } 1389 } 1390 if (feof (file)) { 1391 if (!no_intty) { 1392 Currline = saveln; 1393 Fseek (file, startline); 1394 } 1395 else { 1396 pr (gettext("\nPattern not found\n")); 1397 end_it (0); 1398 } 1399 error (gettext("Pattern not found")); 1400 } 1401 } 1402 1403 #define MAXARGS 10 /* enough for 9 args. We are only passed 4 now */ 1404 1405 static void 1406 execute (char *filename, char *cmd, ...) 1407 { 1408 pid_t id; 1409 va_list ap; 1410 char *argp[MAXARGS]; 1411 int count; 1412 1413 fflush (stdout); 1414 reset_tty (); 1415 while ((id = fork ()) < 0) 1416 sleep (5); 1417 if (id == 0) { 1418 if (no_intty) { /*M002*/ 1419 close(0); /*M002*/ 1420 dup(2); /*M002*/ 1421 } /*M002*/ 1422 va_start(ap, cmd); 1423 count = 0; 1424 do { 1425 #ifndef lint 1426 argp[count] = va_arg(ap, char *); 1427 #else 1428 ap = ap; 1429 #endif 1430 count++; 1431 if (count > MAXARGS) 1432 error (gettext("Too many arguments in execute()\n")); 1433 } while (argp[count - 1] != NULL); 1434 va_end(ap); 1435 execvp(cmd, argp); 1436 write (2, "exec failed\n", 12); 1437 exit (1); 1438 } 1439 signal (SIGINT, SIG_IGN); 1440 signal (SIGQUIT, SIG_IGN); 1441 signal (SIGWINCH, SIG_IGN); 1442 #ifdef SIGTSTP 1443 if (catch_susp) 1444 signal(SIGTSTP, SIG_DFL); 1445 #endif 1446 wait ((pid_t)0); 1447 signal (SIGINT, end_it); 1448 signal (SIGQUIT, onquit); 1449 signal (SIGWINCH, chgwinsz); 1450 #ifdef SIGTSTP 1451 if (catch_susp) 1452 signal(SIGTSTP, onsusp); 1453 #endif 1454 /* 1455 * Since we were ignoring window change signals while we executed 1456 * the command, we must assume the window changed. 1457 */ 1458 (void) chgwinsz(0); 1459 set_tty (); 1460 1461 pr ("------------------------\n"); 1462 prompt (filename); 1463 } 1464 /* 1465 ** Skip n lines in the file f 1466 */ 1467 1468 static void 1469 skiplns(register off_t n, register FILE *f) 1470 { 1471 register int c; 1472 1473 while (n > 0) { 1474 while ((c = Getc (f)) != '\n') 1475 if (c == EOF) 1476 return; 1477 n--; 1478 Currline++; 1479 } 1480 } 1481 1482 /* 1483 ** Skip nskip files in the file list (from the command line). Nskip may be 1484 ** negative. 1485 */ 1486 1487 static void 1488 skipf(register int nskip) 1489 { 1490 if (nskip == 0) return; 1491 if (nskip > 0) { 1492 if (fnum + nskip > nfiles - 1) 1493 nskip = nfiles - fnum - 1; 1494 } 1495 else if (within) 1496 ++fnum; 1497 fnum += nskip; 1498 if (fnum < 0) 1499 fnum = 0; 1500 pr (gettext("\n...Skipping ")); 1501 pr ("\n"); 1502 if (clreol) 1503 cleareol (); 1504 if (nskip > 0) 1505 printf(gettext("...Skipping to file %s\n"), fnames[fnum]); 1506 else 1507 printf(gettext("...Skipping back to file %s\n"), fnames[fnum]); 1508 if (clreol) 1509 cleareol (); 1510 pr ("\n"); 1511 --fnum; 1512 } 1513 1514 /*----------------------------- Terminal I/O -------------------------------*/ 1515 1516 static void 1517 initterm(void) 1518 { 1519 int erret = 0; 1520 1521 setbuf(stdout, obuf); 1522 if (!(no_tty = ioctl(1, TCGETA, &otty))) { 1523 if (setupterm(NULL, 1, &erret) != OK) { 1524 dumb++; ul_opt = 0; 1525 } 1526 else { 1527 reset_shell_mode(); 1528 if (((Lpp = lines) < 0) || hard_copy) { 1529 hard++; /* Hard copy terminal */ 1530 Lpp = 24; 1531 } 1532 if (tailequ(fnames[0], "page") || !hard && (scroll_forward == NULL)) 1533 noscroll++; 1534 if ((Mcol = columns) < 0) 1535 Mcol = 80; 1536 Wrap = tigetflag("am"); 1537 /* 1538 * Set up for underlining: some terminals don't need it; 1539 * others have start/stop sequences, still others have an 1540 * underline char sequence which is assumed to move the 1541 * cursor forward one character. If underline sequence 1542 * isn't available, settle for standout sequence. 1543 */ 1544 1545 if (transparent_underline || over_strike) 1546 ul_opt = 0; 1547 if ((ULenter = tigetstr("smul")) == NULL && 1548 (!underline_char) && (ULenter = tigetstr("smso")) == NULL) 1549 ULenter = ""; 1550 if ((ULexit = tigetstr("rmul")) == NULL && 1551 (!underline_char) && (ULexit = tigetstr("rmso")) == NULL) 1552 ULexit = ""; 1553 } 1554 if ((shell = getenv("SHELL")) == NULL) 1555 shell = "/usr/bin/sh"; 1556 } 1557 no_intty = ioctl(0, TCGETA, &otty); 1558 ioctl(2, TCGETA, &otty); 1559 hardtabs = !(otty.c_oflag & TAB3); 1560 } 1561 1562 static int 1563 readch(void) 1564 { 1565 char ch; 1566 extern int errno; 1567 1568 if (read (2, &ch, 1) <= 0) 1569 if (errno != EINTR) 1570 end_it(0); /* clean up before exiting */ 1571 else 1572 ch = otty.c_cc[VKILL]; 1573 return (ch); 1574 } 1575 1576 static char BS = '\b'; 1577 static char CARAT = '^'; 1578 1579 static void 1580 ttyin(char buf[], register int nmax, char pchar) 1581 { 1582 register char *sptr; 1583 register unsigned char ch; 1584 int LengthBuffer[80]; 1585 int *BufferPointer; 1586 int csno; 1587 register int slash = 0; 1588 int maxlen; 1589 char cbuf; 1590 1591 BufferPointer = LengthBuffer; 1592 sptr = buf; 1593 maxlen = 0; 1594 while (sptr - buf < nmax) { 1595 if (promptlen > maxlen) 1596 maxlen = promptlen; 1597 ch = readch (); 1598 csno = csetno(ch); 1599 if (!csno) { 1600 if (ch == '\\') { 1601 slash++; 1602 } else if ((ch == otty.c_cc[VERASE]) && !slash) { 1603 if (sptr > buf) { 1604 --promptlen; 1605 write (2, &BS, 1); 1606 sptr -= (*--BufferPointer); 1607 if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 1608 --promptlen; 1609 write (2, &BS, 1); 1610 } 1611 continue; 1612 } else { 1613 if (!clr_eol) 1614 promptlen = maxlen; 1615 longjmp (restore, 1); 1616 } 1617 } else if ((ch == otty.c_cc[VKILL]) && !slash) { 1618 if (hard) { 1619 show(ch); 1620 putchar ('\n'); 1621 putchar (pchar); 1622 } else { 1623 putchar ('\r'); 1624 putchar (pchar); 1625 if (clr_eol) 1626 prmpt_erase (1); 1627 promptlen = 1; 1628 } 1629 sptr = buf; 1630 fflush (stdout); 1631 continue; 1632 } 1633 if (slash && (ch == otty.c_cc[VKILL] || ch == otty.c_cc[VERASE])) { 1634 write (2, &BS, 1); 1635 sptr -= (*--BufferPointer); 1636 } 1637 if (ch != '\\') 1638 slash = 0; 1639 *BufferPointer++ = 1; 1640 *sptr++ = ch; 1641 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 1642 ch += ch == RUBOUT ? -0100 : 0100; 1643 write (2, &CARAT, 1); 1644 promptlen++; 1645 } 1646 cbuf = ch; 1647 if (ch != '\n' && ch != ESC) { 1648 write (2, &cbuf, 1); 1649 promptlen++; 1650 } else 1651 break; 1652 /* end of code set 0 */ 1653 } else { 1654 int i; 1655 u_char buffer[5]; 1656 1657 *BufferPointer++ = cw[csno]; 1658 buffer[0] = *sptr++ = ch; 1659 for(i=1; i<cw[csno]; i++) { 1660 buffer[i] = *sptr++ = readch(); 1661 } 1662 buffer[i]='\0'; 1663 write(2, buffer, strlen((char *)buffer)); 1664 } 1665 } 1666 *--sptr = '\0'; 1667 if (!clr_eol) promptlen = maxlen; 1668 if (sptr - buf >= nmax - 1) 1669 error (gettext("Line too long")); 1670 } 1671 1672 static int 1673 expand(char *outbuf, char *inbuf) 1674 { 1675 register char *in_str; 1676 register char *out_str; 1677 register char ch; 1678 char temp[200]; 1679 int changed = 0; 1680 1681 in_str = inbuf; 1682 out_str = temp; 1683 while ((ch = *in_str++) != '\0') 1684 switch (ch) { 1685 case '%': 1686 if (!no_intty) { 1687 strcpy (out_str, fnames[fnum]); 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 strcpy (out_str, shell_line); 1698 out_str += strlen (shell_line); 1699 changed++; 1700 break; 1701 case '\\': 1702 if (*in_str == '%' || *in_str == '!') { 1703 *out_str++ = *in_str++; 1704 break; 1705 } 1706 default: 1707 *out_str++ = ch; 1708 } 1709 *out_str++ = '\0'; 1710 strcpy (outbuf, temp); 1711 return (changed); 1712 } 1713 1714 static void 1715 show(register char ch) 1716 { 1717 char cbuf; 1718 1719 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 1720 ch += ch == RUBOUT ? -0100 : 0100; 1721 write (2, &CARAT, 1); 1722 promptlen++; 1723 } 1724 cbuf = ch; 1725 write (2, &cbuf, 1); 1726 promptlen++; 1727 } 1728 1729 static void 1730 error (char *mess) 1731 { 1732 if (clreol) 1733 cleareol (); 1734 else 1735 kill_line (); 1736 promptlen += strlen (mess); 1737 if (enter_standout_mode && exit_standout_mode) { 1738 putp (enter_standout_mode); 1739 pr(mess); 1740 putp (exit_standout_mode); 1741 } 1742 else 1743 pr (mess); 1744 fflush(stdout); 1745 errors++; 1746 longjmp (restore, 1); 1747 } 1748 1749 1750 static void 1751 set_tty(void) 1752 { 1753 ioctl(2, TCGETA, &otty); /* save old tty modes */ 1754 ioctl(2, TCGETA, &ntty); 1755 ntty.c_lflag &= ~ECHO & ~ICANON; 1756 ntty.c_cc[VMIN] = (char)1; 1757 ntty.c_cc[VTIME] = (char)0; 1758 ioctl (2, TCSETAF, &ntty); /* set new tty modes */ 1759 } 1760 1761 static void 1762 reset_tty(void) 1763 { 1764 ioctl (2, TCSETAF, &otty); /* reset tty modes */ 1765 } 1766 1767 static void 1768 rdline(register FILE *f) 1769 { 1770 register int c; 1771 register char *p; 1772 1773 p = Line; 1774 while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 1775 *p++ = c; 1776 if (c == '\n') 1777 Currline++; 1778 *p = '\0'; 1779 } 1780 1781 /* Come here when we get a suspend signal from the terminal */ 1782 1783 /* 1784 * sig is put in as a dummy arg to have the compiler not to complain 1785 */ 1786 #ifdef SIGTSTP 1787 /* ARGSUSED */ 1788 void 1789 onsusp(int sig) 1790 { 1791 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 1792 signal(SIGTTOU, SIG_IGN); 1793 reset_tty (); 1794 fflush (stdout); 1795 signal(SIGTTOU, SIG_DFL); 1796 1797 /* Send the TSTP signal to suspend our process group */ 1798 kill (0, SIGTSTP); 1799 /* Pause for station break */ 1800 1801 /* We're back */ 1802 signal (SIGTSTP, onsusp); 1803 set_tty (); 1804 if (inwait) 1805 longjmp (restore, 1); 1806 } 1807 #endif 1808