Print this page
10120 smatch indenting fixes for usr/src/cmd
Reviewed by: Gergő Doma <domag02@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/pg/pg.c
+++ new/usr/src/cmd/pg/pg.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2016 by Delphix. All rights reserved.
25 + * Copyright (c) 2018, Joyent, Inc.
25 26 */
26 27
27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 29 /* All Rights Reserved */
29 30
30 31 #include <signal.h>
31 32 #include <setjmp.h>
32 33 #include <sys/types.h>
33 34 #include <sys/dirent.h>
34 35 #include <sys/stat.h>
35 36 #include <fcntl.h>
36 37 #include <ctype.h>
37 38 #include <stdio.h>
38 39 #include <wchar.h>
39 40 #include <curses.h>
40 41 #include <term.h>
41 42 #include <errno.h>
42 43 #include <stdlib.h>
43 44 #include <regexpr.h>
44 45 #include <limits.h>
45 46 #include <locale.h>
46 47 #include <wctype.h> /* iswprint() */
47 48 #include <string.h>
48 49 #include <unistd.h>
49 50 #include <wait.h>
50 51 #include <libw.h>
51 52 #include <regexpr.h>
52 53
53 54
54 55 /*
55 56 * pg -- paginator for crt terminals
56 57 *
57 58 * Includes the ability to display pages that have
58 59 * already passed by. Also gives the user the ability
59 60 * to search forward and backwards for regular expressions.
60 61 * This works for piped input by copying to a temporary file,
61 62 * and resolving backreferences from there.
62 63 *
63 64 * Note: The reason that there are so many commands to do
64 65 * the same types of things is to try to accommodate
65 66 * users of other paginators.
66 67 */
67 68
68 69 #define LINSIZ 1024
69 70 #define QUIT '\034'
70 71 #define BOF (EOF - 1) /* Begining of File */
71 72 #define STOP (EOF - 2)
72 73 #define PROMPTSIZE 256
73 74
74 75 /*
75 76 * Function definitions
76 77 */
77 78 static void lineset(int);
78 79 static char *setprompt();
79 80 static int set_state(int *, wchar_t, char *);
80 81 static void help();
81 82 static void copy_file(FILE *, FILE *);
82 83 static void re_error(int);
83 84 static void save_input(FILE *);
84 85 static void save_pipe();
85 86 static void newdol(FILE *);
86 87 static void erase_line(int);
87 88 static void kill_line();
88 89 static void doclear();
89 90 static void sopr(char *, int);
90 91 static void prompt(char *);
91 92 static void error(char *);
92 93 static void terminit();
93 94 static void compact();
94 95 static off_t getaline(FILE *);
95 96 static int mrdchar();
96 97 static off_t find(int, off_t);
97 98 static int search(char *, off_t);
98 99 static FILE *checkf(char *);
99 100 static int skipf(int);
100 101 static int readch();
101 102 static int ttyin();
102 103 static int number();
103 104 static int command(char *);
104 105 static int screen(char *);
105 106 static int fgetputc();
106 107 static char *pg_strchr();
107 108
108 109
109 110 struct line { /* how line addresses are stored */
110 111 off_t l_addr; /* file offset */
111 112 off_t l_no; /* line number in file */
112 113 };
113 114
114 115 typedef struct line LINE;
115 116
116 117 static LINE *zero = NULL, /* first line */
117 118 *dot, /* current line */
118 119 *dol, /* last line */
119 120 *contig; /* where contiguous (non-aged) lines start */
120 121 static long nlall; /* room for how many LINEs in memory */
121 122
122 123 static FILE *in_file, /* current input stream */
123 124 *tmp_fin, /* pipe temporary file in */
124 125 *tmp_fou; /* pipe temporary file out */
125 126 static char tmp_name[] = "/tmp/pgXXXXXX";
126 127
127 128 static short sign; /* sign of command input */
128 129
129 130 static int fnum, /* which file argument we're in */
130 131 pipe_in, /* set when stdin is a pipe */
131 132 out_is_tty; /* set if stdout is a tty */
132 133 static pid_t my_pgid;
133 134
134 135 static void on_brk(),
135 136 end_it();
136 137 static short brk_hit; /* interrupt handling is pending flag */
137 138
138 139 static int window = 0; /* window size in lines */
139 140 static short eof_pause = 1; /* pause w/ prompt at end of files */
140 141 static short rmode = 0; /* deny shell escape in restricted mode */
141 142 static short soflag = 0; /* output all messages in standout mode */
142 143 static short promptlen; /* length of the current prompt */
143 144 static short firstf = 1; /* set before first file has been processed */
144 145 static short inwait, /* set while waiting for user input */
145 146 errors; /* set if error message has been printed. */
146 147 /* if so, need to erase it and prompt */
147 148
148 149 static char **fnames;
149 150 static short status = 0; /* set > 0 if error detected */
150 151 static short fflag = 0; /* set if the f option is used */
151 152 static short nflag = 0; /* set for "no newline" input option */
152 153 static short clropt = 0; /* set if the clear option is used */
153 154 static int initopt = 0; /* set if the line option is used */
154 155 static int srchopt = 0; /* set if the search option is used */
155 156 static int initline;
156 157 static char initbuf[BUFSIZ];
157 158 static wchar_t leave_search = L't';
158 159 /* where on the page to leave a found string */
159 160 static short nfiles;
160 161 static char *shell;
161 162 static char *promptstr = ":";
162 163 static off_t nchars; /* return from getaline in find() */
163 164 static jmp_buf restore;
164 165 static char Line[LINSIZ+2];
165 166
166 167 static int catch_susp;
167 168
168 169 static void onsusp();
169 170
170 171 struct screen_stat {
171 172 off_t first_line;
172 173 off_t last_line;
173 174 short is_eof;
174 175 };
175 176
176 177 static struct screen_stat old_ss = { 0, 0, 0 };
177 178 static struct screen_stat new_ss;
178 179 static struct termio otty; /* to save old terminal settings */
179 180
180 181 static short termflg = 0; /* set once terminal is initialized */
181 182 static short eoflag; /* set whenever at end of current file */
182 183 static short doliseof; /* set when last line of file is known */
183 184 static off_t eofl_no; /* what the last line of the file is */
184 185 static void usage(void);
185 186 static FILE *pg_stdin;
186 187
187 188 int
188 189 main(int argc, char **argv)
189 190 {
190 191 char *s;
191 192 char *p;
192 193 int prnames = 0;
193 194 int opt;
194 195 int i;
195 196
196 197 (void) setlocale(LC_ALL, "");
197 198 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
198 199 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
199 200 #endif
200 201 (void) textdomain(TEXT_DOMAIN);
201 202
202 203 /* check for non-standard "-#" option */
203 204 for (i = 1; i < argc; i++) {
204 205 if (strcmp(argv[i], "--") == 0)
205 206 break;
206 207
207 208 if ((argv[i][0] == '-') && isdigit(argv[i][1])) {
208 209 if (strlen(&argv[i][1]) !=
209 210 strspn(&argv[i][1], "0123456789")) {
210 211 (void) fprintf(stderr, gettext(
211 212 "pg: Badly formed number\n"));
212 213 usage();
213 214 }
214 215
215 216 window = (int)strtol(&argv[i][1], (char **)NULL, 10);
216 217
217 218 while (i < argc) {
218 219 argv[i] = argv[i + 1];
↓ open down ↓ |
184 lines elided |
↑ open up ↑ |
219 220 i++;
220 221 }
221 222 i--;
222 223 argc--;
223 224 }
224 225 }
225 226
226 227 /* check for non-standard + option */
227 228 for (i = 1; i < argc; i++) {
228 229 if (strcmp(argv[i], "--") == 0)
229 - break;
230 + break;
230 231
231 232 if (argv[i][0] == '+') {
232 233 if (argv[i][1] == '/') {
233 234 srchopt++;
234 235 initopt = 0;
235 236 for (s = &argv[i][2], p = initbuf; *s != '\0'; )
236 237 if (p < initbuf + sizeof (initbuf))
237 238 *p++ = *s++;
238 239 else {
239 240 (void) fprintf(stderr, gettext(
240 241 "pg: pattern too long\n"));
241 242 return (1);
242 243 }
243 244 *p = '\0';
244 245 } else {
245 246 initopt++;
246 247 srchopt = 0;
247 248 s = &argv[i][2];
248 249 for (; isdigit(*s); s++)
249 250 initline = initline*10 + *s -'0';
250 251 if (*s != '\0')
251 252 usage();
252 253 }
253 254
254 255 while (i < argc) {
255 256 argv[i] = argv[i + 1];
256 257 i++;
257 258 }
258 259 i--;
259 260 argc--;
260 261 }
261 262 }
262 263
263 264 while ((opt = getopt(argc, argv, "cefnrsp:")) != EOF) {
264 265 switch (opt) {
265 266 case 'c':
266 267 clropt = 1;
267 268 break;
268 269
269 270 case 'e':
270 271 eof_pause = 0;
271 272 break;
272 273
273 274 case 'f':
274 275 fflag = 1;
275 276 break;
276 277
277 278 case 'n':
278 279 nflag = 1;
279 280 break;
280 281
281 282 case 'r':
282 283 rmode = 1; /* restricted mode */
283 284 break;
284 285
285 286 case 's':
286 287 soflag = 1; /* standout mode */
287 288 break;
288 289
289 290 case 'p':
290 291 promptstr = setprompt(optarg);
291 292 break;
292 293
293 294 default:
294 295 usage();
295 296 }
296 297 }
297 298
298 299 nfiles = argc - optind;
299 300 fnames = &argv[optind];
300 301
301 302 (void) signal(SIGQUIT, end_it);
302 303 (void) signal(SIGINT, end_it);
303 304 out_is_tty = isatty(1);
304 305 my_pgid = getpgrp();
305 306 if (out_is_tty) {
306 307 terminit();
307 308 (void) signal(SIGQUIT, on_brk);
308 309 (void) signal(SIGINT, on_brk);
309 310 if (signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
310 311 (void) signal(SIGTSTP, onsusp);
311 312 catch_susp++;
312 313 }
313 314 }
314 315 if (window == 0)
315 316 window = lines - 1;
316 317 if (window <= 1)
317 318 window = 2;
318 319 if (initline <= 0)
319 320 initline = 1;
320 321 if (nfiles > 1)
321 322 prnames++;
322 323
323 324 if (nfiles == 0) {
324 325 fnames[0] = "-";
325 326 nfiles++;
326 327 }
327 328 while (fnum < nfiles) {
328 329 if (strcmp(fnames[fnum], "") == 0)
329 330 fnames[fnum] = "-";
330 331 if ((in_file = checkf(fnames[fnum])) == NULL) {
331 332 status = 2;
332 333 fnum++;
333 334 } else {
334 335 status = 0;
335 336 if (out_is_tty)
336 337 fnum += screen(fnames[fnum]);
337 338 else {
338 339 if (prnames) {
339 340 (void) fputs("::::::::::::::\n",
340 341 stdout);
341 342 (void) fputs(fnames[fnum], stdout);
342 343 (void) fputs("\n::::::::::::::\n",
343 344 stdout);
344 345 }
345 346 copy_file(in_file, stdout);
346 347 fnum++;
347 348 }
348 349 (void) fflush(stdout);
349 350 if (pipe_in)
350 351 save_pipe();
351 352 else
352 353 if (in_file != tmp_fin)
353 354 (void) fclose(in_file);
354 355 }
355 356 }
356 357 end_it();
357 358
358 359 /*NOTREACHED*/
359 360 return (0);
360 361 }
361 362
362 363 static char *
363 364 setprompt(char *s)
364 365 {
365 366 int i = 0;
366 367 int pct_d = 0;
367 368 static char pstr[PROMPTSIZE];
368 369
369 370 while (i < PROMPTSIZE - 2)
370 371 switch (pstr[i++] = *s++) {
371 372 case '\0':
372 373 return (pstr);
373 374 case '%':
374 375 if (*s == 'd' && !pct_d) {
375 376 pct_d++;
376 377 } else if (*s != '%')
377 378 pstr[i++] = '%';
378 379 if ((pstr[i++] = *s++) == '\0')
379 380 return (pstr);
380 381 break;
381 382 default:
382 383 break;
383 384 }
384 385 (void) fprintf(stderr, gettext("pg: prompt too long\n"));
385 386 exit(1);
386 387 /*NOTREACHED*/
387 388 }
388 389
389 390
390 391 /*
391 392 * Print out the contents of the file f, one screenful at a time.
392 393 */
393 394
394 395 static int
395 396 screen(char *file_name)
396 397 {
397 398 int cmd_ret = 0;
398 399 off_t start;
399 400 short hadchance = 0;
400 401
401 402 old_ss.is_eof = 0;
402 403 old_ss.first_line = 0;
403 404 old_ss.last_line = 0;
404 405 new_ss = old_ss;
405 406 if (!firstf)
406 407 cmd_ret = command(file_name);
407 408 else {
408 409 firstf = 0;
409 410 if (initopt) {
410 411 initopt = 0;
411 412 new_ss.first_line = initline;
412 413 new_ss.last_line = initline + (off_t)window - 1;
413 414 } else if (srchopt) {
414 415 srchopt = 0;
415 416 if (!search(initbuf, (off_t)1))
416 417 cmd_ret = command(file_name);
417 418 } else {
418 419 new_ss.first_line = 1;
419 420 new_ss.last_line = (off_t)window;
420 421 }
421 422 }
422 423
423 424 for (;;) {
424 425 if (cmd_ret)
425 426 return (cmd_ret);
426 427 if (hadchance && new_ss.last_line >= eofl_no)
427 428 return (1);
428 429 hadchance = 0;
429 430
430 431 if (new_ss.last_line < (off_t)window)
431 432 new_ss.last_line = (off_t)window;
432 433 if (find(0, new_ss.last_line + 1) != EOF)
433 434 new_ss.is_eof = 0;
434 435 else {
435 436 new_ss.is_eof = 1;
436 437 new_ss.last_line = eofl_no - 1;
437 438 new_ss.first_line = new_ss.last_line -
438 439 (off_t)window + 1;
439 440 }
440 441
441 442 if (new_ss.first_line < 1)
442 443 new_ss.first_line = 1;
443 444 if (clropt) {
444 445 doclear();
445 446 start = new_ss.first_line;
446 447 } else {
447 448 if (new_ss.first_line == old_ss.last_line)
448 449 start = new_ss.first_line + 1;
449 450 else
450 451 if (new_ss.first_line > old_ss.last_line)
451 452 start = new_ss.first_line;
452 453 else
453 454 if (old_ss.first_line < new_ss.first_line)
454 455 start = old_ss.last_line + 1;
455 456 else
456 457 start = new_ss.first_line;
457 458
458 459 if (start < old_ss.first_line)
459 460 sopr(gettext("...skipping backward\n"), 0);
460 461 else
461 462 if (start > old_ss.last_line + 1)
462 463 sopr(gettext("...skipping forward\n"), 0);
463 464 }
464 465
465 466 for (; start <= new_ss.last_line; start++) {
466 467 (void) find(0, start);
467 468 (void) fputs(Line, stdout);
468 469 if (brk_hit) {
469 470 new_ss.last_line = find(1, 0);
470 471 new_ss.is_eof = 0;
471 472 break;
472 473 }
473 474 }
474 475
475 476 brk_hit = 0;
476 477 (void) fflush(stdout);
477 478 if (new_ss.is_eof) {
478 479 if (!eof_pause || eofl_no == 1)
479 480 return (1);
480 481 hadchance++;
481 482 error("(EOF)");
482 483 }
483 484 old_ss = new_ss;
484 485 cmd_ret = command((char *)NULL);
485 486 }
486 487 }
487 488
488 489 static char cmdbuf[LINSIZ], *cmdptr;
489 490 #define BEEP() if (bell) { (void) putp(bell); (void) fflush(stdout); }
490 491 #define BLANKS(p) while (*p == ' ' || *p == '\t') p++
491 492 #define CHECKEND() BLANKS(cmdptr); if (*cmdptr) { BEEP(); break; }
492 493
493 494 /*
494 495 * Read a command and do it. A command consists of an optional integer
495 496 * argument followed by the command character. Return the number of files
496 497 * to skip, 0 if we're still talking about the same file.
497 498 */
498 499
499 500 static int
500 501 command(char *filename)
501 502 {
502 503 off_t nlines;
503 504 FILE *sf;
504 505 char *cmdend;
505 506 pid_t id;
506 507 int skip;
507 508 int len;
508 509 wchar_t wc;
509 510 wchar_t wc_e;
510 511 wchar_t wc_e1;
511 512 char *p;
512 513
513 514 for (;;) {
514 515 /*
515 516 * Wait for output to drain before going on.
516 517 * This is done so that the user will not hit
517 518 * break and quit before they have seen the prompt.
518 519 */
519 520 (void) ioctl(1, TCSBRK, 1);
520 521 if (setjmp(restore) > 0)
521 522 end_it();
522 523 inwait = 1;
523 524 brk_hit = 0;
524 525 if (errors)
525 526 errors = 0;
526 527 else {
527 528 kill_line();
528 529 prompt(filename);
529 530 }
530 531 (void) fflush(stdout);
531 532 if (ttyin())
532 533 continue;
533 534 cmdptr = cmdbuf;
534 535 nlines = number();
535 536 BLANKS(cmdptr);
536 537
537 538 if ((len = mbtowc(&wc, cmdptr, MB_CUR_MAX)) <= 0) {
538 539 wc = *cmdptr;
539 540 len = 1;
540 541 }
541 542 cmdptr += len;
542 543 switch (wc) {
543 544 case 'h':
544 545 CHECKEND();
545 546 help();
546 547 break;
547 548 case '\014': /* ^L */
548 549 case '.': /* redisplay current window */
549 550 CHECKEND();
550 551 new_ss.first_line = old_ss.first_line;
551 552 new_ss.last_line = old_ss.last_line;
552 553 inwait = 0;
553 554 return (0);
554 555 case 'w': /* set window size */
555 556 case 'z':
556 557 if (sign == -1) {
557 558 BEEP();
558 559 break;
559 560 }
560 561 CHECKEND();
561 562 if (nlines == 0)
562 563 nlines = (off_t)window;
563 564 else
564 565 if (nlines > 1)
565 566 window = (int)nlines;
566 567 else {
567 568 BEEP();
568 569 break;
569 570 }
570 571 new_ss.first_line = old_ss.last_line;
571 572 new_ss.last_line = new_ss.first_line +
572 573 (off_t)window - 1;
573 574 inwait = 0;
574 575 return (0);
575 576 case '\004': /* ^D */
576 577 case 'd':
577 578 CHECKEND();
578 579 if (sign == 0)
579 580 sign = 1;
580 581 new_ss.last_line = old_ss.last_line +
581 582 (off_t)sign*window/2;
582 583 new_ss.first_line = new_ss.last_line -
583 584 (off_t)window + 1;
584 585 inwait = 0;
585 586 return (0);
586 587 case 's':
587 588 /*
588 589 * save input in filename.
589 590 * Check for filename, access, etc.
590 591 */
591 592 BLANKS(cmdptr);
592 593 if (!*cmdptr) {
593 594 BEEP();
594 595 break;
595 596 }
596 597 if (setjmp(restore) > 0) {
597 598 BEEP();
598 599 } else {
599 600 char outstr[PROMPTSIZE];
600 601 if ((sf = fopen(cmdptr, "w")) == NULL) {
601 602 error("cannot open save file");
602 603 break;
603 604 }
604 605 kill_line();
605 606 (void) sprintf(outstr, gettext(
606 607 "saving file %s"), cmdptr);
607 608 sopr(outstr, 1);
608 609 (void) fflush(stdout);
609 610 save_input(sf);
610 611 error("saved");
611 612 }
612 613 (void) fclose(sf);
613 614 break;
614 615 case 'q':
615 616 case 'Q':
616 617 CHECKEND();
617 618 inwait = 0;
618 619 end_it();
619 620 /*FALLTHROUGH*/
620 621
621 622 case 'f': /* skip forward screenfuls */
622 623 CHECKEND();
623 624 if (sign == 0)
624 625 sign++; /* skips are always relative */
625 626 if (nlines == 0)
626 627 nlines++;
627 628 nlines = nlines * (window - 1);
628 629 if (sign == 1)
629 630 new_ss.first_line = old_ss.last_line + nlines;
630 631 else
631 632 new_ss.first_line = old_ss.first_line - nlines;
632 633 new_ss.last_line = new_ss.first_line +
633 634 (off_t)window - 1;
634 635 inwait = 0;
635 636 return (0);
636 637 case 'l': /* get a line */
637 638 CHECKEND();
638 639 if (nlines == 0) {
639 640 nlines++;
640 641 if (sign == 0)
641 642 sign = 1;
642 643 }
643 644 switch (sign) {
644 645 case 1:
645 646 new_ss.last_line = old_ss.last_line + nlines;
646 647 new_ss.first_line =
647 648 new_ss.last_line - (off_t)window + 1;
648 649 break;
649 650 case 0: /* leave addressed line at top */
650 651 new_ss.first_line = nlines;
651 652 new_ss.last_line = nlines + (off_t)window - 1;
652 653 break;
653 654 case -1:
654 655 new_ss.first_line = old_ss.first_line - nlines;
655 656 new_ss.last_line =
656 657 new_ss.first_line + (off_t)window - 1;
657 658 break;
658 659 }
659 660 inwait = 0;
660 661 return (0);
661 662 case '\0': /* \n or blank */
662 663 if (nlines == 0) {
663 664 nlines++;
664 665 if (sign == 0)
665 666 sign = 1;
666 667 }
667 668 nlines = (nlines - 1) * (window - 1);
668 669 switch (sign) {
669 670 case 1:
670 671 new_ss.first_line = old_ss.last_line + nlines;
671 672 new_ss.last_line =
672 673 new_ss.first_line + (off_t)window - 1;
673 674 break;
674 675 case 0:
675 676 new_ss.first_line = nlines + 1;
676 677 new_ss.last_line = nlines + (off_t)window;
677 678 /*
678 679 * This if statement is to fix the obscure bug
679 680 * where you have a file that has less lines
680 681 * than a screen holds, and the user types '1',
681 682 * expecting to have the 1st page (re)displayed.
682 683 * If we didn't set the new last_line to
683 684 * eofl_no-1, the screen() routine
684 685 * would cause pg to exit.
685 686 */
686 687 if (new_ss.first_line == 1 &&
687 688 new_ss.last_line >= eofl_no)
688 689 new_ss.last_line = eofl_no - 1;
689 690 break;
690 691 case -1:
691 692 new_ss.last_line = old_ss.first_line - nlines;
692 693 new_ss.first_line =
693 694 new_ss.last_line - (off_t)window + 1;
694 695 break;
695 696 }
696 697 inwait = 0;
697 698 return (0);
698 699 case 'n': /* switch to next file in arglist */
699 700 CHECKEND();
700 701 if (sign == 0)
701 702 sign = 1;
702 703 if (nlines == 0)
703 704 nlines++;
704 705 if ((skip = skipf(sign *nlines)) == 0) {
705 706 BEEP();
706 707 break;
707 708 }
708 709 inwait = 0;
709 710 return (skip);
710 711 case 'p': /* switch to previous file in arglist */
711 712 CHECKEND();
712 713 if (sign == 0)
713 714 sign = 1;
714 715 if (nlines == 0)
715 716 nlines++;
716 717 if ((skip = skipf(-sign * nlines)) == 0) {
717 718 BEEP();
718 719 break;
719 720 }
720 721 inwait = 0;
721 722 return (skip);
722 723 case '$': /* go to end of file */
723 724 CHECKEND();
724 725 sign = 1;
725 726 while (find(1, (off_t)10000) != EOF)
726 727 /* any large number will do */;
727 728 new_ss.last_line = eofl_no - 1;
728 729 new_ss.first_line = eofl_no - (off_t)window;
729 730 inwait = 0;
730 731 return (0);
731 732 case '/': /* search forward for r.e. */
732 733 case '?': /* " backwards */
733 734 case '^': /* this ones a ? for regent100s */
734 735 if (sign < 0) {
735 736 BEEP();
736 737 break;
737 738 }
738 739 if (nlines == 0)
739 740 nlines++;
740 741 cmdptr--;
741 742 cmdend = cmdptr + (strlen(cmdptr) - 1);
742 743 wc_e1 = -1;
743 744 wc_e = -1;
744 745 for (p = cmdptr; p <= cmdend; p += len) {
745 746 wc_e1 = wc_e;
746 747 if ((len = mbtowc(&wc_e, p, MB_CUR_MAX)) <= 0) {
747 748 wc_e = *p;
748 749 len = 1;
749 750 }
750 751 }
751 752
752 753 if (cmdend > cmdptr + 1) {
753 754 if ((wc_e1 == *cmdptr) &&
754 755 ((wc_e == L't') ||
755 756 (wc_e == L'm') || (wc_e == L'b'))) {
756 757 leave_search = wc_e;
757 758 wc_e = wc_e1;
758 759 cmdend--;
759 760 }
760 761 }
761 762 if ((cmdptr < cmdend) && (wc_e == *cmdptr))
762 763 *cmdend = '\0';
763 764 if (*cmdptr != '/') /* signify back search by - */
764 765 nlines = -nlines;
765 766 if (!search(++cmdptr, (off_t)nlines))
766 767 break;
767 768 else {
768 769 inwait = 0;
769 770 return (0);
770 771 }
771 772 case '!': /* shell escape */
772 773 if (rmode) { /* restricted mode */
773 774 (void) fprintf(stderr, gettext(
774 775 "!command not allowed in restricted mode.\n"));
775 776 break;
776 777 }
777 778 if (!hard_copy) { /* redisplay the command */
778 779 (void) fputs(cmdbuf, stdout);
779 780 (void) fputs("\n", stdout);
780 781 }
781 782 if ((id = fork()) < 0) {
782 783 error("cannot fork, try again later");
783 784 break;
784 785 }
785 786 if (id == (pid_t)0) {
786 787 /*
787 788 * if stdin is a pipe, need to close it so
788 789 * that the terminal is really stdin for
789 790 * the command
790 791 */
791 792 (void) fclose(stdin);
792 793 (void) fclose(pg_stdin);
793 794 (void) dup(fileno(stdout));
794 795 (void) execl(shell, shell, "-c", cmdptr, 0);
795 796 (void) perror("exec");
796 797 exit(1);
797 798 }
798 799 (void) signal(SIGINT, SIG_IGN);
799 800 (void) signal(SIGQUIT, SIG_IGN);
800 801 if (catch_susp)
801 802 (void) signal(SIGTSTP, SIG_DFL);
802 803 while (wait(NULL) != id) {
803 804 if (errno == ECHILD)
804 805 break;
805 806 else
806 807 errno = 0;
807 808 }
808 809 (void) fputs("!\n", stdout);
809 810 (void) fflush(stdout);
810 811 (void) signal(SIGINT, on_brk);
811 812 (void) signal(SIGQUIT, on_brk);
812 813 if (catch_susp)
813 814 (void) signal(SIGTSTP, onsusp);
814 815 break;
815 816 default:
816 817 BEEP();
817 818 break;
818 819 }
819 820 }
820 821 }
821 822
822 823 static int
823 824 number()
824 825 {
825 826 int i;
826 827 char *p;
827 828
828 829 i = 0;
829 830 sign = 0;
830 831 p = cmdptr;
831 832 BLANKS(p);
832 833 if (*p == '+') {
833 834 p++;
834 835 sign = 1;
835 836 }
836 837 else
837 838 if (*p == '-') {
838 839 p++;
839 840 sign = -1;
840 841 }
841 842 while (isdigit(*p))
842 843 i = i * 10 + *p++ - '0';
843 844 cmdptr = p;
844 845 return (i);
845 846 }
846 847
847 848 static int
848 849 ttyin(void)
849 850 {
850 851 char *sptr, *p;
851 852 wchar_t ch;
852 853 int slash = 0;
853 854 int state = 0;
854 855 int width, length;
855 856 char multic[MB_LEN_MAX];
856 857 int len;
857 858
858 859 (void) fixterm();
859 860 /* initialize state processing */
860 861 (void) set_state(&state, ' ', (char *)0);
861 862 sptr = cmdbuf;
862 863 while (state != 10) {
863 864 if ((ch = readch()) < 0 || !iswascii(ch) && !iswprint(ch)) {
864 865 BEEP();
865 866 continue;
866 867 }
867 868
868 869 if ((length = wctomb(multic, ch)) < 0)
869 870 length = 0;
870 871 multic[length] = 0;
871 872
872 873 if (ch == '\n' && !slash)
873 874 break;
874 875 if (ch == erasechar() && !slash) {
875 876 if (sptr > cmdbuf) {
876 877 char *oldp = cmdbuf;
877 878 wchar_t wchar;
878 879 p = cmdbuf;
879 880 while (p < sptr) {
880 881 oldp = p;
881 882 len = mbtowc(&wchar, p, MB_CUR_MAX);
882 883 if (len <= 0) {
883 884 wchar = (unsigned char)*p;
884 885 len = 1;
885 886 }
886 887 p += len;
887 888 }
888 889 if ((width = wcwidth(wchar)) <= 0)
889 890 /* ascii control character */
890 891 width = 2;
891 892 promptlen -= width;
892 893 while (width--)
893 894 (void) fputs("\b \b", stdout);
894 895 sptr = oldp;
895 896 }
896 897 (void) set_state(&state, ch, sptr);
897 898 (void) fflush(stdout);
898 899 continue;
899 900 }
900 901 else
901 902 if (ch == killchar() && !slash) {
902 903 if (hard_copy)
903 904 (void) putwchar(ch);
904 905 (void) resetterm();
905 906 return (1);
906 907 }
907 908 if (ch < ' ')
908 909 width = 2;
909 910 else
910 911 if ((width = wcwidth(ch)) <= 0)
911 912 width = 0;
912 913 if (slash) {
913 914 slash = 0;
914 915 (void) fputs("\b \b", stdout);
915 916 sptr--;
916 917 promptlen--;
917 918 } else /* is there room to keep this character? */
918 919 if (sptr >= cmdbuf + sizeof (cmdbuf) ||
919 920 promptlen + width >= columns) {
920 921 BEEP();
921 922 continue;
922 923 }
923 924 else
924 925 if (ch == '\\')
925 926 slash++;
926 927 if (set_state(&state, ch, sptr) == 0) {
927 928 BEEP();
928 929 continue;
929 930 }
930 931 (void) strncpy(sptr, multic, (size_t)length);
931 932 sptr += length;
932 933 if (ch < ' ') {
933 934 ch += 0100;
934 935 multic[0] = '^';
935 936 multic[1] = ch;
936 937 length = 2;
937 938 }
938 939 p = multic;
939 940 while (length--)
940 941 (void) putchar(*p++);
941 942 promptlen += width;
942 943 (void) fflush(stdout);
943 944 }
944 945
945 946 *sptr = '\0';
946 947 kill_line();
947 948 (void) fflush(stdout);
948 949 (void) resetterm();
949 950 return (0);
950 951 }
951 952
952 953 static int
953 954 set_state(int *pstate, wchar_t c, char *pc)
954 955 {
955 956 static char *psign;
956 957 static char *pnumber;
957 958 static char *pcommand;
958 959 static int slash;
959 960
960 961 if (*pstate == 0) {
961 962 psign = (char *)NULL;
962 963 pnumber = (char *)NULL;
963 964 pcommand = (char *)NULL;
964 965 *pstate = 1;
965 966 slash = 0;
966 967 return (1);
967 968 }
968 969 if (c == '\\' && !slash) {
969 970 slash++;
970 971 return (1);
971 972 }
972 973 if (c == erasechar() && !slash)
973 974 switch (*pstate) {
974 975 case 4:
975 976 if (pc > pcommand)
976 977 return (1);
977 978 pcommand = (char *)NULL;
978 979 /*FALLTHROUGH*/
979 980
980 981 case 3:
981 982 if (pnumber && pc > pnumber) {
982 983 *pstate = 3;
983 984 return (1);
984 985 }
985 986 pnumber = (char *)NULL;
986 987 /*FALLTHROUGH*/
987 988
988 989 case 2:
989 990 if (psign && pc > psign) {
990 991 *pstate = 2;
991 992 return (1);
992 993 }
993 994 psign = (char *)NULL;
994 995 /*FALLTHROUGH*/
995 996
996 997 case 1:
997 998 *pstate = 1;
998 999 return (1);
999 1000 }
1000 1001
1001 1002 slash = 0;
1002 1003 switch (*pstate) {
1003 1004 case 1: /* before recieving anything interesting */
1004 1005 if (c == '\t' || (!nflag && c == ' '))
1005 1006 return (1);
1006 1007 if (c == '+' || c == '-') {
1007 1008 psign = pc;
1008 1009 *pstate = 2;
1009 1010 return (1);
1010 1011 }
1011 1012 /*FALLTHROUGH*/
1012 1013
1013 1014 case 2: /* recieved sign, waiting for digit */
1014 1015 if (iswascii(c) && isdigit(c)) {
1015 1016 pnumber = pc;
1016 1017 *pstate = 3;
1017 1018 return (1);
1018 1019 }
1019 1020 /*FALLTHROUGH*/
1020 1021
1021 1022 case 3: /* recieved digit, waiting for the rest of the number */
1022 1023 if (iswascii(c) && isdigit(c))
1023 1024 return (1);
1024 1025 if (iswascii(c) && pg_strchr("h\014.wz\004dqQfl np$", c)) {
1025 1026 pcommand = pc;
1026 1027 if (nflag)
1027 1028 *pstate = 10;
1028 1029 else
1029 1030 *pstate = 4;
1030 1031 return (1);
1031 1032 }
1032 1033 if (iswascii(c) && pg_strchr("s/^?!", c)) {
1033 1034 pcommand = pc;
1034 1035 *pstate = 4;
1035 1036 return (1);
1036 1037 }
1037 1038 return (0);
1038 1039 case 4:
1039 1040 return (1);
1040 1041 }
1041 1042 return (0);
1042 1043 }
1043 1044
1044 1045 static int
1045 1046 readch(void)
1046 1047 {
1047 1048 return (fgetwc(pg_stdin));
1048 1049 }
1049 1050
1050 1051 static void
1051 1052 help(void)
1052 1053 {
1053 1054 if (clropt)
1054 1055 doclear();
1055 1056
1056 1057 (void) fputs(gettext(
1057 1058 "-------------------------------------------------------\n"
1058 1059 " h help\n"
1059 1060 " q or Q quit\n"
1060 1061 " <blank> or <newline> next page\n"
1061 1062 " l next line\n"
1062 1063 " d or <^D> display half a page more\n"
1063 1064 " . or <^L> redisplay current page\n"
1064 1065 " f skip the next page forward\n"
1065 1066 " n next file\n"
1066 1067 " p previous file\n"
1067 1068 " $ last page\n"
1068 1069 " w or z set window size and display next page\n"
1069 1070 " s savefile save current file in savefile\n"
1070 1071 " /pattern/ search forward for pattern\n"
1071 1072 " ?pattern? or\n"
1072 1073 " ^pattern^ search backward for pattern\n"
1073 1074 " !command execute command\n"
1074 1075 "\n"
1075 1076 "Most commands can be preceeded by a number, as in:\n"
1076 1077 "+1<newline> (next page); -1<newline> (previous page); 1<newline> (page 1).\n"
1077 1078 "\n"
1078 1079 "See the manual page for more detail.\n"
1079 1080 "-------------------------------------------------------\n"),
1080 1081 stdout);
1081 1082 }
1082 1083
1083 1084 /*
1084 1085 * Skip nskip files in the file list (from the command line). Nskip may be
1085 1086 * negative.
1086 1087 */
1087 1088
1088 1089 static int
1089 1090 skipf(int nskip)
1090 1091 {
1091 1092 if (fnum + nskip < 0) {
1092 1093 nskip = -fnum;
1093 1094 if (nskip == 0)
1094 1095 error("No previous file");
1095 1096 }
1096 1097 else
1097 1098 if (fnum + nskip > nfiles - 1) {
1098 1099 nskip = (nfiles - 1) - fnum;
1099 1100 if (nskip == 0)
1100 1101 error("No next file");
1101 1102 }
1102 1103 return (nskip);
1103 1104 }
1104 1105
1105 1106 /*
1106 1107 * Check whether the file named by fs is a file which the user may
1107 1108 * access. If it is, return the opened file. Otherwise return NULL.
1108 1109 */
1109 1110
1110 1111 static FILE *
1111 1112 checkf(char *fs)
1112 1113 {
1113 1114 struct stat stbuf;
1114 1115 FILE *f;
1115 1116 int fd;
1116 1117 int f_was_opened;
1117 1118
1118 1119 pipe_in = 0;
1119 1120 if (strcmp(fs, "-") == 0) {
1120 1121 if (tmp_fin == NULL)
1121 1122 f = stdin;
1122 1123 else {
1123 1124 rewind(tmp_fin);
1124 1125 f = tmp_fin;
1125 1126 }
1126 1127 f_was_opened = 0;
1127 1128 } else {
1128 1129 if ((f = fopen(fs, "r")) == (FILE *)NULL) {
1129 1130 (void) fflush(stdout);
1130 1131 perror(fs);
1131 1132 return ((FILE *)NULL);
1132 1133 }
1133 1134 f_was_opened = 1;
1134 1135 }
1135 1136 if (fstat(fileno(f), &stbuf) == -1) {
1136 1137 if (f_was_opened)
1137 1138 (void) fclose(f);
1138 1139 (void) fflush(stdout);
1139 1140 perror(fs);
1140 1141 return ((FILE *)NULL);
1141 1142 }
1142 1143 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1143 1144 if (f_was_opened)
1144 1145 (void) fclose(f);
1145 1146 (void) fprintf(stderr, "pg: ");
1146 1147 (void) fprintf(stderr, gettext("%s is a directory\n"), fs);
1147 1148 return ((FILE *)NULL);
1148 1149 }
1149 1150 if ((stbuf.st_mode & S_IFMT) == S_IFREG) {
1150 1151 if (f == stdin) /* It may have been read from */
1151 1152 rewind(f); /* already, and not reopened */
1152 1153 } else {
1153 1154 if (f != stdin) {
1154 1155 if (f_was_opened)
1155 1156 (void) fclose(f);
1156 1157 (void) fprintf(stderr, "pg: ");
1157 1158 (void) fprintf(stderr, gettext(
1158 1159 "special files only handled as standard input\n"));
1159 1160 return ((FILE *)NULL);
1160 1161 } else {
1161 1162 if ((fd = mkstemp(tmp_name)) < 0) {
1162 1163 (void) perror(tmp_name);
1163 1164 return ((FILE *)NULL);
1164 1165 }
1165 1166 (void) close(fd);
1166 1167 if ((tmp_fou = fopen(tmp_name, "w")) == NULL) {
1167 1168 (void) perror(tmp_name);
1168 1169 return ((FILE *)NULL);
1169 1170 }
1170 1171 if ((tmp_fin = fopen(tmp_name, "r")) == NULL) {
1171 1172 (void) perror(tmp_name);
1172 1173 return ((FILE *)NULL);
1173 1174 }
1174 1175 pipe_in = 1;
1175 1176 }
1176 1177 }
1177 1178 lineset(BOF);
1178 1179 return (f);
1179 1180 }
1180 1181
1181 1182 static void
1182 1183 copy_file(FILE *f, FILE *out)
1183 1184 {
1184 1185 int c;
1185 1186
1186 1187 while ((c = getc(f)) != EOF)
1187 1188 (void) putc(c, out);
1188 1189
1189 1190 }
1190 1191
1191 1192 static void
1192 1193 re_error(int i)
1193 1194 {
1194 1195 int j;
1195 1196 static struct messages {
1196 1197 char *message;
1197 1198 int number;
1198 1199 } re_errmsg[] = {
1199 1200 "Pattern not found", 1,
1200 1201 "Range endpoint too large", 11,
1201 1202 "Bad number", 16,
1202 1203 "`\\digit' out of range", 25,
1203 1204 "No remembered search string", 41,
1204 1205 "\\( \\) imbalance", 42,
1205 1206 "Too many \\(", 43,
1206 1207 "More than two numbers given in \\{ \\}", 44,
1207 1208 "} expected after \\", 45,
1208 1209 "First number exceeds second in \\{ \\}", 46,
1209 1210 "[] imbalance", 49,
1210 1211 "Regular expression overflow", 50,
1211 1212 "Illegal byte sequence", 67,
1212 1213 "Bad regular expression", 0
1213 1214 };
1214 1215
1215 1216 for (j = 0; re_errmsg[j].number != 0; j++)
1216 1217 if (re_errmsg[j].number == i)
1217 1218 break;
1218 1219 error(re_errmsg[j].message);
1219 1220 longjmp(restore, 1); /* restore to search() */
1220 1221 }
1221 1222
1222 1223 /*
1223 1224 * Search for nth ocurrence of regular expression contained in buf in the file
1224 1225 * negative n implies backward search
1225 1226 * n 'guaranteed' non-zero
1226 1227 */
1227 1228 static int
1228 1229 search(char *buf, off_t n)
1229 1230 {
1230 1231 int direction;
1231 1232 static char *expbuf;
1232 1233 char *nexpbuf;
1233 1234 int END_COND;
1234 1235
1235 1236 if (setjmp(restore) <= 0) {
1236 1237 nexpbuf = compile(buf, (char *)0, (char *)0);
1237 1238 if (regerrno) {
1238 1239 if (regerrno != 41 || expbuf == NULL)
1239 1240 re_error(regerrno);
1240 1241 } else {
1241 1242 if (expbuf)
1242 1243 free(expbuf);
1243 1244 expbuf = nexpbuf;
1244 1245 }
1245 1246
1246 1247 if (n < 0) { /* search back */
1247 1248 direction = -1;
1248 1249 (void) find(0, old_ss.first_line);
1249 1250 END_COND = BOF;
1250 1251 } else {
1251 1252 direction = 1;
1252 1253 (void) find(0, old_ss.last_line);
1253 1254 END_COND = EOF;
1254 1255 }
1255 1256
1256 1257 while (find(1, direction) != END_COND) {
1257 1258 if (brk_hit)
1258 1259 break;
1259 1260 if (step(Line, expbuf))
1260 1261 if ((n -= direction) == 0) {
1261 1262 switch (leave_search) {
1262 1263 case 't':
1263 1264 new_ss.first_line =
1264 1265 find(1, (off_t)0);
1265 1266 new_ss.last_line =
1266 1267 new_ss.first_line +
1267 1268 (off_t)window
1268 1269 - 1;
1269 1270 break;
1270 1271 case 'b':
1271 1272 new_ss.last_line =
1272 1273 find(1, (off_t)0);
1273 1274 new_ss.first_line =
1274 1275 new_ss.last_line -
1275 1276 (off_t)window
1276 1277 + 1;
1277 1278 break;
1278 1279 case 'm':
1279 1280 new_ss.first_line =
1280 1281 find(1, (off_t)0) -
1281 1282 ((off_t)window - 1)/2;
1282 1283 new_ss.last_line =
1283 1284 new_ss.first_line +
1284 1285 (off_t)window
1285 1286 - 1;
1286 1287 break;
1287 1288 }
1288 1289 return (1);
1289 1290 }
1290 1291 }
1291 1292 re_error(1); /* Pattern not found */
1292 1293 }
1293 1294 BEEP();
1294 1295 return (0);
1295 1296 }
1296 1297
1297 1298 /*
1298 1299 * find -- find line in file f, subject to certain constraints.
1299 1300 *
1300 1301 * This is the reason for all the funny stuff with sign and nlines.
1301 1302 * We need to be able to differentiate between relative and abosolute
1302 1303 * address specifications.
1303 1304 *
1304 1305 * So...there are basically three cases that this routine
1305 1306 * handles. Either line is zero, which means there is to be
1306 1307 * no motion (because line numbers start at one), or
1307 1308 * how and line specify a number, or line itself is negative,
1308 1309 * which is the same as having how == -1 and line == abs(line).
1309 1310 *
1310 1311 * Then, figure where exactly it is that we are going (an absolute
1311 1312 * line number). Find out if it is within what we have read,
1312 1313 * if so, go there without further ado. Otherwise, do some
1313 1314 * magic to get there, saving all the intervening lines,
1314 1315 * in case the user wants to see them some time later.
1315 1316 *
1316 1317 * In any case, return the line number that we end up at.
1317 1318 * (This is used by search() and screen()). If we go past EOF,
1318 1319 * return EOF.
1319 1320 * This EOF will go away eventually, as pg is expanded to
1320 1321 * handle multiple files as one huge one. Then EOF will
1321 1322 * mean we have run off the file list.
1322 1323 * If the requested line number is too far back, return BOF.
1323 1324 */
1324 1325
1325 1326 static off_t
1326 1327 find(int how, off_t line)
1327 1328 {
1328 1329 /* no compacted memory yet */
1329 1330 FILE *f = in_file;
1330 1331 off_t where;
1331 1332
1332 1333 if (how == 0)
1333 1334 where = line;
1334 1335 else
1335 1336 if (dot == zero - 1)
1336 1337 where = how * line;
1337 1338 else
1338 1339 where = how * line + dot->l_no;
1339 1340
1340 1341 /* now, where is either at, before, or after dol */
1341 1342 /* most likely case is after, so do it first */
1342 1343
1343 1344 eoflag = 0;
1344 1345 if (where >= dol->l_no) {
1345 1346 if (doliseof) {
1346 1347 dot = dol;
1347 1348 eoflag++;
1348 1349 return (EOF);
1349 1350 }
1350 1351 if (pipe_in)
1351 1352 in_file = f = stdin;
1352 1353 else
1353 1354 (void) fseeko(f, (off_t)dol->l_addr, SEEK_SET);
1354 1355 dot = dol - 1;
1355 1356 while ((nchars = getaline(f)) != EOF) {
1356 1357 dot++;
1357 1358 newdol(f);
1358 1359 if (where == dot->l_no || brk_hit)
1359 1360 break;
1360 1361 }
1361 1362 if (nchars != EOF)
1362 1363 return (dot->l_no);
1363 1364 else { /* EOF */
1364 1365 dot = dol;
1365 1366 eoflag++;
1366 1367 doliseof++;
1367 1368 eofl_no = dol->l_no;
1368 1369 return (EOF);
1369 1370 }
1370 1371 } else { /* where < dol->l_no */
1371 1372 if (pipe_in) {
1372 1373 (void) fflush(tmp_fou);
1373 1374 in_file = f = tmp_fin;
1374 1375 }
1375 1376 if (where < zero->l_no) {
1376 1377 (void) fseeko(f, (off_t)zero->l_addr, SEEK_SET);
1377 1378 dot = zero - 1;
1378 1379 return (BOF);
1379 1380 } else {
1380 1381 dot = zero + where - 1;
1381 1382 (void) fseeko(f, (off_t)dot->l_addr, SEEK_SET);
1382 1383 nchars = getaline(f);
1383 1384 return (dot->l_no);
1384 1385 }
1385 1386 }
1386 1387 }
1387 1388
1388 1389 static FILE *fileptr;
1389 1390 static int (*rdchar)();
1390 1391
1391 1392 static int
1392 1393 mrdchar()
1393 1394 {
1394 1395 return (rdchar(fileptr));
1395 1396 }
1396 1397
1397 1398 /*
1398 1399 * Get a logical line
1399 1400 */
1400 1401 static off_t
1401 1402 getaline(FILE *f)
1402 1403 {
1403 1404 char *p;
1404 1405 int column;
1405 1406 static char multic[MB_LEN_MAX];
1406 1407 static int savlength;
1407 1408 wchar_t c;
1408 1409 int length, width;
1409 1410
1410 1411 if (pipe_in && f == stdin)
1411 1412 rdchar = fgetputc;
1412 1413 else
1413 1414 rdchar = (int (*)())fgetwc;
1414 1415
1415 1416 fileptr = f;
1416 1417 /* copy overlap from previous call to getaline */
1417 1418 if (savlength)
1418 1419 (void) strncpy(Line, multic, (size_t)savlength);
1419 1420 for (column = 0, p = Line + savlength; ; ) {
1420 1421 if ((c = mrdchar()) <= 0) {
1421 1422 clearerr(f);
1422 1423 if (p > Line) { /* last line doesn't have '\n', */
1423 1424 *p++ = '\n';
1424 1425 *p = '\0'; /* print it any way */
1425 1426 return (column);
1426 1427 }
1427 1428 return (EOF);
1428 1429 }
1429 1430 length = wctomb(multic, c);
1430 1431 if (length < 0) {
1431 1432 length = -length;
1432 1433 c = 0;
1433 1434 }
1434 1435 if ((width = wcwidth(c)) < 0)
1435 1436 width = 0;
1436 1437 if (column + width > columns && !fflag)
1437 1438 break;
1438 1439
1439 1440 if (p + length > &Line[LINSIZ - 2] && c != '\n')
1440 1441 break;
1441 1442 (void) strncpy(p, multic, (size_t)length);
1442 1443 p += length;
1443 1444 column += width;
1444 1445 /* don't have any overlap here */
1445 1446 length = 0;
1446 1447 switch (c) {
1447 1448 case '\t': /* just a guess */
1448 1449 column = 1 + (column | 7);
1449 1450 break;
1450 1451 case '\b':
1451 1452 if (column > 0)
1452 1453 column--;
1453 1454 break;
1454 1455 case '\r':
1455 1456 column = 0;
1456 1457 break;
1457 1458 }
1458 1459 if (c == '\n')
1459 1460 break;
1460 1461 if (column >= columns && !fflag)
1461 1462 break;
1462 1463 }
1463 1464 if (c != '\n') { /* We're stopping in the middle of the line */
1464 1465 if (column != columns || !auto_right_margin)
1465 1466 *p++ = '\n'; /* for the display */
1466 1467 /* save overlap for next call to getaline */
1467 1468 savlength = length;
1468 1469 if (savlength == 0) {
1469 1470 /*
1470 1471 * check if following byte is newline and get
1471 1472 * it if it is
1472 1473 */
1473 1474 c = fgetwc(f);
1474 1475 if (c == '\n') {
1475 1476 /* gobble and copy (if necessary) newline */
1476 1477 (void) ungetwc(c, f);
1477 1478 (void) (*rdchar)(f);
1478 1479 } else if (c == EOF)
1479 1480 clearerr(f);
1480 1481 else
1481 1482 (void) ungetwc(c, f);
1482 1483 }
1483 1484 } else
1484 1485 savlength = 0;
1485 1486 *p = 0;
1486 1487 return (column);
1487 1488 }
1488 1489
1489 1490 static void
1490 1491 save_input(FILE *f)
1491 1492 {
1492 1493 if (pipe_in) {
1493 1494 save_pipe();
1494 1495 in_file = tmp_fin;
1495 1496 pipe_in = 0;
1496 1497 }
1497 1498 (void) fseeko(in_file, (off_t)0, SEEK_SET);
1498 1499 copy_file(in_file, f);
1499 1500 }
1500 1501
1501 1502 static void
1502 1503 save_pipe(void)
1503 1504 {
1504 1505 if (!doliseof)
1505 1506 while (fgetputc(stdin) != EOF)
1506 1507 if (brk_hit) {
1507 1508 brk_hit = 0;
1508 1509 error("Piped input only partially saved");
1509 1510 break;
1510 1511 }
1511 1512 (void) fclose(tmp_fou);
1512 1513 }
1513 1514
1514 1515 /*
1515 1516 * copy anything read from a pipe to tmp_fou
1516 1517 */
1517 1518 static int
1518 1519 fgetputc(FILE *f)
1519 1520 {
1520 1521 int c;
1521 1522
1522 1523 if ((c = fgetwc(f)) != EOF)
1523 1524 (void) fputwc(c, tmp_fou);
1524 1525 return (c);
1525 1526 }
1526 1527
1527 1528 /*
1528 1529 * initialize line memory
1529 1530 */
1530 1531 static void
1531 1532 lineset(int how)
1532 1533 {
1533 1534 if (zero == NULL) {
1534 1535 nlall = 128;
1535 1536 zero = (LINE *) malloc(nlall * sizeof (LINE));
1536 1537 }
1537 1538 dol = contig = zero;
1538 1539 zero->l_no = 1;
1539 1540 zero->l_addr = 0l;
1540 1541 if (how == BOF) {
1541 1542 dot = zero - 1;
1542 1543 eoflag = 0;
1543 1544 doliseof = 0;
1544 1545 eofl_no = -1;
1545 1546 } else {
1546 1547 dot = dol;
1547 1548 eoflag = 1;
1548 1549 doliseof = 1;
1549 1550 eofl_no = 1;
1550 1551 }
1551 1552 }
1552 1553
1553 1554 /*
1554 1555 * add address of new 'dol'
1555 1556 * assumes that f is currently at beginning of said line
1556 1557 * updates dol
1557 1558 */
1558 1559 static void
1559 1560 newdol(FILE *f)
1560 1561 {
1561 1562 int diff;
1562 1563
1563 1564 if ((dol - zero) + 1 >= nlall) {
1564 1565 LINE *ozero = zero;
1565 1566
1566 1567 nlall += 512;
1567 1568 if ((zero = (LINE *)realloc((char *)zero,
1568 1569 (unsigned)(nlall * sizeof (LINE)))) == NULL) {
1569 1570 zero = ozero;
1570 1571 compact();
1571 1572 }
1572 1573 diff = (int)((int)zero - (int)ozero);
1573 1574 dot = (LINE *)((int)dot + diff);
1574 1575 dol = (LINE *)((int)dol + diff);
1575 1576 contig = (LINE *)((int)contig + diff);
1576 1577 }
1577 1578 dol++;
1578 1579 if (!pipe_in)
1579 1580 dol->l_addr = (off_t)ftello(f);
1580 1581 else {
1581 1582 (void) fflush(tmp_fou);
1582 1583 dol->l_addr = (off_t)ftello(tmp_fou);
1583 1584 }
1584 1585 dol->l_no = (dol-1)->l_no + 1;
1585 1586 }
1586 1587
1587 1588 static void
1588 1589 compact(void)
1589 1590 {
1590 1591 (void) perror("realloc");
1591 1592 end_it();
1592 1593
1593 1594 }
1594 1595
1595 1596 static void
1596 1597 terminit(void) /* set up terminal dependencies from termlib */
1597 1598 {
1598 1599 int err_ret;
1599 1600 struct termio ntty;
1600 1601
1601 1602 for (;;) {
1602 1603 pid_t my_tgid;
1603 1604 my_tgid = tcgetpgrp(1);
1604 1605 if (my_tgid == -1 || my_tgid == my_pgid)
1605 1606 break;
1606 1607 (void) kill(-my_pgid, SIGTTOU);
1607 1608 }
1608 1609
1609 1610 if ((freopen("/dev/tty", "r+", stdout)) == NULL) {
1610 1611 (void) perror("open");
1611 1612 exit(1);
1612 1613 }
1613 1614 (void) ioctl(fileno(stdout), TCGETA, &otty);
1614 1615 termflg = 1;
1615 1616
1616 1617 (void) setupterm(0, fileno(stdout), &err_ret);
1617 1618 (void) ioctl(fileno(stdout), TCGETA, &ntty);
1618 1619 ntty.c_lflag &= ~(ECHONL | ECHO | ICANON);
1619 1620 ntty.c_cc[VMIN] = 1;
1620 1621 ntty.c_cc[VTIME] = 1;
1621 1622 (void) ioctl(fileno(stdout), TCSETAW, &ntty);
1622 1623 pg_stdin = fdopen(dup(fileno(stdout)), "r");
1623 1624 (void) saveterm();
1624 1625 (void) resetterm();
1625 1626 if (lines <= 0 || hard_copy) {
1626 1627 hard_copy = 1;
1627 1628 lines = 24;
1628 1629 }
1629 1630 if (columns <= 0)
1630 1631 columns = 80;
1631 1632 if (clropt && !clear_screen)
1632 1633 clropt = 0;
1633 1634 if ((shell = getenv("SHELL")) == (char *)NULL)
1634 1635 shell = "/usr/bin/sh";
1635 1636 }
1636 1637
1637 1638 static void
1638 1639 error(char *mess)
1639 1640 {
1640 1641 kill_line();
1641 1642 sopr(gettext(mess), 1);
1642 1643 prompt((char *)NULL);
1643 1644 errors++;
1644 1645 }
1645 1646
1646 1647 static void
1647 1648 prompt(char *filename)
1648 1649 {
1649 1650 char outstr[PROMPTSIZE+6];
1650 1651 int pagenum;
1651 1652 if (filename != NULL) {
1652 1653 /*
1653 1654 * TRANSLATION_NOTE
1654 1655 * %s is a filename.
1655 1656 */
1656 1657 (void) sprintf(outstr, gettext("(Next file: %s)"), filename);
1657 1658 } else {
1658 1659 if ((pagenum = (int)((new_ss.last_line-2)/(window-1)+1)) >
1659 1660 999999) {
1660 1661 pagenum = 999999;
1661 1662 }
1662 1663 (void) sprintf(outstr, promptstr, pagenum);
1663 1664 }
1664 1665 sopr(outstr, 1);
1665 1666 (void) fflush(stdout);
1666 1667 }
1667 1668
1668 1669 /*
1669 1670 * sopr puts out the message (please no \n's) surrounded by standout
1670 1671 * begins and ends
1671 1672 */
1672 1673
1673 1674 static void
1674 1675 sopr(char *m, int count)
1675 1676 {
1676 1677 wchar_t wc;
1677 1678 int len, n;
1678 1679 char *p;
1679 1680
1680 1681 if (count) {
1681 1682 p = m;
1682 1683 for (; *p; p += len) {
1683 1684 if ((len = mbtowc(&wc, p, MB_CUR_MAX)) <= 0) {
1684 1685 len = 1;
1685 1686 continue;
1686 1687 }
1687 1688 if ((n = wcwidth(wc)) > 0)
1688 1689 promptlen += n;
1689 1690 }
1690 1691 }
1691 1692 if (soflag && enter_standout_mode && exit_standout_mode) {
1692 1693 (void) putp(enter_standout_mode);
1693 1694 (void) fputs(m, stdout);
1694 1695 (void) putp(exit_standout_mode);
1695 1696 }
1696 1697 else
1697 1698 (void) fputs(m, stdout);
1698 1699 }
1699 1700
1700 1701 static void
1701 1702 doclear(void)
1702 1703 {
1703 1704 if (clear_screen)
1704 1705 (void) putp(clear_screen);
1705 1706 (void) putchar('\r'); /* this resets the terminal drivers character */
1706 1707 /* count in case it is trying to expand tabs */
1707 1708
1708 1709 }
1709 1710
1710 1711 static void
1711 1712 kill_line(void)
1712 1713 {
1713 1714 erase_line(0);
1714 1715 if (!clr_eol) (void) putchar('\r');
1715 1716
1716 1717 }
1717 1718
1718 1719 /* erase from after col to end of prompt */
1719 1720 static void
1720 1721 erase_line(int col)
1721 1722 {
1722 1723
1723 1724 if (promptlen == 0)
1724 1725 return;
1725 1726 if (hard_copy)
1726 1727 (void) putchar('\n');
1727 1728 else {
1728 1729 if (col == 0)
1729 1730 (void) putchar('\r');
1730 1731 if (clr_eol) {
1731 1732 (void) putp(clr_eol);
1732 1733 /* for the terminal driver again */
1733 1734 (void) putchar('\r');
1734 1735 }
1735 1736 else
1736 1737 for (col = promptlen - col; col > 0; col--)
1737 1738 (void) putchar(' ');
1738 1739 }
1739 1740 promptlen = 0;
1740 1741 }
1741 1742
1742 1743 /*
1743 1744 * Come here if a quit or interrupt signal is received
1744 1745 */
1745 1746
1746 1747 static void
1747 1748 on_brk(int sno)
1748 1749 {
1749 1750 (void) signal(sno, on_brk);
1750 1751 if (!inwait) {
1751 1752 BEEP();
1752 1753 brk_hit = 1;
1753 1754 } else {
1754 1755 brk_hit = 0;
1755 1756 longjmp(restore, 1);
1756 1757 }
1757 1758 }
1758 1759
1759 1760 /*
1760 1761 * Clean up terminal state and exit.
1761 1762 */
1762 1763
1763 1764 void
1764 1765 end_it(void)
1765 1766 {
1766 1767
1767 1768 if (out_is_tty) {
1768 1769 kill_line();
1769 1770 (void) resetterm();
1770 1771 if (termflg)
1771 1772 (void) ioctl(fileno(stdout), TCSETAW, &otty);
1772 1773 }
1773 1774 if (tmp_fin)
1774 1775 (void) fclose(tmp_fin);
1775 1776 if (tmp_fou)
1776 1777 (void) fclose(tmp_fou);
1777 1778 if (tmp_fou || tmp_fin)
1778 1779 (void) unlink(tmp_name);
1779 1780 exit(status);
1780 1781 }
1781 1782
1782 1783 void
1783 1784 onsusp(void)
1784 1785 {
1785 1786 int ttou_is_dfl;
1786 1787
1787 1788 /* ignore SIGTTOU so following resetterm and flush works */
1788 1789 ttou_is_dfl = (signal(SIGTTOU, SIG_IGN) == SIG_DFL);
1789 1790 (void) resetterm();
1790 1791 (void) fflush(stdout);
1791 1792 if (ttou_is_dfl)
1792 1793 (void) signal(SIGTTOU, SIG_DFL);
1793 1794
1794 1795 /* send SIGTSTP to stop this process group */
1795 1796 (void) signal(SIGTSTP, SIG_DFL);
1796 1797 (void) kill(-my_pgid, SIGTSTP);
1797 1798
1798 1799 /* continued - reset the terminal */
1799 1800 #ifdef __STDC__
1800 1801 (void) signal(SIGTSTP, (void (*)(int))onsusp);
1801 1802 #else
1802 1803 (void) signal(SIGTSTP, (void (*))onsusp);
1803 1804 #endif
1804 1805 (void) resetterm();
1805 1806 if (inwait)
1806 1807 longjmp(restore, -1);
1807 1808
1808 1809 }
1809 1810
1810 1811 static char *
1811 1812 pg_strchr(char *str, wchar_t c)
1812 1813 {
1813 1814 while (*str) {
1814 1815 if (c == *str)
1815 1816 return (str);
1816 1817 str++;
1817 1818 }
1818 1819 return (0);
1819 1820 }
1820 1821
1821 1822 void
1822 1823 usage(void)
1823 1824 {
1824 1825 (void) fprintf(stderr, gettext(
1825 1826 "Usage: pg [-number] [-p string] [-cefnrs] [+line] [+/pattern/] files\n"));
1826 1827 exit(1);
1827 1828 }
↓ open down ↓ |
1588 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX