~ubuntu-branches/debian/stretch/protobuf/stretch

« back to all changes in this revision

Viewing changes to src/google/protobuf/io/strtod.cc

  • Committer: Package Import Robot
  • Author(s): Robert S. Edmonds
  • Date: 2014-09-11 22:50:10 UTC
  • mfrom: (10.1.9 experimental)
  • Revision ID: package-import@ubuntu.com-20140911225010-wt4yo9dpc1fzuq5g
Tags: 2.6.0-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Protocol Buffers - Google's data interchange format
 
2
// Copyright 2008 Google Inc.  All rights reserved.
 
3
// http://code.google.com/p/protobuf/
 
4
//
 
5
// Redistribution and use in source and binary forms, with or without
 
6
// modification, are permitted provided that the following conditions are
 
7
// met:
 
8
//
 
9
//     * Redistributions of source code must retain the above copyright
 
10
// notice, this list of conditions and the following disclaimer.
 
11
//     * Redistributions in binary form must reproduce the above
 
12
// copyright notice, this list of conditions and the following disclaimer
 
13
// in the documentation and/or other materials provided with the
 
14
// distribution.
 
15
//     * Neither the name of Google Inc. nor the names of its
 
16
// contributors may be used to endorse or promote products derived from
 
17
// this software without specific prior written permission.
 
18
//
 
19
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
20
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
21
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
22
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
23
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
24
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
25
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
26
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
27
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
28
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
29
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
30
 
 
31
#include <google/protobuf/io/strtod.h>
 
32
 
 
33
#include <cstdio>
 
34
#include <cstring>
 
35
#include <string>
 
36
 
 
37
#include <google/protobuf/stubs/common.h>
 
38
 
 
39
namespace google {
 
40
namespace protobuf {
 
41
namespace io {
 
42
 
 
43
// ----------------------------------------------------------------------
 
44
// NoLocaleStrtod()
 
45
//   This code will make you cry.
 
46
// ----------------------------------------------------------------------
 
47
 
 
48
namespace {
 
49
 
 
50
// Returns a string identical to *input except that the character pointed to
 
51
// by radix_pos (which should be '.') is replaced with the locale-specific
 
52
// radix character.
 
53
string LocalizeRadix(const char* input, const char* radix_pos) {
 
54
  // Determine the locale-specific radix character by calling sprintf() to
 
55
  // print the number 1.5, then stripping off the digits.  As far as I can
 
56
  // tell, this is the only portable, thread-safe way to get the C library
 
57
  // to divuldge the locale's radix character.  No, localeconv() is NOT
 
58
  // thread-safe.
 
59
  char temp[16];
 
60
  int size = sprintf(temp, "%.1f", 1.5);
 
61
  GOOGLE_CHECK_EQ(temp[0], '1');
 
62
  GOOGLE_CHECK_EQ(temp[size-1], '5');
 
63
  GOOGLE_CHECK_LE(size, 6);
 
64
 
 
65
  // Now replace the '.' in the input with it.
 
66
  string result;
 
67
  result.reserve(strlen(input) + size - 3);
 
68
  result.append(input, radix_pos);
 
69
  result.append(temp + 1, size - 2);
 
70
  result.append(radix_pos + 1);
 
71
  return result;
 
72
}
 
73
 
 
74
}  // namespace
 
75
 
 
76
double NoLocaleStrtod(const char* text, char** original_endptr) {
 
77
  // We cannot simply set the locale to "C" temporarily with setlocale()
 
78
  // as this is not thread-safe.  Instead, we try to parse in the current
 
79
  // locale first.  If parsing stops at a '.' character, then this is a
 
80
  // pretty good hint that we're actually in some other locale in which
 
81
  // '.' is not the radix character.
 
82
 
 
83
  char* temp_endptr;
 
84
  double result = strtod(text, &temp_endptr);
 
85
  if (original_endptr != NULL) *original_endptr = temp_endptr;
 
86
  if (*temp_endptr != '.') return result;
 
87
 
 
88
  // Parsing halted on a '.'.  Perhaps we're in a different locale?  Let's
 
89
  // try to replace the '.' with a locale-specific radix character and
 
90
  // try again.
 
91
  string localized = LocalizeRadix(text, temp_endptr);
 
92
  const char* localized_cstr = localized.c_str();
 
93
  char* localized_endptr;
 
94
  result = strtod(localized_cstr, &localized_endptr);
 
95
  if ((localized_endptr - localized_cstr) >
 
96
      (temp_endptr - text)) {
 
97
    // This attempt got further, so replacing the decimal must have helped.
 
98
    // Update original_endptr to point at the right location.
 
99
    if (original_endptr != NULL) {
 
100
      // size_diff is non-zero if the localized radix has multiple bytes.
 
101
      int size_diff = localized.size() - strlen(text);
 
102
      // const_cast is necessary to match the strtod() interface.
 
103
      *original_endptr = const_cast<char*>(
 
104
        text + (localized_endptr - localized_cstr - size_diff));
 
105
    }
 
106
  }
 
107
 
 
108
  return result;
 
109
}
 
110
 
 
111
}  // namespace io
 
112
}  // namespace protobuf
 
113
}  // namespace google