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.4 by jebusbfb, Sun May 5 20:31:11 2002 UTC vs.
Revision 1.11 by pcg, Fri Mar 26 13:14:54 2004 UTC

28#include <fcntl.h> 28#include <fcntl.h>
29#include <errno.h> 29#include <errno.h>
30#include <sys/time.h> 30#include <sys/time.h>
31#include <sys/stat.h> 31#include <sys/stat.h>
32#include <sys/types.h> 32#include <sys/types.h>
33#include <locale.h>
34#include <ctype.h>
35#include <stdarg.h>
33#if HAS_REGEX 36#if HAS_REGEX
34#include <regex.h> 37#include <regex.h>
35#endif 38#endif
36#include <X11/Xlib.h> 39#include <X11/Xlib.h>
40#include <X11/Xatom.h>
37#include <X11/Xutil.h> 41#include <X11/Xutil.h>
38 42
39/* data structures */ 43/* data structures */
40struct logfile_entry { 44struct logfile_entry
41 char *fname; /* name of file */ 45{
42 char *desc; /* alternative description */
43 FILE *fp; /* FILE struct associated with file */
44 ino_t inode; /* inode of the file opened */
45 off_t last_size; /* file size at the last check */
46 unsigned long color; /* color to be used for printing */
47 struct logfile_entry *next; 46 struct logfile_entry *next;
47
48 char *fname; /* name of file */
49 char *desc; /* alternative description */
50 char *buf; /* text read but not yet displayed */
51 FILE *fp; /* FILE struct associated with file */
52 ino_t inode; /* inode of the file opened */
53 off_t last_size; /* file size at the last check */
54 unsigned long color; /* color to be used for printing */
55 int partial; /* true if the last line isn't complete */
56 int lastpartial; /* true if the previous output wasn't complete */
57 int index; /* index into linematrix of a partial line */
48}; 58};
49 59
50struct linematrix { 60struct linematrix
61{
51 char *line; 62 char *line;
52 unsigned long color; 63 unsigned long color;
53}; 64};
54 65
55
56/* global variables */ 66/* global variables */
57unsigned int width = STD_WIDTH, listlen = STD_HEIGHT; 67int width = STD_WIDTH, height = STD_HEIGHT, listlen;
58int win_x = LOC_X, win_y = LOC_Y; 68int win_x = LOC_X, win_y = LOC_Y;
59int w = -1, h = -1, font_width, font_height, font_descent; 69int font_descent, font_height;
60int do_reopen; 70int do_reopen;
61struct timeval interval = { 2, 400000 }; /* see Knuth */ 71struct timeval interval = { 3, 0 };
72XFontSet fontset;
62 73
63/* command line options */ 74/* command line options */
64int opt_noinitial, opt_shade, opt_frame, opt_reverse=0, opt_nofilename, 75int opt_noinitial, opt_shade, opt_frame, opt_reverse, opt_nofilename,
65 geom_mask, reload = 3600; 76 opt_whole, opt_update, geom_mask, reload = 0;
66const char *command = NULL, 77const char *command = NULL,
67 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR; 78 *fontname = USE_FONT, *dispname = NULL, *def_color = DEF_COLOR,
79 *continuation = "[+]";
68 80
69struct logfile_entry *loglist = NULL, *loglist_tail = NULL; 81struct logfile_entry *loglist = NULL, *loglist_tail = NULL;
70 82
71Display *disp; 83Display *disp;
72Window root; 84Window root;
73GC WinGC; 85GC WinGC;
74 86
75#if HAS_REGEX 87#if HAS_REGEX
76struct re_list { 88struct re_list
89{
77 regex_t from; 90 regex_t from;
78 const char *to; 91 const char *to;
79 struct re_list *next; 92 struct re_list *next;
80}; 93};
81struct re_list *re_head, *re_tail; 94struct re_list *re_head, *re_tail;
82#endif 95#endif
83 96
84 97
85/* prototypes */ 98/* prototypes */
86void list_files(int); 99void list_files (int);
87void force_reopen(int); 100void force_reopen (int);
88void force_refresh(int); 101void force_refresh (int);
89void blank_window(int); 102void blank_window (int);
90 103
91void InitWindow(void); 104void InitWindow (void);
92unsigned long GetColor(const char *); 105unsigned long GetColor (const char *);
93void redraw(void); 106void redraw (void);
94void refresh(struct linematrix *, int, int); 107void refresh (struct linematrix *, int, int);
95 108
96void transform_line(char *s); 109void transform_line (char *s);
97int lineinput(char *, int, FILE *); 110int lineinput (struct logfile_entry *);
98void reopen(void); 111void reopen (void);
99void check_open_files(void); 112void check_open_files (void);
100FILE *openlog(struct logfile_entry *); 113FILE *openlog (struct logfile_entry *);
101void main_loop(void); 114void main_loop (void);
102 115
103void display_version(void); 116void display_version (void);
104void display_help(char *); 117void display_help (char *);
105void install_signal(int, void (*)(int)); 118void install_signal (int, void (*)(int));
106void *xstrdup(const char *); 119void *xstrdup (const char *);
107void *xmalloc(size_t); 120void *xmalloc (size_t);
108int daemonize(void); 121int daemonize (void);
109 122
110/* signal handlers */ 123/* signal handlers */
124void
111void list_files(int dummy) 125list_files (int dummy)
112{ 126{
113 struct logfile_entry *e; 127 struct logfile_entry *e;
114 128
115 fprintf(stderr, "Files opened:\n"); 129 fprintf (stderr, "Files opened:\n");
116 for (e = loglist; e; e = e->next) 130 for (e = loglist; e; e = e->next)
117 fprintf(stderr, "\t%s (%s)\n", e->fname, e->desc); 131 fprintf (stderr, "\t%s (%s)\n", e->fname, e->desc);
118} 132}
119 133
134void
120void force_reopen(int dummy) 135force_reopen (int dummy)
121{ 136{
122 do_reopen = 1; 137 do_reopen = 1;
123} 138}
124 139
140void
125void force_refresh(int dummy) 141force_refresh (int dummy)
126{ 142{
127 XClearWindow(disp, root); 143 XClearArea (disp, root, win_x, win_y, width, height, False);
128 redraw(); 144 redraw ();
129} 145}
130 146
147void
131void blank_window(int dummy) 148blank_window (int dummy)
132{ 149{
133 XClearWindow(disp, root); 150 XClearArea (disp, root, win_x, win_y, width, height, False);
134 XFlush(disp); 151 XFlush (disp);
135 exit(0); 152 exit (0);
136} 153}
137 154
138/* X related functions */ 155/* X related functions */
156unsigned long
139unsigned long GetColor(const char *ColorName) 157GetColor (const char *ColorName)
140{ 158{
141 XColor Color; 159 XColor Color;
142 XWindowAttributes Attributes; 160 XWindowAttributes Attributes;
143 161
144 XGetWindowAttributes(disp, root, &Attributes); 162 XGetWindowAttributes (disp, root, &Attributes);
145 Color.pixel = 0; 163 Color.pixel = 0;
164
146 if (!XParseColor(disp, Attributes.colormap, ColorName, &Color)) 165 if (!XParseColor (disp, Attributes.colormap, ColorName, &Color))
147 fprintf(stderr, "can't parse %s\n", ColorName); 166 fprintf (stderr, "can't parse %s\n", ColorName);
148 else if (!XAllocColor(disp, Attributes.colormap, &Color)) 167 else if (!XAllocColor (disp, Attributes.colormap, &Color))
149 fprintf(stderr, "can't allocate %s\n", ColorName); 168 fprintf (stderr, "can't allocate %s\n", ColorName);
169
150 return Color.pixel; 170 return Color.pixel;
151} 171}
152 172
173static Window
174root_window (Display * display, int screen_number)
175{
176 Atom SWM_VROOT = XInternAtom (display, "__SWM_VROOT", False);
177 Window real_root_window = RootWindow (display, screen_number);
178
179 if (root) /* root window set via option */
180 return root;
181
182 if (SWM_VROOT != None)
183 {
184 Window unused, *windows;
185 unsigned int count;
186
187 if (XQueryTree (display, real_root_window, &unused, &unused, &windows,
188 &count))
189 {
190 int i;
191
192 for (i = 0; i < count; i++)
193 {
194 Atom type;
195 int format;
196 unsigned long nitems, bytes_after_return;
197 unsigned char *virtual_root_window;
198
199 if (XGetWindowProperty (display, windows[i], SWM_VROOT,
200 0, 1, False, XA_WINDOW, &type, &format,
201 &nitems, &bytes_after_return,
202 &virtual_root_window) == Success)
203 {
204 if (type != None)
205 {
206 if (type == XA_WINDOW)
207 {
208 XFree (windows);
209 return (Window) virtual_root_window;
210 }
211 else
212 fprintf (stderr,
213 "__SWM_VROOT property type mismatch");
214 }
215 }
216 else
217 fprintf (stderr,
218 "failed to get __SWM_VROOT property on window 0x%lx",
219 windows[i]);
220 }
221
222 if (count)
223 XFree (windows);
224 }
225 else
226 fprintf (stderr, "Can't query tree on root window 0x%lx",
227 real_root_window);
228 }
229 else
230 /* This shouldn't happen. The Xlib documentation is wrong BTW. */
231 fprintf (stderr, "Can't intern atom __SWM_VROOT");
232
233 return real_root_window;
234}
235
236void
153void InitWindow(void) 237InitWindow (void)
154{ 238{
155 XGCValues gcv; 239 XGCValues gcv;
156 Font font;
157 unsigned long gcm; 240 unsigned long gcm;
158 XFontStruct *info;
159 int screen, ScreenWidth, ScreenHeight; 241 int screen, ScreenWidth, ScreenHeight;
160 242
161 if (!(disp = XOpenDisplay(dispname))) { 243 if (!(disp = XOpenDisplay (dispname)))
244 {
162 fprintf(stderr, "Can't open display %s.\n", dispname); 245 fprintf (stderr, "Can't open display %s.\n", dispname);
163 exit(1); 246 exit (1);
164 } 247 }
248
165 screen = DefaultScreen(disp); 249 screen = DefaultScreen (disp);
166 ScreenHeight = DisplayHeight(disp, screen); 250 ScreenHeight = DisplayHeight (disp, screen);
167 ScreenWidth = DisplayWidth(disp, screen); 251 ScreenWidth = DisplayWidth (disp, screen);
252
168 root = RootWindow(disp, screen); 253 root = root_window (disp, screen);
254
169 gcm = GCBackground; 255 gcm = GCBackground;
170 gcv.graphics_exposures = True; 256 gcv.graphics_exposures = True;
171 WinGC = XCreateGC(disp, root, gcm, &gcv); 257 WinGC = XCreateGC (disp, root, gcm, &gcv);
172 XMapWindow(disp, root); 258 XMapWindow (disp, root);
173 XSetForeground(disp, WinGC, GetColor(DEF_COLOR)); 259 XSetForeground (disp, WinGC, GetColor (DEF_COLOR));
174 260
261 {
262 char **missing_charset_list;
263 int missing_charset_count;
264 char *def_string;
265
175 font = XLoadFont(disp, fontname); 266 fontset = XCreateFontSet (disp, fontname,
176 XSetFont(disp, WinGC, font); 267 &missing_charset_list, &missing_charset_count,
177 info = XQueryFont(disp, font); 268 &def_string);
178 font_width = info->max_bounds.width;
179 font_descent = info->max_bounds.descent;
180 font_height = info->max_bounds.ascent + font_descent;
181 269
182 w = width * font_width; 270 if (missing_charset_count)
183 h = listlen * font_height; 271 {
272 fprintf (stderr,
273 "Missing charsets in String to FontSet conversion (%s)\n",
274 missing_charset_list[0]);
275 XFreeStringList (missing_charset_list);
276 }
277 }
278
279 if (!fontset)
280 {
281 fprintf (stderr, "unable to create fontset, exiting.\n");
282 exit (1);
283 }
284
285 {
286 XFontSetExtents *xfe = XExtentsOfFontSet (fontset);
287
288 font_height = xfe->max_logical_extent.height;
289 font_descent = xfe->max_logical_extent.y;
290 }
291
184 if (geom_mask & XNegative) 292 if (geom_mask & XNegative)
185 win_x = win_x + ScreenWidth - w; 293 win_x = win_x + ScreenWidth - width;
186 if (geom_mask & YNegative) 294 if (geom_mask & YNegative)
187 win_y = win_y + ScreenHeight - h; 295 win_y = win_y + ScreenHeight - height;
188 296
297 listlen = height / font_height;
298
299 if (!listlen)
300 {
301 fprintf (stderr, "height too small for a single line, setting to %d\n",
302 font_height);
303 listlen = 1;
304 }
305
306 height = listlen * font_height;
307
189 XSelectInput(disp, root, ExposureMask|FocusChangeMask); 308 XSelectInput (disp, root, ExposureMask | FocusChangeMask);
190} 309}
191 310
192char * 311char *
193detabificate (char *s) 312detabificate (char *s)
194{ 313{
195 char * out; 314 char *out;
196 int i, j; 315 int i, j;
197 316
198 out = malloc (8 * strlen (s) + 1); 317 out = malloc (8 * strlen (s) + 1);
199 318
200 for(i = 0, j = 0; s[i]; i++) 319 for (i = 0, j = 0; s[i]; i++)
201 { 320 {
202 if (s[i] == '\t') 321 if (s[i] == '\t')
203 do 322 do
204 out[j++] = ' '; 323 out[j++] = ' ';
205 while (j % 8); 324 while (j % 8);
206 else 325 else
207 out[j++] = s[i]; 326 out[j++] = s[i];
208 } 327 }
209 328
210 out[j] = '\0'; 329 out[j] = '\0';
211 return out; 330 return out;
212} 331}
213 332
214/* 333/*
215 * redraw does a complete redraw, rather than an update (i.e. the area 334 * redraw does a complete redraw, rather than an update (i.e. the area
216 * gets cleared first) 335 * gets cleared first)
217 * the rest is handled by regular refresh()'es 336 * the rest is handled by regular refresh()'es
218 */ 337 */
338void
219void redraw(void) 339redraw (void)
220{ 340{
221 XClearArea(disp, root, win_x, win_y, w, h + font_descent + 2, True); 341 XClearArea (disp, root, win_x, win_y, width, height, True);
222} 342}
223 343
224/* Just redraw everything without clearing (i.e. after an EXPOSE event) */ 344/* Just redraw everything without clearing (i.e. after an EXPOSE event) */
345void
225void refresh(struct linematrix *lines, int miny, int maxy) 346refresh (struct linematrix *lines, int miny, int maxy)
226{ 347{
227 int lin; 348 int lin;
228 int offset = (listlen + 1) * font_height; 349 int offset = (listlen + 1) * font_height;
229 unsigned long black_color = GetColor("black"); 350 unsigned long black_color = GetColor ("black");
230 351
231 miny -= win_y + font_height; 352 miny -= win_y + font_height;
232 maxy -= win_y - font_height; 353 maxy -= win_y - font_height;
233 354
234 for (lin = listlen; lin--;) 355 for (lin = listlen; lin--;)
235 { 356 {
236 char *temp; 357 struct linematrix *line =
237 358 lines + (opt_reverse ? listlen - lin - 1 : lin);
359
238 offset -= font_height; 360 offset -= font_height;
239 361
240 if (offset < miny || offset > maxy) 362 if (offset < miny || offset > maxy)
241 continue; 363 continue;
242 364
243#define LIN ((opt_reverse)?(listlen-lin-1):(lin))
244 temp = detabificate (lines[LIN].line);
245
246 if (opt_shade) 365 if (opt_shade)
247 { 366 {
248 XSetForeground (disp, WinGC, black_color); 367 XSetForeground (disp, WinGC, black_color);
249 XDrawString (disp, root, WinGC, win_x + 2, win_y + offset + 2, 368 XmbDrawString (disp, root, fontset, WinGC, win_x + 2,
250 temp, strlen (temp)); 369 win_y + offset + 2, line->line, strlen (line->line));
251 }
252
253 XSetForeground (disp, WinGC, lines[LIN].color);
254 XDrawString (disp, root, WinGC, win_x, win_y + offset,
255 temp, strlen (temp));
256 370 }
257 free (temp);
258 }
259 371
372 XSetForeground (disp, WinGC, line->color);
373 XmbDrawString (disp, root, fontset, WinGC, win_x, win_y + offset,
374 line->line, strlen (line->line));
375 }
376
260 if (opt_frame) { 377 if (opt_frame)
261 int bot_y = win_y + h + font_descent + 2; 378 XDrawRectangle (disp, root, WinGC, win_x, win_y, width, height);
262
263 XDrawLine(disp, root, WinGC, win_x, win_y, win_x + w, win_y);
264 XDrawLine(disp, root, WinGC, win_x + w, win_y, win_x + w, bot_y);
265 XDrawLine(disp, root, WinGC, win_x + w, bot_y, win_x, bot_y);
266 XDrawLine(disp, root, WinGC, win_x, bot_y, win_x, win_y);
267 }
268} 379}
269 380
270#if HAS_REGEX 381#if HAS_REGEX
382void
271void transform_line(char *s) 383transform_line (char *s)
272{ 384{
273#ifdef I_AM_Md 385#ifdef I_AM_Md
274 int i; 386 int i;
275 if (1) { 387 if (1)
388 {
276 for (i = 16; s[i]; i++) 389 for (i = 16; s[i]; i++)
277 s[i] = s[i + 11]; 390 s[i] = s[i + 11];
278 } 391 }
279 s[i + 1] = '\0'; 392 s[i + 1] = '\0';
280#endif 393#endif
281 394
282 if (transformre) { 395 if (transformre)
283 int i; 396 {
397 int i;
284 regmatch_t matched[16]; 398 regmatch_t matched[16];
285 399
286 i = regexec(&transformre, string, 16, matched, 0); 400 i = regexec (&transformre, string, 16, matched, 0);
287 if (i == 0) { /* matched */ 401 if (i == 0)
288 } 402 { /* matched */
403 }
289 } 404 }
290} 405}
291#endif 406#endif
292 407
293 408
294/* 409/*
295 * This routine should read 'width' characters and not more. However, 410 * This routine should read 'width' characters and not more. However,
296 * we really want to read width + 1 charachters if the last char is a '\n', 411 * we really want to read width + 1 characters if the last char is a '\n',
297 * which we should remove afterwards. So, read width+1 chars and ungetc 412 * which we should remove afterwards. So, read width+1 chars and ungetc
298 * the last character if it's not a newline. This means 'string' must be 413 * the last character if it's not a newline. This means 'string' must be
299 * width + 2 wide! 414 * width + 2 wide!
300 */ 415 */
301int lineinput(char *string, int slen, FILE *f) 416int
417lineinput (struct logfile_entry *logfile)
302{ 418{
303 int len; 419 char *string = logfile->buf;
420 int slen = width + 2;
421 FILE *f = logfile->fp;
304 422
305 do {
306 if (fgets(string, slen, f) == NULL) /* EOF or Error */
307 return 0;
308
309 len = strlen(string); 423 int len = strlen (string);
424 int partial = logfile->partial;
425
426 do
427 {
428 if (fgets (string + len, slen - len, f) == NULL) /* EOF or Error */
429 return 0;
430
431 len = strlen (string);
432 }
310 } while (len == 0); 433 while (len == 0);
311 434
435 logfile->partial = 0;
436
312 if (string[len - 1] == '\n') 437 if (string[len - 1] == '\n')
438 /* if the string ends in a newline, delete the newline */
313 string[len - 1] = '\0'; /* erase newline */ 439 string[len - 1] = '\0'; /* erase newline */
314 else if (len >= slen - 1) { 440 else if (len >= slen - 1)
441 {
442 /* otherwise if we've read one too many characters, un-read the last one and delete it */
315 ungetc(string[len - 1], f); 443 ungetc (string[len - 1], f);
316 string[len - 1] = '\0'; 444 string[len - 1] = '\0';
317 } 445 }
446 else if (opt_whole)
447 return 0;
448 else
449 logfile->partial = 1;
318 450
319#if HAS_REGEX 451#if HAS_REGEX
320 transform_line(string); 452 transform_line (string);
321#endif 453#endif
454 logfile->lastpartial = partial;
322 return len; 455 return len;
323} 456}
324 457
325/* input: reads file->fname 458/* input: reads file->fname
326 * output: fills file->fp, file->inode 459 * output: fills file->fp, file->inode
327 * returns file->fp 460 * returns file->fp
328 * in case of error, file->fp is NULL 461 * in case of error, file->fp is NULL
329 */ 462 */
463FILE *
330FILE *openlog(struct logfile_entry *file) 464openlog (struct logfile_entry * file)
331{ 465{
332 struct stat stats; 466 struct stat stats;
333 467
334 if ((file->fp = fopen(file->fname, "r")) == NULL) { 468 if ((file->fp = fopen (file->fname, "r")) == NULL)
469 {
335 file->fp = NULL; 470 file->fp = NULL;
336 return NULL; 471 return NULL;
337 } 472 }
338 473
339 fstat(fileno(file->fp), &stats); 474 fstat (fileno (file->fp), &stats);
340 if (S_ISFIFO(stats.st_mode)) { 475 if (S_ISFIFO (stats.st_mode))
476 {
341 if (fcntl(fileno(file->fp), F_SETFL, O_NONBLOCK) < 0) 477 if (fcntl (fileno (file->fp), F_SETFL, O_NONBLOCK) < 0)
342 perror("fcntl"), exit(1); 478 perror ("fcntl"), exit (1);
343 file->inode = 0; 479 file->inode = 0;
480 }
344 } else 481 else
345 file->inode = stats.st_ino; 482 file->inode = stats.st_ino;
346 483
347 if (opt_noinitial) 484 if (opt_noinitial)
348 fseek (file->fp, 0, SEEK_END); 485 fseek (file->fp, 0, SEEK_END);
349 else if (stats.st_size > (listlen + 1) * width) 486 else if (stats.st_size > (listlen + 1) * width)
350 {
351 char dummy[255];
352
353 fseek(file->fp, -((listlen + 2) * width), SEEK_END); 487 fseek (file->fp, -((listlen + 2) * width), SEEK_END);
354 /* the pointer might point halfway some line. Let's
355 be nice and skip this damaged line */
356 lineinput(dummy, sizeof(dummy), file->fp);
357 }
358 488
359 file->last_size = stats.st_size; 489 file->last_size = stats.st_size;
360 return file->fp; 490 return file->fp;
361} 491}
362 492
493void
363void reopen(void) 494reopen (void)
364{ 495{
365 struct logfile_entry *e; 496 struct logfile_entry *e;
366 497
367 for (e = loglist; e; e = e->next) { 498 for (e = loglist; e; e = e->next)
499 {
368 if (!e->inode) 500 if (!e->inode)
369 continue; /* skip stdin */ 501 continue; /* skip stdin */
370 502
371 if (e->fp) 503 if (e->fp)
372 fclose(e->fp); 504 fclose (e->fp);
373 /* if fp is NULL we will try again later */ 505 /* if fp is NULL we will try again later */
374 openlog(e); 506 openlog (e);
375 } 507 }
376 508
377 do_reopen = 0; 509 do_reopen = 0;
378} 510}
379 511
512void
380void check_open_files(void) 513check_open_files (void)
381{ 514{
382 struct logfile_entry *e; 515 struct logfile_entry *e;
383 struct stat stats; 516 struct stat stats;
384 517
385 for (e = loglist; e; e = e->next) { 518 for (e = loglist; e; e = e->next)
519 {
386 if (!e->inode) 520 if (!e->inode)
387 continue; /* skip stdin */ 521 continue; /* skip stdin */
388 522
389 if (stat(e->fname, &stats) < 0) { /* file missing? */ 523 if (stat (e->fname, &stats) < 0)
524 { /* file missing? */
390 sleep(1); 525 sleep (1);
391 if (e->fp) 526 if (e->fp)
392 fclose(e->fp); 527 fclose (e->fp);
393 if (openlog(e) == NULL) 528 if (openlog (e) == NULL)
394 break; 529 break;
395 } 530 }
396 531
397 if (stats.st_ino != e->inode) { /* file renamed? */ 532 if (stats.st_ino != e->inode)
533 { /* file renamed? */
398 if (e->fp) 534 if (e->fp)
399 fclose(e->fp); 535 fclose (e->fp);
400 if (openlog(e) == NULL) 536 if (openlog (e) == NULL)
401 break; 537 break;
402 } 538 }
403 539
404 if (stats.st_size < e->last_size) { /* file truncated? */ 540 if (stats.st_size < e->last_size)
541 { /* file truncated? */
405 fseek(e->fp, 0, SEEK_SET); 542 fseek (e->fp, 0, SEEK_SET);
406 e->last_size = stats.st_size; 543 e->last_size = stats.st_size;
407 } 544 }
408 } 545 }
409} 546}
410 547
411#define SCROLL_UP(lines, listlen) \ 548#define SCROLL_UP(lines, listlen) \
412{ \ 549{ \
413 int cur_line; \ 550 int cur_line; \
551 struct logfile_entry *current; \
414 for (cur_line = 0; cur_line < (listlen - 1); cur_line++) { \ 552 for (cur_line = 0; cur_line < (listlen - 1); cur_line++) { \
415 strcpy(lines[cur_line].line, lines[cur_line + 1].line); \ 553 strcpy(lines[cur_line].line, lines[cur_line + 1].line); \
416 lines[cur_line].color = lines[cur_line + 1].color; \ 554 lines[cur_line].color = lines[cur_line + 1].color; \
417 } \ 555 } \
556 for (current = loglist; current; current = current->next) \
557 if (current->partial && current->index) \
558 current->index--; \
418} 559}
419 560
561void
420void main_loop(void) 562main_loop (void)
421{ 563{
422 struct linematrix *lines = xmalloc(sizeof(struct linematrix) * listlen); 564 struct linematrix *lines = xmalloc (sizeof (struct linematrix) * listlen);
423 int lin, miny, maxy, buflen; 565 int lin, miny, maxy;
424 char *buf;
425 time_t lastreload; 566 time_t lastreload;
426 Region region = XCreateRegion(); 567 Region region = XCreateRegion ();
427 XEvent xev; 568 XEvent xev;
569 struct logfile_entry *lastprinted = NULL;
570 struct logfile_entry *current;
428 571
429 maxy = 0; 572 maxy = 0;
430 miny = win_y + h; 573 miny = win_y + height;
431 buflen = width + 2;
432 buf = xmalloc(buflen);
433 lastreload = time(NULL); 574 lastreload = time (NULL);
434 575
435 /* Initialize linematrix */ 576 /* Initialize linematrix */
436 for (lin = 0; lin < listlen; lin++) { 577 for (lin = 0; lin < listlen; lin++)
437 lines[lin].line = xmalloc(buflen); 578 {
579 lines[lin].line = xmalloc (width + 2);
438 strcpy(lines[lin].line, "~"); 580 strcpy (lines[lin].line, "~");
439 lines[lin].color = GetColor(def_color); 581 lines[lin].color = GetColor (def_color);
440 } 582 }
441 583
442 if (!opt_noinitial) 584 /* show the display full of empty lines ("~") in case the first
443 while (lineinput(buf, buflen, loglist->fp) != 0) { 585 * time around the loop doesn't produce any output, as it won't if
444 SCROLL_UP(lines, listlen); 586 * either (a) -noinitial is set or (b) all the files are currently
445 /* print the next line */ 587 * empty */
446 strcpy(lines[listlen - 1].line, buf); 588 redraw ();
447 }
448 589
449 for (;;) { 590 for (;;)
591 {
450 int need_update = 0; 592 int need_update = 0;
451 struct logfile_entry *current;
452 static struct logfile_entry *lastprinted = NULL;
453 593
454 /* read logs */ 594 /* read logs */
455 for (current = loglist; current; current = current->next) { 595 for (current = loglist; current; current = current->next)
596 {
456 if (!current->fp) 597 if (!current->fp)
457 continue; /* skip missing files */ 598 continue; /* skip missing files */
458 599
459 clearerr(current->fp); 600 clearerr (current->fp);
460 601
461 while (lineinput(buf, buflen, current->fp) != 0) { 602 while (lineinput (current) != 0)
603 {
604 /* if we're trying to update old partial lines in
605 * place, and the last time this file was updated the
606 * output was partial, and that partial line is not
607 * too close to the top of the screen, then update
608 * that partial line */
609 if (opt_update && current->lastpartial && current->index >= 3)
610 {
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,
616 width - old_len);
617 /* if we can't fit the whole update into the old
618 * partial line then we're going to have to print
619 * the rest of it at the bottom on the screen */
620 if (new_len > space_on_old_line)
621 {
622 /* strcpy() doesn't like the strings to
623 * overlap in memory, but memmove() doesn't
624 * care */
625 memmove (current->buf,
626 current->buf + space_on_old_line,
627 new_len - space_on_old_line + 1);
628 }
629 else
630 {
631 need_update = 1;
632 strcpy (current->buf, "");
633 continue;
634 }
635 }
636
462 /* print filename if any, and if last line was from 637 /* print filename if any, and if last line was from
463 different file */ 638 * different file */
464 if (!opt_nofilename && 639 if (!opt_nofilename &&
465 !(lastprinted && lastprinted == current) && 640 lastprinted != current && current->desc[0])
466 current->desc[0]) { 641 {
467 SCROLL_UP(lines, listlen); 642 SCROLL_UP (lines, listlen);
468 sprintf(lines[listlen - 1].line, "[%s]", current->desc); 643 sprintf (lines[listlen - 1].line, "[%s]", current->desc);
644 lines[listlen - 1].color = current->color;
645 }
646
647 /* if this is the same file we showed last, and the
648 * last time we showed it, it wasn't finished, then
649 * append to the last line shown */
650 if (lastprinted == current && current->lastpartial)
651 {
652 int old_len = strlen (lines[listlen - 1].line);
653 int new_len = strlen (current->buf);
654 strncat (lines[listlen - 1].line, current->buf,
655 width - old_len);
656 /* if it doesn't all fit, then put the part that
657 * doesn't fit on a new line */
658 if (new_len > width - old_len)
659 {
660 SCROLL_UP (lines, listlen);
661 strcpy (lines[listlen - 1].line,
662 current->buf + width - old_len);
663 }
664 /* show the 'continuation' string because we've got a
665 * continued partial line, but we weren't able to
666 * append it to the old displayed partial line */
667 }
668 else if (current->lastpartial)
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 }
685 else
686 {
687 SCROLL_UP (lines, listlen);
688 strcpy (lines[listlen - 1].line, current->buf);
689 }
690
691 /* we've shown the line now. clear the buffer for the next line */
692 strcpy (current->buf, "");
693 current->index = listlen - 1;
469 lines[listlen - 1].color = current->color; 694 lines[listlen - 1].color = current->color;
470 }
471 695
472 SCROLL_UP(lines, listlen); 696 lastprinted = current;
473 strcpy(lines[listlen - 1].line, buf); 697 need_update = 1;
474 lines[listlen - 1].color = current->color; 698 }
699 }
475 700
476 lastprinted = current;
477 need_update = 1;
478 }
479 }
480
481 if (need_update) 701 if (need_update)
482 redraw(); 702 redraw ();
483 else { 703 else
704 {
484 XFlush(disp); 705 XFlush (disp);
706
485 if (!XPending(disp)) { 707 if (!XPending (disp))
486 fd_set fdr; 708 {
709 fd_set fdr;
487 struct timeval to = interval; 710 struct timeval to = interval;
488 711
489 FD_ZERO(&fdr); 712 FD_ZERO (&fdr);
490 FD_SET(ConnectionNumber(disp), &fdr); 713 FD_SET (ConnectionNumber (disp), &fdr);
491 select(ConnectionNumber(disp) + 1, &fdr, 0, 0, &to); 714 select (ConnectionNumber (disp) + 1, &fdr, 0, 0, &to);
492 } 715 }
493 } 716 }
494 717
495 check_open_files(); 718 check_open_files ();
496 719
497 if (do_reopen) 720 if (do_reopen)
498 reopen(); 721 reopen ();
499 722
500 /* we ignore possible errors due to window resizing &c */ 723 /* we ignore possible errors due to window resizing &c */
501 while (XPending(disp)) { 724 while (XPending (disp))
725 {
502 XNextEvent(disp, &xev); 726 XNextEvent (disp, &xev);
727
503 switch (xev.type) { 728 switch (xev.type)
729 {
504 case Expose: 730 case Expose:
505 { 731 {
506 XRectangle r; 732 XRectangle r;
507 733
508 r.x = xev.xexpose.x; 734 r.x = xev.xexpose.x;
509 r.y = xev.xexpose.y; 735 r.y = xev.xexpose.y;
510 r.width = xev.xexpose.width; 736 r.width = xev.xexpose.width;
511 r.height = xev.xexpose.height; 737 r.height = xev.xexpose.height;
512 XUnionRectWithRegion(&r, region, region); 738 XUnionRectWithRegion (&r, region, region);
513 if (miny > r.y) 739 if (miny > r.y)
514 miny = r.y; 740 miny = r.y;
515 if (maxy < r.y + r.height) 741 if (maxy < r.y + r.height)
516 maxy = r.y + r.height; 742 maxy = r.y + r.height;
517 } 743 }
518 break; 744 break;
519 default: 745 default:
520#ifdef DEBUGMODE 746#ifdef DEBUGMODE
521 fprintf(stderr, "PANIC! Unknown event %d\n", xev.type); 747 fprintf (stderr, "PANIC! Unknown event %d\n", xev.type);
522#endif 748#endif
523 break; 749 break;
750 }
751 }
752
753 /* reload if requested */
754 if (reload && lastreload + reload < time (NULL))
755 {
756 if (command && command[0])
757 system (command);
758
759 reopen ();
760 lastreload = time (NULL);
761 }
762
763 if (!XEmptyRegion (region))
764 {
765 XSetRegion (disp, WinGC, region);
766
767 refresh (lines, miny, maxy);
768 XDestroyRegion (region);
769 region = XCreateRegion ();
770 maxy = 0;
771 miny = win_y + height;
772 }
524 } 773 }
525 }
526
527 /* reload if requested */
528 if (reload && lastreload + reload < time(NULL)) {
529 if (command)
530 system(command);
531
532 reopen();
533 lastreload = time(NULL);
534 }
535
536 if (!XEmptyRegion(region)) {
537 XSetRegion(disp, WinGC, region);
538 refresh(lines, miny, maxy);
539 XDestroyRegion(region);
540 region = XCreateRegion();
541 maxy = 0;
542 miny = win_y + h;
543 }
544 }
545} 774}
546 775
547 776
777int
548int main(int argc, char *argv[]) 778main (int argc, char *argv[])
549{ 779{
550 int i; 780 int i;
551 int opt_daemonize = 0; 781 int opt_daemonize = 0;
782 int opt_partial = 0, file_count = 0;
552#if HAS_REGEX 783#if HAS_REGEX
553 char *transform = NULL; 784 char *transform = NULL;
554#endif 785#endif
555 786
787 setlocale (LC_CTYPE, ""); /* try to initialize the locale. */
788
556 /* window needs to be initialized before colorlookups can be done */ 789 /* window needs to be initialized before colorlookups can be done */
557 /* just a dummy to get the color lookups right */ 790 /* just a dummy to get the color lookups right */
558 geom_mask = NoValue; 791 geom_mask = NoValue;
559 InitWindow(); 792 InitWindow ();
560 793
561 for (i = 1; i < argc; i++) { 794 for (i = 1; i < argc; i++)
795 {
796 const char *arg = argv[i];
797
562 if (argv[i][0] == '-' && argv[i][1] != '\0' && argv[i][1] != ',') { 798 if (arg[0] == '-' && arg[1] != '\0' && arg[1] != ',')
799 {
800 if (arg[1] == '-')
801 arg++;
802
563 if (!strcmp(argv[i], "--?") || 803 if (!strcmp (arg, "-?") ||
564 !strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) 804 !strcmp (arg, "-help") || !strcmp (arg, "-h"))
565 display_help(argv[0]); 805 display_help (argv[0]);
566 else if (!strcmp(argv[i], "-V")) 806 else if (!strcmp (arg, "-V"))
567 display_version(); 807 display_version ();
568 else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "-geometry")) 808 else if (!strcmp (arg, "-g") || !strcmp (arg, "-geometry"))
569 geom_mask = XParseGeometry(argv[++i], 809 geom_mask =
570 &win_x, &win_y, &width, &listlen); 810 XParseGeometry (argv[++i], &win_x, &win_y, &width, &height);
571 else if (!strcmp(argv[i], "-display")) 811 else if (!strcmp (arg, "-display"))
572 dispname = argv[++i]; 812 dispname = argv[++i];
813 else if (!strcmp (arg, "-cont"))
814 continuation = argv[++i];
573 else if (!strcmp(argv[i], "-font") || !strcmp(argv[i], "-fn")) 815 else if (!strcmp (arg, "-font") || !strcmp (arg, "-fn"))
574 fontname = argv[++i]; 816 fontname = argv[++i];
575#if HAS_REGEX 817#if HAS_REGEX
576 else if (!strcmp(argv[i], "-t")) 818 else if (!strcmp (arg, "-t"))
577 transform = argv[++i]; 819 transform = argv[++i];
578#endif 820#endif
579 else if (!strcmp(argv[i], "-fork") || !strcmp(argv[i], "-f")) 821 else if (!strcmp (arg, "-fork") || !strcmp (arg, "-f"))
580 opt_daemonize = 1; 822 opt_daemonize = 1;
581 else if (!strcmp(argv[i], "-reload")) { 823 else if (!strcmp (arg, "-reload"))
582 reload = atoi(argv[++i]); 824 {
583 command = argv[++i]; 825 reload = atoi (argv[++i]);
584 } 826 command = argv[++i];
827 }
585 else if (!strcmp(argv[i], "-shade")) 828 else if (!strcmp (arg, "-shade"))
586 opt_shade = 1; 829 opt_shade = 1;
587 else if (!strcmp(argv[i], "-frame")) 830 else if (!strcmp (arg, "-frame"))
588 opt_frame = 1; 831 opt_frame = 1;
589 else if (!strcmp(argv[i], "-no-filename")) 832 else if (!strcmp (arg, "-no-filename"))
590 opt_nofilename = 1; 833 opt_nofilename = 1;
591 else if (!strcmp(argv[i], "-reverse")) 834 else if (!strcmp (arg, "-reverse"))
592 opt_reverse = 1; 835 opt_reverse = 1;
836 else if (!strcmp (arg, "-whole"))
837 opt_whole = 1;
838 else if (!strcmp (arg, "-partial"))
839 opt_partial = 1;
840 else if (!strcmp (arg, "-update"))
841 opt_update = opt_partial = 1;
593 else if (!strcmp(argv[i], "-color")) 842 else if (!strcmp (arg, "-color"))
594 def_color = argv[++i]; 843 def_color = argv[++i];
595 else if (!strcmp(argv[i], "-noinitial")) 844 else if (!strcmp (arg, "-noinitial"))
596 opt_noinitial = 1; 845 opt_noinitial = 1;
846 else if (!strcmp (arg, "-id"))
847 root = atoi (argv[++i]);
597 else if (!strcmp(argv[i], "-interval") || !strcmp(argv[i], "-i")) { 848 else if (!strcmp (arg, "-interval") || !strcmp (arg, "-i"))
849 {
598 double iv = atof(argv[++i]); 850 double iv = atof (argv[++i]);
599 851
600 interval.tv_sec = (int) iv; 852 interval.tv_sec = (int) iv;
601 interval.tv_usec = (iv - interval.tv_sec) * 1e6; 853 interval.tv_usec = (iv - interval.tv_sec) * 1e6;
602 } else { 854 }
855 else
856 {
603 fprintf(stderr, "Unknown option '%s'.\n" 857 fprintf (stderr, "Unknown option '%s'.\n"
604 "Try --help for more information.\n", argv[i]); 858 "Try --help for more information.\n", arg);
605 exit(1); 859 exit (1);
606 } 860 }
607 } else { /* it must be a filename */ 861 }
862 else
863 { /* it must be a filename */
608 struct logfile_entry *e; 864 struct logfile_entry *e;
609 const char *fname, *desc, *fcolor = def_color; 865 const char *fname, *desc, *fcolor = def_color;
610 char *p; 866 char *p;
611 867
868 file_count++;
869
612 /* this is not foolproof yet (',' in filenames are not allowed) */ 870 /* this is not foolproof yet (',' in filenames are not allowed) */
613 fname = desc = argv[i]; 871 fname = desc = arg;
614 if ((p = strchr(argv[i], ','))) { 872 if ((p = strchr (arg, ',')))
615 *p = '\0'; 873 {
616 fcolor = p + 1; 874 *p = '\0';
875 fcolor = p + 1;
617 876
618 if ((p = strchr(fcolor, ','))) { 877 if ((p = strchr (fcolor, ',')))
619 *p = '\0'; 878 {
620 desc = p + 1; 879 *p = '\0';
621 } 880 desc = p + 1;
622 } 881 }
882 }
623 883
624 e = xmalloc(sizeof(struct logfile_entry)); 884 e = xmalloc (sizeof (struct logfile_entry));
625 if (argv[i][0] == '-' && argv[i][1] == '\0') { 885 if (arg[0] == '-' && arg[1] == '\0')
886 {
626 if ((e->fp = fdopen(0, "r")) == NULL) 887 if ((e->fp = fdopen (0, "r")) == NULL)
627 perror("fdopen"), exit(1); 888 perror ("fdopen"), exit (1);
628 if (fcntl(0, F_SETFL, O_NONBLOCK) < 0) 889 if (fcntl (0, F_SETFL, O_NONBLOCK) < 0)
629 perror("fcntl"), exit(1); 890 perror ("fcntl"), exit (1);
630 e->fname = NULL; 891 e->fname = NULL;
631 e->inode = 0; 892 e->inode = 0;
632 e->desc = xstrdup("stdin"); 893 e->desc = xstrdup ("stdin");
633 } else { 894 }
634 int l; 895 else
896 {
897 int l;
635 898
636 e->fname = xstrdup(fname); 899 e->fname = xstrdup (fname);
637 if (openlog(e) == NULL) 900 if (openlog (e) == NULL)
638 perror(fname), exit(1); 901 perror (fname), exit (1);
639 902
640 l = strlen(desc); 903 l = strlen (desc);
641 if (l > width - 2) /* must account for [ ] */ 904 if (l > width - 2) /* must account for [ ] */
642 l = width - 2; 905 l = width - 2;
643 e->desc = xmalloc(l + 1); 906 e->desc = xmalloc (l + 1);
644 memcpy(e->desc, desc, l); 907 memcpy (e->desc, desc, l);
645 *(e->desc + l) = '\0'; 908 *(e->desc + l) = '\0';
909 }
910
911 e->color = GetColor (fcolor);
912 e->buf = xmalloc (width + 2);
913 e->partial = 0;
914 e->buf[0] = '\0';
915 e->next = NULL;
916
917 if (!loglist)
918 loglist = e;
919 if (loglist_tail)
920 loglist_tail->next = e;
921 loglist_tail = e;
922 }
646 } 923 }
647 924
648 e->color = GetColor(fcolor);
649 e->next = NULL;
650
651 if (!loglist) 925 if (!loglist)
652 loglist = e;
653 if (loglist_tail)
654 loglist_tail->next = e;
655 loglist_tail = e;
656 }
657 } 926 {
658
659 if (!loglist) {
660 fprintf(stderr, "You did not specify any files to tail\n" 927 fprintf (stderr, "You did not specify any files to tail\n"
661 "use %s --help for help\n", argv[0]); 928 "use %s --help for help\n", argv[0]);
662 exit(1); 929 exit (1);
930 }
931
932 if (opt_partial && opt_whole)
663 } 933 {
934 fprintf (stderr, "Specify at most one of -partial and -whole\n");
935 exit (1);
936 }
937
938 if (opt_partial)
939 /* if we specifically requested to see partial lines then don't insist on whole lines */
940 opt_whole = 0;
941 else if (file_count > 1)
942 /* otherwise, if we've viewing multiple files, default to showing whole lines */
943 opt_whole = 1;
664 944
665#if HAS_REGEX 945#if HAS_REGEX
666 if (transform) { 946 if (transform)
667 int i; 947 {
948 int i;
668 949
669 transformre = xmalloc(sizeof(transformre)); 950 transformre = xmalloc (sizeof (transformre));
670 i = regcomp(&transformre, transform, REG_EXTENDED); 951 i = regcomp (&transformre, transform, REG_EXTENDED);
671 if (i != 0) { 952 if (i != 0)
953 {
672 char buf[512]; 954 char buf[512];
673 955
674 regerror(i, &transformre, buf, sizeof(buf)); 956 regerror (i, &transformre, buf, sizeof (buf));
675 fprintf(stderr, "Cannot compile regular expression: %s\n", buf); 957 fprintf (stderr, "Cannot compile regular expression: %s\n", buf);
676 } 958 }
677 } 959 }
678#endif 960#endif
679 961
680 InitWindow(); 962 InitWindow ();
681 963
682 install_signal(SIGINT, blank_window); 964 install_signal (SIGINT, blank_window);
683 install_signal(SIGQUIT, blank_window); 965 install_signal (SIGQUIT, blank_window);
684 install_signal(SIGTERM, blank_window); 966 install_signal (SIGTERM, blank_window);
685 install_signal(SIGHUP, force_reopen); 967 install_signal (SIGHUP, force_reopen);
686 install_signal(SIGUSR1, list_files); 968 install_signal (SIGUSR1, list_files);
687 install_signal(SIGUSR2, force_refresh); 969 install_signal (SIGUSR2, force_refresh);
688 970
689 if (opt_daemonize) 971 if (opt_daemonize)
690 daemonize(); 972 daemonize ();
691 973
692 main_loop(); 974 main_loop ();
693 975
694 exit(1); /* to make gcc -Wall stop complaining */ 976 exit (1); /* to make gcc -Wall stop complaining */
695} 977}
696 978
979void
697void install_signal(int sig, void (*handler)(int)) 980install_signal (int sig, void (*handler) (int))
698{ 981{
699 struct sigaction action; 982 struct sigaction action;
700 983
701 action.sa_handler = handler; 984 action.sa_handler = handler;
702 sigemptyset(&action.sa_mask); 985 sigemptyset (&action.sa_mask);
703 action.sa_flags = SA_RESTART; 986 action.sa_flags = SA_RESTART;
987
704 if (sigaction(sig, &action, NULL) < 0) 988 if (sigaction (sig, &action, NULL) < 0)
705 fprintf(stderr, "sigaction(%d): %s\n", sig, strerror(errno)), exit(1); 989 fprintf (stderr, "sigaction(%d): %s\n", sig, strerror (errno)), exit (1);
706} 990}
707 991
992void *
708void *xstrdup(const char *string) 993xstrdup (const char *string)
709{ 994{
710 void *p; 995 void *p;
711 996
712 while ((p = strdup(string)) == NULL) { 997 while ((p = strdup (string)) == NULL)
998 {
713 fprintf(stderr, "Memory exausted."); 999 fprintf (stderr, "Memory exausted.");
714 sleep(10); 1000 sleep (10);
715 } 1001 }
1002
716 return p; 1003 return p;
717} 1004}
718 1005
1006void *
719void *xmalloc(size_t size) 1007xmalloc (size_t size)
720{ 1008{
721 void *p; 1009 void *p;
722 1010
723 while ((p = malloc(size)) == NULL) { 1011 while ((p = malloc (size)) == NULL)
1012 {
724 fprintf(stderr, "Memory exausted."); 1013 fprintf (stderr, "Memory exausted.");
725 sleep(10); 1014 sleep (10);
726 } 1015 }
727 return p; 1016 return p;
728} 1017}
729 1018
1019void
730void display_help(char *myname) 1020display_help (char *myname)
731{ 1021{
732 printf("Usage: %s [options] file1[,color[,desc]] " 1022 printf ("Usage: %s [options] file1[,color[,desc]] "
733 "[file2[,color[,desc]] ...]\n", myname); 1023 "[file2[,color[,desc]] ...]\n", myname);
734 printf(" -g | -geometry geometry -g WIDTHxHEIGHT+X+Y\n" 1024 printf (" -g | -geometry geometry -g WIDTHxHEIGHT+X+Y\n"
735 " -color color use color $color as default\n" 1025 " -color color use color $color as default\n"
736 " -reload sec command reload after $sec and run command\n" 1026 " -reload sec command reload after $sec and run command\n"
737 " by default -- 3 mins\n" 1027 " -id id window id to use instead of the root window\n"
738 " -font FONTSPEC (-fn) font to use\n" 1028 " -font FONTSPEC (-fn) font to use\n"
739 " -f | -fork fork into background\n" 1029 " -f | -fork fork into background\n"
740 " -reverse print new lines at the top\n" 1030 " -reverse print new lines at the top\n"
1031 " -whole wait for \\n before showing a line\n"
1032 " -partial show lines even if they don't end with a \\n\n"
1033 " -update allow updates to old partial lines\n"
1034 " -cont string to prefix continued partial lines with\n"
1035 " defaults to \"[+]\"\n"
741 " -shade add shading to font\n" 1036 " -shade add shading to font\n"
742 " -noinitial don't display the last file lines on\n" 1037 " -noinitial don't display the last file lines on\n"
743 " startup\n" 1038 " startup\n"
744 " -i | -interval seconds interval between checks (fractional\n" 1039 " -i | -interval seconds interval between checks (fractional\n"
745 " values o.k.). Default 3\n" 1040 " values o.k.). Default 3 seconds\n"
746 " -V display version information and exit\n" 1041 " -V display version information and exit\n"
747 "\n"); 1042 "\n");
748 printf("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green " 1043 printf ("Example:\n%s -g 80x25+100+50 -font fixed /var/log/messages,green "
749 "/var/log/secure,red,'ALERT'\n", myname); 1044 "/var/log/secure,red,'ALERT'\n", myname);
750 exit(0); 1045 exit (0);
751} 1046}
752 1047
1048void
753void display_version(void) { 1049display_version (void)
1050{
754 printf("root-tail version " VERSION "\n"); 1051 printf ("root-tail version " VERSION "\n");
755 exit(0); 1052 exit (0);
756} 1053}
757 1054
1055int
758int daemonize(void) { 1056daemonize (void)
1057{
759 switch (fork()) { 1058 switch (fork ())
1059 {
760 case -1: 1060 case -1:
761 return -1; 1061 return -1;
762 case 0: 1062 case 0:
763 break; 1063 break;
764 default: 1064 default:
765 _exit(0); 1065 _exit (0);
766 } 1066 }
767 1067
768 if (setsid() == -1) 1068 if (setsid () == -1)
769 return -1; 1069 return -1;
770 1070
771 return 0; 1071 return 0;
772} 1072}
773

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines