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.56 by pcg, Fri Apr 9 04:26:52 2004 UTC

1/* 1/*
2 * Copyright 2001 by Marco d'Itri <md@linux.it> 2 * Copyright 2001 by Marco d'Itri <md@linux.it>
3 * Copyright 2000,2001,2002,2003,2004 3 * Copyright 2000,2001,2002,2003,2004
4 * Marc Lehmann <pcg@goof.com>, 4 * Marc Lehmann <pcg@goof.com>,
5 * Chris Moore <chris.moore@mail.com>,
5 * and many others, see README 6 * and many others, see README
6 * 7 *
7 * Original version by Mike Baker. 8 * Original version by Mike Baker.
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or 12 * the Free Software Foundation; either version 2 of the License, or
20 * along with this program; if not, write to the Free Software 21 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22 */ 23 */
23 24
24#include "config.h" 25#include "config.h"
26#include <assert.h>
25#include <stdlib.h> 27#include <stdlib.h>
26#include <stdio.h> 28#include <stdio.h>
27#include <unistd.h> 29#include <unistd.h>
28#include <string.h> 30#include <string.h>
29#include <signal.h> 31#include <signal.h>
45#endif 47#endif
46 48
47#define SHADE_X 2 49#define SHADE_X 2
48#define SHADE_Y 2 50#define SHADE_Y 2
49 51
52/* some italic fonts still go over the margin - this margin of error cleans up the mess */
53#define MARGIN_OF_ERROR 2
54
50/* data structures */ 55/* data structures */
51struct logfile_entry 56struct logfile_entry
52{ 57{
53 struct logfile_entry *next; 58 struct logfile_entry *next;
54 59
55 char *fname; /* name of file */ 60 char *fname; /* name of file */
56 char *desc; /* alternative description */ 61 char *desc; /* alternative description */
57 char *buf; /* text read but not yet displayed */ 62 char *buf; /* text read but not yet displayed */
63 const char *fontname;
64 XFontSet fontset;
65 int font_height;
66 int font_ascent;
58 FILE *fp; /* FILE struct associated with file */ 67 FILE *fp; /* FILE struct associated with file */
59 ino_t inode; /* inode of the file opened */ 68 ino_t inode; /* inode of the file opened */
60 off_t last_size; /* file size at the last check */ 69 off_t last_size; /* file size at the last check */
61 unsigned long color; /* color to be used for printing */ 70 unsigned long color; /* color to be used for printing */
62 int partial; /* true if the last line isn't complete */ 71 int partial; /* true if the last line isn't complete */
63 int lastpartial; /* true if the previous output wasn't complete */ 72 int lastpartial; /* true if the previous output wasn't complete */
64 int index; /* index into linematrix of a partial line */ 73 struct line_node *last; /* last line we output */
65 int modified; /* true if line is modified & needs displaying */ 74 int modified; /* true if line is modified & needs displaying */
66}; 75};
67 76
77struct line_node
78{
79 struct line_node *next;
80 struct line_node *prev;
81 struct logfile_entry *logfile;
82
83 char *line; /* the text of the line (so far) */
84 int len; /* the length of the line (in bytes) so far */
85 int wrapped_left; /* true if wrapped from the previous line */
86 int wrapped_right; /* true if wrapped to the next line */
87 struct breakinfo *breaks; /* array of indicies to spaces if wrapped_right */
88 int num_words; /* the number of words in the line */
89 int free_pixels; /* the number of free pixels to spread out */
90};
91
92struct breakinfo
93{
94 int index; /* index into string of start of substring */
95 int width; /* width in pixels of start of substring */
96 int len; /* length of substring */
97};
98
68struct linematrix 99struct displaymatrix
69{ 100{
70 char *line; 101 char *line;
71 int len; 102 int len;
103 int offset;
104 int buffer_size;
72 unsigned long color; 105 unsigned long color;
73}; 106};
74 107
75struct displaymatrix
76{
77 char *line;
78 int len;
79 int buffer_size;
80};
81
82/* global variables */ 108/* global variables */
83struct linematrix *lines; 109struct line_node *linelist = NULL, *linelist_tail = NULL;
84struct displaymatrix *display; 110struct displaymatrix *display;
111int continuation_width = -1;
112int continuation_color;
113int continuation_length;
114
115/* HACK - ideally listlen will start at however many '~'s will fit on
116 * the screen */
85int width = STD_WIDTH, height = STD_HEIGHT, listlen; 117int width = STD_WIDTH, height = STD_HEIGHT, listlen = 50;
86int win_x = LOC_X, win_y = LOC_Y; 118int win_x = LOC_X, win_y = LOC_Y;
87int font_ascent, font_height;
88int effect_x_space, effect_y_space; /* how much space does shading / outlining take up */ 119int 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 */ 120int effect_x_offset, effect_y_offset; /* and how does it offset the usable space */
90int do_reopen; 121int do_reopen;
91struct timeval interval = { 2, 400000 }; 122struct timeval interval = { 2, 400000 };
92XFontSet fontset;
93 123
94/* command line options */ 124/* command line options */
95int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename, 125int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename,
96 opt_outline, opt_noflicker, opt_whole, opt_update, opt_wordwrap, 126 opt_outline, opt_noflicker, opt_whole, opt_update, opt_wordwrap,
97 geom_mask, reload = 0; 127 opt_justify, geom_mask, reload = 0;
98const char *command = NULL, 128const char *command = NULL,
99 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR, 129 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR,
100 *continuation = "[+]"; 130 *continuation = "|| ", *cont_color = DEF_CONT_COLOR;
101 131
102struct logfile_entry *loglist = NULL, *loglist_tail = NULL; 132struct logfile_entry *loglist = NULL, *loglist_tail = NULL;
103 133
104Display *disp; 134Display *disp;
105Window root; 135Window root;
168} 198}
169 199
170void 200void
171blank_window (int dummy) 201blank_window (int dummy)
172{ 202{
173 XClearArea (disp, root, win_x - 2, win_y - 2, width + 5, height + 5, False); 203 XClearArea (disp, root, win_x, win_y, width + MARGIN_OF_ERROR, height, False);
174 XFlush (disp); 204 XFlush (disp);
175 exit (0); 205 exit (0);
176} 206}
177 207
178/* X related functions */ 208/* X related functions */
205 if (SWM_VROOT != None) 235 if (SWM_VROOT != None)
206 { 236 {
207 Window unused, *windows; 237 Window unused, *windows;
208 unsigned int count; 238 unsigned int count;
209 239
210 if (XQueryTree (display, real_root_window, &unused, &unused, &windows, 240 if (XQueryTree (display, real_root_window, &unused, &unused, &windows, &count))
211 &count))
212 { 241 {
213 int i; 242 int i;
214 243
215 for (i = 0; i < count; i++) 244 for (i = 0; i < count; i++)
216 { 245 {
226 { 255 {
227 if (type != None) 256 if (type != None)
228 { 257 {
229 if (type == XA_WINDOW) 258 if (type == XA_WINDOW)
230 { 259 {
260 root = *(Window *)virtual_root_window;
231 XFree (windows); 261 XFree (windows);
232 return (Window) virtual_root_window; 262 XFree (virtual_root_window);
263 return root;
233 } 264 }
234 else 265 else
235 fprintf (stderr,
236 "__SWM_VROOT property type mismatch"); 266 fprintf (stderr, "__SWM_VROOT property type mismatch");
237 } 267 }
238 } 268 }
239 else 269 else
240 fprintf (stderr, 270 fprintf (stderr,
241 "failed to get __SWM_VROOT property on window 0x%lx", 271 "failed to get __SWM_VROOT property on window 0x%lx",
260InitWindow (void) 290InitWindow (void)
261{ 291{
262 XGCValues gcv; 292 XGCValues gcv;
263 unsigned long gcm; 293 unsigned long gcm;
264 int screen, ScreenWidth, ScreenHeight; 294 int screen, ScreenWidth, ScreenHeight;
295 struct logfile_entry *e;
265 296
266 if (!(disp = XOpenDisplay (dispname))) 297 if (!(disp = XOpenDisplay (dispname)))
267 { 298 {
268 fprintf (stderr, "Can't open display %s.\n", dispname); 299 fprintf (stderr, "Can't open display %s.\n", dispname);
269 exit (1); 300 exit (1);
279 gcv.graphics_exposures = True; 310 gcv.graphics_exposures = True;
280 WinGC = XCreateGC (disp, root, gcm, &gcv); 311 WinGC = XCreateGC (disp, root, gcm, &gcv);
281 XMapWindow (disp, root); 312 XMapWindow (disp, root);
282 XSetForeground (disp, WinGC, GetColor (DEF_COLOR)); 313 XSetForeground (disp, WinGC, GetColor (DEF_COLOR));
283 314
315 for (e = loglist; e; e = e->next)
284 { 316 {
285 char **missing_charset_list; 317 char **missing_charset_list;
286 int missing_charset_count; 318 int missing_charset_count;
287 char *def_string; 319 char *def_string;
288 320
289 fontset = XCreateFontSet (disp, fontname, 321 e->fontset = XCreateFontSet (disp, e->fontname,
290 &missing_charset_list, &missing_charset_count, 322 &missing_charset_list, &missing_charset_count,
291 &def_string); 323 &def_string);
292 324
293 if (missing_charset_count) 325 if (missing_charset_count)
326 {
327 fprintf (stderr,
328 "Missing charsets in String to FontSet conversion (%s)\n",
329 missing_charset_list[0]);
330 XFreeStringList (missing_charset_list);
331 }
332
333 if (!e->fontset)
334 {
335 fprintf (stderr, "unable to create fontset for font '%s', exiting.\n", e->fontname);
336 exit (1);
337 }
338
294 { 339 {
295 fprintf (stderr, 340 XFontSetExtents *xfe = XExtentsOfFontSet (e->fontset);
296 "Missing charsets in String to FontSet conversion (%s)\n", 341
297 missing_charset_list[0]); 342 e->font_height = xfe->max_logical_extent.height;
298 XFreeStringList (missing_charset_list); 343 e->font_ascent = -xfe->max_logical_extent.y;
299 } 344 }
300 }
301
302 if (!fontset)
303 { 345 }
304 fprintf (stderr, "unable to create fontset, exiting.\n");
305 exit (1);
306 }
307
308 {
309 XFontSetExtents *xfe = XExtentsOfFontSet (fontset);
310
311 font_height = xfe->max_logical_extent.height;
312 font_ascent = -xfe->max_logical_extent.y;
313 }
314 346
315 if (geom_mask & XNegative) 347 if (geom_mask & XNegative)
316 win_x = win_x + ScreenWidth - width; 348 win_x = win_x + ScreenWidth - width;
317 if (geom_mask & YNegative) 349 if (geom_mask & YNegative)
318 win_y = win_y + ScreenHeight - height; 350 win_y = win_y + ScreenHeight - height;
319 351
320 if (opt_outline) 352 if (opt_outline)
321 { 353 {
322 /* adding outline increases the total width and height by 2 354 /* adding outline increases the total width and height by 2
323 pixels each, and offsets the text one pixel right and one 355 pixels each, and offsets the text one pixel right and one
324 pixel down */ 356 pixel down */
325 effect_x_space = effect_y_space = 2; 357 effect_x_space = effect_y_space = 2;
326 effect_x_offset = effect_y_offset = 1; 358 effect_x_offset = effect_y_offset = 1;
327 } 359 }
328 else if (opt_shade) 360 else if (opt_shade)
329 { 361 {
330 /* adding a shadow increases the space used */ 362 /* adding a shadow increases the space used */
331 effect_x_space = abs(SHADE_X); 363 effect_x_space = abs (SHADE_X);
332 effect_y_space = abs(SHADE_Y); 364 effect_y_space = abs (SHADE_Y);
365
333 /* if the shadow is to the right and below then we don't need 366 /* 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 367 * to move the text to make space for it, but shadows to the left
335 * and above need accomodating */ 368 * and above need accomodating */
336 effect_x_offset = SHADE_X > 0 ? 0 : -SHADE_X; 369 effect_x_offset = SHADE_X > 0 ? 0 : -SHADE_X;
337 effect_y_offset = SHADE_Y > 0 ? 0 : -SHADE_Y; 370 effect_y_offset = SHADE_Y > 0 ? 0 : -SHADE_Y;
340 { 373 {
341 effect_x_space = effect_y_space = 0; 374 effect_x_space = effect_y_space = 0;
342 effect_x_offset = effect_y_offset = 0; 375 effect_x_offset = effect_y_offset = 0;
343 } 376 }
344 377
345 /* if we are using -shade or -outline, there will be less usable
346 * space for output */
347 listlen = (height - effect_y_space) / font_height;
348
349 if (!listlen)
350 {
351 fprintf (stderr, "height too small for a single line, setting to %d\n",
352 font_height);
353 listlen = 1;
354 }
355
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); 378 XSelectInput (disp, root, ExposureMask | FocusChangeMask);
363} 379}
364 380
365/* 381/*
366 * if redraw() is passwd a non-zero argument, it does a complete 382 * if redraw () is passwd a non-zero argument, it does a complete
367 * redraw, rather than an update. if the argument is zero (and 383 * redraw, rather than an update. if the argument is zero (and
368 * -noflicker is in effect) then only the lines which have changed 384 * -noflicker is in effect) then only the lines which have changed
369 * since the last draw are redrawn. 385 * since the last draw are redrawn.
370 * 386 *
371 * the rest is handled by regular refresh()'es 387 * the rest is handled by regular refresh ()'es
372 */ 388 */
373void 389void
374redraw (int redraw_all) 390redraw (int redraw_all)
375{ 391{
376 XSetClipMask (disp, WinGC, None); 392 XSetClipMask (disp, WinGC, None);
377 refresh (0, 32768, 1, redraw_all); 393 refresh (0, 32768, 1, redraw_all);
378} 394}
379 395
396void draw_text (Display *disp, Window root, GC WinGC, int x, int y, struct line_node *line, int foreground)
397{
398 if (line->wrapped_right && opt_justify && line->breaks)
399 {
400 int i;
401 for (i = 0; i < line->num_words; i++)
402 XmbDrawString (disp, root, line->logfile->fontset, WinGC,
403 x + line->breaks[i].width + ((i * line->free_pixels) / (line->num_words - 1))
404 + 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, line->logfile->fontset, WinGC, x, y, continuation, continuation_length);
412 }
413 }
414 else
415 {
416 XmbDrawString (disp, root, line->logfile->fontset, WinGC, x + continuation_width * line->wrapped_left,
417 y, line->line, line->len);
418
419 if (line->wrapped_left)
420 {
421 if (foreground) XSetForeground (disp, WinGC, continuation_color);
422 XmbDrawString (disp, root, line->logfile->fontset, WinGC, x, y, continuation, continuation_length);
423 }
424 }
425}
426
380/* Just redraw everything without clearing (i.e. after an EXPOSE event) */ 427/* Just redraw everything without clearing (i.e. after an EXPOSE event) */
381void 428void
382refresh (int miny, int maxy, int clear, int refresh_all) 429refresh (int miny, int maxy, int clear, int refresh_all)
383{ 430{
384 int lin; 431 int lin = 0;
385 int offset = listlen * font_height + font_ascent + effect_y_offset; 432 int space = height;
433 int offset;
386 unsigned long black_color = GetColor ("black"); 434 unsigned long black_color = GetColor ("black");
435 struct line_node *line;
436 int step_per_line;
437 int foreground = 0;
387 438
388 miny -= win_y + font_height; 439 if (opt_reverse)
389 maxy -= win_y - font_height; 440 offset = effect_y_offset;
441 else
442 offset = height + effect_y_offset;
443
444 miny -= win_y;
445 maxy -= win_y;
390 446
391 if (clear && !opt_noflicker) 447 if (clear && !opt_noflicker)
392 XClearArea (disp, root, win_x, win_y, width, height, False); 448 XClearArea (disp, root, win_x, win_y, width + MARGIN_OF_ERROR, height, False);
393 449
394 for (lin = listlen; lin--;) 450 for (line = linelist; line; line = line->next, lin++)
395 { 451 {
396 struct linematrix *line = lines + (opt_reverse ? listlen - lin - 1 : lin);
397 struct displaymatrix *display_line = display + lin; 452 struct displaymatrix *display_line;
398 453
399 offset -= font_height; 454 if (opt_noflicker && lin >= listlen)
455 {
456 int i = listlen;
457 listlen *= 1.5;
458 display = xrealloc(display, listlen * sizeof(struct displaymatrix));
459 for (; i < listlen; i++)
460 {
461 display[i].line = xstrdup ("");
462 display[i].len = 0;
463 display[i].offset = 0;
464 display[i].buffer_size = 0;
465 }
466 }
400 467
468 display_line = display + lin;
469
470 step_per_line = line->logfile->font_height + effect_y_space;
471 if (step_per_line > space)
472 break;
473
474 if (!opt_reverse)
475 offset -= step_per_line;
476
477 offset += line->logfile->font_ascent;
478
479 miny -= line->logfile->font_height;
480 maxy += line->logfile->font_height;
481
401 if (offset < miny || offset > maxy) 482 if (offset >= miny && offset <= maxy)
402 continue; 483 {
403
404 /* if this line is a different than it was, then it 484 /* if this line is a different than it was, then it
405 * needs displaying */ 485 * needs displaying */
406 if (!opt_noflicker 486 if (!opt_noflicker
407 || refresh_all 487 || refresh_all
408 || display_line->len != line->len 488 || display_line->len != line->len
489 || display_line->color != line->logfile->color
490 || display_line->offset != offset
409 || memcmp (display_line->line, line->line, line->len)) 491 || memcmp (display_line->line, line->line, line->len))
410 { 492 {
411 /* don't bother updating the record of what has been 493 /* don't bother updating the record of what has been
412 * displayed if -noflicker isn't in effect, since we redraw 494 * displayed if -noflicker isn't in effect, since we redraw
413 * the whole display every time anyway */ 495 * the whole display every time anyway */
414 if (opt_noflicker) 496 if (opt_noflicker)
415 { 497 {
416 /* update the record of what has been displayed; 498 /* update the record of what has been displayed;
417 * first make sure the buffer is big enough */ 499 * first make sure the buffer is big enough */
418 if (display_line->buffer_size <= line->len) 500 if (display_line->buffer_size < line->len)
419 { 501 {
420 display_line->buffer_size = line->len + 1; 502 display_line->buffer_size = line->len;
421 display_line->line = xrealloc (display_line->line, display_line->buffer_size); 503 display_line->line = xrealloc (display_line->line, display_line->buffer_size);
422 } 504 }
423 505
424 display_line->len = line->len; 506 display_line->len = line->len;
507 display_line->color = line->logfile->color;
508 display_line->offset = offset;
425 memcpy (display_line->line, line->line, line->len); 509 memcpy (display_line->line, line->line, line->len);
426 510
427 if (clear) 511 if (clear)
512 {
513#ifdef DEBUG
514 static int toggle;
515 toggle = 1 - toggle;
516 XSetForeground (disp, WinGC, toggle ? GetColor ("cyan") : GetColor ("yellow"));
517 XFillRectangle (disp, root, WinGC, win_x, win_y + offset - line->logfile->font_ascent,
518 width, step_per_line);
519#else /* DEBUG */
428 XClearArea (disp, root, win_x, win_y + offset - font_ascent, 520 XClearArea (disp, root, win_x, win_y + offset - line->logfile->font_ascent,
429 width + effect_x_space, font_height + effect_y_space, False); 521 width + MARGIN_OF_ERROR, step_per_line, False);
430 } 522#endif /* DEBUG */
523 }
524 }
431 525
432 if (opt_outline) 526 if (opt_outline)
433 { 527 {
434 int x, y; 528 int x, y;
435 XSetForeground (disp, WinGC, black_color); 529 XSetForeground (disp, WinGC, black_color);
436 530
437 for (x = -1; x < 2; x += 2) 531 for (x = -1; x <= 1; x += 2)
438 for (y = -1; y < 2; y += 2) 532 for (y = -1; y <= 1; y += 2)
439 XmbDrawString (disp, root, fontset, WinGC, 533 draw_text (disp, root, WinGC,
440 win_x + effect_x_offset + x, 534 win_x + effect_x_offset + x,
441 win_y + y + offset, 535 win_y + y + offset, line, foreground = 0);
442 line->line, line->len);
443 } 536 }
444 else if (opt_shade) 537 else if (opt_shade)
445 { 538 {
446 XSetForeground (disp, WinGC, black_color); 539 XSetForeground (disp, WinGC, black_color);
447 XmbDrawString (disp, root, fontset, WinGC, 540 draw_text (disp, root, WinGC,
448 win_x + effect_x_offset + SHADE_X, 541 win_x + effect_x_offset + SHADE_X,
449 win_y + offset + SHADE_Y, 542 win_y + offset + SHADE_Y, line, foreground = 0);
450 line->line, line->len);
451 } 543 }
452 544
453 XSetForeground (disp, WinGC, line->color); 545 XSetForeground (disp, WinGC, line->logfile->color);
454 XmbDrawString (disp, root, fontset, WinGC, 546 draw_text (disp, root, WinGC,
455 win_x + effect_x_offset, 547 win_x + effect_x_offset,
456 win_y + offset, 548 win_y + offset, line, foreground = 1);
457 line->line, line->len); 549 }
458 } 550 }
551
552 if (opt_reverse)
553 offset += step_per_line;
554 offset -= line->logfile->font_ascent;
555
556 miny += line->logfile->font_height;
557 maxy -= line->logfile->font_height;
558
559 space -= step_per_line;
560 }
561
562 if (space > 0 && clear)
563 {
564#ifdef DEBUG
565 XSetForeground (disp, WinGC, GetColor ("orange"));
566 XFillRectangle (disp, root, WinGC, win_x, win_y + offset - (opt_reverse ? 0 : space),
567 width, space);
568#else /* DEBUG */
569 XClearArea (disp, root, win_x, win_y + offset - (opt_reverse ? 0 : space),
570 width + MARGIN_OF_ERROR, space, False);
571#endif
572 }
573
574 /* any lines that didn't just get looked at are never going to be, so break the chain */
575 if (line) line->prev->next = 0;
576
577 /* and throw them all away */
578 while (line)
579 {
580 struct line_node *this = line;
581 line = line->next;
582 if (this->logfile && this->logfile->last == this)
583 this->logfile->last = NULL;
584 free (this->line);
585 free (this->breaks);
586 free (this);
459 } 587 }
460 588
461 if (opt_frame) 589 if (opt_frame)
462 { 590 {
463 XSetForeground (disp, WinGC, GetColor (def_color)); 591 XSetForeground (disp, WinGC, GetColor (def_color));
592 /* note that XDrawRectangle() draws a rectangle one pixel bigger
593 * in both dimensions than you ask for, hence the subtractions.
594 * XFillRectangle() doesn't suffer from this problem */
464 XDrawRectangle (disp, root, WinGC, win_x - 0, win_y - 0, width - 1, height - 1); 595 XDrawRectangle (disp, root, WinGC, win_x - 0, win_y - 0, width - 1, height - 1);
465 } 596 }
466} 597}
467 598
468#if HAS_REGEX 599#if HAS_REGEX
485 regmatch_t matched[16]; 616 regmatch_t matched[16];
486 617
487 i = regexec (transformre, s, 16, matched, 0); 618 i = regexec (transformre, s, 16, matched, 0);
488 if (i == 0) 619 if (i == 0)
489 { /* matched */ 620 { /* matched */
490 int match_start = matched[0].rm_so; 621 int match_start = matched[0].rm_so;
491 int match_end = matched[0].rm_eo; 622 int match_end = matched[0].rm_eo;
492 int old_len = match_end - match_start; 623 int old_len = match_end - match_start;
493 int new_len = strlen(transform_to); 624 int new_len = strlen (transform_to);
494 int old_whole_len = strlen(s); 625 int old_whole_len = strlen (s);
626
495 printf("regexp was matched by '%s' - replace with '%s'\n", s, transform_to); 627 printf ("regexp was matched by '%s' - replace with '%s'\n", s, transform_to);
496 printf("match is from %d to %d\n", 628 printf ("match is from %d to %d\n", match_start, match_end);
497 match_start, match_end);
498 if (new_len > old_len) { 629 if (new_len > old_len)
499 s = xrealloc(s, old_whole_len + new_len - old_len); 630 s = xrealloc (s, old_whole_len + new_len - old_len);
500 } 631
501 if (new_len != old_len) { 632 if (new_len != old_len)
633 {
502 memcpy(s + match_end + new_len - old_len, 634 memcpy (s + match_end + new_len - old_len,
503 s + match_end, 635 s + match_end,
504 old_whole_len - match_end); 636 old_whole_len - match_end);
505 s[old_whole_len + new_len - old_len] = '\0'; 637 s[old_whole_len + new_len - old_len] = '\0';
506 } 638 }
639
507 memcpy(s + match_start, 640 memcpy (s + match_start,
508 transform_to, 641 transform_to,
509 new_len); 642 new_len);
510 printf("transformed to '%s'\n", s); 643 printf ("transformed to '%s'\n", s);
511 } 644 }
512 else 645 else
513 {
514 printf("regexp was not matched by '%s'\n", s); 646 printf ("regexp was not matched by '%s'\n", s);
515 }
516 } 647 }
517} 648}
518#endif 649#endif
519 650
651/*
652 * appends p2 to the end of p1, if p1 is not null
653 * otherwise allocates a new string and copies p2 to it
654 */
520char * 655char *
521concat_line (const char *p1, const char *p2) 656concat_line (char *p1, const char *p2)
522{ 657{
658 assert(p2);
659
523 int l1 = p1 ? strlen (p1) : 0; 660 int l1 = p1 ? strlen (p1) : 0;
524 int l2 = strlen (p2); 661 int l2 = strlen (p2);
525 char *r = xmalloc (l1 + l2 + 1); 662 char *r;
526 663
527 memcpy (r, p1, l1); 664 if (p1)
665 r = xrealloc(p1, l1 + l2 + 1);
666 else
667 r = xmalloc (l2 + 1);
668
528 memcpy (r + l1, p2, l2); 669 memcpy (r + l1, p2, l2);
529 r[l1 + l2] = 0; 670 r[l1 + l2] = 0;
530 671
531 return r; 672 return r;
532} 673}
533 674
534/* 675/*
535 * HACK-1: This routine should read a single line, no matter how long. 676 * This routine can read a line of any length if it is called enough times.
536 */ 677 */
537int 678int
538lineinput (struct logfile_entry *logfile) 679lineinput (struct logfile_entry *logfile)
539{ 680{
540 char buff[1024], *p = buff; 681 char buff[1024], *p;
541 int ch; 682 int ch;
542 /* HACK-2: add on the length of any partial line which we will be appending to */ 683 /* 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; 684 int ofs = logfile->buf ? strlen (logfile->buf) : 0;
544 685
686 /* this loop ensures that the whole line is read, even if it's
687 * longer than the buffer. we need to do this because when --whole
688 * is in effect we don't know whether to display the line or not
689 * until we've seen how (ie. whether) it ends */
545 do 690 do
546 { 691 {
692 p = buff;
693 do
694 {
547 ch = fgetc (logfile->fp); 695 ch = fgetc (logfile->fp);
548 696
549 if (ch == '\n' || ch == EOF) 697 if (ch == '\n' || ch == EOF)
550 break; 698 break;
551 else if (ch == '\r') 699 else if (ch == '\r')
552 continue; /* skip */ 700 continue; /* skip */
553 else if (ch == '\t') 701 else if (ch == '\t')
554 { 702 {
555 do 703 do
556 { 704 {
557 *p++ = ' '; 705 *p++ = ' ';
706 ofs++;
707 }
708 while (ofs & 7);
709 }
710 else
711 {
712 *p++ = ch;
558 ofs++; 713 ofs++;
559 } 714 }
560 while (ofs & 7);
561 }
562 else
563 { 715 }
564 *p++ = ch;
565 ofs++;
566 }
567 }
568 while (p < buff + (sizeof buff) - 8 - 1); 716 while (p < buff + (sizeof buff) - 8 - 1);
569 717
570 if (p == buff && ch == EOF) 718 if (p == buff && ch == EOF)
571 return 0; 719 return 0;
572 720
573 *p = 0; 721 *p = 0;
574 722
575 p = concat_line (logfile->buf, buff); 723 p = logfile->buf = concat_line (logfile->buf, buff);
576 free (logfile->buf); logfile->buf = p; 724 }
725 while (ch != '\n' && ch != EOF);
577 726
578 logfile->lastpartial = logfile->partial; 727 logfile->lastpartial = logfile->partial;
579 /* there are 3 ways we could have exited the loop: reading '\n', 728 /* 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 729 * reaching EOF, or filling the buffer; the 2nd and 3rd of these
581 * both result in a partial line */ 730 * both result in a partial line */
582 logfile->partial = ch != '\n'; 731 logfile->partial = ch != '\n';
583 732
584 if (logfile->partial && opt_whole) 733 if (logfile->partial && opt_whole)
585 return 0; 734 return 0;
586 735
587#if HAS_REGEX 736#if HAS_REGEX
588 transform_line (logfile->buf); 737 transform_line (logfile->buf);
616 else 765 else
617 file->inode = stats.st_ino; 766 file->inode = stats.st_ino;
618 767
619 if (opt_noinitial) 768 if (opt_noinitial)
620 fseek (file->fp, 0, SEEK_END); 769 fseek (file->fp, 0, SEEK_END);
621 else if (stats.st_size > (listlen + 1) * width) 770 else /* if (stats.st_size > (listlen + 1) * width)
771 * HACK - 'width' is in pixels - how are we to know how much text will fit?
622 fseek (file->fp, -((listlen + 2) * width), SEEK_END); 772 * fseek (file->fp, -((listlen + 2) * width/10), SEEK_END); */
773 fseek (file->fp, -5000, SEEK_END);
623 774
624 file->last_size = stats.st_size; 775 file->last_size = stats.st_size;
625 return file->fp; 776 return file->fp;
626} 777}
627 778
670 { /* file renamed? */ 821 { /* file renamed? */
671 if (e->fp) 822 if (e->fp)
672 fclose (e->fp); 823 fclose (e->fp);
673 if (openlog (e) == NULL) 824 if (openlog (e) == NULL)
674 continue; 825 continue;
826 if (fstat (fileno (e->fp), &stats) < 0)
827 continue;
675 } 828 }
676 829
677 if (stats.st_size < e->last_size) 830 if (stats.st_size < e->last_size)
678 { /* file truncated? */ 831 { /* file truncated? */
679 fseek (e->fp, 0, SEEK_SET); 832 fseek (e->fp, 0, SEEK_SET);
681 } 834 }
682 } 835 }
683} 836}
684 837
685/* 838/*
686 * insert a single physical line (that must be short enough to fit) 839 * 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 840 * pointer to the new node.
688 * MUST then fill in lines[idx] with valid data. 841 * the caller MUST then fill in ret->line and ret->len with valid
842 * data.
843 */
844static struct line_node *
845new_line_node (struct logfile_entry *log)
846{
847 struct line_node *new = xmalloc (sizeof (struct line_node));
848
849 new->logfile = log;
850 new->wrapped_left = 0;
851 new->wrapped_right = 0;
852 new->breaks = 0;
853
854 assert(log);
855
856 if (!log || !log->last)
857 {
858 new->next = linelist;
859 new->next->prev = new;
860
861 new->prev = NULL;
862 linelist = new;
863 }
864 else
865 {
866 /* 2 pointers from the new node */
867 new->next = log->last;
868 new->prev = log->last->prev;
869
870 /* 2 pointers back to the new node */
871 if (new->next) new->next->prev = new;
872 if (new->prev) new->prev->next = new;
873
874 /* if this is a new first entry in the list then update
875 * 'linelist' */
876 if (log->last == linelist)
877 linelist = new;
878 }
879
880 /* update the logfile record */
881 if (log)
882 log->last = new;
883
884 return new;
885}
886
887/*
888 * this is called after either adding a new line or appending to an
889 * old one. in both cases it's possible that the line no longer fits,
890 * and needs wrapping. this function checks the last line associated
891 * with the supplied logfile.
689 */ 892 */
690static void 893static void
691insert_line (int idx) 894possibly_split_long_line (struct logfile_entry *log)
692{ 895{
693 int cur_line; 896 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); 897 int l = strlen (str);
735 int last_wrapped = 0;
736 const char *p = str; 898 char *p = str;
737 static int continuation_width = -1; 899 struct line_node *line;
738 static int continuation_length; 900 int spaces;
901 static struct breakinfo *breaks;
902 static int break_buffer_size;
739 903
740 /* only calculate the continuation's width once */ 904 /* only calculate the continuation's width once */
741 if (continuation_width == -1) 905 if (continuation_width == -1)
742 { 906 {
743 continuation_length = strlen(continuation); 907 continuation_length = strlen (continuation);
744 continuation_width = XmbTextEscapement (fontset, continuation, continuation_length); 908 continuation_width = XmbTextEscapement (log->fontset, continuation, continuation_length);
909 continuation_color = GetColor (cont_color);
910
911 /* make an array to store information about the location of
912 * spaces in the line */
913 if (opt_justify)
914 {
915 break_buffer_size = 32;
916 breaks = xmalloc (break_buffer_size * sizeof (struct breakinfo));
917 }
745 } 918 }
746 919
747 do 920 do
748 { 921 {
749 const char *beg = p; 922 const char *beg = p;
750 int w = last_wrapped ? continuation_width : 0; 923 int start_w = log->last->wrapped_left ? continuation_width : 0;
924 int w = start_w;
751 int wrapped = 0; 925 int wrapped = 0;
752 const char *break_p = NULL; 926 char *break_p = NULL;
927 int width_at_break_p = 0;
928 spaces = 0;
929
930 if (opt_justify)
931 breaks[spaces].index = breaks[spaces].width = 0;
753 932
754 while (*p) 933 while (*p)
755 { 934 {
935 int cw, len;
936
756 /* find the length in bytes of the next multibyte character */ 937 /* find the length in bytes of the next multibyte character */
757 int len = mblen (p, l); 938 len = mblen (p, l);
758 if (len <= 0) 939 if (len <= 0)
759 len = 1; /* ignore (don't skip) illegal character sequences */ 940 len = 1; /* ignore (don't skip) illegal character sequences */
760 941
761 /* find the width in pixels of the next character */ 942 /* find the width in pixels of the next character */
762 int cw = XmbTextEscapement (fontset, p, len); 943 cw = XmbTextEscapement (log->fontset, p, len);
944 if (opt_wordwrap && len == 1 && p[0] == ' ' && p != break_p + 1)
945 {
946 break_p = p;
947 width_at_break_p = w;
948 spaces++;
949
950 if (opt_justify)
951 {
952 /* increase the size of the 'breaks' array when
953 * necessary */
954 if (spaces >= break_buffer_size)
955 {
956 break_buffer_size *= 1.5;
957 breaks = xrealloc (breaks, break_buffer_size * sizeof (struct breakinfo));
958 }
959
960 /* store information about (a) the location of each
961 * space */
962 breaks[spaces].index = p + 1 - beg;
963 /* (b) the width (in pixels) of the string up to
964 * this space */
965 breaks[spaces].width = cw + w - start_w;
966 /* (c) the length of each 'word' */
967 breaks[spaces-1].len = breaks[spaces].index - breaks[spaces-1].index;
968 }
969 }
970
763 if (cw + w > width - effect_x_space) 971 if (cw + w > width - effect_x_space)
764 { 972 {
765 if (p == beg) 973 if (p == beg)
766 { 974 {
767 fprintf(stderr, "we can't even fit a single character onto the line\n"); 975 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); 976 if (len == 1) fprintf (stderr, "(the character we couldn't fit was '%c')\n", *p);
769 exit(1); 977 exit (1);
770 } 978 }
771 979
772 wrapped = 1; 980 wrapped = 1;
773 break; 981 break;
774 } 982 }
775
776 if (opt_wordwrap && len == 1 && p[0] == ' ')
777 break_p = p;
778 983
779 w += cw; 984 w += cw;
780 p += len; 985 p += len;
781 l -= len; 986 l -= len;
782 } 987 }
783 988
784 /* if we're wrapping at spaces, and the line is long enough to 989 /* 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 990 * 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 */ 991 * the first character on the line, then wrap at the space */
992 if (!wrapped)
993 break;
994
995 int prefix_len;
996
997 /* choose where to break the line */
787 if (opt_wordwrap && wrapped && break_p && break_p != beg) 998 if (opt_wordwrap && break_p && break_p != beg)
788 {
789 l += p - break_p;
790 p = break_p;
791 }
792
793 { 999 {
794 /* HACK-4 - consider inserting the 'continuation string' 1000 prefix_len = break_p - beg;
795 * before the rest of the wrapped line */ 1001 p = break_p;
796 int len = p - beg + (last_wrapped ? continuation_length : 0); 1002 w = width_at_break_p;
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 1003
806 s[len] = 0; 1004 /* if breaking at a space, skip all adjacent spaces */
807 insert_line (idx); 1005 while (*p == ' ')
808 lines[idx].line = s; 1006 {
809 lines[idx].len = len; 1007 int len = mblen (p, l);
810 lines[idx].color = color; 1008 if (len != 1) break;
1009 p++;
1010 }
1011
1012 if (opt_justify)
1013 {
1014 spaces--;
1015 breaks[spaces].len--;
1016 }
811 } 1017 }
1018 else
1019 prefix_len = p - beg;
812 1020
813 /* if we wrapped at a space, don't display the space */ 1021 /* make a copy of the tail end of the string */
814 if (opt_wordwrap && wrapped && break_p && break_p != beg) 1022 p = xstrdup (p);
815 {
816 l--;
817 p++;
818 }
819 1023
820 last_wrapped = wrapped; 1024 /* and reduce the size of the head of the string */
1025 log->last->line = xrealloc (log->last->line, prefix_len + 1);
1026 log->last->len = prefix_len;
1027 log->last->line[prefix_len] = '\0';
1028
1029 /* note that the head was wrapped on it's right */
1030 log->last->wrapped_right = 1;
1031
1032 /* 'spaces' includes any space we broke on; we can only justify
1033 * if there's at least one other space */
1034 if (opt_justify && spaces &&
1035 width - effect_x_space - width_at_break_p < spaces * log->font_height)
1036 {
1037 int i;
1038 log->last->free_pixels = width - effect_x_space - w;
1039 log->last->num_words = spaces + 1;
1040 log->last->breaks = malloc (log->last->num_words * sizeof (struct breakinfo));
1041 for (i = 0; i < log->last->num_words; i++)
1042 log->last->breaks[i] = breaks[i];
1043 }
1044
1045 line = new_line_node (log);
1046 line->line = p;
1047 l = line->len = strlen (p);
1048
1049 /* note that the tail end of the string is wrapped at its left */
1050 line->wrapped_left = 1;
821 } 1051 }
822 while (l); 1052 while (l);
1053}
1054
1055static void
1056insert_new_line (char *str, struct logfile_entry *log)
1057{
1058 struct line_node *new;
1059 new = new_line_node (log);
1060 new->line = str;
1061 new->len = strlen (str);
1062
1063 possibly_split_long_line (log);
823} 1064}
824 1065
825/* 1066/*
826 * append something to an existing physical line. this is done 1067 * append something to an existing physical line. this is done
827 * by deleting the file on-screen, concatenating the new data to it 1068 * by deleting the file on-screen, concatenating the new data to it
828 * and splitting it again. 1069 * and splitting it again.
829 */ 1070 */
830static void 1071static void
831append_line (int idx, const char *str) 1072append_to_existing_line (char *str, struct logfile_entry *log)
832{ 1073{
833 unsigned long color = lines[idx].color; 1074 char *old, *new;
834 char *old = lines[idx].line; 1075
1076 assert(log);
1077 assert(log->last);
1078
1079 old = log->last->line;
1080 assert(old);
1081
835 char *new = concat_line (old, str); 1082 new = concat_line (old, str);
836
837 free (old); 1083 free (str);
838 1084 log->last->line = new;
839 delete_line (idx); 1085 log->last->len = strlen (new);
840 split_line (idx, new, color); 1086 possibly_split_long_line (log);
841} 1087}
842 1088
843static void 1089static void
844main_loop (void) 1090main_loop (void)
845{ 1091{
846 lines = xmalloc (sizeof (struct linematrix) * listlen);
847 display = xmalloc (sizeof (struct displaymatrix) * listlen);
848 int lin; 1092 int lin;
849 time_t lastreload; 1093 time_t lastreload;
850 Region region = XCreateRegion (); 1094 Region region = XCreateRegion ();
851 XEvent xev; 1095 XEvent xev;
852 struct logfile_entry *lastprinted = NULL; 1096 struct logfile_entry *lastprinted = NULL;
853 struct logfile_entry *current; 1097 struct logfile_entry *current;
854 int need_update = 1; 1098 int need_update = 1;
855 1099
1100 display = xmalloc (sizeof (struct displaymatrix) * listlen);
1101
856 lastreload = time (NULL); 1102 lastreload = time (NULL);
857 1103
858 /* Initialize linematrix */ 1104 /* Initialize line_node */
859 for (lin = 0; lin < listlen; lin++) 1105 for (lin = 0; lin < listlen; lin++)
860 { 1106 {
1107 struct line_node *e = xmalloc (sizeof (struct line_node));
861 lines[lin].line = xstrdup ("~"); 1108 e->line = xstrdup ("~");
862 lines[lin].len = 1; 1109 e->len = 1;
1110 e->logfile = loglist; /* this is only needed to get a color for the '~' */
1111 e->wrapped_left = 0;
1112 e->wrapped_right = 0;
1113 e->breaks = 0;
1114 e->next = NULL;
1115 e->prev = linelist_tail;
1116
1117 if (!linelist)
1118 linelist = e;
1119 if (linelist_tail)
1120 linelist_tail->next = e;
1121 linelist_tail = e;
1122
863 display[lin].line = xstrdup(""); 1123 display[lin].line = xstrdup ("");
864 display[lin].len = 0; 1124 display[lin].len = 0;
1125 display[lin].offset = 0;
865 display[lin].buffer_size = 1; 1126 display[lin].buffer_size = 0;
866 lines[lin].color = GetColor (def_color);
867 } 1127 }
868 1128
869 for (;;) 1129 for (;;)
870 { 1130 {
871 /* read logs */ 1131 /* read logs */
882 /* if we're trying to update old partial lines in 1142 /* if we're trying to update old partial lines in
883 * place, and the last time this file was updated the 1143 * place, and the last time this file was updated the
884 * output was partial, and that partial line is not 1144 * output was partial, and that partial line is not
885 * too close to the top of the screen, then update 1145 * too close to the top of the screen, then update
886 * that partial line */ 1146 * that partial line */
887 if (opt_update && current->lastpartial && current->index >= 0) 1147 if (opt_update && current->lastpartial && current->last)
888 { 1148 {
889 int idx = current->index;
890 append_line (idx, current->buf); 1149 append_to_existing_line (current->buf, current);
891 current->index = idx; 1150 current->buf = 0;
1151 continue;
1152 }
1153
1154 /* if all we just read was a newline ending a line that we've already displayed, skip it */
1155 if (current->buf[0] == '\0' && current->lastpartial)
1156 {
892 free (current->buf), current->buf = 0; 1157 free(current->buf);
1158 current->buf = 0;
893 continue; 1159 continue;
894 } 1160 }
895 1161
896 /* print filename if any, and if last line was from 1162 /* print filename if any, and if last line was from
897 * different file */ 1163 * different file */
898 if (!opt_nofilename && lastprinted != current && current->desc[0]) 1164 if (!opt_nofilename && lastprinted != current && current->desc[0])
899 { 1165 {
900 char buf[1024]; /* HACK-5 */ 1166 current->last = 0;
901 snprintf (buf, sizeof (buf), "[%s]", current->desc); 1167 insert_new_line (xstrdup ("["), current);
902 split_line (listlen - 1, buf, current->color); 1168 append_to_existing_line (xstrdup (current->desc), current);
1169 append_to_existing_line (xstrdup ("]"), current);
903 } 1170 }
904 1171
905 /* if we're dealing with partial lines, and the last 1172 /* if we're dealing with partial lines, and the last
906 * time we showed the line it wasn't finished ... */ 1173 * time we showed the line it wasn't finished ... */
907 if (!opt_whole && current->lastpartial) 1174 if (!opt_whole && current->lastpartial)
908 { 1175 {
909 /* if this is the same file we showed last then 1176 /* if this is the same file we showed last then
910 append to the last line shown */ 1177 append to the last line shown */
911 if (lastprinted == current) 1178 if (lastprinted == current)
912 append_line (listlen - 1, current->buf); 1179 append_to_existing_line (current->buf, current);
913 else 1180 else
914 { 1181 {
915 /* but if a different file has been shown in the 1182 /* but if a different file has been shown in the
916 * mean time, make a new line, starting with the 1183 * mean time, make a new line, starting with the
917 * continuation string */ 1184 * continuation string */
918 split_line (listlen - 1, continuation, current->color); 1185 insert_new_line (current->buf, current);
919 append_line (listlen - 1, current->buf); 1186 current->last->wrapped_left = 1;
920 } 1187 }
921 } 1188 }
922 else 1189 else
923 /* otherwise just make a plain and simple new line */ 1190 /* otherwise just make a plain and simple new line */
924 split_line (listlen - 1, current->buf, current->color); 1191 insert_new_line (current->buf, current);
925 1192
926 free (current->buf), current->buf = 0; 1193 current->buf = 0;
927 current->index = listlen - 1;
928 lastprinted = current; 1194 lastprinted = current;
929 } 1195 }
930 } 1196 }
931 1197
932 if (need_update) 1198 if (need_update)
1043 XParseGeometry (argv[++i], &win_x, &win_y, &width, &height); 1309 XParseGeometry (argv[++i], &win_x, &win_y, &width, &height);
1044 else if (!strcmp (arg, "-display")) 1310 else if (!strcmp (arg, "-display"))
1045 dispname = argv[++i]; 1311 dispname = argv[++i];
1046 else if (!strcmp (arg, "-cont")) 1312 else if (!strcmp (arg, "-cont"))
1047 continuation = argv[++i]; 1313 continuation = argv[++i];
1314 else if (!strcmp (arg, "-cont-color"))
1315 cont_color = argv[++i];
1048 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn")) 1316 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn"))
1049 fontname = argv[++i]; 1317 fontname = argv[++i];
1050#if HAS_REGEX 1318#if HAS_REGEX
1051 else if (!strcmp (arg, "-t")) 1319 else if (!strcmp (arg, "-t"))
1052 { 1320 {
1053 transform = argv[++i]; 1321 transform = argv[++i];
1054 transform_to = argv[++i]; 1322 transform_to = argv[++i];
1055 printf("transform: '%s' to '%s'\n", transform, transform_to); 1323 printf ("transform: '%s' to '%s'\n", transform, transform_to);
1056 } 1324 }
1057#endif 1325#endif
1058 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f")) 1326 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f"))
1059 opt_daemonize = 1; 1327 opt_daemonize = 1;
1060 else if (!strcmp (arg, "-reload")) 1328 else if (!strcmp (arg, "-reload"))
1061 { 1329 {
1080 opt_partial = 1; 1348 opt_partial = 1;
1081 else if (!strcmp (arg, "-update")) 1349 else if (!strcmp (arg, "-update"))
1082 opt_update = opt_partial = 1; 1350 opt_update = opt_partial = 1;
1083 else if (!strcmp (arg, "-wordwrap")) 1351 else if (!strcmp (arg, "-wordwrap"))
1084 opt_wordwrap = 1; 1352 opt_wordwrap = 1;
1353 else if (!strcmp (arg, "-justify"))
1354 opt_justify = 1;
1085 else if (!strcmp (arg, "-color")) 1355 else if (!strcmp (arg, "-color"))
1086 def_color = argv[++i]; 1356 def_color = argv[++i];
1087 else if (!strcmp (arg, "-noinitial")) 1357 else if (!strcmp (arg, "-noinitial"))
1088 opt_noinitial = 1; 1358 opt_noinitial = 1;
1089 else if (!strcmp (arg, "-id")) 1359 else if (!strcmp (arg, "-id"))
1090 root = atoi (argv[++i]); 1360 {
1361 unsigned long id;
1362
1363 if (sscanf (argv[++i], "%li", &id) == 1 && id)
1364 root = id;
1365 }
1091 else if (!strcmp (arg, "-interval") || !strcmp (arg, "-i")) 1366 else if (!strcmp (arg, "-interval") || !strcmp (arg, "-i"))
1092 { 1367 {
1093 double iv = atof (argv[++i]); 1368 double iv = atof (argv[++i]);
1094 1369
1095 interval.tv_sec = (int) iv; 1370 interval.tv_sec = (int) iv;
1125 } 1400 }
1126 1401
1127 e = xmalloc (sizeof (struct logfile_entry)); 1402 e = xmalloc (sizeof (struct logfile_entry));
1128 e->partial = 0; 1403 e->partial = 0;
1129 e->buf = 0; 1404 e->buf = 0;
1130 e->index = -1;
1131 1405
1132 if (arg[0] == '-' && arg[1] == '\0') 1406 if (arg[0] == '-' && arg[1] == '\0')
1133 { 1407 {
1134 if ((e->fp = fdopen (0, "r")) == NULL) 1408 if ((e->fp = fdopen (0, "r")) == NULL)
1135 perror ("fdopen"), exit (1); 1409 perror ("fdopen"), exit (1);
1136 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0) 1410 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0)
1137 perror ("fcntl"), exit (1); 1411 perror ("fcntl"), exit (1);
1412
1138 e->fname = NULL; 1413 e->fname = NULL;
1139 e->inode = 0; 1414 e->inode = 0;
1415 if (desc == arg)
1140 e->desc = xstrdup ("stdin"); 1416 e->desc = xstrdup ("stdin");
1417 else
1418 e->desc = xstrdup (desc);
1141 } 1419 }
1142 else 1420 else
1143 { 1421 {
1144 int l;
1145
1146 e->fname = xstrdup (fname); 1422 e->fname = xstrdup (fname);
1423
1147 if (openlog (e) == NULL) 1424 if (openlog (e) == NULL)
1148 perror (fname), exit (1); 1425 perror (fname), exit (1);
1149 1426
1150 e->desc = xstrdup (desc); 1427 e->desc = xstrdup (desc);
1151 } 1428 }
1152 1429
1153 e->color = GetColor (fcolor); 1430 e->color = GetColor (fcolor);
1154 e->partial = 0; 1431 e->partial = 0;
1432 e->fontname = fontname;
1433 e->last = NULL;
1155 e->next = NULL; 1434 e->next = NULL;
1156 1435
1157 if (!loglist) 1436 if (!loglist)
1158 loglist = e; 1437 loglist = e;
1159 if (loglist_tail) 1438 if (loglist_tail)
1160 loglist_tail->next = e; 1439 loglist_tail->next = e;
1440
1161 loglist_tail = e; 1441 loglist_tail = e;
1162 } 1442 }
1163 } 1443 }
1164 1444
1165 if (!loglist) 1445 if (!loglist)
1167 fprintf (stderr, "You did not specify any files to tail\n" 1447 fprintf (stderr, "You did not specify any files to tail\n"
1168 "use %s --help for help\n", argv[0]); 1448 "use %s --help for help\n", argv[0]);
1169 exit (1); 1449 exit (1);
1170 } 1450 }
1171 1451
1452 if (opt_update && opt_whole)
1453 {
1454 fprintf (stderr, "Specify at most one of -update and -whole\n");
1455 exit (1);
1456 }
1172 if (opt_partial && opt_whole) 1457 else if (opt_partial && opt_whole)
1173 { 1458 {
1174 fprintf (stderr, "Specify at most one of -partial and -whole\n"); 1459 fprintf (stderr, "Specify at most one of -partial and -whole\n");
1175 exit (1); 1460 exit (1);
1176 } 1461 }
1462
1463 /* it doesn't make sense to justify if word wrap isn't on */
1464 if (opt_justify)
1465 opt_wordwrap = 1;
1177 1466
1178 /* HACK-7: do we want to allow both -shade and -outline? */ 1467 /* HACK-7: do we want to allow both -shade and -outline? */
1179 if (opt_shade && opt_outline) 1468 if (opt_shade && opt_outline)
1180 { 1469 {
1181 fprintf (stderr, "Specify at most one of -shade and -outline\n"); 1470 fprintf (stderr, "Specify at most one of -shade and -outline\n");
1192#if HAS_REGEX 1481#if HAS_REGEX
1193 if (transform) 1482 if (transform)
1194 { 1483 {
1195 int i; 1484 int i;
1196 1485
1197 printf("compiling regexp '%s'\n", transform); 1486 printf ("compiling regexp '%s'\n", transform);
1198 transformre = xmalloc (sizeof (regex_t)); 1487 transformre = xmalloc (sizeof (regex_t));
1199 i = regcomp (transformre, transform, REG_EXTENDED); 1488 i = regcomp (transformre, transform, REG_EXTENDED);
1200 if (i != 0) 1489 if (i != 0)
1201 { 1490 {
1202 char buf[512]; 1491 char buf[512];
1203 1492
1204 regerror (i, transformre, buf, sizeof (buf)); 1493 regerror (i, transformre, buf, sizeof (buf));
1205 fprintf (stderr, "Cannot compile regular expression: %s\n", buf); 1494 fprintf (stderr, "Cannot compile regular expression: %s\n", buf);
1206 } 1495 }
1207 else 1496 else
1208 {
1209 printf("compiled '%s' OK to %x\n", transform, (int)transformre); 1497 printf ("compiled '%s' OK to %x\n", transform, (int)transformre);
1210 }
1211 } 1498 }
1212#endif 1499#endif
1213 1500
1214 InitWindow (); 1501 InitWindow ();
1215 1502
1236 action.sa_handler = handler; 1523 action.sa_handler = handler;
1237 sigemptyset (&action.sa_mask); 1524 sigemptyset (&action.sa_mask);
1238 action.sa_flags = SA_RESTART; 1525 action.sa_flags = SA_RESTART;
1239 1526
1240 if (sigaction (sig, &action, NULL) < 0) 1527 if (sigaction (sig, &action, NULL) < 0)
1241 fprintf (stderr, "sigaction(%d): %s\n", sig, strerror (errno)), exit (1); 1528 fprintf (stderr, "sigaction (%d): %s\n", sig, strerror (errno)), exit (1);
1242} 1529}
1243 1530
1244void * 1531void *
1245xstrdup (const char *string) 1532xstrdup (const char *string)
1246{ 1533{
1247 void *p; 1534 void *p;
1248 1535
1249 while ((p = strdup (string)) == NULL) 1536 while ((p = strdup (string)) == NULL)
1250 { 1537 {
1251 fprintf (stderr, "Memory exausted."); 1538 fprintf (stderr, "Memory exhausted in xstrdup ().\n");
1252 sleep (10); 1539 sleep (10);
1253 } 1540 }
1254 1541
1255 return p; 1542 return p;
1256} 1543}
1260{ 1547{
1261 void *p; 1548 void *p;
1262 1549
1263 while ((p = malloc (size)) == NULL) 1550 while ((p = malloc (size)) == NULL)
1264 { 1551 {
1265 fprintf (stderr, "Memory exausted."); 1552 fprintf (stderr, "Memory exhausted in xmalloc ().\n");
1266 sleep (10); 1553 sleep (10);
1267 } 1554 }
1268 1555
1269 return p; 1556 return p;
1270} 1557}
1274{ 1561{
1275 void *p; 1562 void *p;
1276 1563
1277 while ((p = realloc (ptr, size)) == NULL) 1564 while ((p = realloc (ptr, size)) == NULL)
1278 { 1565 {
1279 fprintf (stderr, "Memory exausted."); 1566 fprintf (stderr, "Memory exhausted in xrealloc ().\n");
1280 sleep (10); 1567 sleep (10);
1281 } 1568 }
1282 1569
1283 return p; 1570 return p;
1284} 1571}
1285 1572
1286void 1573void
1287display_help (char *myname) 1574display_help (char *myname)
1288{ 1575{
1289 printf ("Usage: %s [options] file1[,color[,desc]] " 1576 printf ("Usage: %s [options] file1[,color[,desc]]"
1290 "[file2[,color[,desc]] ...]\n", myname); 1577 "[options] [file2[,color[,desc]] ...]\n", myname);
1291 printf (" -g | -geometry geometry -g WIDTHxHEIGHT+X+Y\n" 1578 printf (" -g | -geometry geometry -g WIDTHxHEIGHT+X+Y\n"
1292 " -color color use color $color as default\n" 1579 " -color color use color $color as default\n"
1293 " -reload sec command reload after $sec and run command\n" 1580 " -reload sec command reload after $sec and run command\n"
1294 " -id id window id to use instead of the root window\n" 1581 " -id id window id to use instead of the root window\n"
1295 " -font FONTSPEC (-fn) font to use\n" 1582 " -font FONTSPEC (-fn) font to use\n"
1306 " startup\n" 1593 " startup\n"
1307 " -i | -interval seconds interval between checks (fractional\n" 1594 " -i | -interval seconds interval between checks (fractional\n"
1308 " values o.k.). Default 2.4 seconds\n" 1595 " values o.k.). Default 2.4 seconds\n"
1309 " -V display version information and exit\n" 1596 " -V display version information and exit\n"
1310 "\n"); 1597 "\n");
1311 printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green " 1598 printf ("Example:\n%s -g 800x250+100+50 -font fixed /var/log/messages,green "
1312 "/var/log/secure,red,'ALERT'\n", myname); 1599 "/var/log/secure,red,'ALERT'\n", myname);
1313 exit (0); 1600 exit (0);
1314} 1601}
1315 1602
1316void 1603void
1330 case -1: 1617 case -1:
1331 return -1; 1618 return -1;
1332 case 0: 1619 case 0:
1333 break; 1620 break;
1334 default: 1621 default:
1335 /*printf("%d\n", pid);*/ 1622 /*printf ("%d\n", pid);*/
1336 exit (0); 1623 exit (0);
1337 } 1624 }
1338 1625
1339 if (setsid () == -1) 1626 if (setsid () == -1)
1340 return -1; 1627 return -1;
1341 1628
1342 return 0; 1629 return 0;
1343} 1630}
1631
1632/* todo - get reverse display working again */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines