… | |
… | |
75 | struct displaymatrix |
75 | struct displaymatrix |
76 | { |
76 | { |
77 | char *line; |
77 | char *line; |
78 | int len; |
78 | int len; |
79 | int buffer_size; |
79 | int buffer_size; |
|
|
80 | unsigned long color; |
80 | }; |
81 | }; |
81 | |
82 | |
82 | /* global variables */ |
83 | /* global variables */ |
83 | struct linematrix *lines; |
84 | struct linematrix *lines; |
84 | struct displaymatrix *display; |
85 | struct displaymatrix *display; |
… | |
… | |
404 | /* if this line is a different than it was, then it |
405 | /* if this line is a different than it was, then it |
405 | * needs displaying */ |
406 | * needs displaying */ |
406 | if (!opt_noflicker |
407 | if (!opt_noflicker |
407 | || refresh_all |
408 | || refresh_all |
408 | || display_line->len != line->len |
409 | || display_line->len != line->len |
|
|
410 | || display_line->color != line->color |
409 | || memcmp (display_line->line, line->line, line->len)) |
411 | || memcmp (display_line->line, line->line, line->len)) |
410 | { |
412 | { |
411 | /* don't bother updating the record of what has been |
413 | /* don't bother updating the record of what has been |
412 | * displayed if -noflicker isn't in effect, since we redraw |
414 | * displayed if -noflicker isn't in effect, since we redraw |
413 | * the whole display every time anyway */ |
415 | * the whole display every time anyway */ |
414 | if (opt_noflicker) |
416 | if (opt_noflicker) |
415 | { |
417 | { |
416 | /* update the record of what has been displayed; |
418 | /* update the record of what has been displayed; |
417 | * first make sure the buffer is big enough */ |
419 | * first make sure the buffer is big enough */ |
418 | if (display_line->buffer_size <= line->len) |
420 | if (display_line->buffer_size < line->len) |
419 | { |
421 | { |
420 | display_line->buffer_size = line->len + 1; |
422 | display_line->buffer_size = line->len; |
421 | display_line->line = xrealloc (display_line->line, display_line->buffer_size); |
423 | display_line->line = xrealloc (display_line->line, display_line->buffer_size); |
422 | } |
424 | } |
423 | |
425 | |
424 | display_line->len = line->len; |
426 | display_line->len = line->len; |
|
|
427 | display_line->color = line->color; |
425 | memcpy (display_line->line, line->line, line->len); |
428 | memcpy (display_line->line, line->line, line->len); |
426 | |
429 | |
427 | if (clear) |
430 | if (clear) |
428 | XClearArea (disp, root, win_x, win_y + offset - font_ascent, |
431 | XClearArea (disp, root, win_x, win_y + offset - font_ascent, |
429 | width + effect_x_space, font_height + effect_y_space, False); |
432 | width + effect_x_space, font_height + effect_y_space, False); |
… | |
… | |
432 | if (opt_outline) |
435 | if (opt_outline) |
433 | { |
436 | { |
434 | int x, y; |
437 | int x, y; |
435 | XSetForeground (disp, WinGC, black_color); |
438 | XSetForeground (disp, WinGC, black_color); |
436 | |
439 | |
437 | for (x = -1; x < 2; x += 2) |
440 | for (x = -1; x <= 1; x += 2) |
438 | for (y = -1; y < 2; y += 2) |
441 | for (y = -1; y <= 1; y += 2) |
439 | XmbDrawString (disp, root, fontset, WinGC, |
442 | XmbDrawString (disp, root, fontset, WinGC, |
440 | win_x + effect_x_offset + x, |
443 | win_x + effect_x_offset + x, |
441 | win_y + y + offset, |
444 | win_y + y + offset, |
442 | line->line, line->len); |
445 | line->line, line->len); |
443 | } |
446 | } |
… | |
… | |
488 | if (i == 0) |
491 | if (i == 0) |
489 | { /* matched */ |
492 | { /* matched */ |
490 | int match_start = matched[0].rm_so; |
493 | int match_start = matched[0].rm_so; |
491 | int match_end = matched[0].rm_eo; |
494 | int match_end = matched[0].rm_eo; |
492 | int old_len = match_end - match_start; |
495 | int old_len = match_end - match_start; |
493 | int new_len = strlen(transform_to); |
496 | int new_len = strlen (transform_to); |
494 | int old_whole_len = strlen(s); |
497 | int old_whole_len = strlen (s); |
|
|
498 | |
495 | 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); |
496 | printf("match is from %d to %d\n", |
500 | printf ("match is from %d to %d\n", match_start, match_end); |
497 | match_start, match_end); |
|
|
498 | if (new_len > old_len) { |
501 | if (new_len > old_len) |
499 | s = xrealloc(s, old_whole_len + new_len - old_len); |
502 | s = xrealloc(s, old_whole_len + new_len - old_len); |
500 | } |
503 | |
501 | if (new_len != old_len) { |
504 | if (new_len != old_len) |
|
|
505 | { |
502 | memcpy(s + match_end + new_len - old_len, |
506 | memcpy(s + match_end + new_len - old_len, |
503 | s + match_end, |
507 | s + match_end, |
504 | old_whole_len - match_end); |
508 | old_whole_len - match_end); |
505 | s[old_whole_len + new_len - old_len] = '\0'; |
509 | s[old_whole_len + new_len - old_len] = '\0'; |
506 | } |
510 | } |
|
|
511 | |
507 | memcpy(s + match_start, |
512 | memcpy (s + match_start, |
508 | transform_to, |
513 | transform_to, |
509 | new_len); |
514 | new_len); |
510 | printf("transformed to '%s'\n", s); |
515 | printf ("transformed to '%s'\n", s); |
511 | } |
516 | } |
512 | else |
517 | else |
513 | { |
518 | { |
514 | printf("regexp was not matched by '%s'\n", s); |
519 | printf ("regexp was not matched by '%s'\n", s); |
515 | } |
520 | } |
516 | } |
521 | } |
517 | } |
522 | } |
518 | #endif |
523 | #endif |
519 | |
524 | |
… | |
… | |
530 | |
535 | |
531 | return r; |
536 | return r; |
532 | } |
537 | } |
533 | |
538 | |
534 | /* |
539 | /* |
535 | * HACK-1: 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. |
536 | */ |
541 | */ |
537 | int |
542 | int |
538 | lineinput (struct logfile_entry *logfile) |
543 | lineinput (struct logfile_entry *logfile) |
539 | { |
544 | { |
540 | char buff[1024], *p = buff; |
545 | char buff[1024], *p; |
541 | int ch; |
546 | int ch; |
542 | /* HACK-2: 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 */ |
543 | int ofs = logfile->buf ? strlen (logfile->buf) : 0; |
548 | int ofs = logfile->buf ? strlen (logfile->buf) : 0; |
544 | |
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 */ |
545 | do |
554 | do |
546 | { |
555 | { |
|
|
556 | p = buff; |
|
|
557 | do |
|
|
558 | { |
547 | ch = fgetc (logfile->fp); |
559 | ch = fgetc (logfile->fp); |
548 | |
560 | |
549 | if (ch == '\n' || ch == EOF) |
561 | if (ch == '\n' || ch == EOF) |
550 | break; |
562 | break; |
551 | else if (ch == '\r') |
563 | else if (ch == '\r') |
552 | continue; /* skip */ |
564 | continue; /* skip */ |
553 | else if (ch == '\t') |
565 | else if (ch == '\t') |
554 | { |
566 | { |
555 | do |
567 | do |
556 | { |
568 | { |
557 | *p++ = ' '; |
569 | *p++ = ' '; |
558 | ofs++; |
570 | ofs++; |
559 | } |
571 | } |
560 | while (ofs & 7); |
572 | while (ofs & 7); |
561 | } |
|
|
562 | else |
|
|
563 | { |
|
|
564 | *p++ = ch; |
|
|
565 | ofs++; |
|
|
566 | } |
|
|
567 | } |
573 | } |
|
|
574 | else |
|
|
575 | { |
|
|
576 | *p++ = ch; |
|
|
577 | ofs++; |
|
|
578 | } |
|
|
579 | } |
568 | while (p < buff + (sizeof buff) - 8 - 1); |
580 | while (p < buff + (sizeof buff) - 8 - 1); |
569 | |
581 | |
570 | if (p == buff && ch == EOF) |
582 | if (p == buff && ch == EOF) |
571 | return 0; |
583 | return 0; |
572 | |
584 | |
573 | *p = 0; |
585 | *p = 0; |
574 | |
586 | |
575 | p = concat_line (logfile->buf, buff); |
587 | p = concat_line (logfile->buf, buff); |
576 | free (logfile->buf); logfile->buf = p; |
588 | free (logfile->buf); logfile->buf = p; |
|
|
589 | } |
|
|
590 | while (ch != '\n' && ch != EOF); |
577 | |
591 | |
578 | logfile->lastpartial = logfile->partial; |
592 | logfile->lastpartial = logfile->partial; |
579 | /* 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', |
580 | * 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 |
581 | * both result in a partial line */ |
595 | * both result in a partial line */ |
… | |
… | |
670 | { /* file renamed? */ |
684 | { /* file renamed? */ |
671 | if (e->fp) |
685 | if (e->fp) |
672 | fclose (e->fp); |
686 | fclose (e->fp); |
673 | if (openlog (e) == NULL) |
687 | if (openlog (e) == NULL) |
674 | continue; |
688 | continue; |
|
|
689 | if (fstat (fileno (e->fp), &stats) < 0) |
|
|
690 | continue; |
675 | } |
691 | } |
676 | |
692 | |
677 | if (stats.st_size < e->last_size) |
693 | if (stats.st_size < e->last_size) |
678 | { /* file truncated? */ |
694 | { /* file truncated? */ |
679 | fseek (e->fp, 0, SEEK_SET); |
695 | fseek (e->fp, 0, SEEK_SET); |
… | |
… | |
738 | static int continuation_length; |
754 | static int continuation_length; |
739 | |
755 | |
740 | /* only calculate the continuation's width once */ |
756 | /* only calculate the continuation's width once */ |
741 | if (continuation_width == -1) |
757 | if (continuation_width == -1) |
742 | { |
758 | { |
743 | continuation_length = strlen(continuation); |
759 | continuation_length = strlen (continuation); |
744 | continuation_width = XmbTextEscapement (fontset, continuation, continuation_length); |
760 | continuation_width = XmbTextEscapement (fontset, continuation, continuation_length); |
745 | } |
761 | } |
746 | |
762 | |
747 | do |
763 | do |
748 | { |
764 | { |
… | |
… | |
751 | int wrapped = 0; |
767 | int wrapped = 0; |
752 | const char *break_p = NULL; |
768 | const char *break_p = NULL; |
753 | |
769 | |
754 | while (*p) |
770 | while (*p) |
755 | { |
771 | { |
|
|
772 | int cw, len; |
|
|
773 | |
756 | /* find the length in bytes of the next multibyte character */ |
774 | /* find the length in bytes of the next multibyte character */ |
757 | int len = mblen (p, l); |
775 | len = mblen (p, l); |
758 | if (len <= 0) |
776 | if (len <= 0) |
759 | len = 1; /* ignore (don't skip) illegal character sequences */ |
777 | len = 1; /* ignore (don't skip) illegal character sequences */ |
760 | |
778 | |
761 | /* find the width in pixels of the next character */ |
779 | /* find the width in pixels of the next character */ |
762 | int cw = XmbTextEscapement (fontset, p, len); |
780 | cw = XmbTextEscapement (fontset, p, len); |
763 | if (cw + w > width - effect_x_space) |
781 | if (cw + w > width - effect_x_space) |
764 | { |
782 | { |
765 | if (p == beg) |
783 | if (p == beg) |
766 | { |
784 | { |
767 | fprintf(stderr, "we can't even fit a single character onto the line\n"); |
785 | fprintf (stderr, "we can't even fit a single character onto the line\n"); |
768 | if (len == 1) fprintf(stderr, "(the character we couldn't fit was '%c')\n", *p); |
786 | if (len == 1) fprintf (stderr, "(the character we couldn't fit was '%c')\n", *p); |
769 | exit(1); |
787 | exit (1); |
770 | } |
788 | } |
771 | |
789 | |
772 | wrapped = 1; |
790 | wrapped = 1; |
773 | break; |
791 | break; |
774 | } |
792 | } |
… | |
… | |
789 | l += p - break_p; |
807 | l += p - break_p; |
790 | p = break_p; |
808 | p = break_p; |
791 | } |
809 | } |
792 | |
810 | |
793 | { |
811 | { |
794 | /* HACK-4 - consider inserting the 'continuation string' |
|
|
795 | * before the rest of the wrapped line */ |
|
|
796 | int len = p - beg + (last_wrapped ? continuation_length : 0); |
812 | int len = p - beg + (last_wrapped ? continuation_length : 0); |
797 | char *s = xmalloc (len + 1); |
813 | char *s = xmalloc (len + 1); |
798 | if (last_wrapped) |
814 | if (last_wrapped) |
799 | { |
815 | { |
800 | memcpy (s, continuation, continuation_length); |
816 | memcpy (s, continuation, continuation_length); |
801 | memcpy (s + continuation_length, beg, p - beg); |
817 | memcpy (s + continuation_length, beg, p - beg); |
802 | } |
818 | } |
803 | else |
819 | else |
804 | memcpy (s, beg, len); |
820 | memcpy (s, beg, len); |
805 | |
821 | |
806 | s[len] = 0; |
822 | s[len] = 0; |
807 | insert_line (idx); |
823 | insert_line (idx); |
808 | lines[idx].line = s; |
824 | lines[idx].line = s; |
809 | lines[idx].len = len; |
825 | lines[idx].len = len; |
… | |
… | |
841 | } |
857 | } |
842 | |
858 | |
843 | static void |
859 | static void |
844 | main_loop (void) |
860 | main_loop (void) |
845 | { |
861 | { |
846 | lines = xmalloc (sizeof (struct linematrix) * listlen); |
|
|
847 | display = xmalloc (sizeof (struct displaymatrix) * listlen); |
|
|
848 | int lin; |
862 | int lin; |
849 | time_t lastreload; |
863 | time_t lastreload; |
850 | Region region = XCreateRegion (); |
864 | Region region = XCreateRegion (); |
851 | XEvent xev; |
865 | XEvent xev; |
852 | struct logfile_entry *lastprinted = NULL; |
866 | struct logfile_entry *lastprinted = NULL; |
853 | struct logfile_entry *current; |
867 | struct logfile_entry *current; |
854 | int need_update = 1; |
868 | int need_update = 1; |
855 | |
869 | |
|
|
870 | lines = xmalloc (sizeof (struct linematrix) * listlen); |
|
|
871 | display = xmalloc (sizeof (struct displaymatrix) * listlen); |
|
|
872 | |
856 | lastreload = time (NULL); |
873 | lastreload = time (NULL); |
857 | |
874 | |
858 | /* Initialize linematrix */ |
875 | /* Initialize linematrix */ |
859 | for (lin = 0; lin < listlen; lin++) |
876 | for (lin = 0; lin < listlen; lin++) |
860 | { |
877 | { |
861 | lines[lin].line = xstrdup ("~"); |
878 | lines[lin].line = xstrdup ("~"); |
862 | lines[lin].len = 1; |
879 | lines[lin].len = 1; |
863 | display[lin].line = xstrdup(""); |
880 | display[lin].line = xstrdup(""); |
864 | display[lin].len = 0; |
881 | display[lin].len = 0; |
865 | display[lin].buffer_size = 1; |
882 | display[lin].buffer_size = 0; |
866 | lines[lin].color = GetColor (def_color); |
883 | lines[lin].color = GetColor (def_color); |
867 | } |
884 | } |
868 | |
885 | |
869 | for (;;) |
886 | for (;;) |
870 | { |
887 | { |
… | |
… | |
895 | |
912 | |
896 | /* print filename if any, and if last line was from |
913 | /* print filename if any, and if last line was from |
897 | * different file */ |
914 | * different file */ |
898 | if (!opt_nofilename && lastprinted != current && current->desc[0]) |
915 | if (!opt_nofilename && lastprinted != current && current->desc[0]) |
899 | { |
916 | { |
900 | char buf[1024]; /* HACK-5 */ |
|
|
901 | snprintf (buf, sizeof (buf), "[%s]", current->desc); |
|
|
902 | 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, "]"); |
903 | } |
920 | } |
904 | |
921 | |
905 | /* if we're dealing with partial lines, and the last |
922 | /* if we're dealing with partial lines, and the last |
906 | * time we showed the line it wasn't finished ... */ |
923 | * time we showed the line it wasn't finished ... */ |
907 | if (!opt_whole && current->lastpartial) |
924 | if (!opt_whole && current->lastpartial) |
… | |
… | |
1133 | { |
1150 | { |
1134 | if ((e->fp = fdopen (0, "r")) == NULL) |
1151 | if ((e->fp = fdopen (0, "r")) == NULL) |
1135 | perror ("fdopen"), exit (1); |
1152 | perror ("fdopen"), exit (1); |
1136 | if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) |
1153 | if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) |
1137 | perror ("fcntl"), exit (1); |
1154 | perror ("fcntl"), exit (1); |
|
|
1155 | |
1138 | e->fname = NULL; |
1156 | e->fname = NULL; |
1139 | e->inode = 0; |
1157 | e->inode = 0; |
1140 | e->desc = xstrdup ("stdin"); |
1158 | e->desc = xstrdup ("stdin"); |
1141 | } |
1159 | } |
1142 | else |
1160 | else |
1143 | { |
1161 | { |
1144 | int l; |
|
|
1145 | |
|
|
1146 | e->fname = xstrdup (fname); |
1162 | e->fname = xstrdup (fname); |
|
|
1163 | |
1147 | if (openlog (e) == NULL) |
1164 | if (openlog (e) == NULL) |
1148 | perror (fname), exit (1); |
1165 | perror (fname), exit (1); |
1149 | |
1166 | |
1150 | e->desc = xstrdup (desc); |
1167 | e->desc = xstrdup (desc); |
1151 | } |
1168 | } |
… | |
… | |
1156 | |
1173 | |
1157 | if (!loglist) |
1174 | if (!loglist) |
1158 | loglist = e; |
1175 | loglist = e; |
1159 | if (loglist_tail) |
1176 | if (loglist_tail) |
1160 | loglist_tail->next = e; |
1177 | loglist_tail->next = e; |
|
|
1178 | |
1161 | loglist_tail = e; |
1179 | loglist_tail = e; |
1162 | } |
1180 | } |
1163 | } |
1181 | } |
1164 | |
1182 | |
1165 | if (!loglist) |
1183 | if (!loglist) |
… | |
… | |
1167 | fprintf (stderr, "You did not specify any files to tail\n" |
1185 | fprintf (stderr, "You did not specify any files to tail\n" |
1168 | "use %s --help for help\n", argv[0]); |
1186 | "use %s --help for help\n", argv[0]); |
1169 | exit (1); |
1187 | exit (1); |
1170 | } |
1188 | } |
1171 | |
1189 | |
|
|
1190 | if (opt_update && opt_whole) |
|
|
1191 | { |
|
|
1192 | fprintf (stderr, "Specify at most one of -update and -whole\n"); |
|
|
1193 | exit (1); |
|
|
1194 | } |
1172 | if (opt_partial && opt_whole) |
1195 | else if (opt_partial && opt_whole) |
1173 | { |
1196 | { |
1174 | fprintf (stderr, "Specify at most one of -partial and -whole\n"); |
1197 | fprintf (stderr, "Specify at most one of -partial and -whole\n"); |
1175 | exit (1); |
1198 | exit (1); |
1176 | } |
1199 | } |
1177 | |
1200 | |
… | |
… | |
1246 | { |
1269 | { |
1247 | void *p; |
1270 | void *p; |
1248 | |
1271 | |
1249 | while ((p = strdup (string)) == NULL) |
1272 | while ((p = strdup (string)) == NULL) |
1250 | { |
1273 | { |
1251 | fprintf (stderr, "Memory exausted."); |
1274 | fprintf (stderr, "Memory exhausted in xstrdup().\n"); |
1252 | sleep (10); |
1275 | sleep (10); |
1253 | } |
1276 | } |
1254 | |
1277 | |
1255 | return p; |
1278 | return p; |
1256 | } |
1279 | } |
… | |
… | |
1260 | { |
1283 | { |
1261 | void *p; |
1284 | void *p; |
1262 | |
1285 | |
1263 | while ((p = malloc (size)) == NULL) |
1286 | while ((p = malloc (size)) == NULL) |
1264 | { |
1287 | { |
1265 | fprintf (stderr, "Memory exausted."); |
1288 | fprintf (stderr, "Memory exhausted in xmalloc().\n"); |
1266 | sleep (10); |
1289 | sleep (10); |
1267 | } |
1290 | } |
1268 | |
1291 | |
1269 | return p; |
1292 | return p; |
1270 | } |
1293 | } |
… | |
… | |
1274 | { |
1297 | { |
1275 | void *p; |
1298 | void *p; |
1276 | |
1299 | |
1277 | while ((p = realloc (ptr, size)) == NULL) |
1300 | while ((p = realloc (ptr, size)) == NULL) |
1278 | { |
1301 | { |
1279 | fprintf (stderr, "Memory exausted."); |
1302 | fprintf (stderr, "Memory exhausted in xrealloc().\n"); |
1280 | sleep (10); |
1303 | sleep (10); |
1281 | } |
1304 | } |
1282 | |
1305 | |
1283 | return p; |
1306 | return p; |
1284 | } |
1307 | } |
… | |
… | |
1306 | " startup\n" |
1329 | " startup\n" |
1307 | " -i | -interval seconds interval between checks (fractional\n" |
1330 | " -i | -interval seconds interval between checks (fractional\n" |
1308 | " values o.k.). Default 2.4 seconds\n" |
1331 | " values o.k.). Default 2.4 seconds\n" |
1309 | " -V display version information and exit\n" |
1332 | " -V display version information and exit\n" |
1310 | "\n"); |
1333 | "\n"); |
1311 | 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 " |
1312 | "/var/log/secure,red,'ALERT'\n", myname); |
1335 | "/var/log/secure,red,'ALERT'\n", myname); |
1313 | exit (0); |
1336 | exit (0); |
1314 | } |
1337 | } |
1315 | |
1338 | |
1316 | void |
1339 | void |