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.38 by pcg, Wed Mar 31 01:50:24 2004 UTC vs.
Revision 1.49 by chris_moore, Wed Apr 7 03:54:30 2004 UTC

20 * along with this program; if not, write to the Free Software 20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22 */ 22 */
23 23
24#include "config.h" 24#include "config.h"
25#include <assert.h>
25#include <stdlib.h> 26#include <stdlib.h>
26#include <stdio.h> 27#include <stdio.h>
27#include <unistd.h> 28#include <unistd.h>
28#include <string.h> 29#include <string.h>
29#include <signal.h> 30#include <signal.h>
50/* data structures */ 51/* data structures */
51struct logfile_entry 52struct logfile_entry
52{ 53{
53 struct logfile_entry *next; 54 struct logfile_entry *next;
54 55
55 char *fname; /* name of file */ 56 char *fname; /* name of file */
56 char *desc; /* alternative description */ 57 char *desc; /* alternative description */
57 char *buf; /* text read but not yet displayed */ 58 char *buf; /* text read but not yet displayed */
58 FILE *fp; /* FILE struct associated with file */ 59 FILE *fp; /* FILE struct associated with file */
59 ino_t inode; /* inode of the file opened */ 60 ino_t inode; /* inode of the file opened */
60 off_t last_size; /* file size at the last check */ 61 off_t last_size; /* file size at the last check */
61 unsigned long color; /* color to be used for printing */ 62 unsigned long color; /* color to be used for printing */
62 int partial; /* true if the last line isn't complete */ 63 int partial; /* true if the last line isn't complete */
63 int lastpartial; /* true if the previous output wasn't complete */ 64 int lastpartial; /* true if the previous output wasn't complete */
64 int index; /* index into linematrix of a partial line */ 65 struct line_node *last; /* last line we output */
65 int modified; /* true if line is modified & needs displaying */ 66 int modified; /* true if line is modified & needs displaying */
66}; 67};
67 68
68struct linematrix 69struct line_node
69{ 70{
70 char *line; 71 struct line_node *next;
71 int len; 72 struct line_node *prev;
72 unsigned long color; 73 struct logfile_entry *logfile;
74
75 char *line; /* the text of the line (so far) */
76 int len; /* the length of the line (in bytes) so far */
77 int wrapped_left; /* true if wrapped from the previous line */
78 int wrapped_right; /* true if wrapped to the next line */
79 struct breakinfo *breaks; /* array of indicies to spaces if wrapped_right */
80 int num_words; /* the number of words in the line */
81 int free_pixels; /* the number of free pixels to spread out */
82};
83
84struct breakinfo
85{
86 int index; /* index into string of start of substring */
87 int width; /* width in pixels of start of substring */
88 int len; /* length of substring */
73}; 89};
74 90
75struct displaymatrix 91struct displaymatrix
76{ 92{
77 char *line; 93 char *line;
78 int len; 94 int len;
79 int buffer_size; 95 int buffer_size;
96 unsigned long color;
80}; 97};
81 98
82/* global variables */ 99/* global variables */
83struct linematrix *lines; 100int debug = 1;
101
102struct line_node *linelist = NULL, *linelist_tail = NULL;
84struct displaymatrix *display; 103struct displaymatrix *display;
104int continuation_width = -1;
105int continuation_color;
106int continuation_length;
107
85int width = STD_WIDTH, height = STD_HEIGHT, listlen; 108int width = STD_WIDTH, height = STD_HEIGHT, listlen;
86int win_x = LOC_X, win_y = LOC_Y; 109int win_x = LOC_X, win_y = LOC_Y;
87int font_ascent, font_height; 110int font_ascent, font_height;
88int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */ 111int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */
89int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */ 112int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */
92XFontSet fontset; 115XFontSet fontset;
93 116
94/* command line options */ 117/* command line options */
95int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename, 118int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename,
96 opt_outline, opt_noflicker, opt_whole, opt_update, opt_wordwrap, 119 opt_outline, opt_noflicker, opt_whole, opt_update, opt_wordwrap,
97 geom_mask, reload = 0; 120 opt_justify, geom_mask, reload = 0;
98const char *command = NULL, 121const char *command = NULL,
99 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR, 122 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR,
100 *continuation = "[+]"; 123 *continuation = "|| ", *cont_color = DEF_CONT_COLOR;
101 124
102struct logfile_entry *loglist = NULL, *loglist_tail = NULL; 125struct logfile_entry *loglist = NULL, *loglist_tail = NULL;
103 126
104Display *disp; 127Display *disp;
105Window root; 128Window root;
318 win_y = win_y + ScreenHeight - height; 341 win_y = win_y + ScreenHeight - height;
319 342
320 if (opt_outline) 343 if (opt_outline)
321 { 344 {
322 /* adding outline increases the total width and height by 2 345 /* adding outline increases the total width and height by 2
323 pixels each, and offsets the text one pixel right and one 346 pixels each, and offsets the text one pixel right and one
324 pixel down */ 347 pixel down */
325 effect_x_space = effect_y_space = 2; 348 effect_x_space = effect_y_space = 2;
326 effect_x_offset = effect_y_offset = 1; 349 effect_x_offset = effect_y_offset = 1;
327 } 350 }
328 else if (opt_shade) 351 else if (opt_shade)
329 { 352 {
330 /* adding a shadow increases the space used */ 353 /* adding a shadow increases the space used */
331 effect_x_space = abs(SHADE_X); 354 effect_x_space = abs (SHADE_X);
332 effect_y_space = abs(SHADE_Y); 355 effect_y_space = abs (SHADE_Y);
333 /* if the shadow is to the right and below then we don't need 356 /* if the shadow is to the right and below then we don't need
334 * to move the text to make space for it, but shadows to the left 357 * to move the text to make space for it, but shadows to the left
335 * and above need accomodating */ 358 * and above need accomodating */
336 effect_x_offset = SHADE_X > 0 ? 0 : -SHADE_X; 359 effect_x_offset = SHADE_X > 0 ? 0 : -SHADE_X;
337 effect_y_offset = SHADE_Y > 0 ? 0 : -SHADE_Y; 360 effect_y_offset = SHADE_Y > 0 ? 0 : -SHADE_Y;
351 fprintf (stderr, "height too small for a single line, setting to %d\n", 374 fprintf (stderr, "height too small for a single line, setting to %d\n",
352 font_height); 375 font_height);
353 listlen = 1; 376 listlen = 1;
354 } 377 }
355 378
356 /* leave the height how the user requested it. it might not all be
357 * used, but this will allow the geometry to be tuned more accurately
358 * (with the -frame option)
359 * the old code did this:
360 * height = listlen * font_height + effect_y_space; */
361
362 XSelectInput (disp, root, ExposureMask | FocusChangeMask); 379 XSelectInput (disp, root, ExposureMask | FocusChangeMask);
363} 380}
364 381
365/* 382/*
366 * if redraw() is passwd a non-zero argument, it does a complete 383 * if redraw () is passwd a non-zero argument, it does a complete
367 * redraw, rather than an update. if the argument is zero (and 384 * redraw, rather than an update. if the argument is zero (and
368 * -noflicker is in effect) then only the lines which have changed 385 * -noflicker is in effect) then only the lines which have changed
369 * since the last draw are redrawn. 386 * since the last draw are redrawn.
370 * 387 *
371 * the rest is handled by regular refresh()'es 388 * the rest is handled by regular refresh ()'es
372 */ 389 */
373void 390void
374redraw (int redraw_all) 391redraw (int redraw_all)
375{ 392{
376 XSetClipMask (disp, WinGC, None); 393 XSetClipMask (disp, WinGC, None);
377 refresh (0, 32768, 1, redraw_all); 394 refresh (0, 32768, 1, redraw_all);
378} 395}
379 396
397void draw_text (Display *disp, Window root, XFontSet fontset, GC WinGC, int x, int y, struct line_node *line, int foreground)
398{
399 if (line->wrapped_right && opt_justify && line->breaks)
400 {
401 int i;
402 for (i = 0; i < line->num_words; i++) {
403 XmbDrawString (disp, root, fontset, WinGC,
404 x + line->breaks[i].width + ((i * line->free_pixels) / (line->num_words - 1)) + continuation_width * line->wrapped_left, y,
405 line->line + line->breaks[i].index,
406 line->breaks[i].len);
407 }
408 if (line->wrapped_left)
409 {
410 if (foreground) XSetForeground (disp, WinGC, continuation_color);
411 XmbDrawString (disp, root, fontset, WinGC, x, y, continuation, continuation_length);
412 }
413 }
414 else
415 {
416 XmbDrawString (disp, root, fontset, WinGC, x + continuation_width * line->wrapped_left, y, line->line, line->len);
417 if (line->wrapped_left)
418 {
419 if (foreground) XSetForeground (disp, WinGC, continuation_color);
420 XmbDrawString (disp, root, fontset, WinGC, x, y, continuation, continuation_length);
421 }
422 }
423}
424
380/* Just redraw everything without clearing (i.e. after an EXPOSE event) */ 425/* Just redraw everything without clearing (i.e. after an EXPOSE event) */
381void 426void
382refresh (int miny, int maxy, int clear, int refresh_all) 427refresh (int miny, int maxy, int clear, int refresh_all)
383{ 428{
384 int lin; 429 int lin = 0;
385 int offset = listlen * font_height + font_ascent + effect_y_offset; 430 int offset;
386 unsigned long black_color = GetColor ("black"); 431 unsigned long black_color = GetColor ("black");
432 struct line_node *line;
433 int step_per_line;
434 int foreground = 0;
435
436 if (opt_reverse)
437 {
438 step_per_line = font_height;
439 offset = font_ascent + effect_y_offset;
440 }
441 else
442 {
443 step_per_line = -font_height;
444 offset = (listlen - 1) * font_height + font_ascent + effect_y_offset;
445 }
387 446
388 miny -= win_y + font_height; 447 miny -= win_y + font_height;
389 maxy -= win_y - font_height; 448 maxy -= win_y - font_height;
390 449
391 if (clear && !opt_noflicker) 450 if (clear && !opt_noflicker)
392 XClearArea (disp, root, win_x, win_y, width, height, False); 451 XClearArea (disp, root, win_x, win_y, width, height, False);
393 452
394 for (lin = listlen; lin--;) 453 for (line = linelist; line && lin < listlen; line = line->next, lin++, offset += step_per_line)
395 { 454 {
396 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin);
397 struct displaymatrix *display_line = display + lin; 455 struct displaymatrix *display_line = display + lin;
398
399 offset -= font_height;
400 456
401 if (offset < miny || offset > maxy) 457 if (offset < miny || offset > maxy)
402 continue; 458 continue;
403 459
404 /* if this line is a different than it was, then it 460 /* if this line is a different than it was, then it
405 * needs displaying */ 461 * needs displaying */
406 if (!opt_noflicker 462 if (!opt_noflicker
407 || refresh_all 463 || refresh_all
408 || display_line->len != line->len 464 || display_line->len != line->len
465 || display_line->color != line->logfile->color
409 || memcmp (display_line->line, line->line, line->len)) 466 || memcmp (display_line->line, line->line, line->len))
410 { 467 {
411 /* don't bother updating the record of what has been 468 /* don't bother updating the record of what has been
412 * displayed if -noflicker isn't in effect, since we redraw 469 * displayed if -noflicker isn't in effect, since we redraw
413 * the whole display every time anyway */ 470 * the whole display every time anyway */
414 if (opt_noflicker) 471 if (opt_noflicker)
415 { 472 {
416 /* update the record of what has been displayed; 473 /* update the record of what has been displayed;
417 * first make sure the buffer is big enough */ 474 * first make sure the buffer is big enough */
418 if (display_line->buffer_size <= line->len) 475 if (display_line->buffer_size < line->len)
419 { 476 {
420 display_line->buffer_size = line->len + 1; 477 display_line->buffer_size = line->len;
421 display_line->line = xrealloc (display_line->line, display_line->buffer_size); 478 display_line->line = xrealloc (display_line->line, display_line->buffer_size);
422 } 479 }
423 480
424 display_line->len = line->len; 481 display_line->len = line->len;
482 display_line->color = line->logfile->color;
425 memcpy (display_line->line, line->line, line->len); 483 memcpy (display_line->line, line->line, line->len);
426 484
427 if (clear) 485 if (clear)
428 XClearArea (disp, root, win_x, win_y + offset - font_ascent, 486 XClearArea (disp, root, win_x, win_y + offset - font_ascent,
429 width + effect_x_space, font_height + effect_y_space, False); 487 width + effect_x_space, font_height + effect_y_space, False);
430 } 488 }
431 489
432 if (opt_outline) 490 if (opt_outline)
433 { 491 {
434 int x, y; 492 int x, y;
435 XSetForeground (disp, WinGC, black_color); 493 XSetForeground (disp, WinGC, black_color);
436 494
437 for (x = -1; x < 2; x += 2) 495 for (x = -1; x <= 1; x += 2)
438 for (y = -1; y < 2; y += 2) 496 for (y = -1; y <= 1; y += 2)
439 XmbDrawString (disp, root, fontset, WinGC, 497 draw_text (disp, root, fontset, WinGC,
440 win_x + effect_x_offset + x, 498 win_x + effect_x_offset + x,
441 win_y + y + offset, 499 win_y + y + offset, line, foreground = 0);
442 line->line, line->len);
443 } 500 }
444 else if (opt_shade) 501 else if (opt_shade)
445 { 502 {
446 XSetForeground (disp, WinGC, black_color); 503 XSetForeground (disp, WinGC, black_color);
447 XmbDrawString (disp, root, fontset, WinGC, 504 draw_text (disp, root, fontset, WinGC,
448 win_x + effect_x_offset + SHADE_X, 505 win_x + effect_x_offset + SHADE_X,
449 win_y + offset + SHADE_Y, 506 win_y + offset + SHADE_Y, line, foreground = 0);
450 line->line, line->len);
451 } 507 }
452 508
453 XSetForeground (disp, WinGC, line->color); 509 XSetForeground (disp, WinGC, line->logfile->color);
454 XmbDrawString (disp, root, fontset, WinGC, 510 draw_text (disp, root, fontset, WinGC,
455 win_x + effect_x_offset, 511 win_x + effect_x_offset,
456 win_y + offset, 512 win_y + offset, line, foreground = 1);
457 line->line, line->len); 513 }
458 } 514 }
515
516 /* any lines that didn't just get looked at are never going to be, so break the chain */
517 if (line) line->prev->next = 0;
518
519 /* and throw them all away */
520 while (line)
521 {
522 struct line_node *this = line;
523 line = line->next;
524 if (this->logfile && this->logfile->last == this)
525 this->logfile->last = NULL;
526 free (this->line);
527 free (this->breaks);
528 free (this);
459 } 529 }
460 530
461 if (opt_frame) 531 if (opt_frame)
462 { 532 {
463 XSetForeground (disp, WinGC, GetColor (def_color)); 533 XSetForeground (disp, WinGC, GetColor (def_color));
485 regmatch_t matched[16]; 555 regmatch_t matched[16];
486 556
487 i = regexec (transformre, s, 16, matched, 0); 557 i = regexec (transformre, s, 16, matched, 0);
488 if (i == 0) 558 if (i == 0)
489 { /* matched */ 559 { /* matched */
490 int match_start = matched[0].rm_so; 560 int match_start = matched[0].rm_so;
491 int match_end = matched[0].rm_eo; 561 int match_end = matched[0].rm_eo;
492 int old_len = match_end - match_start; 562 int old_len = match_end - match_start;
493 int new_len = strlen(transform_to); 563 int new_len = strlen (transform_to);
494 int old_whole_len = strlen(s); 564 int old_whole_len = strlen (s);
565
495 printf("regexp was matched by '%s' - replace with '%s'\n", s, transform_to); 566 printf ("regexp was matched by '%s' - replace with '%s'\n", s, transform_to);
496 printf("match is from %d to %d\n", 567 printf ("match is from %d to %d\n", match_start, match_end);
497 match_start, match_end);
498 if (new_len > old_len) { 568 if (new_len > old_len)
499 s = xrealloc(s, old_whole_len + new_len - old_len); 569 s = xrealloc (s, old_whole_len + new_len - old_len);
500 } 570
501 if (new_len != old_len) { 571 if (new_len != old_len)
572 {
502 memcpy(s + match_end + new_len - old_len, 573 memcpy (s + match_end + new_len - old_len,
503 s + match_end, 574 s + match_end,
504 old_whole_len - match_end); 575 old_whole_len - match_end);
505 s[old_whole_len + new_len - old_len] = '\0'; 576 s[old_whole_len + new_len - old_len] = '\0';
506 } 577 }
578
507 memcpy(s + match_start, 579 memcpy (s + match_start,
508 transform_to, 580 transform_to,
509 new_len); 581 new_len);
510 printf("transformed to '%s'\n", s); 582 printf ("transformed to '%s'\n", s);
511 } 583 }
512 else 584 else
513 {
514 printf("regexp was not matched by '%s'\n", s); 585 printf ("regexp was not matched by '%s'\n", s);
515 }
516 } 586 }
517} 587}
518#endif 588#endif
519 589
590/*
591 * appends p2 to the end of p1, if p1 is not null
592 * otherwise allocates a new string and copies p2 to it
593 */
520char * 594char *
521concat_line (const char *p1, const char *p2) 595concat_line (char *p1, const char *p2)
522{ 596{
597 assert(p2);
598
523 int l1 = p1 ? strlen (p1) : 0; 599 int l1 = p1 ? strlen (p1) : 0;
524 int l2 = strlen (p2); 600 int l2 = strlen (p2);
525 char *r = xmalloc (l1 + l2 + 1); 601 char *r;
526 602
527 memcpy (r, p1, l1); 603 if (p1)
604 r = xrealloc(p1, l1 + l2 + 1);
605 else
606 r = xmalloc (l2 + 1);
607
528 memcpy (r + l1, p2, l2); 608 memcpy (r + l1, p2, l2);
529 r[l1 + l2] = 0; 609 r[l1 + l2] = 0;
530 610
531 return r; 611 return r;
532} 612}
533 613
534/* 614/*
535 * HACK-1: This routine should read a single line, no matter how long. 615 * This routine can read a line of any length if it is called enough times.
536 */ 616 */
537int 617int
538lineinput (struct logfile_entry *logfile) 618lineinput (struct logfile_entry *logfile)
539{ 619{
540 char buff[1024], *p = buff; 620 char buff[1024], *p;
541 int ch; 621 int ch;
542 /* HACK-2: add on the length of any partial line which we will be appending to */ 622 /* 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; 623 int ofs = logfile->buf ? strlen (logfile->buf) : 0;
544 624
625 /* this loop ensures that the whole line is read, even if it's
626 * longer than the buffer. we need to do this because when --whole
627 * is in effect we don't know whether to display the line or not
628 * until we've seen how (ie. whether) it ends */
545 do 629 do
546 { 630 {
631 p = buff;
632 do
633 {
547 ch = fgetc (logfile->fp); 634 ch = fgetc (logfile->fp);
548 635
549 if (ch == '\n' || ch == EOF) 636 if (ch == '\n' || ch == EOF)
550 break; 637 break;
551 else if (ch == '\r') 638 else if (ch == '\r')
552 continue; /* skip */ 639 continue; /* skip */
553 else if (ch == '\t') 640 else if (ch == '\t')
554 { 641 {
555 do 642 do
556 { 643 {
557 *p++ = ' '; 644 *p++ = ' ';
645 ofs++;
646 }
647 while (ofs & 7);
648 }
649 else
650 {
651 *p++ = ch;
558 ofs++; 652 ofs++;
559 } 653 }
560 while (ofs & 7);
561 }
562 else
563 { 654 }
564 *p++ = ch;
565 ofs++;
566 }
567 }
568 while (p < buff + (sizeof buff) - 8 - 1); 655 while (p < buff + (sizeof buff) - 8 - 1);
569 656
570 if (p == buff && ch == EOF) 657 if (p == buff && ch == EOF)
571 return 0; 658 return 0;
572 659
573 *p = 0; 660 *p = 0;
574 661
575 p = concat_line (logfile->buf, buff); 662 p = logfile->buf = concat_line (logfile->buf, buff);
576 free (logfile->buf); logfile->buf = p; 663 }
664 while (ch != '\n' && ch != EOF);
577 665
578 logfile->lastpartial = logfile->partial; 666 logfile->lastpartial = logfile->partial;
579 /* there are 3 ways we could have exited the loop: reading '\n', 667 /* 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 668 * reaching EOF, or filling the buffer; the 2nd and 3rd of these
581 * both result in a partial line */ 669 * both result in a partial line */
617 file->inode = stats.st_ino; 705 file->inode = stats.st_ino;
618 706
619 if (opt_noinitial) 707 if (opt_noinitial)
620 fseek (file->fp, 0, SEEK_END); 708 fseek (file->fp, 0, SEEK_END);
621 else if (stats.st_size > (listlen + 1) * width) 709 else if (stats.st_size > (listlen + 1) * width)
710 /* HACK - 'width' is in pixels - how are we to know how much text will fit? */
622 fseek (file->fp, -((listlen + 2) * width), SEEK_END); 711 fseek (file->fp, -((listlen + 2) * width/10), SEEK_END);
623 712
624 file->last_size = stats.st_size; 713 file->last_size = stats.st_size;
625 return file->fp; 714 return file->fp;
626} 715}
627 716
670 { /* file renamed? */ 759 { /* file renamed? */
671 if (e->fp) 760 if (e->fp)
672 fclose (e->fp); 761 fclose (e->fp);
673 if (openlog (e) == NULL) 762 if (openlog (e) == NULL)
674 continue; 763 continue;
764 if (fstat (fileno (e->fp), &stats) < 0)
765 continue;
675 } 766 }
676 767
677 if (stats.st_size < e->last_size) 768 if (stats.st_size < e->last_size)
678 { /* file truncated? */ 769 { /* file truncated? */
679 fseek (e->fp, 0, SEEK_SET); 770 fseek (e->fp, 0, SEEK_SET);
681 } 772 }
682 } 773 }
683} 774}
684 775
685/* 776/*
686 * insert a single physical line (that must be short enough to fit) 777 * insert a single node in the list of screen lines and return a
687 * at position "idx" by pushing up lines above it. the caller 778 * pointer to the new node.
688 * MUST then fill in lines[idx] with valid data. 779 * the caller MUST then fill in ret->line and ret->len with valid
780 * data.
781 */
782static struct line_node *
783new_line_node (struct logfile_entry *log)
784{
785 struct line_node *new = xmalloc (sizeof (struct line_node));
786
787 new->logfile = log;
788 new->wrapped_left = 0;
789 new->wrapped_right = 0;
790 new->breaks = 0;
791
792 assert(log);
793
794 if (!log || !log->last)
795 {
796 new->next = linelist;
797 new->next->prev = new;
798
799 new->prev = NULL;
800 linelist = new;
801 }
802 else
803 {
804 /* 2 pointers from the new node */
805 new->next = log->last;
806 new->prev = log->last->prev;
807
808 /* 2 pointers back to the new node */
809 if (new->next) new->next->prev = new;
810 if (new->prev) new->prev->next = new;
811
812 /* if this is a new first entry in the list then update
813 * 'linelist' */
814 if (log->last == linelist)
815 linelist = new;
816 }
817
818 /* update the logfile record */
819 if (log)
820 log->last = new;
821
822 return new;
823}
824
825/*
826 * this is called after either adding a new line or appending to an
827 * old one. in both cases it's possible that the line no longer fits,
828 * and needs wrapping. this function checks the last line associated
829 * with the supplied logfile.
689 */ 830 */
690static void 831static void
691insert_line (int idx) 832possibly_split_long_line (struct logfile_entry *log)
692{ 833{
693 int cur_line; 834 char *str = log->last->line;
694 struct logfile_entry *current;
695
696 free (lines[0].line);
697
698 for (cur_line = 0; cur_line < idx; cur_line++)
699 lines[cur_line] = lines[cur_line + 1];
700
701 for (current = loglist; current; current = current->next)
702 if (current->index <= idx)
703 current->index--;
704}
705
706/*
707 * remove a single physical line at position "idx" by moving the lines above it
708 * down and inserting a "~" line at the top.
709 */
710static void
711delete_line (int idx)
712{
713 int cur_line;
714 struct logfile_entry *current;
715
716 for (cur_line = idx; cur_line > 0; cur_line--)
717 lines[cur_line] = lines[cur_line - 1];
718
719 lines[0].line = xstrdup ("~");
720
721 for (current = loglist; current; current = current->next)
722 if (current->index >= 0 && current->index <= idx)
723 current->index++;
724}
725
726/*
727 * takes a logical log file line and splits it into multiple physical
728 * screen lines by splitting it whenever a part becomes too long.
729 * lal lines will be inserted at position "idx".
730 */
731static void
732split_line (int idx, const char *str, unsigned long color)
733{
734 int l = strlen (str); 835 int l = strlen (str);
735 int last_wrapped = 0;
736 const char *p = str; 836 char *p = str;
737 static int continuation_width = -1; 837 struct line_node *line;
738 static int continuation_length; 838 int spaces;
839 static struct breakinfo *breaks;
840 static int break_buffer_size;
739 841
740 /* only calculate the continuation's width once */ 842 /* only calculate the continuation's width once */
741 if (continuation_width == -1) 843 if (continuation_width == -1)
742 { 844 {
743 continuation_length = strlen(continuation); 845 continuation_length = strlen (continuation);
744 continuation_width = XmbTextEscapement (fontset, continuation, continuation_length); 846 continuation_width = XmbTextEscapement (fontset, continuation, continuation_length);
847 continuation_color = GetColor (cont_color);
848
849 /* make an array to store information about the location of
850 * spaces in the line */
851 if (opt_justify)
852 {
853 break_buffer_size = 32;
854 breaks = xmalloc (break_buffer_size * sizeof (struct breakinfo));
855 }
745 } 856 }
746 857
747 do 858 do
748 { 859 {
749 const char *beg = p; 860 const char *beg = p;
750 int w = last_wrapped ? continuation_width : 0; 861 int start_w = log->last->wrapped_left ? continuation_width : 0;
862 int w = start_w;
751 int wrapped = 0; 863 int wrapped = 0;
752 const char *break_p = NULL; 864 char *break_p = NULL;
865 int width_at_break_p;
866 spaces = 0;
867
868 if (opt_justify)
869 breaks[spaces].index = breaks[spaces].width = 0;
753 870
754 while (*p) 871 while (*p)
755 { 872 {
873 int cw, len;
874
756 /* find the length in bytes of the next multibyte character */ 875 /* find the length in bytes of the next multibyte character */
757 int len = mblen (p, l); 876 len = mblen (p, l);
758 if (len <= 0) 877 if (len <= 0)
759 len = 1; /* ignore (don't skip) illegal character sequences */ 878 len = 1; /* ignore (don't skip) illegal character sequences */
760 879
761 /* find the width in pixels of the next character */ 880 /* find the width in pixels of the next character */
762 int cw = XmbTextEscapement (fontset, p, len); 881 cw = XmbTextEscapement (fontset, p, len);
882
883 if (opt_wordwrap && len == 1 && p[0] == ' ' && p != break_p + 1)
884 {
885 break_p = p;
886 width_at_break_p = w;
887 spaces++;
888
889 if (opt_justify)
890 {
891 /* increase the size of the 'breaks' array when
892 * necessary */
893 if (spaces >= break_buffer_size)
894 {
895 break_buffer_size *= 1.5;
896 breaks = xrealloc (breaks, break_buffer_size * sizeof (struct breakinfo));
897 }
898
899 /* store information about (a) the location of each
900 * space */
901 breaks[spaces].index = p + 1 - beg;
902 /* (b) the width (in pixels) of the string up to
903 * this space */
904 breaks[spaces].width = cw + w - start_w;
905 /* (c) the length of each 'word' */
906 breaks[spaces-1].len = breaks[spaces].index - breaks[spaces-1].index;
907 }
908 }
909
763 if (cw + w > width - effect_x_space) 910 if (cw + w > width - effect_x_space)
764 { 911 {
765 if (p == beg) 912 if (p == beg)
766 { 913 {
767 fprintf(stderr, "we can't even fit a single character onto the line\n"); 914 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); 915 if (len == 1) fprintf (stderr, "(the character we couldn't fit was '%c')\n", *p);
769 exit(1); 916 exit (1);
770 } 917 }
771 918
772 wrapped = 1; 919 wrapped = 1;
773 break; 920 break;
774 } 921 }
775
776 if (opt_wordwrap && len == 1 && p[0] == ' ')
777 break_p = p;
778 922
779 w += cw; 923 w += cw;
780 p += len; 924 p += len;
781 l -= len; 925 l -= len;
782 } 926 }
783 927
784 /* if we're wrapping at spaces, and the line is long enough to 928 /* if we're wrapping at spaces, and the line is long enough to
785 * wrap, and we've seen a space already, and the space wasn't 929 * wrap, and we've seen a space already, and the space wasn't
786 * the first character on the line, then wrap at the space */ 930 * the first character on the line, then wrap at the space */
787 if (opt_wordwrap && wrapped && break_p && break_p != beg) 931 if (!wrapped)
788 { 932 break;
789 l += p - break_p;
790 p = break_p;
791 }
792
793 { 933
794 /* HACK-4 - consider inserting the 'continuation string' 934 int prefix_len;
795 * before the rest of the wrapped line */
796 int len = p - beg + (last_wrapped ? continuation_length : 0);
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
804 memcpy (s, beg, len);
805 935
806 s[len] = 0; 936 /* choose where to break the line */
807 insert_line (idx);
808 lines[idx].line = s;
809 lines[idx].len = len;
810 lines[idx].color = color;
811 }
812
813 /* if we wrapped at a space, don't display the space */
814 if (opt_wordwrap && wrapped && break_p && break_p != beg) 937 if (opt_wordwrap && break_p && break_p != beg)
815 { 938 {
816 l--; 939 prefix_len = break_p - beg;
817 p++; 940 p = break_p;
818 } 941 w = width_at_break_p;
819 942
820 last_wrapped = wrapped; 943 /* if breaking at a space, skip all adjacent spaces */
944 while (*p == ' ')
945 {
946 int len = mblen (p, l);
947 if (len != 1) break;
948 p++;
949 }
950
951 if (opt_justify)
952 {
953 spaces--;
954 breaks[spaces].len--;
955 }
956 }
957 else
958 prefix_len = p - beg;
959
960 /* make a copy of the tail end of the string */
961 p = xstrdup (p);
962
963 /* and reduce the size of the head of the string */
964 log->last->line = xrealloc (log->last->line, prefix_len + 1);
965 log->last->len = prefix_len;
966 log->last->line[prefix_len] = '\0';
967
968 /* note that the head was wrapped on it's right */
969 log->last->wrapped_right = 1;
970
971 /* 'spaces' includes any space we broke on; we can only justify
972 * if there's at least one other space */
973 if (opt_justify && spaces &&
974 width - effect_x_space - width_at_break_p < spaces * font_height)
975 {
976 int i;
977 log->last->free_pixels = width - w;
978 log->last->num_words = spaces + 1;
979 log->last->breaks = malloc (log->last->num_words * sizeof (struct breakinfo));
980 for (i = 0; i < log->last->num_words; i++)
981 log->last->breaks[i] = breaks[i];
982 }
983
984 line = new_line_node (log);
985 line->line = p;
986 l = line->len = strlen (p);
987
988 /* note that the tail end of the string is wrapped at its left */
989 line->wrapped_left = 1;
821 } 990 }
822 while (l); 991 while (l);
992}
993
994static void
995insert_new_line (char *str, struct logfile_entry *log)
996{
997 struct line_node *new;
998 new = new_line_node (log);
999 new->line = str;
1000 new->len = strlen (str);
1001
1002 possibly_split_long_line (log);
823} 1003}
824 1004
825/* 1005/*
826 * append something to an existing physical line. this is done 1006 * append something to an existing physical line. this is done
827 * by deleting the file on-screen, concatenating the new data to it 1007 * by deleting the file on-screen, concatenating the new data to it
828 * and splitting it again. 1008 * and splitting it again.
829 */ 1009 */
830static void 1010static void
831append_line (int idx, const char *str) 1011append_to_existing_line (char *str, struct logfile_entry *log)
832{ 1012{
833 unsigned long color = lines[idx].color; 1013 char *old, *new;
834 char *old = lines[idx].line; 1014
1015 assert(log);
1016 assert(log->last);
1017
1018 old = log->last->line;
1019 assert(old);
1020
835 char *new = concat_line (old, str); 1021 new = concat_line (old, str);
836
837 free (old); 1022 free (str);
838 1023 log->last->line = new;
839 delete_line (idx); 1024 log->last->len = strlen (new);
840 split_line (idx, new, color); 1025 possibly_split_long_line (log);
841} 1026}
842 1027
843static void 1028static void
844main_loop (void) 1029main_loop (void)
845{ 1030{
846 lines = xmalloc (sizeof (struct linematrix) * listlen);
847 display = xmalloc (sizeof (struct displaymatrix) * listlen);
848 int lin; 1031 int lin;
849 time_t lastreload; 1032 time_t lastreload;
850 Region region = XCreateRegion (); 1033 Region region = XCreateRegion ();
851 XEvent xev; 1034 XEvent xev;
852 struct logfile_entry *lastprinted = NULL; 1035 struct logfile_entry *lastprinted = NULL;
853 struct logfile_entry *current; 1036 struct logfile_entry *current;
854 int need_update = 1; 1037 int need_update = 1;
855 1038
1039 display = xmalloc (sizeof (struct displaymatrix) * listlen);
1040
856 lastreload = time (NULL); 1041 lastreload = time (NULL);
857 1042
858 /* Initialize linematrix */ 1043 /* Initialize line_node */
859 for (lin = 0; lin < listlen; lin++) 1044 for (lin = 0; lin < listlen; lin++)
860 { 1045 {
1046 struct line_node *e = xmalloc (sizeof (struct line_node));
861 lines[lin].line = xstrdup ("~"); 1047 e->line = xstrdup ("~");
862 lines[lin].len = 1; 1048 e->len = 1;
1049 e->logfile = loglist; /* this is only needed to get a color for the '~' */
1050 e->wrapped_left = 0;
1051 e->wrapped_right = 0;
1052 e->breaks = 0;
1053 e->next = NULL;
1054 e->prev = linelist_tail;
1055
1056 if (!linelist)
1057 linelist = e;
1058 if (linelist_tail)
1059 linelist_tail->next = e;
1060 linelist_tail = e;
1061
863 display[lin].line = xstrdup(""); 1062 display[lin].line = xstrdup ("");
864 display[lin].len = 0; 1063 display[lin].len = 0;
865 display[lin].buffer_size = 1; 1064 display[lin].buffer_size = 0;
866 lines[lin].color = GetColor (def_color);
867 } 1065 }
868 1066
869 for (;;) 1067 for (;;)
870 { 1068 {
871 /* read logs */ 1069 /* read logs */
882 /* if we're trying to update old partial lines in 1080 /* if we're trying to update old partial lines in
883 * place, and the last time this file was updated the 1081 * place, and the last time this file was updated the
884 * output was partial, and that partial line is not 1082 * output was partial, and that partial line is not
885 * too close to the top of the screen, then update 1083 * too close to the top of the screen, then update
886 * that partial line */ 1084 * that partial line */
887 if (opt_update && current->lastpartial && current->index >= 0) 1085 if (opt_update && current->lastpartial && current->last)
888 { 1086 {
889 int idx = current->index; 1087 // int idx = current->index;
890 append_line (idx, current->buf); 1088 append_to_existing_line (current->buf, current);
891 current->index = idx; 1089 // current->index = idx;
892 free (current->buf), current->buf = 0; 1090 current->buf = 0;
1091 continue;
1092 }
1093
1094 /* if all we just read was a newline ending a line that we've already displayed, skip it */
1095 if (current->buf[0] == '\0' && current->lastpartial)
1096 {
1097 current->buf = 0;
893 continue; 1098 continue;
894 } 1099 }
895 1100
896 /* print filename if any, and if last line was from 1101 /* print filename if any, and if last line was from
897 * different file */ 1102 * different file */
898 if (!opt_nofilename && lastprinted != current && current->desc[0]) 1103 if (!opt_nofilename && lastprinted != current && current->desc[0])
899 { 1104 {
900 char buf[1024]; /* HACK-5 */ 1105 current->last = 0;
901 snprintf (buf, sizeof (buf), "[%s]", current->desc); 1106 insert_new_line (xstrdup ("["), current);
902 split_line (listlen - 1, buf, current->color); 1107 append_to_existing_line (xstrdup (current->desc), current);
1108 append_to_existing_line (xstrdup ("]"), current);
903 } 1109 }
904 1110
905 /* if we're dealing with partial lines, and the last 1111 /* if we're dealing with partial lines, and the last
906 * time we showed the line it wasn't finished ... */ 1112 * time we showed the line it wasn't finished ... */
907 if (!opt_whole && current->lastpartial) 1113 if (!opt_whole && current->lastpartial)
908 { 1114 {
909 /* if this is the same file we showed last then 1115 /* if this is the same file we showed last then
910 append to the last line shown */ 1116 append to the last line shown */
911 if (lastprinted == current) 1117 if (lastprinted == current)
912 append_line (listlen - 1, current->buf); 1118 append_to_existing_line (current->buf, current);
913 else 1119 else
914 { 1120 {
915 /* but if a different file has been shown in the 1121 /* but if a different file has been shown in the
916 * mean time, make a new line, starting with the 1122 * mean time, make a new line, starting with the
917 * continuation string */ 1123 * continuation string */
918 split_line (listlen - 1, continuation, current->color); 1124 insert_new_line (current->buf, current);
919 append_line (listlen - 1, current->buf); 1125 current->last->wrapped_left = 1;
920 } 1126 }
921 } 1127 }
922 else 1128 else
923 /* otherwise just make a plain and simple new line */ 1129 /* otherwise just make a plain and simple new line */
924 split_line (listlen - 1, current->buf, current->color); 1130 insert_new_line (current->buf, current);
925 1131
926 free (current->buf), current->buf = 0; 1132 current->buf = 0;
927 current->index = listlen - 1; 1133 // current->index = listlen - 1;
928 lastprinted = current; 1134 lastprinted = current;
929 } 1135 }
930 } 1136 }
931 1137
932 if (need_update) 1138 if (need_update)
1043 XParseGeometry (argv[++i], &win_x, &win_y, &width, &height); 1249 XParseGeometry (argv[++i], &win_x, &win_y, &width, &height);
1044 else if (!strcmp (arg, "-display")) 1250 else if (!strcmp (arg, "-display"))
1045 dispname = argv[++i]; 1251 dispname = argv[++i];
1046 else if (!strcmp (arg, "-cont")) 1252 else if (!strcmp (arg, "-cont"))
1047 continuation = argv[++i]; 1253 continuation = argv[++i];
1254 else if (!strcmp (arg, "-cont-color"))
1255 cont_color = argv[++i];
1048 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn")) 1256 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn"))
1049 fontname = argv[++i]; 1257 fontname = argv[++i];
1050#if HAS_REGEX 1258#if HAS_REGEX
1051 else if (!strcmp (arg, "-t")) 1259 else if (!strcmp (arg, "-t"))
1052 { 1260 {
1053 transform = argv[++i]; 1261 transform = argv[++i];
1054 transform_to = argv[++i]; 1262 transform_to = argv[++i];
1055 printf("transform: '%s' to '%s'\n", transform, transform_to); 1263 printf ("transform: '%s' to '%s'\n", transform, transform_to);
1056 } 1264 }
1057#endif 1265#endif
1058 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f")) 1266 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f"))
1059 opt_daemonize = 1; 1267 opt_daemonize = 1;
1060 else if (!strcmp (arg, "-reload")) 1268 else if (!strcmp (arg, "-reload"))
1061 { 1269 {
1080 opt_partial = 1; 1288 opt_partial = 1;
1081 else if (!strcmp (arg, "-update")) 1289 else if (!strcmp (arg, "-update"))
1082 opt_update = opt_partial = 1; 1290 opt_update = opt_partial = 1;
1083 else if (!strcmp (arg, "-wordwrap")) 1291 else if (!strcmp (arg, "-wordwrap"))
1084 opt_wordwrap = 1; 1292 opt_wordwrap = 1;
1293 else if (!strcmp (arg, "-justify"))
1294 opt_justify = 1;
1085 else if (!strcmp (arg, "-color")) 1295 else if (!strcmp (arg, "-color"))
1086 def_color = argv[++i]; 1296 def_color = argv[++i];
1087 else if (!strcmp (arg, "-noinitial")) 1297 else if (!strcmp (arg, "-noinitial"))
1088 opt_noinitial = 1; 1298 opt_noinitial = 1;
1089 else if (!strcmp (arg, "-id")) 1299 else if (!strcmp (arg, "-id"))
1125 } 1335 }
1126 1336
1127 e = xmalloc (sizeof (struct logfile_entry)); 1337 e = xmalloc (sizeof (struct logfile_entry));
1128 e->partial = 0; 1338 e->partial = 0;
1129 e->buf = 0; 1339 e->buf = 0;
1130 e->index = -1; 1340 // e->index = -1;
1131 1341
1132 if (arg[0] == '-' && arg[1] == '\0') 1342 if (arg[0] == '-' && arg[1] == '\0')
1133 { 1343 {
1134 if ((e->fp = fdopen (0, "r")) == NULL) 1344 if ((e->fp = fdopen (0, "r")) == NULL)
1135 perror ("fdopen"), exit (1); 1345 perror ("fdopen"), exit (1);
1136 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) 1346 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0)
1137 perror ("fcntl"), exit (1); 1347 perror ("fcntl"), exit (1);
1348
1138 e->fname = NULL; 1349 e->fname = NULL;
1139 e->inode = 0; 1350 e->inode = 0;
1140 e->desc = xstrdup ("stdin"); 1351 e->desc = xstrdup ("stdin");
1141 } 1352 }
1142 else 1353 else
1143 { 1354 {
1144 int l;
1145
1146 e->fname = xstrdup (fname); 1355 e->fname = xstrdup (fname);
1356
1147 if (openlog (e) == NULL) 1357 if (openlog (e) == NULL)
1148 perror (fname), exit (1); 1358 perror (fname), exit (1);
1149 1359
1150 e->desc = xstrdup (desc); 1360 e->desc = xstrdup (desc);
1151 } 1361 }
1152 1362
1153 e->color = GetColor (fcolor); 1363 e->color = GetColor (fcolor);
1154 e->partial = 0; 1364 e->partial = 0;
1365 e->last = NULL;
1155 e->next = NULL; 1366 e->next = NULL;
1156 1367
1157 if (!loglist) 1368 if (!loglist)
1158 loglist = e; 1369 loglist = e;
1159 if (loglist_tail) 1370 if (loglist_tail)
1160 loglist_tail->next = e; 1371 loglist_tail->next = e;
1372
1161 loglist_tail = e; 1373 loglist_tail = e;
1162 } 1374 }
1163 } 1375 }
1164 1376
1165 if (!loglist) 1377 if (!loglist)
1167 fprintf (stderr, "You did not specify any files to tail\n" 1379 fprintf (stderr, "You did not specify any files to tail\n"
1168 "use %s --help for help\n", argv[0]); 1380 "use %s --help for help\n", argv[0]);
1169 exit (1); 1381 exit (1);
1170 } 1382 }
1171 1383
1384 if (opt_update && opt_whole)
1385 {
1386 fprintf (stderr, "Specify at most one of -update and -whole\n");
1387 exit (1);
1388 }
1172 if (opt_partial && opt_whole) 1389 else if (opt_partial && opt_whole)
1173 { 1390 {
1174 fprintf (stderr, "Specify at most one of -partial and -whole\n"); 1391 fprintf (stderr, "Specify at most one of -partial and -whole\n");
1175 exit (1); 1392 exit (1);
1176 } 1393 }
1394
1395 /* it doesn't make sense to justify if word wrap isn't on */
1396 if (opt_justify)
1397 opt_wordwrap = 1;
1177 1398
1178 /* HACK-7: do we want to allow both -shade and -outline? */ 1399 /* HACK-7: do we want to allow both -shade and -outline? */
1179 if (opt_shade && opt_outline) 1400 if (opt_shade && opt_outline)
1180 { 1401 {
1181 fprintf (stderr, "Specify at most one of -shade and -outline\n"); 1402 fprintf (stderr, "Specify at most one of -shade and -outline\n");
1192#if HAS_REGEX 1413#if HAS_REGEX
1193 if (transform) 1414 if (transform)
1194 { 1415 {
1195 int i; 1416 int i;
1196 1417
1197 printf("compiling regexp '%s'\n", transform); 1418 printf ("compiling regexp '%s'\n", transform);
1198 transformre = xmalloc (sizeof (regex_t)); 1419 transformre = xmalloc (sizeof (regex_t));
1199 i = regcomp (transformre, transform, REG_EXTENDED); 1420 i = regcomp (transformre, transform, REG_EXTENDED);
1200 if (i != 0) 1421 if (i != 0)
1201 { 1422 {
1202 char buf[512]; 1423 char buf[512];
1203 1424
1204 regerror (i, transformre, buf, sizeof (buf)); 1425 regerror (i, transformre, buf, sizeof (buf));
1205 fprintf (stderr, "Cannot compile regular expression: %s\n", buf); 1426 fprintf (stderr, "Cannot compile regular expression: %s\n", buf);
1206 } 1427 }
1207 else 1428 else
1208 {
1209 printf("compiled '%s' OK to %x\n", transform, (int)transformre); 1429 printf ("compiled '%s' OK to %x\n", transform, (int)transformre);
1210 }
1211 } 1430 }
1212#endif 1431#endif
1213 1432
1214 InitWindow (); 1433 InitWindow ();
1215 1434
1236 action.sa_handler = handler; 1455 action.sa_handler = handler;
1237 sigemptyset (&action.sa_mask); 1456 sigemptyset (&action.sa_mask);
1238 action.sa_flags = SA_RESTART; 1457 action.sa_flags = SA_RESTART;
1239 1458
1240 if (sigaction (sig, &action, NULL) < 0) 1459 if (sigaction (sig, &action, NULL) < 0)
1241 fprintf (stderr, "sigaction(%d): %s\n", sig, strerror (errno)), exit (1); 1460 fprintf (stderr, "sigaction (%d): %s\n", sig, strerror (errno)), exit (1);
1242} 1461}
1243 1462
1244void * 1463void *
1245xstrdup (const char *string) 1464xstrdup (const char *string)
1246{ 1465{
1247 void *p; 1466 void *p;
1248 1467
1249 while ((p = strdup (string)) == NULL) 1468 while ((p = strdup (string)) == NULL)
1250 { 1469 {
1251 fprintf (stderr, "Memory exausted."); 1470 fprintf (stderr, "Memory exhausted in xstrdup ().\n");
1252 sleep (10); 1471 sleep (10);
1253 } 1472 }
1254 1473
1255 return p; 1474 return p;
1256} 1475}
1260{ 1479{
1261 void *p; 1480 void *p;
1262 1481
1263 while ((p = malloc (size)) == NULL) 1482 while ((p = malloc (size)) == NULL)
1264 { 1483 {
1265 fprintf (stderr, "Memory exausted."); 1484 fprintf (stderr, "Memory exhausted in xmalloc ().\n");
1266 sleep (10); 1485 sleep (10);
1267 } 1486 }
1268 1487
1269 return p; 1488 return p;
1270} 1489}
1274{ 1493{
1275 void *p; 1494 void *p;
1276 1495
1277 while ((p = realloc (ptr, size)) == NULL) 1496 while ((p = realloc (ptr, size)) == NULL)
1278 { 1497 {
1279 fprintf (stderr, "Memory exausted."); 1498 fprintf (stderr, "Memory exhausted in xrealloc ().\n");
1280 sleep (10); 1499 sleep (10);
1281 } 1500 }
1282 1501
1283 return p; 1502 return p;
1284} 1503}
1306 " startup\n" 1525 " startup\n"
1307 " -i | -interval seconds interval between checks (fractional\n" 1526 " -i | -interval seconds interval between checks (fractional\n"
1308 " values o.k.). Default 2.4 seconds\n" 1527 " values o.k.). Default 2.4 seconds\n"
1309 " -V display version information and exit\n" 1528 " -V display version information and exit\n"
1310 "\n"); 1529 "\n");
1311 printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green " 1530 printf ("Example:\n%s -g 800x250+100+50 -font fixed /var/log/messages,green "
1312 "/var/log/secure,red,'ALERT'\n", myname); 1531 "/var/log/secure,red,'ALERT'\n", myname);
1313 exit (0); 1532 exit (0);
1314} 1533}
1315 1534
1316void 1535void
1330 case -1: 1549 case -1:
1331 return -1; 1550 return -1;
1332 case 0: 1551 case 0:
1333 break; 1552 break;
1334 default: 1553 default:
1335 /*printf("%d\n", pid);*/ 1554 /*printf ("%d\n", pid);*/
1336 exit (0); 1555 exit (0);
1337 } 1556 }
1338 1557
1339 if (setsid () == -1) 1558 if (setsid () == -1)
1340 return -1; 1559 return -1;
1341 1560
1342 return 0; 1561 return 0;
1343} 1562}
1563
1564/* todo - get reverse display working again */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines