… | |
… | |
530 | |
530 | |
531 | return r; |
531 | return r; |
532 | } |
532 | } |
533 | |
533 | |
534 | /* |
534 | /* |
535 | * This routine should read a single line, no matter how long. |
535 | * HACK-1: This routine should read a single line, no matter how long. |
536 | */ |
536 | */ |
537 | int |
537 | int |
538 | lineinput (struct logfile_entry *logfile) |
538 | lineinput (struct logfile_entry *logfile) |
539 | { |
539 | { |
540 | char buff[1024], *p = buff; |
540 | char buff[1024], *p = buff; |
541 | int ch; |
541 | int ch; |
542 | /* HACK this - to add on the length of any partial line which we will be appending to */ |
542 | /* HACK-2: add on the length of any partial line which we will be appending to */ |
543 | int ofs = logfile->buf ? strlen (logfile->buf) : 0; |
543 | int ofs = logfile->buf ? strlen (logfile->buf) : 0; |
544 | |
544 | |
545 | do |
545 | do |
546 | { |
546 | { |
547 | ch = fgetc (logfile->fp); |
547 | ch = fgetc (logfile->fp); |
… | |
… | |
660 | sleep (1); |
660 | sleep (1); |
661 | if (e->fp) |
661 | if (e->fp) |
662 | fclose (e->fp); |
662 | fclose (e->fp); |
663 | if (openlog (e) == NULL) |
663 | if (openlog (e) == NULL) |
664 | continue; |
664 | continue; |
|
|
665 | if (fstat (fileno (e->fp), &stats) < 0) |
|
|
666 | continue; |
665 | } |
667 | } |
666 | |
668 | |
667 | /* HACK this - stats can be uninitialised here (if the file |
|
|
668 | * didn't exist when stat() was called, but was recreated during |
|
|
669 | * the sleep(1)) */ |
|
|
670 | if (stats.st_ino != e->inode) |
669 | if (stats.st_ino != e->inode) |
671 | { /* file renamed? */ |
670 | { /* file renamed? */ |
672 | if (e->fp) |
671 | if (e->fp) |
673 | fclose (e->fp); |
672 | fclose (e->fp); |
674 | if (openlog (e) == NULL) |
673 | if (openlog (e) == NULL) |
… | |
… | |
731 | */ |
730 | */ |
732 | static void |
731 | static void |
733 | split_line (int idx, const char *str, unsigned long color) |
732 | split_line (int idx, const char *str, unsigned long color) |
734 | { |
733 | { |
735 | int l = strlen (str); |
734 | int l = strlen (str); |
|
|
735 | int last_wrapped = 0; |
736 | const char *p = str; |
736 | const char *p = str; |
|
|
737 | static int continuation_width = -1; |
|
|
738 | static int continuation_length; |
|
|
739 | |
|
|
740 | /* only calculate the continuation's width once */ |
|
|
741 | if (continuation_width == -1) |
|
|
742 | { |
|
|
743 | continuation_length = strlen(continuation); |
|
|
744 | continuation_width = XmbTextEscapement (fontset, continuation, continuation_length); |
|
|
745 | } |
737 | |
746 | |
738 | do |
747 | do |
739 | { |
748 | { |
740 | const char *beg = p; |
749 | const char *beg = p; |
|
|
750 | int w = last_wrapped ? continuation_width : 0; |
741 | int w = 0, wrapped = 0; |
751 | int wrapped = 0; |
742 | const char *break_p = NULL; |
752 | const char *break_p = NULL; |
743 | |
753 | |
744 | while (*p) |
754 | while (*p) |
745 | { |
755 | { |
746 | /* find the length in bytes of the next multibyte character */ |
756 | /* find the length in bytes of the next multibyte character */ |
… | |
… | |
750 | |
760 | |
751 | /* find the width in pixels of the next character */ |
761 | /* find the width in pixels of the next character */ |
752 | int cw = XmbTextEscapement (fontset, p, len); |
762 | int cw = XmbTextEscapement (fontset, p, len); |
753 | if (cw + w > width - effect_x_space) |
763 | if (cw + w > width - effect_x_space) |
754 | { |
764 | { |
|
|
765 | if (p == beg) |
|
|
766 | { |
|
|
767 | fprintf(stderr, "we can't even fit a single character onto the line\n"); |
|
|
768 | if (len == 1) fprintf(stderr, "(the character we couldn't fit was '%c')\n", *p); |
|
|
769 | exit(1); |
|
|
770 | } |
|
|
771 | |
755 | wrapped = 1; |
772 | wrapped = 1; |
756 | break; |
773 | break; |
757 | } |
774 | } |
758 | |
775 | |
759 | if (opt_wordwrap && len == 1 && p[0] == ' ') |
776 | if (opt_wordwrap && len == 1 && p[0] == ' ') |
… | |
… | |
772 | l += p - break_p; |
789 | l += p - break_p; |
773 | p = break_p; |
790 | p = break_p; |
774 | } |
791 | } |
775 | |
792 | |
776 | { |
793 | { |
|
|
794 | /* HACK-4 - consider inserting the 'continuation string' |
|
|
795 | * before the rest of the wrapped line */ |
|
|
796 | int len = p - beg + (last_wrapped ? continuation_length : 0); |
777 | char *s = xmalloc (p - beg + 1); |
797 | char *s = xmalloc (len + 1); |
|
|
798 | if (last_wrapped) |
|
|
799 | { |
|
|
800 | memcpy (s, continuation, continuation_length); |
|
|
801 | memcpy (s + continuation_length, beg, p - beg); |
|
|
802 | } |
|
|
803 | else |
778 | memcpy (s, beg, p - beg); |
804 | memcpy (s, beg, len); |
|
|
805 | |
779 | s[p - beg] = 0; |
806 | s[len] = 0; |
780 | insert_line (idx); |
807 | insert_line (idx); |
781 | lines[idx].line = s; |
808 | lines[idx].line = s; |
782 | lines[idx].len = p - beg; |
809 | lines[idx].len = len; |
783 | lines[idx].color = color; |
810 | lines[idx].color = color; |
784 | } |
811 | } |
785 | |
812 | |
786 | /* if we wrapped at a space, don't display the space */ |
813 | /* if we wrapped at a space, don't display the space */ |
787 | if (opt_wordwrap && wrapped && break_p && break_p != beg) |
814 | if (opt_wordwrap && wrapped && break_p && break_p != beg) |
788 | { |
815 | { |
789 | l--; |
816 | l--; |
790 | p++; |
817 | p++; |
791 | } |
818 | } |
|
|
819 | |
|
|
820 | last_wrapped = wrapped; |
792 | } |
821 | } |
793 | while (l); |
822 | while (l); |
794 | } |
823 | } |
795 | |
824 | |
796 | /* |
825 | /* |
… | |
… | |
866 | |
895 | |
867 | /* print filename if any, and if last line was from |
896 | /* print filename if any, and if last line was from |
868 | * different file */ |
897 | * different file */ |
869 | if (!opt_nofilename && lastprinted != current && current->desc[0]) |
898 | if (!opt_nofilename && lastprinted != current && current->desc[0]) |
870 | { |
899 | { |
871 | char buf[1024]; /* HACK */ |
900 | char buf[1024]; /* HACK-5 */ |
872 | snprintf (buf, sizeof (buf), "[%s]", current->desc); |
901 | snprintf (buf, sizeof (buf), "[%s]", current->desc); |
873 | split_line (listlen - 1, buf, current->color); |
902 | split_line (listlen - 1, buf, current->color); |
874 | } |
903 | } |
875 | |
904 | |
876 | /* if this is the same file we showed last, and the |
905 | /* if we're dealing with partial lines, and the last |
877 | * last time we showed it, it wasn't finished, then |
906 | * time we showed the line it wasn't finished ... */ |
878 | * append to the last line shown */ |
|
|
879 | if (lastprinted == current && current->lastpartial) |
|
|
880 | append_line (listlen - 1, current->buf); |
|
|
881 | else if (current->lastpartial) |
907 | if (!opt_whole && current->lastpartial) |
882 | { |
908 | { |
|
|
909 | /* if this is the same file we showed last then |
|
|
910 | append to the last line shown */ |
|
|
911 | if (lastprinted == current) |
|
|
912 | append_line (listlen - 1, current->buf); |
|
|
913 | else |
|
|
914 | { |
|
|
915 | /* but if a different file has been shown in the |
|
|
916 | * mean time, make a new line, starting with the |
|
|
917 | * continuation string */ |
883 | split_line (listlen - 1, continuation, current->color); |
918 | split_line (listlen - 1, continuation, current->color); |
884 | append_line (listlen - 1, current->buf); |
919 | append_line (listlen - 1, current->buf); |
|
|
920 | } |
885 | } |
921 | } |
886 | else |
922 | else |
|
|
923 | /* otherwise just make a plain and simple new line */ |
887 | split_line (listlen - 1, current->buf, current->color); |
924 | split_line (listlen - 1, current->buf, current->color); |
888 | |
925 | |
889 | free (current->buf), current->buf = 0; |
926 | free (current->buf), current->buf = 0; |
890 | current->index = listlen - 1; |
927 | current->index = listlen - 1; |
891 | lastprinted = current; |
928 | lastprinted = current; |
… | |
… | |
1108 | |
1145 | |
1109 | e->fname = xstrdup (fname); |
1146 | e->fname = xstrdup (fname); |
1110 | if (openlog (e) == NULL) |
1147 | if (openlog (e) == NULL) |
1111 | perror (fname), exit (1); |
1148 | perror (fname), exit (1); |
1112 | |
1149 | |
1113 | l = strlen (desc); |
1150 | e->desc = xstrdup (desc); |
1114 | /* HACK on this - width is in pixels now */ |
|
|
1115 | if (l > width - 2) /* must account for [ ] */ |
|
|
1116 | l = width - 2; |
|
|
1117 | e->desc = xmalloc (l + 1); |
|
|
1118 | memcpy (e->desc, desc, l); |
|
|
1119 | *(e->desc + l) = '\0'; |
|
|
1120 | } |
1151 | } |
1121 | |
1152 | |
1122 | e->color = GetColor (fcolor); |
1153 | e->color = GetColor (fcolor); |
1123 | e->partial = 0; |
1154 | e->partial = 0; |
1124 | e->next = NULL; |
1155 | e->next = NULL; |
… | |
… | |
1142 | { |
1173 | { |
1143 | fprintf (stderr, "Specify at most one of -partial and -whole\n"); |
1174 | fprintf (stderr, "Specify at most one of -partial and -whole\n"); |
1144 | exit (1); |
1175 | exit (1); |
1145 | } |
1176 | } |
1146 | |
1177 | |
1147 | /* HACK this - do we want to allow both -shade and -outline? */ |
1178 | /* HACK-7: do we want to allow both -shade and -outline? */ |
1148 | if (opt_shade && opt_outline) |
1179 | if (opt_shade && opt_outline) |
1149 | { |
1180 | { |
1150 | fprintf (stderr, "Specify at most one of -shade and -outline\n"); |
1181 | fprintf (stderr, "Specify at most one of -shade and -outline\n"); |
1151 | exit (1); |
1182 | exit (1); |
1152 | } |
1183 | } |
1153 | |
1184 | |
1154 | if (opt_partial) |
1185 | if (opt_partial) |
1155 | /* if we specifically requested to see partial lines then don't insist on whole lines */ |
1186 | /* if we specifically requested to see partial lines then don't insist on whole lines */ |
1156 | opt_whole = 0; |
1187 | opt_whole = 0; |
1157 | else if (file_count > 1) |
1188 | else if (file_count > 1) |
1158 | /* otherwise, if we've viewing multiple files, default to showing whole lines */ |
1189 | /* otherwise, if we're viewing multiple files, default to showing whole lines */ |
1159 | opt_whole = 1; |
1190 | opt_whole = 1; |
1160 | |
1191 | |
1161 | #if HAS_REGEX |
1192 | #if HAS_REGEX |
1162 | if (transform) |
1193 | if (transform) |
1163 | { |
1194 | { |