1 | /* |
1 | /* |
2 | * Copyright 2001 by Marco d'Itri <md@linux.it> |
2 | * Copyright 2001 by Marco d'Itri <md@linux.it> |
3 | * |
3 | * Copyright 2000,2001,2002,2003,2004 |
4 | * Original version by Mike Baker, then maintained by pcg@goof.com. |
4 | * Marc Lehmann <pcg@goof.com>, |
|
|
5 | * and many others, see README |
|
|
6 | * |
|
|
7 | * Original version by Mike Baker. |
5 | * |
8 | * |
6 | * This program is free software; you can redistribute it and/or modify |
9 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
10 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
11 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
12 | * (at your option) any later version. |
… | |
… | |
57 | off_t last_size; /* file size at the last check */ |
60 | off_t last_size; /* file size at the last check */ |
58 | unsigned long color; /* color to be used for printing */ |
61 | unsigned long color; /* color to be used for printing */ |
59 | int partial; /* true if the last line isn't complete */ |
62 | int partial; /* true if the last line isn't complete */ |
60 | int lastpartial; /* true if the previous output wasn't complete */ |
63 | int lastpartial; /* true if the previous output wasn't complete */ |
61 | int index; /* index into linematrix of a partial line */ |
64 | int index; /* index into linematrix of a partial line */ |
|
|
65 | int modified; /* true if line is modified & needs displaying */ |
62 | }; |
66 | }; |
63 | |
67 | |
64 | struct linematrix |
68 | struct linematrix |
65 | { |
69 | { |
66 | char *line; |
70 | char *line; |
67 | int len; |
71 | int len; |
68 | unsigned long color; |
72 | unsigned long color; |
69 | }; |
73 | }; |
70 | |
74 | |
|
|
75 | struct displaymatrix |
|
|
76 | { |
|
|
77 | char *line; |
|
|
78 | int len; |
|
|
79 | int buffer_size; |
|
|
80 | unsigned long color; |
|
|
81 | }; |
|
|
82 | |
71 | /* global variables */ |
83 | /* global variables */ |
72 | struct linematrix *lines; |
84 | struct linematrix *lines; |
|
|
85 | struct displaymatrix *display; |
73 | int width = STD_WIDTH, height = STD_HEIGHT, listlen; |
86 | int width = STD_WIDTH, height = STD_HEIGHT, listlen; |
74 | int win_x = LOC_X, win_y = LOC_Y; |
87 | int win_x = LOC_X, win_y = LOC_Y; |
75 | int font_ascent, font_height; |
88 | int font_ascent, font_height; |
76 | int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */ |
89 | int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */ |
77 | int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */ |
90 | int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */ |
… | |
… | |
112 | void force_refresh (int); |
125 | void force_refresh (int); |
113 | void blank_window (int); |
126 | void blank_window (int); |
114 | |
127 | |
115 | void InitWindow (void); |
128 | void InitWindow (void); |
116 | unsigned long GetColor (const char *); |
129 | unsigned long GetColor (const char *); |
117 | void redraw (void); |
130 | void redraw (int); |
118 | void refresh (int, int, int); |
131 | void refresh (int, int, int, int); |
119 | |
132 | |
120 | void transform_line (char *s); |
133 | void transform_line (char *s); |
121 | int lineinput (struct logfile_entry *); |
134 | int lineinput (struct logfile_entry *); |
122 | void reopen (void); |
135 | void reopen (void); |
123 | void check_open_files (void); |
136 | void check_open_files (void); |
… | |
… | |
127 | void display_version (void); |
140 | void display_version (void); |
128 | void display_help (char *); |
141 | void display_help (char *); |
129 | void install_signal (int, void (*)(int)); |
142 | void install_signal (int, void (*)(int)); |
130 | void *xstrdup (const char *); |
143 | void *xstrdup (const char *); |
131 | void *xmalloc (size_t); |
144 | void *xmalloc (size_t); |
|
|
145 | void *xrealloc (void *, size_t); |
132 | int daemonize (void); |
146 | int daemonize (void); |
133 | |
147 | |
134 | /* signal handlers */ |
148 | /* signal handlers */ |
135 | void |
149 | void |
136 | list_files (int dummy) |
150 | list_files (int dummy) |
… | |
… | |
149 | } |
163 | } |
150 | |
164 | |
151 | void |
165 | void |
152 | force_refresh (int dummy) |
166 | force_refresh (int dummy) |
153 | { |
167 | { |
154 | redraw (); |
168 | redraw (1); |
155 | } |
169 | } |
156 | |
170 | |
157 | void |
171 | void |
158 | blank_window (int dummy) |
172 | blank_window (int dummy) |
159 | { |
173 | { |
… | |
… | |
348 | |
362 | |
349 | XSelectInput (disp, root, ExposureMask | FocusChangeMask); |
363 | XSelectInput (disp, root, ExposureMask | FocusChangeMask); |
350 | } |
364 | } |
351 | |
365 | |
352 | /* |
366 | /* |
353 | * redraw does a complete redraw, rather than an update (i.e. the area |
367 | * if redraw() is passwd a non-zero argument, it does a complete |
354 | * gets cleared first) |
368 | * redraw, rather than an update. if the argument is zero (and |
|
|
369 | * -noflicker is in effect) then only the lines which have changed |
|
|
370 | * since the last draw are redrawn. |
|
|
371 | * |
355 | * the rest is handled by regular refresh()'es |
372 | * the rest is handled by regular refresh()'es |
356 | */ |
373 | */ |
357 | void |
374 | void |
358 | redraw (void) |
375 | redraw (int redraw_all) |
359 | { |
376 | { |
360 | XSetClipMask (disp, WinGC, None); |
377 | XSetClipMask (disp, WinGC, None); |
361 | refresh (0, 32768, 1); |
378 | refresh (0, 32768, 1, redraw_all); |
362 | } |
379 | } |
363 | |
380 | |
364 | /* Just redraw everything without clearing (i.e. after an EXPOSE event) */ |
381 | /* Just redraw everything without clearing (i.e. after an EXPOSE event) */ |
365 | void |
382 | void |
366 | refresh (int miny, int maxy, int clear) |
383 | refresh (int miny, int maxy, int clear, int refresh_all) |
367 | { |
384 | { |
368 | int lin; |
385 | int lin; |
369 | int offset = (listlen + 1) * font_height; |
386 | int offset = listlen * font_height + font_ascent + effect_y_offset; |
370 | unsigned long black_color = GetColor ("black"); |
387 | unsigned long black_color = GetColor ("black"); |
371 | |
388 | |
372 | miny -= win_y + font_height; |
389 | miny -= win_y + font_height; |
373 | maxy -= win_y - font_height; |
390 | maxy -= win_y - font_height; |
374 | |
391 | |
… | |
… | |
376 | XClearArea (disp, root, win_x, win_y, width, height, False); |
393 | XClearArea (disp, root, win_x, win_y, width, height, False); |
377 | |
394 | |
378 | for (lin = listlen; lin--;) |
395 | for (lin = listlen; lin--;) |
379 | { |
396 | { |
380 | struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin); |
397 | struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin); |
|
|
398 | struct displaymatrix *display_line = display + lin; |
381 | |
399 | |
382 | offset -= font_height; |
400 | offset -= font_height; |
383 | |
401 | |
384 | if (offset < miny || offset > maxy) |
402 | if (offset < miny || offset > maxy) |
385 | continue; |
403 | continue; |
386 | |
404 | |
|
|
405 | /* if this line is a different than it was, then it |
|
|
406 | * needs displaying */ |
387 | if (clear && opt_noflicker) |
407 | if (!opt_noflicker |
388 | XClearArea (disp, root, win_x, win_y + offset - font_height, |
408 | || refresh_all |
389 | width + effect_x_space, font_height + effect_y_space, False); |
409 | || display_line->len != line->len |
390 | |
410 | || display_line->color != line->color |
391 | if (opt_outline) |
411 | || memcmp (display_line->line, line->line, line->len)) |
392 | { |
412 | { |
393 | int x, y; |
413 | /* don't bother updating the record of what has been |
|
|
414 | * displayed if -noflicker isn't in effect, since we redraw |
|
|
415 | * the whole display every time anyway */ |
|
|
416 | if (opt_noflicker) |
|
|
417 | { |
|
|
418 | /* update the record of what has been displayed; |
|
|
419 | * first make sure the buffer is big enough */ |
|
|
420 | if (display_line->buffer_size < line->len) |
|
|
421 | { |
|
|
422 | display_line->buffer_size = line->len; |
|
|
423 | display_line->line = xrealloc (display_line->line, display_line->buffer_size); |
|
|
424 | } |
|
|
425 | |
|
|
426 | display_line->len = line->len; |
|
|
427 | display_line->color = line->color; |
|
|
428 | memcpy (display_line->line, line->line, line->len); |
|
|
429 | |
|
|
430 | if (clear) |
|
|
431 | XClearArea (disp, root, win_x, win_y + offset - font_ascent, |
|
|
432 | width + effect_x_space, font_height + effect_y_space, False); |
|
|
433 | } |
|
|
434 | |
|
|
435 | if (opt_outline) |
|
|
436 | { |
|
|
437 | int x, y; |
394 | XSetForeground (disp, WinGC, black_color); |
438 | XSetForeground (disp, WinGC, black_color); |
395 | |
439 | |
396 | for (x = -1; x < 2; x += 2) |
440 | for (x = -1; x <= 1; x += 2) |
397 | for (y = -1; y < 2; y += 2) |
441 | for (y = -1; y <= 1; y += 2) |
398 | XmbDrawString (disp, root, fontset, WinGC, |
442 | XmbDrawString (disp, root, fontset, WinGC, |
399 | win_x + effect_x_offset + x, |
443 | win_x + effect_x_offset + x, |
400 | win_y + effect_y_offset + y + offset - font_height + font_ascent, |
444 | win_y + y + offset, |
401 | line->line, line->len); |
445 | line->line, line->len); |
402 | } |
446 | } |
403 | else if (opt_shade) |
447 | else if (opt_shade) |
404 | { |
448 | { |
405 | XSetForeground (disp, WinGC, black_color); |
449 | XSetForeground (disp, WinGC, black_color); |
|
|
450 | XmbDrawString (disp, root, fontset, WinGC, |
|
|
451 | win_x + effect_x_offset + SHADE_X, |
|
|
452 | win_y + offset + SHADE_Y, |
|
|
453 | line->line, line->len); |
|
|
454 | } |
|
|
455 | |
|
|
456 | XSetForeground (disp, WinGC, line->color); |
406 | XmbDrawString (disp, root, fontset, WinGC, |
457 | XmbDrawString (disp, root, fontset, WinGC, |
407 | win_x + effect_x_offset + SHADE_X, |
458 | win_x + effect_x_offset, |
408 | win_y + effect_y_offset + offset + SHADE_Y - font_height + font_ascent, |
459 | win_y + offset, |
409 | line->line, line->len); |
|
|
410 | } |
|
|
411 | |
|
|
412 | XSetForeground (disp, WinGC, line->color); |
|
|
413 | XmbDrawString (disp, root, fontset, WinGC, |
|
|
414 | win_x + effect_x_offset, |
|
|
415 | win_y + effect_y_offset + offset - font_height + font_ascent, |
|
|
416 | line->line, line->len); |
460 | line->line, line->len); |
|
|
461 | } |
417 | } |
462 | } |
418 | |
463 | |
419 | if (opt_frame) |
464 | if (opt_frame) |
420 | { |
465 | { |
421 | XSetForeground (disp, WinGC, GetColor (def_color)); |
466 | XSetForeground (disp, WinGC, GetColor (def_color)); |
… | |
… | |
446 | if (i == 0) |
491 | if (i == 0) |
447 | { /* matched */ |
492 | { /* matched */ |
448 | int match_start = matched[0].rm_so; |
493 | int match_start = matched[0].rm_so; |
449 | int match_end = matched[0].rm_eo; |
494 | int match_end = matched[0].rm_eo; |
450 | int old_len = match_end - match_start; |
495 | int old_len = match_end - match_start; |
451 | int new_len = strlen(transform_to); |
496 | int new_len = strlen (transform_to); |
452 | int old_whole_len = strlen(s); |
497 | int old_whole_len = strlen (s); |
|
|
498 | |
453 | printf("regexp was matched by '%s' - replace with '%s'\n", s, transform_to); |
499 | printf ("regexp was matched by '%s' - replace with '%s'\n", s, transform_to); |
454 | printf("match is from %d to %d\n", |
500 | printf ("match is from %d to %d\n", match_start, match_end); |
455 | match_start, match_end); |
|
|
456 | if (new_len > old_len) { |
501 | if (new_len > old_len) |
457 | s = realloc(s, old_whole_len + new_len - old_len); |
502 | s = xrealloc(s, old_whole_len + new_len - old_len); |
458 | } |
503 | |
459 | if (new_len != old_len) { |
504 | if (new_len != old_len) |
|
|
505 | { |
460 | memcpy(s + match_end + new_len - old_len, |
506 | memcpy(s + match_end + new_len - old_len, |
461 | s + match_end, |
507 | s + match_end, |
462 | old_whole_len - match_end); |
508 | old_whole_len - match_end); |
463 | s[old_whole_len + new_len - old_len] = '\0'; |
509 | s[old_whole_len + new_len - old_len] = '\0'; |
464 | } |
510 | } |
|
|
511 | |
465 | memcpy(s + match_start, |
512 | memcpy (s + match_start, |
466 | transform_to, |
513 | transform_to, |
467 | new_len); |
514 | new_len); |
468 | printf("transformed to '%s'\n", s); |
515 | printf ("transformed to '%s'\n", s); |
469 | } |
516 | } |
470 | else |
517 | else |
471 | { |
518 | { |
472 | printf("regexp was not matched by '%s'\n", s); |
519 | printf ("regexp was not matched by '%s'\n", s); |
473 | } |
520 | } |
474 | } |
521 | } |
475 | } |
522 | } |
476 | #endif |
523 | #endif |
477 | |
524 | |
… | |
… | |
488 | |
535 | |
489 | return r; |
536 | return r; |
490 | } |
537 | } |
491 | |
538 | |
492 | /* |
539 | /* |
493 | * This routine should read a single line, no matter how long. |
540 | * This routine can read a line of any length if it is called enough times. |
494 | */ |
541 | */ |
495 | int |
542 | int |
496 | lineinput (struct logfile_entry *logfile) |
543 | lineinput (struct logfile_entry *logfile) |
497 | { |
544 | { |
498 | char buff[1024], *p = buff; |
545 | char buff[1024], *p; |
499 | int ch; |
546 | int ch; |
500 | /* HACK this - to add on the length of any partial line which we will be appending to */ |
547 | /* HACK-2: add on the length of any partial line which we will be appending to */ |
501 | int ofs = logfile->buf ? strlen (logfile->buf) : 0; |
548 | int ofs = logfile->buf ? strlen (logfile->buf) : 0; |
502 | |
549 | |
|
|
550 | /* this loop ensures that the whole line is read, even if it's |
|
|
551 | * longer than the buffer. we need to do this because when --whole |
|
|
552 | * is in effect we don't know whether to display the line or not |
|
|
553 | * until we've seen how (ie. whether) it ends */ |
503 | do |
554 | do |
504 | { |
555 | { |
|
|
556 | p = buff; |
|
|
557 | do |
|
|
558 | { |
505 | ch = fgetc (logfile->fp); |
559 | ch = fgetc (logfile->fp); |
506 | |
560 | |
507 | if (ch == '\n' || ch == EOF) |
561 | if (ch == '\n' || ch == EOF) |
508 | break; |
562 | break; |
509 | else if (ch == '\r') |
563 | else if (ch == '\r') |
510 | continue; /* skip */ |
564 | continue; /* skip */ |
511 | else if (ch == '\t') |
565 | else if (ch == '\t') |
512 | { |
566 | { |
513 | do |
567 | do |
514 | { |
568 | { |
515 | *p++ = ' '; |
569 | *p++ = ' '; |
516 | ofs++; |
570 | ofs++; |
517 | } |
571 | } |
518 | while (ofs & 7); |
572 | while (ofs & 7); |
519 | } |
|
|
520 | else |
|
|
521 | { |
|
|
522 | *p++ = ch; |
|
|
523 | ofs++; |
|
|
524 | } |
|
|
525 | } |
573 | } |
|
|
574 | else |
|
|
575 | { |
|
|
576 | *p++ = ch; |
|
|
577 | ofs++; |
|
|
578 | } |
|
|
579 | } |
526 | while (p < buff + (sizeof buff) - 8 - 1); |
580 | while (p < buff + (sizeof buff) - 8 - 1); |
527 | |
581 | |
528 | if (p == buff && ch == EOF) |
582 | if (p == buff && ch == EOF) |
529 | return 0; |
583 | return 0; |
530 | |
584 | |
531 | *p = 0; |
585 | *p = 0; |
532 | |
586 | |
533 | p = concat_line (logfile->buf, buff); |
587 | p = concat_line (logfile->buf, buff); |
534 | free (logfile->buf); logfile->buf = p; |
588 | free (logfile->buf); logfile->buf = p; |
|
|
589 | } |
|
|
590 | while (ch != '\n' && ch != EOF); |
535 | |
591 | |
536 | logfile->lastpartial = logfile->partial; |
592 | logfile->lastpartial = logfile->partial; |
537 | /* there are 3 ways we could have exited the loop: reading '\n', |
593 | /* there are 3 ways we could have exited the loop: reading '\n', |
538 | * reaching EOF, or filling the buffer; the 2nd and 3rd of these |
594 | * reaching EOF, or filling the buffer; the 2nd and 3rd of these |
539 | * both result in a partial line */ |
595 | * both result in a partial line */ |
… | |
… | |
618 | sleep (1); |
674 | sleep (1); |
619 | if (e->fp) |
675 | if (e->fp) |
620 | fclose (e->fp); |
676 | fclose (e->fp); |
621 | if (openlog (e) == NULL) |
677 | if (openlog (e) == NULL) |
622 | continue; |
678 | continue; |
|
|
679 | if (fstat (fileno (e->fp), &stats) < 0) |
|
|
680 | continue; |
623 | } |
681 | } |
624 | |
682 | |
625 | /* HACK this - stats can be uninitialised here (if the file |
|
|
626 | * didn't exist when stat() was called, but was recreated during |
|
|
627 | * the sleep(1)) */ |
|
|
628 | if (stats.st_ino != e->inode) |
683 | if (stats.st_ino != e->inode) |
629 | { /* file renamed? */ |
684 | { /* file renamed? */ |
630 | if (e->fp) |
685 | if (e->fp) |
631 | fclose (e->fp); |
686 | fclose (e->fp); |
632 | if (openlog (e) == NULL) |
687 | if (openlog (e) == NULL) |
|
|
688 | continue; |
|
|
689 | if (fstat (fileno (e->fp), &stats) < 0) |
633 | continue; |
690 | continue; |
634 | } |
691 | } |
635 | |
692 | |
636 | if (stats.st_size < e->last_size) |
693 | if (stats.st_size < e->last_size) |
637 | { /* file truncated? */ |
694 | { /* file truncated? */ |
… | |
… | |
673 | struct logfile_entry *current; |
730 | struct logfile_entry *current; |
674 | |
731 | |
675 | for (cur_line = idx; cur_line > 0; cur_line--) |
732 | for (cur_line = idx; cur_line > 0; cur_line--) |
676 | lines[cur_line] = lines[cur_line - 1]; |
733 | lines[cur_line] = lines[cur_line - 1]; |
677 | |
734 | |
678 | lines[0].line = strdup ("~"); |
735 | lines[0].line = xstrdup ("~"); |
679 | |
736 | |
680 | for (current = loglist; current; current = current->next) |
737 | for (current = loglist; current; current = current->next) |
681 | if (current->index >= 0 && current->index <= idx) |
738 | if (current->index >= 0 && current->index <= idx) |
682 | current->index++; |
739 | current->index++; |
683 | } |
740 | } |
… | |
… | |
689 | */ |
746 | */ |
690 | static void |
747 | static void |
691 | split_line (int idx, const char *str, unsigned long color) |
748 | split_line (int idx, const char *str, unsigned long color) |
692 | { |
749 | { |
693 | int l = strlen (str); |
750 | int l = strlen (str); |
|
|
751 | int last_wrapped = 0; |
694 | const char *p = str; |
752 | const char *p = str; |
|
|
753 | static int continuation_width = -1; |
|
|
754 | static int continuation_length; |
|
|
755 | |
|
|
756 | /* only calculate the continuation's width once */ |
|
|
757 | if (continuation_width == -1) |
|
|
758 | { |
|
|
759 | continuation_length = strlen (continuation); |
|
|
760 | continuation_width = XmbTextEscapement (fontset, continuation, continuation_length); |
|
|
761 | } |
695 | |
762 | |
696 | do |
763 | do |
697 | { |
764 | { |
698 | const char *beg = p; |
765 | const char *beg = p; |
|
|
766 | int w = last_wrapped ? continuation_width : 0; |
699 | int w = 0, wrapped = 0; |
767 | int wrapped = 0; |
700 | const char *break_p = NULL; |
768 | const char *break_p = NULL; |
701 | |
769 | |
702 | while (*p) |
770 | while (*p) |
703 | { |
771 | { |
|
|
772 | int cw, len; |
|
|
773 | |
704 | /* find the length in bytes of the next multibyte character */ |
774 | /* find the length in bytes of the next multibyte character */ |
705 | int len = mblen (p, l); |
775 | len = mblen (p, l); |
706 | if (len <= 0) |
776 | if (len <= 0) |
707 | len = 1; /* ignore (don't skip) illegal character sequences */ |
777 | len = 1; /* ignore (don't skip) illegal character sequences */ |
708 | |
778 | |
709 | /* find the width in pixels of the next character */ |
779 | /* find the width in pixels of the next character */ |
710 | int cw = XmbTextEscapement (fontset, p, len); |
780 | cw = XmbTextEscapement (fontset, p, len); |
711 | if (cw + w > width - effect_x_space) |
781 | if (cw + w > width - effect_x_space) |
712 | { |
782 | { |
|
|
783 | if (p == beg) |
|
|
784 | { |
|
|
785 | fprintf (stderr, "we can't even fit a single character onto the line\n"); |
|
|
786 | if (len == 1) fprintf (stderr, "(the character we couldn't fit was '%c')\n", *p); |
|
|
787 | exit (1); |
|
|
788 | } |
|
|
789 | |
713 | wrapped = 1; |
790 | wrapped = 1; |
714 | break; |
791 | break; |
715 | } |
792 | } |
716 | |
793 | |
717 | if (opt_wordwrap && len == 1 && p[0] == ' ') |
794 | if (opt_wordwrap && len == 1 && p[0] == ' ') |
… | |
… | |
730 | l += p - break_p; |
807 | l += p - break_p; |
731 | p = break_p; |
808 | p = break_p; |
732 | } |
809 | } |
733 | |
810 | |
734 | { |
811 | { |
|
|
812 | int len = p - beg + (last_wrapped ? continuation_length : 0); |
735 | char *s = xmalloc (p - beg + 1); |
813 | char *s = xmalloc (len + 1); |
736 | memcpy (s, beg, p - beg); |
814 | if (last_wrapped) |
|
|
815 | { |
|
|
816 | memcpy (s, continuation, continuation_length); |
|
|
817 | memcpy (s + continuation_length, beg, p - beg); |
|
|
818 | } |
|
|
819 | else |
|
|
820 | memcpy (s, beg, len); |
|
|
821 | |
737 | s[p - beg] = 0; |
822 | s[len] = 0; |
738 | insert_line (idx); |
823 | insert_line (idx); |
739 | lines[idx].line = s; |
824 | lines[idx].line = s; |
740 | lines[idx].len = p - beg; |
825 | lines[idx].len = len; |
741 | lines[idx].color = color; |
826 | lines[idx].color = color; |
742 | } |
827 | } |
743 | |
828 | |
744 | /* if we wrapped at a space, don't display the space */ |
829 | /* if we wrapped at a space, don't display the space */ |
745 | if (opt_wordwrap && wrapped && break_p && break_p != beg) |
830 | if (opt_wordwrap && wrapped && break_p && break_p != beg) |
746 | { |
831 | { |
747 | l--; |
832 | l--; |
748 | p++; |
833 | p++; |
749 | } |
834 | } |
|
|
835 | |
|
|
836 | last_wrapped = wrapped; |
750 | } |
837 | } |
751 | while (l); |
838 | while (l); |
752 | } |
839 | } |
753 | |
840 | |
754 | /* |
841 | /* |
… | |
… | |
770 | } |
857 | } |
771 | |
858 | |
772 | static void |
859 | static void |
773 | main_loop (void) |
860 | main_loop (void) |
774 | { |
861 | { |
775 | lines = xmalloc (sizeof (struct linematrix) * listlen); |
|
|
776 | int lin; |
862 | int lin; |
777 | time_t lastreload; |
863 | time_t lastreload; |
778 | Region region = XCreateRegion (); |
864 | Region region = XCreateRegion (); |
779 | XEvent xev; |
865 | XEvent xev; |
780 | struct logfile_entry *lastprinted = NULL; |
866 | struct logfile_entry *lastprinted = NULL; |
781 | struct logfile_entry *current; |
867 | struct logfile_entry *current; |
782 | int need_update = 1; |
868 | int need_update = 1; |
783 | |
869 | |
|
|
870 | lines = xmalloc (sizeof (struct linematrix) * listlen); |
|
|
871 | display = xmalloc (sizeof (struct displaymatrix) * listlen); |
|
|
872 | |
784 | lastreload = time (NULL); |
873 | lastreload = time (NULL); |
785 | |
874 | |
786 | /* Initialize linematrix */ |
875 | /* Initialize linematrix */ |
787 | for (lin = 0; lin < listlen; lin++) |
876 | for (lin = 0; lin < listlen; lin++) |
788 | { |
877 | { |
789 | lines[lin].line = strdup ("~"); |
878 | lines[lin].line = xstrdup ("~"); |
790 | lines[lin].len = 1; |
879 | lines[lin].len = 1; |
|
|
880 | display[lin].line = xstrdup(""); |
|
|
881 | display[lin].len = 0; |
|
|
882 | display[lin].buffer_size = 0; |
791 | lines[lin].color = GetColor (def_color); |
883 | lines[lin].color = GetColor (def_color); |
792 | } |
884 | } |
793 | |
885 | |
794 | for (;;) |
886 | for (;;) |
795 | { |
887 | { |
… | |
… | |
820 | |
912 | |
821 | /* print filename if any, and if last line was from |
913 | /* print filename if any, and if last line was from |
822 | * different file */ |
914 | * different file */ |
823 | if (!opt_nofilename && lastprinted != current && current->desc[0]) |
915 | if (!opt_nofilename && lastprinted != current && current->desc[0]) |
824 | { |
916 | { |
825 | char buf[1024]; /* HACK */ |
|
|
826 | snprintf (buf, sizeof (buf), "[%s]", current->desc); |
|
|
827 | split_line (listlen - 1, buf, current->color); |
917 | split_line (listlen - 1, "[", current->color); |
|
|
918 | append_line (listlen - 1, current->desc); |
|
|
919 | append_line (listlen - 1, "]"); |
828 | } |
920 | } |
829 | |
921 | |
830 | /* if this is the same file we showed last, and the |
922 | /* if we're dealing with partial lines, and the last |
831 | * last time we showed it, it wasn't finished, then |
923 | * time we showed the line it wasn't finished ... */ |
832 | * append to the last line shown */ |
|
|
833 | if (lastprinted == current && current->lastpartial) |
|
|
834 | append_line (listlen - 1, current->buf); |
|
|
835 | else if (current->lastpartial) |
924 | if (!opt_whole && current->lastpartial) |
836 | { |
925 | { |
|
|
926 | /* if this is the same file we showed last then |
|
|
927 | append to the last line shown */ |
|
|
928 | if (lastprinted == current) |
|
|
929 | append_line (listlen - 1, current->buf); |
|
|
930 | else |
|
|
931 | { |
|
|
932 | /* but if a different file has been shown in the |
|
|
933 | * mean time, make a new line, starting with the |
|
|
934 | * continuation string */ |
837 | split_line (listlen - 1, continuation, current->color); |
935 | split_line (listlen - 1, continuation, current->color); |
838 | append_line (listlen - 1, current->buf); |
936 | append_line (listlen - 1, current->buf); |
|
|
937 | } |
839 | } |
938 | } |
840 | else |
939 | else |
|
|
940 | /* otherwise just make a plain and simple new line */ |
841 | split_line (listlen - 1, current->buf, current->color); |
941 | split_line (listlen - 1, current->buf, current->color); |
842 | |
942 | |
843 | free (current->buf), current->buf = 0; |
943 | free (current->buf), current->buf = 0; |
844 | current->index = listlen - 1; |
944 | current->index = listlen - 1; |
845 | lastprinted = current; |
945 | lastprinted = current; |
846 | } |
946 | } |
847 | } |
947 | } |
848 | |
948 | |
849 | if (need_update) |
949 | if (need_update) |
850 | { |
950 | { |
851 | redraw (); |
951 | redraw (0); |
852 | need_update = 0; |
952 | need_update = 0; |
853 | } |
953 | } |
854 | else |
954 | else |
855 | { |
955 | { |
856 | XFlush (disp); |
956 | XFlush (disp); |
… | |
… | |
913 | XRectangle r; |
1013 | XRectangle r; |
914 | |
1014 | |
915 | XSetRegion (disp, WinGC, region); |
1015 | XSetRegion (disp, WinGC, region); |
916 | XClipBox (region, &r); |
1016 | XClipBox (region, &r); |
917 | |
1017 | |
918 | refresh (r.y, r.y + r.height, 0); |
1018 | refresh (r.y, r.y + r.height, 0, 1); |
919 | |
1019 | |
920 | XDestroyRegion (region); |
1020 | XDestroyRegion (region); |
921 | region = XCreateRegion (); |
1021 | region = XCreateRegion (); |
922 | } |
1022 | } |
923 | } |
1023 | } |
… | |
… | |
1050 | { |
1150 | { |
1051 | if ((e->fp = fdopen (0, "r")) == NULL) |
1151 | if ((e->fp = fdopen (0, "r")) == NULL) |
1052 | perror ("fdopen"), exit (1); |
1152 | perror ("fdopen"), exit (1); |
1053 | if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) |
1153 | if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) |
1054 | perror ("fcntl"), exit (1); |
1154 | perror ("fcntl"), exit (1); |
|
|
1155 | |
1055 | e->fname = NULL; |
1156 | e->fname = NULL; |
1056 | e->inode = 0; |
1157 | e->inode = 0; |
1057 | e->desc = xstrdup ("stdin"); |
1158 | e->desc = xstrdup ("stdin"); |
1058 | } |
1159 | } |
1059 | else |
1160 | else |
1060 | { |
1161 | { |
1061 | int l; |
|
|
1062 | |
|
|
1063 | e->fname = xstrdup (fname); |
1162 | e->fname = xstrdup (fname); |
|
|
1163 | |
1064 | if (openlog (e) == NULL) |
1164 | if (openlog (e) == NULL) |
1065 | perror (fname), exit (1); |
1165 | perror (fname), exit (1); |
1066 | |
1166 | |
1067 | l = strlen (desc); |
1167 | e->desc = xstrdup (desc); |
1068 | /* HACK on this - width is in pixels now */ |
|
|
1069 | if (l > width - 2) /* must account for [ ] */ |
|
|
1070 | l = width - 2; |
|
|
1071 | e->desc = xmalloc (l + 1); |
|
|
1072 | memcpy (e->desc, desc, l); |
|
|
1073 | *(e->desc + l) = '\0'; |
|
|
1074 | } |
1168 | } |
1075 | |
1169 | |
1076 | e->color = GetColor (fcolor); |
1170 | e->color = GetColor (fcolor); |
1077 | e->partial = 0; |
1171 | e->partial = 0; |
1078 | e->next = NULL; |
1172 | e->next = NULL; |
1079 | |
1173 | |
1080 | if (!loglist) |
1174 | if (!loglist) |
1081 | loglist = e; |
1175 | loglist = e; |
1082 | if (loglist_tail) |
1176 | if (loglist_tail) |
1083 | loglist_tail->next = e; |
1177 | loglist_tail->next = e; |
|
|
1178 | |
1084 | loglist_tail = e; |
1179 | loglist_tail = e; |
1085 | } |
1180 | } |
1086 | } |
1181 | } |
1087 | |
1182 | |
1088 | if (!loglist) |
1183 | if (!loglist) |
… | |
… | |
1090 | fprintf (stderr, "You did not specify any files to tail\n" |
1185 | fprintf (stderr, "You did not specify any files to tail\n" |
1091 | "use %s --help for help\n", argv[0]); |
1186 | "use %s --help for help\n", argv[0]); |
1092 | exit (1); |
1187 | exit (1); |
1093 | } |
1188 | } |
1094 | |
1189 | |
|
|
1190 | if (opt_update && opt_whole) |
|
|
1191 | { |
|
|
1192 | fprintf (stderr, "Specify at most one of -update and -whole\n"); |
|
|
1193 | exit (1); |
|
|
1194 | } |
1095 | if (opt_partial && opt_whole) |
1195 | else if (opt_partial && opt_whole) |
1096 | { |
1196 | { |
1097 | fprintf (stderr, "Specify at most one of -partial and -whole\n"); |
1197 | fprintf (stderr, "Specify at most one of -partial and -whole\n"); |
1098 | exit (1); |
1198 | exit (1); |
1099 | } |
1199 | } |
1100 | |
1200 | |
1101 | /* HACK this - do we want to allow both -shade and -outline? */ |
1201 | /* HACK-7: do we want to allow both -shade and -outline? */ |
1102 | if (opt_shade && opt_outline) |
1202 | if (opt_shade && opt_outline) |
1103 | { |
1203 | { |
1104 | fprintf (stderr, "Specify at most one of -shade and -outline\n"); |
1204 | fprintf (stderr, "Specify at most one of -shade and -outline\n"); |
1105 | exit (1); |
1205 | exit (1); |
1106 | } |
1206 | } |
1107 | |
1207 | |
1108 | if (opt_partial) |
1208 | if (opt_partial) |
1109 | /* if we specifically requested to see partial lines then don't insist on whole lines */ |
1209 | /* if we specifically requested to see partial lines then don't insist on whole lines */ |
1110 | opt_whole = 0; |
1210 | opt_whole = 0; |
1111 | else if (file_count > 1) |
1211 | else if (file_count > 1) |
1112 | /* otherwise, if we've viewing multiple files, default to showing whole lines */ |
1212 | /* otherwise, if we're viewing multiple files, default to showing whole lines */ |
1113 | opt_whole = 1; |
1213 | opt_whole = 1; |
1114 | |
1214 | |
1115 | #if HAS_REGEX |
1215 | #if HAS_REGEX |
1116 | if (transform) |
1216 | if (transform) |
1117 | { |
1217 | { |
… | |
… | |
1169 | { |
1269 | { |
1170 | void *p; |
1270 | void *p; |
1171 | |
1271 | |
1172 | while ((p = strdup (string)) == NULL) |
1272 | while ((p = strdup (string)) == NULL) |
1173 | { |
1273 | { |
1174 | fprintf (stderr, "Memory exausted."); |
1274 | fprintf (stderr, "Memory exhausted in xstrdup().\n"); |
1175 | sleep (10); |
1275 | sleep (10); |
1176 | } |
1276 | } |
1177 | |
1277 | |
1178 | return p; |
1278 | return p; |
1179 | } |
1279 | } |
… | |
… | |
1183 | { |
1283 | { |
1184 | void *p; |
1284 | void *p; |
1185 | |
1285 | |
1186 | while ((p = malloc (size)) == NULL) |
1286 | while ((p = malloc (size)) == NULL) |
1187 | { |
1287 | { |
1188 | fprintf (stderr, "Memory exausted."); |
1288 | fprintf (stderr, "Memory exhausted in xmalloc().\n"); |
|
|
1289 | sleep (10); |
|
|
1290 | } |
|
|
1291 | |
|
|
1292 | return p; |
|
|
1293 | } |
|
|
1294 | |
|
|
1295 | void * |
|
|
1296 | xrealloc (void *ptr, size_t size) |
|
|
1297 | { |
|
|
1298 | void *p; |
|
|
1299 | |
|
|
1300 | while ((p = realloc (ptr, size)) == NULL) |
|
|
1301 | { |
|
|
1302 | fprintf (stderr, "Memory exhausted in xrealloc().\n"); |
1189 | sleep (10); |
1303 | sleep (10); |
1190 | } |
1304 | } |
1191 | |
1305 | |
1192 | return p; |
1306 | return p; |
1193 | } |
1307 | } |
… | |
… | |
1215 | " startup\n" |
1329 | " startup\n" |
1216 | " -i | -interval seconds interval between checks (fractional\n" |
1330 | " -i | -interval seconds interval between checks (fractional\n" |
1217 | " values o.k.). Default 2.4 seconds\n" |
1331 | " values o.k.). Default 2.4 seconds\n" |
1218 | " -V display version information and exit\n" |
1332 | " -V display version information and exit\n" |
1219 | "\n"); |
1333 | "\n"); |
1220 | printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green " |
1334 | printf ("Example:\n%s -g 800x250+100+50 -font fixed /var/log/messages,green " |
1221 | "/var/log/secure,red,'ALERT'\n", myname); |
1335 | "/var/log/secure,red,'ALERT'\n", myname); |
1222 | exit (0); |
1336 | exit (0); |
1223 | } |
1337 | } |
1224 | |
1338 | |
1225 | void |
1339 | void |
… | |
… | |
1239 | case -1: |
1353 | case -1: |
1240 | return -1; |
1354 | return -1; |
1241 | case 0: |
1355 | case 0: |
1242 | break; |
1356 | break; |
1243 | default: |
1357 | default: |
1244 | printf("%d\n", pid); |
1358 | /*printf("%d\n", pid);*/ |
1245 | exit (0); |
1359 | exit (0); |
1246 | } |
1360 | } |
1247 | |
1361 | |
1248 | if (setsid () == -1) |
1362 | if (setsid () == -1) |
1249 | return -1; |
1363 | return -1; |