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.16 by pcg, Sat Mar 27 15:49:16 2004 UTC vs.
Revision 1.28 by chris_moore, Mon Mar 29 17:25:51 2004 UTC

31#include <sys/stat.h> 31#include <sys/stat.h>
32#include <sys/types.h> 32#include <sys/types.h>
33#include <locale.h> 33#include <locale.h>
34#include <ctype.h> 34#include <ctype.h>
35#include <stdarg.h> 35#include <stdarg.h>
36#include <X11/Xlib.h>
37#include <X11/Xatom.h>
38#include <X11/Xutil.h>
39
36#if HAS_REGEX 40#if HAS_REGEX
37#include <regex.h> 41#include <regex.h>
38#endif 42#endif
39#include <X11/Xlib.h> 43
40#include <X11/Xatom.h> 44#define SHADE_X 2
41#include <X11/Xutil.h> 45#define SHADE_Y 2
42 46
43/* data structures */ 47/* data structures */
44struct logfile_entry 48struct logfile_entry
45{ 49{
46 struct logfile_entry *next; 50 struct logfile_entry *next;
53 off_t last_size; /* file size at the last check */ 57 off_t last_size; /* file size at the last check */
54 unsigned long color; /* color to be used for printing */ 58 unsigned long color; /* color to be used for printing */
55 int partial; /* true if the last line isn't complete */ 59 int partial; /* true if the last line isn't complete */
56 int lastpartial; /* true if the previous output wasn't complete */ 60 int lastpartial; /* true if the previous output wasn't complete */
57 int index; /* index into linematrix of a partial line */ 61 int index; /* index into linematrix of a partial line */
62 int modified; /* true if line is modified & needs displaying */
58}; 63};
59 64
60struct linematrix 65struct linematrix
61{ 66{
62 char *line; 67 char *line;
63 int len; 68 int len;
64 unsigned long color; 69 unsigned long color;
65}; 70};
66 71
72struct displaymatrix
73{
74 char *line;
75 int len;
76 int buffer_size;
77};
78
67/* global variables */ 79/* global variables */
68struct linematrix *lines; 80struct linematrix *lines;
81struct displaymatrix *display;
69int width = STD_WIDTH, height = STD_HEIGHT, listlen; 82int width = STD_WIDTH, height = STD_HEIGHT, listlen;
70int win_x = LOC_X, win_y = LOC_Y; 83int win_x = LOC_X, win_y = LOC_Y;
71int font_descent, font_height; 84int font_ascent, font_height;
85int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */
86int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */
72int do_reopen; 87int do_reopen;
73struct timeval interval = { 3, 0 }; 88struct timeval interval = { 2, 400000 };
74XFontSet fontset; 89XFontSet fontset;
75 90
76/* command line options */ 91/* command line options */
77int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename, 92int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename,
78 opt_whole, opt_update, geom_mask, reload = 0; 93 opt_outline, opt_noflicker, opt_whole, opt_update, opt_wordwrap,
94 geom_mask, reload = 0;
79const char *command = NULL, 95const char *command = NULL,
80 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR, 96 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR,
81 *continuation = "[+]"; 97 *continuation = "[+]";
82 98
83struct logfile_entry *loglist = NULL, *loglist_tail = NULL; 99struct logfile_entry *loglist = NULL, *loglist_tail = NULL;
92 regex_t from; 108 regex_t from;
93 const char *to; 109 const char *to;
94 struct re_list *next; 110 struct re_list *next;
95}; 111};
96struct re_list *re_head, *re_tail; 112struct re_list *re_head, *re_tail;
113char *transform_to = NULL;
114regex_t *transformre;
97#endif 115#endif
98 116
99 117
100/* prototypes */ 118/* prototypes */
101void list_files (int); 119void list_files (int);
103void force_refresh (int); 121void force_refresh (int);
104void blank_window (int); 122void blank_window (int);
105 123
106void InitWindow (void); 124void InitWindow (void);
107unsigned long GetColor (const char *); 125unsigned long GetColor (const char *);
108void redraw (void); 126void redraw (int);
109void refresh (int, int); 127void refresh (int, int, int, int);
110 128
111void transform_line (char *s); 129void transform_line (char *s);
112int lineinput (struct logfile_entry *); 130int lineinput (struct logfile_entry *);
113void reopen (void); 131void reopen (void);
114void check_open_files (void); 132void check_open_files (void);
118void display_version (void); 136void display_version (void);
119void display_help (char *); 137void display_help (char *);
120void install_signal (int, void (*)(int)); 138void install_signal (int, void (*)(int));
121void *xstrdup (const char *); 139void *xstrdup (const char *);
122void *xmalloc (size_t); 140void *xmalloc (size_t);
141void *xrealloc (void *, size_t);
123int daemonize (void); 142int daemonize (void);
124 143
125/* signal handlers */ 144/* signal handlers */
126void 145void
127list_files (int dummy) 146list_files (int dummy)
140} 159}
141 160
142void 161void
143force_refresh (int dummy) 162force_refresh (int dummy)
144{ 163{
145 redraw (); 164 redraw (1);
146} 165}
147 166
148void 167void
149blank_window (int dummy) 168blank_window (int dummy)
150{ 169{
151 XClearArea (disp, root, win_x, win_y, width, height, False); 170 XClearArea (disp, root, win_x - 2, win_y - 2, width + 5, height + 5, False);
152 XFlush (disp); 171 XFlush (disp);
153 exit (0); 172 exit (0);
154} 173}
155 174
156/* X related functions */ 175/* X related functions */
285 304
286 { 305 {
287 XFontSetExtents *xfe = XExtentsOfFontSet (fontset); 306 XFontSetExtents *xfe = XExtentsOfFontSet (fontset);
288 307
289 font_height = xfe->max_logical_extent.height; 308 font_height = xfe->max_logical_extent.height;
290 font_descent = xfe->max_logical_extent.y; 309 font_ascent = -xfe->max_logical_extent.y;
291 } 310 }
292 311
293 if (geom_mask & XNegative) 312 if (geom_mask & XNegative)
294 win_x = win_x + ScreenWidth - width; 313 win_x = win_x + ScreenWidth - width;
295 if (geom_mask & YNegative) 314 if (geom_mask & YNegative)
296 win_y = win_y + ScreenHeight - height; 315 win_y = win_y + ScreenHeight - height;
297 316
317 if (opt_outline)
318 {
319 /* adding outline increases the total width and height by 2
320 pixels each, and offsets the text one pixel right and one
321 pixel down */
322 effect_x_space = effect_y_space = 2;
323 effect_x_offset = effect_y_offset = 1;
324 }
325 else if (opt_shade)
326 {
327 /* adding a shadow increases the space used */
328 effect_x_space = abs(SHADE_X);
329 effect_y_space = abs(SHADE_Y);
330 /* if the shadow is to the right and below then we don't need
331 * to move the text to make space for it, but shadows to the left
332 * and above need accomodating */
333 effect_x_offset = SHADE_X > 0 ? 0 : -SHADE_X;
334 effect_y_offset = SHADE_Y > 0 ? 0 : -SHADE_Y;
335 }
336 else
337 {
338 effect_x_space = effect_y_space = 0;
339 effect_x_offset = effect_y_offset = 0;
340 }
341
342 /* if we are using -shade or -outline, there will be less usable
343 * space for output */
298 listlen = height / font_height; 344 listlen = (height - effect_y_space) / font_height;
299 345
300 if (!listlen) 346 if (!listlen)
301 { 347 {
302 fprintf (stderr, "height too small for a single line, setting to %d\n", 348 fprintf (stderr, "height too small for a single line, setting to %d\n",
303 font_height); 349 font_height);
304 listlen = 1; 350 listlen = 1;
305 } 351 }
306 352
307 height = listlen * font_height; 353 /* leave the height how the user requested it. it might not all be
308 354 * used, but this will allow the geometry to be tuned more accurately
355 * (with the -frame option)
356 * the old code did this:
357 * height = listlen * font_height + effect_y_space; */
358
309 XSelectInput (disp, root, ExposureMask | FocusChangeMask); 359 XSelectInput (disp, root, ExposureMask | FocusChangeMask);
310} 360}
311 361
312/* 362/*
313 * redraw does a complete redraw, rather than an update (i.e. the area 363 * if redraw() is passwd a non-zero argument, it does a complete
314 * gets cleared first) 364 * redraw, rather than an update. if the argument is zero (and
365 * -noflicker is in effect) then only the lines which have changed
366 * since the last draw are redrawn.
367 *
315 * the rest is handled by regular refresh()'es 368 * the rest is handled by regular refresh()'es
316 */ 369 */
317void 370void
318redraw (void) 371redraw (int redraw_all)
319{ 372{
320 XClearArea (disp, root, win_x, win_y, width, height, False); 373 XSetClipMask (disp, WinGC, None);
321 refresh (0, 32768); 374 refresh (0, 32768, 1, redraw_all);
322} 375}
323 376
324/* Just redraw everything without clearing (i.e. after an EXPOSE event) */ 377/* Just redraw everything without clearing (i.e. after an EXPOSE event) */
325void 378void
326refresh (int miny, int maxy) 379refresh (int miny, int maxy, int clear, int refresh_all)
327{ 380{
328 int lin; 381 int lin;
329 int offset = (listlen + 1) * font_height; 382 int offset = (listlen + 1) * font_height;
330 unsigned long black_color = GetColor ("black"); 383 unsigned long black_color = GetColor ("black");
331 384
332 miny -= win_y + font_height; 385 miny -= win_y + font_height;
333 maxy -= win_y - font_height; 386 maxy -= win_y - font_height;
334 387
388 if (clear && !opt_noflicker)
389 XClearArea (disp, root, win_x, win_y, width, height, False);
335 390
336 for (lin = listlen; lin--;) 391 for (lin = listlen; lin--;)
337 { 392 {
338 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin); 393 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin);
394 struct displaymatrix *display_line = display + lin;
339 395
340 offset -= font_height; 396 offset -= font_height;
341 397
342 if (offset < miny || offset > maxy) 398 if (offset < miny || offset > maxy)
343 continue; 399 continue;
344 400
345 if (opt_shade) 401 if (opt_noflicker)
346 { 402 {
403 /* if this line is a different than it was, then it
404 * needs displaying */
405 if (refresh_all ||
406 display_line->len != line->len ||
407 strcmp(display_line->line, line->line))
408 {
409 /* update the record of what has been displayed;
410 * first make sure the buffer is big enough */
411 if (display_line->buffer_size <= line->len)
412 {
413 display_line->buffer_size = line->len + 1;
414 display_line->line = xrealloc(display_line->line, display_line->buffer_size);
415 }
416 strcpy(display_line->line, line->line);
417 display_line->len = line->len;
418
419 if (clear)
420 XClearArea (disp, root, win_x, win_y + offset - font_height,
421 width + effect_x_space, font_height + effect_y_space, False);
422
423 if (opt_outline)
424 {
425 int x, y;
347 XSetForeground (disp, WinGC, black_color); 426 XSetForeground (disp, WinGC, black_color);
427
428 for (x = -1; x < 2; x += 2)
429 for (y = -1; y < 2; y += 2)
348 XmbDrawString (disp, root, fontset, WinGC, win_x + 2, 430 XmbDrawString (disp, root, fontset, WinGC,
349 win_y + offset + 2, line->line, line->len); 431 win_x + effect_x_offset + x,
350 } 432 win_y + effect_y_offset + y + offset - font_height + font_ascent,
433 line->line, line->len);
434 }
435 else if (opt_shade)
436 {
437 XSetForeground (disp, WinGC, black_color);
438 XmbDrawString (disp, root, fontset, WinGC,
439 win_x + effect_x_offset + SHADE_X,
440 win_y + effect_y_offset + offset + SHADE_Y - font_height + font_ascent,
441 line->line, line->len);
442 }
351 443
352 XSetForeground (disp, WinGC, line->color); 444 XSetForeground (disp, WinGC, line->color);
353 XmbDrawString (disp, root, fontset, WinGC, win_x, win_y + offset, 445 XmbDrawString (disp, root, fontset, WinGC,
354 line->line, line->len); 446 win_x + effect_x_offset,
447 win_y + effect_y_offset + offset - font_height + font_ascent,
448 line->line, line->len);
449 }
450 }
451 else
452 {
453 XSetForeground (disp, WinGC, line->color);
454 XmbDrawString (disp, root, fontset, WinGC,
455 win_x + effect_x_offset,
456 win_y + effect_y_offset + offset - font_height + font_ascent,
457 line->line, line->len);
458 }
355 } 459 }
356 460
357 if (opt_frame) 461 if (opt_frame)
358 { 462 {
359 XSetForeground (disp, WinGC, GetColor (def_color)); 463 XSetForeground (disp, WinGC, GetColor (def_color));
360 XDrawRectangle (disp, root, WinGC, win_x - 2, win_y - 2, width + 4, height + 4); 464 XDrawRectangle (disp, root, WinGC, win_x - 0, win_y - 0, width - 1, height - 1);
361 } 465 }
362} 466}
363 467
364#if HAS_REGEX 468#if HAS_REGEX
365void 469void
378 if (transformre) 482 if (transformre)
379 { 483 {
380 int i; 484 int i;
381 regmatch_t matched[16]; 485 regmatch_t matched[16];
382 486
383 i = regexec (&transformre, string, 16, matched, 0); 487 i = regexec (transformre, s, 16, matched, 0);
384 if (i == 0) 488 if (i == 0)
385 { /* matched */ 489 { /* matched */
490 int match_start = matched[0].rm_so;
491 int match_end = matched[0].rm_eo;
492 int old_len = match_end - match_start;
493 int new_len = strlen(transform_to);
494 int old_whole_len = strlen(s);
495 printf("regexp was matched by '%s' - replace with '%s'\n", s, transform_to);
496 printf("match is from %d to %d\n",
497 match_start, match_end);
498 if (new_len > old_len) {
499 s = xrealloc(s, old_whole_len + new_len - old_len);
500 }
501 if (new_len != old_len) {
502 memcpy(s + match_end + new_len - old_len,
503 s + match_end,
504 old_whole_len - match_end);
505 s[old_whole_len + new_len - old_len] = '\0';
506 }
507 memcpy(s + match_start,
508 transform_to,
509 new_len);
510 printf("transformed to '%s'\n", s);
386 } 511 }
512 else
513 {
514 printf("regexp was not matched by '%s'\n", s);
515 }
387 } 516 }
388} 517}
389#endif 518#endif
390 519
391char * 520char *
408int 537int
409lineinput (struct logfile_entry *logfile) 538lineinput (struct logfile_entry *logfile)
410{ 539{
411 char buff[1024], *p = buff; 540 char buff[1024], *p = buff;
412 int ch; 541 int ch;
542 /* HACK this - to add on the length of any partial line which we will be appending to */
413 int ofs = logfile->buf ? strlen (logfile->buf) : 0; 543 int ofs = logfile->buf ? strlen (logfile->buf) : 0;
414 544
415 do 545 do
416 { 546 {
417 ch = fgetc (logfile->fp); 547 ch = fgetc (logfile->fp);
418 548
419 if (ch == '\r') 549 if (ch == '\n' || ch == EOF)
420 continue;
421 else if (ch == EOF || ch == '\n')
422 break; 550 break;
551 else if (ch == '\r')
552 continue; /* skip */
423 else if (ch == '\t') 553 else if (ch == '\t')
424 { 554 {
425 do 555 do
426 { 556 {
427 *p++ = ' '; 557 *p++ = ' ';
435 ofs++; 565 ofs++;
436 } 566 }
437 } 567 }
438 while (p < buff + (sizeof buff) - 8 - 1); 568 while (p < buff + (sizeof buff) - 8 - 1);
439 569
440 if (p == buff) 570 if (p == buff && ch == EOF)
441 return 0; 571 return 0;
442 572
443 *p = 0; 573 *p = 0;
444 574
445 p = concat_line (logfile->buf, buff); 575 p = concat_line (logfile->buf, buff);
446 free (logfile->buf); logfile->buf = p; 576 free (logfile->buf); logfile->buf = p;
447 577
448 logfile->lastpartial = logfile->partial; 578 logfile->lastpartial = logfile->partial;
579 /* 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
581 * both result in a partial line */
449 logfile->partial = ch == EOF; 582 logfile->partial = ch != '\n';
450 583
451 if (logfile->partial && opt_whole) 584 if (logfile->partial && opt_whole)
452 return 0; 585 return 0;
453 586
454#if HAS_REGEX 587#if HAS_REGEX
526 { /* file missing? */ 659 { /* file missing? */
527 sleep (1); 660 sleep (1);
528 if (e->fp) 661 if (e->fp)
529 fclose (e->fp); 662 fclose (e->fp);
530 if (openlog (e) == NULL) 663 if (openlog (e) == NULL)
531 break; 664 continue;
532 } 665 }
533 666
667 /* HACK this - stats can be uninitialised here (if the file
668 * didn't exist when stat() was called, but was recreated during
669 * the sleep(1)) */
534 if (stats.st_ino != e->inode) 670 if (stats.st_ino != e->inode)
535 { /* file renamed? */ 671 { /* file renamed? */
536 if (e->fp) 672 if (e->fp)
537 fclose (e->fp); 673 fclose (e->fp);
538 if (openlog (e) == NULL) 674 if (openlog (e) == NULL)
539 break; 675 continue;
540 } 676 }
541 677
542 if (stats.st_size < e->last_size) 678 if (stats.st_size < e->last_size)
543 { /* file truncated? */ 679 { /* file truncated? */
544 fseek (e->fp, 0, SEEK_SET); 680 fseek (e->fp, 0, SEEK_SET);
579 struct logfile_entry *current; 715 struct logfile_entry *current;
580 716
581 for (cur_line = idx; cur_line > 0; cur_line--) 717 for (cur_line = idx; cur_line > 0; cur_line--)
582 lines[cur_line] = lines[cur_line - 1]; 718 lines[cur_line] = lines[cur_line - 1];
583 719
584 lines[0].line = strdup ("~"); 720 lines[0].line = xstrdup ("~");
585 721
586 for (current = loglist; current; current = current->next) 722 for (current = loglist; current; current = current->next)
587 if (current->index >= 0 && current->index <= idx) 723 if (current->index >= 0 && current->index <= idx)
588 current->index++; 724 current->index++;
589} 725}
590 726
591/* 727/*
592 * takes a logical log file line and split it into multiple physical 728 * takes a logical log file line and splits it into multiple physical
593 * screen lines by splitting it whenever a part becomes too long. 729 * screen lines by splitting it whenever a part becomes too long.
594 * lal lines will be inserted at position "idx". 730 * lal lines will be inserted at position "idx".
595 */ 731 */
596static void 732static void
597split_line (int idx, const char *str, unsigned long color) 733split_line (int idx, const char *str, unsigned long color)
600 const char *p = str; 736 const char *p = str;
601 737
602 do 738 do
603 { 739 {
604 const char *beg = p; 740 const char *beg = p;
605 int w = 0; 741 int w = 0, wrapped = 0;
742 const char *break_p = NULL;
606 743
607 while (*p) 744 while (*p)
608 { 745 {
746 /* find the length in bytes of the next multibyte character */
609 int len = mblen (p, l); 747 int len = mblen (p, l);
610 if (len <= 0) 748 if (len <= 0)
611 len = 1; /* ignore (don't skip) ilegal character sequences */ 749 len = 1; /* ignore (don't skip) illegal character sequences */
612 750
751 /* find the width in pixels of the next character */
613 int cw = XmbTextEscapement (fontset, p, len); 752 int cw = XmbTextEscapement (fontset, p, len);
614 if (cw + w >= width) 753 if (cw + w > width - effect_x_space)
754 {
755 wrapped = 1;
615 break; 756 break;
757 }
758
759 if (opt_wordwrap && len == 1 && p[0] == ' ')
760 break_p = p;
616 761
617 w += cw; 762 w += cw;
618 p += len; 763 p += len;
619 l -= len; 764 l -= len;
620 } 765 }
766
767 /* if we're wrapping at spaces, and the line is long enough to
768 * wrap, and we've seen a space already, and the space wasn't
769 * the first character on the line, then wrap at the space */
770 if (opt_wordwrap && wrapped && break_p && break_p != beg)
771 {
772 l += p - break_p;
773 p = break_p;
774 }
621 775
622 { 776 {
623 char *s = xmalloc (p - beg + 1); 777 char *s = xmalloc (p - beg + 1);
624 memcpy (s, beg, p - beg); 778 memcpy (s, beg, p - beg);
625 s[p - beg] = 0; 779 s[p - beg] = 0;
626 insert_line (idx); 780 insert_line (idx);
627 lines[idx].line = s; 781 lines[idx].line = s;
628 lines[idx].len = p - beg; 782 lines[idx].len = p - beg;
629 lines[idx].color = color; 783 lines[idx].color = color;
630 } 784 }
785
786 /* if we wrapped at a space, don't display the space */
787 if (opt_wordwrap && wrapped && break_p && break_p != beg)
788 {
789 l--;
790 p++;
791 }
631 } 792 }
632 while (l); 793 while (l);
633} 794}
634 795
635/* 796/*
652 813
653static void 814static void
654main_loop (void) 815main_loop (void)
655{ 816{
656 lines = xmalloc (sizeof (struct linematrix) * listlen); 817 lines = xmalloc (sizeof (struct linematrix) * listlen);
657 int lin, miny, maxy; 818 display = xmalloc (sizeof (struct displaymatrix) * listlen);
819 int lin;
658 time_t lastreload; 820 time_t lastreload;
659 Region region = XCreateRegion (); 821 Region region = XCreateRegion ();
660 XEvent xev; 822 XEvent xev;
661 struct logfile_entry *lastprinted = NULL; 823 struct logfile_entry *lastprinted = NULL;
662 struct logfile_entry *current; 824 struct logfile_entry *current;
825 int need_update = 1;
663 826
664 maxy = 0;
665 miny = win_y + height;
666 lastreload = time (NULL); 827 lastreload = time (NULL);
667 828
668 /* Initialize linematrix */ 829 /* Initialize linematrix */
669 for (lin = 0; lin < listlen; lin++) 830 for (lin = 0; lin < listlen; lin++)
670 { 831 {
671 lines[lin].line = strdup ("~"); 832 lines[lin].line = xstrdup ("~");
672 lines[lin].len = 1; 833 lines[lin].len = 1;
834 display[lin].line = xstrdup("");
835 display[lin].len = 0;
836 display[lin].buffer_size = 1;
673 lines[lin].color = GetColor (def_color); 837 lines[lin].color = GetColor (def_color);
674 } 838 }
675 839
676 /* show the display full of empty lines ("~") in case the first
677 * time around the loop doesn't produce any output, as it won't if
678 * either (a) -noinitial is set or (b) all the files are currently
679 * empty */
680 redraw ();
681
682 for (;;) 840 for (;;)
683 { 841 {
684 int need_update = 0;
685
686 /* read logs */ 842 /* read logs */
687 for (current = loglist; current; current = current->next) 843 for (current = loglist; current; current = current->next)
688 { 844 {
689 if (!current->fp) 845 if (!current->fp)
690 continue; /* skip missing files */ 846 continue; /* skip missing files */
719 875
720 /* if this is the same file we showed last, and the 876 /* if this is the same file we showed last, and the
721 * last time we showed it, it wasn't finished, then 877 * last time we showed it, it wasn't finished, then
722 * append to the last line shown */ 878 * append to the last line shown */
723 if (lastprinted == current && current->lastpartial) 879 if (lastprinted == current && current->lastpartial)
724 { 880 append_line (listlen - 1, current->buf);
881 else if (current->lastpartial)
882 {
883 split_line (listlen - 1, continuation, current->color);
725 append_line (listlen - 1, current->buf); 884 append_line (listlen - 1, current->buf);
726 free (current->buf), current->buf = 0; 885 }
727 continue;
728 }
729 else 886 else
730 {
731 split_line (listlen - 1, current->buf, current->color); 887 split_line (listlen - 1, current->buf, current->color);
888
732 free (current->buf), current->buf = 0; 889 free (current->buf), current->buf = 0;
733 }
734
735 current->index = listlen - 1; 890 current->index = listlen - 1;
736 lastprinted = current; 891 lastprinted = current;
737 } 892 }
738 } 893 }
739 894
740 if (need_update) 895 if (need_update)
896 {
741 redraw (); 897 redraw (0);
898 need_update = 0;
899 }
742 else 900 else
743 { 901 {
744 XFlush (disp); 902 XFlush (disp);
745 903
746 if (!XPending (disp)) 904 if (!XPending (disp))
772 930
773 r.x = xev.xexpose.x; 931 r.x = xev.xexpose.x;
774 r.y = xev.xexpose.y; 932 r.y = xev.xexpose.y;
775 r.width = xev.xexpose.width; 933 r.width = xev.xexpose.width;
776 r.height = xev.xexpose.height; 934 r.height = xev.xexpose.height;
935
777 XUnionRectWithRegion (&r, region, region); 936 XUnionRectWithRegion (&r, region, region);
778 if (miny > r.y)
779 miny = r.y;
780 if (maxy < r.y + r.height)
781 maxy = r.y + r.height;
782 } 937 }
783 break; 938 break;
784 default: 939 default:
785#ifdef DEBUGMODE 940#ifdef DEBUGMODE
786 fprintf (stderr, "PANIC! Unknown event %d\n", xev.type); 941 fprintf (stderr, "PANIC! Unknown event %d\n", xev.type);
799 lastreload = time (NULL); 954 lastreload = time (NULL);
800 } 955 }
801 956
802 if (!XEmptyRegion (region)) 957 if (!XEmptyRegion (region))
803 { 958 {
959 XRectangle r;
960
804 XSetRegion (disp, WinGC, region); 961 XSetRegion (disp, WinGC, region);
962 XClipBox (region, &r);
805 963
806 refresh (miny, maxy); 964 refresh (r.y, r.y + r.height, 0, 1);
965
807 XDestroyRegion (region); 966 XDestroyRegion (region);
808 region = XCreateRegion (); 967 region = XCreateRegion ();
809 maxy = 0;
810 miny = 32768;
811 } 968 }
812 } 969 }
813} 970}
814 971
815 972
853 continuation = argv[++i]; 1010 continuation = argv[++i];
854 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn")) 1011 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn"))
855 fontname = argv[++i]; 1012 fontname = argv[++i];
856#if HAS_REGEX 1013#if HAS_REGEX
857 else if (!strcmp (arg, "-t")) 1014 else if (!strcmp (arg, "-t"))
1015 {
858 transform = argv[++i]; 1016 transform = argv[++i];
1017 transform_to = argv[++i];
1018 printf("transform: '%s' to '%s'\n", transform, transform_to);
1019 }
859#endif 1020#endif
860 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f")) 1021 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f"))
861 opt_daemonize = 1; 1022 opt_daemonize = 1;
862 else if (!strcmp (arg, "-reload")) 1023 else if (!strcmp (arg, "-reload"))
863 { 1024 {
864 reload = atoi (argv[++i]); 1025 reload = atoi (argv[++i]);
865 command = argv[++i]; 1026 command = argv[++i];
866 } 1027 }
867 else if (!strcmp (arg, "-shade")) 1028 else if (!strcmp (arg, "-shade"))
868 opt_shade = 1; 1029 opt_shade = 1;
1030 else if (!strcmp (arg, "-outline"))
1031 opt_outline = 1;
1032 else if (!strcmp (arg, "-noflicker"))
1033 opt_noflicker = 1;
869 else if (!strcmp (arg, "-frame")) 1034 else if (!strcmp (arg, "-frame"))
870 opt_frame = 1; 1035 opt_frame = 1;
871 else if (!strcmp (arg, "-no-filename")) 1036 else if (!strcmp (arg, "-no-filename"))
872 opt_nofilename = 1; 1037 opt_nofilename = 1;
873 else if (!strcmp (arg, "-reverse")) 1038 else if (!strcmp (arg, "-reverse"))
876 opt_whole = 1; 1041 opt_whole = 1;
877 else if (!strcmp (arg, "-partial")) 1042 else if (!strcmp (arg, "-partial"))
878 opt_partial = 1; 1043 opt_partial = 1;
879 else if (!strcmp (arg, "-update")) 1044 else if (!strcmp (arg, "-update"))
880 opt_update = opt_partial = 1; 1045 opt_update = opt_partial = 1;
1046 else if (!strcmp (arg, "-wordwrap"))
1047 opt_wordwrap = 1;
881 else if (!strcmp (arg, "-color")) 1048 else if (!strcmp (arg, "-color"))
882 def_color = argv[++i]; 1049 def_color = argv[++i];
883 else if (!strcmp (arg, "-noinitial")) 1050 else if (!strcmp (arg, "-noinitial"))
884 opt_noinitial = 1; 1051 opt_noinitial = 1;
885 else if (!strcmp (arg, "-id")) 1052 else if (!strcmp (arg, "-id"))
942 e->fname = xstrdup (fname); 1109 e->fname = xstrdup (fname);
943 if (openlog (e) == NULL) 1110 if (openlog (e) == NULL)
944 perror (fname), exit (1); 1111 perror (fname), exit (1);
945 1112
946 l = strlen (desc); 1113 l = strlen (desc);
1114 /* HACK on this - width is in pixels now */
947 if (l > width - 2) /* must account for [ ] */ 1115 if (l > width - 2) /* must account for [ ] */
948 l = width - 2; 1116 l = width - 2;
949 e->desc = xmalloc (l + 1); 1117 e->desc = xmalloc (l + 1);
950 memcpy (e->desc, desc, l); 1118 memcpy (e->desc, desc, l);
951 *(e->desc + l) = '\0'; 1119 *(e->desc + l) = '\0';
974 { 1142 {
975 fprintf (stderr, "Specify at most one of -partial and -whole\n"); 1143 fprintf (stderr, "Specify at most one of -partial and -whole\n");
976 exit (1); 1144 exit (1);
977 } 1145 }
978 1146
1147 /* HACK this - do we want to allow both -shade and -outline? */
1148 if (opt_shade && opt_outline)
1149 {
1150 fprintf (stderr, "Specify at most one of -shade and -outline\n");
1151 exit (1);
1152 }
1153
979 if (opt_partial) 1154 if (opt_partial)
980 /* if we specifically requested to see partial lines then don't insist on whole lines */ 1155 /* if we specifically requested to see partial lines then don't insist on whole lines */
981 opt_whole = 0; 1156 opt_whole = 0;
982 else if (file_count > 1) 1157 else if (file_count > 1)
983 /* otherwise, if we've viewing multiple files, default to showing whole lines */ 1158 /* otherwise, if we've viewing multiple files, default to showing whole lines */
986#if HAS_REGEX 1161#if HAS_REGEX
987 if (transform) 1162 if (transform)
988 { 1163 {
989 int i; 1164 int i;
990 1165
1166 printf("compiling regexp '%s'\n", transform);
991 transformre = xmalloc (sizeof (transformre)); 1167 transformre = xmalloc (sizeof (regex_t));
992 i = regcomp (&transformre, transform, REG_EXTENDED); 1168 i = regcomp (transformre, transform, REG_EXTENDED);
993 if (i != 0) 1169 if (i != 0)
994 { 1170 {
995 char buf[512]; 1171 char buf[512];
996 1172
997 regerror (i, &transformre, buf, sizeof (buf)); 1173 regerror (i, transformre, buf, sizeof (buf));
998 fprintf (stderr, "Cannot compile regular expression: %s\n", buf); 1174 fprintf (stderr, "Cannot compile regular expression: %s\n", buf);
999 } 1175 }
1176 else
1177 {
1178 printf("compiled '%s' OK to %x\n", transform, (int)transformre);
1179 }
1000 } 1180 }
1001#endif 1181#endif
1002 1182
1003 InitWindow (); 1183 InitWindow ();
1004 1184
1048xmalloc (size_t size) 1228xmalloc (size_t size)
1049{ 1229{
1050 void *p; 1230 void *p;
1051 1231
1052 while ((p = malloc (size)) == NULL) 1232 while ((p = malloc (size)) == NULL)
1233 {
1234 fprintf (stderr, "Memory exausted.");
1235 sleep (10);
1236 }
1237
1238 return p;
1239}
1240
1241void *
1242xrealloc (void *ptr, size_t size)
1243{
1244 void *p;
1245
1246 while ((p = realloc (ptr, size)) == NULL)
1053 { 1247 {
1054 fprintf (stderr, "Memory exausted."); 1248 fprintf (stderr, "Memory exausted.");
1055 sleep (10); 1249 sleep (10);
1056 } 1250 }
1057 1251
1072 " -reverse print new lines at the top\n" 1266 " -reverse print new lines at the top\n"
1073 " -whole wait for \\n before showing a line\n" 1267 " -whole wait for \\n before showing a line\n"
1074 " -partial show lines even if they don't end with a \\n\n" 1268 " -partial show lines even if they don't end with a \\n\n"
1075 " -update allow updates to old partial lines\n" 1269 " -update allow updates to old partial lines\n"
1076 " -cont string to prefix continued partial lines with\n" 1270 " -cont string to prefix continued partial lines with\n"
1271 " -wordwrap wrap long lines at spaces to avoid breaking words\n"
1077 " defaults to \"[+]\"\n" 1272 " defaults to \"[+]\"\n"
1078 " -shade add shading to font\n" 1273 " -shade add shading to font\n"
1079 " -noinitial don't display the last file lines on\n" 1274 " -noinitial don't display the last file lines on\n"
1080 " startup\n" 1275 " startup\n"
1081 " -i | -interval seconds interval between checks (fractional\n" 1276 " -i | -interval seconds interval between checks (fractional\n"
1082 " values o.k.). Default 3 seconds\n" 1277 " values o.k.). Default 2.4 seconds\n"
1083 " -V display version information and exit\n" 1278 " -V display version information and exit\n"
1084 "\n"); 1279 "\n");
1085 printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green " 1280 printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green "
1086 "/var/log/secure,red,'ALERT'\n", myname); 1281 "/var/log/secure,red,'ALERT'\n", myname);
1087 exit (0); 1282 exit (0);
1095} 1290}
1096 1291
1097int 1292int
1098daemonize (void) 1293daemonize (void)
1099{ 1294{
1295 pid_t pid;
1296
1100 switch (fork ()) 1297 switch (pid = fork ())
1101 { 1298 {
1102 case -1: 1299 case -1:
1103 return -1; 1300 return -1;
1104 case 0: 1301 case 0:
1105 break; 1302 break;
1106 default: 1303 default:
1304 printf("%d\n", pid);
1107 _exit (0); 1305 exit (0);
1108 } 1306 }
1109 1307
1110 if (setsid () == -1) 1308 if (setsid () == -1)
1111 return -1; 1309 return -1;
1112 1310

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines