ArgParser.cxx 4.22 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2020 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

Max Kellermann's avatar
Max Kellermann committed
20
#include "ArgParser.hxx"
21
#include "RangeArg.hxx"
22
#include "Ack.hxx"
23
#include "Chrono.hxx"
24
#include "util/NumberParser.hxx"
25 26 27

#include <stdlib.h>

28 29
uint32_t
ParseCommandArgU32(const char *s)
30 31
{
	char *test;
32 33 34 35
	auto value = strtoul(s, &test, 10);
	if (test == s || *test != '\0')
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Integer expected: %s", s);
36

37
	return value;
38 39
}

40 41
int
ParseCommandArgInt(const char *s, int min_value, int max_value)
42 43
{
	char *test;
44 45 46 47
	auto value = strtol(s, &test, 10);
	if (test == s || *test != '\0')
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Integer expected: %s", s);
48

49 50 51
	if (value < min_value || value > max_value)
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Number too large: %s", s);
52

53
	return (int)value;
54 55
}

56 57
int
ParseCommandArgInt(const char *s)
58
{
59 60 61
	return ParseCommandArgInt(s,
				  std::numeric_limits<int>::min(),
				  std::numeric_limits<int>::max());
62 63
}

64 65
RangeArg
ParseCommandArgRange(const char *s)
66 67
{
	char *test, *test2;
68 69 70 71
	auto value = strtol(s, &test, 10);
	if (test == s || (*test != '\0' && *test != ':'))
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Integer or range expected: %s", s);
72

73
	if (value == -1 && *test == 0)
74 75
		/* compatibility with older MPD versions: specifying
		   "-1" makes MPD display the whole list */
76
		return RangeArg::All();
77

78 79 80
	if (value < 0)
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Number is negative: %s", s);
81

82
	if (value > std::numeric_limits<int>::max())
83 84
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Number too large: %s", s);
85

86 87
	RangeArg range;
	range.start = (unsigned)value;
88 89 90

	if (*test == ':') {
		value = strtol(++test, &test2, 10);
91 92 93 94
		if (*test2 != '\0')
			throw FormatProtocolError(ACK_ERROR_ARG,
						  "Integer or range expected: %s",
						  s);
95 96

		if (test == test2)
97
			value = std::numeric_limits<int>::max();
98

99 100 101
		if (value < 0)
			throw FormatProtocolError(ACK_ERROR_ARG,
						  "Number is negative: %s", s);
102 103


104
		if (value > std::numeric_limits<int>::max())
105 106
			throw FormatProtocolError(ACK_ERROR_ARG,
						  "Number too large: %s", s);
107

108
		range.end = (unsigned)value;
109
	} else {
110
		range.end = (unsigned)value + 1;
111 112
	}

113
	return range;
114 115
}

116 117
unsigned
ParseCommandArgUnsigned(const char *s, unsigned max_value)
118 119
{
	char *endptr;
120 121 122 123
	auto value = strtoul(s, &endptr, 10);
	if (endptr == s || *endptr != 0)
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Integer expected: %s", s);
124

125 126 127
	if (value > max_value)
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Number too large: %s", s);
128

129
	return (unsigned)value;
130 131
}

132 133
unsigned
ParseCommandArgUnsigned(const char *s)
134
{
135 136
	return ParseCommandArgUnsigned(s,
				       std::numeric_limits<unsigned>::max());
137 138
}

139
bool
140
ParseCommandArgBool(const char *s)
141 142
{
	char *endptr;
143 144 145 146
	auto value = strtol(s, &endptr, 10);
	if (endptr == s || *endptr != 0 || (value != 0 && value != 1))
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Boolean (0/1) expected: %s", s);
147

148
	return !!value;
149 150
}

151 152
float
ParseCommandArgFloat(const char *s)
153 154
{
	char *endptr;
155
	auto value = ParseFloat(s, &endptr);
156 157 158
	if (endptr == s || *endptr != 0)
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Float expected: %s", s);
159

160
	return value;
161
}
162

163 164
SongTime
ParseCommandArgSongTime(const char *s)
165
{
166
	auto value = ParseCommandArgFloat(s);
167 168 169 170
	if (value < 0)
		throw FormatProtocolError(ACK_ERROR_ARG,
					  "Negative value not allowed: %s", s);

171
	return SongTime::FromS(value);
172 173
}

174 175
SignedSongTime
ParseCommandArgSignedSongTime(const char *s)
176
{
177
	auto value = ParseCommandArgFloat(s);
178
	return SignedSongTime::FromS(value);
179
}