检查main中的字符串是否为有效的float

时间:2016-09-23 18:51:30

标签: c

我目前有以下代码。但是,如果输入3.1?43之类的东西,它仍然被标记为浮动。我知道我之后没有正确检查。但我不确定如何检查。

int floatNum(char *s) {
    char *ptr = s;
    char *ep = NULL;
    long i = strtol(s, &ep, 0);

    //check if converted to long int
    if (!*ep) {
        return false;
    }

    //Check if char 
    if (*ep == 'e' || *ep == 'E' || *ep == '.') {
        return true;
    }

    return false;
}

谢谢你,这是我的解决方案。由于我的项目设置方式,我只希望它返回true,如果它是一个有效的浮点数,否则为假。

int floatNum(char *s) {
    const char *ptr = s;
    double x = strtod(ptr, &s);

    //check if converted to long int
    if (*s == 0) {
        return true;
    }
    else {
        return false;
    }
    return false;
}

2 个答案:

答案 0 :(得分:1)

要测试字符串是否为有效浮点值,请使用strtod。此函数使用可选的小数点和可选的指数说明符解析数字字符串(" e"或" E"):

char *p;

errno = 0;
double f = strtod(str,&p);
if (errno) {
    printf("conversion failed");
}
if (strlen(str)==0) {
    printf("empty string\n");
} else {
    printf("f=%f\n", f);
    if (*p == 0) {
        printf("entire string valid\n");
    } else {
        printf("extra characters: %s\n", p);
    }
}

答案 1 :(得分:0)

检查正确性与完全解析它一样困难,没有捷径。我正在重新处理我的任意精度库,其中一个仍然是一个非常混乱的东西是字符串解析,所以我设置并做了一个(希望)正确实现有限状态机(有一些快捷方式,被允许)。近500行代码。我已经使用简单的双重测试(不使用,错误太大了!),以便能够运行一些简单的测试。

请注意,我也允许八进制数字,使用相同的二进制指数和指数标记p作为标准化的十六进制数字,strtod不会。

哦,我很确定它有一些错误。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// for pow() only
#include <math.h>


#ifdef DEBUG
#   define PUTS(x) puts(x)
#else
#   define PUTS(x)
#endif


#define FSM_OK     1
#define FSM_ERROR  0

/*
   EBNF (ISO 14977) for the real numbers this code should be able to treat correctly.

   (* sign *)
   sign = '+'|'-';

   (* numbers starting with zero are octal, hence the special treatment for zero *)
   zero = '0';

   (* binary digit *)
   bindig = '1';
   (* binary integer *)
   binint = bindig , [{(zero | bindig)}];

   (* octal digit *);
   octdig = bindig|'2'|'3'|'4'|'5'|'6'|'7';
   (* octal integer *)
   octint = octdig , [{(zero | octdig)}];

   (* decimal digit *)
   decdig = octdig|'8'|'9';
   (* decimal integer *)
   decint = decdig , [{(zero | decdig)}];

   (* hexadecimal digit *)
   hexdig =  decdig |'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'e'|'f';
   (* hexadecimal integer *)
   hexint = hexdig , [{(zero | hexdig)}];

   (* prefix for the base; inclusion of octal numbers made it interesting *)
   prefix = '0';
   (* Implementing only the four main bases has been deemed sufficient *)
   binbase = prefix , ('B'|'b');
   octbase = prefix , octdig;
   hexbase = prefix , ('X'|'x');

   (* decimal point *)
   decpoint = '.';

   (* exponents *)
   expobin = ('P'|'p'), [sign], decint;
   expodec = ('E'|'e'), [sign], decint;

   (* thousands separator *)
   (* tsep = ','|'\''|'_'; *)

   (* "xyz", "xyz.", "xyz.zyx", ".zyx" *)   
   stubrealbin = binint | (binint, decpoint, [binint]) | (decpoint, binint);
   stubrealoct = octint | (octint, decpoint, [octint]) | (decpoint, octint);
   stubrealdec = decint | (decint, decpoint, [decint]) | (decpoint, decint);
   stubrealhex = hexint | (hexint, decpoint, [hexint]) | (decpoint, hexint);

   fullrealbin = [sign], binbase, stubrealbin, [expobin];
   fullrealoct = [sign], octbase, stubrealoct, [expobin];
   fullrealdec = [sign],          stubrealdec, [expodec];
   fullrealhex = [sign], hexbase, stubrealhex, [expobin];

   (* "InF" and "NaN" should be case insensitive in praxi *)
   real = ([sign], "Inf") | "NaN" | fullrealbin | fullrealoct | fullrealdec | fullrealhex;



   Input characters (grouped for clarity. Case sensitive for brevity only!).
   The input is case insensitive, so 'e', 'E', 'b', and 'B' are only
   distinguishable by context: once you have hexdigits 'e' and 'b' are hexdigits
   and a following sign must trigger an error

   '0'
   '1'                     = bin
   '2'|'3'|'4'|'5'|'6'|'7' = oct
   '8'|'9'                 = dec
   'A'|   |'C'|'D'    |'F' = hex
   'x'
   'b'
   'e'
   'p'
   '.'
   '+' | '-'               = sgn

   Any other input character is not valid (state: ERROR), "Inf" and "NaN" get handled
   elsewhere to keep things simple.


   States

   START
   SIGN
   PREFIX
   DECPOINT
   DECFRAC
   BINBASE
   OCTBASE
   DECBASE
   HEXBASE
   BINFRAC
   OCTFRAC
   HEXFRAC
   EXPOMARK
   EXPOSIGN
   EXPONENT
   ERROR

   Transition table

   START   '0'  it is a prefix              PREFIX
           bin  it is a binary digit        DECBASE
           oct  it is an octal digit        DECBASE
           dec  it is a decimal digit       DECBASE
           hex  it is a hexadecimal digit   HEXBASE
           'x'  cannot be                   ERROR
           'b'  it is a hexadecimal digit   HEXBASE
           'e'  it is a hexadecimal digit   HEXBASE
           'p'  cannot be                   ERROR
           '.'  a decimal point             DECPOINT (!)
           sgn  a sign                      SIGN

   SIGN   '0'   it is a prefix              PREFIX
           bin  it is a binary digit        DECBASE
           oct  it is an octal digit        DECBASE
           dec  it is a decimal digit       DECBASE
           hex  it is a hexadecimal digit   HEXBASE
           'x'  cannot be                   ERROR
           'b'  it is a hexadecimal digit   HEXBASE
           'e'  it is a hexadecimal digit   HEXBASE
           'p'  cannot be                   ERROR
           '.'  a decimal point             DECPOINT (!)
           sgn  a sign                      ERROR

   PREFIX  '0'  zero                        OCTBASE
           bin  binary digit                OCTBASE
           oct  octal digit                 OCTBASE
           dec  cannot be                   ERROR
           hex  cannot be                   ERROR
           'x'  hexadecimal number          HEXBASE
           'b'  binary number               BINBASE
           'e'  cannot be                   ERROR
           'p'  cannot be                   ERROR
           '.'  decimal point               DECFRAC
           sgn  cannot be                   ERROR

   The only place, that is still lingering in limbo is the decimal point. We
   need to fork again, but we do not know in which base the integral part (if one
   exists at all) is, so we still take "decimal" to be the default base.


   DECPOINT '0'  binary digit               DECFRAC
            bin  binary digit               DECFRAC
            oct  octal digit                DECFRAC
            dec  decimal digit              DECFRAC
            hex  hexadecimal digit          HEXFRAC
            'x'  cannot be                  ERROR
            'b'  hexadecimal digit          HEXFRAC
            'e'  hexadecimal digit          HEXFRAC
            'p'  binary exponent            EXPOMARK
            '.'  decimal point              ERROR
            sgn  cannot be                  ERROR

   A fractional part in decimal base is simple enough

   DECFRAC '0'   binary digit               DECFRAC
            bin  binary digit               DECFRAC
            oct  octal digit                DECFRAC
            dec  decimal digit              DECFRAC
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  exponent delimiter         EXPOMARK
            'p'  cannot be                  ERROR
            '.'  cannot be                  ERROR
            sgn  cannot be                  ERROR

   All other fractions need a base, so handle bases first

   BINBASE '0'   binary digit               BINBASE
            bin  binary digit               BINBASE
            oct  cannot be                  ERROR
            dec  cannot be                  ERROR
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  exponent delimiter         EXPOMARK
            '.'  decimal point              BINFRAC
            sgn  cannot be                  ERROR

   OCTBASE  '0'  binary digit               OCTBASE
            bin  binary digit               OCTBASE
            oct  octal digit                OCTBASE
            dec  cannot be                  ERROR
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  exponent delimiter         EXPOMARK
            '.'  decimal point              OCTFRAC
            sgn  cannot be                  ERROR

   HEXBASE  '0'  binary digit               HEXBASE
            bin  binary digit               HEXBASE
            oct  octal digit                HEXBASE
            dec  decimal digit              HEXBASE
            hex  hexadecimal digit          HEXBASE
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  exponent delimiter         EXPOMARK
            '.'  decimal point              HEXFRAC
            sgn  cannot be                  ERROR

   It is easy now to fill the gaps.

   BINFRAC '0'   binary digit               BINFRAC
            bin  binary digit               BINFRAC
            oct  cannot be                  ERROR
            dec  cannot be                  ERROR
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  exponent delimiter         EXPOMARK
            '.'  cannot be                  ERROR
            sgn  cannot be                  ERROR

   OCTFRAC  '0'  binary digit               OCTFRAC
            bin  binary digit               OCTFRAC
            oct  octal digit                OCTFRAC
            dec  cannot be                  ERROR
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  exponent delimiter         EXPOMARK
            '.'  cannot be                  ERROR
            sgn  cannot be                  ERROR

   HEXFRAC  '0'  binary digit               HEXFRAC
            bin  binary digit               HEXFRAC
            oct  octal digit                HEXFRAC
            dec  decimal digit              HEXFRAC
            hex  hexadecimal digit          HEXFRAC
            'x'  cannot be                  ERROR
            'b'  hexadecimal digit          HEXFRAC
            'e'  hexadecimal digit          HEXFRAC
            'p'  exponent delimiter         EXPOMARK
            '.'  decimal point              ERROR
            sgn  cannot be                  ERROR

   The exponent is always encoded in decimal base (IEEE 754 (ISO/IEC 60559) sec. 5.12.3 for
   the hexadecimal example)

   EXPOMARK '0'  binary digit               EXPONENT
            bin  binary digit               EXPONENT
            oct  octal digit                EXPONENT
            dec  decimal digit              EXPONENT
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  cannot be                  ERROR
            '.'  cannot be                  ERROR
            sgn  sign                       EXPOSIGN

   EXPOSIGN '0'  binary digit               EXPONENT
            bin  binary digit               EXPONENT
            oct  octal digit                EXPONENT
            dec  decimal digit              EXPONENT
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  cannot be                  ERROR
            '.'  cannot be                  ERROR
            sgn  sign                       ERROR

   EXPONENT '0'  binary digit               EXPONENT
            bin  binary digit               EXPONENT
            oct  octal digit                EXPONENT
            dec  decimal digit              EXPONENT
            hex  cannot be                  ERROR
            'x'  cannot be                  ERROR
            'b'  cannot be                  ERROR
            'e'  cannot be                  ERROR
            'p'  cannot be                  ERROR
            '.'  cannot be                  ERROR
            sgn  sign                       ERROR

   ERROR    nothing follows an error, only more ERROR

   Nothing marking an end-state, it is just the end of the input buffer


ZERO     '0'
BINDIG   '1'
OCTDIG   '2'|'3'|'4'|'5'|'6'|'7'
DECDIG   '8'|'9'
HEXDIG   'A'|   |'C'|'D'    |'F'
PREHEX   'x'
PREBIN   'b'
EXPDEC   'e'
EXPBIN   'p'
DECPNT   '.'
SGNCHR     '+' | '-'

           ZERO   BINDIG  OCTDIG  DECDIG  HEXDIG PREHEX  PREBIN  EXPDEC   EXPBIN  DECPNT   SGNCHR
START     PREFIX  DECBASE DECBASE DECBASE HEXBASE ERROR  HEXBASE HEXBASE  ERROR   DECPOINT SIGN
SIGN      PREFIX  DECBASE DECBASE DECBASE HEXBASE ERROR  HEXBASE HEXBASE  ERROR   DECPOINT ERROR
PREFIX    OCTBASE OCTBASE OCTBASE  ERROR   ERROR HEXBASE BINBASE  ERROR   ERROR   DECFRAC  ERROR
DECPOINT  DECFRAC DECFRAC DECFRAC DECFRAC HEXFRAC ERROR  HEXFRAC HEXFRAC  EXPOMARK ERROR   ERROR
DECFRAC   DECFRAC DECFRAC DECFRAC DECFRAC  ERROR  ERROR   ERROR  EXPOMARK ERROR    ERROR   ERROR
BINBASE   BINBASE BINBASE  ERROR   ERROR   ERROR  ERROR   ERROR   ERROR   EXPOMARK BINFRAC ERROR
OCTBASE   OCTBASE OCTBASE OCTBASE  ERROR   ERROR  ERROR   ERROR   ERROR   EXPOMARK OCTFRAC ERROR
DECBASE   DECBASE DECBASE DECBASE  ERROR   ERROR  ERROR   ERROR  EXPOMARK ERROR    DECFRAC ERROR
HEXBASE   HEXBASE HEXBASE HEXBASE HEXBASE HEXBASE ERROR   ERROR   ERROR   EXPOMARK HEXFRAC ERROR
BINFRAC   BINFRAC BINFRAC  ERROR   ERROR   ERROR  ERROR   ERROR   ERROR   EXPOMARK ERROR   ERROR
OCTFRAC   OCTFRAC OCTFRAC OCTFRAC  ERROR   ERROR  ERROR   ERROR   ERROR   EXPOMARK ERROR   ERROR
HEXFRAC   HEXFRAC HEXFRAC HEXFRAC HEXFRAC HEXFRAC ERROR  HEXFRAC HEXFRAC  EXPOMARK ERROR   ERROR
EXPOMARK  EXPON'T EXPON'T EXPON'T EXPON'T  ERROR  ERROR   ERROR   ERROR   ERROR    ERROR   EXPOSIGN
EXPOSIGN  EXPON'T EXPON'T EXPON'T EXPON'T  ERROR  ERROR   ERROR   ERROR   ERROR    ERROR   ERROR
EXPONENT  EXPON'T EXPON'T EXPON'T EXPON'T  ERROR  ERROR   ERROR   ERROR   ERROR    ERROR   ERROR
ERROR     ERROR   ERROR    ERROR   ERROR   ERROR  ERROR   ERROR   ERROR   ERROR    ERROR   ERROR
*/


#if !(defined _BSD_SOURCE || defined _DEFAULT_SOURCE || _POSIX_C_SOURCE >= 200112L)
#   include <ctype.h>
static int strncasecmp(const char *s1, const char *s2, size_t n)
{
  char c1 = 0;
  char c2 = 0;

  while (n--) {
    c1 = tolower(*s1);
    c2 = tolower(*s2);

    if (c1 != c2) {
      break;
    }
    if (c1 == '\0') {
      break;
    }
    s1++;
    s2++;
  }
  return (int) (c1 - c2);
}
#endif

#ifdef _MSC_VER
#define strncasecmp(x,y,z) _strnicmp(x,y,z)
#endif


enum fsm_input {
  ZERO,                         // '0'
  BINDIG,                       // '1'
  OCTDIG,                       // '2'|'3'|'4'|'5'|'6'|'7'
  DECDIG,                       // '8'|'9'
  HEXDIG,                       // 'A'    |'C'|'D'    |'F'
  PREHEX,                       // 'x'
  PREBIN,                       // 'b'
  EXPDEC,                       // 'e'
  EXPBIN,                       // 'p'
  DECPNT,                       // '.'
  SGNCHR,                       // '+' | '-'
  OTHER
};

enum fsm_states {
  START,
  SIGN,
  PREFIX,
  DECPOINT,
  DECFRAC,
  BINBASE,
  OCTBASE,
  DECBASE,
  HEXBASE,
  BINFRAC,
  OCTFRAC,
  HEXFRAC,
  EXPOMARK,
  EXPOSIGN,
  EXPONENT,
  ERROR
};

#ifdef DEBUG
static const char *st2str[16] = {
  "START",
  "SIGN",
  "PREFIX",
  "DECPOINT",
  "DECFRAC",
  "BINBASE",
  "OCTBASE",
  "DECBASE",
  "HEXBASE",
  "BINFRAC",
  "OCTFRAC",
  "HEXFRAC",
  "EXPOMARK",
  "EXPOSIGN",
  "EXPONENT",
  "ERROR"
};
#endif
// transition-table
static int fsm_table[16][11] = {
  {PREFIX, DECBASE, DECBASE, DECBASE, HEXBASE, ERROR, HEXBASE, HEXBASE, ERROR,
   DECPOINT, SIGN},
  {PREFIX, DECBASE, DECBASE, DECBASE, HEXBASE, ERROR, HEXBASE,
   HEXBASE, ERROR, DECPOINT, ERROR},
  {OCTBASE, OCTBASE, OCTBASE, ERROR, ERROR, HEXBASE, BINBASE, ERROR, ERROR,
   DECFRAC,
   ERROR},
  {DECFRAC, DECFRAC, DECFRAC, DECFRAC, HEXFRAC, ERROR, HEXFRAC, HEXFRAC,
   EXPOMARK, ERROR, ERROR},
  {DECFRAC, DECFRAC, DECFRAC, DECFRAC, ERROR, ERROR, ERROR, EXPOMARK, ERROR,
   ERROR, ERROR},
  {BINBASE, BINBASE, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK,
   BINFRAC, ERROR},
  {OCTBASE, OCTBASE, OCTBASE, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK,
   OCTFRAC, ERROR},
  {DECBASE, DECBASE, DECBASE, ERROR, ERROR, ERROR, ERROR, EXPOMARK, ERROR,
   DECFRAC, ERROR},
  {HEXBASE, HEXBASE, HEXBASE, HEXBASE, HEXBASE, ERROR, ERROR, ERROR, EXPOMARK,
   HEXFRAC, ERROR},
  {BINFRAC, BINFRAC, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK, ERROR,
   ERROR},
  {OCTFRAC, OCTFRAC, OCTFRAC, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK,
   ERROR, ERROR},
  {HEXFRAC, HEXFRAC, HEXFRAC, HEXFRAC, HEXFRAC, ERROR, HEXFRAC, HEXFRAC,
   EXPOMARK, ERROR, ERROR},
  {EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR,
   ERROR, EXPOSIGN},
  {EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR,
   ERROR, ERROR},
  {EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR,
   ERROR, ERROR},
  {ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR}
};


#include <ctype.h>
static int check_type(char c)
{
  int type;
  switch (tolower(c)) {
    case '0':
      type = ZERO;
      break;
    case '1':
      type = BINDIG;
      break;
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
      type = OCTDIG;
      break;
    case '8':
    case '9':
      type = DECDIG;
      break;
    case 'a':
    case 'c':
    case 'd':
    case 'f':
      type = HEXDIG;
      break;
    case 'x':
      type = PREHEX;
      break;
    case 'b':
      type = PREBIN;
      break;
    case 'e':
      type = EXPDEC;
      break;
    case 'p':
      type = EXPBIN;
      break;
    case '.':
      type = DECPNT;
      break;
    case '+':
    case '-':
      type = SGNCHR;
      break;
    default:
      type = OTHER;
      break;
  };
  return type;
}

// some variables to hold the relevant parts of a real number
static int main_sign = 1;
static int expo_sign = 1;

static double integral_part = 0.0;
static double fractional_part = 0.0;
static int hex_frac = 0;
static int dec_frac = 0;
static int oct_frac = 0;
static int bin_frac = 0;

static int exponent_part = 0;
// flags with both a boolean and a numerical value
// prob. not the best idea but simple
#define DECIMAL_EXP 10
#define BINARY_EXP   2
static int exponent_binordec = 0;

// assuming ASCII. Full map for more bases in the future.
// Far future.
static const char digit_map[] = {
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x00-0x07
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x08-0x0f
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x10-0x17
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x18-0x1f
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x20-0x27
    -1, -1,  1, -1, -1, -1, -1, -1,     //  0x28-0x2f '+' = 0x2b, '-' = 0x2d
     0,  1,  2,  3,  4,  5,  6,  7,     //  0x30-0x37
     8,  9, -1, -1, -1, -1, -1, -1,     //  0x38-0x3F
    -1, 10, 11, 12, 13, 14, 15, -1,     //  0x40-0x47
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x48-0x4f
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x50-0x57
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x58-0x5f
    -1, 10, 11, 12, 13, 14, 15, -1,     //  0x60-0x67
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x68-0x6f
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x70-0x77
    -1, -1, -1, -1, -1, -1, -1, -1      //  0x78-0x7f
};


static int fsm(char input, int *state)
{
  int res = FSM_OK;

  input = tolower(input);
#ifdef DEBUG
  printf("INPUT: %c [0x%2x] (%d)  STATE: %-10s\n", input, input,digit_map[+input],st2str[*state]);
#endif
  switch (*state) {
    case START:
      fprintf(stderr,
              "Something is messed up in quite some hefty way and form!\n");
      exit(EXIT_FAILURE);
    case SIGN:
      main_sign = digit_map[+input];
      break;
    case PREFIX:
      // not used
      break;
    case DECPOINT:
      // not used
      break;
    case DECBASE:
      integral_part *= 10.0;
      integral_part += digit_map[+input];
      break;
    case BINBASE:
      integral_part *= 2.0;
      integral_part += digit_map[+input];
      break;
    case OCTBASE:
      integral_part *= 8.0;
      integral_part += digit_map[+input];
      break;
    case HEXBASE:
      if (input == 'x') {
        break;
      }
      integral_part *= 16.0;
      integral_part += digit_map[+input];
      break;
    case BINFRAC:
      if (input == '.') {
        break;
      }
      fractional_part *= 2.0;
      fractional_part += digit_map[+input];
      bin_frac++;
      break;
    case OCTFRAC:
      if (input == '.') {
        break;
      }
      fractional_part *= 8.0;
      fractional_part += digit_map[+input];
      oct_frac++;
      break;
    case DECFRAC:
      if (input == '.') {
        break;
      }
      fractional_part *= 10.0;
      fractional_part += digit_map[+input];
      dec_frac++;
      break;
    case HEXFRAC:
      if (input == '.') {
        break;
      }
      fractional_part *= 16.0;
      fractional_part += digit_map[+input];
      hex_frac++;
      break;
    case EXPOMARK:
      exponent_binordec = (input == 'e') ? DECIMAL_EXP : BINARY_EXP;
      break;
    case EXPOSIGN:
      expo_sign = digit_map[+input];
      break;
    case EXPONENT:
      exponent_part *= 10;
      exponent_part += digit_map[+input];
      break;
    case ERROR:
      fprintf(stderr, "ERROR state reached\n");
      exit(EXIT_FAILURE);
      // "Run in circles, scream and shout!"
      // Infantry Journal, Vol. 35, p. 396, United States Infantry Association, 1929
      // Or was it Herman Wouk? The Caine Mutiny? No, that would be 1951 and too late.
      break;
    default:
      fprintf(stderr, "Unexpected state with input %c\n", input);
      *state = ERROR;
      res = FSM_ERROR;
      break;
  }
  return res;
}

static char *trim_both(char *s)
{
  char *end,*p;
  p = s;
  while (isspace(*p)) {
    p++;
  }
  if (*p == '\0') {
    return p;
  }
  end = p + strlen(p) - 1;
  while (end > p && isspace(*end)) {
    end--;
  }
  *(end + 1) = '\0';
  return p;
}

static int str2dbl(char *s, double *d)
{
  int cur_state = START;
  int type;
  int res;

  s = trim_both(s);

  if(*s == '\0'){
     // empty input, would an error be better?
     *d = 0.0;
     return FSM_OK;
  }

  if(*s == '0' && *(s+1) == '\0'){
     *d = 0.0;
     return FSM_OK;
  }

  if (!strncasecmp(s, "-inf", 4)) {
    *d = -INFINITY;
    return FSM_OK;
  }
  if (!strncasecmp(s, "+inf", 4) || !strncasecmp(s, "inf", 3)) {
    *d = INFINITY;
    return FSM_OK;
  }
  if (!strncasecmp(s, "-nan", 4) || !strncasecmp(s, "+nan", 4) || !strncasecmp(s, "nan", 3) ) {
    *d = NAN;
    return FSM_OK;
  }

  while (*s != '\0') {
    type = check_type(*s);
    if (type == OTHER) {
      fprintf(stderr, "OTHER: %c", *s);
      return FSM_ERROR;
    }

    cur_state = fsm_table[cur_state][type];
    res = fsm(*s, &cur_state);
    if (res != FSM_OK) {
      break;
    }
    s++;
  }

  printf("exp; %d, intp: %.20g, fracp: %.20g\n", exponent_part, integral_part,
         fractional_part);

  // The following will work with arbitray precision in production, use of
  // a "double" is just for testing and not for real use. The error is
  // larger than one ulp in way too many times

  // the integral part needs no treatment, yet.
  *d += integral_part;

  // the fractional part needs to be shifted by the base to the right
  if (hex_frac > 0) {
    fractional_part /= pow(16, hex_frac);
  } else if (dec_frac > 0) {
    fractional_part /= pow(10, dec_frac);
  } else if (oct_frac > 0) {
    fractional_part /= pow(8, oct_frac);
  } else if (bin_frac > 0) {
    fractional_part /= pow(2, bin_frac);
  }
  printf("fracp: %.20g\n", fractional_part);
  *d += fractional_part;

  // (exponent_binordec != 0) also means that there is an exponent in the first place
  if (exponent_binordec) {
    if (expo_sign >= 0) {
      *d *= pow(exponent_binordec, exponent_part);
    } else {
      *d /= pow(exponent_binordec, exponent_part);
    }
  }
  *d *= main_sign;
  return FSM_OK;
}

int main(int argc, char **argv)
{
  int res;
  char *input, *endptr;
  double out, libc;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s float\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  input = malloc(strlen(argv[1]) + 1);
  if (input == NULL) {
    fprintf(stderr, "Malloc failed to allocate a measly %zu bytes\n",
            strlen(argv[1]) + 1);
    exit(EXIT_FAILURE);
  }
  strcpy(input, argv[1]);

  // all checks ommited!
  libc = strtod(input, &endptr);
  printf("\nINPUT: %s\t%g\t%s\n\n", input, libc, endptr);
  out = 0.0;

  res = str2dbl(input, &out);

  printf
      ("fsm returned %d and the result (if any) is: \n\tinp:  %s\n\town:  %.20g\n\tlibc: %.20g\n",
       res, trim_both(input) ,out, libc);
  free(input);
  exit(EXIT_SUCCESS);
}