ICU-20121 Initial UFormattedList implementation, C.
diff --git a/icu4c/source/i18n/formattedval_iterimpl.cpp b/icu4c/source/i18n/formattedval_iterimpl.cpp
index fc981b3..35ce55c 100644
--- a/icu4c/source/i18n/formattedval_iterimpl.cpp
+++ b/icu4c/source/i18n/formattedval_iterimpl.cpp
@@ -29,9 +29,9 @@
 
 UnicodeString FormattedValueFieldPositionIteratorImpl::toTempString(
         UErrorCode&) const {
-    UnicodeString ret;
-    ret.fastCopyFrom(fString);
-    return ret;
+    // The alias must point to memory owned by this object;
+    // fastCopyFrom doesn't do this when using a stack buffer.
+    return UnicodeString(TRUE, fString.getBuffer(), fString.length());
 }
 
 Appendable& FormattedValueFieldPositionIteratorImpl::appendTo(
diff --git a/icu4c/source/i18n/ulistformatter.cpp b/icu4c/source/i18n/ulistformatter.cpp
index c140c78..e011422 100644
--- a/icu4c/source/i18n/ulistformatter.cpp
+++ b/icu4c/source/i18n/ulistformatter.cpp
@@ -15,6 +15,7 @@
 #include "unicode/listformatter.h"
 #include "unicode/localpointer.h"
 #include "cmemory.h"
+#include "formattedval_impl.h"
 
 U_NAMESPACE_USE
 
@@ -40,6 +41,49 @@
 }
 
 
+// Magic number: FLST in ASCII
+UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
+    FormattedList,
+    UFormattedList,
+    UFormattedListImpl,
+    UFormattedListApiHelper,
+    ulistfmt,
+    0x464C5354)
+
+
+static UnicodeString* getUnicodeStrings(
+        const UChar* const strings[],
+        const int32_t* stringLengths,
+        int32_t stringCount,
+        UnicodeString* length4StackBuffer,
+        LocalArray<UnicodeString>& maybeOwner,
+        UErrorCode& status) {
+    U_ASSERT(U_SUCCESS(status));
+    if (stringCount < 0 || (strings == NULL && stringCount > 0)) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return nullptr;
+    }
+    UnicodeString* ustrings = length4StackBuffer;
+    if (stringCount > 4) {
+        maybeOwner.adoptInsteadAndCheckErrorCode(new UnicodeString[stringCount], status);
+        if (U_FAILURE(status)) {
+            return nullptr;
+        }
+        ustrings = maybeOwner.getAlias();
+    }
+    if (stringLengths == NULL) {
+        for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
+            ustrings[stringIndex].setTo(TRUE, strings[stringIndex], -1);
+        }
+    } else {
+        for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
+            ustrings[stringIndex].setTo(stringLengths[stringIndex] < 0, strings[stringIndex], stringLengths[stringIndex]);
+        }
+    }
+    return ustrings;
+}
+
+
 U_CAPI int32_t U_EXPORT2
 ulistfmt_format(const UListFormatter* listfmt,
                 const UChar* const strings[],
@@ -52,27 +96,16 @@
     if (U_FAILURE(*status)) {
         return -1;
     }
-    if (stringCount < 0 || (strings == NULL && stringCount > 0) || ((result == NULL)? resultCapacity != 0 : resultCapacity < 0)) {
+    if ((result == NULL) ? resultCapacity != 0 : resultCapacity < 0) {
         *status = U_ILLEGAL_ARGUMENT_ERROR;
         return -1;
     }
-    UnicodeString ustringsStackBuf[4];
-    UnicodeString* ustrings = ustringsStackBuf;
-    if (stringCount > UPRV_LENGTHOF(ustringsStackBuf)) {
-        ustrings = new UnicodeString[stringCount];
-        if (ustrings == NULL) {
-            *status = U_MEMORY_ALLOCATION_ERROR;
-            return -1;
-        }
-    }
-    if (stringLengths == NULL) {
-        for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
-            ustrings[stringIndex].setTo(TRUE, strings[stringIndex], -1);
-        }
-    } else {
-        for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
-            ustrings[stringIndex].setTo(stringLengths[stringIndex] < 0, strings[stringIndex], stringLengths[stringIndex]);
-        }
+    UnicodeString length4StackBuffer[4];
+    LocalArray<UnicodeString> maybeOwner;
+    UnicodeString* ustrings = getUnicodeStrings(
+        strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
+    if (U_FAILURE(*status)) {
+        return -1;
     }
     UnicodeString res;
     if (result != NULL) {
@@ -80,12 +113,33 @@
         // otherwise, alias the destination buffer (copied from udat_format)
         res.setTo(result, 0, resultCapacity);
     }
-    ((const ListFormatter*)listfmt)->format( ustrings, stringCount, res, *status );
-    if (ustrings != ustringsStackBuf) {
-        delete[] ustrings;
-    }
+    reinterpret_cast<const ListFormatter*>(listfmt)->format( ustrings, stringCount, res, *status );
     return res.extract(result, resultCapacity, *status);
 }
 
 
+U_CAPI void U_EXPORT2
+ulistfmt_formatStringsToValue(
+                const UListFormatter* listfmt,
+                const UChar* const strings[],
+                const int32_t *    stringLengths,
+                int32_t            stringCount,
+                UFormattedList*    uresult,
+                UErrorCode*        status) {
+    auto* result = UFormattedListApiHelper::validate(uresult, *status);
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    UnicodeString length4StackBuffer[4];
+    LocalArray<UnicodeString> maybeOwner;
+    UnicodeString* ustrings = getUnicodeStrings(
+        strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
+    if (U_FAILURE(*status)) {
+        return;
+    }
+    result->fImpl = reinterpret_cast<const ListFormatter*>(listfmt)
+        ->formatStringsToValue(ustrings, stringCount, *status);
+}
+
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/unicode/ulistformatter.h b/icu4c/source/i18n/unicode/ulistformatter.h
index d794a89..1321ee1 100644
--- a/icu4c/source/i18n/unicode/ulistformatter.h
+++ b/icu4c/source/i18n/unicode/ulistformatter.h
@@ -15,6 +15,7 @@
 #if !UCONFIG_NO_FORMATTING
 
 #include "unicode/localpointer.h"
+#include "unicode/uformattedvalue.h"
 
 /**
  * \file
@@ -33,6 +34,13 @@
 struct UListFormatter;
 typedef struct UListFormatter UListFormatter;  /**< C typedef for struct UListFormatter. @stable ICU 55 */
 
+struct UFormattedList;
+/**
+ * Opaque struct to contain the results of a UListFormatter operation.
+ * @draft ICU 64
+ */
+typedef struct UFormattedList UFormattedList;
+
 #ifndef U_HIDE_DRAFT_API
 /**
  * FieldPosition and UFieldPosition selectors for format fields
@@ -82,6 +90,44 @@
 U_CAPI void U_EXPORT2
 ulistfmt_close(UListFormatter *listfmt);
 
+/**
+ * Creates an object to hold the result of a UListFormatter
+ * operation. The object can be used repeatedly; it is cleared whenever
+ * passed to a format function.
+ *
+ * @param ec Set if an error occurs.
+ * @return A pointer needing ownership.
+ * @draft ICU 64
+ */
+U_CAPI UFormattedList* U_EXPORT2
+ulistfmt_openResult(UErrorCode* ec);
+
+/**
+ * Returns a representation of a UFormattedList as a UFormattedValue,
+ * which can be subsequently passed to any API requiring that type.
+ *
+ * The returned object is owned by the UFormattedList and is valid
+ * only as long as the UFormattedList is present and unchanged in memory.
+ *
+ * You can think of this method as a cast between types.
+ *
+ * @param uresult The object containing the formatted string.
+ * @param ec Set if an error occurs.
+ * @return A UFormattedValue owned by the input object.
+ * @draft ICU 64
+ */
+U_CAPI const UFormattedValue* U_EXPORT2
+ulistfmt_resultAsValue(const UFormattedList* uresult, UErrorCode* ec);
+
+/**
+ * Releases the UFormattedList created by ulistfmt_openResult().
+ *
+ * @param uresult The object to release.
+ * @draft ICU 64
+ */
+U_CAPI void U_EXPORT2
+ulistfmt_closeResult(UFormattedList* uresult);
+
 
 #if U_SHOW_CPLUSPLUS_API
 
@@ -98,6 +144,17 @@
  */
 U_DEFINE_LOCAL_OPEN_POINTER(LocalUListFormatterPointer, UListFormatter, ulistfmt_close);
 
+/**
+ * \class LocalUFormattedListPointer
+ * "Smart pointer" class, closes a UFormattedList via ulistfmt_closeResult().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 55
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedListPointer, UFormattedList, ulistfmt_closeResult);
+
 U_NAMESPACE_END
 
 #endif
@@ -145,6 +202,40 @@
                 int32_t            resultCapacity,
                 UErrorCode*        status);
 
+/**
+ * Formats a list of strings to a UFormattedList, which exposes more
+ * information than the string exported by ulistfmt_format().
+ *
+ * @param listfmt
+ *            The UListFormatter object specifying the list conventions.
+ * @param strings
+ *            An array of pointers to UChar strings; the array length is
+ *            specified by stringCount. Must be non-NULL if stringCount > 0.
+ * @param stringLengths
+ *            An array of string lengths corresponding to the strings[]
+ *            parameter; any individual length value may be negative to indicate
+ *            that the corresponding strings[] entry is 0-terminated, or
+ *            stringLengths itself may be NULL if all of the strings are
+ *            0-terminated. If non-NULL, the stringLengths array must have
+ *            stringCount entries.
+ * @param stringCount
+ *            the number of entries in strings[], and the number of entries
+ *            in the stringLengths array if it is not NULL. Must be >= 0.
+ * @param uresult
+ *            The object in which to store the result of the list formatting
+ *            operation. See ulistfmt_openResult().
+ * @param status
+ *            Error code set if an error occurred during formatting.
+ */
+U_CAPI void U_EXPORT2
+ulistfmt_formatStringsToValue(
+                const UListFormatter* listfmt,
+                const UChar* const strings[],
+                const int32_t *    stringLengths,
+                int32_t            stringCount,
+                UFormattedList*    uresult,
+                UErrorCode*        status);
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
 
 #endif
diff --git a/icu4c/source/test/cintltst/ulistfmttest.c b/icu4c/source/test/cintltst/ulistfmttest.c
index 165bff4..e2e5a80 100644
--- a/icu4c/source/test/cintltst/ulistfmttest.c
+++ b/icu4c/source/test/cintltst/ulistfmttest.c
@@ -15,8 +15,10 @@
 #include "cintltst.h"
 #include "cmemory.h"
 #include "cstring.h"
+#include "cformtst.h"
 
 static void TestUListFmt(void);
+static void TestUListFmtToValue(void);
 
 void addUListFmtTest(TestNode** root);
 
@@ -25,6 +27,7 @@
 void addUListFmtTest(TestNode** root)
 {
     TESTCASE(TestUListFmt);
+    TESTCASE(TestUListFmtToValue);
 }
 
 static const UChar str0[] = { 0x41,0 }; /* "A" */
@@ -126,5 +129,76 @@
     }
 }
 
+static void TestUListFmtToValue() {
+    UErrorCode ec = U_ZERO_ERROR;
+    UListFormatter* fmt = ulistfmt_open("en", &ec);
+    UFormattedList* fl = ulistfmt_openResult(&ec);
+    assertSuccess("Opening", &ec);
+
+    {
+        const char* message = "Field position test 1";
+        const UChar* expectedString = u"hello, wonderful, and world";
+        const UChar* inputs[] = {
+            u"hello",
+            u"wonderful",
+            u"world"
+        };
+        ulistfmt_formatStringsToValue(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
+        assertSuccess("Formatting", &ec);
+        static const UFieldPositionWithCategory expectedFieldPositions[] = {
+            // field, begin index, end index
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 5},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 7, 16},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 27},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 5, 7},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22}};
+        checkMixedFormattedValue(
+            message,
+            ulistfmt_resultAsValue(fl, &ec),
+            expectedString,
+            expectedFieldPositions,
+            UPRV_LENGTHOF(expectedFieldPositions));
+    }
+    {
+        const char* message = "Field position test 1";
+        const UChar* expectedString = u"A, B, C, D, E, F, and G";
+        const UChar* inputs[] = {
+            u"A",
+            u"B",
+            u"C",
+            u"D",
+            u"E",
+            u"F",
+            u"G"
+        };
+        ulistfmt_formatStringsToValue(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
+        assertSuccess("Formatting", &ec);
+        static const UFieldPositionWithCategory expectedFieldPositions[] = {
+            // field, begin index, end index
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0,  1},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 3,  4},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 6,  7},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 9,  10},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 12, 13},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 15, 16},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 23},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 1,  3},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 4,  6},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 7,  9},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 10, 12},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 13, 15},
+            {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22}};
+        checkMixedFormattedValue(
+            message,
+            ulistfmt_resultAsValue(fl, &ec),
+            expectedString,
+            expectedFieldPositions,
+            UPRV_LENGTHOF(expectedFieldPositions));
+    }
+
+    ulistfmt_close(fmt);
+    ulistfmt_closeResult(fl);
+}
+
 
 #endif /* #if !UCONFIG_NO_FORMATTING */