/* Hierarchial argument parsing help output
- Copyright (C) 1995-2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1995-2005, 2007, 2009 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
- This program is free software; you can redistribute it and/or modify
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
int dup_args_note;
/* Various output columns. */
- int short_opt_col; /* column in which short options start */
- int long_opt_col; /* column in which long options start */
+ int short_opt_col; /* column in which short options start */
+ int long_opt_col; /* column in which long options start */
int doc_opt_col; /* column in which doc options start */
int opt_doc_col; /* column in which option text starts */
- int header_col; /* column in which group headers are printed */
+ int header_col; /* column in which group headers are printed */
int usage_indent; /* indentation of wrapped usage lines */
int rmargin; /* right margin used for wrapping */
{
const char *var = getenv ("ARGP_HELP_FMT");
struct uparams new_params = uparams;
-
-#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0);
+
+#define SKIPWS(p) do { while (isspace ((unsigned char) *p)) p++; } while (0);
if (var)
{
while (*var)
{
SKIPWS (var);
-
- if (isalpha (*var))
+
+ if (isalpha ((unsigned char) *var))
{
size_t var_len;
const struct uparam_name *un;
int unspec = 0, val = 0;
const char *arg = var;
- while (isalnum (*arg) || *arg == '-' || *arg == '_')
+ while (isalnum ((unsigned char) *arg) || *arg == '-' || *arg == '_')
arg++;
var_len = arg - var;
-
+
SKIPWS (arg);
-
+
if (*arg == '\0' || *arg == ',')
unspec = 1;
else if (*arg == '=')
arg++;
SKIPWS (arg);
}
-
+
if (unspec)
{
if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
else
val = 1;
}
- else if (isdigit (*arg))
+ else if (isdigit ((unsigned char) *arg))
{
val = atoi (arg);
- while (isdigit (*arg))
+ while (isdigit ((unsigned char) *arg))
arg++;
SKIPWS (arg);
}
-
+
for (un = uparam_names; un->name; un++)
if (strlen (un->name) == var_len
&& strncmp (var, un->name, var_len) == 0)
/* The argp from which this option came. */
const struct argp *argp;
+
+ /* Position in the array */
+ unsigned ord;
};
/* A cluster of entries to reflect the argp tree structure. */
}
\f
/* Iterator that returns true for the first short option. */
-static inline int
+static int
until_short (const struct argp_option *opt, const struct argp_option *real,
const char *domain, void *cookie)
{
hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2)
{
/* If one cluster is deeper than the other, use its ancestor at the same
- level, so that finding the common ancestor is straightforward. */
- while (cl1->depth < cl2->depth)
+ level, so that finding the common ancestor is straightforward.
+
+ clN->depth > 0 means that clN->parent != NULL (see hol_add_cluster) */
+ while (cl1->depth > cl2->depth)
cl1 = cl1->parent;
- while (cl2->depth < cl1->depth)
+ while (cl2->depth > cl1->depth)
cl2 = cl2->parent;
/* Now reduce both clusters to their ancestors at the point where both have
else
{
/* Skip initial whitespace. */
- while (isspace (**name))
+ while (isspace ((unsigned char) **name))
(*name)++;
/* Decide whether this looks like an option (leading `-') or not. */
non_opt = (**name != '-');
/* Skip until part of name used for sorting. */
- while (**name && !isalnum (**name))
+ while (**name && !isalnum ((unsigned char) **name))
(*name)++;
}
return non_opt;
}
+#define HOL_ENTRY_PTRCMP(a,b) ((a)->ord < (b)->ord ? -1 : 1)
+
/* Order ENTRY1 & ENTRY2 by the order which they should appear in a help
listing. */
static int
/* The group numbers by which the entries should be ordered; if either is
in a cluster, then this is just the group within the cluster. */
int group1 = entry1->group, group2 = entry2->group;
+ int rc;
if (entry1->cluster != entry2->cluster)
{
return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1);
else
/* Both entries are in clusters, we can just compare the clusters. */
- return hol_cluster_cmp (entry1->cluster, entry2->cluster);
+ return (rc = hol_cluster_cmp (entry1->cluster, entry2->cluster)) ?
+ rc : HOL_ENTRY_PTRCMP(entry1, entry2);
}
else if (group1 == group2)
/* The entries are both in the same cluster and group, so compare them
return doc1 - doc2;
else if (!short1 && !short2 && long1 && long2)
/* Only long options. */
- return __strcasecmp (long1, long2);
+ return (rc = __strcasecmp (long1, long2)) ?
+ rc : HOL_ENTRY_PTRCMP(entry1, entry2);
else
/* Compare short/short, long/short, short/long, using the first
character of long options. Entries without *any* valid
first, but as they're not displayed, it doesn't matter where
they are. */
{
- char first1 = short1 ? short1 : long1 ? *long1 : 0;
- char first2 = short2 ? short2 : long2 ? *long2 : 0;
-#ifdef _tolower
- int lower_cmp = _tolower (first1) - _tolower (first2);
-#else
+ unsigned char first1 = short1 ? short1 : long1 ? *long1 : 0;
+ unsigned char first2 = short2 ? short2 : long2 ? *long2 : 0;
+ /* Use tolower, not _tolower, since only the former is
+ guaranteed to work on something already lower case. */
int lower_cmp = tolower (first1) - tolower (first2);
-#endif
/* Compare ignoring case, except when the options are both the
same letter, in which case lower-case always comes first. */
- return lower_cmp ? lower_cmp : first2 - first1;
+ return lower_cmp ? lower_cmp :
+ (rc = first2 - first1) ?
+ rc : HOL_ENTRY_PTRCMP(entry1, entry2);
}
}
else
/* Within the same cluster, but not the same group, so just compare
groups. */
- return group_cmp (group1, group2, 0);
+ return group_cmp (group1, group2, HOL_ENTRY_PTRCMP(entry1, entry2));
}
/* Version of hol_entry_cmp with correct signature for qsort. */
hol_sort (struct hol *hol)
{
if (hol->num_entries > 0)
- qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry),
- hol_entry_qcmp);
+ {
+ unsigned i;
+ struct hol_entry *e;
+ for (i = 0, e = hol->entries; i < hol->num_entries; i++, e++)
+ e->ord = i;
+ qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry),
+ hol_entry_qcmp);
+ }
}
\f
/* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow