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.12 by pcg, Sat Mar 27 00:52:52 2004 UTC

58}; 58};
59 59
60struct linematrix 60struct linematrix
61{ 61{
62 char *line; 62 char *line;
63 int len;
63 unsigned long color; 64 unsigned long color;
64}; 65};
65 66
66/* global variables */ 67/* global variables */
68struct linematrix *lines;
67int width = STD_WIDTH, height = STD_HEIGHT, listlen; 69int width = STD_WIDTH, height = STD_HEIGHT, listlen;
68int win_x = LOC_X, win_y = LOC_Y; 70int win_x = LOC_X, win_y = LOC_Y;
69int font_descent, font_height; 71int font_descent, font_height;
70int do_reopen; 72int do_reopen;
71struct timeval interval = { 3, 0 }; 73struct timeval interval = { 3, 0 };
102void blank_window (int); 104void blank_window (int);
103 105
104void InitWindow (void); 106void InitWindow (void);
105unsigned long GetColor (const char *); 107unsigned long GetColor (const char *);
106void redraw (void); 108void redraw (void);
107void refresh (struct linematrix *, int, int); 109void refresh (int, int);
108 110
109void transform_line (char *s); 111void transform_line (char *s);
110int lineinput (struct logfile_entry *); 112int lineinput (struct logfile_entry *);
111void reopen (void); 113void reopen (void);
112void check_open_files (void); 114void check_open_files (void);
113FILE *openlog (struct logfile_entry *); 115FILE *openlog (struct logfile_entry *);
114void main_loop (void); 116static void main_loop (void);
115 117
116void display_version (void); 118void display_version (void);
117void display_help (char *); 119void display_help (char *);
118void install_signal (int, void (*)(int)); 120void install_signal (int, void (*)(int));
119void *xstrdup (const char *); 121void *xstrdup (const char *);
138} 140}
139 141
140void 142void
141force_refresh (int dummy) 143force_refresh (int dummy)
142{ 144{
143 XClearArea (disp, root, win_x, win_y, width, height, False);
144 redraw (); 145 redraw ();
145} 146}
146 147
147void 148void
148blank_window (int dummy) 149blank_window (int dummy)
306 height = listlen * font_height; 307 height = listlen * font_height;
307 308
308 XSelectInput (disp, root, ExposureMask | FocusChangeMask); 309 XSelectInput (disp, root, ExposureMask | FocusChangeMask);
309} 310}
310 311
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}
332
333/* 312/*
334 * redraw does a complete redraw, rather than an update (i.e. the area 313 * redraw does a complete redraw, rather than an update (i.e. the area
335 * gets cleared first) 314 * gets cleared first)
336 * the rest is handled by regular refresh()'es 315 * the rest is handled by regular refresh()'es
337 */ 316 */
338void 317void
339redraw (void) 318redraw (void)
340{ 319{
341 XClearArea (disp, root, win_x, win_y, width, height, True); 320 XClearArea (disp, root, win_x, win_y, width, height, False);
321 refresh (0, 32768);
342} 322}
343 323
344/* Just redraw everything without clearing (i.e. after an EXPOSE event) */ 324/* Just redraw everything without clearing (i.e. after an EXPOSE event) */
345void 325void
346refresh (struct linematrix *lines, int miny, int maxy) 326refresh (int miny, int maxy)
347{ 327{
348 int lin; 328 int lin;
349 int offset = (listlen + 1) * font_height; 329 int offset = (listlen + 1) * font_height;
350 unsigned long black_color = GetColor ("black"); 330 unsigned long black_color = GetColor ("black");
351 331
352 miny -= win_y + font_height; 332 miny -= win_y + font_height;
353 maxy -= win_y - font_height; 333 maxy -= win_y - font_height;
354 334
335
355 for (lin = listlen; lin--;) 336 for (lin = listlen; lin--;)
356 { 337 {
357 struct linematrix *line =
358 lines + (opt_reverse ? listlen - lin - 1 : lin); 338 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin);
359 339
360 offset -= font_height; 340 offset -= font_height;
361 341
362 if (offset < miny || offset > maxy) 342 if (offset < miny || offset > maxy)
363 continue; 343 continue;
364 344
365 if (opt_shade) 345 if (opt_shade)
366 { 346 {
367 XSetForeground (disp, WinGC, black_color); 347 XSetForeground (disp, WinGC, black_color);
368 XmbDrawString (disp, root, fontset, WinGC, win_x + 2, 348 XmbDrawString (disp, root, fontset, WinGC, win_x + 2,
369 win_y + offset + 2, line->line, strlen (line->line)); 349 win_y + offset + 2, line->line, line->len);
370 } 350 }
371 351
372 XSetForeground (disp, WinGC, line->color); 352 XSetForeground (disp, WinGC, line->color);
373 XmbDrawString (disp, root, fontset, WinGC, win_x, win_y + offset, 353 XmbDrawString (disp, root, fontset, WinGC, win_x, win_y + offset,
374 line->line, strlen (line->line)); 354 line->line, line->len);
375 } 355 }
376 356
377 if (opt_frame) 357 if (opt_frame)
378 XDrawRectangle (disp, root, WinGC, win_x, win_y, width, height); 358 XDrawRectangle (disp, root, WinGC, win_x - 2, win_y - 2, width + 4, height + 4);
379} 359}
380 360
381#if HAS_REGEX 361#if HAS_REGEX
382void 362void
383transform_line (char *s) 363transform_line (char *s)
403 } 383 }
404 } 384 }
405} 385}
406#endif 386#endif
407 387
388char *
389concat_line (const char *p1, const char *p2)
390{
391 int l1 = p1 ? strlen (p1) : 0;
392 int l2 = strlen (p2);
393 char *r = xmalloc (l1 + l2 + 1);
394
395 memcpy (r, p1, l1);
396 memcpy (r + l1, p2, l2);
397 r[l1 + l2] = 0;
398
399 return r;
400}
408 401
409/* 402/*
410 * This routine should read 'width' characters and not more. However, 403 * 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 */ 404 */
416int 405int
417lineinput (struct logfile_entry *logfile) 406lineinput (struct logfile_entry *logfile)
418{ 407{
419 char *string = logfile->buf; 408 char buff[1024], *p = buff;
420 int slen = width + 2; 409 int ch;
421 FILE *f = logfile->fp; 410 int ofs = logfile->buf ? strlen (logfile->buf) : 0;
422
423 int len = strlen (string);
424 int partial = logfile->partial;
425 411
426 do 412 do
427 { 413 {
428 if (fgets (string + len, slen - len, f) == NULL) /* EOF or Error */ 414 ch = fgetc (logfile->fp);
429 return 0;
430 415
431 len = strlen (string); 416 if (ch == '\r')
432 } 417 continue;
433 while (len == 0); 418 else if (ch == EOF || ch == '\n')
434 419 break;
435 logfile->partial = 0; 420 else if (ch == '\t')
436 421 {
437 if (string[len - 1] == '\n') 422 do
438 /* if the string ends in a newline, delete the newline */ 423 {
439 string[len - 1] = '\0'; /* erase newline */ 424 *p++ = ' ';
440 else if (len >= slen - 1) 425 ofs++;
426 }
427 while (ofs & 7);
428 }
429 else
430 {
431 *p++ = ch;
432 ofs++;
433 }
441 { 434 }
442 /* otherwise if we've read one too many characters, un-read the last one and delete it */ 435 while (p < buff + (sizeof buff) - 8 - 1);
443 ungetc (string[len - 1], f); 436
444 string[len - 1] = '\0'; 437 if (p == buff)
445 }
446 else if (opt_whole)
447 return 0; 438 return 0;
448 else 439
440 *p = 0;
441
442 p = concat_line (logfile->buf, buff);
443 free (logfile->buf); logfile->buf = p;
444
445 logfile->lastpartial = logfile->partial;
449 logfile->partial = 1; 446 logfile->partial = ch == EOF;
447
448 if (logfile->partial && opt_whole)
449 return 0;
450 450
451#if HAS_REGEX 451#if HAS_REGEX
452 transform_line (string); 452 transform_line (logfile->buf);
453#endif 453#endif
454 logfile->lastpartial = partial; 454 printf ("got buf <%s>\n", logfile->buf);
455 return len; 455 return 1;
456} 456}
457 457
458/* input: reads file->fname 458/* input: reads file->fname
459 * output: fills file->fp, file->inode 459 * output: fills file->fp, file->inode
460 * returns file->fp 460 * returns file->fp
543 e->last_size = stats.st_size; 543 e->last_size = stats.st_size;
544 } 544 }
545 } 545 }
546} 546}
547 547
548#define SCROLL_UP(lines, listlen) \ 548static void
549{ \ 549insert_line (int idx)
550 int cur_line; \ 550{
551 struct logfile_entry *current; \ 551 int cur_line;
552 struct logfile_entry *current;
553
554 free (lines[0].line);
555
552 for (cur_line = 0; cur_line < (listlen - 1); cur_line++) { \ 556 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; \ 557 lines[cur_line] = lines[cur_line + 1];
555 } \ 558
556 for (current = loglist; current; current = current->next) \ 559 for (current = loglist; current; current = current->next)
557 if (current->partial && current->index) \ 560 if (current->partial && current->index && current->index <= idx)
558 current->index--; \ 561 current->index--;
559} 562}
560 563
561void 564static void
565delete_line (int idx)
566{
567 int cur_line;
568 struct logfile_entry *current;
569
570 for (cur_line = idx; cur_line > 0; cur_line--)
571 lines[cur_line] = lines[cur_line - 1];
572
573 lines[0].line = strdup ("~");
574
575 for (current = loglist; current; current = current->next)
576 if (current->partial && current->index && current->index <= idx)
577 current->index++;
578}
579
580static void
581split_line (int idx, const char *str, unsigned long color)
582{
583 int l = strlen (str);
584 const char *p = str;
585
586 do
587 {
588 const char *beg = p;
589 int w = 0;
590
591 while (*p)
592 {
593 int len = mblen (p, l);
594 if (len <= 0)
595 len = 1; /* ignore (don't skip) ilegal character sequences */
596
597 int cw = XmbTextEscapement (fontset, p, len);
598 if (cw + w >= width)
599 break;
600
601 w += cw;
602 p += len;
603 l -= len;
604 }
605
606 {
607 char *s = xmalloc (p - beg + 1);
608 memcpy (s, beg, p - beg);
609 s[p - beg] = 0;
610 insert_line (idx);
611 lines[idx].line = s;
612 lines[idx].len = p - beg;
613 lines[idx].color = color;
614 }
615 }
616 while (l);
617}
618
619static void
620append_line (int idx, const char *str)
621{
622 unsigned long color = lines[idx].color;
623 char *old = lines[idx].line;
624 char *new = concat_line (old, str);
625
626 free (old);
627 free (str);
628
629 delete_line (idx);
630 split_line (idx, new, color);
631}
632
633static void
562main_loop (void) 634main_loop (void)
563{ 635{
564 struct linematrix *lines = xmalloc (sizeof (struct linematrix) * listlen); 636 lines = xmalloc (sizeof (struct linematrix) * listlen);
565 int lin, miny, maxy; 637 int lin, miny, maxy;
566 time_t lastreload; 638 time_t lastreload;
567 Region region = XCreateRegion (); 639 Region region = XCreateRegion ();
568 XEvent xev; 640 XEvent xev;
569 struct logfile_entry *lastprinted = NULL; 641 struct logfile_entry *lastprinted = NULL;
574 lastreload = time (NULL); 646 lastreload = time (NULL);
575 647
576 /* Initialize linematrix */ 648 /* Initialize linematrix */
577 for (lin = 0; lin < listlen; lin++) 649 for (lin = 0; lin < listlen; lin++)
578 { 650 {
579 lines[lin].line = xmalloc (width + 2); 651 lines[lin].line = strdup ("~");
580 strcpy (lines[lin].line, "~"); 652 lines[lin].len = 1;
581 lines[lin].color = GetColor (def_color); 653 lines[lin].color = GetColor (def_color);
582 } 654 }
583 655
584 /* show the display full of empty lines ("~") in case the first 656 /* 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 657 * time around the loop doesn't produce any output, as it won't if
597 if (!current->fp) 669 if (!current->fp)
598 continue; /* skip missing files */ 670 continue; /* skip missing files */
599 671
600 clearerr (current->fp); 672 clearerr (current->fp);
601 673
602 while (lineinput (current) != 0) 674 while (lineinput (current))
603 { 675 {
676 printf ("lineinput %s\n", current->buf);//D
677 need_update = 1;
604 /* if we're trying to update old partial lines in 678 /* if we're trying to update old partial lines in
605 * place, and the last time this file was updated the 679 * place, and the last time this file was updated the
606 * output was partial, and that partial line is not 680 * output was partial, and that partial line is not
607 * too close to the top of the screen, then update 681 * too close to the top of the screen, then update
608 * that partial line */ 682 * that partial line */
683 printf ("BPa\n");//D
609 if (opt_update && current->lastpartial && current->index >= 3) 684 if (opt_update && current->lastpartial && current->index >= 3)
610 { 685 {
611 int old_len = strlen (lines[current->index].line);
612 int new_len = strlen (current->buf);
613 int space_on_old_line = width / font_width - old_len; //D
614
615 strncat (lines[current->index].line, current->buf, 686 append_line (current->index, current->buf);
616 width - old_len); 687
617 /* if we can't fit the whole update into the old 688 if (!current->partial)
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 { 689 {
622 /* strcpy() doesn't like the strings to
623 * overlap in memory, but memmove() doesn't
624 * care */
625 memmove (current->buf, 690 free (current->buf);
626 current->buf + space_on_old_line, 691 current->buf = 0;
627 new_len - space_on_old_line + 1);
628 } 692 }
629 else 693
630 {
631 need_update = 1;
632 strcpy (current->buf, "");
633 continue; 694 continue;
634 }
635 } 695 }
636 696
697 printf ("BPb\n");//D
637 /* print filename if any, and if last line was from 698 /* print filename if any, and if last line was from
638 * different file */ 699 * different file */
639 if (!opt_nofilename && 700 if (!opt_nofilename &&
640 lastprinted != current && current->desc[0]) 701 lastprinted != current && current->desc[0])
641 { 702 {
642 SCROLL_UP (lines, listlen); 703 char buf[1024]; /* HACK */
643 sprintf (lines[listlen - 1].line, "[%s]", current->desc); 704 snprintf (buf, sizeof (buf), "[%s]", current->desc);
705 printf ("BPc<%s>\n", buf);//D
644 lines[listlen - 1].color = current->color; 706 split_line (listlen - 1, buf, current->color);
645 } 707 }
646 708
709 printf ("BP1\n");//D
647 /* if this is the same file we showed last, and the 710 /* if this is the same file we showed last, and the
648 * last time we showed it, it wasn't finished, then 711 * last time we showed it, it wasn't finished, then
649 * append to the last line shown */ 712 * append to the last line shown */
650 if (lastprinted == current && current->lastpartial) 713 if (lastprinted == current && current->lastpartial)
651 { 714 {
652 int old_len = strlen (lines[listlen - 1].line); 715 append_line (listlen - 1, current->buf);
653 int new_len = strlen (current->buf); 716 free (current->buf);
654 strncat (lines[listlen - 1].line, current->buf, 717 current->buf = 0;
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 { 718 continue;
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)
669 {
670 int old_len = strlen (continuation);
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,
675 width - old_len);
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 } 719 }
685 else 720 else
686 { 721 {
687 SCROLL_UP (lines, listlen); 722 split_line (listlen - 1, current->buf, current->color);
688 strcpy (lines[listlen - 1].line, current->buf); 723 free (current->buf); current->buf = 0;
689 } 724 }
725 printf ("BP3\n");//D
690 726
691 /* we've shown the line now. clear the buffer for the next line */
692 strcpy (current->buf, "");
693 current->index = listlen - 1; 727 current->index = listlen - 1;
694 lines[listlen - 1].color = current->color;
695
696 lastprinted = current; 728 lastprinted = current;
697 need_update = 1;
698 } 729 }
699 } 730 }
700 731
701 if (need_update) 732 if (need_update)
702 redraw (); 733 redraw ();
762 793
763 if (!XEmptyRegion (region)) 794 if (!XEmptyRegion (region))
764 { 795 {
765 XSetRegion (disp, WinGC, region); 796 XSetRegion (disp, WinGC, region);
766 797
767 refresh (lines, miny, maxy); 798 refresh (miny, maxy);
768 XDestroyRegion (region); 799 XDestroyRegion (region);
769 region = XCreateRegion (); 800 region = XCreateRegion ();
770 maxy = 0; 801 maxy = 0;
771 miny = win_y + height; 802 miny = win_y + height;
772 } 803 }
880 desc = p + 1; 911 desc = p + 1;
881 } 912 }
882 } 913 }
883 914
884 e = xmalloc (sizeof (struct logfile_entry)); 915 e = xmalloc (sizeof (struct logfile_entry));
916 e->partial = 0;
917 e->buf = 0;
918
885 if (arg[0] == '-' && arg[1] == '\0') 919 if (arg[0] == '-' && arg[1] == '\0')
886 { 920 {
887 if ((e->fp = fdopen (0, "r")) == NULL) 921 if ((e->fp = fdopen (0, "r")) == NULL)
888 perror ("fdopen"), exit (1); 922 perror ("fdopen"), exit (1);
889 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) 923 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0)
907 memcpy (e->desc, desc, l); 941 memcpy (e->desc, desc, l);
908 *(e->desc + l) = '\0'; 942 *(e->desc + l) = '\0';
909 } 943 }
910 944
911 e->color = GetColor (fcolor); 945 e->color = GetColor (fcolor);
912 e->buf = xmalloc (width + 2);
913 e->partial = 0; 946 e->partial = 0;
914 e->buf[0] = '\0';
915 e->next = NULL; 947 e->next = NULL;
916 948
917 if (!loglist) 949 if (!loglist)
918 loglist = e; 950 loglist = e;
919 if (loglist_tail) 951 if (loglist_tail)
1011 while ((p = malloc (size)) == NULL) 1043 while ((p = malloc (size)) == NULL)
1012 { 1044 {
1013 fprintf (stderr, "Memory exausted."); 1045 fprintf (stderr, "Memory exausted.");
1014 sleep (10); 1046 sleep (10);
1015 } 1047 }
1048
1016 return p; 1049 return p;
1017} 1050}
1018 1051
1019void 1052void
1020display_help (char *myname) 1053display_help (char *myname)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines