Commit fd19deb4 fd19deb4391f18e1a752ae5cfe4a9d3155e97705 by Sergey Poznyakoff

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.
1 parent e8f82804
...@@ -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 {
73 86 if (!(optbuf[i]->opt_flags & MU_OPTION_ALIAS))
74 qsort (&optbuf[start], i - start, sizeof (optbuf[0]), optcmp); 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 }
126
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 fprintf (fp, "%s", buf); 166 if (rc)
167 free (buf); 167 {
168 fprintf (fp, "(can't convert value: %s)", mu_strerror (rc));
169 }
170 else
171 {
172 fprintf (fp, "%s", 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,
......