summaryrefslogtreecommitdiffstats
path: root/smenu.c
diff options
context:
space:
mode:
authorpgen <p.gen.progs@gmail.com>2023-03-22 00:29:03 +0100
committerpgen <p.gen.progs@gmail.com>2023-03-22 00:29:03 +0100
commit41050198d30ece7c2e8cb0379428969db271b84d (patch)
tree1fa6e26395e3f74e80851af98b2391b89741501d /smenu.c
parented7866ddd36a1b385a358575756382df9c56c5c4 (diff)
Allow words to be aligned in column mode.
It is also possible to align all the words in a set of columns or rows. Updated options: -C, -R New option: -al|-align Updated manual.
Diffstat (limited to 'smenu.c')
-rw-r--r--smenu.c831
1 files changed, 777 insertions, 54 deletions
diff --git a/smenu.c b/smenu.c
index bd534d6..8e76cee 100644
--- a/smenu.c
+++ b/smenu.c
@@ -1650,15 +1650,10 @@ isempty(const char * s)
/* like: <delim><regex string><delim> as in /a.*b/ by example. */
/* */
/* str (in) delimited string to parse */
-/* filter (in) INCLUDE_FILTER or EXCLUDE_FILTER */
-/* inc_regex_list (out) INCLUDE_FILTER or EXCLUDE_FILTER */
-/* regular expression if the filter is INCLUDE_FILTER */
-/* exc_regex_list (out) INCLUDE_FILTER or EXCLUDE_FILTER */
-/* regular expression if the filter is EXCLUDE_FILTER */
+/* regex_list (out) regex list to modify. */
/* ======================================================================== */
void
-parse_regex_selector_part(char * str, filters_t filter, ll_t ** inc_regex_list,
- ll_t ** exc_regex_list)
+parse_regex_selector_part(char * str, ll_t ** regex_list)
{
regex_t * regex;
@@ -1672,20 +1667,10 @@ parse_regex_selector_part(char * str, filters_t filter, ll_t ** inc_regex_list,
regex = xmalloc(sizeof(regex_t));
if (regcomp(regex, str + 1, REG_EXTENDED | REG_NOSUB) == 0)
{
- if (filter == INCLUDE_FILTER)
- {
- if (*inc_regex_list == NULL)
- *inc_regex_list = ll_new();
-
- ll_append(*inc_regex_list, regex);
- }
- else
- {
- if (*exc_regex_list == NULL)
- *exc_regex_list = ll_new();
+ if (*regex_list == NULL)
+ *regex_list = ll_new();
- ll_append(*exc_regex_list, regex);
- }
+ ll_append(*regex_list, regex);
}
}
@@ -1695,10 +1680,11 @@ parse_regex_selector_part(char * str, filters_t filter, ll_t ** inc_regex_list,
/* <range> is n1-n2 | n1 where n1 starts with 1. */
/* */
/* <letter> is a|A|s|S|r|R|u|U where: */
-/* a|A is for Add. */
-/* s|S is for Select (same as Add). */
-/* r|R is for Remove. */
-/* d|D is for Deselect (same as Remove). */
+/* i|I is for 'include'. */
+/* e|E is for 'exclude'. */
+/* l|L is for 'left' alignment. */
+/* r|R is for 'right' alignment. */
+/* c|C is for 'center' alignment. */
/* */
/* str (in) string to parse. */
/* filter (out) is INCLUDE_FILTER or EXCLUDE_FILTER according */
@@ -1711,14 +1697,21 @@ parse_regex_selector_part(char * str, filters_t filter, ll_t ** inc_regex_list,
/* elements to be included. */
/* exc_interval_list (out) is a list of the interval of elements to be */
/* excluded. */
-/* exc_regex_list (out) is a list of extended interval of elements to */
+/* exc_regex_list (out) is a list of regex matching elements to */
/* be excluded. */
+/* a{lrc}terval_list (out) is a list of the interval of elements to be */
+/* aligned to the left, right or centered. */
+/* a{lrc}_regex_list (out) is a list of regex matching elements to */
+/* be aligned to the left, right or centered. */
/* ===================================================================== */
void
parse_selectors(char * str, filters_t * filter, char * unparsed,
ll_t ** inc_interval_list, ll_t ** inc_regex_list,
ll_t ** exc_interval_list, ll_t ** exc_regex_list,
- misc_t * misc)
+ ll_t ** al_interval_list, ll_t ** al_regex_list,
+ ll_t ** ar_interval_list, ll_t ** ar_regex_list,
+ ll_t ** ac_interval_list, ll_t ** ac_regex_list,
+ alignment_t * default_alignment, win_t * win, misc_t * misc)
{
char mark; /* Value to set */
char c;
@@ -1726,6 +1719,7 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
size_t first, second; /* range starting and ending values. */
char * ptr; /* pointer to the remaining string to parse. */
interval_t * interval;
+ int type;
/* Replace the UTF-8 string representation in the selector by */
/* their binary values. */
@@ -1740,14 +1734,46 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
switch (c)
{
+ case 'l':
+ case 'L':
+ if (!win->col_mode)
+ {
+ my_strcpy(unparsed, str);
+ return;
+ }
+ type = ALEFT;
+ break;
+
+ case 'r':
+ case 'R':
+ if (!win->col_mode)
+ {
+ my_strcpy(unparsed, str);
+ return;
+ }
+ type = ARIGHT;
+ break;
+
+ case 'c':
+ case 'C':
+ if (!win->col_mode)
+ {
+ my_strcpy(unparsed, str);
+ return;
+ }
+ type = ACENTER;
+ break;
+
case 'i':
case 'I':
+ type = IN;
*filter = INCLUDE_FILTER;
mark = INCLUDE_MARK;
break;
case 'e':
case 'E':
+ type = EX;
*filter = EXCLUDE_FILTER;
mark = EXCLUDE_MARK;
break;
@@ -1761,6 +1787,7 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
case '7':
case '8':
case '9':
+ type = IN;
*filter = INCLUDE_FILTER;
mark = INCLUDE_MARK;
start = 0;
@@ -1770,6 +1797,7 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
if (!isgraph(c))
return;
+ type = IN;
*filter = INCLUDE_FILTER;
mark = INCLUDE_MARK;
start = 0;
@@ -1780,9 +1808,27 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
/* """"""""""""""""""""""""""""""""""""""""""""""""""" */
ptr = str + start;
+ if (*ptr == '\0' && *default_alignment == AL_NONE)
+ switch (type)
+ {
+ case ALEFT:
+ *default_alignment = AL_LEFT;
+ break;
+ case ARIGHT:
+ *default_alignment = AL_RIGHT;
+ break;
+ case ACENTER:
+ *default_alignment = AL_CENTERED;
+ break;
+ default:
+ my_strcpy(unparsed, str);
+ return;
+ }
+
first = second = -1;
/* Scan the comma separated ranges. */
+ /* '\' can be used to escape a ','. */
/* """""""""""""""""""""""""""""""" */
while (*ptr)
{
@@ -1794,8 +1840,14 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
while (*ptr && *ptr != ',')
{
if (*ptr == '-')
+ {
is_range = 1;
- ptr++;
+ ptr++;
+ }
+ else if (*ptr == '\\' && *(ptr + 1) != '\0' && *(ptr + 1) == ',')
+ ptr += 2;
+ else
+ ptr++;
}
/* Forbid the trailing comma (ex: xxx,). */
@@ -1839,8 +1891,24 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
{
/* Process the regex. */
/* """""""""""""""""" */
- parse_regex_selector_part(str + start, *filter, inc_regex_list,
- exc_regex_list);
+ switch (type)
+ {
+ case IN:
+ parse_regex_selector_part(str + start, inc_regex_list);
+ break;
+ case EX:
+ parse_regex_selector_part(str + start, exc_regex_list);
+ break;
+ case ALEFT:
+ parse_regex_selector_part(str + start, al_regex_list);
+ break;
+ case ARIGHT:
+ parse_regex_selector_part(str + start, ar_regex_list);
+ break;
+ case ACENTER:
+ parse_regex_selector_part(str + start, ac_regex_list);
+ break;
+ }
/* Adjust the start of the new interval to read in the */
/* initial string. */
@@ -1919,19 +1987,218 @@ parse_selectors(char * str, filters_t * filter, char * unparsed,
/* Add the new interval to the correct list. */
/* """"""""""""""""""""""""""""""""""""""""" */
- if (mark == EXCLUDE_MARK)
+ switch (type)
{
- if (*exc_interval_list == NULL)
- *exc_interval_list = ll_new();
+ case IN:
+ if (*inc_interval_list == NULL)
+ *inc_interval_list = ll_new();
+
+ ll_append(*inc_interval_list, interval);
+ break;
+
+ case EX:
+ if (*exc_interval_list == NULL)
+ *exc_interval_list = ll_new();
+
+ ll_append(*exc_interval_list, interval);
+ break;
- ll_append(*exc_interval_list, interval);
+ case ALEFT:
+ if (*al_interval_list == NULL)
+ *al_interval_list = ll_new();
+
+ ll_append(*al_interval_list, interval);
+ break;
+
+ case ARIGHT:
+ if (*ar_interval_list == NULL)
+ *ar_interval_list = ll_new();
+
+ ll_append(*ar_interval_list, interval);
+ break;
+
+ case ACENTER:
+ if (*ac_interval_list == NULL)
+ *ac_interval_list = ll_new();
+
+ ll_append(*ac_interval_list, interval);
+ break;
}
- else
+ }
+
+ /* If we are here, then all the intervals have be successfully parsed */
+ /* Ensure that the unparsed string is empty. */
+ /* """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+ *unparsed = '\0';
+}
+
+/* ===================================================================== */
+/* Parse a commas separated sequence of regular expression. */
+/* Uses to align to the left, right or center some words base on reguler */
+/* expressions. */
+/* */
+/* str (in) sequence of regular expression. */
+/* al_regex_list (out) list of RE for left-aligned words. */
+/* ar_regex_list (out) list of RE for left-aligned words. */
+/* ac_regex_list (out) list of RE for centered words. */
+/* default_alignment (out) new default alignment. */
+/* misc (in) used by utf8_interpret. */
+/* ===================================================================== */
+void
+parse_al_selectors(char * str, char * unparsed, ll_t ** al_regex_list,
+ ll_t ** ar_regex_list, ll_t ** ac_regex_list,
+ alignment_t * default_alignment, misc_t * misc)
+{
+ char mark; /* Value to set */
+ char c;
+ size_t start = 1; /* column string offset in the parsed string. */
+ size_t first, second; /* range starting and ending values. */
+ char * ptr; /* pointer to the remaining string to parse. */
+ interval_t * interval;
+ int type;
+
+ /* Replace the UTF-8 string representation in the selector by */
+ /* their binary values. */
+ /* """""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+ utf8_interpret(str, misc->invalid_char_substitute);
+
+ /* Get the first character to see if this is */
+ /* an additive or restrictive operation. */
+ /* """"""""""""""""""""""""""""""""""""""""" */
+ if (sscanf(str, "%c", &c) == 0)
+ return;
+
+ switch (c)
+ {
+ case 'l':
+ case 'L':
+ type = ALEFT;
+ break;
+
+ case 'r':
+ case 'R':
+ type = ARIGHT;
+ break;
+
+ case 'c':
+ case 'C':
+ type = ACENTER;
+ break;
+
+ default:
+ if (!isgraph(c))
+ return;
+
+ start = 0;
+ break;
+ }
+
+ /* Set ptr to the start of the interval list to parse. */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""" */
+ ptr = str + start;
+
+ if (*ptr == '\0' && *default_alignment == AL_NONE)
+ switch (type)
+ {
+ case ALEFT:
+ *default_alignment = AL_LEFT;
+ break;
+ case ARIGHT:
+ *default_alignment = AL_RIGHT;
+ break;
+ case ACENTER:
+ *default_alignment = AL_CENTERED;
+ break;
+ default:
+ my_strcpy(unparsed, str);
+ return;
+ }
+
+ first = second = -1;
+
+ /* Scan the comma separated ranges. */
+ /* '\' can be used to escape a ','. */
+ /* """""""""""""""""""""""""""""""" */
+ while (*ptr)
+ {
+ char delim1, delim2 = '\0';
+ char * oldptr;
+
+ oldptr = ptr;
+ while (*ptr && *ptr != ',')
+ {
+ if (*ptr == '\\' && *(ptr + 1) != '\0' && *(ptr + 1) == ',')
+ ptr += 2;
+ else
+ ptr++;
+ }
+
+ /* Forbid the trailing comma (ex: xxx,). */
+ /* """"""""""""""""""""""""""""""""""""" */
+ if (*ptr == ',' && (*(ptr + 1) == '\0'))
+ {
+ my_strcpy(unparsed, ptr);
+ return;
+ }
+
+ /* Forbid the empty patterns (ex: xxx,,yyy). */
+ /* """"""""""""""""""""""""""""""""""""""""" */
+ if (oldptr == ptr)
{
- if (*inc_interval_list == NULL)
- *inc_interval_list = ll_new();
+ my_strcpy(unparsed, ptr);
+ return;
+ }
+
+ /* Mark the end of the interval found. */
+ /* """"""""""""""""""""""""""""""""""" */
+ if (*ptr)
+ *ptr++ = '\0';
+
+ /* If the regex contains at least three characters then delim1 */
+ /* and delim2 point to the first and last delimiter of the */
+ /* regular expression. E.g. /abc/ */
+ /* ^ ^ */
+ /* | | */
+ /* delim1 delim2 */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+ delim1 = *(str + start);
+ if (*ptr == '\0')
+ delim2 = *(ptr - 1);
+ else if (ptr > str + start + 2)
+ delim2 = *(ptr - 2);
- ll_append(*inc_interval_list, interval);
+ /* Forbid the empty patterns (ex: xxx,,yyy) and check is we have */
+ /* found a well described regular expression. */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+ if (ptr > str + start + 2 && delim1 == delim2 && isgraph(delim1)
+ && isgraph(delim2) && !isdigit(delim1) && !isdigit(delim2))
+ {
+ /* Process the regex. */
+ /* """""""""""""""""" */
+ switch (type)
+ {
+ case ALEFT:
+ parse_regex_selector_part(str + start, al_regex_list);
+ break;
+ case ARIGHT:
+ parse_regex_selector_part(str + start, ar_regex_list);
+ break;
+ case ACENTER:
+ parse_regex_selector_part(str + start, ac_regex_list);
+ break;
+ }
+
+ /* Adjust the start of the new interval to read in the */
+ /* initial string. */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""" */
+ start = ptr - str;
+
+ continue;
+ }
+ else
+ {
+ my_strcpy(unparsed, ptr - 1);
+ return;
}
}
@@ -5564,6 +5831,22 @@ rows_select_action(char * ctx_name, char * opt_name, char * param,
}
void
+aligns_select_action(char * ctx_name, char * opt_name, char * param,
+ int nb_values, char ** values, int nb_opt_data,
+ void ** opt_data, int nb_ctx_data, void ** ctx_data)
+{
+ int v;
+ ll_t ** aligns_selector_list = opt_data[0];
+ win_t * win = opt_data[1];
+
+ if (*aligns_selector_list == NULL)
+ *aligns_selector_list = ll_new();
+
+ for (v = 0; v < nb_values; v++)
+ ll_append(*aligns_selector_list, xstrdup(values[v]));
+}
+
+void
toggle_action(char * ctx_name, char * opt_name, char * param, int nb_values,
char ** values, int nb_opt_data, void ** opt_data,
int nb_ctx_data, void ** ctx_data)
@@ -6793,6 +7076,85 @@ shift_arrow_clicked(win_t * win, term_t * term, int line_click,
return 1;
}
+/* ============================================================== */
+/* Takes a string with leading and/or trailing spaces and try to */
+/* left-align, right-align or center them by re-arranging blanks. */
+/* word IN/OUT string to work with. */
+/* alignment IN kind of alignments. */
+/* ============================================================== */
+void
+align_word(word_t * word, alignment_t alignment, size_t prefix)
+{
+ switch (alignment)
+ {
+ char * str;
+ size_t n;
+ size_t m;
+ size_t wl;
+ size_t l;
+
+ case AL_LEFT:
+ /* Left align the word. */
+ /* """""""""""""""""""" */
+ str = strdup(word->str + prefix);
+ n = 0;
+
+ while (isspace(str[n]))
+ n++;
+
+ swap_string_parts(&str, n);
+
+ strcpy(word->str + prefix, str);
+ free(str);
+
+ break;
+
+ case AL_RIGHT:
+ /* Right align the word. */
+ /* """"""""""""""""""""" */
+ str = strdup(word->str + prefix);
+ n = strlen(str) - 1;
+
+ while (n && isspace(str[n]))
+ n--;
+
+ swap_string_parts(&str, n + 1);
+
+ strcpy(word->str + prefix, str);
+ free(str);
+
+ break;
+
+ case AL_CENTERED:
+ /* Center the word. */
+ /* """""""""""""""" */
+ str = strdup(word->str + prefix);
+ n = 0;
+ l = strlen(str);
+ m = l - 1;
+
+ while (isspace(str[n]))
+ n++;
+
+ while (m && isspace(str[m]))
+ m--;
+
+ if (n > m)
+ break;
+
+ wl = m - n + 1;
+ memset(word->str + prefix, ' ', l);
+
+ strncpy(word->str + prefix + (l - wl) / 2, str + n, wl);
+ free(str);
+
+ break;
+
+ default:
+ break;
+ }
+}
+
/* ================= */
/* Main entry point. */
/* ================= */
@@ -7016,16 +7378,36 @@ main(int argc, char * argv[])
ll_t * include_sed_list = NULL; /* idem for -I. */
ll_t * exclude_sed_list = NULL; /* idem for -E. */
- ll_t * inc_col_interval_list = NULL; /* list of included or */
+ ll_t * inc_col_interval_list = NULL; /* Lists of included or */
ll_t * exc_col_interval_list = NULL; /* excluded numerical intervals */
ll_t * inc_row_interval_list = NULL; /* for lines and columns. */
ll_t * exc_row_interval_list = NULL;
- ll_t * inc_col_regex_list = NULL; /* same for lines and columns specified. */
+ ll_t * inc_col_regex_list = NULL; /* Same for lines and columns specified. */
ll_t * exc_col_regex_list = NULL; /* by regular expressions. */
ll_t * inc_row_regex_list = NULL;
ll_t * exc_row_regex_list = NULL;
+ ll_t * al_col_interval_list = NULL; /* Lists of left aligned rows/columns, */
+ ll_t * ar_col_interval_list = NULL; /* right aligned rows/columns, */
+ ll_t * ac_col_interval_list = NULL; /* centered rows/columns */
+ ll_t * al_row_interval_list = NULL;
+ ll_t * ar_row_interval_list = NULL;
+ ll_t * ac_row_interval_list = NULL;
+
+ ll_t * al_col_regex_list = NULL; /* Same for regular expression based */
+ ll_t * ar_col_regex_list = NULL; /* alignments. */
+ ll_t * ac_col_regex_list = NULL;
+ ll_t * al_row_regex_list = NULL;
+ ll_t * ar_row_regex_list = NULL;
+ ll_t * ac_row_regex_list = NULL;
+
+ ll_t * al_word_regex_list = NULL;
+ ll_t * ar_word_regex_list = NULL;
+ ll_t * ac_word_regex_list = NULL;
+
+ alignment_t default_alignment = AL_NONE;
+
filters_t rows_filter_type = UNKNOWN_FILTER;
char * first_word_pattern = NULL; /* used by -A/-Z. */
@@ -7043,10 +7425,15 @@ main(int argc, char * argv[])
| -S/-I/-E. */
ll_t * cols_selector_list = NULL; /* to store ASCII representations of */
- char * cols_selector = NULL; /* RE to select some columns with -C. */
+ char * cols_selector = NULL; /* ranges add RE to select some columns *
+ | with -C. */
ll_t * rows_selector_list = NULL; /* to store ASCII representations of */
- char * rows_selector = NULL; /* RE to select some rows with -R. */
+ char * rows_selector = NULL; /* ranges and RE to select some rows *
+ | with -R. */
+
+ ll_t * aligns_selector_list = NULL; /* to store ASCII representations of */
+ char * aligns_selector = NULL; /* RE to select some rows with -al. */
long wi; /* word index. */
@@ -7092,16 +7479,22 @@ main(int argc, char * argv[])
long * col_real_max_size = NULL; /* Array of maximum sizes (bytes) of each */
/* column in column mode. */
- long * col_max_size = NULL; /* Array of maximum sizes of each column */
- /* in column mode. */
+
+ long * col_max_size = NULL; /* Array of maximum sizes (in display cells) *
+ | of each column in column mode. */
+
+ alignment_t * col_alignments; /* Alignment tag for each column in column *
+ | mode. */
long word_real_max_size = 0; /* size of the longer word after expansion. */
long cols_real_max_size = 0; /* Max real width of all columns used when *
| -w and -c are both set. */
- long cols_max_size = 0; /* Same as above for the columns widths */
- long col_index = 0; /* Index of the current column when reading words, *
+ long cols_max_size = 0; /* Same as above for the columns widths */
+
+ long col_index = 0; /* Index of the current column when reading words, *
| used in column mode. */
+
long cols_number = 0; /* Number of columns in column mode. */
char * pre_selection_index = NULL; /* pattern used to set the initial *
@@ -7397,6 +7790,7 @@ main(int argc, char * argv[])
col_spec_options = "[wide_mode] "
"[columns_select... #selector...] "
"[rows_select... #selector...] "
+ "[aligns_select... #re_selector...] "
"[gutter [#string]] "
"[line_separators #bytes] "
"[da_options #prefix:attr...] "
@@ -7505,6 +7899,7 @@ main(int argc, char * argv[])
"-C -cs -cols -cols_select");
ctxopt_add_opt_settings(parameters, "rows_select",
"-R -rs -rows -rows_select");
+ ctxopt_add_opt_settings(parameters, "aligns_select", "-al -align");
ctxopt_add_opt_settings(parameters, "force_first_column",
"-A -fc -first_column");
ctxopt_add_opt_settings(parameters, "force_last_column",
@@ -7598,6 +7993,8 @@ main(int argc, char * argv[])
&cols_selector_list, (char *)0);
ctxopt_add_opt_settings(actions, "rows_select", rows_select_action,
&rows_selector_list, &win, (char *)0);
+ ctxopt_add_opt_settings(actions, "aligns_select", aligns_select_action,
+ &aligns_selector_list, &win, (char *)0);
ctxopt_add_opt_settings(actions, "include_re", include_re_action,
&pattern_def_include, &include_pattern, &misc,
(char *)0);
@@ -8576,11 +8973,18 @@ main(int argc, char * argv[])
parse_selectors(rows_selector, &filter_type, unparsed,
&inc_row_interval_list, &inc_row_regex_list,
- &exc_row_interval_list, &exc_row_regex_list, &misc);
+ &exc_row_interval_list, &exc_row_regex_list,
+ &al_row_interval_list, &al_row_regex_list,
+ &ar_row_interval_list, &ar_row_regex_list,
+ &ac_row_interval_list, &ac_row_regex_list,
+ &default_alignment, &win, &misc);
if (*unparsed != '\0')
{
- fprintf(stderr, "%s: Bad -R argument. Unparsed part.\n", unparsed);
+ fprintf(stderr,
+ "Bad not allowed row selection argument. "
+ "Unparsed part: %s\n",
+ unparsed);
exit(EXIT_FAILURE);
}
@@ -8594,6 +8998,9 @@ main(int argc, char * argv[])
}
merge_intervals(inc_row_interval_list);
merge_intervals(exc_row_interval_list);
+ merge_intervals(al_row_interval_list);
+ merge_intervals(ar_row_interval_list);
+ merge_intervals(ac_row_interval_list);
}
/* Parse the column selection string if any. */
@@ -8615,11 +9022,18 @@ main(int argc, char * argv[])
parse_selectors(cols_selector, &filter_type, unparsed,
&inc_col_interval_list, &inc_col_regex_list,
- &exc_col_interval_list, &exc_col_regex_list, &misc);
+ &exc_col_interval_list, &exc_col_regex_list,
+ &al_col_interval_list, &al_col_regex_list,
+ &ar_col_interval_list, &ar_col_regex_list,
+ &ac_col_interval_list, &ac_col_regex_list,
+ &default_alignment, &win, &misc);
if (*unparsed != '\0')
{
- fprintf(stderr, "%s: Bad -C argument. Unparsed part.\n", unparsed);
+ fprintf(stderr,
+ "Bad not allowed column selection argument. "
+ "Unparsed part: %s\n",
+ unparsed);
exit(EXIT_FAILURE);
}
@@ -8627,8 +9041,6 @@ main(int argc, char * argv[])
merge_intervals(inc_col_interval_list);
merge_intervals(exc_col_interval_list);
- free(unparsed);
-
if (cols_filter_type == UNKNOWN_FILTER)
cols_filter_type = filter_type;
@@ -8675,6 +9087,39 @@ main(int argc, char * argv[])
}
node_selector = node_selector->next;
+
+ free(unparsed);
+ }
+
+ merge_intervals(al_col_interval_list);
+ merge_intervals(ar_col_interval_list);
+ merge_intervals(ac_col_interval_list);
+ }
+
+ /* parse the alignment selector list if any. */
+ /* """"""""""""""""""""""""""""""""""""""""" */
+ if (aligns_selector_list != NULL)
+ {
+ ll_node_t * node_selector = aligns_selector_list->head;
+
+ while (node_selector != NULL)
+ {
+ aligns_selector = node_selector->data;
+ char * unparsed = xstrdup((char *)aligns_selector);
+
+ parse_al_selectors(aligns_selector, unparsed, &al_word_regex_list,
+ &ar_word_regex_list, &ac_word_regex_list,
+ &default_alignment, &misc);
+
+ if (*unparsed != '\0')
+ {
+ fprintf(stderr, "Bad alignment selection argument. Unparsed part: %s\n",
+ unparsed);
+
+ exit(EXIT_FAILURE);
+ }
+
+ node_selector = node_selector->next;
}
}
@@ -9117,6 +9562,12 @@ main(int argc, char * argv[])
}
}
+ /* Initialize the alignment information of each column to be 'left'. */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+ col_alignments = xmalloc(cols_number * sizeof(alignment_t));
+ for (long ci = 0; ci < cols_number; ci++)
+ col_alignments[ci] = AL_NONE;
+
/* Store some known values in the current word's structure. */
/* """""""""""""""""""""""""""""""""""""""""""""""""""""""" */
word_a[count].start = word_a[count].end = 0;
@@ -9783,9 +10234,50 @@ main(int argc, char * argv[])
col_index = 0;
for (wi = 0; wi < count; wi++)
{
- long s1, s2;
- long word_width;
- wchar_t * w;
+ long s1, s2;
+ long word_width;
+ wchar_t * w;
+ regex_t re;
+ ll_node_t * node;
+ interval_t * interval;
+
+ /* Does this word matched by one of the alignment regex? */
+ /* If yes, then add the current column number to the list of the
+ * corresponding column_alignment list
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""""" */
+ ll_t * regex_list_a[3] = { al_col_regex_list, ar_col_regex_list,
+ ac_col_regex_list };
+ ll_t ** interval_list_a[3] = { &al_col_interval_list,
+ &ar_col_interval_list,
+ &ac_col_interval_list };
+
+ for (int i = 0; i < 3; i++) /* For each regex list. */
+ {
+ if (regex_list_a[i] == NULL)
+ continue;
+
+ node = regex_list_a[i]->head;
+ while (node) /* For each RE in the list. */
+ {
+ re = *(regex_t *)(node->data);
+ if (regexec(&re, word_a[wi].str, (int)0, NULL, 0) == 0)
+ {
+ /* We have a match. */
+ /* '''''''''''''''' */
+ interval = malloc(sizeof(interval_t));
+ interval->low = interval->high = col_index;
+
+ /* Append a new interval containing the current column number */
+ /* in the interval list matching the regex list. */
+ /* '''''''''''''''''''''''''''''''''''''''''''''''''''''''''' */
+ if (*interval_list_a[i] == NULL)
+ *interval_list_a[i] = ll_new();
+
+ ll_append(*interval_list_a[i], interval);
+ }
+ node = node->next;
+ }
+ }
s1 = (long)strlen(word_a[wi].str);
word_width = mbstowcs(NULL, word_a[wi].str, 0);
@@ -9803,6 +10295,9 @@ main(int argc, char * argv[])
else
col_index++;
}
+ merge_intervals(al_col_interval_list);
+ merge_intervals(ar_col_interval_list);
+ merge_intervals(ac_col_interval_list);
}
else if (win.tab_mode)
{
@@ -9880,6 +10375,234 @@ main(int argc, char * argv[])
}
}
+ /* Sixth pass: Apply alignment rules in column modes. */
+ /* """""""""""""""""""""""""""""""""""""""""""""""""" */
+ if (win.col_mode)
+ {
+ long row_index = 0;
+ interval_t interval;
+ size_t n;
+ char * words;
+ alignment_t row_alignment;
+ alignment_t word_alignment;
+
+ col_index = 0;
+
+ ll_t * word_regex_list_a[3] = { al_word_regex_list, ar_word_regex_list,
+ ac_word_regex_list };
+
+ ll_node_t * cur_word_node_a[3];
+
+ ll_t * col_interval_list_a[3] = { al_col_interval_list,
+ ar_col_interval_list,
+ ac_col_interval_list };
+
+ ll_node_t * cur_col_node_a[3] = {
+ al_col_interval_list != NULL ? al_col_interval_list->head : NULL,
+ ar_col_interval_list != NULL ? ar_col_interval_list->head : NULL,
+ ac_col_interval_list != NULL ? ac_col_interval_list->head : NULL
+ };
+
+ ll_t * row_interval_list_a[3] = { al_row_interval_list,
+ ar_row_interval_list,
+ ac_row_interval_list };
+
+ ll_node_t * cur_row_interval_node_a[3] = {
+ al_row_interval_list != NULL ? al_row_interval_list->head : NULL,
+ ar_row_interval_list != NULL ? ar_row_interval_list->head : NULL,
+ ac_row_interval_list != NULL ? ac_row_interval_list->head : NULL
+ };
+
+ ll_t * row_regex_list_a[3] = { al_row_regex_list, ar_row_regex_list,
+ ac_row_regex_list };
+
+ ll_node_t * cur_row_regex_node_a[3];
+
+ alignment_t alignment_a[3] = { AL_LEFT, AL_RIGHT, AL_CENTERED };
+
+ char * aligned_a; /* Array of indicators used to remember that a word *
+ | has been aliugnes with -al in a row. */
+
+ /* Initialize each of its places with No ('N'). */
+ /* """""""""""""""""""""""""""""""""""""""""""" */
+ aligned_a = xmalloc(cols_number);
+
+ for (int i = 0; i < cols_number; i++)
+ aligned_a[i] = 'N';
+
+ row_alignment = AL_NONE;
+
+ for (wi = 0; wi < count; wi++)
+ {
+ word_alignment = AL_NONE;
+
+ /* First heck if the current word is matched by a word specified */
+ /* regular expression set by the * alignment option. */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+
+ cur_word_node_a[0] = al_word_regex_list != NULL ? al_word_regex_list->head
+ : NULL;
+
+ cur_word_node_a[1] = ar_word_regex_list != NULL ? ar_word_regex_list->head
+ : NULL;
+
+ cur_word_node_a[2] = ac_word_regex_list != NULL ? ac_word_regex_list->head
+ : NULL;
+
+ cur_row_regex_node_a[0] = al_row_regex_list != NULL
+ ? al_row_regex_list->head
+ : NULL;
+
+ cur_row_regex_node_a[1] = ar_row_regex_list != NULL
+ ? ar_row_regex_list->head
+ : NULL;
+
+ cur_row_regex_node_a[2] = ac_row_regex_list != NULL
+ ? ac_row_regex_list->head
+ : NULL;
+
+ /* Process the word alignment regex lists. */
+ /* """"""""""""""""""""""""""""""""""""""" */
+ for (int i = 0; i < 3; i++)
+ {
+ while (word_alignment == AL_NONE && cur_word_node_a[i] != NULL)
+ {
+ char * str;
+ regex_t * re;
+
+ str = word_a[wi].str + daccess.flength;
+ re = (regex_t *)(cur_word_node_a[i]->data);
+
+ if (regexec(re, str, (int)0, NULL, 0) == 0)
+ {
+ word_alignment = alignment_a[i];
+
+ /* Mark this word as aligned in this row. */
+ /* """""""""""""""""""""""""""""""""""""" */
+ if (win.col_mode)
+ aligned_a[col_index] = 'Y';
+
+ break; /* Early exit of the while loop. */
+ }
+
+ cur_word_node_a[i] = cur_word_node_a[i]->next;
+ }
+ }
+
+ /* Process the alignment lists for columns and increment */
+ /* their current pointers when needed. */
+ /* The current interval pointer cur_col_node_a[i] is only */
+ /* modified to point to the next one of the list is the */
+ /* current column is greater than the max column in the */
+ /* pointed interval. */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+ for (int i = 0; i < 3; i++)
+ {
+ if (cur_col_node_a[i] != NULL)
+ {
+ interval = *(interval_t *)(cur_col_node_a[i]->data);
+ if (col_index >= interval.low && col_index <= interval.high)
+ {
+ if (col_alignments[col_index] == AL_NONE)
+ col_alignments[col_index] = alignment_a[i];
+ }
+ else if (col_index > interval.high)
+ cur_col_node_a[i] = cur_col_node_a[i]->next;
+ }
+ if (word_a[wi].is_last && col_interval_list_a[i] != NULL)
+ cur_col_node_a[i] = col_interval_list_a[i]->head;
+ }
+
+ /* Process row interval and regex alignment lists. */
+ /* """"""""""""""""""""""""""""""""""""""""""""""" */
+ for (int i = 0; i < 3; i++)
+ {
+ /* Lists of intervals. */
+ /* ''''''''''''''''''' */
+ if (cur_row_interval_node_a[i] != NULL)
+ {
+ interval = *(interval_t *)(cur_row_interval_node_a[i]->data);
+ if (row_index >= interval.low && row_index <= interval.high)
+ row_alignment = alignment_a[i];
+ else if (row_index > interval.high)
+ cur_row_interval_no