ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/root-tail/root-tail.c
(Generate patch)

Comparing root-tail/root-tail.c (file contents):
Revision 1.27 by chris_moore, Mon Mar 29 02:20:55 2004 UTC vs.
Revision 1.38 by pcg, Wed Mar 31 01:50:24 2004 UTC

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
64struct linematrix 68struct 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
75struct displaymatrix
76{
77 char *line;
78 int len;
79 int buffer_size;
80};
81
71/* global variables */ 82/* global variables */
72struct linematrix *lines; 83struct linematrix *lines;
84struct displaymatrix *display;
73int width = STD_WIDTH, height = STD_HEIGHT, listlen; 85int width = STD_WIDTH, height = STD_HEIGHT, listlen;
74int win_x = LOC_X, win_y = LOC_Y; 86int win_x = LOC_X, win_y = LOC_Y;
75int font_ascent, font_height; 87int font_ascent, font_height;
76int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */ 88int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */
77int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */ 89int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */
112void force_refresh (int); 124void force_refresh (int);
113void blank_window (int); 125void blank_window (int);
114 126
115void InitWindow (void); 127void InitWindow (void);
116unsigned long GetColor (const char *); 128unsigned long GetColor (const char *);
117void redraw (void); 129void redraw (int);
118void refresh (int, int, int); 130void refresh (int, int, int, int);
119 131
120void transform_line (char *s); 132void transform_line (char *s);
121int lineinput (struct logfile_entry *); 133int lineinput (struct logfile_entry *);
122void reopen (void); 134void reopen (void);
123void check_open_files (void); 135void check_open_files (void);
127void display_version (void); 139void display_version (void);
128void display_help (char *); 140void display_help (char *);
129void install_signal (int, void (*)(int)); 141void install_signal (int, void (*)(int));
130void *xstrdup (const char *); 142void *xstrdup (const char *);
131void *xmalloc (size_t); 143void *xmalloc (size_t);
144void *xrealloc (void *, size_t);
132int daemonize (void); 145int daemonize (void);
133 146
134/* signal handlers */ 147/* signal handlers */
135void 148void
136list_files (int dummy) 149list_files (int dummy)
149} 162}
150 163
151void 164void
152force_refresh (int dummy) 165force_refresh (int dummy)
153{ 166{
154 redraw (); 167 redraw (1);
155} 168}
156 169
157void 170void
158blank_window (int dummy) 171blank_window (int dummy)
159{ 172{
348 361
349 XSelectInput (disp, root, ExposureMask | FocusChangeMask); 362 XSelectInput (disp, root, ExposureMask | FocusChangeMask);
350} 363}
351 364
352/* 365/*
353 * redraw does a complete redraw, rather than an update (i.e. the area 366 * if redraw() is passwd a non-zero argument, it does a complete
354 * gets cleared first) 367 * redraw, rather than an update. if the argument is zero (and
368 * -noflicker is in effect) then only the lines which have changed
369 * since the last draw are redrawn.
370 *
355 * the rest is handled by regular refresh()'es 371 * the rest is handled by regular refresh()'es
356 */ 372 */
357void 373void
358redraw (void) 374redraw (int redraw_all)
359{ 375{
360 XSetClipMask (disp, WinGC, None); 376 XSetClipMask (disp, WinGC, None);
361 refresh (0, 32768, 1); 377 refresh (0, 32768, 1, redraw_all);
362} 378}
363 379
364/* Just redraw everything without clearing (i.e. after an EXPOSE event) */ 380/* Just redraw everything without clearing (i.e. after an EXPOSE event) */
365void 381void
366refresh (int miny, int maxy, int clear) 382refresh (int miny, int maxy, int clear, int refresh_all)
367{ 383{
368 int lin; 384 int lin;
369 int offset = (listlen + 1) * font_height; 385 int offset = listlen * font_height + font_ascent + effect_y_offset;
370 unsigned long black_color = GetColor ("black"); 386 unsigned long black_color = GetColor ("black");
371 387
372 miny -= win_y + font_height; 388 miny -= win_y + font_height;
373 maxy -= win_y - font_height; 389 maxy -= win_y - font_height;
374 390
376 XClearArea (disp, root, win_x, win_y, width, height, False); 392 XClearArea (disp, root, win_x, win_y, width, height, False);
377 393
378 for (lin = listlen; lin--;) 394 for (lin = listlen; lin--;)
379 { 395 {
380 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin); 396 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin);
397 struct displaymatrix *display_line = display + lin;
381 398
382 offset -= font_height; 399 offset -= font_height;
383 400
384 if (offset < miny || offset > maxy) 401 if (offset < miny || offset > maxy)
385 continue; 402 continue;
386 403
404 /* if this line is a different than it was, then it
405 * needs displaying */
387 if (clear && opt_noflicker) 406 if (!opt_noflicker
388 XClearArea (disp, root, win_x, win_y + offset - font_height, 407 || refresh_all
389 width + effect_x_space, font_height + effect_y_space, False); 408 || display_line->len != line->len
390 409 || memcmp (display_line->line, line->line, line->len))
391 if (opt_outline)
392 { 410 {
393 int x, y; 411 /* don't bother updating the record of what has been
412 * displayed if -noflicker isn't in effect, since we redraw
413 * the whole display every time anyway */
414 if (opt_noflicker)
415 {
416 /* update the record of what has been displayed;
417 * first make sure the buffer is big enough */
418 if (display_line->buffer_size <= line->len)
419 {
420 display_line->buffer_size = line->len + 1;
421 display_line->line = xrealloc (display_line->line, display_line->buffer_size);
422 }
423
424 display_line->len = line->len;
425 memcpy (display_line->line, line->line, line->len);
426
427 if (clear)
428 XClearArea (disp, root, win_x, win_y + offset - font_ascent,
429 width + effect_x_space, font_height + effect_y_space, False);
430 }
431
432 if (opt_outline)
433 {
434 int x, y;
394 XSetForeground (disp, WinGC, black_color); 435 XSetForeground (disp, WinGC, black_color);
395 436
396 for (x = -1; x < 2; x += 2) 437 for (x = -1; x < 2; x += 2)
397 for (y = -1; y < 2; y += 2) 438 for (y = -1; y < 2; y += 2)
398 XmbDrawString (disp, root, fontset, WinGC, 439 XmbDrawString (disp, root, fontset, WinGC,
399 win_x + effect_x_offset + x, 440 win_x + effect_x_offset + x,
400 win_y + effect_y_offset + y + offset - font_height + font_ascent, 441 win_y + y + offset,
401 line->line, line->len); 442 line->line, line->len);
402 } 443 }
403 else if (opt_shade) 444 else if (opt_shade)
404 { 445 {
405 XSetForeground (disp, WinGC, black_color); 446 XSetForeground (disp, WinGC, black_color);
447 XmbDrawString (disp, root, fontset, WinGC,
448 win_x + effect_x_offset + SHADE_X,
449 win_y + offset + SHADE_Y,
450 line->line, line->len);
451 }
452
453 XSetForeground (disp, WinGC, line->color);
406 XmbDrawString (disp, root, fontset, WinGC, 454 XmbDrawString (disp, root, fontset, WinGC,
407 win_x + effect_x_offset + SHADE_X, 455 win_x + effect_x_offset,
408 win_y + effect_y_offset + offset + SHADE_Y - font_height + font_ascent, 456 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); 457 line->line, line->len);
458 }
417 } 459 }
418 460
419 if (opt_frame) 461 if (opt_frame)
420 { 462 {
421 XSetForeground (disp, WinGC, GetColor (def_color)); 463 XSetForeground (disp, WinGC, GetColor (def_color));
452 int old_whole_len = strlen(s); 494 int old_whole_len = strlen(s);
453 printf("regexp was matched by '%s' - replace with '%s'\n", s, transform_to); 495 printf("regexp was matched by '%s' - replace with '%s'\n", s, transform_to);
454 printf("match is from %d to %d\n", 496 printf("match is from %d to %d\n",
455 match_start, match_end); 497 match_start, match_end);
456 if (new_len > old_len) { 498 if (new_len > old_len) {
457 s = realloc(s, old_whole_len + new_len - old_len); 499 s = xrealloc(s, old_whole_len + new_len - old_len);
458 } 500 }
459 if (new_len != old_len) { 501 if (new_len != old_len) {
460 memcpy(s + match_end + new_len - old_len, 502 memcpy(s + match_end + new_len - old_len,
461 s + match_end, 503 s + match_end,
462 old_whole_len - match_end); 504 old_whole_len - match_end);
488 530
489 return r; 531 return r;
490} 532}
491 533
492/* 534/*
493 * This routine should read a single line, no matter how long. 535 * HACK-1: This routine should read a single line, no matter how long.
494 */ 536 */
495int 537int
496lineinput (struct logfile_entry *logfile) 538lineinput (struct logfile_entry *logfile)
497{ 539{
498 char buff[1024], *p = buff; 540 char buff[1024], *p = buff;
499 int ch; 541 int ch;
500 /* HACK this - to add on the length of any partial line which we will be appending to */ 542 /* 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; 543 int ofs = logfile->buf ? strlen (logfile->buf) : 0;
502 544
503 do 545 do
504 { 546 {
505 ch = fgetc (logfile->fp); 547 ch = fgetc (logfile->fp);
618 sleep (1); 660 sleep (1);
619 if (e->fp) 661 if (e->fp)
620 fclose (e->fp); 662 fclose (e->fp);
621 if (openlog (e) == NULL) 663 if (openlog (e) == NULL)
622 continue; 664 continue;
665 if (fstat (fileno (e->fp), &stats) < 0)
666 continue;
623 } 667 }
624 668
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) 669 if (stats.st_ino != e->inode)
629 { /* file renamed? */ 670 { /* file renamed? */
630 if (e->fp) 671 if (e->fp)
631 fclose (e->fp); 672 fclose (e->fp);
632 if (openlog (e) == NULL) 673 if (openlog (e) == NULL)
673 struct logfile_entry *current; 714 struct logfile_entry *current;
674 715
675 for (cur_line = idx; cur_line > 0; cur_line--) 716 for (cur_line = idx; cur_line > 0; cur_line--)
676 lines[cur_line] = lines[cur_line - 1]; 717 lines[cur_line] = lines[cur_line - 1];
677 718
678 lines[0].line = strdup ("~"); 719 lines[0].line = xstrdup ("~");
679 720
680 for (current = loglist; current; current = current->next) 721 for (current = loglist; current; current = current->next)
681 if (current->index >= 0 && current->index <= idx) 722 if (current->index >= 0 && current->index <= idx)
682 current->index++; 723 current->index++;
683} 724}
689 */ 730 */
690static void 731static void
691split_line (int idx, const char *str, unsigned long color) 732split_line (int idx, const char *str, unsigned long color)
692{ 733{
693 int l = strlen (str); 734 int l = strlen (str);
735 int last_wrapped = 0;
694 const char *p = str; 736 const char *p = str;
737 static int continuation_width = -1;
738 static int continuation_length;
739
740 /* only calculate the continuation's width once */
741 if (continuation_width == -1)
742 {
743 continuation_length = strlen(continuation);
744 continuation_width = XmbTextEscapement (fontset, continuation, continuation_length);
745 }
695 746
696 do 747 do
697 { 748 {
698 const char *beg = p; 749 const char *beg = p;
750 int w = last_wrapped ? continuation_width : 0;
699 int w = 0, wrapped = 0; 751 int wrapped = 0;
700 const char *break_p = NULL; 752 const char *break_p = NULL;
701 753
702 while (*p) 754 while (*p)
703 { 755 {
704 /* find the length in bytes of the next multibyte character */ 756 /* find the length in bytes of the next multibyte character */
708 760
709 /* find the width in pixels of the next character */ 761 /* find the width in pixels of the next character */
710 int cw = XmbTextEscapement (fontset, p, len); 762 int cw = XmbTextEscapement (fontset, p, len);
711 if (cw + w > width - effect_x_space) 763 if (cw + w > width - effect_x_space)
712 { 764 {
765 if (p == beg)
766 {
767 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);
769 exit(1);
770 }
771
713 wrapped = 1; 772 wrapped = 1;
714 break; 773 break;
715 } 774 }
716 775
717 if (opt_wordwrap && len == 1 && p[0] == ' ') 776 if (opt_wordwrap && len == 1 && p[0] == ' ')
730 l += p - break_p; 789 l += p - break_p;
731 p = break_p; 790 p = break_p;
732 } 791 }
733 792
734 { 793 {
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);
735 char *s = xmalloc (p - beg + 1); 797 char *s = xmalloc (len + 1);
798 if (last_wrapped)
799 {
800 memcpy (s, continuation, continuation_length);
801 memcpy (s + continuation_length, beg, p - beg);
802 }
803 else
736 memcpy (s, beg, p - beg); 804 memcpy (s, beg, len);
805
737 s[p - beg] = 0; 806 s[len] = 0;
738 insert_line (idx); 807 insert_line (idx);
739 lines[idx].line = s; 808 lines[idx].line = s;
740 lines[idx].len = p - beg; 809 lines[idx].len = len;
741 lines[idx].color = color; 810 lines[idx].color = color;
742 } 811 }
743 812
744 /* if we wrapped at a space, don't display the space */ 813 /* if we wrapped at a space, don't display the space */
745 if (opt_wordwrap && wrapped && break_p && break_p != beg) 814 if (opt_wordwrap && wrapped && break_p && break_p != beg)
746 { 815 {
747 l--; 816 l--;
748 p++; 817 p++;
749 } 818 }
819
820 last_wrapped = wrapped;
750 } 821 }
751 while (l); 822 while (l);
752} 823}
753 824
754/* 825/*
771 842
772static void 843static void
773main_loop (void) 844main_loop (void)
774{ 845{
775 lines = xmalloc (sizeof (struct linematrix) * listlen); 846 lines = xmalloc (sizeof (struct linematrix) * listlen);
847 display = xmalloc (sizeof (struct displaymatrix) * listlen);
776 int lin; 848 int lin;
777 time_t lastreload; 849 time_t lastreload;
778 Region region = XCreateRegion (); 850 Region region = XCreateRegion ();
779 XEvent xev; 851 XEvent xev;
780 struct logfile_entry *lastprinted = NULL; 852 struct logfile_entry *lastprinted = NULL;
784 lastreload = time (NULL); 856 lastreload = time (NULL);
785 857
786 /* Initialize linematrix */ 858 /* Initialize linematrix */
787 for (lin = 0; lin < listlen; lin++) 859 for (lin = 0; lin < listlen; lin++)
788 { 860 {
789 lines[lin].line = strdup ("~"); 861 lines[lin].line = xstrdup ("~");
790 lines[lin].len = 1; 862 lines[lin].len = 1;
863 display[lin].line = xstrdup("");
864 display[lin].len = 0;
865 display[lin].buffer_size = 1;
791 lines[lin].color = GetColor (def_color); 866 lines[lin].color = GetColor (def_color);
792 } 867 }
793 868
794 for (;;) 869 for (;;)
795 { 870 {
820 895
821 /* print filename if any, and if last line was from 896 /* print filename if any, and if last line was from
822 * different file */ 897 * different file */
823 if (!opt_nofilename && lastprinted != current && current->desc[0]) 898 if (!opt_nofilename && lastprinted != current && current->desc[0])
824 { 899 {
825 char buf[1024]; /* HACK */ 900 char buf[1024]; /* HACK-5 */
826 snprintf (buf, sizeof (buf), "[%s]", current->desc); 901 snprintf (buf, sizeof (buf), "[%s]", current->desc);
827 split_line (listlen - 1, buf, current->color); 902 split_line (listlen - 1, buf, current->color);
828 } 903 }
829 904
830 /* if this is the same file we showed last, and the 905 /* if we're dealing with partial lines, and the last
831 * last time we showed it, it wasn't finished, then 906 * 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) 907 if (!opt_whole && current->lastpartial)
836 { 908 {
909 /* if this is the same file we showed last then
910 append to the last line shown */
911 if (lastprinted == current)
912 append_line (listlen - 1, current->buf);
913 else
914 {
915 /* but if a different file has been shown in the
916 * mean time, make a new line, starting with the
917 * continuation string */
837 split_line (listlen - 1, continuation, current->color); 918 split_line (listlen - 1, continuation, current->color);
838 append_line (listlen - 1, current->buf); 919 append_line (listlen - 1, current->buf);
920 }
839 } 921 }
840 else 922 else
923 /* otherwise just make a plain and simple new line */
841 split_line (listlen - 1, current->buf, current->color); 924 split_line (listlen - 1, current->buf, current->color);
842 925
843 free (current->buf), current->buf = 0; 926 free (current->buf), current->buf = 0;
844 current->index = listlen - 1; 927 current->index = listlen - 1;
845 lastprinted = current; 928 lastprinted = current;
846 } 929 }
847 } 930 }
848 931
849 if (need_update) 932 if (need_update)
850 { 933 {
851 redraw (); 934 redraw (0);
852 need_update = 0; 935 need_update = 0;
853 } 936 }
854 else 937 else
855 { 938 {
856 XFlush (disp); 939 XFlush (disp);
913 XRectangle r; 996 XRectangle r;
914 997
915 XSetRegion (disp, WinGC, region); 998 XSetRegion (disp, WinGC, region);
916 XClipBox (region, &r); 999 XClipBox (region, &r);
917 1000
918 refresh (r.y, r.y + r.height, 0); 1001 refresh (r.y, r.y + r.height, 0, 1);
919 1002
920 XDestroyRegion (region); 1003 XDestroyRegion (region);
921 region = XCreateRegion (); 1004 region = XCreateRegion ();
922 } 1005 }
923 } 1006 }
1062 1145
1063 e->fname = xstrdup (fname); 1146 e->fname = xstrdup (fname);
1064 if (openlog (e) == NULL) 1147 if (openlog (e) == NULL)
1065 perror (fname), exit (1); 1148 perror (fname), exit (1);
1066 1149
1067 l = strlen (desc); 1150 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 } 1151 }
1075 1152
1076 e->color = GetColor (fcolor); 1153 e->color = GetColor (fcolor);
1077 e->partial = 0; 1154 e->partial = 0;
1078 e->next = NULL; 1155 e->next = NULL;
1096 { 1173 {
1097 fprintf (stderr, "Specify at most one of -partial and -whole\n"); 1174 fprintf (stderr, "Specify at most one of -partial and -whole\n");
1098 exit (1); 1175 exit (1);
1099 } 1176 }
1100 1177
1101 /* HACK this - do we want to allow both -shade and -outline? */ 1178 /* HACK-7: do we want to allow both -shade and -outline? */
1102 if (opt_shade && opt_outline) 1179 if (opt_shade && opt_outline)
1103 { 1180 {
1104 fprintf (stderr, "Specify at most one of -shade and -outline\n"); 1181 fprintf (stderr, "Specify at most one of -shade and -outline\n");
1105 exit (1); 1182 exit (1);
1106 } 1183 }
1107 1184
1108 if (opt_partial) 1185 if (opt_partial)
1109 /* if we specifically requested to see partial lines then don't insist on whole lines */ 1186 /* if we specifically requested to see partial lines then don't insist on whole lines */
1110 opt_whole = 0; 1187 opt_whole = 0;
1111 else if (file_count > 1) 1188 else if (file_count > 1)
1112 /* otherwise, if we've viewing multiple files, default to showing whole lines */ 1189 /* otherwise, if we're viewing multiple files, default to showing whole lines */
1113 opt_whole = 1; 1190 opt_whole = 1;
1114 1191
1115#if HAS_REGEX 1192#if HAS_REGEX
1116 if (transform) 1193 if (transform)
1117 { 1194 {
1182xmalloc (size_t size) 1259xmalloc (size_t size)
1183{ 1260{
1184 void *p; 1261 void *p;
1185 1262
1186 while ((p = malloc (size)) == NULL) 1263 while ((p = malloc (size)) == NULL)
1264 {
1265 fprintf (stderr, "Memory exausted.");
1266 sleep (10);
1267 }
1268
1269 return p;
1270}
1271
1272void *
1273xrealloc (void *ptr, size_t size)
1274{
1275 void *p;
1276
1277 while ((p = realloc (ptr, size)) == NULL)
1187 { 1278 {
1188 fprintf (stderr, "Memory exausted."); 1279 fprintf (stderr, "Memory exausted.");
1189 sleep (10); 1280 sleep (10);
1190 } 1281 }
1191 1282
1239 case -1: 1330 case -1:
1240 return -1; 1331 return -1;
1241 case 0: 1332 case 0:
1242 break; 1333 break;
1243 default: 1334 default:
1244 printf("%d\n", pid); 1335 /*printf("%d\n", pid);*/
1245 exit (0); 1336 exit (0);
1246 } 1337 }
1247 1338
1248 if (setsid () == -1) 1339 if (setsid () == -1)
1249 return -1; 1340 return -1;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines