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.11 by pcg, Fri Mar 26 13:14:54 2004 UTC vs.
Revision 1.26 by chris_moore, Sun Mar 28 21:53:09 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>
40#include <X11/Xatom.h>
41#include <X11/Xutil.h>
42 43
43/* data structures */ 44/* data structures */
44struct logfile_entry 45struct logfile_entry
45{ 46{
46 struct logfile_entry *next; 47 struct logfile_entry *next;
58}; 59};
59 60
60struct linematrix 61struct linematrix
61{ 62{
62 char *line; 63 char *line;
64 int len;
63 unsigned long color; 65 unsigned long color;
64}; 66};
65 67
66/* global variables */ 68/* global variables */
69struct linematrix *lines;
67int width = STD_WIDTH, height = STD_HEIGHT, listlen; 70int width = STD_WIDTH, height = STD_HEIGHT, listlen;
68int win_x = LOC_X, win_y = LOC_Y; 71int win_x = LOC_X, win_y = LOC_Y;
69int font_descent, font_height; 72int font_ascent, font_height;
70int do_reopen; 73int do_reopen;
71struct timeval interval = { 3, 0 }; 74struct timeval interval = { 2, 400000 };
72XFontSet fontset; 75XFontSet fontset;
73 76
74/* command line options */ 77/* command line options */
75int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename, 78int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename,
76 opt_whole, opt_update, geom_mask, reload = 0; 79 opt_outline, opt_noflicker, opt_whole, opt_update, opt_wordwrap,
80 geom_mask, reload = 0;
77const char *command = NULL, 81const char *command = NULL,
78 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR, 82 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR,
79 *continuation = "[+]"; 83 *continuation = "[+]";
80 84
81struct logfile_entry *loglist = NULL, *loglist_tail = NULL; 85struct logfile_entry *loglist = NULL, *loglist_tail = NULL;
90 regex_t from; 94 regex_t from;
91 const char *to; 95 const char *to;
92 struct re_list *next; 96 struct re_list *next;
93}; 97};
94struct re_list *re_head, *re_tail; 98struct re_list *re_head, *re_tail;
99char *transform_to = NULL;
100regex_t *transformre;
95#endif 101#endif
96 102
97 103
98/* prototypes */ 104/* prototypes */
99void list_files (int); 105void list_files (int);
102void blank_window (int); 108void blank_window (int);
103 109
104void InitWindow (void); 110void InitWindow (void);
105unsigned long GetColor (const char *); 111unsigned long GetColor (const char *);
106void redraw (void); 112void redraw (void);
107void refresh (struct linematrix *, int, int); 113void refresh (int, int, int);
108 114
109void transform_line (char *s); 115void transform_line (char *s);
110int lineinput (struct logfile_entry *); 116int lineinput (struct logfile_entry *);
111void reopen (void); 117void reopen (void);
112void check_open_files (void); 118void check_open_files (void);
113FILE *openlog (struct logfile_entry *); 119FILE *openlog (struct logfile_entry *);
114void main_loop (void); 120static void main_loop (void);
115 121
116void display_version (void); 122void display_version (void);
117void display_help (char *); 123void display_help (char *);
118void install_signal (int, void (*)(int)); 124void install_signal (int, void (*)(int));
119void *xstrdup (const char *); 125void *xstrdup (const char *);
138} 144}
139 145
140void 146void
141force_refresh (int dummy) 147force_refresh (int dummy)
142{ 148{
143 XClearArea (disp, root, win_x, win_y, width, height, False);
144 redraw (); 149 redraw ();
145} 150}
146 151
147void 152void
148blank_window (int dummy) 153blank_window (int dummy)
149{ 154{
150 XClearArea (disp, root, win_x, win_y, width, height, False); 155 XClearArea (disp, root, win_x - 2, win_y - 2, width + 5, height + 5, False);
151 XFlush (disp); 156 XFlush (disp);
152 exit (0); 157 exit (0);
153} 158}
154 159
155/* X related functions */ 160/* X related functions */
284 289
285 { 290 {
286 XFontSetExtents *xfe = XExtentsOfFontSet (fontset); 291 XFontSetExtents *xfe = XExtentsOfFontSet (fontset);
287 292
288 font_height = xfe->max_logical_extent.height; 293 font_height = xfe->max_logical_extent.height;
289 font_descent = xfe->max_logical_extent.y; 294 font_ascent = -xfe->max_logical_extent.y;
290 } 295 }
291 296
292 if (geom_mask & XNegative) 297 if (geom_mask & XNegative)
293 win_x = win_x + ScreenWidth - width; 298 win_x = win_x + ScreenWidth - width;
294 if (geom_mask & YNegative) 299 if (geom_mask & YNegative)
304 } 309 }
305 310
306 height = listlen * font_height; 311 height = listlen * font_height;
307 312
308 XSelectInput (disp, root, ExposureMask | FocusChangeMask); 313 XSelectInput (disp, root, ExposureMask | FocusChangeMask);
309}
310
311char *
312detabificate (char *s)
313{
314 char *out;
315 int i, j;
316
317 out = malloc (8 * strlen (s) + 1);
318
319 for (i = 0, j = 0; s[i]; i++)
320 {
321 if (s[i] == '\t')
322 do
323 out[j++] = ' ';
324 while (j % 8);
325 else
326 out[j++] = s[i];
327 }
328
329 out[j] = '\0';
330 return out;
331} 314}
332 315
333/* 316/*
334 * redraw does a complete redraw, rather than an update (i.e. the area 317 * redraw does a complete redraw, rather than an update (i.e. the area
335 * gets cleared first) 318 * gets cleared first)
336 * the rest is handled by regular refresh()'es 319 * the rest is handled by regular refresh()'es
337 */ 320 */
338void 321void
339redraw (void) 322redraw (void)
340{ 323{
341 XClearArea (disp, root, win_x, win_y, width, height, True); 324 XSetClipMask (disp, WinGC, None);
325 refresh (0, 32768, 1);
342} 326}
343 327
344/* Just redraw everything without clearing (i.e. after an EXPOSE event) */ 328/* Just redraw everything without clearing (i.e. after an EXPOSE event) */
345void 329void
346refresh (struct linematrix *lines, int miny, int maxy) 330refresh (int miny, int maxy, int clear)
347{ 331{
348 int lin; 332 int lin;
349 int offset = (listlen + 1) * font_height; 333 int offset = (listlen + 1) * font_height;
350 unsigned long black_color = GetColor ("black"); 334 unsigned long black_color = GetColor ("black");
351 335
352 miny -= win_y + font_height; 336 miny -= win_y + font_height;
353 maxy -= win_y - font_height; 337 maxy -= win_y - font_height;
354 338
339 if (clear && !opt_noflicker)
340 XClearArea (disp, root, win_x, win_y, width, height, False);
341
355 for (lin = listlen; lin--;) 342 for (lin = listlen; lin--;)
356 { 343 {
357 struct linematrix *line =
358 lines + (opt_reverse ? listlen - lin - 1 : lin); 344 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin);
359 345
360 offset -= font_height; 346 offset -= font_height;
361 347
362 if (offset < miny || offset > maxy) 348 if (offset < miny || offset > maxy)
363 continue; 349 continue;
364 350
351 if (clear && opt_noflicker)
352 XClearArea (disp, root, win_x, win_y + offset - font_ascent, width, font_height, False);
353
354 if (opt_outline)
355 {
356 XSetForeground (disp, WinGC, black_color);
357 XmbDrawString (disp, root, fontset, WinGC, win_x - 1,
358 win_y + offset + 1, line->line, line->len);
359 XmbDrawString (disp, root, fontset, WinGC, win_x + 1,
360 win_y + offset + 1, line->line, line->len);
361 XmbDrawString (disp, root, fontset, WinGC, win_x - 1,
362 win_y + offset - 1, line->line, line->len);
363 XmbDrawString (disp, root, fontset, WinGC, win_x + 1,
364 win_y + offset - 1, line->line, line->len);
365 }
365 if (opt_shade) 366 else if (opt_shade)
366 { 367 {
367 XSetForeground (disp, WinGC, black_color); 368 XSetForeground (disp, WinGC, black_color);
368 XmbDrawString (disp, root, fontset, WinGC, win_x + 2, 369 XmbDrawString (disp, root, fontset, WinGC, win_x + 2,
369 win_y + offset + 2, line->line, strlen (line->line)); 370 win_y + offset + 2, line->line, line->len);
370 } 371 }
371 372
372 XSetForeground (disp, WinGC, line->color); 373 XSetForeground (disp, WinGC, line->color);
373 XmbDrawString (disp, root, fontset, WinGC, win_x, win_y + offset, 374 XmbDrawString (disp, root, fontset, WinGC, win_x, win_y + offset,
374 line->line, strlen (line->line)); 375 line->line, line->len);
375 } 376 }
376 377
377 if (opt_frame) 378 if (opt_frame)
379 {
380 XSetForeground (disp, WinGC, GetColor (def_color));
378 XDrawRectangle (disp, root, WinGC, win_x, win_y, width, height); 381 XDrawRectangle (disp, root, WinGC, win_x - 2, win_y - 2, width + 4, height + 4);
382 }
379} 383}
380 384
381#if HAS_REGEX 385#if HAS_REGEX
382void 386void
383transform_line (char *s) 387transform_line (char *s)
395 if (transformre) 399 if (transformre)
396 { 400 {
397 int i; 401 int i;
398 regmatch_t matched[16]; 402 regmatch_t matched[16];
399 403
400 i = regexec (&transformre, string, 16, matched, 0); 404 i = regexec (transformre, s, 16, matched, 0);
401 if (i == 0) 405 if (i == 0)
402 { /* matched */ 406 { /* matched */
407 int match_start = matched[0].rm_so;
408 int match_end = matched[0].rm_eo;
409 int old_len = match_end - match_start;
410 int new_len = strlen(transform_to);
411 int old_whole_len = strlen(s);
412 printf("regexp was matched by '%s' - replace with '%s'\n", s, transform_to);
413 printf("match is from %d to %d\n",
414 match_start, match_end);
415 if (new_len > old_len) {
416 s = realloc(s, old_whole_len + new_len - old_len);
417 }
418 if (new_len != old_len) {
419 memcpy(s + match_end + new_len - old_len,
420 s + match_end,
421 old_whole_len - match_end);
422 s[old_whole_len + new_len - old_len] = '\0';
423 }
424 memcpy(s + match_start,
425 transform_to,
426 new_len);
427 printf("transformed to '%s'\n", s);
403 } 428 }
429 else
430 {
431 printf("regexp was not matched by '%s'\n", s);
432 }
404 } 433 }
405} 434}
406#endif 435#endif
407 436
437char *
438concat_line (const char *p1, const char *p2)
439{
440 int l1 = p1 ? strlen (p1) : 0;
441 int l2 = strlen (p2);
442 char *r = xmalloc (l1 + l2 + 1);
443
444 memcpy (r, p1, l1);
445 memcpy (r + l1, p2, l2);
446 r[l1 + l2] = 0;
447
448 return r;
449}
408 450
409/* 451/*
410 * This routine should read 'width' characters and not more. However, 452 * This routine should read a single line, no matter how long.
411 * we really want to read width + 1 characters if the last char is a '\n',
412 * which we should remove afterwards. So, read width+1 chars and ungetc
413 * the last character if it's not a newline. This means 'string' must be
414 * width + 2 wide!
415 */ 453 */
416int 454int
417lineinput (struct logfile_entry *logfile) 455lineinput (struct logfile_entry *logfile)
418{ 456{
419 char *string = logfile->buf; 457 char buff[1024], *p = buff;
420 int slen = width + 2; 458 int ch;
421 FILE *f = logfile->fp; 459 /* HACK this - to add on the length of any partial line which we will be appending to */
422 460 int ofs = logfile->buf ? strlen (logfile->buf) : 0;
423 int len = strlen (string);
424 int partial = logfile->partial;
425 461
426 do 462 do
427 { 463 {
428 if (fgets (string + len, slen - len, f) == NULL) /* EOF or Error */ 464 ch = fgetc (logfile->fp);
429 return 0;
430 465
431 len = strlen (string); 466 if (ch == '\n' || ch == EOF)
432 } 467 break;
433 while (len == 0); 468 else if (ch == '\r')
434 469 continue; /* skip */
435 logfile->partial = 0; 470 else if (ch == '\t')
436 471 {
437 if (string[len - 1] == '\n') 472 do
438 /* if the string ends in a newline, delete the newline */ 473 {
439 string[len - 1] = '\0'; /* erase newline */ 474 *p++ = ' ';
440 else if (len >= slen - 1) 475 ofs++;
476 }
477 while (ofs & 7);
478 }
479 else
480 {
481 *p++ = ch;
482 ofs++;
483 }
441 { 484 }
442 /* otherwise if we've read one too many characters, un-read the last one and delete it */ 485 while (p < buff + (sizeof buff) - 8 - 1);
443 ungetc (string[len - 1], f); 486
444 string[len - 1] = '\0'; 487 if (p == buff && ch == EOF)
445 }
446 else if (opt_whole)
447 return 0; 488 return 0;
448 else 489
490 *p = 0;
491
492 p = concat_line (logfile->buf, buff);
493 free (logfile->buf); logfile->buf = p;
494
495 logfile->lastpartial = logfile->partial;
496 /* there are 3 ways we could have exited the loop: reading '\n',
497 * reaching EOF, or filling the buffer; the 2nd and 3rd of these
498 * both result in a partial line */
449 logfile->partial = 1; 499 logfile->partial = ch != '\n';
500
501 if (logfile->partial && opt_whole)
502 return 0;
450 503
451#if HAS_REGEX 504#if HAS_REGEX
452 transform_line (string); 505 transform_line (logfile->buf);
453#endif 506#endif
454 logfile->lastpartial = partial;
455 return len; 507 return 1;
456} 508}
457 509
458/* input: reads file->fname 510/* input: reads file->fname
459 * output: fills file->fp, file->inode 511 * output: fills file->fp, file->inode
460 * returns file->fp 512 * returns file->fp
524 { /* file missing? */ 576 { /* file missing? */
525 sleep (1); 577 sleep (1);
526 if (e->fp) 578 if (e->fp)
527 fclose (e->fp); 579 fclose (e->fp);
528 if (openlog (e) == NULL) 580 if (openlog (e) == NULL)
529 break; 581 continue;
530 } 582 }
531 583
584 /* HACK this - stats can be uninitialised here (if the file
585 * didn't exist when stat() was called, but was recreated during
586 * the sleep(1)) */
532 if (stats.st_ino != e->inode) 587 if (stats.st_ino != e->inode)
533 { /* file renamed? */ 588 { /* file renamed? */
534 if (e->fp) 589 if (e->fp)
535 fclose (e->fp); 590 fclose (e->fp);
536 if (openlog (e) == NULL) 591 if (openlog (e) == NULL)
537 break; 592 continue;
538 } 593 }
539 594
540 if (stats.st_size < e->last_size) 595 if (stats.st_size < e->last_size)
541 { /* file truncated? */ 596 { /* file truncated? */
542 fseek (e->fp, 0, SEEK_SET); 597 fseek (e->fp, 0, SEEK_SET);
543 e->last_size = stats.st_size; 598 e->last_size = stats.st_size;
544 } 599 }
545 } 600 }
546} 601}
547 602
548#define SCROLL_UP(lines, listlen) \ 603/*
549{ \ 604 * insert a single physical line (that must be short enough to fit)
550 int cur_line; \ 605 * at position "idx" by pushing up lines above it. the caller
551 struct logfile_entry *current; \ 606 * MUST then fill in lines[idx] with valid data.
607 */
608static void
609insert_line (int idx)
610{
611 int cur_line;
612 struct logfile_entry *current;
613
614 free (lines[0].line);
615
552 for (cur_line = 0; cur_line < (listlen - 1); cur_line++) { \ 616 for (cur_line = 0; cur_line < idx; cur_line++)
553 strcpy(lines[cur_line].line, lines[cur_line + 1].line); \
554 lines[cur_line].color = lines[cur_line + 1].color; \ 617 lines[cur_line] = lines[cur_line + 1];
555 } \ 618
556 for (current = loglist; current; current = current->next) \ 619 for (current = loglist; current; current = current->next)
557 if (current->partial && current->index) \ 620 if (current->index <= idx)
558 current->index--; \ 621 current->index--;
559} 622}
560 623
561void 624/*
625 * remove a single physical line at position "idx" by moving the lines above it
626 * down and inserting a "~" line at the top.
627 */
628static void
629delete_line (int idx)
630{
631 int cur_line;
632 struct logfile_entry *current;
633
634 for (cur_line = idx; cur_line > 0; cur_line--)
635 lines[cur_line] = lines[cur_line - 1];
636
637 lines[0].line = strdup ("~");
638
639 for (current = loglist; current; current = current->next)
640 if (current->index >= 0 && current->index <= idx)
641 current->index++;
642}
643
644/*
645 * takes a logical log file line and splits it into multiple physical
646 * screen lines by splitting it whenever a part becomes too long.
647 * lal lines will be inserted at position "idx".
648 */
649static void
650split_line (int idx, const char *str, unsigned long color)
651{
652 int l = strlen (str);
653 const char *p = str;
654
655 do
656 {
657 const char *beg = p;
658 int w = 0, wrapped = 0;
659 const char *break_p = NULL;
660
661 while (*p)
662 {
663 /* find the length in bytes of the next multibyte character */
664 int len = mblen (p, l);
665 if (len <= 0)
666 len = 1; /* ignore (don't skip) illegal character sequences */
667
668 /* find the width in pixels of the next character */
669 int cw = XmbTextEscapement (fontset, p, len);
670 if (cw + w >= width)
671 {
672 wrapped = 1;
673 break;
674 }
675
676 if (opt_wordwrap && len == 1 && p[0] == ' ')
677 break_p = p;
678
679 w += cw;
680 p += len;
681 l -= len;
682 }
683
684 /* if we're wrapping at spaces, and the line is long enough to
685 * wrap, and we've seen a space already, and the space wasn't
686 * the first character on the line, then wrap at the space */
687 if (opt_wordwrap && wrapped && break_p && break_p != beg)
688 {
689 l += p - break_p;
690 p = break_p;
691 }
692
693 {
694 char *s = xmalloc (p - beg + 1);
695 memcpy (s, beg, p - beg);
696 s[p - beg] = 0;
697 insert_line (idx);
698 lines[idx].line = s;
699 lines[idx].len = p - beg;
700 lines[idx].color = color;
701 }
702
703 /* if we wrapped at a space, don't display the space */
704 if (opt_wordwrap && wrapped && break_p && break_p != beg)
705 {
706 l--;
707 p++;
708 }
709 }
710 while (l);
711}
712
713/*
714 * append something to an existing physical line. this is done
715 * by deleting the file on-screen, concatenating the new data to it
716 * and splitting it again.
717 */
718static void
719append_line (int idx, const char *str)
720{
721 unsigned long color = lines[idx].color;
722 char *old = lines[idx].line;
723 char *new = concat_line (old, str);
724
725 free (old);
726
727 delete_line (idx);
728 split_line (idx, new, color);
729}
730
731static void
562main_loop (void) 732main_loop (void)
563{ 733{
564 struct linematrix *lines = xmalloc (sizeof (struct linematrix) * listlen); 734 lines = xmalloc (sizeof (struct linematrix) * listlen);
565 int lin, miny, maxy; 735 int lin;
566 time_t lastreload; 736 time_t lastreload;
567 Region region = XCreateRegion (); 737 Region region = XCreateRegion ();
568 XEvent xev; 738 XEvent xev;
569 struct logfile_entry *lastprinted = NULL; 739 struct logfile_entry *lastprinted = NULL;
570 struct logfile_entry *current; 740 struct logfile_entry *current;
741 int need_update = 1;
571 742
572 maxy = 0;
573 miny = win_y + height;
574 lastreload = time (NULL); 743 lastreload = time (NULL);
575 744
576 /* Initialize linematrix */ 745 /* Initialize linematrix */
577 for (lin = 0; lin < listlen; lin++) 746 for (lin = 0; lin < listlen; lin++)
578 { 747 {
579 lines[lin].line = xmalloc (width + 2); 748 lines[lin].line = strdup ("~");
580 strcpy (lines[lin].line, "~"); 749 lines[lin].len = 1;
581 lines[lin].color = GetColor (def_color); 750 lines[lin].color = GetColor (def_color);
582 } 751 }
583 752
584 /* show the display full of empty lines ("~") in case the first
585 * time around the loop doesn't produce any output, as it won't if
586 * either (a) -noinitial is set or (b) all the files are currently
587 * empty */
588 redraw ();
589
590 for (;;) 753 for (;;)
591 { 754 {
592 int need_update = 0;
593
594 /* read logs */ 755 /* read logs */
595 for (current = loglist; current; current = current->next) 756 for (current = loglist; current; current = current->next)
596 { 757 {
597 if (!current->fp) 758 if (!current->fp)
598 continue; /* skip missing files */ 759 continue; /* skip missing files */
599 760
600 clearerr (current->fp); 761 clearerr (current->fp);
601 762
602 while (lineinput (current) != 0) 763 while (lineinput (current))
603 { 764 {
765 need_update = 1;
604 /* if we're trying to update old partial lines in 766 /* if we're trying to update old partial lines in
605 * place, and the last time this file was updated the 767 * place, and the last time this file was updated the
606 * output was partial, and that partial line is not 768 * output was partial, and that partial line is not
607 * too close to the top of the screen, then update 769 * too close to the top of the screen, then update
608 * that partial line */ 770 * that partial line */
609 if (opt_update && current->lastpartial && current->index >= 3) 771 if (opt_update && current->lastpartial && current->index >= 0)
610 { 772 {
611 int old_len = strlen (lines[current->index].line); 773 int idx = current->index;
612 int new_len = strlen (current->buf); 774 append_line (idx, current->buf);
613 int space_on_old_line = width / font_width - old_len; //D 775 current->index = idx;
614 776 free (current->buf), current->buf = 0;
615 strncat (lines[current->index].line, current->buf,
616 width - old_len);
617 /* if we can't fit the whole update into the old
618 * partial line then we're going to have to print
619 * the rest of it at the bottom on the screen */
620 if (new_len > space_on_old_line)
621 {
622 /* strcpy() doesn't like the strings to
623 * overlap in memory, but memmove() doesn't
624 * care */
625 memmove (current->buf,
626 current->buf + space_on_old_line,
627 new_len - space_on_old_line + 1);
628 }
629 else
630 {
631 need_update = 1;
632 strcpy (current->buf, "");
633 continue; 777 continue;
634 }
635 } 778 }
636 779
637 /* print filename if any, and if last line was from 780 /* print filename if any, and if last line was from
638 * different file */ 781 * different file */
639 if (!opt_nofilename &&
640 lastprinted != current && current->desc[0]) 782 if (!opt_nofilename && lastprinted != current && current->desc[0])
641 { 783 {
642 SCROLL_UP (lines, listlen); 784 char buf[1024]; /* HACK */
643 sprintf (lines[listlen - 1].line, "[%s]", current->desc); 785 snprintf (buf, sizeof (buf), "[%s]", current->desc);
644 lines[listlen - 1].color = current->color; 786 split_line (listlen - 1, buf, current->color);
645 } 787 }
646 788
647 /* if this is the same file we showed last, and the 789 /* if this is the same file we showed last, and the
648 * last time we showed it, it wasn't finished, then 790 * last time we showed it, it wasn't finished, then
649 * append to the last line shown */ 791 * append to the last line shown */
650 if (lastprinted == current && current->lastpartial) 792 if (lastprinted == current && current->lastpartial)
651 { 793 append_line (listlen - 1, current->buf);
652 int old_len = strlen (lines[listlen - 1].line);
653 int new_len = strlen (current->buf);
654 strncat (lines[listlen - 1].line, current->buf,
655 width - old_len);
656 /* if it doesn't all fit, then put the part that
657 * doesn't fit on a new line */
658 if (new_len > width - old_len)
659 {
660 SCROLL_UP (lines, listlen);
661 strcpy (lines[listlen - 1].line,
662 current->buf + width - old_len);
663 }
664 /* show the 'continuation' string because we've got a
665 * continued partial line, but we weren't able to
666 * append it to the old displayed partial line */
667 }
668 else if (current->lastpartial) 794 else if (current->lastpartial)
669 { 795 {
670 int old_len = strlen (continuation); 796 split_line (listlen - 1, continuation, current->color);
671 int new_len = strlen (current->buf);
672 SCROLL_UP (lines, listlen);
673 strcpy (lines[listlen - 1].line, continuation);
674 strncat (lines[listlen - 1].line, current->buf, 797 append_line (listlen - 1, current->buf);
675 width - old_len); 798 }
676 /* it might not fit, now that we've displayed the
677 * continuation string, so we may need to 'wrap' it */
678 if (new_len > width - old_len)
679 {
680 SCROLL_UP (lines, listlen);
681 strcpy (lines[listlen - 1].line,
682 current->buf + width - old_len);
683 }
684 }
685 else 799 else
686 { 800 split_line (listlen - 1, current->buf, current->color);
687 SCROLL_UP (lines, listlen);
688 strcpy (lines[listlen - 1].line, current->buf);
689 }
690 801
691 /* we've shown the line now. clear the buffer for the next line */ 802 free (current->buf), current->buf = 0;
692 strcpy (current->buf, "");
693 current->index = listlen - 1; 803 current->index = listlen - 1;
694 lines[listlen - 1].color = current->color;
695
696 lastprinted = current; 804 lastprinted = current;
697 need_update = 1;
698 } 805 }
699 } 806 }
700 807
701 if (need_update) 808 if (need_update)
809 {
702 redraw (); 810 redraw ();
811 need_update = 0;
812 }
703 else 813 else
704 { 814 {
705 XFlush (disp); 815 XFlush (disp);
706 816
707 if (!XPending (disp)) 817 if (!XPending (disp))
733 843
734 r.x = xev.xexpose.x; 844 r.x = xev.xexpose.x;
735 r.y = xev.xexpose.y; 845 r.y = xev.xexpose.y;
736 r.width = xev.xexpose.width; 846 r.width = xev.xexpose.width;
737 r.height = xev.xexpose.height; 847 r.height = xev.xexpose.height;
848
738 XUnionRectWithRegion (&r, region, region); 849 XUnionRectWithRegion (&r, region, region);
739 if (miny > r.y)
740 miny = r.y;
741 if (maxy < r.y + r.height)
742 maxy = r.y + r.height;
743 } 850 }
744 break; 851 break;
745 default: 852 default:
746#ifdef DEBUGMODE 853#ifdef DEBUGMODE
747 fprintf (stderr, "PANIC! Unknown event %d\n", xev.type); 854 fprintf (stderr, "PANIC! Unknown event %d\n", xev.type);
760 lastreload = time (NULL); 867 lastreload = time (NULL);
761 } 868 }
762 869
763 if (!XEmptyRegion (region)) 870 if (!XEmptyRegion (region))
764 { 871 {
872 XRectangle r;
873
765 XSetRegion (disp, WinGC, region); 874 XSetRegion (disp, WinGC, region);
875 XClipBox (region, &r);
766 876
767 refresh (lines, miny, maxy); 877 refresh (r.y, r.y + r.height, 0);
878
768 XDestroyRegion (region); 879 XDestroyRegion (region);
769 region = XCreateRegion (); 880 region = XCreateRegion ();
770 maxy = 0;
771 miny = win_y + height;
772 } 881 }
773 } 882 }
774} 883}
775 884
776 885
814 continuation = argv[++i]; 923 continuation = argv[++i];
815 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn")) 924 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn"))
816 fontname = argv[++i]; 925 fontname = argv[++i];
817#if HAS_REGEX 926#if HAS_REGEX
818 else if (!strcmp (arg, "-t")) 927 else if (!strcmp (arg, "-t"))
928 {
819 transform = argv[++i]; 929 transform = argv[++i];
930 transform_to = argv[++i];
931 printf("transform: '%s' to '%s'\n", transform, transform_to);
932 }
820#endif 933#endif
821 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f")) 934 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f"))
822 opt_daemonize = 1; 935 opt_daemonize = 1;
823 else if (!strcmp (arg, "-reload")) 936 else if (!strcmp (arg, "-reload"))
824 { 937 {
825 reload = atoi (argv[++i]); 938 reload = atoi (argv[++i]);
826 command = argv[++i]; 939 command = argv[++i];
827 } 940 }
828 else if (!strcmp (arg, "-shade")) 941 else if (!strcmp (arg, "-shade"))
829 opt_shade = 1; 942 opt_shade = 1;
943 else if (!strcmp (arg, "-outline"))
944 opt_outline = 1;
945 else if (!strcmp (arg, "-noflicker"))
946 opt_noflicker = 1;
830 else if (!strcmp (arg, "-frame")) 947 else if (!strcmp (arg, "-frame"))
831 opt_frame = 1; 948 opt_frame = 1;
832 else if (!strcmp (arg, "-no-filename")) 949 else if (!strcmp (arg, "-no-filename"))
833 opt_nofilename = 1; 950 opt_nofilename = 1;
834 else if (!strcmp (arg, "-reverse")) 951 else if (!strcmp (arg, "-reverse"))
837 opt_whole = 1; 954 opt_whole = 1;
838 else if (!strcmp (arg, "-partial")) 955 else if (!strcmp (arg, "-partial"))
839 opt_partial = 1; 956 opt_partial = 1;
840 else if (!strcmp (arg, "-update")) 957 else if (!strcmp (arg, "-update"))
841 opt_update = opt_partial = 1; 958 opt_update = opt_partial = 1;
959 else if (!strcmp (arg, "-wordwrap"))
960 opt_wordwrap = 1;
842 else if (!strcmp (arg, "-color")) 961 else if (!strcmp (arg, "-color"))
843 def_color = argv[++i]; 962 def_color = argv[++i];
844 else if (!strcmp (arg, "-noinitial")) 963 else if (!strcmp (arg, "-noinitial"))
845 opt_noinitial = 1; 964 opt_noinitial = 1;
846 else if (!strcmp (arg, "-id")) 965 else if (!strcmp (arg, "-id"))
880 desc = p + 1; 999 desc = p + 1;
881 } 1000 }
882 } 1001 }
883 1002
884 e = xmalloc (sizeof (struct logfile_entry)); 1003 e = xmalloc (sizeof (struct logfile_entry));
1004 e->partial = 0;
1005 e->buf = 0;
1006 e->index = -1;
1007
885 if (arg[0] == '-' && arg[1] == '\0') 1008 if (arg[0] == '-' && arg[1] == '\0')
886 { 1009 {
887 if ((e->fp = fdopen (0, "r")) == NULL) 1010 if ((e->fp = fdopen (0, "r")) == NULL)
888 perror ("fdopen"), exit (1); 1011 perror ("fdopen"), exit (1);
889 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) 1012 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0)
907 memcpy (e->desc, desc, l); 1030 memcpy (e->desc, desc, l);
908 *(e->desc + l) = '\0'; 1031 *(e->desc + l) = '\0';
909 } 1032 }
910 1033
911 e->color = GetColor (fcolor); 1034 e->color = GetColor (fcolor);
912 e->buf = xmalloc (width + 2);
913 e->partial = 0; 1035 e->partial = 0;
914 e->buf[0] = '\0';
915 e->next = NULL; 1036 e->next = NULL;
916 1037
917 if (!loglist) 1038 if (!loglist)
918 loglist = e; 1039 loglist = e;
919 if (loglist_tail) 1040 if (loglist_tail)
945#if HAS_REGEX 1066#if HAS_REGEX
946 if (transform) 1067 if (transform)
947 { 1068 {
948 int i; 1069 int i;
949 1070
1071 printf("compiling regexp '%s'\n", transform);
950 transformre = xmalloc (sizeof (transformre)); 1072 transformre = xmalloc (sizeof (regex_t));
951 i = regcomp (&transformre, transform, REG_EXTENDED); 1073 i = regcomp (transformre, transform, REG_EXTENDED);
952 if (i != 0) 1074 if (i != 0)
953 { 1075 {
954 char buf[512]; 1076 char buf[512];
955 1077
956 regerror (i, &transformre, buf, sizeof (buf)); 1078 regerror (i, transformre, buf, sizeof (buf));
957 fprintf (stderr, "Cannot compile regular expression: %s\n", buf); 1079 fprintf (stderr, "Cannot compile regular expression: %s\n", buf);
958 } 1080 }
1081 else
1082 {
1083 printf("compiled '%s' OK to %x\n", transform, (int)transformre);
1084 }
959 } 1085 }
960#endif 1086#endif
961 1087
962 InitWindow (); 1088 InitWindow ();
963 1089
1011 while ((p = malloc (size)) == NULL) 1137 while ((p = malloc (size)) == NULL)
1012 { 1138 {
1013 fprintf (stderr, "Memory exausted."); 1139 fprintf (stderr, "Memory exausted.");
1014 sleep (10); 1140 sleep (10);
1015 } 1141 }
1142
1016 return p; 1143 return p;
1017} 1144}
1018 1145
1019void 1146void
1020display_help (char *myname) 1147display_help (char *myname)
1030 " -reverse print new lines at the top\n" 1157 " -reverse print new lines at the top\n"
1031 " -whole wait for \\n before showing a line\n" 1158 " -whole wait for \\n before showing a line\n"
1032 " -partial show lines even if they don't end with a \\n\n" 1159 " -partial show lines even if they don't end with a \\n\n"
1033 " -update allow updates to old partial lines\n" 1160 " -update allow updates to old partial lines\n"
1034 " -cont string to prefix continued partial lines with\n" 1161 " -cont string to prefix continued partial lines with\n"
1162 " -wordwrap wrap long lines at spaces to avoid breaking words\n"
1035 " defaults to \"[+]\"\n" 1163 " defaults to \"[+]\"\n"
1036 " -shade add shading to font\n" 1164 " -shade add shading to font\n"
1037 " -noinitial don't display the last file lines on\n" 1165 " -noinitial don't display the last file lines on\n"
1038 " startup\n" 1166 " startup\n"
1039 " -i | -interval seconds interval between checks (fractional\n" 1167 " -i | -interval seconds interval between checks (fractional\n"
1040 " values o.k.). Default 3 seconds\n" 1168 " values o.k.). Default 2.4 seconds\n"
1041 " -V display version information and exit\n" 1169 " -V display version information and exit\n"
1042 "\n"); 1170 "\n");
1043 printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green " 1171 printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green "
1044 "/var/log/secure,red,'ALERT'\n", myname); 1172 "/var/log/secure,red,'ALERT'\n", myname);
1045 exit (0); 1173 exit (0);
1053} 1181}
1054 1182
1055int 1183int
1056daemonize (void) 1184daemonize (void)
1057{ 1185{
1186 pid_t pid;
1187
1058 switch (fork ()) 1188 switch (pid = fork ())
1059 { 1189 {
1060 case -1: 1190 case -1:
1061 return -1; 1191 return -1;
1062 case 0: 1192 case 0:
1063 break; 1193 break;
1064 default: 1194 default:
1195 printf("%d\n", pid);
1065 _exit (0); 1196 exit (0);
1066 } 1197 }
1067 1198
1068 if (setsid () == -1) 1199 if (setsid () == -1)
1069 return -1; 1200 return -1;
1070 1201

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines