]> granicus.if.org Git - procps-ng/commitdiff
top: tweak argument parsing for some locale situations
authorJim Warner <james.warner@comcast.net>
Wed, 25 Jun 2014 05:00:00 +0000 (00:00 -0500)
committerJaromir Capik <jcapik@redhat.com>
Wed, 25 Jun 2014 11:58:31 +0000 (13:58 +0200)
Boy I hate locale stuff. For code I thought was pretty
robust, Jaromir sure proved that it wasn't. Anyway, me
thinks this commit closes some gaps and will cause top
to behave appropriately under various locale settings.

It does *not* permit top to respond to the ',' and '.'
floating point separator without regard to the locale.
It does, however, enforce proper LC_NUMERIC responses.

Let's look on this commit as an interim solution until
Jaromir can create that proposed 'fp_decode' function.
Who knows, he might even borrow some of our mkfloat().

[ An aside: the coreutils sleep and timeout programs ]
[ claim to permit floating point arguments. However, ]
[ neither one will accept the comma separator should ]
[ the locale be a country that in fact uses a comma. ]

[ In other words, with this commit we are way ahead! ]

Reference(s):
http://www.freelists.org/post/procps/topwatch-floating-point-input
http://www.freelists.org/post/procps/topwatch-floating-point-input,1

Signed-off-by: Jim Warner <james.warner@comcast.net>
top/top.c
top/top.h
top/top_nls.c

index f0369bc43b4f2ac3920f3c91286fd2391d2de0e9..3fb7a4d797adc65de6aba27056783a0056a1ab73 100644 (file)
--- a/top/top.c
+++ b/top/top.c
@@ -1349,6 +1349,21 @@ static inline const char *hex_make (KLONG num, int noz) {
 } // end: hex_make
 
 
+        /*
+         * Make locale aware float (but maybe restrict to whole numbers). */
+static int mkfloat (const char *str, float *num, int whole) {
+   char *ep;
+
+   if (whole)
+      *num = (float)strtol(str, &ep, 0);
+   else
+      *num = strtof(str, &ep);
+   if (ep != str && *ep == '\0' && *num < MAXINT)
+      return 1;
+   return 0;
+} // end: mkfloat
+
+
         /*
          * This sructure is hung from a WIN_t when other filtering is active */
 struct osel_s {
@@ -3640,7 +3655,6 @@ static void parse_args (char **args) {
       .  we tolerate NO whitespace and NO switches -- maybe too tolerant? */
    static const char numbs_str[] = "+,-.0123456789";
    float tmp_delay = MAXFLOAT;
-   char *p;
    int i;
 
    while (*args) {
@@ -3648,6 +3662,8 @@ static void parse_args (char **args) {
 
       while (*cp) {
          char ch;
+         float tmp;
+
          switch ((ch = *cp)) {
             case '\0':
                break;
@@ -3668,9 +3684,10 @@ static void parse_args (char **args) {
                if (cp[1]) ++cp;
                else if (*args) cp = *args++;
                else error_exit(fmtmk(N_fmt(MISSING_args_fmt), ch));
-                  /* a negative delay will be dealt with shortly... */
-               if (1 != sscanf(cp, "%f", &tmp_delay))
+               if (!mkfloat(cp, &tmp_delay, 0))
                   error_exit(fmtmk(N_fmt(BAD_delayint_fmt), cp));
+               if (0 > tmp_delay)
+                  error_exit(N_txt(DELAY_badarg_txt));
                break;
             case 'H':
                Thread_mode = 1;
@@ -3688,8 +3705,9 @@ static void parse_args (char **args) {
                if (cp[1]) cp++;
                else if (*args) cp = *args++;
                else error_exit(fmtmk(N_fmt(MISSING_args_fmt), ch));
-               if (1 != sscanf(cp, "%d", &Loops) || 1 > Loops)
+               if (!mkfloat(cp, &tmp, 1) || 1.0 > tmp)
                   error_exit(fmtmk(N_fmt(BAD_niterate_fmt), cp));
+               Loops = (int)tmp;
                break;
             case 'o':
                if (cp[1]) cp++;
@@ -3709,15 +3727,18 @@ static void parse_args (char **args) {
                for (i = 0; i < EU_MAXPFLGS; i++)
                   puts(N_col(i));
                bye_bye(NULL);
-            case 'p':
+            case 'p': {
+               int pid; char *p;
                if (Curwin->usrseltyp) error_exit(N_txt(SELECT_clash_txt));
-               do { int pid;
+               do {
                   if (cp[1]) cp++;
                   else if (*args) cp = *args++;
                   else error_exit(fmtmk(N_fmt(MISSING_args_fmt), ch));
                   if (Monpidsidx >= MONPIDMAX)
                      error_exit(fmtmk(N_fmt(LIMIT_exceed_fmt), MONPIDMAX));
-                  if (1 != sscanf(cp, "%d", &pid) || 0 > pid)
+                  if (1 != sscanf(cp, "%d", &pid)
+                  || strpbrk(cp, "+-.")
+                  || 0 > pid)
                      error_exit(fmtmk(N_fmt(BAD_mon_pids_fmt), cp));
                   if (!pid) pid = getpid();
                   for (i = 0; i < Monpidsidx; i++)
@@ -3727,7 +3748,7 @@ static void parse_args (char **args) {
                   if (!(p = strchr(cp, ','))) break;
                   cp = p;
                } while (*cp);
-               break;
+            }  break;
             case 's':
                Secure_mode = 1;
                break;
@@ -3751,15 +3772,14 @@ static void parse_args (char **args) {
                Width_mode = -1;
                if (cp[1]) pn = &cp[1];
                else if (*args) { pn = *args; ai = 1; }
-               if (pn && !(ci = strspn(pn, "0123456789"))) { ai = 0; pn = NULL; }
-               if (pn && (1 != sscanf(pn, "%d", &Width_mode)
-               || Width_mode < W_MIN_COL))
-                  error_exit(fmtmk(N_fmt(BAD_widtharg_fmt), pn, W_MIN_COL-1));
+               if (pn && !(ci = strspn(pn, numbs_str))) { ai = 0; pn = NULL; }
+               if (pn && (!mkfloat(pn, &tmp, 1) || tmp < W_MIN_COL))
+                  error_exit(fmtmk(N_fmt(BAD_widtharg_fmt), pn));
+               Width_mode = (int)tmp;
                cp++;
                args += ai;
                if (pn) cp = pn + ci;
-               continue;
-            }
+            }  continue;
             default :
                error_exit(fmtmk(N_fmt(UNKNOWN_opts_fmt)
                   , *cp, Myname, N_txt(USAGE_abbrev_txt)));
@@ -3776,8 +3796,6 @@ static void parse_args (char **args) {
    if (MAXFLOAT > tmp_delay) {
       if (Secure_mode)
          error_exit(N_txt(DELAY_secure_txt));
-      if (0 > tmp_delay)
-         error_exit(N_txt(DELAY_badarg_txt));
       Rc.delay_time = tmp_delay;
    }
 } // end: parse_args
index 6f55b7ee7d2df1d8c4606459aea91edfb56468f7..b1fe2bc783b3798fa52475d0b78c9f78072e2369 100644 (file)
--- a/top/top.h
+++ b/top/top.h
@@ -682,6 +682,7 @@ typedef struct WIN_t {
 //atic float         get_float (const char *prompt);
 //atic int           get_int (const char *prompt);
 //atic inline const char *hex_make (KLONG num, int noz);
+//atic int           mkfloat (const char *str, float *num, int whole);
 //atic void          osel_clear (WIN_t *q);
 //atic inline int    osel_matched (const WIN_t *q, FLG_t enu, const char *str);
 //atic const char   *user_certify (WIN_t *q, const char *str, char typ);
index 01dd968ea803f946ef25a860729858a3f9299b53..1ef1000def03f5a11249bd150f07de00146d2433 100644 (file)
@@ -312,7 +312,7 @@ static void build_norm_nlstab (void) {
    Norm_nlstab[LIMIT_exceed_fmt] = _("pid limit (%d) exceeded");
    Norm_nlstab[BAD_mon_pids_fmt] = _("bad pid '%s'");
    Norm_nlstab[MISSING_args_fmt] = _("-%c requires argument");
-   Norm_nlstab[BAD_widtharg_fmt] = _("bad width arg '%s', must > %d");
+   Norm_nlstab[BAD_widtharg_fmt] = _("bad width arg '%s'");
    Norm_nlstab[UNKNOWN_opts_fmt] = _(""
       "unknown option '%c'\n"
       "Usage:\n  %s%s");