diff --git a/libc/src/stdio/printf_files/converter.h b/libc/src/stdio/printf_files/converter.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/printf_files/converter.h @@ -0,0 +1,35 @@ +//===-- Format specifier converter for printf -------------------*- 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_PRINTF_FILES_CONVERTER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_FILES_CONVERTER_H + +#include "src/stdio/printf_files/core_structs.h" +#include "src/stdio/printf_files/writer.h" + +#include + +namespace __llvm_libc { +namespace printf_core { + +class Converter { + Writer *writer; + +public: + Converter(Writer *writer); + + // convert will call a conversion function to convert the FormatSection into + // its string representation, and then that will write the result to the + // writer. + void convert(FormatSection to_conv); +}; + +} // namespace printf_core +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_FILES_CONVERTER_H diff --git a/libc/src/stdio/printf_files/core_structs.h b/libc/src/stdio/printf_files/core_structs.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/printf_files/core_structs.h @@ -0,0 +1,72 @@ +//===-- Core Structures for printf ------------------------------*- 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_PRINTF_FILES_CORE_STRUCTS_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_FILES_CORE_STRUCTS_H + +#include +#include + +namespace __llvm_libc { +namespace printf_core { + +enum class LengthModifier { hh, h, l, ll, j, z, t, L, none }; +enum VariableType : uint8_t { + // Types + + Void = 0x00, + Char = 0x01, + // WChar = 0x02, + // WInt = 0x03, + Short = 0x04, + Int = 0x05, + Long = 0x06, + LLong = 0x07, + Intmax = 0x08, + Size = 0x09, + Ptrdiff = 0x0a, + Double = 0x0b, + LDouble = 0x0c, + + // Modifiers + + Signed = 0x40, + Pointer = 0x80, + + // Masks + + Type_Mask = 0x3f, + Modifier_Mask = 0xc, +}; + +struct FormatSection { + bool has_conv; + + const char *__restrict raw_string; + size_t raw_len; + + // Format Specifier Values + bool left_justified; + bool force_sign; + bool space_prefix; + bool alt_form; + bool leading_zeroes; + LengthModifier length_modifier; + int min_width; + int precision; + + __uint128_t conv_val_raw; // Needs to be large enough to hold a long double. + void *conv_val_ptr; + + char conv_name; +}; + +} // namespace printf_core +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_FILES_CORE_STRUCTS_H diff --git a/libc/src/stdio/printf_files/parser.h b/libc/src/stdio/printf_files/parser.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/printf_files/parser.h @@ -0,0 +1,56 @@ +//===-- Format string parser for printf -------------------------*- 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_PRINTF_FILES_PARSER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_FILES_PARSER_H + +#include "src/stdio/printf_files/core_structs.h" + +#include +#include + +namespace __llvm_libc { +namespace printf_core { + +// TODO: Make this a compile option. +constexpr size_t TYPE_ARR_SIZE = 32; + +class Parser { + const char *__restrict str; + + size_t cur_pos = 0; + + va_list *vlist_start; + va_list *vlist_cur; + size_t vlist_index; + + // TODO: Make this an optional piece. + VariableType type_arr[TYPE_ARR_SIZE]; + + // TODO: Look into object stores for optimization. + +public: + Parser(const char *__restrict str, va_list *vlist); + + // get_next_section will parse the format string until it has a fully + // specified format section. This can either be a raw format section with no + // conversion, or a format section with a conversion that has all of its + // variables stored in the format section. + FormatSection get_next_section(); + +private: + // get_arg_value gets the value from the vlist at index (starting at 1). This + // may require parsing the format string. An index of 0 is interpreted as the + // next value. + template T get_arg_value(size_t index); +}; + +} // namespace printf_core +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_FILES_PARSER_H diff --git a/libc/src/stdio/printf_files/printf_main.h b/libc/src/stdio/printf_files/printf_main.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/printf_files/printf_main.h @@ -0,0 +1,41 @@ +//===-- Starting point for printf -------------------------------*- 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_PRINTF_FILES_PRINTF_MAIN_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_FILES_PRINTF_MAIN_H + +#include "src/stdio/printf_files/converter.h" +#include "src/stdio/printf_files/core_structs.h" +#include "src/stdio/printf_files/parser.h" +#include "src/stdio/printf_files/writer.h" + +#include +#include + +namespace __llvm_libc { +namespace printf_core { + +int printf_main(Writer *writer, const char *__restrict str, va_list vlist) { + Parser parser(str, &vlist); + Converter converter(writer); + + for (FormatSection cur_section = parser.get_next_section(); + cur_section.raw_len > 0; cur_section = parser.get_next_section()) { + if (cur_section.has_conv) + converter.convert(cur_section); + else + writer->write(cur_section.raw_string, cur_section.raw_len); + } + + return writer->get_chars_written(); +} + +} // namespace printf_core +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_FILES_PRINTF_MAIN_H diff --git a/libc/src/stdio/printf_files/writer.h b/libc/src/stdio/printf_files/writer.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/printf_files/writer.h @@ -0,0 +1,51 @@ +//===-- String writer for printf --------------------------------*- 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_PRINTF_FILES_WRITER_H +#define LLVM_LIBC_SRC_STDIO_PRINTF_FILES_WRITER_H + +#include + +namespace __llvm_libc { +namespace printf_core { + +using WriteFunc = void (*)(void *, const char *__restrict, size_t); + +class Writer final { + // output is a pointer to the string or file that the writer is meant to write + // to. + void *output; + + // raw_write is a function that, when called on output with a char* and + // length, will copy the number of bytes equal to the length from the char* + // onto the end of output. + WriteFunc raw_write; + + size_t max_length; + size_t chars_written; + +public: + Writer(void *output, WriteFunc raw_write, size_t max_length); + + // write will copy length bytes from new_string into output using + // raw_write, unless that would cause more bytes than max_length to be + // written. It always increments chars_written by length. + void write(const char *new_string, size_t length); + + // write_chars will copy length copies of new_char into output using raw_write + // unless that would cause more bytes than max_length to be written. It always + // increments chars_written by length. + void write_chars(char new_char, size_t length); + + size_t get_chars_written(); +}; + +} // namespace printf_core +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_PRINTF_FILES_WRITER_H