Safer string to number conversion with ato*() -> safe_strto*().
authorW. Trevor King <wking@drexel.edu>
Thu, 13 Aug 2009 10:09:42 +0000 (06:09 -0400)
committerW. Trevor King <wking@drexel.edu>
Thu, 13 Aug 2009 11:24:49 +0000 (07:24 -0400)
Current hack to avoid including string.h for strlen() in every *.c
file that uses safe_strto*(), which I should fix when I pull them out
into utils.h/c files or similar.

.be/bugs/c41489cf-8225-42a5-adf5-ee6761e45bd8/comments/1cda0419-ce8c-452c-9aac-75b18f5ee4f3/body [new file with mode: 0644]
.be/bugs/c41489cf-8225-42a5-adf5-ee6761e45bd8/comments/1cda0419-ce8c-452c-9aac-75b18f5ee4f3/values [new file with mode: 0644]
.be/bugs/c41489cf-8225-42a5-adf5-ee6761e45bd8/values
src/sawsim.nw

diff --git a/.be/bugs/c41489cf-8225-42a5-adf5-ee6761e45bd8/comments/1cda0419-ce8c-452c-9aac-75b18f5ee4f3/body b/.be/bugs/c41489cf-8225-42a5-adf5-ee6761e45bd8/comments/1cda0419-ce8c-452c-9aac-75b18f5ee4f3/body
new file mode 100644 (file)
index 0000000..a459f86
--- /dev/null
@@ -0,0 +1,8 @@
+Fixed in the ato*() -> safe_strto*() transition.
+Now the error message looks like:
+
+$ bin/sawsim -v1 -s A,null -N -s B,null -k A,B,const,1
+Error: unparsable '-s' while parsing '-s' for -N
+sawsim: build/sawsim.c:720: safe_strtoi: Assertion `endp == ((void *)0)' failed.
+Aborted
+
diff --git a/.be/bugs/c41489cf-8225-42a5-adf5-ee6761e45bd8/comments/1cda0419-ce8c-452c-9aac-75b18f5ee4f3/values b/.be/bugs/c41489cf-8225-42a5-adf5-ee6761e45bd8/comments/1cda0419-ce8c-452c-9aac-75b18f5ee4f3/values
new file mode 100644 (file)
index 0000000..ade20bc
--- /dev/null
@@ -0,0 +1,11 @@
+Author: W. Trevor King <wking@drexel.edu>
+
+
+Content-type: text/plain
+
+
+Date: Thu, 13 Aug 2009 10:08:57 +0000
+
+
+In-reply-to: 0aca6729-b1ed-4eeb-9347-28dcee29b588
+
index ced2a81e0c6ae029f26daa41520a1f4c6fb640f5..4d60cd74d458f736d964266630a4495d9df6c2a2 100644 (file)
@@ -7,7 +7,7 @@ reporter: W. Trevor King <wking@drexel.edu>
 severity: minor
 
 
-status: open
+status: fixed
 
 
 summary: list_element fails when -N eats s argument...
index 1132a9fa5b67afeeeb71dbd48191ff4f6f7562c1..be36e715a1dfa0d57056f53556684e8b8301fbd3 100644 (file)
@@ -899,6 +899,7 @@ void help(char *prog_name, double P, double t_max, double dt_max, double v, doub
 \label{sec.get_options}
 
 <<get options>>=
+<<safe strto*>>
 void get_options(int argc, char **argv,
                  double *pP, double *pT_max, double *pDt_max, double *pV,
                 double *pX_step, state_t **pStop_state, environment_t *env,
@@ -959,13 +960,13 @@ void get_options(int argc, char **argv,
         }
       }
       break;
-    case 't':  *pT_max  = atof(optarg);           break;
-    case 'd':  *pDt_max = atof(optarg);           break;
-    case 'P':  *pP      = atof(optarg);           break;
-    case 'v':  *pV      = atof(optarg);           break;
-    case 'x':  *pX_step = atof(optarg);           break;
-    case 'T':  env->T   = atof(optarg);           break;
-    case 'C':  env->T   = atof(optarg)+273.15;    break;
+    case 't':  *pT_max  = safe_strtod(optarg, "-t");         break;
+    case 'd':  *pDt_max = safe_strtod(optarg, "-d");         break;
+    case 'P':  *pP      = safe_strtod(optarg, "-P");         break;
+    case 'v':  *pV      = safe_strtod(optarg, "-v");         break;
+    case 'x':  *pX_step = safe_strtod(optarg, "-x");         break;
+    case 'T':  env->T   = safe_strtod(optarg, "-T");         break;
+    case 'C':  env->T   = safe_strtod(optarg, "-C")+273.15;  break;
     case 's':
       parse_list_string(optarg, SEP, '{', '}', &num_strings, &strings);
       assert(num_strings >= 2 && num_strings <= 4);
@@ -977,7 +978,7 @@ void get_options(int argc, char **argv,
       }
       tension_model = index_tension_model(n_tension_models, tension_models, strings[1]);
       if (num_strings == 4)
-        tension_group = atoi(strings[2]);
+        tension_group = safe_strtoi(strings[2], optarg);
       else
         tension_group = 0;
       if (num_strings >= 3)
@@ -998,7 +999,7 @@ void get_options(int argc, char **argv,
       free_parsed_list(num_strings, strings);
       break;
     case 'N':
-      n = atoi(optarg);
+      n = safe_strtoi(optarg, "-N");
 #ifdef DEBUG
       fprintf(stderr, "%s:\tadding %d domains to %s\n", __FUNCTION__, n, S(*pState_list)->name);
 #endif
@@ -1109,6 +1110,47 @@ int index_k_model(int n_models, k_model_getopt_t *models, char *name)
   } while (0);
 @
 
+First we define some safe string parsing functions.  Currently these
+abort on any irregularity, but in the future they could print error
+messages, etc.  [[static]] because the functions are currently
+defined in each [[*.c]] file that uses them, but perhaps they should
+be moved to [[utils.h/c]] or some such instead\ldots
+
+<<safe strto*>>=
+static int safe_strtoi(const char *s, const char *description) {
+  char *endp = NULL;
+  long int ret;
+  assert(s != NULL);
+  ret = strtol(s, &endp, 10);
+  if (endp[0] != '\0') { //strlen(endp) > 0) {
+    fprintf(stderr, "Error: unparsable '%s' while parsing '%s' for %s\n",
+            endp, s, description);
+    assert(1==0);  //strlen(endp) == 0);
+  } else if (errno == ERANGE) {
+    fprintf(stderr, "Error: '%s' out of range for %s\n", s, description);
+    assert(errno != ERANGE);
+  }
+  return (int) ret;
+}
+
+static double safe_strtod(const char *s, const char *description) {
+  char *endp = NULL;
+  double ret;
+  assert(s != NULL);
+  ret = strtod(s, &endp);
+  if (endp[0] != '\0') { //strlen(endp) > 0) {
+    fprintf(stderr, "Error: unparsable '%s' while parsing '%s' for %s\n",
+            endp, s, description);
+    assert(1==0);  //strlen(endp) == 0);
+  } else if (errno == ERANGE) {
+    fprintf(stderr, "Error: '%s' out of range for %s\n", s, description);
+    assert(errno != ERANGE);
+  }
+  return ret;
+}
+
+@
+
 \phantomsection
 \appendix
 \addcontentsline{toc}{section}{Appendicies}
@@ -1131,12 +1173,13 @@ The general layout of our simulation code is:
 We include [[math.h]], so don't forget to link to the libm with `-lm'.
 <<includes>>=
 #include <assert.h> /* assert()                                */
-#include <stdlib.h> /* malloc(), free(), rand()                */
+#include <stdlib.h> /* malloc(), free(), rand(), strto*()      */
 #include <stdio.h>  /* fprintf(), stdout                       */
 #include <string.h> /* strlen, strtok()                        */
 #include <math.h>   /* exp(), M_PI, sqrt()                     */
 #include <sys/types.h> /* pid_t (returned by getpid())         */
 #include <unistd.h> /* getpid() (for seeding rand()), getopt() */
+#include <errno.h>  /* errno, ERANGE (for safe_strto*())       */
 #include "global.h"
 #include "list.h"
 #include "tension_balance.h"
@@ -1916,10 +1959,10 @@ Here we check to make sure the various functions work as expected, using \citeta
 @
 
 <<parse check includes>>=
-#include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE, atof() */
-#include <stdio.h>  /* printf()                              */
-#include <assert.h> /* assert()                              */
-#include <string.h> /* strlen()                              */
+#include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE */
+#include <stdio.h>  /* printf()                      */
+#include <assert.h> /* assert()                      */
+#include <string.h> /* strlen()                      */
 <<check includes>>
 #include "parse.h"
 @
@@ -3398,11 +3441,11 @@ Here we check to make sure the various functions work as expected, using \citeta
 @
 
 <<string eval check includes>>=
-#include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE, atof() */
-#include <stdio.h>  /* printf()                              */
-#include <assert.h> /* assert()                              */
-#include <string.h> /* strlen()                              */
-#include <signal.h> /* SIGKILL                               */
+#include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE */
+#include <stdio.h>  /* printf()                      */
+#include <assert.h> /* assert()                      */
+#include <string.h> /* strlen()                      */
+#include <signal.h> /* SIGKILL                       */
 <<check includes>>
 #include "string_eval.h"
 @
@@ -3720,7 +3763,8 @@ const_tension_param_t *create_const_tension_param_t(double F)
 
 void *string_create_const_tension_param_t(char **param_strings)
 {
-  return create_const_tension_param_t(atof(param_strings[0]));
+  return create_const_tension_param_t(
+      safe_strtod(param_strings[0],__FUNCTION__));
 }
 
 void destroy_const_tension_param_t(void *p)
@@ -3858,7 +3902,7 @@ hooke_param_t *create_hooke_param_t(double k)
 
 void *string_create_hooke_param_t(char **param_strings)
 {
-  return create_hooke_param_t(atof(param_strings[0]));
+  return create_hooke_param_t(safe_strtod(param_strings[0], __FUNCTION__));
 }
 
 void destroy_hooke_param_t(void *p)
@@ -4093,7 +4137,8 @@ wlc_param_t *create_wlc_param_t(double p, double L)
 
 void *string_create_wlc_param_t(char **param_strings)
 {
-  return create_wlc_param_t(atof(param_strings[0]), atof(param_strings[1]));
+  return create_wlc_param_t(safe_strtod(param_strings[0], __FUNCTION__),
+                            safe_strtod(param_strings[1], __FUNCTION__));
 }
 
 void destroy_wlc_param_t(void *p /* wlc_param_t * */)
@@ -4235,7 +4280,8 @@ fjc_param_t *create_fjc_param_t(double l, double N)
 
 void *string_create_fjc_param_t(char **param_strings)
 {
-  return create_fjc_param_t(atof(param_strings[0]), atof(param_strings[1]));
+  return create_fjc_param_t(safe_strtod(param_strings[0], __FUNCTION__),
+                            safe_strtod(param_strings[1], __FUNCTION__));
 }
 
 void destroy_fjc_param_t(void *p)
@@ -4275,9 +4321,10 @@ char fjc_param_string[]="0.5e-9,200";
 
 <<tension model includes>>=
 #include <assert.h> /* assert()                */
-#include <stdlib.h> /* NULL                    */
+#include <stdlib.h> /* NULL, strto*()          */
 #include <math.h>   /* HUGE_VAL, sqrt(), exp() */
 #include <stdio.h>  /* fprintf(), stdout       */
+#include <errno.h>  /* errno, ERANGE           */
 #include "global.h"
 #include "list.h"
 #include "tension_balance.h" /* oneD_*() */
@@ -4299,6 +4346,7 @@ char fjc_param_string[]="0.5e-9,200";
 @
 
 <<tension model functions>>=
+<<safe strto*>>
 <<constant tension functions>>
 <<hooke functions>>
 <<worm-like chain functions>>
@@ -4381,8 +4429,9 @@ int main(int argc, char **argv)
 <<tension model utility includes>>=
 #include <stdlib.h>
 #include <stdio.h>
-#include <string.h> /* strlen() */
-#include <assert.h> /* assert() */
+#include <string.h> /* strlen()      */
+#include <assert.h> /* assert()      */
+#include <errno.h>  /* errno, ERANGE */
 #include "global.h"
 #include "parse.h"
 #include "list.h"
@@ -4399,6 +4448,7 @@ int main(int argc, char **argv)
 @
 
 <<tension model utility getopt functions>>=
+<<safe strto*>>
 <<index tension model>>
 <<tension model utility help>>
 <<tension model utility get options>>
@@ -4459,16 +4509,16 @@ void get_options(int argc, char **argv, environment_t *env,
   /* setup defaults */
 
   prog_name = argv[0];
-  env->T = 300.0;   /* K           */
-  *Fmax = 1e5;
-  *Xmax = 1e-6;
+  env->T = 300.0;   /* K */
+  *Fmax = 1e5;      /* N */
+  *Xmax = 1e-6;     /* m */
   *flags = 0;
   *model = tension_models;
 
   while ((c=getopt(argc, argv, options)) != -1) {
     switch(c) {
-    case 'T':  env->T   = atof(optarg);           break;
-    case 'C':  env->T   = atof(optarg)+273.15;    break;
+    case 'T':  env->T   = safe_strtod(optarg, "-T");         break;
+    case 'C':  env->T   = safe_strtod(optarg, "-C")+273.15;  break;
     case 'm':
       tension_model = index_tension_model(n_tension_models, tension_models, optarg);
       *model = tension_models+tension_model;
@@ -4476,9 +4526,9 @@ void get_options(int argc, char **argv, environment_t *env,
     case 'a':
       tension_models[tension_model].params = optarg;
       break;
-    case 'F': *Fmax = atof(optarg); break;
-    case 'X': *Xmax = atof(optarg); break;
-    case 'V': *flags |= VFLAG;      break;
+    case 'F': *Fmax = safe_strtod(optarg, "-F"); break;
+    case 'X': *Xmax = safe_strtod(optarg, "-X"); break;
+    case 'V': *flags |= VFLAG;                   break;
     case '?':
       fprintf(stderr, "unrecognized option '%c'\n", optopt);
       /* fall through to default case */
@@ -4621,7 +4671,7 @@ const_k_param_t *create_const_k_param_t(double knot)
 
 void *string_create_const_k_param_t(char **param_strings)
 {
-  return create_const_k_param_t(atof(param_strings[0]));
+  return create_const_k_param_t(safe_strtod(param_strings[0], __FUNCTION__));
 }
 
 void destroy_const_k_param_t(void *p /* const_k_param_t * */)
@@ -4717,7 +4767,8 @@ bell_param_t *create_bell_param_t(double knot, double dx)
 
 void *string_create_bell_param_t(char **param_strings)
 {
-  return create_bell_param_t(atof(param_strings[0]), atof(param_strings[1]));
+  return create_bell_param_t(safe_strtod(param_strings[0], __FUNCTION__),
+                             safe_strtod(param_strings[1], __FUNCTION__));
 }
 
 void destroy_bell_param_t(void *p /* bell_param_t * */)
@@ -4817,7 +4868,8 @@ kbell_param_t *create_kbell_param_t(double knot, double dx)
 
 void *string_create_kbell_param_t(char **param_strings)
 {
-  return create_kbell_param_t(atof(param_strings[0]), atof(param_strings[1]));
+  return create_kbell_param_t(safe_strtod(param_strings[0], __FUNCTION__),
+                              safe_strtod(param_strings[1], __FUNCTION__));
 }
 
 void destroy_kbell_param_t(void *p /* kbell_param_t * */)
@@ -4922,7 +4974,7 @@ double kramers_x_fn(FILE *in, FILE *out, char *fn, double F, double T)
   fprintf(in, "F = %g; T = %g\n", F, T);
   sprintf(input, "print repr(%s)\n", fn); /* repr() to keep full precision */
   string_eval(in, out, input, 80, output);
-  return atof(output);
+  return safe_strtod(output, __FUNCTION__);
 }
 
 double kramers_E_fn(FILE *in, FILE *out, char *fn, double F, double T, double x)
@@ -4933,7 +4985,7 @@ double kramers_E_fn(FILE *in, FILE *out, char *fn, double F, double T, double x)
   fprintf(in, "F = %g;T = %g;x = %g\n", F, T, x);
   sprintf(input, "print repr(%s)\n", fn); /* repr() to keep full precision */
   string_eval(in, out, input, 80, output);
-  return atof(output);
+  return safe_strtod(output, __FUNCTION__);
 }
 
 double kramers_E(double F, environment_t *env, void *kramers_params, double x)
@@ -5010,7 +5062,7 @@ kramers_param_t *create_kramers_param_t(double D,
 /* takes an array of 4 functions: {"(1,2),(2,0),..."} */
 void *string_create_kramers_param_t(char **param_strings)
 {
-  return create_kramers_param_t(atof(param_strings[0]),
+  return create_kramers_param_t(safe_strtod(param_strings[0], __FUNCTION__),
                                param_strings[2],
                                param_strings[3],
                                param_strings[4],
@@ -5247,11 +5299,11 @@ void *string_create_kramers_integ_param_t(char **param_strings)
   //printf("create kramers integ.  D: %s, knots: %s, x in [%s, %s]\n",
   //       param_strings[0],param_strings[1],param_strings[2],param_strings[3]);
   void *E_params = string_create_spline_param_t(param_strings+1);
-  return create_kramers_integ_param_t(atof(param_strings[0]),
-                                      atof(param_strings[2]),
-                                      atof(param_strings[3]),
-                                     &spline_eval, E_params,
-                                     destroy_spline_param_t);
+  return create_kramers_integ_param_t(
+      safe_strtod(param_strings[0], __FUNCTION__),
+      safe_strtod(param_strings[2], __FUNCTION__),
+      safe_strtod(param_strings[3], __FUNCTION__),
+      &spline_eval, E_params, destroy_spline_param_t);
 }
 
 void destroy_kramers_integ_param_t(void *params)
@@ -5373,11 +5425,12 @@ Initialized with Titin I27 parameters\citep{carrion-vazquez99b}.
 @
 
 <<k model includes>>=
-#include <assert.h> /* assert()                */
-#include <stdlib.h> /* NULL, malloc()          */
-#include <math.h>   /* HUGE_VAL, sqrt(), exp() */
-#include <stdio.h>  /* fprintf(), stdout       */
-#include <string.h> /* strlen(), strcpy()      */
+#include <assert.h> /* assert()                 */
+#include <stdlib.h> /* NULL, malloc(), strto*() */
+#include <math.h>   /* HUGE_VAL, sqrt(), exp()  */
+#include <stdio.h>  /* fprintf(), stdout        */
+#include <string.h> /* strlen(), strcpy()       */
+#include <errno.h>  /* errno, ERANGE            */
 #include <gsl/gsl_integration.h>
 #include <gsl/gsl_spline.h>
 #include "global.h"
@@ -5403,6 +5456,7 @@ Initialized with Titin I27 parameters\citep{carrion-vazquez99b}.
 @
 
 <<k model functions>>=
+<<safe strto*>>
 <<null k functions>>
 <<const k functions>>
 <<bell k functions>>
@@ -5423,16 +5477,18 @@ Here we check to make sure the various functions work as expected, using \citeta
 @
 
 <<k model check includes>>=
-#include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE, atof() */
-#include <stdio.h>  /* sprintf()                             */
-#include <assert.h> /* assert()                              */
-#include <math.h>   /* exp()                                 */
+#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
+#include <stdio.h>  /* sprintf()                  */
+#include <assert.h> /* assert()                   */
+#include <math.h>   /* exp()                      */
+#include <errno.h>  /* errno, ERANGE              */
 <<check includes>>
 #include "global.h"
 #include "k_model.h"
 @
 
 <<k model test suite>>=
+<<safe strto*>>
 <<const k tests>>
 <<bell k tests>>
 <<k model suite definition>>
@@ -5493,7 +5549,7 @@ START_TEST(test_const_k_over_range)
     params[0] = knot[i];
     p = string_create_const_k_param_t(params);
     for ( F=Fm; F<FM; F+=dF ) {
-      fail_unless(const_k(F, &env, p)==atof(knot[i]),
+      fail_unless(const_k(F, &env, p)==safe_strtod(knot[i], __FUNCTION__),
           "const_k(%g, %g, &{%s}) = %g != %s",
           F, T, knot[i], const_k(F, &env, p), knot[i]);
     }
@@ -5546,7 +5602,7 @@ START_TEST(test_bell_k_at_zero)
   for( i=0; i < sizeof(knot)/sizeof(char *); i++) {
     params[0] = knot[i];
     p = string_create_bell_param_t(params);
-    fail_unless(bell_k(F, &env, p)==atof(knot[i]),
+    fail_unless(bell_k(F, &env, p)==safe_strtod(knot[i], __FUNCTION__),
                 "bell_k(%g, %g, &{%s,%s}) = %g != %s",
                 F, T, knot[i], dx, bell_k(F, &env, p), knot[i]);
     destroy_bell_param_t(p);
@@ -5560,7 +5616,7 @@ START_TEST(test_bell_k_at_one)
   char *knot[] = {"1","2","3","4","5","6"};
   char *dx="1";
   char *params[] = {knot[0], dx};
-  double F= k_B*T/atof(dx);
+  double F= k_B*T/safe_strtod(dx, __FUNCTION__);
   void *p = NULL;
   environment_t env;
   char param_string[80];
@@ -5569,10 +5625,10 @@ START_TEST(test_bell_k_at_one)
   for( i=0; i < sizeof(knot)/sizeof(char *); i++) {
     params[0] = knot[i];
     p = string_create_bell_param_t(params);
-    CHECK_ERR(1e-6, atof(knot[i])*exp(1.0), bell_k(F, &env, p));
-    //fail_unless(bell_k(F, &env, p)==atof(knot[i])*exp(1.0),
+    CHECK_ERR(1e-6, safe_strtod(knot[i], __FUNCTION__)*exp(1.0), bell_k(F, &env, p));
+    //fail_unless(bell_k(F, &env, p)==safe_strtod(knot[i], __FUNCTION__)*exp(1.0),
     //            "bell_k(%g, %g, &{%s,%s}) = %g != %g",
-    //            F, T, knot[i], dx, bell_k(F, &env, p), atof(knot[i])*exp(1.0));
+    //            F, T, knot[i], dx, bell_k(F, &env, p), safe_strtod(knot[i], __FUNCTION__)*exp(1.0));
     destroy_bell_param_t(p);
   }
 }
@@ -5710,8 +5766,9 @@ double multi_model_E(k_func_t *k, void *model_params, environment_t *env, double
 <<k model utility includes>>=
 #include <stdlib.h>
 #include <stdio.h>
-#include <string.h> /* strlen() */
-#include <assert.h> /* assert() */
+#include <string.h> /* strlen()      */
+#include <assert.h> /* assert()      */
+#include <errno.h>  /* errno, ERANGE */
 #include "global.h"
 #include "parse.h"
 #include "string_eval.h"
@@ -5731,6 +5788,7 @@ enum mode_t {M_K_OF_F, M_SPECIAL};
 @
 
 <<k model utility getopt functions>>=
+<<safe strto*>>
 <<index k model>>
 <<k model utility help>>
 <<k model utility get options>>
@@ -5800,18 +5858,18 @@ void get_options(int argc, char **argv, environment_t *env,
   /* setup defaults */
 
   prog_name = argv[0];
-  env->T = 300.0;   /* K           */
+  env->T = 300.0;   /* K */
   *mode = M_K_OF_F;
   *flags = 0;
   *model = k_models;
-  *Fmax = 1e-9;
+  *Fmax = 1e-9;     /* N */
   *special_xmax = 1e-8;
   *special_xmin = 0.0;
 
   while ((c=getopt(argc, argv, options)) != -1) {
     switch(c) {
-    case 'T':  env->T   = atof(optarg);           break;
-    case 'C':  env->T   = atof(optarg)+273.15;    break;
+    case 'T':  env->T   = safe_strtod(optarg, "-T");         break;
+    case 'C':  env->T   = safe_strtod(optarg, "-C")+273.15;  break;
     case 'k':
       k_model = index_k_model(n_k_models, k_models, optarg);
       *model = k_models+k_model;
@@ -5819,12 +5877,12 @@ void get_options(int argc, char **argv, environment_t *env,
     case 'K':
       k_models[k_model].params = optarg;
       break;
-    case 'm': *mode = M_K_OF_F;             break;
-    case 'M': *mode = M_SPECIAL;            break;
-    case 'F': *Fmax = atof(optarg);         break;
-    case 'x': *special_xmin = atof(optarg); break;
-    case 'X': *special_xmax = atof(optarg); break;
-    case 'V': *flags |= VFLAG;              break;
+    case 'm': *mode = M_K_OF_F;                          break;
+    case 'M': *mode = M_SPECIAL;                         break;
+    case 'F': *Fmax = safe_strtod(optarg, "-F");         break;
+    case 'x': *special_xmin = safe_strtod(optarg, "-x"); break;
+    case 'X': *special_xmax = safe_strtod(optarg, "-X"); break;
+    case 'V': *flags |= VFLAG;                           break;
     case '?':
       fprintf(stderr, "unrecognized option '%c'\n", optopt);
       /* fall through to default case */