1 /* Lazyread 2.0 -by Ryan Kulla (aka gt3) Feb 2nd 2003 */
2 /* HomePage: http://www30.brinkster.com/gt3world/myworld.html */
3 /* E-Mail: ambiod@sbcglobal.net */
4 /* License: GPL */
5
6 #include <curses.h>
7 #include <time.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <sys/stat.h>
15 #include <errno.h>
16 #include <signal.h>
17
18 #define BUFMAX 1024
19 #define OFF 0
20 #define ON 1
21 #define UC 1 /* upper case */
22 #define LC 2 /* lower case */
23 #define CR 13 /* carriage return */
24 #define LF 10 /* line feed */
25
26 struct my_windows {
27 WINDOW *scrollwin;
28 WINDOW *statwin;
29 } *pstat, *pscroll;
30
31 struct {
32 char *filename;
33 char *display_filename;
34 char *tty_name;
35 FILE *fp;
36 FILE *which;
37 unsigned long int the_file_size;
38 unsigned int piped;
39 float percent;
40 unsigned long int page_num;
41 char homedir[BUFMAX];
42 char lazy_file[BUFMAX];
43 char lazy_tmp[BUFMAX];
44 char lazy_pipe[BUFMAX];
45 } lfile = { NULL, NULL, NULL, NULL, NULL, 0, 1, 0, 1 };
46
47 struct lazy_options {
48 unsigned long int default_speed;
49 char *special_word;
50 char *editor;
51 char *use_color;
52 unsigned int want_color;
53 unsigned int y;
54 unsigned int pos_changed;
55 unsigned int view_normal;
56 unsigned int case_change;
57 unsigned int case_type;
58 unsigned int scrollmode_chars;
59 unsigned int statusbar;
60 unsigned int auto_pause;
61 unsigned int beep_ok;
62 unsigned int reshow_statusbar;
63 unsigned int highlight;
64 unsigned int new_speed;
65 } lop = { 1000, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 };
66
67 SCREEN *STDIN_SCREEN;
68 char *progname;
69
70 void scan_command_line(int, char **);
71 void lazy_colors(void);
72 void scroll_it(unsigned int, int, char *);
73 void usage(void);
74 void quit_cleanly(void);
75 void get_stats(unsigned long int, unsigned long int);
76 void highlight_word(char *, unsigned int, unsigned int, unsigned int, unsigned long int, unsigned long int);
77 void user_input(unsigned int *, unsigned int, unsigned int *, unsigned long int, unsigned long int);
78 void do_options(unsigned int, int, char *);
79 unsigned int get_key(void);
80 int char_check(char *);
81 long line_nums(FILE *);
82 void change_case(char *, int);
83 void char_scroll(unsigned int);
84 void show_info(unsigned int, unsigned int, unsigned long int, unsigned long int);
85 int file_size(FILE *);
86 int check_if_pdf(char *);
87 void lesspipe(void);
88 void fmt(void);
89 void get_editor(void);
90 int start_editor(unsigned long int);
91 void strip_extra_blanks(void);
92 char *get_basename(char *);
93 char *str_trunc(char *, int);
94 void my_perror(char *);
95 void cperror(char *);
96 void catch_sigwinch(int signo);
97 void catch_sigint(int signo);
98 void signal_setup(void);
99 void create_windows(void);
100 void check_homedir(void);
101 void check_stdin(void);
102 FILE *open_tty(char *);
103
main(int argc,char ** argv)104 int main(int argc, char **argv)
105 {
106 signal_setup();
107 progname = argv[0];
108 check_homedir();
109 get_editor();
110 scan_command_line(argc, argv);
111 unlink(lfile.lazy_file);
112 if (lfile.piped)
113 unlink(lfile.lazy_pipe);
114 clear();
115 refresh();
116 endwin();
117 return 0;
118 }
119
check_homedir(void)120 void check_homedir(void)
121 {
122 char *home = getenv("HOME");
123
124 if (home) {
125 snprintf(lfile.homedir, (strlen(home) + 12), "%s/.lazyread/", home);
126 if ((access(lfile.homedir, F_OK|W_OK)) != 0)
127 if (mkdir(lfile.homedir, S_IRUSR|S_IWUSR|S_IXUSR) != 0)
128 my_perror(lfile.homedir);
129 }
130 snprintf(lfile.lazy_file, sizeof lfile.lazy_file, "%slazy_file", lfile.homedir);
131 snprintf(lfile.lazy_tmp, sizeof lfile.lazy_tmp, "%slazy_tmp", lfile.homedir);
132 if (lfile.piped)
133 snprintf(lfile.lazy_pipe, sizeof lfile.lazy_pipe, "%spiped", lfile.homedir);
134
135 }
136
check_stdin(void)137 void check_stdin(void)
138 {
139 /* do this before any initscr()'ing due to ncurses tty i/o handling
140 when input is piped from another program */
141 char stdin_buf[BUFMAX];
142 FILE *fp, *input, *output;
143
144 if (lfile.piped) {
145 input = output = open_tty(lfile.tty_name);
146
147 if (!(fp = fopen(lfile.lazy_pipe, "w")))
148 my_perror("fopen()");
149 while (fgets(stdin_buf, sizeof stdin_buf, stdin)) {
150 fprintf(fp, "%s", stdin_buf);
151 }
152 fclose(fp);
153 STDIN_SCREEN = newterm((char *)0, output, input);
154 }
155 }
156
open_tty(char * tty_path)157 FILE *open_tty(char *tty_path)
158 {
159 FILE *fp;
160 struct stat sb;
161
162 if (stat(tty_path, &sb) < 0)
163 my_perror(tty_path);
164 if ((sb.st_mode & S_IFMT) != S_IFCHR) {
165 errno = ENOTTY;
166 my_perror(tty_path);
167 }
168
169 if (!(fp = fopen(tty_path, "a+")))
170 my_perror("fopen()");
171 if (fp == 0)
172 my_perror(tty_path);
173
174 return fp;
175 }
176
create_windows(void)177 void create_windows(void)
178 {
179 initscr();
180 if (lfile.piped) {
181 set_term(STDIN_SCREEN); /* switch to a real tty */
182 refresh();
183 endwin();
184 }
185 cbreak();
186 noecho();
187 nonl();
188 intrflush(stdscr, FALSE);
189 keypad(stdscr, TRUE);
190 curs_set(FALSE);
191 if (lop.want_color)
192 lazy_colors();
193
194 if (!(pscroll = (struct my_windows *)malloc(sizeof(struct my_windows))))
195 cperror("malloc()");
196
197 pscroll->scrollwin = newwin(LINES, 0, 0, 0);
198
199 if (!(pstat = (struct my_windows *)malloc(sizeof(struct my_windows))))
200 cperror("malloc()");
201
202 pstat->statwin = newwin(1, COLS, LINES - 1, 0);
203 refresh();
204 }
205
scan_command_line(int argc,char ** argv)206 void scan_command_line(int argc, char **argv)
207 {
208 int optch, opt;
209 static char optstring[] = "s:p:f:w:c:navhbluxmt:";
210 char speed[20], position[3], *filename_nodashf;
211 unsigned int scroll_speed = lop.default_speed;
212
213 if (argc < 2)
214 usage();
215 if (argv[1])
216 filename_nodashf = argv[1];
217 for (opt = 1; opt < argc; opt++) {
218 if (!strncmp(argv[opt], "-", 1))
219 break;
220 else { /* no options just filename */
221 lfile.piped = FALSE;
222 if (strlen(argv[opt]) > BUFMAX)
223 usage();
224 if (!(lfile.filename = (char *)malloc(strlen(argv[opt])+1)))
225 my_perror("malloc()");
226 strncpy(lfile.filename, argv[opt], strlen(argv[opt]));
227 if (!(lfile.fp = fopen(lfile.filename, "r")))
228 my_perror("fopen()");
229 }
230 }
231
232 while ((optch = getopt(argc, argv, optstring)) != -1)
233 switch (optch) {
234 case 's':
235 if (!char_check(optarg))
236 usage();
237 strncpy(speed, optarg, 20);
238 scroll_speed = (unsigned int)atoi(speed);
239 break;
240 case 'p':
241 if (!char_check(optarg))
242 usage();
243 strncpy(position, optarg, 3);
244 lop.pos_changed = (unsigned int)atoi(position);
245 break;
246 case 'f':
247 lfile.piped = FALSE;
248 if (strlen(optarg) > BUFMAX)
249 usage();
250 if (!(lfile.filename = (char *)malloc(strlen(optarg)+1)))
251 my_perror("malloc()");
252 strncpy(lfile.filename, optarg, strlen(optarg));
253 if (!(lfile.fp = fopen(lfile.filename, "r")))
254 my_perror("fopen()");
255 break;
256 case 't':
257 if (!(lfile.tty_name = (char *)malloc(strlen(optarg)+1)))
258 my_perror("malloc()");
259 strncpy(lfile.tty_name, optarg, strlen(optarg));
260 break;
261 case 'w':
262 if (strlen(optarg) > BUFMAX)
263 usage();
264 if (!(lop.special_word = (char *)malloc(strlen(optarg)+1)))
265 my_perror("malloc()");
266 strncpy(lop.special_word, optarg, strlen(optarg));
267 break;
268 case 'n':
269 lop.view_normal = TRUE;
270 break;
271 case 'u':
272 lop.case_type = UC;
273 lop.case_change = TRUE;
274 break;
275 case 'l':
276 lop.case_type = LC;
277 lop.case_change = TRUE;
278 break;
279 case 'c':
280 lop.want_color = 1;
281 if (!(lop.use_color = (char *)malloc(strlen(optarg)+1)))
282 my_perror("malloc");
283 strncpy(lop.use_color, optarg, strlen(optarg));
284 break;
285 case 'x':
286 lop.statusbar = FALSE;
287 break;
288 case 'v':
289 endwin();
290 printf("lazyread 2.0 By Ryan Kulla\n");
291 exit(EXIT_SUCCESS);
292 break;
293 case 'h':
294 usage();
295 break;
296 case 'a':
297 lop.auto_pause = TRUE;
298 break;
299 case 'm':
300 lop.scrollmode_chars = TRUE;
301 break;
302 case 'b':
303 lop.beep_ok = TRUE;
304 break;
305 default:
306 usage();
307 break;
308 }
309 do_options(scroll_speed, argc, filename_nodashf);
310 }
311
lazy_colors(void)312 void lazy_colors(void)
313 {
314 if (has_colors() == FALSE)
315 cperror("Your terminal does not support colors");
316
317 start_color();
318 if (!strncmp(lop.use_color, "red", 3))
319 assume_default_colors(COLOR_RED, COLOR_BLACK);
320 if (!strncmp(lop.use_color, "bgred", 5))
321 assume_default_colors(COLOR_WHITE, COLOR_RED);
322 if (!strncmp(lop.use_color, "bgblue", 6))
323 assume_default_colors(COLOR_WHITE, COLOR_BLUE);
324 if (!strncmp(lop.use_color, "blue", 4))
325 assume_default_colors(COLOR_BLUE, COLOR_BLACK);
326 if (!strncmp(lop.use_color, "green", 5))
327 assume_default_colors(COLOR_GREEN, COLOR_BLACK);
328 if (!strncmp(lop.use_color, "bggreen", 7))
329 assume_default_colors(COLOR_BLUE, COLOR_GREEN);
330 if (!strncmp(lop.use_color, "magenta", 7))
331 assume_default_colors(COLOR_MAGENTA, COLOR_BLACK);
332 if (!strncmp(lop.use_color, "bgmagenta", 9))
333 assume_default_colors(COLOR_WHITE, COLOR_MAGENTA);
334 if (!strncmp(lop.use_color, "yellow", 6))
335 assume_default_colors(COLOR_YELLOW, COLOR_BLACK);
336 if (!strncmp(lop.use_color, "bgyellow", 8))
337 assume_default_colors(COLOR_WHITE, COLOR_YELLOW);
338 if (!strncmp(lop.use_color, "bgwhite", 7))
339 assume_default_colors(COLOR_BLACK, COLOR_WHITE);
340 if (!strncmp(lop.use_color, "bgblack", 7))
341 assume_default_colors(COLOR_WHITE, COLOR_BLACK);
342 }
343
do_options(unsigned int scroll_speed,int argc,char * filename_nodashf)344 void do_options(unsigned int scroll_speed, int argc, char *filename_nodashf)
345 {
346 if (lfile.piped) {
347 lfile.filename = lfile.lazy_pipe;
348 check_stdin();
349 }
350
351 lesspipe();
352 fmt();
353
354 if (!lop.view_normal)
355 strip_extra_blanks();
356
357 create_windows();
358
359 if (lfile.filename)
360 lfile.display_filename = str_trunc(get_basename(lfile.filename), 15);
361
362 if (!lop.special_word)
363 lop.special_word = "lazyread";
364
365 if (scroll_speed)
366 scroll_it(scroll_speed, argc, filename_nodashf);
367 else
368 usage();
369 }
370
lesspipe(void)371 void lesspipe(void)
372 {
373 FILE *fp_read, *fp_write;
374 char *c, buf[BUFMAX], command[BUFMAX], lesscommand[BUFMAX], *lesspipe;
375 unsigned long int empty = 0;
376 char qfilename[BUFMAX]; /* quoted filename */
377
378 printf("Loading..\n");
379 /* $LESSOPEN will look like: |/usr/bin/lesspipe.sh %s */
380 lesspipe = "|/usr/bin/lesspipe.sh %s";
381 if (lesspipe) {
382 /* strip off the leading | */
383 if ((c = strchr(lesspipe, '|'))) {
384 strncpy(lesscommand, c + 1, strlen(c + 1));
385 /* redirection */
386 if (check_if_pdf(lfile.filename))
387 strncat(lesscommand, " - > ", 5); /* pdftotext needs the - */
388 else
389 strncat(lesscommand, " > ", 3);
390 strncat(lesscommand, lfile.lazy_file, strlen(lfile.lazy_file));
391 /* add quotes for filenames containing spaces: */
392 snprintf(qfilename, sizeof qfilename, "\"%s\"", lfile.filename);
393 snprintf(command, (strlen(lesscommand) + strlen(qfilename)), lesscommand, qfilename);
394 }
395 system(command); /* run lesspipe.sh */
396 }
397
398 if (!(fp_write = fopen(lfile.lazy_file, "r")))
399 my_perror("fopen()");
400 if (file_size(fp_write) == 0)
401 empty = 1;
402 fclose(fp_write);
403
404 if (empty) {
405 /* lesspipe didn't have any output, make the file ourselves */
406 if (!(fp_read = fopen(lfile.filename, "r")))
407 my_perror("fopen()");
408 if (!(fp_write = fopen(lfile.lazy_file, "w")))
409 my_perror("fopen()");
410 while (fgets(buf, sizeof buf, fp_read)) {
411 fprintf(fp_write, "%s", buf);
412 }
413 fclose(fp_read);
414 fclose(fp_write);
415 }
416 }
417
check_if_pdf(char * filename)418 int check_if_pdf(char *filename)
419 {
420 char *c;
421
422 if (strstr(filename, ".pdf")) {
423 if ((c = strrchr(filename, '.')))
424 if (!strncmp(c, ".pdf", 4))
425 return 1;
426 }
427
428 return 0;
429 }
430
fmt(void)431 void fmt(void)
432 {
433 char command[BUFMAX];
434
435 snprintf(command, sizeof command, "fmt -s %s > %s", lfile.lazy_file, lfile.lazy_tmp);
436 system(command);
437
438 if (unlink(lfile.lazy_file))
439 my_perror("unlink()");
440 if (link(lfile.lazy_tmp, lfile.lazy_file) != 0)
441 my_perror("link()");
442 if (unlink(lfile.lazy_tmp))
443 my_perror("unlink()");
444 }
445
strip_extra_blanks(void)446 void strip_extra_blanks(void)
447 {
448 FILE *fp_read, *fp_write;
449 char buf[BUFMAX];
450 unsigned int blank = 0;
451
452 if (!(fp_read = fopen(lfile.lazy_file, "r+")))
453 my_perror("fopen()");
454 if (!(fp_write = fopen(lfile.lazy_tmp, "w")))
455 my_perror("fopen()");
456 while (fgets(buf, sizeof buf, fp_read)) {
457 /* Don't print 2+ blank lines */
458 if (buf[0] == CR || buf[0] == LF)
459 blank++;
460 else
461 blank = 0;
462 if (blank == 2) {
463 blank = 1;
464 continue;
465 }
466 fprintf(fp_write, "%s", buf);
467 }
468 fclose(fp_read);
469 fclose(fp_write);
470 if (unlink(lfile.lazy_file))
471 my_perror("unlink()");
472 if (link(lfile.lazy_tmp, lfile.lazy_file) != 0)
473 my_perror("link()");
474 if (unlink(lfile.lazy_tmp))
475 my_perror("unlink()");
476 }
477
scroll_it(unsigned int scroll_speed,int argc,char * filename_nodashf)478 void scroll_it(unsigned int scroll_speed, int argc, char *filename_nodashf)
479 {
480 char buf[BUFMAX], *s;
481 unsigned int origspeed = scroll_speed, toggle = ON;
482 unsigned long int total_lines = 0, line = 0;
483
484 lop.y = LINES - 2;
485 if (lop.pos_changed)
486 lop.y = lop.pos_changed;
487 if ((lop.y > LINES - 2) || (lop.y < 1))
488 usage();
489
490 if (!lfile.piped) { /* if they used -f */
491 if (!(lfile.fp = fopen(lfile.lazy_file, "r")))
492 cperror("fopen()");
493 lfile.which = lfile.fp;
494 total_lines = line_nums(lfile.which);
495 } else {
496 if (!(lfile.which = fopen(lfile.lazy_pipe, "r")))
497 cperror("fopen()");
498 lfile.display_filename = "piped output";
499 total_lines = line_nums(lfile.which);
500 }
501 lfile.the_file_size = file_size(lfile.which);
502
503 if (lop.scrollmode_chars)
504 char_scroll(scroll_speed);
505 else {
506 scrollok(pscroll->scrollwin, TRUE);
507 while ((s = fgets(buf, sizeof(buf), lfile.which))) { /* scroll time */
508 flushinp();
509 line++;
510 if (lop.statusbar)
511 if (toggle)
512 get_stats(total_lines, line);
513 highlight_word(buf, scroll_speed, origspeed, toggle, total_lines, line);
514 if (lop.case_change)
515 change_case(buf, lop.case_type);
516 mvwprintw(pscroll->scrollwin, lop.y, 0, "%s", buf);
517 napms(scroll_speed);
518 scroll(pscroll->scrollwin);
519 wrefresh(pscroll->scrollwin);
520 user_input(&scroll_speed, origspeed, &toggle, total_lines, line);
521 }
522 get_stats(total_lines, line); /* see stats at eof */
523 wgetch(pscroll->scrollwin);
524 fclose(lfile.which);
525 }
526 }
527
char_scroll(unsigned int scroll_speed)528 void char_scroll(unsigned int scroll_speed)
529 {
530 unsigned int i, line = 0;
531 char buf[BUFMAX], *s;
532 unsigned int origspeed = scroll_speed, toggle = ON;
533 unsigned long int total_lines = line_nums(lfile.which);
534
535 while ((s = fgets(buf, sizeof(buf), lfile.which))) {
536 line++;
537 highlight_word(buf, scroll_speed, origspeed, toggle, total_lines, line);
538 if (lop.case_change)
539 change_case(buf, lop.case_type);
540 if (lop.highlight) {
541 lop.highlight = FALSE;
542 wclear(pscroll->scrollwin);
543 wrefresh(pscroll->scrollwin);
544 continue;
545 }
546 for (i = 0; buf[i] != '\0'; i++) {
547 if (lop.statusbar)
548 if (toggle)
549 get_stats(total_lines, line);
550 if (lop.reshow_statusbar) {
551 get_stats(total_lines, line); /* see status bar */
552 lop.reshow_statusbar = FALSE;
553 }
554 if (lop.pos_changed)
555 mvwprintw(pscroll->scrollwin, lop.y, i, "%c", buf[i]);
556 else
557 mvwprintw(pscroll->scrollwin, lop.y / 2, i, "%c", buf[i]);
558 napms(scroll_speed);
559 wrefresh(pscroll->scrollwin);
560 user_input(&scroll_speed, origspeed, &toggle, total_lines, line);
561 }
562 wclear(pscroll->scrollwin);
563 wrefresh(pscroll->scrollwin);
564 }
565 get_stats(total_lines, line); /* see stats at eof */
566 wgetch(pscroll->scrollwin);
567 fclose(lfile.which);
568 }
569
file_size(FILE * fp)570 int file_size(FILE *fp)
571 {
572 unsigned long int len = 0;
573
574 fseek(fp, 0, SEEK_END);
575 len = ftell(fp);
576 fseek(fp, 0, SEEK_SET);
577
578 return(len);
579 }
580
change_case(char * buf,int choice)581 void change_case(char *buf, int choice)
582 {
583 char *p;
584
585 for (p = buf; *p != '\0'; p++) {
586 if (choice == LC)
587 *p = tolower(*p);
588 else
589 *p = toupper(*p);
590 }
591 }
592
highlight_word(char * buf,unsigned int scroll_speed,unsigned int origspeed,unsigned int toggle,unsigned long int total_lines,unsigned long int line)593 void highlight_word(char *buf, unsigned int scroll_speed, unsigned int origspeed, unsigned int toggle, unsigned long int total_lines, unsigned long int line)
594 {
595 unsigned int i = 0;
596
597 /* highlight the entire line special_word is on */
598 if (strstr(buf, lop.special_word)) {
599 lop.highlight = TRUE;
600 wattrset(pscroll->scrollwin, A_BOLD);
601 if (lop.beep_ok)
602 beep();
603
604 if (lop.scrollmode_chars) {
605 /* print again to see correctly */
606 for (i = 0; buf[i] != '\0'; i++) {
607 if (lop.statusbar)
608 if (toggle)
609 get_stats(total_lines, line);
610 if (lop.pos_changed)
611 mvwprintw(pscroll->scrollwin, lop.y, i, "%c", buf[i]);
612 else
613 mvwprintw(pscroll->scrollwin, lop.y / 2, i, "%c", buf[i]);
614 user_input(&scroll_speed, origspeed, &toggle, total_lines, line);
615 napms(scroll_speed);
616 wrefresh(pscroll->scrollwin);
617 }
618 }
619 if (lop.auto_pause) {
620 wrefresh(pscroll->scrollwin);
621 nodelay(stdscr, FALSE);
622 getch();
623 }
624 }
625 else
626 wattrset(pscroll->scrollwin, A_NORMAL);
627 }
628
get_stats(unsigned long int total_lines,unsigned long int line)629 void get_stats(unsigned long int total_lines, unsigned long int line)
630 {
631 time_t now;
632 struct tm *tmptr;
633 char sdate[64];
634
635 time(&now);
636 tmptr = localtime(&now);
637 strftime(sdate, sizeof sdate, "%a %b %d %I:%M:%S%p", tmptr);
638
639 lfile.percent = (((float)line / (float)total_lines) * 100);
640
641 wbkgd(pstat->statwin, A_REVERSE);
642
643 if ((line % LINES) == 0)
644 lfile.page_num++;
645 mvwprintw(pstat->statwin, 0, 0, "%ld/%ld - %.0f%% Page: %ld - %s", line,
646 total_lines, lfile.percent, lfile.page_num, lfile.display_filename);
647
648 mvwprintw(pstat->statwin, 0, COLS - 23, "%s", sdate);
649
650 wrefresh(pstat->statwin);
651 }
652
get_editor(void)653 void get_editor(void)
654 {
655 if (getenv("VISUAL"))
656 lop.editor = getenv("VISUAL");
657 else if (getenv("EDITOR"))
658 lop.editor = getenv("EDITOR");
659
660 if ((access(lop.editor, F_OK)) != 0) {
661 if (!(access("/bin/vi", F_OK)))
662 lop.editor = "/bin/vi";
663 else
664 lop.editor = "None";
665 }
666 }
667
start_editor(unsigned long int line)668 int start_editor(unsigned long int line)
669 {
670 char *editor_base, line_str[BUFMAX];
671 pid_t pid, wpid;
672 int status;
673
674 if ((strncmp(lop.editor, "None", 4)) != 0) {
675 editor_base = get_basename(lop.editor);
676 snprintf(line_str, sizeof line_str, "+%ld", line);
677 def_prog_mode();
678
679 pid = fork();
680 if (pid == -1) {
681 cperror("fork()");
682 } else if (pid == 0) {
683 execlp(lop.editor, editor_base, line_str, lfile.filename, NULL);
684 cperror("execlp()");
685 } else {
686 wpid = wait(&status);
687 if (wpid == -1)
688 cperror("wait()");
689 if (wpid != pid)
690 exit(1);
691 }
692 clear();
693 refresh();
694 reset_prog_mode();
695 refresh();
696 }
697 return 0;
698 }
699
get_basename(char * editor)700 char *get_basename(char *editor)
701 {
702 char *c;
703
704 if ((c = strrchr(editor, '/')))
705 return (c + 1);
706 else
707 return editor;
708 }
709
user_input(unsigned int * scroll_speed,unsigned int origspeed,unsigned int * toggle,unsigned long int total_lines,unsigned long int line)710 void user_input(unsigned int *scroll_speed, unsigned int origspeed, unsigned
711 int *toggle, unsigned long int total_lines, unsigned long int line)
712 {
713 switch (get_key()) {
714 case 1:
715 if (*scroll_speed != 1) /* speed up */
716 *scroll_speed = 1;
717 else {
718 if (lop.new_speed)
719 *scroll_speed = lop.new_speed;
720 else
721 *scroll_speed = origspeed; /* stop speeding */
722 }
723 break;
724 case 2:
725 quit_cleanly();
726 break;
727 case 3:
728 *scroll_speed = origspeed;
729 lop.new_speed = 0;
730 break;
731 case 4:
732 if (lop.statusbar)
733 if (toggle)
734 get_stats(total_lines, line);
735 nodelay(stdscr, FALSE);
736 getch();
737 break;
738 case 5:
739 if (!lop.statusbar)
740 lop.statusbar = ON;
741 *toggle = ON;
742 break;
743 case 6:
744 if (!lop.statusbar)
745 break;
746 *toggle = OFF;
747 wbkgd(pstat->statwin, A_NORMAL);
748 wclear(pstat->statwin);
749 wrefresh(pstat->statwin);
750 break;
751 case 7:
752 wclear(pscroll->scrollwin);
753 wrefresh(pscroll->scrollwin);
754 break;
755 case 8:
756 *scroll_speed -= ((*scroll_speed * 25) / 100);
757 lop.new_speed = *scroll_speed;
758 break;
759 case 9:
760 *scroll_speed += ((*scroll_speed * 25) / 100);
761 lop.new_speed = *scroll_speed;
762 break;
763 case 10:
764 lop.auto_pause ^= 1; /* toggle */
765 break;
766 case 11:
767 if (lop.beep_ok)
768 beep();
769 show_info(*scroll_speed, origspeed, total_lines, line);
770 break;
771 case 12:
772 start_editor(line);
773 break;
774 }
775 }
776
get_key(void)777 unsigned int get_key(void)
778 {
779 chtype key;
780
781 nodelay(stdscr, TRUE);
782 if ((key = getch()) != (unsigned long int)ERR)
783 if (key == 32) return 1;
784 if (key == 'q') return 2;
785 if (key == 'o') return 3;
786 if (key == 'p') return 4;
787 if (key == 'v') return 5;
788 if (key == 'n') return 6;
789 if (key == 'c') return 7;
790 if (key == 'f') return 8;
791 if (key == 's') return 9;
792 if (key == 'a') return 10;
793 if (key == 'i') return 11;
794 if (key == 'e') return 12;
795
796 return 0;
797 }
798
show_info(unsigned int scroll_speed,unsigned int origspeed,unsigned long int total_lines,unsigned long int line)799 void show_info(unsigned int scroll_speed, unsigned int origspeed, unsigned long int total_lines, unsigned long int line)
800 {
801 char buf[BUFMAX], *current_dir;
802 char *header_msg = "Lazyread 2.0 [Press any key]";
803
804 if (!getcwd(buf, BUFMAX))
805 cperror("getcwd()");
806 if (strlen(buf) > (COLS - 18))
807 current_dir = str_trunc(buf, (COLS - 18));
808 else
809 current_dir = buf;
810
811 def_prog_mode(); /* save the old screen */
812 clear();
813 refresh();
814
815 box(stdscr, 0, 0);
816 attrset(A_BOLD);
817 mvprintw(0, ((COLS / 2) - (strlen(header_msg) / 2)), "%s", header_msg);
818 attrset(A_NORMAL);
819 mvhline(1, 1, ACS_HLINE, COLS - 2);
820 attrset(A_BOLD); mvprintw(2, 1, "Filename: "); attrset(A_NORMAL);
821 mvprintw(2, 11, "%s", get_basename(lfile.filename));
822 attrset(A_BOLD); mvprintw(3, 1, "File Size: "); attrset(A_NORMAL);
823 mvprintw(3, 12, "%ld bytes", lfile.the_file_size);
824 attrset(A_BOLD); mvprintw(4, 1, "Current Dir: "); attrset(A_NORMAL);
825 mvprintw(4, 14, "%s%c", current_dir, strlen(current_dir) < 2 ? ' ' : '/');
826 attrset(A_BOLD); mvprintw(5, 1, "Current Line: "); attrset(A_NORMAL);
827 mvprintw(5, 15, "%ld of %ld - %.0f%% - Page: %d", line, total_lines, lfile.percent, lfile.page_num);
828 attrset(A_BOLD); mvprintw(6, 1, "Scroll Speed: "); attrset(A_NORMAL);
829 mvprintw(6, 15, "(%d Milliseconds | %.2f Second%s", scroll_speed, (float)scroll_speed / 1000, scroll_speed > 1000 ? "s)" : ")");
830 attrset(A_BOLD); mvprintw(7, 1, "Original Speed: "); attrset(A_NORMAL);
831 mvprintw(7, 17, "(%d Milliseconds | %.2f Second%s", origspeed, (float)origspeed / 1000, origspeed > 1000 ? "%s)" : ")");
832 attrset(A_BOLD); mvprintw(8, 1, "External Editor: "); attrset(A_NORMAL);
833 mvprintw(8, 18, "%s", lop.editor);
834 attrset(A_BOLD); mvprintw(9, 1, "Terminal Size: "); attrset(A_NORMAL);
835 mvprintw(9, 16, "%d Rows, %d Columns", LINES, COLS);
836 attrset(A_BOLD); mvprintw(10, 1, "Beep On Events: "); attrset(A_NORMAL);
837 mvprintw(10, 17, "%s", lop.beep_ok ? "Yes" : "No");
838 attrset(A_BOLD); mvprintw(11, 1, "Auto-Pause: "); attrset(A_NORMAL);
839 mvprintw(11, 13, "%s", lop.auto_pause ? "Yes" : "No");
840 attrset(A_BOLD); mvprintw(12, 1, "Skip Extra Blank Lines: "); attrset(A_NORMAL);
841 mvprintw(12, 25, "%s", lop.view_normal ? "No" : "Yes");
842
843 nodelay(stdscr, FALSE);
844 getch();
845 clear();
846 refresh();
847 reset_prog_mode(); /* Return the screen */
848 refresh(); /* needed to show the screen */
849 lop.reshow_statusbar = TRUE;
850 }
851
usage()852 void usage()
853 {
854 printf("Usage: %s [OPTIONS]\n", progname);
855 printf("-f <filename> File to scroll.\n"
856 "-s <n> Scroll at <n> milliseconds. Default: 1000 (1 sec).\n"
857 "-p <n> Start text on row <n> (1 to LINES-2).\n"
858 "-w <string> Highlight all lines that <string> appears on.\n"
859 "-l Display in all lower case characters.\n"
860 "-u Display in all upper case characters.\n"
861 "-c <color> red, bgred, green, bggreen, blue, bgblue, yellow, bgyellow, magenta, bgmagenta, bgwhite.\n"
862 "-n Don't take out extra blank lines. Display as is.\n"
863 "-a Automatically pause on highlight word from -w.\n"
864 "-v Display program version number.\n"
865 "-h Help (This message).\n"
866 "-x Don't show status bar.\n"
867 "-b Allow beeping on important events.\n"
868 "-m Scroll a character at a time mode.\n"
869 "-t <ttyname> Name of tty your running lazyread from while piped\n"
870
871 "\tWhile lazyread is running you can use the option keys:\n"
872 "'q' to quit.\n'p' to pause.\n'spacebar' to scroll super"
873 "fast (hit again to turn off).\n'c' to clear the current screen."
874 "\n'n' to turn off the status bar.\n'v' to turn the status bar back on.\n"
875 "'f' to speed scrolling up in 25 percent increments.\n's' to slow "
876 "scrolling speed down in 25 percent increments.\n"
877 "'o' to go back to original speed.\n'a' to toggle Auto-Pausing on/off.\n"
878 "'e' open file in your editor. Uses $VISUAL, $EDITOR or /bin/vi.\n"
879 "'i' to view detailed file/program/etc information.\n");
880
881 exit(EXIT_SUCCESS);
882 }
883
quit_cleanly(void)884 void quit_cleanly(void)
885 {
886 unlink(lfile.lazy_file);
887 if (lfile.piped)
888 unlink(lfile.lazy_pipe);
889 clear();
890 refresh();
891 flushinp();
892 endwin();
893 exit(EXIT_SUCCESS);
894 }
895
char_check(char * str)896 int char_check(char *str)
897 {
898 /* checks if any non-digits are found in the input string */
899
900 for (; *str; str++)
901 if (!isdigit(*str))
902 return 0;
903
904 return 1;
905 }
906
line_nums(FILE * fp)907 long line_nums(FILE *fp)
908 {
909 char buf[255];
910 long linenum = 0;
911
912 /* add up all the lines of the file */
913 while (fgets(buf, sizeof(buf), fp))
914 ++linenum;
915
916 rewind(fp);
917
918 return (linenum);
919 }
920
str_trunc(char * s,int n)921 char *str_trunc(char *s, int n)
922 {
923 char *buf;
924
925 if (n > strlen(s))
926 n = strlen(s) + 1;
927
928 if (!(buf = (char *)malloc(n + 1)))
929 cperror("malloc()");
930
931 strncpy(buf, s, n);
932
933 if (strlen(s) > strlen(buf))
934 strncat(buf, "~", 1);
935
936 return (buf);
937 }
938
my_perror(char * msg)939 void my_perror(char *msg)
940 {
941 perror(msg);
942 exit(EXIT_FAILURE);
943 }
944
cperror(char * msg)945 void cperror(char *msg)
946 {
947 endwin(); /* kill the window first so we can print to stdout */
948 perror(msg);
949 quit_cleanly();
950 }
951
catch_sigwinch(int signo)952 void catch_sigwinch(int signo)
953 {
954 /* terminal resizing functionality */
955 refresh();
956 endwin();
957 free(pscroll->scrollwin);
958 free(pstat->statwin);
959 create_windows();
960 scrollok(pscroll->scrollwin, TRUE);
961 lop.y = LINES - 2;
962 }
963
catch_sigint(int signo)964 void catch_sigint(int signo)
965 {
966 quit_cleanly();
967 }
968
signal_setup(void)969 void signal_setup(void)
970 {
971 struct sigaction sa_resize_old, sa_resize_new;
972 struct sigaction sa_kill_old, sa_kill_new;
973
974 /* xterm resizing */
975 sa_resize_new.sa_handler = catch_sigwinch;
976 sigemptyset(&sa_resize_new.sa_mask);
977 sa_resize_new.sa_flags = 0;
978 sigaction(SIGWINCH, &sa_resize_new, &sa_resize_old);
979
980 /* control-C */
981 sa_kill_new.sa_handler = catch_sigint;
982 sigemptyset(&sa_kill_new.sa_mask);
983 sa_kill_new.sa_flags = 0;
984 sigaction(SIGINT, &sa_kill_new, &sa_kill_old);
985 }
986