#define _LARGEFILE64_SOURCE /* required for GLIBC to enable stat64 and friends */
#include "doassert.h"
#include <sys/types.h>
#include <regex.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "mt.h"
#include "mem.h"
#include "error.h"
#include "color.h"
#include "term.h"
#include "utils.h"
#include "config.h"
#include "cv.h"
#include "exec.h"
#include "globals.h"
void usage(void)
{
printf("%s", version_str);
printf("\n\nmultitail [-cs|-Cs|-c-] [-i] inputfile [-i anotherinputfile] [...]\n");
printf("-i x the following parameter is a filename (in case it starts with a dash)\n");
printf("-I x like -i only this one merges this logfile into the previous window\n");
printf("-l x parameter is a command to be executed\n");
printf("-L x see -l but add to the previous window\n");
printf("-j read from stdin (can be used (of course) only once)\n");
printf("-J like -j but merge into previous window\n");
printf("--listen [interface]:port behave like a syslog server. port is normally 514\n");
printf("--Listen [interface]:port like --listen but merge into previous window\n");
printf("-r interval restart the command when it died after `interval' seconds\n");
printf("-R interval same as -r, only with this one only the difference is displayed\n");
printf("-Rc/-rc interval like -r/-R but clean the window before each iteration\n");
printf("--cont reconnect lines with a '\' at the end\n");
printf("--mergeall merge all of the following files into the same window (in the previous window)\n");
printf("--mergeall-new merge all of the following files into the same window (in a new window)\n");
printf("--no-mergeall stop merging all files into one window\n");
printf("--no-repeat suppress repeating lines and replace them with a \"last message repeated x times\"\n");
printf("--mark-interval x when nothing comes in, print a '---mark---' line every 'x' seconds\n");
printf("--mark-change when multiple files are merged an multitail switches between two windows, print a markerline with the filename\n");
printf("--no-mark-change do NOT print the markerline when the file changes (overrides the configfile)\n");
printf("-n x initial number of lines to tail\n");
printf("-m x set scrollback buffer size (# lines)\n");
printf("-mb x set scrollback buffer size (in bytes, use xKB/MB/GB)\n");
printf("-bw a/f what to buffer: 'a'll or what went through the 'f'ilter\n");
printf("-a x like 'tee': write (filtered) input to file 'x'\n");
printf("-A x see -a: but write the unfiltered(!) input to file 'x'\n");
printf("-g x redirect the input also (filtered) to command/process 'x'\n");
printf("-G x redirect the unfiltered input also to command/process 'x'\n");
printf("--label x put in front of each line\n");
printf("-q i path check every 'i' seconds for new files in 'path', create a new window for those\n");
printf("-Q i path check every 'i' seconds for new files in 'path', put them all in the same window (using subwindows)\n");
printf("--closeidle x close windows when more then 'x' seconds no new data was processed\n");
printf("--new-only (for -q/-Q) only create windows for files created after multitail was started\n");
printf("-s x vertical split screen (in 'x' columns)\n");
printf("-sw x,x,... at what columns to split the screen, use '0' for automatic size\n");
printf("-sn x,x,... number of windows per column\n");
printf("-wh x height of window\n");
printf("-S prepend merged output with subwindow-number\n");
printf("-f follow the following filename, not the descriptor\n");
printf("--retry keep trying to open the following file if it is inaccessible\n");
printf("--retry-all like --retry but for all following files\n");
printf("-fr scheme use the predefined filter from the configfile\n");
printf("-e[m] print only when matching with this regexp\n");
printf("-ev print only when NOT matching with this regexp\n");
printf("-ec use regular expression but display the matches inverted on following file\n");
printf("-eC use regexp, display everything but matches inverted on following file\n");
printf("-ex execute command ('-ex regexp command') when matches, matching line is given as commandline parameter\n");
printf("-eX like -ex but only give the matching substring as commandline parameter to the command\n");
printf("-E use regular expression on following files\n");
printf("-Ec use regular expression but display the matches inverted on following files\n");
printf("-EC use regexp, display everything but matches inverted on following files\n");
printf("-ke x strip parts of the input using regular expression 'x'\n");
printf("-kr x y strip parts of the input starting at offset x and ending (not including!) offset y\n");
printf("-kc x y strip parts of the input: strip column 'y' with delimiter 'x'\n");
printf("-ks x use edit scheme 'x' (defined in configfile)\n");
printf("-kS x only show the substrings matched by the substring-selects (the parts between '(' and ')') in the regular epxression 'x'\n");
printf("-v invert next regular expression (do not use with -ev/em)\n");
printf("-cv x use conversion scheme 'x' (see multitail.conf)\n");
printf("-c colorize current\n");
printf("-cS scheme use colorscheme 'scheme' (as defined in multitail.conf)\n");
printf("-csn extra switch for the following switches; do not use reverse (inverted) colors\n");
printf("-Cs colorize all following files with syslog-scheme\n");
printf("-C colorize all following files\n");
printf("-Cf/-cf field delimiter colorize next/all file(s) depending on the given field number. fields are delimited with the given field-delimiter\n");
printf("-ci color use 'color' (red, green, etc), usefull when merging multiple inputs\n");
printf("-c- do NOT colorize the following file\n");
printf("-C- do NOT colorize the following files\n");
printf("-cT term interpret terminal-codes from file/command (for terminal type 'term')\n");
printf("-Z color set color for markerline\n");
printf("-ts add a timestamp (format configurable in multitail.conf) before each line\n");
printf("-T put a timestamp in markerlines\n");
printf("-d do NOT update the status-line\n");
printf("-D do not display a status-line at all\n");
printf("-du put the statusline above the data window\n");
printf("-z do not \"window closed\" windows\n");
printf("-w do not use colors\n");
printf("-u set update interval (for slow links)\n");
printf("-p x [y] set linewrap (l=left/a=all/r=right/s=syslog,S=syslog w/o procname,o=offset -> 'y',w=wordwrap)\n");
printf("-P like -p but for all following files\n");
printf("-b n set TAB-width\n");
printf("--basename only display the filename (and not the path) in the statusline\n");
printf("-x str switch on the xtermtitlebar stuff\n");
#ifndef S_SPLINT_S
printf("-F file use 'file' as configfile (instead of " CONFIG_FILE ")\n");
printf("--no-load-global-config do not read " CONFIG_FILE "\n");
#endif
printf("-o configfileparameter do a setting which would normally be set in the configfile\n");
printf("-H x show heartbeat (to keep your sessions alive)\n");
printf("-iw file i check every 'i' seconds if 'file' appeared in the filesystem\n");
printf("-t x display 'x' in the window-title (when MultiTail runs in an xterm)\n");
printf("--beep-interval x beep every x lines processed\n");
printf("--bi x like '--beep-interval' but only for current (sub-)window\n");
printf("-V show version and exit\n");
printf("-h this help\n");
printf("\n");
printf("You can have multiple regular expressions per file/command. Be warned: if\n");
printf("you define multiple and one of them is specified with '-E' (=for every\n");
printf("following file), _all_ of the current regular expressions are for all\n");
printf("following files!\n");
printf("\n");
printf("%s\n", F1);
}
void add_redir_to_file(char mode, char *file, redirect_t **predir, int *n_redirect)
{
int cur_index = (*n_redirect)++;
*predir = (redirect_t *)myrealloc(*predir, (*n_redirect) * sizeof(redirect_t), __FILE__, __PRETTY_FUNCTION__, __LINE__);
assert(mode == 'A' || mode == 'a');
if (mode == 'a')
(*predir)[cur_index].type = REDIRECTTO_FILE_FILTERED;
else
(*predir)[cur_index].type = REDIRECTTO_FILE;
(*predir)[cur_index].redirect = mystrdup(file, __FILE__, __PRETTY_FUNCTION__, __LINE__);
(*predir)[cur_index].fd = open((*predir)[cur_index].redirect, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
if ((*predir)[cur_index].fd == -1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "%s: cannot open file %s for write access.\n", file, (*predir)[cur_index].redirect);
}
void add_redir_to_proc(char mode, char *proc, redirect_t **predir, int *n_redirect)
{
int fds_to_proc[2], fds_from_proc[2];
int cur_index = (*n_redirect)++;
assert(mode == 'G' || mode == 'g');
*predir = (redirect_t *)myrealloc(*predir, (*n_redirect) * sizeof(redirect_t), __FILE__, __PRETTY_FUNCTION__, __LINE__);
if ((*predir)[cur_index].type != REDIRECTTO_NONE) error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "One can only set one redirection-type per (sub-)window.\n");
if (mode == 'g')
(*predir)[cur_index].type = REDIRECTTO_PIPE_FILTERED;
else
(*predir)[cur_index].type = REDIRECTTO_PIPE;
(*predir)[cur_index].redirect = mystrdup(proc, __FILE__, __PRETTY_FUNCTION__, __LINE__);
(*predir)[cur_index].pid = exec_with_pipe((*predir)[cur_index].redirect, fds_to_proc, fds_from_proc);
myclose(fds_to_proc[0]);
myclose(fds_from_proc[0]);
myclose(fds_from_proc[1]);
(*predir)[cur_index].fd = fds_to_proc[1];
}
void add_redir_to_socket(char filtered, char *prio, char *fac, char *address, redirect_t **predir, int *n_redirect)
{
struct hostent *hp;
char *local_address = mystrdup(address, __FILE__, __PRETTY_FUNCTION__, __LINE__);
char *colon = strchr(local_address, ':');
int prio_nr = -1, fac_nr = -1;
int loop;
int cur_index = (*n_redirect)++;
*predir = (redirect_t *)myrealloc(*predir, (*n_redirect) * sizeof(redirect_t), __FILE__, __PRETTY_FUNCTION__, __LINE__);
assert(filtered == 1 || filtered == 0);
if (filtered)
(*predir)[cur_index].type = REDIRECTTO_SOCKET_FILTERED;
else
(*predir)[cur_index].type = REDIRECTTO_SOCKET;
(*predir)[cur_index].redirect = mystrdup(address, __FILE__, __PRETTY_FUNCTION__, __LINE__);
(*predir)[cur_index].fd = socket(AF_INET, SOCK_DGRAM, 0);
if ((*predir)[cur_index].fd == -1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Cannot create socket for redirecting via syslog protocol.\n");
memset(&(*predir)[cur_index].sai, 0x00, sizeof((*predir)[cur_index].sai));
(*predir)[cur_index].sai.sin_family = AF_INET;
if (colon)
{
*colon = 0x00;
(*predir)[cur_index].sai.sin_port = atoi(colon + 1);
}
else
(*predir)[cur_index].sai.sin_port = 514;
hp = gethostbyname(local_address);
memcpy(&(*predir)[cur_index].sai.sin_addr.s_addr, hp -> h_addr, hp -> h_length);
for(loop=0; loop<8; loop++)
{
if (strcasecmp(severities[loop], prio) == 0)
{
prio_nr = loop;
break;
}
}
if (prio_nr == -1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Priority '%s' is not recognized.\n", prio);
for(loop=0; loop<24; loop++)
{
if (strcasecmp(facilities[loop], fac) == 0)
{
fac_nr = loop;
break;
}
}
if (fac_nr == -1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Facility '%s' is not known.\n", fac);
(*predir)[cur_index].prio_fac = (fac_nr * 8) + prio_nr;
myfree(local_address);
}
void argv_set_window_widths(char *widths)
{
if (split != 0)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-s and -sw are mutual exclusive.\n");
split = 0;
for(;;)
{
int cur_width;
char *pnt;
pnt = strtok(widths, ",");
if (!pnt) break;
split++;
vertical_split = (int *)myrealloc(vertical_split, split * sizeof(int), __FILE__, __PRETTY_FUNCTION__, __LINE__);
cur_width = get_value_arg("-sw", pnt, VAL_POSITIVE);
widths = NULL;
if (cur_width < 4)
{
if (cur_width == 0)
cur_width = -1;
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "The width of a column must be 4 or greater (or '0' for automatic size).\n");
}
vertical_split[split - 1] = cur_width;
}
if (split == 1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "You have to give the width for each window or set it to 0 (=auto width).\n");
}
void argv_set_n_windows_per_column(char *pars)
{
int index = 0;
if (split == 0)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "First use -s or -sw to define the number of columns.\n");
for(;;)
{
int cur_n;
char *pnt;
pnt = strtok(pars, ",");
if (!pnt) break;
index++;
n_win_per_col = (int *)myrealloc(n_win_per_col, index * sizeof(int), __FILE__, __PRETTY_FUNCTION__, __LINE__);
cur_n = get_value_arg("-sn", pnt, VAL_POSITIVE);
pars = NULL;
if (cur_n < 0)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "The number of windows must be either 0 (=auto) or >= 1.\n");
n_win_per_col[index - 1] = cur_n;
}
}
int argv_add_re(char *mode, char *pars[], char invert_regex, re **pre_cur, int *n_re_cur, re **pre_all, int *n_re_all)
{
char *cmd = NULL, *expr = NULL;
char regex_mode = 0;
int n_pars_used = 0;
re **pre = pre_cur;
int *n_re = n_re_cur;
/* -e => only for this file, -E => for all following files */
if (mode[1] == 'E')
{
pre = pre_all;
n_re = n_re_all;
}
/* c/C/m define colors, x says: execute */
if (toupper(mode[2]) == 'C')
regex_mode = mode[2];
else if (toupper(mode[2]) == 'B')
regex_mode = mode[2];
else if (mode[2] == 'm' || mode[2] == 0x00)
regex_mode = 'm'; /* m = match, only print when matches */
else if (mode[2] == 'v')
regex_mode = 'v'; /* v = !match, only print when not matching */
else if (toupper(mode[2]) == 'X')
regex_mode = mode[2]; /* x = execute */
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "%s is an unknown switch.\n", mode);
/* get expression */
expr = pars[n_pars_used++];
/* and if there's anything to execute, get commandline */
if (toupper(regex_mode) == 'X')
{
cmd = pars[n_pars_used++];
if (regex_mode == 'X' && (strchr(expr, '(') == NULL || strchr(expr, ')') == NULL))
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Filterscheme rule: -eX requires a regular expression which selects a substring using '(' and ')'.\n");
}
/* compile & set expression */
/* allocate new structure */
*pre = (re *)myrealloc(*pre, sizeof(re) * (*n_re + 1), __FILE__, __PRETTY_FUNCTION__, __LINE__);
/* initialize structure */
memset(&(*pre)[*n_re], 0x00, sizeof(re));
/* compile */
compile_re(&(*pre)[*n_re].regex, expr);
/* remember string for later edit */
(*pre)[*n_re].regex_str = mystrdup(expr, __FILE__, __PRETTY_FUNCTION__, __LINE__);
/* set flag on current file */
(*pre)[*n_re].use_regex = regex_mode;
if (mode[1] == 'E')
regex_mode = 0;
/* wether to invert the reg exp or not */
if ((regex_mode == 'v' || regex_mode == 'm') && invert_regex)
{
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-e[m] / -ev cannot be used together with -v\n");
}
(*pre)[*n_re].invert_regex = invert_regex;
/* what to execute (if...) */
if (cmd)
(*pre)[*n_re].cmd = mystrdup(cmd, __FILE__, __PRETTY_FUNCTION__, __LINE__);
else
(*pre)[*n_re].cmd = NULL;
(*n_re)++;
return n_pars_used;
}
int argv_color_settings(char *mode, char *pars[], char *allcolor, char *curcolor, int *field_index, char **field_delimiter, myattr_t *cdef, term_t *cur_term_emul, int_array_t *cur_color_schemes, myattr_t *alt_col_cdev1, myattr_t *alt_col_cdev2)
{
int n_pars_used = 0;
char cur_mode = mode[2], doall = 0;
if (mode[1] == 'C')
doall = 1;
if (cur_mode == 's') /* syslog-file coloring? */
{
}
else if (cur_mode == 'a') /* alternating colors */
{
*alt_col_cdev1 = parse_attributes(pars[n_pars_used++]);
*alt_col_cdev2 = parse_attributes(pars[n_pars_used++]);
}
else if (cur_mode == 'i') /* use one specific color */
{
*cdef = parse_attributes(pars[n_pars_used++]);
}
else if (cur_mode == 'T') /* terminal mode */
{
if (pars[n_pars_used] != NULL && (strcasecmp(pars[n_pars_used], "ANSI") == 0 || strcasecmp(pars[n_pars_used], "vt100") == 0))
*cur_term_emul = TERM_ANSI;
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Terminal emulation '%s' is not known.\n", pars[n_pars_used]);
n_pars_used++;
}
else if (cur_mode == 'S') /* use colorscheme */
{
int cur_scheme_index;
char *cur_cscheme = pars[n_pars_used++];
if (!cur_cscheme)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "%s requires a color scheme name.\n", mode);
if ((cur_scheme_index = find_colorscheme(cur_cscheme)) == -1)
{
if (use_colors)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Color scheme %s not found! Please check your configuration file.\n", cur_cscheme);
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Color schemes are not supported on monochrome terminals.\n");
}
add_color_scheme(cur_color_schemes, cur_scheme_index);
}
else if (cur_mode == '-') /* do not color current */
{
cur_mode = 'n';
}
else if (cur_mode == 'f') /* select field for coloring */
{
*field_index = get_value_arg(mode, pars[n_pars_used++], VAL_ZERO_POSITIVE);
*field_delimiter = pars[n_pars_used++];
}
else if (cur_mode == 0x00) /* use complete line for coloring */
{
cur_mode = 'm';
}
else
{
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Invalid -c mode: '%c'.\n", cur_mode);
}
if (doall)
{
*allcolor = cur_mode;
*curcolor = 'n';
}
else
{
*curcolor = cur_mode;
*allcolor = 'n';
}
return n_pars_used;
}
int argv_add_stripper(char *mode, char *pars[], strip_t **pstrip, int *n_strip)
{
int n_pars_used = 0;
if (mode[2] == 'e' || mode[2] == 'S')
{
char *re = pars[n_pars_used++];
*pstrip = myrealloc(*pstrip, (*n_strip + 1) * sizeof(strip_t), __FILE__, __PRETTY_FUNCTION__, __LINE__);
if (mode[2] == 'e')
(*pstrip)[*n_strip].type = STRIP_TYPE_REGEXP;
else if (mode[2] == 'S')
(*pstrip)[*n_strip].type = STRIP_KEEP_SUBSTR;
(*pstrip)[*n_strip].regex_str = mystrdup(re, __FILE__, __PRETTY_FUNCTION__, __LINE__);
compile_re(&(*pstrip)[*n_strip].regex, re);
(*n_strip)++;
}
else if (mode[2] == 'r')
{
*pstrip = myrealloc(*pstrip, (*n_strip + 1) * sizeof(strip_t), __FILE__, __PRETTY_FUNCTION__, __LINE__);
(*pstrip)[*n_strip].type = STRIP_TYPE_RANGE;
(*pstrip)[*n_strip].start = get_value_arg(mode, pars[n_pars_used++], VAL_ZERO_POSITIVE);
(*pstrip)[*n_strip].end = get_value_arg(mode, pars[n_pars_used++], VAL_ZERO_POSITIVE);
if ((*pstrip)[*n_strip].end <= (*pstrip)[*n_strip].start)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "'-kr start end': end must be higher then start.\n");
(*n_strip)++;
}
else if (mode[2] == 'c')
{
*pstrip = myrealloc(*pstrip, (*n_strip + 1) * sizeof(strip_t), __FILE__, __PRETTY_FUNCTION__, __LINE__);
(*pstrip)[*n_strip].type = STRIP_TYPE_COLUMN;
(*pstrip)[*n_strip].del = mystrdup(pars[n_pars_used++], __FILE__, __PRETTY_FUNCTION__, __LINE__);
(*pstrip)[*n_strip].col_nr = get_value_arg(mode, pars[n_pars_used++], VAL_ZERO_POSITIVE);
(*n_strip)++;
}
else if (mode[2] == 's')
{
char *scheme = pars[n_pars_used++];
int editscheme_index = find_editscheme(scheme);
if (editscheme_index == -1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-ks %s: scheme not found.\n", scheme);
duplicate_es_array(pes[editscheme_index].strips, pes[editscheme_index].n_strips, pstrip, n_strip);
}
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "'%s' is not recognized.\n", mode);
return n_pars_used;
}
void add_glob_check(char *check_glob, int check_interval, char merge, char new_only)
{
cdg = (check_dir_glob *)myrealloc(cdg, sizeof(check_dir_glob) * (n_cdg + 1), __FILE__, __PRETTY_FUNCTION__, __LINE__);
cdg[n_cdg].glob_str = mystrdup(check_glob, __FILE__, __PRETTY_FUNCTION__, __LINE__);
cdg[n_cdg].check_interval = check_interval;
cdg[n_cdg].in_one_window = merge;
cdg[n_cdg].new_only = new_only;
cdg[n_cdg].window_nr = -1;
cdg[n_cdg].last_check = (dtime_t)0.0;
n_cdg++;
}
void do_commandline(int argc, char *argv[])
{
int loop;
char curcolor = 'n', allcolor = 'n';
int field_index = 0;
char *field_delimiter = NULL;
char follow_filename = -1, retry = 0, invert_regex = 0;
char retry_all = 0;
int maxlines = -1;
char setallmaxlines = 0;
int restart = -1;
char restart_clear = 0;
char do_diff = 0;
char cur_line_wrap = -1;
int cur_line_wrap_offset = -1;
char all_line_wrap = 0;
char *label = NULL;
re *pre = NULL;
int n_re = 0;
re *pre_all = NULL;
int n_re_all = 0;
int_array_t cur_color_schemes = { NULL, 0, 0 };
myattr_t cdef = { -1, -1 };
int window_height = -1;
int initial_n_lines_tail = -1;
char *win_title = NULL;
term_t cur_term_emul = TERM_IGNORE;
strip_t *pstrip = NULL;
int n_strip = 0;
int n_redirect = 0;
redirect_t *predir = NULL;
mybool_t used_stdin = MY_FALSE;
char merge_all = 0;
char merge_in_new_first = 0;
int close_idle = 0;
char setallmaxbytes = 0;
int maxbytes = -1;
myattr_t alt_col_cdev1 = { -1, -1 }, alt_col_cdev2 = { -1, -1 };
time_field_t new_only = 0;
char no_repeat = 0;
int mark_interval = 0;
char syslog_noreverse = 0;
char cont = 0;
char marker_of_other_window = 0;
char no_marker_of_other_window = 0;
char bufferwhat = -1;
int cur_beep_interval = -1;
char do_add_timestamp = 0;
int_array_t conversions = { NULL, 0, 0 };
/* first, before we load the main configfile, see if we should load the global
* file or not
*/
for(loop=1; loop<argc; loop++)
{
if (strcmp(argv[loop], "--no-load-global-config") == 0)
{
load_global_config = 0;
break;
}
}
if (load_global_config)
(void)load_configfile(NULL);
/* set defaults from configfile */
bufferwhat = default_bufferwhat;
cur_line_wrap = default_linewrap;
cur_line_wrap_offset = default_line_wrap_offset;
follow_filename = default_follow_filename;
/* parse commandline */
for(loop=1; loop<argc; loop++)
{
if (strcmp(argv[loop], "-V") == 0)
{
version();
exit(0);
}
else if (strcmp(argv[loop], "--no-load-global-config") == 0)
{
/* ignore */
}
else if (strcmp(argv[loop], "-bw") == 0)
{
char *what = argv[++loop];
if (what)
{
if (what[0] == 'a' || what[0] == 'f')
bufferwhat = what[0];
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-bw expects either 'a' or 'f' as parameter (got: '%c').\n", what[0]);
}
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-bw expects a parameter ('a' or 'f').\n");
}
else if (strcmp(argv[loop], "--no-repeat") == 0)
{
no_repeat = 1;
}
else if (strcmp(argv[loop], "--cont") == 0)
{
cont = 1;
}
else if (strcmp(argv[loop], "--mark-interval") ==0)
{
mark_interval = get_value_arg("--mark-interval", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (strcmp(argv[loop], "-ts") == 0)
{
do_add_timestamp = 1;
}
else if (strcmp(argv[loop], "--basename") == 0)
{
filename_only = 1;
}
else if (strcmp(argv[loop], "--mergeall") == 0)
{
merge_all = 1;
merge_in_new_first = 0;
}
else if (strcmp(argv[loop], "--mergeall-new") == 0)
{
merge_all = 1;
merge_in_new_first = 1;
}
else if (strcmp(argv[loop], "--no-mergeall") == 0)
{
merge_all = 0;
}
else if (strcmp(argv[loop], "--closeidle") == 0)
{
close_idle = get_value_arg("--closeidle", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (strcmp(argv[loop], "-H") == 0)
{
++loop;
if (argv[loop])
{
heartbeat_interval = atof(argv[loop]);
if (heartbeat_interval < 0.0) error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "The value for -H must be >= 0.\n");
}
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-H requires a parameter.\n");
}
else if (strcasecmp(argv[loop], "-a") == 0)
{
char mode = argv[loop][1];
add_redir_to_file(mode, argv[++loop], &predir, &n_redirect);
}
else if (strcasecmp(argv[loop], "-g") == 0)
{
char mode = argv[loop][1];
add_redir_to_proc(mode, argv[++loop], &predir, &n_redirect);
}
else if (argv[loop][0] == '-' && argv[loop][1] == 'U')
{
char *prio, *fac, *addr;
char filtered;
// -U[af][as] <facil> <prio> host[:port]
if (argv[loop][2] != 'a' && argv[loop][2] != 'f')
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-Ux where x needs to be either 'a' or 'f'");
filtered = argv[loop][2] == 'f';
prio = argv[++loop];
fac = argv[++loop];
addr = argv[++loop];
add_redir_to_socket(filtered, prio, fac, addr, &predir, &n_redirect);
}
else if (strcmp(argv[loop], "-F") == 0 || strcmp(argv[loop], "--config") == 0)
{
config_file = argv[++loop];
if (file_exist(config_file) == -1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Configuration file %s does not exist.\n", config_file);
(void)do_load_config(-1, NULL, config_file);
}
else if (strcmp(argv[loop], "-Z") == 0)
{
markerline_attrs = parse_attributes(argv[++loop]);
}
else if (strcmp(argv[loop], "-T") == 0)
{
timestamp_in_markerline = 1;
}
else if (strcmp(argv[loop], "-S") == 0)
{
show_subwindow_id = 1;
}
else if (strcmp(argv[loop], "-t") == 0)
{
++loop;
if (!argv[loop])
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-t requires a parameter.\n");
win_title = mystrdup(argv[loop], __FILE__, __PRETTY_FUNCTION__, __LINE__);
}
else if (strcmp(argv[loop], "-x") == 0)
{
++loop;
if (!argv[loop])
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-x requires a parameter.\n");
set_title = mystrdup(argv[loop], __FILE__, __PRETTY_FUNCTION__, __LINE__);
}
else if (argv[loop][0] == '-' && toupper(argv[loop][1]) == 'P')
{
char *lw = argv[++loop];
if (lw)
{
if (argv[loop - 1][1] == 'P')
all_line_wrap = 1;
else
all_line_wrap = 0;
cur_line_wrap = lw[0];
if (cur_line_wrap == 'o')
cur_line_wrap_offset = get_value_arg("-p", argv[++loop], VAL_ZERO_POSITIVE);
else if (cur_line_wrap != 'a' && cur_line_wrap != 'l' && cur_line_wrap != 'r' && toupper(cur_line_wrap) != 'S' && cur_line_wrap != 'w')
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Invalid mode for -p\n");
}
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-p requires a parameter.\n");
}
else if (strcmp(argv[loop], "--retry") == 0)
{
retry = 1;
}
else if (strcmp(argv[loop], "--retry-all") == 0)
{
retry_all = 1;
retry = 1;
}
else if (strcmp(argv[loop], "-n") == 0)
{
initial_n_lines_tail = get_value_arg("-n", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (strcmp(argv[loop], "-b") == 0)
{
tab_width = get_value_arg("-b", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (strcmp(argv[loop], "-u") == 0)
{
update_interval = get_value_arg("-u", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (argv[loop][0] == '-' && toupper(argv[loop][1]) == 'R')
{
if (argv[loop][1] == 'R')
do_diff = 1;
if (argv[loop][2] == 'c')
restart_clear = 1;
restart = get_value_arg("-r/R", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (strcmp(argv[loop], "-s") == 0)
{
split = get_value_arg("-s", argv[++loop], VAL_POSITIVE_NOT_1);
}
else if (strcmp(argv[loop], "-sw") == 0)
{
argv_set_window_widths(argv[++loop]);
}
else if (strcmp(argv[loop], "-sn") == 0)
{
argv_set_n_windows_per_column(argv[++loop]);
}
else if (strcmp(argv[loop], "-wh") == 0)
{
window_height = get_value_arg("-wh", argv[++loop], VAL_POSITIVE);
}
else if (strcmp(argv[loop], "-fr") == 0)
{
char *par = argv[++loop];
for(;;)
{
int filter;
char *komma = strchr(par, ',');
if (komma)
*komma = 0x00;
filter = find_filterscheme(par);
if (filter == -1)
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "'%s' is not a known filter scheme.\n", par);
duplicate_re_array(pfs[filter].pre, pfs[filter].n_re, &pre, &n_re);
if (!komma)
break;
par = komma + 1;
}
}
else if (strcmp(argv[loop], "-cv") == 0)
{
char *par = argv[++loop];
for(;;)
{
char *komma = strchr(par, ',');
if (komma)
*komma = 0x00;
add_conversion_scheme(&conversions, par);
if (!komma)
break;
par = komma + 1;
}
}
else if (argv[loop][0] == '-' && toupper(argv[loop][1]) == 'E')
{
loop += argv_add_re(argv[loop], &argv[loop + 1], invert_regex, &pre, &n_re, &pre_all, &n_re_all);
}
else if (strcmp(argv[loop], "-v") == 0)
{
invert_regex = 1;
}
else if (strcmp(argv[loop], "-csn") == 0)
{
syslog_noreverse = 1;
}
else if (argv[loop][0] == '-' && toupper(argv[loop][1]) == 'C')
{
loop += argv_color_settings(argv[loop], &argv[loop + 1], &allcolor, &curcolor, &field_index, &field_delimiter, &cdef, &cur_term_emul, &cur_color_schemes, &alt_col_cdev1, &alt_col_cdev2);
}
else if (strcmp(argv[loop], "-f") == 0)
{
follow_filename = 1;
}
else if (strcmp(argv[loop], "-w") == 0)
{
use_colors = 0;
}
else if (argv[loop][0] == '-' && argv[loop][1] == 'k')
{
loop += argv_add_stripper(argv[loop], &argv[loop + 1], &pstrip, &n_strip);
}
else if (strcasecmp(argv[loop], "-m") == 0)
{
if (argv[loop][1] == 'M')
setallmaxlines = 1;
maxlines = get_value_arg("-m/M", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (strcasecmp(argv[loop], "-mb") == 0)
{
if (argv[loop][1] == 'M')
setallmaxbytes = 1;
maxbytes = get_value_arg("-m/M", argv[++loop], VAL_ZERO_POSITIVE);
}
else if (strcasecmp(argv[loop], "--label") == 0)
{
label = argv[++loop];
}
else if (strcasecmp(argv[loop], "-i") == 0 || argv[loop][0] != '-' ||
strcasecmp(argv[loop], "-l") == 0 ||
strcasecmp(argv[loop], "-j") == 0 ||
strcasecmp(argv[loop], "-iw") == 0 ||
strcasecmp(argv[loop], "--listen") == 0)
{
struct stat64 buf;
char *dummy;
char is_cmd = 0;
char is_sub = 0;
char is_giw = 0;
char is_sock = 0;
char is_stdin = 0;
int check_interval = 0;
proginfo *cur;
if (strcasecmp(argv[loop], "-l") == 0)
{
is_cmd = 1;
}
else if (strcasecmp(argv[loop], "-j") == 0)
{
if (used_stdin == MY_TRUE) error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "One can use %s only once.\n", argv[loop]);
is_stdin = used_stdin = 1;
}
else if (strcasecmp(argv[loop], "-iw") == 0)
{
if (argv[loop + 2])
{
if ((argc - loop) > 2 && isdigit(argv[loop+2][0]))
{
is_giw = 1;
check_interval = atoi(argv[loop + 2]);
}
else
{
check_interval = 5;
}
}
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-iw requires 2 parameters.\n");
}
else if (strcasecmp(argv[loop], "--listen") == 0)
{
is_sock = 1;
}
if (strcmp(argv[loop], "-L") == 0 ||
strcmp(argv[loop], "-I") == 0 ||
strcmp(argv[loop], "-Iw") == 0 ||
strcmp(argv[loop], "-J") == 0 ||
strcmp(argv[loop], "--Listen") == 0 ||
merge_all)
{
is_sub = 1;
if (merge_all & (merge_in_new_first == 1))
{
is_sub = 0;
merge_in_new_first = 0;
}
}
if (argv[loop][0] == '-' && toupper(argv[loop][1]) != 'J')
{
loop++;
}
dummy = argv[loop];
if (is_sub == 1 && nfd > 0)
{
cur = &pi[nfd - 1];
while(cur -> next)
{
cur = cur -> next;
}
cur -> next = (proginfo *)mymalloc(sizeof(proginfo), __FILE__, __PRETTY_FUNCTION__, __LINE__);
cur = cur -> next;
nsubwindows[nfd-1]++;
}
else
{
pi = (proginfo *)myrealloc(pi, (nfd + 1) * sizeof(proginfo), __FILE__, __PRETTY_FUNCTION__, __LINE__);
lb = (buffer *)myrealloc(lb, (nfd + 1) * sizeof(buffer), __FILE__, __PRETTY_FUNCTION__, __LINE__);
nsubwindows = (char *)myrealloc(nsubwindows, (nfd + 1) * sizeof(char), __FILE__, __PRETTY_FUNCTION__, __LINE__);
nsubwindows[nfd] = 1;
memset(&lb[nfd], 0x00, sizeof(buffer));
lb[nfd].maxnlines = maxlines;
if (!setallmaxlines)
maxlines = -1;
lb[nfd].bufferwhat = bufferwhat;
bufferwhat = default_bufferwhat;
lb[nfd].maxbytes = maxbytes;
if (!setallmaxbytes)
maxbytes = -1;
if (marker_of_other_window || lb[nfd].marker_of_other_window)
lb[nfd].marker_of_other_window = 1;
else if (no_marker_of_other_window == 1)
lb[nfd].marker_of_other_window = -1; /* override global configfile setting */
no_marker_of_other_window = marker_of_other_window = 0;
cur = &pi[nfd];
nfd++;
}
memset(cur, 0x00, sizeof(proginfo));
/* see if file exists */
if (check_interval == 0 && is_cmd == 0 && is_stdin == 0 && is_sock == 0 && retry == 0 && stat64(dummy, &buf) == -1)
{
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "Error opening file %s.\n", dummy);
}
/* init. struct. for this file */
if (is_stdin == 0)
{
if (!dummy) error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "No filename given.\n");
cur -> filename = mystrdup(dummy, __FILE__, __PRETTY_FUNCTION__, __LINE__);
}
else
{
cur -> filename = mystrdup("STDIN", __FILE__, __PRETTY_FUNCTION__, __LINE__);
}
if (is_cmd)
cur -> wt = WT_COMMAND;
else if (is_stdin)
cur -> wt = WT_STDIN;
else if (is_sock)
cur -> wt = WT_SOCKET;
else
cur -> wt = WT_FILE;
cur -> check_interval = check_interval;
cur -> win_title = win_title;
win_title = NULL;
cur -> close_idle = close_idle;
close_idle = 0;
/* initial number of lines to tail */
cur -> initial_n_lines_tail = initial_n_lines_tail;
initial_n_lines_tail = -1;
/* default window height */
cur -> win_height = window_height;
window_height = -1;
/* store regular expression(s) */
cur -> pre = pre;
cur -> n_re = n_re;
pre = NULL;
n_re = 0;
if (n_re_all > 0)
duplicate_re_array(pre_all, n_re_all, &cur -> pre, &cur -> n_re);
/* hide this window? */
cur -> hidden = 0;
/* add timestamp in front of each line? */
cur -> add_timestamp = do_add_timestamp;
do_add_timestamp = 0;
/* strip */
cur -> pstrip = pstrip;
cur -> n_strip = n_strip;
pstrip = NULL;
n_strip = 0;
cur -> conversions = conversions;
init_iat(&conversions);
/* line wrap */
cur -> line_wrap = cur_line_wrap;
cur -> line_wrap_offset = cur_line_wrap_offset;
if (!all_line_wrap)
{
cur_line_wrap = default_linewrap;
cur_line_wrap_offset = default_line_wrap_offset;
}
cur -> retry_open = retry;
cur -> follow_filename = follow_filename;
follow_filename = default_follow_filename;
cur -> cont = cont;
cont = 0;
/* 'watch' functionality configuration (more or less) */
cur -> restart.restart = restart;
cur -> restart.restart_clear = restart_clear;
restart = -1; /* invalidate for next parameter */
restart_clear = 0;
cur -> restart.first = 1;
cur -> restart.do_diff = do_diff;
do_diff = 0;
cur -> repeat.suppress_repeating_lines = no_repeat;
cur -> mark_interval = mark_interval;
/* colors */
cur -> cdef.attributes = cdef;
cur -> cdef.alt_col_cdev1 = alt_col_cdev1;
cur -> cdef.alt_col_cdev2 = alt_col_cdev2;
cur -> cdef.syslog_noreverse = syslog_noreverse;
if (curcolor != 'n' && curcolor != 0)
{
cur -> cdef.colorize = curcolor;
cur -> cdef.color_schemes = cur_color_schemes;
init_iat(&cur_color_schemes);
}
else
{
if (allcolor == 'n' && default_color_scheme != -1)
{
cur -> cdef.colorize = 'S';
add_color_scheme(&cur -> cdef.color_schemes, default_color_scheme);
}
else if (allcolor == 'n')
{
cur -> cdef.colorize = 0;
}
else if (allcolor == 'S')
{
cur -> cdef.colorize = 'S';
cur -> cdef.color_schemes = cur_color_schemes;
}
else
{
cur -> cdef.colorize = allcolor;
}
}
cur -> cdef.field_nr = field_index;
cur -> cdef.field_del = field_delimiter ? mystrdup(field_delimiter, __FILE__, __PRETTY_FUNCTION__, __LINE__) : NULL;
cur -> statistics.sccfirst = 1;
curcolor = 'n';
if (!retry_all)
retry = 0;
if (is_giw) /* skip over the checkinterval */
loop++;
cur -> cdef.term_emul = cur_term_emul;
cur_term_emul = TERM_IGNORE;
/* redirect input also to a file or pipe */
cur -> n_redirect = n_redirect;
n_redirect = 0;
cur -> predir = predir;
predir = NULL;
cur -> beep.beep_interval = cur_beep_interval;
cur_beep_interval = -1;
cur -> label = label;
label = NULL;
}
else if (strcmp(argv[loop], "-du") == 0)
{
statusline_above_data = 1;
}
else if (strcmp(argv[loop], "-d") == 0)
{
mode_statusline = 0;
}
else if (strcmp(argv[loop], "-D") == 0)
{
mode_statusline = -1;
}
else if (strcmp(argv[loop], "-z") == 0)
{
warn_closed = 0;
}
else if (strcmp(argv[loop], "--new-only") == 0)
{
char *type = argv[++loop];
if (type)
{
if (strcasecmp(type, "atime") == 0)
new_only = TT_ATIME;
else if (strcasecmp(type, "mtime") == 0)
new_only = TT_MTIME;
else if (strcasecmp(type, "ctime") == 0)
new_only = TT_CTIME;
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "--new-only requires either atime, mtime or ctime as parameter, not '%s'.\n", type);
}
else
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "--new-only requires a parameter.\n");
}
else if (strcasecmp(argv[loop], "-q") == 0)
{
int merge = argv[loop][1] == 'Q';
int check_interval = get_value_arg("-q/-Q", argv[++loop], VAL_ZERO_POSITIVE);
char *check_glob = argv[++loop];
add_glob_check(check_glob, check_interval, merge, new_only);
}
else if (strcmp(argv[loop], "--mark-change") == 0)
{
marker_of_other_window = 1;
}
else if (strcmp(argv[loop], "--no-mark-change") == 0)
{
no_marker_of_other_window = 1;
}
else if (strcmp(argv[loop], "-o") == 0)
{
loop++;
if (!argv[loop])
error_exit(__FILE__, __PRETTY_FUNCTION__, __LINE__, "-o requires a parameter.\n");
else
config_file_entry(-1, argv[loop]);
}
else if (strcmp(argv[loop], "--beep-interval") == 0)
{
beep_interval = get_value_arg("--beep-interval", argv[++loop], VAL_POSITIVE);
}
else if (strcmp(argv[loop], "--bi") == 0)
{
cur_beep_interval = get_value_arg("--bi", argv[++loop], VAL_POSITIVE);
}
else
{
if (strcmp(argv[loop], "-h") != 0)
fprintf(stderr, "unknown parameter '%s'\n", argv[loop]);
usage();
exit(1);
}
}
for(loop=0; loop<n_re_all; loop++)
{
free_re(&pre_all[loop]);
}
myfree(pre_all);
}
syntax highlighted by Code2HTML, v. 0.9.1