~evarlast/ubuntu/utopic/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/mongo/base/parse_number.cpp

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*    Copyright 2012 10gen Inc.
 
2
 *
 
3
 *    Licensed under the Apache License, Version 2.0 (the "License");
 
4
 *    you may not use this file except in compliance with the License.
 
5
 *    You may obtain a copy of the License at
 
6
 *
 
7
 *    http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
9
 *    Unless required by applicable law or agreed to in writing, software
 
10
 *    distributed under the License is distributed on an "AS IS" BASIS,
 
11
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
12
 *    See the License for the specific language governing permissions and
 
13
 *    limitations under the License.
 
14
 */
 
15
 
 
16
#include "mongo/base/parse_number.h"
 
17
 
 
18
#include <limits>
 
19
 
 
20
#include "mongo/platform/cstdint.h"
 
21
 
 
22
namespace mongo {
 
23
 
 
24
    /**
 
25
     * Returns the value of the digit "c", with the same conversion behavior as strtol.
 
26
     *
 
27
     * Assumes "c" is an ASCII character or UTF-8 octet.
 
28
     */
 
29
    static uint8_t _digitValue(char c) {
 
30
        if (c >= '0' && c <= '9')
 
31
            return uint8_t(c - '0');
 
32
        if (c >= 'a' && c <= 'z')
 
33
            return uint8_t(c - 'a' + 10);
 
34
        if (c >= 'A' && c <= 'Z')
 
35
            return uint8_t(c - 'A' + 10);
 
36
        return 36;  // Illegal digit value for all supported bases.
 
37
    }
 
38
 
 
39
    /**
 
40
     * Assuming "stringValue" represents a parseable number, extracts the sign and returns a
 
41
     * substring with any sign characters stripped away.  "*isNegative" is set to true if the
 
42
     * number is negative, and false otherwise.
 
43
     */
 
44
    static inline StringData _extractSign(const StringData& stringValue, bool* isNegative) {
 
45
        if (stringValue.empty()) {
 
46
            *isNegative = false;
 
47
            return stringValue;
 
48
        }
 
49
 
 
50
        bool foundSignMarker;
 
51
        switch (stringValue[0]) {
 
52
        case '-':
 
53
            foundSignMarker = true;
 
54
            *isNegative = true;
 
55
            break;
 
56
        case '+':
 
57
            foundSignMarker = true;
 
58
            *isNegative = false;
 
59
            break;
 
60
        default:
 
61
            foundSignMarker = false;
 
62
            *isNegative = false;
 
63
            break;
 
64
        }
 
65
 
 
66
        if (foundSignMarker)
 
67
            return stringValue.substr(1);
 
68
        return stringValue;
 
69
    }
 
70
 
 
71
    /**
 
72
     * Assuming "stringValue" represents a parseable number, determines what base to use given
 
73
     * "inputBase".  Stores the correct base into "*outputBase".  Follows strtol rules.  If
 
74
     * "inputBase" is not 0, *outputBase is set to "inputBase".  Otherwise, if "stringValue" starts
 
75
     * with "0x" or "0X", sets outputBase to 16, or if it starts with 0, sets outputBase to 8.
 
76
     *
 
77
     * Returns stringValue, unless it sets *outputBase to 16, in which case it will strip off the
 
78
     * "0x" or "0X" prefix, if present.
 
79
     */
 
80
    static inline StringData _extractBase(
 
81
            const StringData& stringValue, int inputBase, int* outputBase) {
 
82
 
 
83
        const StringData hexPrefixLower("0x", StringData::LiteralTag());
 
84
        const StringData hexPrefixUpper("0X", StringData::LiteralTag());
 
85
        if (inputBase == 0) {
 
86
            if (stringValue.size() > 2 && (stringValue.startsWith(hexPrefixLower) ||
 
87
                                           stringValue.startsWith(hexPrefixUpper))) {
 
88
                *outputBase = 16;
 
89
                return stringValue.substr(2);
 
90
            }
 
91
            if (stringValue.size() > 1 && stringValue[0] == '0') {
 
92
                *outputBase = 8;
 
93
                return stringValue;
 
94
            }
 
95
            *outputBase = 10;
 
96
            return stringValue;
 
97
        }
 
98
        else {
 
99
            *outputBase = inputBase;
 
100
            if (inputBase == 16 && (stringValue.startsWith(hexPrefixLower) ||
 
101
                                    stringValue.startsWith(hexPrefixUpper))) {
 
102
                return stringValue.substr(2);
 
103
            }
 
104
            return stringValue;
 
105
        }
 
106
    }
 
107
 
 
108
    template <typename NumberType>
 
109
    Status parseNumberFromStringWithBase(
 
110
            const StringData& stringValue, int base, NumberType* result) {
 
111
 
 
112
        typedef ::std::numeric_limits<NumberType> limits;
 
113
 
 
114
        if (base == 1 || base < 0 || base > 36)
 
115
            return Status(ErrorCodes::BadValue, "Invalid base", 0);
 
116
 
 
117
        bool isNegative = false;
 
118
        StringData str = _extractBase(_extractSign(stringValue, &isNegative), base, &base);
 
119
 
 
120
        if (str.empty())
 
121
            return Status(ErrorCodes::FailedToParse, "No digits");
 
122
 
 
123
        NumberType n(0);
 
124
        if (isNegative) {
 
125
            if (limits::is_signed) {
 
126
                for (size_t i = 0; i < str.size(); ++i) {
 
127
                    NumberType digitValue = NumberType(_digitValue(str[i]));
 
128
                    if (int(digitValue) >= base)
 
129
                        return Status(ErrorCodes::FailedToParse, "Bad digit");
 
130
 
 
131
// MSVC: warning C4146: unary minus operator applied to unsigned type, result still unsigned
 
132
// This code is statically known to be dead when NumberType is unsigned, so the warning is not real
 
133
#pragma warning(push)
 
134
#pragma warning(disable:4146)
 
135
                    if ((NumberType(limits::min() / base) > n) ||
 
136
                        ((limits::min() - NumberType(n * base)) > -digitValue)) {
 
137
#pragma warning(pop)
 
138
 
 
139
                        return Status(ErrorCodes::FailedToParse, "Underflow");
 
140
                    }
 
141
 
 
142
                    n *= NumberType(base);
 
143
                    n -= NumberType(digitValue);
 
144
                }
 
145
            }
 
146
            else {
 
147
                return Status(ErrorCodes::FailedToParse, "Negative value");
 
148
            }
 
149
        }
 
150
        else {
 
151
            for (size_t i = 0; i < str.size(); ++i) {
 
152
                NumberType digitValue = NumberType(_digitValue(str[i]));
 
153
                if (int(digitValue) >= base)
 
154
                    return Status(ErrorCodes::FailedToParse, "Bad digit");
 
155
                if ((NumberType(limits::max() / base) < n) ||
 
156
                    (NumberType(limits::max() - n * base) < digitValue)) {
 
157
 
 
158
                    return Status(ErrorCodes::FailedToParse, "Overflow");
 
159
                }
 
160
 
 
161
                n *= NumberType(base);
 
162
                n += NumberType(digitValue);
 
163
            }
 
164
        }
 
165
        *result = n;
 
166
        return Status::OK();
 
167
    }
 
168
 
 
169
    // Definition of the various supported implementations of parseNumberFromStringWithBase.
 
170
 
 
171
#define DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(NUMBER_TYPE)          \
 
172
    template Status parseNumberFromStringWithBase<NUMBER_TYPE>(const StringData&, int, NUMBER_TYPE*);
 
173
 
 
174
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(long)
 
175
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(long long)
 
176
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned long)
 
177
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned long long)
 
178
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(short)
 
179
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned short)
 
180
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(int)
 
181
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(unsigned int)
 
182
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(int8_t);
 
183
    DEFINE_PARSE_NUMBER_FROM_STRING_WITH_BASE(uint8_t);
 
184
 
 
185
}  // namespace mongo