Fix option sorting.
* libmailutils/opt/opt.c (sort_group): Don't assume stability of the sort. Use auxiliary data structure to sort array of options that contain aliases. * libmailutils/tests/parseopt.c (set_prog_args): Fix delimiter. * libmailutils/tests/strtoc.c (v_cidr_format): Error checking. * maidag/Makefile.am (maidag_LDADD): Reorder libraries to make sure maidag uses freshly built libraries (not the ones already installed in the system). * mh/pick.c (options): Bugfix.
Showing
5 changed files
with
79 additions
and
19 deletions
... | @@ -29,6 +29,14 @@ | ... | @@ -29,6 +29,14 @@ |
29 | #define EXIT_SUCCESS 0 | 29 | #define EXIT_SUCCESS 0 |
30 | #define EXIT_ERROR 1 | 30 | #define EXIT_ERROR 1 |
31 | 31 | ||
32 | /* Option and its aliases form a contiguous array. Option slot is used | ||
33 | to preserve contiguity during sorting. */ | ||
34 | struct opt_slot | ||
35 | { | ||
36 | struct mu_option **opt; /* Points to the option */ | ||
37 | int count; /* Number of options in opt */ | ||
38 | }; | ||
39 | |||
32 | /* Compare pointers to two option structs */ | 40 | /* Compare pointers to two option structs */ |
33 | static int | 41 | static int |
34 | optcmp (const void *a, const void *b) | 42 | optcmp (const void *a, const void *b) |
... | @@ -36,11 +44,6 @@ optcmp (const void *a, const void *b) | ... | @@ -36,11 +44,6 @@ optcmp (const void *a, const void *b) |
36 | struct mu_option const *ap = *(struct mu_option const **)a; | 44 | struct mu_option const *ap = *(struct mu_option const **)a; |
37 | struct mu_option const *bp = *(struct mu_option const **)b; | 45 | struct mu_option const *bp = *(struct mu_option const **)b; |
38 | 46 | ||
39 | while (ap->opt_flags & MU_OPTION_ALIAS) | ||
40 | ap--; | ||
41 | while (bp->opt_flags & MU_OPTION_ALIAS) | ||
42 | bp--; | ||
43 | |||
44 | if (!MU_OPTION_IS_VALID_SHORT_OPTION (ap) | 47 | if (!MU_OPTION_IS_VALID_SHORT_OPTION (ap) |
45 | && MU_OPTION_IS_VALID_LONG_OPTION (ap) | 48 | && MU_OPTION_IS_VALID_LONG_OPTION (ap) |
46 | && !MU_OPTION_IS_VALID_SHORT_OPTION (bp) | 49 | && !MU_OPTION_IS_VALID_SHORT_OPTION (bp) |
... | @@ -60,18 +63,67 @@ optcmp (const void *a, const void *b) | ... | @@ -60,18 +63,67 @@ optcmp (const void *a, const void *b) |
60 | } | 63 | } |
61 | } | 64 | } |
62 | 65 | ||
66 | /* Compare pointers to two option slots */ | ||
67 | static int | ||
68 | slotcmp (const void *a, const void *b) | ||
69 | { | ||
70 | struct opt_slot const *ap = (struct opt_slot const *)a; | ||
71 | struct opt_slot const *bp = (struct opt_slot const *)b; | ||
72 | return optcmp (ap->opt, bp->opt); | ||
73 | } | ||
63 | /* Sort a group of options in OPTBUF, starting at index START (first | 74 | /* Sort a group of options in OPTBUF, starting at index START (first |
64 | option slot after a group header (if any). The group spans up to | 75 | option slot after a group header (if any). The group spans up to |
65 | next group header or end of options */ | 76 | next group header or end of options */ |
66 | static size_t | 77 | static size_t |
67 | sort_group (struct mu_option **optbuf, size_t start) | 78 | sort_group (struct mu_option **optbuf, size_t start) |
68 | { | 79 | { |
69 | size_t i; | 80 | size_t i, count = 0; |
70 | 81 | ||
82 | /* Make sure the first option in group is not an alias. */ | ||
83 | optbuf[start]->opt_flags &= ~MU_OPTION_ALIAS; | ||
71 | for (i = start; optbuf[i] && !MU_OPTION_IS_GROUP_HEADER (optbuf[i]); i++) | 84 | for (i = start; optbuf[i] && !MU_OPTION_IS_GROUP_HEADER (optbuf[i]); i++) |
72 | ; | 85 | { |
86 | if (!(optbuf[i]->opt_flags & MU_OPTION_ALIAS)) | ||
87 | count++; | ||
88 | } | ||
89 | if (count == i - start) | ||
90 | /* Inplace sort */ | ||
91 | qsort (&optbuf[start], count, sizeof (optbuf[0]), optcmp); | ||
92 | else | ||
93 | { | ||
94 | /* Option group contains aliases. Split it into option slots. */ | ||
95 | struct mu_option **tmp; | ||
96 | struct opt_slot *slots; | ||
97 | size_t j, k, l; | ||
98 | |||
99 | slots = mu_calloc (count, sizeof (slots[0])); | ||
100 | j = 0; | ||
101 | slots[0].opt = optbuf + start; | ||
102 | slots[0].count = 1; | ||
103 | for (k = start + 1; k < i; k++) | ||
104 | { | ||
105 | if (optbuf[k]->opt_flags & MU_OPTION_ALIAS) | ||
106 | slots[j].count++; | ||
107 | else | ||
108 | { | ||
109 | j++; | ||
110 | slots[j].opt = optbuf + k; | ||
111 | slots[j].count = 1; | ||
112 | } | ||
113 | } | ||
114 | /* Sort the slots */ | ||
115 | qsort (slots, count, sizeof (slots[0]), slotcmp); | ||
116 | /* Create ordered array of option pointers */ | ||
117 | tmp = mu_calloc (i - start, sizeof (tmp[0])); | ||
118 | for (k = l = 0; k < count; k++) | ||
119 | for (j = 0; j < slots[k].count; j++) | ||
120 | tmp[l++] = slots[k].opt[j]; | ||
121 | /* Copy ordered pointers back and free temporary memory */ | ||
122 | memcpy (optbuf + start, tmp, (i - start) * sizeof tmp[0]); | ||
123 | free (tmp); | ||
124 | free (slots); | ||
125 | } | ||
73 | 126 | ||
74 | qsort (&optbuf[start], i - start, sizeof (optbuf[0]), optcmp); | ||
75 | return i; | 127 | return i; |
76 | } | 128 | } |
77 | 129 | ||
... | @@ -648,9 +700,7 @@ parseopt_init (struct mu_parseopt *po, struct mu_option **options, | ... | @@ -648,9 +700,7 @@ parseopt_init (struct mu_parseopt *po, struct mu_option **options, |
648 | 700 | ||
649 | po->po_optv[j] = NULL; | 701 | po->po_optv[j] = NULL; |
650 | 702 | ||
651 | /* Ensure sane start of options. This is necessary, in particular, | 703 | /* Ensure sane start of options. */ |
652 | because optcmp backs up until it finds an element with cleared | ||
653 | MU_OPTION_ALIAS bit. */ | ||
654 | po->po_optv[0]->opt_flags &= ~MU_OPTION_ALIAS; | 704 | po->po_optv[0]->opt_flags &= ~MU_OPTION_ALIAS; |
655 | if (!(flags & MU_PARSEOPT_NO_SORT)) | 705 | if (!(flags & MU_PARSEOPT_NO_SORT)) |
656 | { | 706 | { | ... | ... |
... | @@ -90,7 +90,7 @@ set_prog_args (struct parseopt_param *param, char const *str, void *target) | ... | @@ -90,7 +90,7 @@ set_prog_args (struct parseopt_param *param, char const *str, void *target) |
90 | 90 | ||
91 | size = 1; | 91 | size = 1; |
92 | for (i = 0; str[i]; i++) | 92 | for (i = 0; str[i]; i++) |
93 | if (str[i] == '\n') | 93 | if (str[i] == '|') |
94 | size++; | 94 | size++; |
95 | 95 | ||
96 | args = mu_calloc (size + 1, sizeof (args[0])); | 96 | args = mu_calloc (size + 1, sizeof (args[0])); | ... | ... |
... | @@ -161,10 +161,17 @@ static void | ... | @@ -161,10 +161,17 @@ static void |
161 | v_cidr_format (union value *val, FILE *fp) | 161 | v_cidr_format (union value *val, FILE *fp) |
162 | { | 162 | { |
163 | char *buf; | 163 | char *buf; |
164 | 164 | int rc; | |
165 | mu_cidr_format (&val->v_cidr, 0, &buf); | 165 | rc = mu_cidr_format (&val->v_cidr, 0, &buf); |
166 | if (rc) | ||
167 | { | ||
168 | fprintf (fp, "(can't convert value: %s)", mu_strerror (rc)); | ||
169 | } | ||
170 | else | ||
171 | { | ||
166 | fprintf (fp, "%s", buf); | 172 | fprintf (fp, "%s", buf); |
167 | free (buf); | 173 | free (buf); |
174 | } | ||
168 | } | 175 | } |
169 | 176 | ||
170 | static int | 177 | static int |
... | @@ -259,6 +266,7 @@ struct testdata tests[] = { | ... | @@ -259,6 +266,7 @@ struct testdata tests[] = { |
259 | .len = 4, | 266 | .len = 4, |
260 | .address = { 127, 0, 0, 0 }, | 267 | .address = { 127, 0, 0, 0 }, |
261 | .netmask = { 255 } } } }, | 268 | .netmask = { 255 } } } }, |
269 | #ifdef MAILUTILS_IPV6 | ||
262 | { mu_c_cidr, "fe80::4a5b:39ff:fe09:97f0/64", 0, { .v_cidr = { | 270 | { mu_c_cidr, "fe80::4a5b:39ff:fe09:97f0/64", 0, { .v_cidr = { |
263 | .family = 10, | 271 | .family = 10, |
264 | .len = 16, | 272 | .len = 16, |
... | @@ -266,7 +274,7 @@ struct testdata tests[] = { | ... | @@ -266,7 +274,7 @@ struct testdata tests[] = { |
266 | 0x4a, 0x5b, 0x39, 0xff, 0xfe, 0x9, 0x97, 0xf0 }, | 274 | 0x4a, 0x5b, 0x39, 0xff, 0xfe, 0x9, 0x97, 0xf0 }, |
267 | .netmask = { 255, 255, 255, 255, 255, 255, 255, 255, | 275 | .netmask = { 255, 255, 255, 255, 255, 255, 255, 255, |
268 | 0, 0, 0, 0, 0, 0, 0, 0 } } } }, | 276 | 0, 0, 0, 0, 0, 0, 0, 0 } } } }, |
269 | 277 | #endif | |
270 | { mu_c_incr, NULL, 0, { .v_int = 1 } }, | 278 | { mu_c_incr, NULL, 0, { .v_int = 1 } }, |
271 | { mu_c_void } | 279 | { mu_c_void } |
272 | }; | 280 | }; | ... | ... |
... | @@ -33,9 +33,6 @@ endif | ... | @@ -33,9 +33,6 @@ endif |
33 | 33 | ||
34 | maidag_LDADD = \ | 34 | maidag_LDADD = \ |
35 | ../lib/libmuscript.a\ | 35 | ../lib/libmuscript.a\ |
36 | @LIBMU_SCM@ @GUILE_LIBS@\ | ||
37 | @LIBMU_SCM_DEPS@\ | ||
38 | @MU_LIB_PY@ @PYTHON_LIBS@\ | ||
39 | ${MU_APP_LIBRARIES}\ | 36 | ${MU_APP_LIBRARIES}\ |
40 | ${MU_LIB_SIEVE}\ | 37 | ${MU_LIB_SIEVE}\ |
41 | ${MU_LIB_MBOX}\ | 38 | ${MU_LIB_MBOX}\ |
... | @@ -49,7 +46,12 @@ maidag_LDADD = \ | ... | @@ -49,7 +46,12 @@ maidag_LDADD = \ |
49 | @MU_AUTHLIBS@\ | 46 | @MU_AUTHLIBS@\ |
50 | ${MU_LIB_MAILUTILS} \ | 47 | ${MU_LIB_MAILUTILS} \ |
51 | @MU_COMMON_LIBRARIES@\ | 48 | @MU_COMMON_LIBRARIES@\ |
49 | @LIBMU_SCM@\ | ||
50 | @LIBMU_SCM_DEPS@\ | ||
51 | @MU_LIB_PY@\ | ||
52 | $(LIBMU_DBM)\ | 52 | $(LIBMU_DBM)\ |
53 | @GUILE_LIBS@\ | ||
54 | @PYTHON_LIBS@\ | ||
53 | @DBMLIBS@\ | 55 | @DBMLIBS@\ |
54 | @MU_TCPWRAP_LIBRARIES@ | 56 | @MU_TCPWRAP_LIBRARIES@ |
55 | 57 | ... | ... |
... | @@ -192,7 +192,7 @@ static struct mu_option options[] = { | ... | @@ -192,7 +192,7 @@ static struct mu_option options[] = { |
192 | { ")", 0, NULL, MU_OPTION_ALIAS }, | 192 | { ")", 0, NULL, MU_OPTION_ALIAS }, |
193 | 193 | ||
194 | MU_OPTION_GROUP (N_("Operations over the selected messages")), | 194 | MU_OPTION_GROUP (N_("Operations over the selected messages")), |
195 | { "list", 0, NULL, MU_OPTION_ALIAS, | 195 | { "list", 0, NULL, MU_OPTION_DEFAULT, |
196 | N_("list the numbers of the selected messages (default)"), | 196 | N_("list the numbers of the selected messages (default)"), |
197 | mu_c_bool, &list }, | 197 | mu_c_bool, &list }, |
198 | { "sequence", 0, N_("NAME"), MU_OPTION_DEFAULT, | 198 | { "sequence", 0, N_("NAME"), MU_OPTION_DEFAULT, | ... | ... |
-
Please register or sign in to post a comment