diff options
Diffstat (limited to 'libxsde/xsde/cxx/parser/non-validating/number.cxx')
-rw-r--r-- | libxsde/xsde/cxx/parser/non-validating/number.cxx | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/libxsde/xsde/cxx/parser/non-validating/number.cxx b/libxsde/xsde/cxx/parser/non-validating/number.cxx new file mode 100644 index 0000000..c271ab5 --- /dev/null +++ b/libxsde/xsde/cxx/parser/non-validating/number.cxx @@ -0,0 +1,127 @@ +// file : xsde/cxx/parser/non-validating/number.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <string.h> // memcpy + +#include <xsde/cxx/parser/non-validating/number.hxx> + +using xsde::cxx::ro_string; + +static bool +trim_leading_zeros (ro_string& s) +{ + ro_string::size_type size = s.size (); + + if (size != 0) + { + const char* f = s.data (); + const char* l = f + size; + const char* of = f; + + while (f < l && *f == '0') + ++f; + + if (f != of) + { + s.assign ((f <= l ? f : 0), (f <= l ? l - f : 0)); + return true; + } + } + + return false; +} + +namespace xsde +{ + namespace cxx + { + namespace parser + { + namespace non_validating + { + void number:: + parse (const ro_string& s, char* str, size_t max) + { + ro_string tmp (s.data (), s.size ()); + size_t size = tmp.size (); + + switch (state_) + { + case leading_ws: + { + size = trim_left (tmp); + + if (size != 0) + state_ = sign; + else + break; + // Fall through. + } + case sign: + { + if (tmp[0] == '-') + sign_ = minus; + else if (tmp[0] == '+') + sign_ = plus; + + if (sign_ != none) + tmp.assign (tmp.data () + 1, --size); + + if (size != 0) + state_ = leading_zeros; + else + break; + + // Fall through. + } + case leading_zeros: + { + if (trim_leading_zeros (tmp)) + { + if (size_ == 0) + { + str[0] = '0'; + size_ = 1; + } + + size = tmp.size (); + } + + if (size != 0) + state_ = literal; + else + break; + // Fall through. + } + case literal: + { + // If this chunk is too long then it has to be the last so trim + // trailing ws. + // + if ((max - size_) < size) + { + size = trim_right (tmp); + state_ = trailing_ws; // It either had ws or is too large. + } + + if ((max - size_) >= size) + { + memcpy (str + size_, tmp.data (), size); + size_ += size; + } + + break; + } + case trailing_ws: + { + // We don't really care if it is not. + break; + } + } + } + } + } + } +} |