aboutsummaryrefslogtreecommitdiff
path: root/libc/src/arpa/inet/inet_aton.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libc/src/arpa/inet/inet_aton.cpp')
-rw-r--r--libc/src/arpa/inet/inet_aton.cpp57
1 files changed, 57 insertions, 0 deletions
diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
new file mode 100644
index 0000000..71419cb
--- /dev/null
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -0,0 +1,57 @@
+//===-- Implementation of inet_aton function ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/arpa/inet/inet_aton.h"
+#include "src/__support/common.h"
+#include "src/__support/endian_internal.h"
+#include "src/__support/str_to_integer.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
+ constexpr int IPV4_MAX_DOT_NUM = 3;
+ unsigned long parts[IPV4_MAX_DOT_NUM + 1] = {0};
+ int dot_num = 0;
+
+ for (; dot_num <= IPV4_MAX_DOT_NUM; ++dot_num) {
+ auto result = internal::strtointeger<unsigned long>(cp, 0);
+ parts[dot_num] = result;
+
+ if (result.has_error() || result.parsed_len == 0)
+ return 0;
+ char next_char = *(cp + result.parsed_len);
+ if (next_char != '.' && next_char != '\0')
+ return 0;
+ else if (next_char == '\0')
+ break;
+ else
+ cp += (result.parsed_len + 1);
+ }
+
+ if (dot_num > IPV4_MAX_DOT_NUM)
+ return 0;
+
+ // converts the Internet host address cp from the IPv4 numbers-and-dots
+ // notation (a[.b[.c[.d]]]) into binary form (in network byte order)
+ unsigned long result = 0;
+ for (int i = 0; i <= dot_num; ++i) {
+ unsigned long max_part =
+ i == dot_num ? (0xffffffffUL >> (8 * dot_num)) : 0xffUL;
+ if (parts[i] > max_part)
+ return 0;
+ int shift = i == dot_num ? 0 : 8 * (IPV4_MAX_DOT_NUM - i);
+ result |= parts[i] << shift;
+ }
+
+ if (inp)
+ inp->s_addr = Endian::to_big_endian(static_cast<uint32_t>(result));
+
+ return 1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL