2007-01-16 21:04:15 +03:00
/*
* Copyright ( C ) 2002 - 2004 Sistina Software , Inc . All rights reserved .
2015-11-10 00:48:13 +03:00
* Copyright ( C ) 2004 - 2015 Red Hat , Inc . All rights reserved .
2007-01-16 21:04:15 +03:00
*
2007-08-21 20:26:07 +04:00
* This file is part of the device - mapper userspace tools .
2007-01-16 21:04:15 +03:00
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 20:26:07 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2007-01-16 21:04:15 +03:00
*
2007-08-21 20:26:07 +04:00
* You should have received a copy of the GNU Lesser General Public License
2007-01-16 21:04:15 +03:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2007-01-16 21:04:15 +03:00
*/
2018-05-14 12:30:20 +03:00
# include "libdm/misc/dmlib.h"
2007-01-16 21:04:15 +03:00
2008-04-20 04:11:08 +04:00
# include <ctype.h>
2014-05-29 11:38:22 +04:00
# include <math.h> /* fabs() */
# include <float.h> /* DBL_EPSILON */
2015-05-21 16:19:03 +03:00
# include <time.h>
2008-04-20 04:11:08 +04:00
2007-01-16 21:04:15 +03:00
/*
* Internal flags
*/
# define RH_SORT_REQUIRED 0x00000100
# define RH_HEADINGS_PRINTED 0x00000200
2016-06-27 15:27:43 +03:00
# define RH_FIELD_CALC_NEEDED 0x00000400
# define RH_ALREADY_REPORTED 0x00000800
2007-01-16 21:04:15 +03:00
libdm: report: fix incorrect memory use while using --select with --unbuffered for reporting
Under certain circumstances, the selection code can segfault:
$ vgs --select 'pv_name=~/dev/sda' --unbuffered vg0
VG #PV #LV #SN Attr VSize VFree
vg0 6 3 0 wz--n- 744.00m 588.00m
Segmentation fault (core dumped)
The problem here is the use of --ubuffered together with regex used in
selection criteria. If the report output is not buffered, each row is
discarded as soon as it is reported. The bug is in the use of report
handle's memory - in the example above, what happens is:
1) report handle is initialized together with its memory pool
2) selection tree is initialized from selection criteria string
(using the report handle's memory pool!)
2a) this also means the regex is initialized from report handle's mem pool
3) the object (row) is reported
3a) any memory needed for output is intialized out of report handle's mem pool
3b) selection criteria matching is executed - if the regex is checked the
very first time (for the very first row reported), some more memory
allocation happens as regex allocates internal structures "on-demand",
it's allocating from report handle's mem pool (see also step 2a)
4) the report output is executed
5) the object (row) is discarded, meaning discarding all the mem pool
memory used since step 3.
Now, with step 5) we have discarded the regex internal structures from step 3b.
When we execute reporting for another object (row), we're using the same
selection criteria (step 3b), but tihs is second time we're using the regex
and as such, it's already initialized completely. But the regex is missing the
internal structures now as they got discarded in step 5) from previous
object (row) reporting (because we're using "unbuffered" reporting).
To resolve this issue and to prevent any similar future issues where each
object/row memory is discarded after output (the unbuffered reporting) while
selection tree is global for all the object/rows, use separate memory pool
for report's selection.
This patch replaces "struct selection_node *selection_root" in struct
dm_report with new struct selection which contains both "selection_root"
and "mem" for separate mem pool used for selection.
We can change struct dm_report this way as it is not exposed via libdevmapper.
(This patch will have even more meaning for upcoming patches where selection
is used even for non-reporting commands where "internal" reporting and
selection criteria matching happens and where the internal reporting is
not buffered.)
2014-12-09 12:36:27 +03:00
struct selection {
struct dm_pool * mem ;
struct selection_node * selection_root ;
2016-05-12 16:04:37 +03:00
int add_new_fields ;
libdm: report: fix incorrect memory use while using --select with --unbuffered for reporting
Under certain circumstances, the selection code can segfault:
$ vgs --select 'pv_name=~/dev/sda' --unbuffered vg0
VG #PV #LV #SN Attr VSize VFree
vg0 6 3 0 wz--n- 744.00m 588.00m
Segmentation fault (core dumped)
The problem here is the use of --ubuffered together with regex used in
selection criteria. If the report output is not buffered, each row is
discarded as soon as it is reported. The bug is in the use of report
handle's memory - in the example above, what happens is:
1) report handle is initialized together with its memory pool
2) selection tree is initialized from selection criteria string
(using the report handle's memory pool!)
2a) this also means the regex is initialized from report handle's mem pool
3) the object (row) is reported
3a) any memory needed for output is intialized out of report handle's mem pool
3b) selection criteria matching is executed - if the regex is checked the
very first time (for the very first row reported), some more memory
allocation happens as regex allocates internal structures "on-demand",
it's allocating from report handle's mem pool (see also step 2a)
4) the report output is executed
5) the object (row) is discarded, meaning discarding all the mem pool
memory used since step 3.
Now, with step 5) we have discarded the regex internal structures from step 3b.
When we execute reporting for another object (row), we're using the same
selection criteria (step 3b), but tihs is second time we're using the regex
and as such, it's already initialized completely. But the regex is missing the
internal structures now as they got discarded in step 5) from previous
object (row) reporting (because we're using "unbuffered" reporting).
To resolve this issue and to prevent any similar future issues where each
object/row memory is discarded after output (the unbuffered reporting) while
selection tree is global for all the object/rows, use separate memory pool
for report's selection.
This patch replaces "struct selection_node *selection_root" in struct
dm_report with new struct selection which contains both "selection_root"
and "mem" for separate mem pool used for selection.
We can change struct dm_report this way as it is not exposed via libdevmapper.
(This patch will have even more meaning for upcoming patches where selection
is used even for non-reporting commands where "internal" reporting and
selection criteria matching happens and where the internal reporting is
not buffered.)
2014-12-09 12:36:27 +03:00
} ;
2016-05-02 15:21:05 +03:00
struct report_group_item ;
2007-01-16 21:04:15 +03:00
struct dm_report {
struct dm_pool * mem ;
libdm: fix report rows and headings memory and state leaks
Not releasing objects back to the pool is fine for short-lived
pools since the memory will be freed when dm_pool_destroy() is
called.
Any pool that may be long-lived needs to be more careful to free
objects back to the pool to avoid leaking memory that will not be
reclaimed until the pool is destroyed at process exit time.
The report pool currently leaks each headings line and some row
data.
Although dm_report_output() tries to free the first allocated row
this may end up freeing a later row due to sorting of the row list
while reporting. Store a pointer to the first allocated row from
_do_report_obect() instead and free this at the end of
_output_as_columns(), _output_as_rows(), and dm_report_clear().
Also make sure to call dm_pool_free() for the headings line built
in _report_headings().
When dmstats is introduced it will maintain dm_report objects for
the whole lifetime of the process: without these changes a stats
report could leak around 600k in 10m (exact rate depends on field
selection and data values):
top - 12:11:32 up 4 days, 3:16, 15 users, load average: 0.01, 0.12, 0.14
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6473 root 20 0 130196 3124 2792 S 0.0 0.0 0:00.00 dmstats
top - 12:22:04 up 4 days, 3:26, 15 users, load average: 0.06, 0.11, 0.13
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6498 root 20 0 130836 3712 2752 S 0.0 0.0 0:00.60 dmstats
With this patch no increase in RSS is seen:
top - 13:54:58 up 4 days, 4:59, 15 users, load average: 0.12, 0.14, 0.14
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
13962 root 20 0 130196 2996 2688 S 0.0 0.0 0:00.00 dmstats
top - 14:04:31 up 4 days, 5:09, 15 users, load average: 1.02, 0.67, 0.36
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
13962 root 20 0 130196 2996 2688 S 0.3 0.0 0:00.32 dmstats
This also affects report output for repeating reports in the
DM_REPORT_OUTPUT_COLUMNS_AS_ROWS case; row state is not fully cleared for
the next iteration leading to progressive growth of the heading width:
vg_hex-lv_home:vg_hex-lv_swap:vg_hex-lv_root:luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:vg_hex-lv_images
253:253:253:253:253
2:0:1:4:3
L--w:L--w:L--w:L--w:L--w
1:2:1:1:1
3:1:1:1:2
0:0:0:0:0
LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiv08BCGvF4WsJSqWUDUt7qtf2hEmjtVvo:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiKf7XIiwdAYOJfaGhQe9fu26cTEICGgFS:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiEZj7ZXbmrWDuGhd7vvi88VF0NdTMG8iA:CRYPT-LUKS1-797339213f684c929eb7d0aca4c6ba3e-luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOi2rKredlBPnw2X7v1BiCuEpFo6gaE7BRw
:::::vg_hex-lv_home:vg_hex-lv_swap:vg_hex-lv_root:luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:vg_hex-lv_images
:::::253:253:253:253:253
:::::2:0:1:4:3
:::::L--w:L--w:L--w:L--w:L--w
:::::1:2:1:1:1
:::::3:1:1:1:2
:::::0:0:0:0:0
:::::LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiv08BCGvF4WsJSqWUDUt7qtf2hEmjtVvo:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiKf7XIiwdAYOJfaGhQe9fu26cTEICGgFS:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOiEZj7ZXbmrWDuGhd7vvi88VF0NdTMG8iA:CRYPT-LUKS1-797339213f684c929eb7d0aca4c6ba3e-luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e:LVM-9t8ITqLZa6AuuyVoz5Olp1KwF9ZDBfOi2rKredlBPnw2X7v1BiCuEpFo6gaE7BRw
2015-08-07 19:08:54 +03:00
/**
* Cache the first row allocated so that all rows and fields
* can be disposed of in a single dm_pool_free ( ) call .
*/
struct row * first_row ;
2010-01-07 17:30:47 +03:00
/* To report all available types */
# define REPORT_TYPES_ALL UINT32_MAX
2007-01-16 21:04:15 +03:00
uint32_t report_types ;
2008-04-20 04:11:08 +04:00
const char * output_field_name_prefix ;
2007-01-16 21:04:15 +03:00
const char * field_prefix ;
uint32_t flags ;
const char * separator ;
uint32_t keys_count ;
/* Ordered list of fields needed for this report */
2008-11-04 01:14:30 +03:00
struct dm_list field_props ;
2007-01-16 21:04:15 +03:00
/* Rows of report data */
2008-11-04 01:14:30 +03:00
struct dm_list rows ;
2007-01-16 21:04:15 +03:00
/* Array of field definitions */
const struct dm_report_field_type * fields ;
2015-08-03 17:29:50 +03:00
const char * * canonical_field_ids ;
2007-01-16 21:04:15 +03:00
const struct dm_report_object_type * types ;
/* To store caller private data */
void * private ;
2014-05-29 11:38:08 +04:00
libdm: report: fix incorrect memory use while using --select with --unbuffered for reporting
Under certain circumstances, the selection code can segfault:
$ vgs --select 'pv_name=~/dev/sda' --unbuffered vg0
VG #PV #LV #SN Attr VSize VFree
vg0 6 3 0 wz--n- 744.00m 588.00m
Segmentation fault (core dumped)
The problem here is the use of --ubuffered together with regex used in
selection criteria. If the report output is not buffered, each row is
discarded as soon as it is reported. The bug is in the use of report
handle's memory - in the example above, what happens is:
1) report handle is initialized together with its memory pool
2) selection tree is initialized from selection criteria string
(using the report handle's memory pool!)
2a) this also means the regex is initialized from report handle's mem pool
3) the object (row) is reported
3a) any memory needed for output is intialized out of report handle's mem pool
3b) selection criteria matching is executed - if the regex is checked the
very first time (for the very first row reported), some more memory
allocation happens as regex allocates internal structures "on-demand",
it's allocating from report handle's mem pool (see also step 2a)
4) the report output is executed
5) the object (row) is discarded, meaning discarding all the mem pool
memory used since step 3.
Now, with step 5) we have discarded the regex internal structures from step 3b.
When we execute reporting for another object (row), we're using the same
selection criteria (step 3b), but tihs is second time we're using the regex
and as such, it's already initialized completely. But the regex is missing the
internal structures now as they got discarded in step 5) from previous
object (row) reporting (because we're using "unbuffered" reporting).
To resolve this issue and to prevent any similar future issues where each
object/row memory is discarded after output (the unbuffered reporting) while
selection tree is global for all the object/rows, use separate memory pool
for report's selection.
This patch replaces "struct selection_node *selection_root" in struct
dm_report with new struct selection which contains both "selection_root"
and "mem" for separate mem pool used for selection.
We can change struct dm_report this way as it is not exposed via libdevmapper.
(This patch will have even more meaning for upcoming patches where selection
is used even for non-reporting commands where "internal" reporting and
selection criteria matching happens and where the internal reporting is
not buffered.)
2014-12-09 12:36:27 +03:00
/* Selection handle */
struct selection * selection ;
report: select: add support for reserved value recognition in report selection string - add struct dm_report_reserved_value
Make dm_report_init_with_selection to accept an argument with an
array of reserved values where each element contains a triple:
{dm report field type, reserved value, array of strings representing this value}
When the selection is parsed, we always check whether a string
representation of some reserved value is not hit and if it is,
we use the reserved value assigned for this string instead of
trying to parse it as a value of certain field type.
This makes it possible to define selections like:
... --select lv_major=undefined (or -1 or unknown or undef or whatever string representations are registered for this reserved value in the future)
... --select lv_read_ahead=auto
... --select vg_mda_copies=unmanaged
With this, each time the field value of certain type is hit
and when we compare it with the selection, we use the proper
value for comparison.
For now, register these reserved values that are used at the moment
(also more descriptive names are used for the values):
const uint64_t _reserved_number_undef_64 = UINT64_MAX;
const uint64_t _reserved_number_unmanaged_64 = UINT64_MAX - 1;
const uint64_t _reserved_size_auto_64 = UINT64_MAX;
{
{DM_REPORT_FIELD_TYPE_NUMBER, _reserved_number_undef_64, {"-1", "undefined", "undef", "unknown", NULL}},
{DM_REPORT_FIELD_TYPE_NUMBER, _reserved_number_unmanaged_64, {"unmanaged", NULL}},
{DM_REPORT_FIELD_TYPE_SIZE, _reserved_size_auto_64, {"auto", NULL}},
NULL
}
Same reserved value of different field types do not collide.
All arrays are null-terminated.
The list of reserved values is automatically displayed within
selection help output:
Selection operands
------------------
...
Reserved values
---------------
-1, undefined, undef, unknown - Reserved value for undefined numeric value. [number]
unmanaged - Reserved value for unmanaged number of metadata copies in VG. [number]
auto - Reserved value for size that is automatically calculated. [size]
Selection operators
-------------------
...
2014-05-30 17:02:21 +04:00
/* Null-terminated array of reserved values */
const struct dm_report_reserved_value * reserved_values ;
2015-05-19 14:01:48 +03:00
struct dm_hash_table * value_cache ;
2016-05-02 15:21:05 +03:00
struct report_group_item * group_item ;
} ;
struct dm_report_group {
dm_report_group_type_t type ;
struct dm_pool * mem ;
struct dm_list items ;
int indent ;
} ;
struct report_group_item {
struct dm_list list ;
struct dm_report_group * group ;
struct dm_report * report ;
2021-04-03 15:25:56 +03:00
union store_u {
2016-05-02 15:21:05 +03:00
uint32_t orig_report_flags ;
uint32_t finished_count ;
} store ;
struct report_group_item * parent ;
2016-12-12 13:21:42 +03:00
unsigned output_done : 1 ;
unsigned needs_closing : 1 ;
2016-05-02 15:21:05 +03:00
void * data ;
2007-01-16 21:04:15 +03:00
} ;
/*
* Internal per - field flags
*/
2014-06-09 18:23:45 +04:00
# define FLD_HIDDEN 0x00001000
# define FLD_SORT_KEY 0x00002000
# define FLD_ASCENDING 0x00004000
# define FLD_DESCENDING 0x00008000
2014-12-05 13:42:43 +03:00
# define FLD_COMPACTED 0x00010000
2015-10-16 16:50:13 +03:00
# define FLD_COMPACT_ONE 0x00020000
2007-01-16 21:04:15 +03:00
struct field_properties {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2007-01-16 21:04:15 +03:00
uint32_t field_num ;
uint32_t sort_posn ;
libdm: reset report field widths in _destroy_rows()
For repeating reports field widths should be re-calculated for
each report interval. Not doing so will cause a single row with
wide field data to cause all subsequent rows to share the width:
Name RgID ArID R/s W/s Histogram Bounds
vg_hex-lv_home 0 0 4522.00 834.00 0s: 991, 2ms: 152, 4ms: 161, 6ms: 4052 0s, 2ms, 4ms, 6ms
vg_hex-lv_swap 0 0 0.00 0.00 0s: 0, 2ms: 0, 4ms: 0, 6ms: 0 0s, 2ms, 4ms, 6ms
vg_hex-lv_root 0 0 1754.00 683.00 0s: 369, 2ms: 65, 4ms: 90, 6ms: 1913 0s, 2ms, 4ms, 6ms
luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e 0 0 4522.00 868.00 0s: 985, 2ms: 152, 4ms: 161, 6ms: 4092 0s, 2ms, 4ms, 6ms
vg_hex-lv_images 0 0 0.00 0.00 0s: 0, 2ms: 0, 4ms: 0, 6ms: 0 0s, 2ms, 4ms, 6ms
Name RgID ArID R/s W/s Histogram Bounds
vg_hex-lv_home 0 0 0.00 0.00 0s: 0, 2ms: 0, 4ms: 0, 6ms: 0 0s, 2ms, 4ms, 6ms
vg_hex-lv_swap 0 0 0.00 0.00 0s: 0, 2ms: 0, 4ms: 0, 6ms: 0 0s, 2ms, 4ms, 6ms
vg_hex-lv_root 0 0 0.00 2.00 0s: 1, 2ms: 0, 4ms: 0, 6ms: 1 0s, 2ms, 4ms, 6ms
luks-79733921-3f68-4c92-9eb7-d0aca4c6ba3e 0 0 0.00 0.00 0s: 0, 2ms: 0, 4ms: 0, 6ms: 0 0s, 2ms, 4ms, 6ms
vg_hex-lv_images 0 0 0.00 0.00 0s: 0, 2ms: 0, 4ms: 0, 6ms: 0 0s, 2ms, 4ms, 6ms
^^^^^^^^^^^^^^^^^
This is especially significant for the current histogram fields:
depending on the time since the last clear operation the first
report iteration may contain very large values leading to a very
large minimum field width. Without resetting field widths this
large minimum field width value is used for all subsequent rows.
2015-08-24 13:38:17 +03:00
int32_t initial_width ;
int32_t width ; /* current width: adjusted by dm_report_object() */
2007-01-16 21:04:15 +03:00
const struct dm_report_object_type * type ;
uint32_t flags ;
2014-06-12 15:57:22 +04:00
int implicit ;
2007-01-16 21:04:15 +03:00
} ;
2014-05-29 11:37:41 +04:00
/*
* Report selection
*/
struct op_def {
const char * string ;
uint32_t flags ;
const char * desc ;
} ;
2014-12-05 13:42:43 +03:00
# define FLD_CMP_MASK 0x0FF00000
# define FLD_CMP_UNCOMPARABLE 0x00100000
# define FLD_CMP_EQUAL 0x00200000
# define FLD_CMP_NOT 0x00400000
# define FLD_CMP_GT 0x00800000
# define FLD_CMP_LT 0x01000000
# define FLD_CMP_REGEX 0x02000000
# define FLD_CMP_NUMBER 0x04000000
2015-05-21 16:19:03 +03:00
# define FLD_CMP_TIME 0x08000000
2014-05-29 11:37:41 +04:00
/*
2015-05-21 16:19:03 +03:00
* # define FLD_CMP_STRING 0x10000000
* We could define FLD_CMP_STRING here for completeness here ,
2014-05-29 11:37:41 +04:00
* but it ' s not needed - we can check operator compatibility with
2015-05-21 16:19:03 +03:00
* field type by using FLD_CMP_REGEX , FLD_CMP_NUMBER and
* FLD_CMP_TIME flags only .
2014-05-29 11:37:41 +04:00
*/
/*
* When defining operators , always define longer one before
* shorter one if one is a prefix of another !
* ( e . g . = ~ comes before = )
*/
2024-05-03 13:58:40 +03:00
static const struct op_def _op_cmp [ ] = {
2014-06-19 17:19:54 +04:00
{ " =~ " , FLD_CMP_REGEX , " Matching regular expression. [regex] " } ,
{ " !~ " , FLD_CMP_REGEX | FLD_CMP_NOT , " Not matching regular expression. [regex] " } ,
2015-05-21 16:19:03 +03:00
{ " = " , FLD_CMP_EQUAL , " Equal to. [number, size, percent, string, string list, time] " } ,
{ " != " , FLD_CMP_NOT | FLD_CMP_EQUAL , " Not equal to. [number, size, percent, string, string_list, time] " } ,
{ " >= " , FLD_CMP_NUMBER | FLD_CMP_TIME | FLD_CMP_GT | FLD_CMP_EQUAL , " Greater than or equal to. [number, size, percent, time] " } ,
{ " > " , FLD_CMP_NUMBER | FLD_CMP_TIME | FLD_CMP_GT , " Greater than. [number, size, percent, time] " } ,
{ " <= " , FLD_CMP_NUMBER | FLD_CMP_TIME | FLD_CMP_LT | FLD_CMP_EQUAL , " Less than or equal to. [number, size, percent, time] " } ,
{ " < " , FLD_CMP_NUMBER | FLD_CMP_TIME | FLD_CMP_LT , " Less than. [number, size, percent, time] " } ,
{ " since " , FLD_CMP_TIME | FLD_CMP_GT | FLD_CMP_EQUAL , " Since specified time (same as '>='). [time] " } ,
{ " after " , FLD_CMP_TIME | FLD_CMP_GT , " After specified time (same as '>'). [time] " } ,
{ " until " , FLD_CMP_TIME | FLD_CMP_LT | FLD_CMP_EQUAL , " Until specified time (same as '<='). [time] " } ,
{ " before " , FLD_CMP_TIME | FLD_CMP_LT , " Before specified time (same as '<'). [time] " } ,
2014-05-29 11:37:41 +04:00
{ NULL , 0 , NULL }
} ;
# define SEL_MASK 0x000000FF
# define SEL_ITEM 0x00000001
# define SEL_AND 0x00000002
# define SEL_OR 0x00000004
# define SEL_MODIFIER_MASK 0x00000F00
# define SEL_MODIFIER_NOT 0x00000100
# define SEL_PRECEDENCE_MASK 0x0000F000
# define SEL_PRECEDENCE_PS 0x00001000
# define SEL_PRECEDENCE_PE 0x00002000
report: select: add support for processing string lists in selection
Selection list items are enclosed in '[' and ']' (if there's only
one item, the '[' and ']' can be omitted). Each element of the list
is a string (either quoted or unquoted, like the usual string operand
used in selection) and each element is delimited either by conjunction
(meaining "match all") or disjunction operator (meaning "match any").
For example, if "," is the conjuction operator and "/" is the
disjunction operator then:
lv_tags=[a,b,c]
...will match all fields where tags contain *all* a, b and c.
lv_tags=[a/b/c]
...will match all fields where tags contain *any* of a, b, or c.
Mixing operators within the list is not supported:
lv_tags=[a,b/c]
...will give an error.
The order in which items are defined in the selection do not matter.
This patch enhances the selection parsing functionality to recognize
such lists.
2014-05-29 11:41:50 +04:00
# define SEL_LIST_MASK 0x000F0000
# define SEL_LIST_LS 0x00010000
# define SEL_LIST_LE 0x00020000
select: add support for selection to match string list subset, recognize { } operator
Using "[ ]" operator together with "&&" (or ",") inside causes the
string list to be matched if and only if all the items given match
the value reported and the number of items also match. This is
strict list matching and the original behaviour we already have.
In contrast to that, the new "{ }" operator together with "&&" inside
causes the string list to be matched if and only if all the items given
match the value reported but the number of items don't need to match.
So we can provide a subset in selection criteria and if the subset
is found, it matches.
For example:
$ lvs -o name,tags
LV LV Tags
lvol0 a
lvol1 a,b
lvol2 b,c,x
lvol3 a,b,y
$ lvs -o name,tags -S 'tags=[a,b]'
LV LV Tags
lvol1 a,b
$ lvs -o name,tags -S 'tags={a,b}'
LV LV Tags
lvol1 a,b
lvol3 a,b,y
So in the example above the a,b is subset of a,b,y and therefore
it also matches.
Clearly, when using "||" (or "#") inside, the { } and [ ] is the
same:
$ lvs -o name,tags -S 'tags=[a#b]'
LV LV Tags
lvol0 a
lvol1 a,b
lvol2 b,c,x
lvol3 a,b,y
$ lvs -o name,tags -S 'tags={a#b}'
LV LV Tags
lvol0 a
lvol1 a,b
lvol2 b,c,x
lvol3 a,b,y
Also in addition to the above feature, fix list with single value
matching when using [ ]:
Before this patch:
$ lvs -o name,tags -S 'tags=[a]'
LV LV Tags
lvol0 a
lvol1 a,b
lvol3 a,b,y
With this patch applied:
$ lvs -o name,tags -S 'tags=[a]'
LV LV Tags
lvol0 a
In case neither [] or {} is used, assume {} (the behaviour is not
changed here):
$ lvs -o name,tags -S 'tags=a'
LV LV Tags
lvol0 a
lvol1 a,b
lvol3 a,b,y
So in new terms 'tags=a' is equal to 'tags={a}'.
2014-08-13 17:39:03 +04:00
# define SEL_LIST_SUBSET_LS 0x00040000
# define SEL_LIST_SUBSET_LE 0x00080000
report: select: add support for processing string lists in selection
Selection list items are enclosed in '[' and ']' (if there's only
one item, the '[' and ']' can be omitted). Each element of the list
is a string (either quoted or unquoted, like the usual string operand
used in selection) and each element is delimited either by conjunction
(meaining "match all") or disjunction operator (meaning "match any").
For example, if "," is the conjuction operator and "/" is the
disjunction operator then:
lv_tags=[a,b,c]
...will match all fields where tags contain *all* a, b and c.
lv_tags=[a/b/c]
...will match all fields where tags contain *any* of a, b, or c.
Mixing operators within the list is not supported:
lv_tags=[a,b/c]
...will give an error.
The order in which items are defined in the selection do not matter.
This patch enhances the selection parsing functionality to recognize
such lists.
2014-05-29 11:41:50 +04:00
2024-05-03 13:58:40 +03:00
static const struct op_def _op_log [ ] = {
2015-08-05 07:11:42 +03:00
{ " && " , SEL_AND , " All fields must match " } ,
2014-05-29 11:37:41 +04:00
{ " , " , SEL_AND , " All fields must match " } ,
2015-08-05 07:11:42 +03:00
{ " || " , SEL_OR , " At least one field must match " } ,
2014-05-29 11:37:41 +04:00
{ " # " , SEL_OR , " At least one field must match " } ,
2015-08-05 07:11:42 +03:00
{ " ! " , SEL_MODIFIER_NOT , " Logical negation " } ,
{ " ( " , SEL_PRECEDENCE_PS , " Left parenthesis " } ,
{ " ) " , SEL_PRECEDENCE_PE , " Right parenthesis " } ,
{ " [ " , SEL_LIST_LS , " List start " } ,
{ " ] " , SEL_LIST_LE , " List end " } ,
{ " { " , SEL_LIST_SUBSET_LS , " List subset start " } ,
{ " } " , SEL_LIST_SUBSET_LE , " List subset end " } ,
{ NULL , 0 , NULL } ,
2014-05-29 11:37:41 +04:00
} ;
report: select: add support for processing string lists in selection
Selection list items are enclosed in '[' and ']' (if there's only
one item, the '[' and ']' can be omitted). Each element of the list
is a string (either quoted or unquoted, like the usual string operand
used in selection) and each element is delimited either by conjunction
(meaining "match all") or disjunction operator (meaning "match any").
For example, if "," is the conjuction operator and "/" is the
disjunction operator then:
lv_tags=[a,b,c]
...will match all fields where tags contain *all* a, b and c.
lv_tags=[a/b/c]
...will match all fields where tags contain *any* of a, b, or c.
Mixing operators within the list is not supported:
lv_tags=[a,b/c]
...will give an error.
The order in which items are defined in the selection do not matter.
This patch enhances the selection parsing functionality to recognize
such lists.
2014-05-29 11:41:50 +04:00
struct selection_str_list {
2015-11-18 12:54:09 +03:00
struct dm_str_list str_list ;
report: select: add support for processing string lists in selection
Selection list items are enclosed in '[' and ']' (if there's only
one item, the '[' and ']' can be omitted). Each element of the list
is a string (either quoted or unquoted, like the usual string operand
used in selection) and each element is delimited either by conjunction
(meaining "match all") or disjunction operator (meaning "match any").
For example, if "," is the conjuction operator and "/" is the
disjunction operator then:
lv_tags=[a,b,c]
...will match all fields where tags contain *all* a, b and c.
lv_tags=[a/b/c]
...will match all fields where tags contain *any* of a, b, or c.
Mixing operators within the list is not supported:
lv_tags=[a,b/c]
...will give an error.
The order in which items are defined in the selection do not matter.
This patch enhances the selection parsing functionality to recognize
such lists.
2014-05-29 11:41:50 +04:00
unsigned type ; /* either SEL_AND or SEL_OR */
} ;
2015-06-30 11:13:35 +03:00
struct field_selection_value {
2021-04-03 15:25:56 +03:00
union value_u {
2014-05-29 11:37:41 +04:00
const char * s ;
uint64_t i ;
2015-05-21 16:19:03 +03:00
time_t t ;
2014-05-29 11:37:41 +04:00
double d ;
struct dm_regex * r ;
report: select: add support for processing string lists in selection
Selection list items are enclosed in '[' and ']' (if there's only
one item, the '[' and ']' can be omitted). Each element of the list
is a string (either quoted or unquoted, like the usual string operand
used in selection) and each element is delimited either by conjunction
(meaining "match all") or disjunction operator (meaning "match any").
For example, if "," is the conjuction operator and "/" is the
disjunction operator then:
lv_tags=[a,b,c]
...will match all fields where tags contain *all* a, b and c.
lv_tags=[a/b/c]
...will match all fields where tags contain *any* of a, b, or c.
Mixing operators within the list is not supported:
lv_tags=[a,b/c]
...will give an error.
The order in which items are defined in the selection do not matter.
This patch enhances the selection parsing functionality to recognize
such lists.
2014-05-29 11:41:50 +04:00
struct selection_str_list * l ;
2014-05-29 11:37:41 +04:00
} v ;
2015-06-30 11:13:35 +03:00
struct field_selection_value * next ;
} ;
struct field_selection {
struct field_properties * fp ;
uint32_t flags ;
struct field_selection_value * value ;
2014-05-29 11:37:41 +04:00
} ;
struct selection_node {
struct dm_list list ;
uint32_t type ;
2021-04-03 15:25:56 +03:00
union selection_u {
2014-05-29 11:37:41 +04:00
struct field_selection * item ;
struct dm_list set ;
} selection ;
} ;
2015-06-30 11:23:35 +03:00
struct reserved_value_wrapper {
const char * matched_name ;
const struct dm_report_reserved_value * reserved ;
const void * value ;
} ;
2007-01-16 21:04:15 +03:00
/*
* Report data field
*/
struct dm_report_field {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2007-01-16 21:04:15 +03:00
struct field_properties * props ;
const char * report_string ; /* Formatted ready for display */
const void * sort_value ; /* Raw value for sorting */
} ;
struct row {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2007-01-16 21:04:15 +03:00
struct dm_report * rh ;
2008-11-04 01:14:30 +03:00
struct dm_list fields ; /* Fields in display order */
2007-01-16 21:04:15 +03:00
struct dm_report_field * ( * sort_fields ) [ ] ; /* Fields in sort order */
2014-06-12 15:57:22 +04:00
int selected ;
2016-05-12 15:03:32 +03:00
struct dm_report_field * field_sel_status ;
2014-06-12 15:57:22 +04:00
} ;
/*
* Implicit report types and fields .
*/
2014-07-10 02:33:09 +04:00
# define SPECIAL_REPORT_TYPE 0x80000000
# define SPECIAL_FIELD_SELECTED_ID "selected"
# define SPECIAL_FIELD_HELP_ID "help"
# define SPECIAL_FIELD_HELP_ALT_ID "?"
2014-06-12 15:57:22 +04:00
2014-06-19 17:33:16 +04:00
static void * _null_returning_fn ( void * obj __attribute__ ( ( unused ) ) )
2014-06-12 15:57:22 +04:00
{
return NULL ;
}
2014-06-19 17:33:16 +04:00
static int _no_report_fn ( struct dm_report * rh __attribute__ ( ( unused ) ) ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field __attribute__ ( ( unused ) ) ,
const void * data __attribute__ ( ( unused ) ) ,
void * private __attribute__ ( ( unused ) ) )
{
return 1 ;
}
2014-06-12 15:57:22 +04:00
static int _selected_disp ( struct dm_report * rh ,
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct dm_report_field * field ,
const void * data ,
void * private __attribute__ ( ( unused ) ) )
{
2015-08-18 16:39:04 +03:00
const struct row * row = ( const struct row * ) data ;
2014-06-12 15:57:22 +04:00
return dm_report_field_int ( rh , field , & row - > selected ) ;
}
2014-07-10 02:33:09 +04:00
static const struct dm_report_object_type _implicit_special_report_types [ ] = {
{ SPECIAL_REPORT_TYPE , " Special " , " special_ " , _null_returning_fn } ,
2014-06-19 17:33:16 +04:00
{ 0 , " " , " " , NULL }
} ;
2014-07-10 02:33:09 +04:00
static const struct dm_report_field_type _implicit_special_report_fields [ ] = {
{ SPECIAL_REPORT_TYPE , DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0 , 8 , SPECIAL_FIELD_HELP_ID , " Help " , _no_report_fn , " Show help. " } ,
{ SPECIAL_REPORT_TYPE , DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0 , 8 , SPECIAL_FIELD_HELP_ALT_ID , " Help " , _no_report_fn , " Show help. " } ,
2014-06-19 17:33:16 +04:00
{ 0 , 0 , 0 , 0 , " " , " " , 0 , 0 }
} ;
2014-07-10 02:33:09 +04:00
static const struct dm_report_field_type _implicit_special_report_fields_with_selection [ ] = {
{ SPECIAL_REPORT_TYPE , DM_REPORT_FIELD_TYPE_NUMBER , 0 , 8 , SPECIAL_FIELD_SELECTED_ID , " Selected " , _selected_disp , " Set if item passes selection criteria. " } ,
{ SPECIAL_REPORT_TYPE , DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0 , 8 , SPECIAL_FIELD_HELP_ID , " Help " , _no_report_fn , " Show help. " } ,
{ SPECIAL_REPORT_TYPE , DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0 , 8 , SPECIAL_FIELD_HELP_ALT_ID , " Help " , _no_report_fn , " Show help. " } ,
2014-06-12 15:57:22 +04:00
{ 0 , 0 , 0 , 0 , " " , " " , 0 , 0 }
2007-01-16 21:04:15 +03:00
} ;
2014-07-10 02:33:09 +04:00
static const struct dm_report_object_type * _implicit_report_types = _implicit_special_report_types ;
static const struct dm_report_field_type * _implicit_report_fields = _implicit_special_report_fields ;
2014-06-19 17:33:16 +04:00
2007-01-16 21:04:15 +03:00
static const struct dm_report_object_type * _find_type ( struct dm_report * rh ,
uint32_t report_type )
{
const struct dm_report_object_type * t ;
2014-06-12 15:57:22 +04:00
for ( t = _implicit_report_types ; t - > data_fn ; t + + )
if ( t - > id = = report_type )
return t ;
2007-01-16 21:04:15 +03:00
for ( t = rh - > types ; t - > data_fn ; t + + )
if ( t - > id = = report_type )
return t ;
return NULL ;
}
/*
* Data - munging functions to prepare each data type for display and sorting
*/
2007-01-22 18:03:57 +03:00
int dm_report_field_string ( struct dm_report * rh ,
2011-02-18 17:38:47 +03:00
struct dm_report_field * field , const char * const * data )
2007-01-16 21:04:15 +03:00
{
char * repstr ;
2007-01-22 18:03:57 +03:00
if ( ! ( repstr = dm_pool_strdup ( rh - > mem , * data ) ) ) {
2007-01-16 21:04:15 +03:00
log_error ( " dm_report_field_string: dm_pool_strdup failed " ) ;
return 0 ;
}
field - > report_string = repstr ;
field - > sort_value = ( const void * ) field - > report_string ;
return 1 ;
}
2014-06-09 14:08:27 +04:00
int dm_report_field_percent ( struct dm_report * rh ,
struct dm_report_field * field ,
const dm_percent_t * data )
{
char * repstr ;
uint64_t * sortval ;
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( uint64_t ) ) ) ) {
log_error ( " dm_report_field_percent: dm_pool_alloc failed for sort_value. " ) ;
return 0 ;
}
* sortval = ( uint64_t ) ( * data ) ;
if ( * data = = DM_PERCENT_INVALID ) {
dm_report_field_set_value ( field , " " , sortval ) ;
return 1 ;
}
if ( ! ( repstr = dm_pool_alloc ( rh - > mem , 8 ) ) ) {
dm_pool_free ( rh - > mem , sortval ) ;
log_error ( " dm_report_field_percent: dm_pool_alloc failed for percent report string. " ) ;
return 0 ;
}
2017-06-24 17:39:50 +03:00
if ( dm_snprintf ( repstr , 7 , " %.2f " , dm_percent_to_round_float ( * data , 2 ) ) < 0 ) {
2014-06-09 14:08:27 +04:00
dm_pool_free ( rh - > mem , sortval ) ;
log_error ( " dm_report_field_percent: percentage too large. " ) ;
return 0 ;
}
dm_report_field_set_value ( field , repstr , sortval ) ;
return 1 ;
}
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
struct pos_len {
2014-08-25 12:04:08 +04:00
unsigned pos ;
size_t len ;
} ;
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
struct str_pos_len {
const char * str ;
struct pos_len item ;
2014-08-25 12:04:08 +04:00
} ;
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
struct str_list_sort_value {
const char * value ;
struct pos_len * items ;
2014-08-25 12:04:08 +04:00
} ;
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
static int _str_sort_cmp ( const void * a , const void * b )
2014-08-25 12:04:08 +04:00
{
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
return strcmp ( ( ( const struct str_pos_len * ) a ) - > str , ( ( const struct str_pos_len * ) b ) - > str ) ;
2014-08-25 12:04:08 +04:00
}
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
# define FIELD_STRING_LIST_DEFAULT_DELIMITER ","
2014-08-25 12:04:08 +04:00
static int _report_field_string_list ( struct dm_report * rh ,
struct dm_report_field * field ,
const struct dm_list * data ,
const char * delimiter ,
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
int sort_repstr )
2014-05-29 11:41:18 +04:00
{
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
static const char _error_msg_prefix [ ] = " _report_field_string_list: " ;
unsigned int list_size , i , pos ;
struct str_pos_len * arr = NULL ;
2014-05-29 11:41:18 +04:00
struct dm_str_list * sl ;
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
size_t delimiter_len , repstr_str_len , repstr_size ;
char * repstr = NULL ;
struct pos_len * repstr_extra ;
struct str_list_sort_value * sortval = NULL ;
2014-05-29 11:41:18 +04:00
int r = 0 ;
/*
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
* The ' field - > report_string ' has 2 parts :
*
* - string representing the whole string list
* ( terminated by ' \0 ' at its end as usual )
*
* - extra info beyond the end of the string representing
* position and length of each list item within the
* field - > report_string ( array of ' struct pos_len ' )
*
* We can use the extra info to unambiguously identify list items ,
* the delimiter is not enough here as it ' s not assured it won ' t appear
* in list item itself . We will make use of this extra info in case
* we need to apply further formatting to the list in dm_report_output
* where the pure field - > report_string is not enough for printout .
*
*
* The ' field - > sort_value ' contains a value of type ' struct
* str_list_sort_value ' ( ' sortval ' ) . This one has a pointer to the
* ' field - > report_string ' string ( ' sortval - > value ' ) and info
* about position and length of each list item within the string
* ( array of ' struct pos_len ' ) .
2014-11-24 12:48:01 +03:00
*
*
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
* The ' field - > report_string ' is either in sorted or unsorted form ,
* depending on ' sort_repstr ' arg .
*
* The ' field - > sort_value . items ' is always in sorted form because
* we need that for effective sorting and selection .
*
* If ' field - > report_string ' is sorted , then field - > report_string
* and field - > sort_value . items share the same array of
* ' struct pos_len ' ( because they ' re both sorted the same way ) ,
* otherwise , each one has its own array .
*
* The very first item in the array of ' struct pos_len ' is always
* a pair denoting ' [ list_size , strlen ( field - > report_string ) ] ' . The
2024-08-30 00:05:41 +03:00
* rest of items denote start and length of each item in the list .
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
*
*
* For example , if we have a list with " abc " , " xy " , " defgh "
* as input and delimiter is " , " , we end up with either :
*
* A ) if we don ' t want the report string sorted ( ' sort_repstr = = 0 ' ) :
*
* - field - > report_string = repstr
*
* repstr repstr_extra
* | |
* V V
* abc , xy , defgh \ 0 { [ 3 , 12 ] , [ 0 , 3 ] , [ 4 , 2 ] , [ 7 , 5 ] }
* | ____________ | | ________________________ |
* string array of struct pos_len
* | ____ | | ________________ |
* # items items
*
* - field - > sort_value = sortval
*
* sortval - > value = repstr
* sortval - > items = { [ 3 , 12 ] , [ 0 , 3 ] , [ 7 , 5 ] , [ 4 , 2 ] }
* ( that is ' abc , defgh , xy ' )
*
*
* B ) if we want the report string sorted ( ' sort_repstr = = 1 ' ) :
*
* - field - > report_string = repstr
*
* repstr repstr_extra
* | |
* V V
* abc , defgh , xy \ 0 { [ 3 , 12 ] , [ 0 , 3 ] , [ 4 , 5 ] , [ 10 , 2 ] }
* | ____________ | | ________________________ |
* string array of struct pos_len
* | ____ | | ________________ |
* # items items
*
* - field - > sort_value = sortval
*
* sortval - > value = repstr
* sortval - > items = repstr_extra
* ( that is ' abc , defgh , xy ' )
2014-05-29 11:41:18 +04:00
*/
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
if ( ! delimiter )
delimiter = FIELD_STRING_LIST_DEFAULT_DELIMITER ;
delimiter_len = strlen ( delimiter ) ;
list_size = dm_list_size ( data ) ;
if ( ! ( sortval = dm_pool_alloc ( rh - > mem , sizeof ( struct str_list_sort_value ) ) ) ) {
log_error ( " %s failed to allocate sort value structure " , _error_msg_prefix ) ;
2014-05-29 11:41:18 +04:00
goto out ;
}
/* zero items */
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
if ( list_size = = 0 ) {
field - > report_string = sortval - > value = " " ;
sortval - > items = NULL ;
field - > sort_value = sortval ;
2014-05-29 11:41:18 +04:00
return 1 ;
}
/* one item */
if ( list_size = = 1 ) {
sl = ( struct dm_str_list * ) dm_list_first ( data ) ;
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
repstr_str_len = strlen ( sl - > str ) ;
repstr_size = repstr_str_len + 1 + ( 2 * sizeof ( struct pos_len ) ) ;
if ( ! ( repstr = dm_pool_alloc ( rh - > mem , repstr_size ) ) ) {
log_error ( " %s failed to allocate report string structure " , _error_msg_prefix ) ;
2014-05-29 11:41:18 +04:00
goto out ;
}
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
repstr_extra = ( struct pos_len * ) ( repstr + repstr_str_len + 1 ) ;
2014-05-29 11:41:18 +04:00
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
memcpy ( repstr , sl - > str , repstr_str_len + 1 ) ;
memcpy ( repstr_extra , & ( ( struct pos_len ) { . pos = 1 , . len = repstr_str_len } ) , sizeof ( struct pos_len ) ) ;
memcpy ( repstr_extra + 1 , & ( ( struct pos_len ) { . pos = 0 , . len = repstr_str_len } ) , sizeof ( struct pos_len ) ) ;
sortval - > value = field - > report_string = repstr ;
sortval - > items = repstr_extra ;
field - > sort_value = sortval ;
return 1 ;
2014-05-29 11:41:18 +04:00
}
libdm: report: enhance the way string list is stored internally
Before, we stored only the report string itself for a string list
in field->report_string. The field->report_string has either
sorted items or not, depending on what we need for a field -
some report fields have sorted output, some don't...
The field->sort_value.value then contains pointer to the exact
field->report_string. The field->sort_value.items ALWAYS keeps
sorted array of individual items, represented as '[position,length]'
pairs pointing to the field->sort_value.value string.
This approach was fine as far as we didn't need to apply further
formatting to field->report_string. However, if we need to apply
further formatting to field->report_string content, taking into
account individual items, we also need to know where each item
starts and what is its length. Before, we only knew this when
items in report string were sorted, but not in the unsorted version.
We can't rely on the delimiter (default ",") only to separate items
back out of report string, because that delimiter can be contained
in the item value itself.
So this patch enhances the field->report_string for a string list so
it also contains '[position,length]' pairs for each individual item
inside field->report_string. We store this array right beyond the
string itself and we encode it in the same manner we already did for
field->sort_value.items before.
If field->report_string has sorted items, the field->sort_value.items
just points to the array of items we store beyond the report string.
If field->report_string has unsorted items, we store separate array
of items for both field->report_string and field->sort_value.
This patch also cleans up the _report_field_string_list function a bit
so it's easier and more straightforward to follow than the original
version.
Example. If we have "abc", "xy", "defgh" as list on input with ","
as delimiter, then:
- field->report_string will have:
- if we need field->report_string unsorted:
abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- if we need field->report_string sorted:
repstr_extra
|
V
abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
|____________||________________________|
string array of [pos,len] pairs
|____||________________|
#items items
- field->sort_value will have:
- if field->report_string is unsorted:
field->sort_value.value = field->report_string
field->sort_value.items = {[0,3],[0,3],[7,5],[4,2]}
(that is 'abc,defgh,xy')
- if field->report_string is sorted already:
field->sort_value.value = field->report_string
field->sort_value.items = repstr_extra
(that is also 'abc,defgh,xy')
2022-06-28 18:00:00 +03:00
/* more than one item - allocate temporary array for string list items for further processing */
if ( ! ( arr = dm_malloc ( list_size * sizeof ( struct str_pos_len ) ) ) ) {
log_error ( " %s failed to allocate temporary array for processing " , _error_msg_prefix ) ;
2014-05-29 11:41:18 +04:00
goto out ;
}