diff --git a/libraries/AP_Common/ExpandingString.cpp b/libraries/AP_Common/ExpandingString.cpp
new file mode 100644
index 0000000000..c6a701eec3
--- /dev/null
+++ b/libraries/AP_Common/ExpandingString.cpp
@@ -0,0 +1,102 @@
+/*
+ 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 3 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, see .
+ */
+/*
+ expanding string for easy construction of text buffers
+ */
+
+#include "ExpandingString.h"
+
+extern const AP_HAL::HAL& hal;
+
+#define EXPAND_INCREMENT 512
+
+/*
+ expand the string buffer
+ */
+bool ExpandingString::expand(uint32_t min_extra_space_needed)
+{
+ // expand a reasonable amount
+ uint32_t newsize = (5*buflen/4) + EXPAND_INCREMENT;
+ if (newsize - used < min_extra_space_needed) {
+ newsize = used + min_extra_space_needed;
+ }
+
+ // add one to ensure we are always null terminated
+ void *newbuf = hal.util->std_realloc(buf, newsize+1);
+
+ if (newbuf == nullptr) {
+ allocation_failed = true;
+ return false;
+ }
+
+ buflen = newsize;
+ buf = (char *)newbuf;
+
+ return true;
+}
+
+/*
+ print into the buffer, expanding if needed
+ */
+void ExpandingString::printf(const char *format, ...)
+{
+ if (allocation_failed) {
+ return;
+ }
+ if (buflen == used && !expand(0)) {
+ return;
+ }
+ int n;
+
+ /*
+ print into the buffer, expanding the buffer if needed
+ */
+ while (true) {
+ va_list arg;
+ va_start(arg, format);
+ n = hal.util->vsnprintf(&buf[used], buflen-used, format, arg);
+ va_end(arg);
+ if (n < 0) {
+ return;
+ }
+ if (uint32_t(n) < buflen - used) {
+ break;
+ }
+ if (!expand(n+1)) {
+ return;
+ }
+ }
+ used += n;
+}
+
+/*
+ print into the buffer, expanding if needed
+ */
+void ExpandingString::append(const char *s, uint32_t len)
+{
+ if (allocation_failed) {
+ return;
+ }
+ if (buflen - used < len && !expand(len)) {
+ return;
+ }
+ memcpy(&buf[used], s, len);
+ used += len;
+}
+
+ExpandingString::~ExpandingString()
+{
+ free(buf);
+}
diff --git a/libraries/AP_Common/ExpandingString.h b/libraries/AP_Common/ExpandingString.h
new file mode 100644
index 0000000000..54a124def0
--- /dev/null
+++ b/libraries/AP_Common/ExpandingString.h
@@ -0,0 +1,54 @@
+/*
+ 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 3 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, see .
+ */
+/*
+ expanding string for easy construction of text buffers
+ */
+
+#pragma once
+
+#include
+
+class ExpandingString {
+public:
+
+ const char *get_string(void) const {
+ return buf;
+ }
+ uint32_t get_length(void) const {
+ return used;
+ }
+
+ // print into the string
+ void printf(const char *format, ...) FMT_PRINTF(2,3);
+
+ // append data to the string
+ void append(const char *s, uint32_t len);
+
+ // destructor
+ ~ExpandingString();
+
+ bool has_failed_allocation() const {
+ return allocation_failed;
+ }
+
+private:
+ char *buf;
+ uint32_t buflen;
+ uint32_t used;
+ bool allocation_failed;
+
+ // try to expand the buffer
+ bool expand(uint32_t min_needed) WARN_IF_UNUSED;
+};