[libc] Add v variants of printf functions

The v variants of the printf functions take their variadic arguments as
a va_list instead of as individual arguments. They are otherwise
identical to the corresponding printf variants. This patch adds them
(vprintf, vfprintf, vsprintf, and vsnprintf) as well as tests.

Reviewed By: phosek

Differential Revision: https://reviews.llvm.org/D157138
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index df0933f..6cd4f2c 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -543,6 +543,53 @@
 )
 
 add_entrypoint_object(
+  vsprintf
+  SRCS
+    vsprintf.cpp
+  HDRS
+    vsprintf.h
+  DEPENDS
+    libc.src.stdio.printf_core.printf_main
+    libc.src.stdio.printf_core.writer
+)
+
+add_entrypoint_object(
+  vsnprintf
+  SRCS
+    vsnprintf.cpp
+  HDRS
+    vsnprintf.h
+  DEPENDS
+    libc.src.stdio.printf_core.printf_main
+    libc.src.stdio.printf_core.writer
+)
+
+add_entrypoint_object(
+  vprintf
+  SRCS
+    vprintf.cpp
+  HDRS
+    vprintf.h
+  DEPENDS
+    ${printf_deps}
+  COMPILE_OPTIONS
+    ${printf_copts}
+)
+
+add_entrypoint_object(
+  vfprintf
+  SRCS
+    vfprintf.cpp
+  HDRS
+    vfprintf.h
+  DEPENDS
+    libc.src.__support.arg_list
+    libc.src.stdio.printf_core.vfprintf_internal
+  COMPILE_OPTIONS
+    ${printf_copts}
+)
+
+add_entrypoint_object(
   ftell
   SRCS
     ftell.cpp
diff --git a/libc/src/stdio/vfprintf.cpp b/libc/src/stdio/vfprintf.cpp
new file mode 100644
index 0000000..aa56c26
--- /dev/null
+++ b/libc/src/stdio/vfprintf.cpp
@@ -0,0 +1,30 @@
+//===-- Implementation of vfprintf ------------------------------*- C++ -*-===//
+//
+// 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/stdio/vfprintf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/vfprintf_internal.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vfprintf,
+                   (::FILE *__restrict stream, const char *__restrict format,
+                    va_list vlist)) {
+  internal::ArgList args(vlist); // This holder class allows for easier copying
+                                 // and pointer semantics, as well as handling
+                                 // destruction automatically.
+  int ret_val = printf_core::vfprintf_internal(stream, format, args);
+  return ret_val;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/vfprintf.h b/libc/src/stdio/vfprintf.h
new file mode 100644
index 0000000..b4a2d5e
--- /dev/null
+++ b/libc/src/stdio/vfprintf.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of vfprintf -----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_VFPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VFPRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+int vfprintf(::FILE *__restrict stream, const char *__restrict format,
+             va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VFPRINTF_H
diff --git a/libc/src/stdio/vprintf.cpp b/libc/src/stdio/vprintf.cpp
new file mode 100644
index 0000000..d38bf4f
--- /dev/null
+++ b/libc/src/stdio/vprintf.cpp
@@ -0,0 +1,36 @@
+//===-- Implementation of vprintf -------------------------------*- C++ -*-===//
+//
+// 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/stdio/vprintf.h"
+
+#include "src/__support/File/file.h"
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/vfprintf_internal.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifndef LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+#define PRINTF_STDOUT __llvm_libc::stdout
+#else // LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+#define PRINTF_STDOUT ::stdout
+#endif // LIBC_COPT_PRINTF_USE_SYSTEM_FILE
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vprintf,
+                   (const char *__restrict format, va_list vlist)) {
+  internal::ArgList args(vlist); // This holder class allows for easier copying
+                                 // and pointer semantics, as well as handling
+                                 // destruction automatically.
+  int ret_val = printf_core::vfprintf_internal(
+      reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
+  return ret_val;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/vprintf.h b/libc/src/stdio/vprintf.h
new file mode 100644
index 0000000..ffc5d39
--- /dev/null
+++ b/libc/src/stdio/vprintf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of vprintf ------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_VPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VPRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+int vprintf(const char *__restrict format, va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VPRINTF_H
diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp
new file mode 100644
index 0000000..0dc34a8
--- /dev/null
+++ b/libc/src/stdio/vsnprintf.cpp
@@ -0,0 +1,35 @@
+//===-- Implementation of vsnprintf -----------------------------*- C++ -*-===//
+//
+// 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/stdio/vsnprintf.h"
+
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/printf_main.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vsnprintf,
+                   (char *__restrict buffer, size_t buffsz,
+                    const char *__restrict format, va_list vlist)) {
+  internal::ArgList args(vlist); // This holder class allows for easier copying
+                                 // and pointer semantics, as well as handling
+                                 // destruction automatically.
+  printf_core::WriteBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+  printf_core::Writer writer(&wb);
+
+  int ret_val = printf_core::printf_main(&writer, format, args);
+  if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
+    wb.buff[wb.buff_cur] = '\0';
+  return ret_val;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/vsnprintf.h b/libc/src/stdio/vsnprintf.h
new file mode 100644
index 0000000..caa381e
--- /dev/null
+++ b/libc/src/stdio/vsnprintf.h
@@ -0,0 +1,22 @@
+//===-- Implementation header of vsnprintf ----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_VSNPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VSNPRINTF_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+int vsnprintf(char *__restrict buffer, size_t buffsz,
+              const char *__restrict format, va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VSNPRINTF_H
diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp
new file mode 100644
index 0000000..cf86f92
--- /dev/null
+++ b/libc/src/stdio/vsprintf.cpp
@@ -0,0 +1,35 @@
+//===-- Implementation of vsprintf ------------------------------*- C++ -*-===//
+//
+// 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/stdio/vsprintf.h"
+
+#include "src/__support/CPP/limits.h"
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/printf_main.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <stdarg.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, vsprintf,
+                   (char *__restrict buffer, const char *__restrict format,
+                    va_list vlist)) {
+  internal::ArgList args(vlist); // This holder class allows for easier copying
+                                 // and pointer semantics, as well as handling
+                                 // destruction automatically.
+
+  printf_core::WriteBuffer wb(buffer, cpp::numeric_limits<size_t>::max());
+  printf_core::Writer writer(&wb);
+
+  int ret_val = printf_core::printf_main(&writer, format, args);
+  wb.buff[wb.buff_cur] = '\0';
+  return ret_val;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/stdio/vsprintf.h b/libc/src/stdio/vsprintf.h
new file mode 100644
index 0000000..a129a2a
--- /dev/null
+++ b/libc/src/stdio/vsprintf.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of vsprintf -----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_VSPRINTF_H
+#define LLVM_LIBC_SRC_STDIO_VSPRINTF_H
+
+#include <stdarg.h>
+
+namespace __llvm_libc {
+
+int vsprintf(char *__restrict buffer, const char *__restrict format,
+             va_list vlist);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_VSPRINTF_H