Skip to content

Commit 98239f6

Browse files
committed
Changing to_str to mimic snprintf
- Updated tests - Updated test scaffold to give better diagnostics
1 parent 4cbcda9 commit 98239f6

File tree

3 files changed

+185
-82
lines changed

3 files changed

+185
-82
lines changed

ipv6.c

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -727,23 +727,29 @@ bool IPV6_API_DEF(ipv6_from_str_diag) (
727727
// Treat the end of input as whitespace to simplify state transitions
728728
ipv6_state_transition(&state, EC_WHITESPACE);
729729

730-
// Early out if there was an error processing the string
731-
if ((state.flags & READER_FLAG_ERROR) != 0) {
732-
return false;
733-
}
734-
735-
// If an IPv4 compatible address was specified the rest of the IPv6 collapsing
736-
// rules can be skipped
737-
if ((state.flags & READER_FLAG_IPV4_COMPAT) != 0) {
738-
state.address_full->flags |= IPV6_FLAG_IPV4_COMPAT;
739-
return true;
740-
}
730+
// Early out if there was an error processing the string
731+
if ((state.flags & READER_FLAG_ERROR) != 0) {
732+
return false;
733+
}
734+
735+
// If an IPv4 compatible address was specified the rest of the IPv6 collapsing
736+
// rules can be skipped
737+
if ((state.flags & READER_FLAG_IPV4_COMPAT) != 0) {
738+
if (state.v4_octets != 4) {
739+
ipv6_error(&state, IPV6_DIAG_V4_BAD_COMPONENT_COUNT,
740+
"IPv4 compatible address was used but required 4 octets");
741+
return false;
742+
}
743+
state.address_full->flags |= IPV6_FLAG_IPV4_COMPAT;
744+
return true;
745+
}
741746

742747
// Mark the presence of embedded IPv4 addresses
743748
if (state.flags & READER_FLAG_IPV4_EMBEDDING) {
744749
if (state.v4_octets != 4) {
745750
ipv6_error(&state, IPV6_DIAG_V4_BAD_COMPONENT_COUNT,
746751
"IPv4 address embedding was used but required 4 octets");
752+
return false;
747753
} else {
748754
state.address_full->flags |= IPV6_FLAG_IPV4_EMBED;
749755
}
@@ -808,29 +814,32 @@ bool IPV6_API_DEF(ipv6_from_str) (
808814

809815
#define OUTPUT_TRUNCATED() \
810816
IPV6_TRACE(" ! buffer truncated at position %u\n", (uint32_t)(wp - out)); \
811-
*out = '\0';
817+
output_bytes = 0; \
818+
*output = '\0';
812819

813820
//--------------------------------------------------------------------------------
814-
char* IPV6_API_DEF(ipv6_to_str) (
821+
size_t IPV6_API_DEF(ipv6_to_str) (
815822
const ipv6_address_full_t* in,
816-
char *out,
817-
size_t size)
823+
char *output,
824+
size_t output_bytes)
818825
{
819-
if (size < 4) {
820-
return NULL;
826+
if (!in || !output) {
827+
return 0;
821828
}
822829

823-
if (!in) {
824-
return NULL;
830+
if (output_bytes < 4) {
831+
return 0;
825832
}
826833

834+
*output = '\0';
835+
827836
const uint16_t* components = in->address.components;
828-
char* wp = out; // write pointer
829-
const char* ep = out + size - 1; // end pointer with one octet for nul
837+
char* wp = output; // write pointer
838+
const char* ep = output + output_bytes - 1; // end pointer with one octet for nul
830839
char token[16] = {0, };
831840

832-
833-
// If the address is an IPv4 compat address shortcut the IPv6 rules and print an address or address:port
841+
// If the address is an IPv4 compatible address shortcut the IPv6 rules and
842+
// print an address or address:port
834843
if (in->flags & IPV6_FLAG_IPV4_COMPAT) {
835844
const uint32_t host_ipv4 = components[0] << 16 | components[1];
836845
if (in->flags & IPV6_FLAG_HAS_PORT) {
@@ -851,8 +860,10 @@ char* IPV6_API_DEF(ipv6_to_str) (
851860
while (wp < ep && *cp) {
852861
*wp++ = *cp++;
853862
}
863+
864+
output_bytes = (size_t)(ptrdiff_t)(wp - output);
854865
*wp++ = '\0';
855-
return out;
866+
return output_bytes;
856867
}
857868

858869
// For each component find the length of 0 digits that it covers (including
@@ -915,7 +926,7 @@ char* IPV6_API_DEF(ipv6_to_str) (
915926
if (i == longest_position && longest_span > 1) {
916927
if (wp + 2 >= ep) {
917928
OUTPUT_TRUNCATED();
918-
return NULL;
929+
return output_bytes;
919930
}
920931

921932
// The previous component already emitted a separator, or this is the
@@ -942,7 +953,7 @@ char* IPV6_API_DEF(ipv6_to_str) (
942953
if (wp == ep) {
943954
// Truncated, return a deterministic result
944955
OUTPUT_TRUNCATED();
945-
return NULL;
956+
return output_bytes;
946957
}
947958
}
948959

@@ -962,9 +973,15 @@ char* IPV6_API_DEF(ipv6_to_str) (
962973
}
963974
}
964975

965-
*wp = '\0';
966-
967-
return out;
976+
// Output truncated
977+
if (wp == ep) {
978+
OUTPUT_TRUNCATED();
979+
}
980+
else {
981+
output_bytes = (size_t)(ptrdiff_t)(wp - output);
982+
*wp = '\0';
983+
}
984+
return output_bytes;
968985
}
969986

970987
//--------------------------------------------------------------------------------

ipv6.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,11 @@ bool IPV6_API_DECL(ipv6_from_str_diag) (
210210
// The conversion will flatten zero address components according to the address
211211
// formatting specification. For example: ffff:0:0:0:0:0:0:1 -> ffff::1
212212
//
213+
// Requires output_bytes
214+
// Returns the size in bytes of the string minus the nul byte.
215+
//
213216
// ~~~~
214-
char* IPV6_API_DECL(ipv6_to_str) (
217+
size_t IPV6_API_DECL(ipv6_to_str) (
215218
const ipv6_address_full_t* in,
216219
char* output,
217220
size_t output_bytes);

0 commit comments

Comments
 (0)