/ externals / fmt / include / fmt / printf.h
printf.h
  1  // Formatting library for C++ - legacy printf implementation
  2  //
  3  // Copyright (c) 2012 - 2016, Victor Zverovich
  4  // All rights reserved.
  5  //
  6  // For the license information refer to format.h.
  7  
  8  #ifndef FMT_PRINTF_H_
  9  #define FMT_PRINTF_H_
 10  
 11  #include <algorithm>  // std::max
 12  #include <limits>     // std::numeric_limits
 13  
 14  #include "format.h"
 15  
 16  FMT_BEGIN_NAMESPACE
 17  FMT_BEGIN_EXPORT
 18  
 19  template <typename T> struct printf_formatter { printf_formatter() = delete; };
 20  
 21  template <typename Char> class basic_printf_context {
 22   private:
 23    detail::buffer_appender<Char> out_;
 24    basic_format_args<basic_printf_context> args_;
 25  
 26   public:
 27    using char_type = Char;
 28    using parse_context_type = basic_format_parse_context<Char>;
 29    template <typename T> using formatter_type = printf_formatter<T>;
 30  
 31    /**
 32      \rst
 33      Constructs a ``printf_context`` object. References to the arguments are
 34      stored in the context object so make sure they have appropriate lifetimes.
 35      \endrst
 36     */
 37    basic_printf_context(detail::buffer_appender<Char> out,
 38                         basic_format_args<basic_printf_context> args)
 39        : out_(out), args_(args) {}
 40  
 41    auto out() -> detail::buffer_appender<Char> { return out_; }
 42    void advance_to(detail::buffer_appender<Char>) {}
 43  
 44    auto locale() -> detail::locale_ref { return {}; }
 45  
 46    auto arg(int id) const -> basic_format_arg<basic_printf_context> {
 47      return args_.get(id);
 48    }
 49  
 50    FMT_CONSTEXPR void on_error(const char* message) {
 51      detail::error_handler().on_error(message);
 52    }
 53  };
 54  
 55  namespace detail {
 56  
 57  // Checks if a value fits in int - used to avoid warnings about comparing
 58  // signed and unsigned integers.
 59  template <bool IsSigned> struct int_checker {
 60    template <typename T> static auto fits_in_int(T value) -> bool {
 61      unsigned max = max_value<int>();
 62      return value <= max;
 63    }
 64    static auto fits_in_int(bool) -> bool { return true; }
 65  };
 66  
 67  template <> struct int_checker<true> {
 68    template <typename T> static auto fits_in_int(T value) -> bool {
 69      return value >= (std::numeric_limits<int>::min)() &&
 70             value <= max_value<int>();
 71    }
 72    static auto fits_in_int(int) -> bool { return true; }
 73  };
 74  
 75  struct printf_precision_handler {
 76    template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
 77    auto operator()(T value) -> int {
 78      if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
 79        throw_format_error("number is too big");
 80      return (std::max)(static_cast<int>(value), 0);
 81    }
 82  
 83    template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
 84    auto operator()(T) -> int {
 85      throw_format_error("precision is not integer");
 86      return 0;
 87    }
 88  };
 89  
 90  // An argument visitor that returns true iff arg is a zero integer.
 91  struct is_zero_int {
 92    template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
 93    auto operator()(T value) -> bool {
 94      return value == 0;
 95    }
 96  
 97    template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
 98    auto operator()(T) -> bool {
 99      return false;
100    }
101  };
102  
103  template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
104  
105  template <> struct make_unsigned_or_bool<bool> { using type = bool; };
106  
107  template <typename T, typename Context> class arg_converter {
108   private:
109    using char_type = typename Context::char_type;
110  
111    basic_format_arg<Context>& arg_;
112    char_type type_;
113  
114   public:
115    arg_converter(basic_format_arg<Context>& arg, char_type type)
116        : arg_(arg), type_(type) {}
117  
118    void operator()(bool value) {
119      if (type_ != 's') operator()<bool>(value);
120    }
121  
122    template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
123    void operator()(U value) {
124      bool is_signed = type_ == 'd' || type_ == 'i';
125      using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
126      if (const_check(sizeof(target_type) <= sizeof(int))) {
127        // Extra casts are used to silence warnings.
128        if (is_signed) {
129          auto n = static_cast<int>(static_cast<target_type>(value));
130          arg_ = detail::make_arg<Context>(n);
131        } else {
132          using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
133          auto n = static_cast<unsigned>(static_cast<unsigned_type>(value));
134          arg_ = detail::make_arg<Context>(n);
135        }
136      } else {
137        if (is_signed) {
138          // glibc's printf doesn't sign extend arguments of smaller types:
139          //   std::printf("%lld", -42);  // prints "4294967254"
140          // but we don't have to do the same because it's a UB.
141          auto n = static_cast<long long>(value);
142          arg_ = detail::make_arg<Context>(n);
143        } else {
144          auto n = static_cast<typename make_unsigned_or_bool<U>::type>(value);
145          arg_ = detail::make_arg<Context>(n);
146        }
147      }
148    }
149  
150    template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)>
151    void operator()(U) {}  // No conversion needed for non-integral types.
152  };
153  
154  // Converts an integer argument to T for printf, if T is an integral type.
155  // If T is void, the argument is converted to corresponding signed or unsigned
156  // type depending on the type specifier: 'd' and 'i' - signed, other -
157  // unsigned).
158  template <typename T, typename Context, typename Char>
159  void convert_arg(basic_format_arg<Context>& arg, Char type) {
160    visit_format_arg(arg_converter<T, Context>(arg, type), arg);
161  }
162  
163  // Converts an integer argument to char for printf.
164  template <typename Context> class char_converter {
165   private:
166    basic_format_arg<Context>& arg_;
167  
168   public:
169    explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
170  
171    template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
172    void operator()(T value) {
173      auto c = static_cast<typename Context::char_type>(value);
174      arg_ = detail::make_arg<Context>(c);
175    }
176  
177    template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
178    void operator()(T) {}  // No conversion needed for non-integral types.
179  };
180  
181  // An argument visitor that return a pointer to a C string if argument is a
182  // string or null otherwise.
183  template <typename Char> struct get_cstring {
184    template <typename T> auto operator()(T) -> const Char* { return nullptr; }
185    auto operator()(const Char* s) -> const Char* { return s; }
186  };
187  
188  // Checks if an argument is a valid printf width specifier and sets
189  // left alignment if it is negative.
190  template <typename Char> class printf_width_handler {
191   private:
192    format_specs<Char>& specs_;
193  
194   public:
195    explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {}
196  
197    template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
198    auto operator()(T value) -> unsigned {
199      auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
200      if (detail::is_negative(value)) {
201        specs_.align = align::left;
202        width = 0 - width;
203      }
204      unsigned int_max = max_value<int>();
205      if (width > int_max) throw_format_error("number is too big");
206      return static_cast<unsigned>(width);
207    }
208  
209    template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
210    auto operator()(T) -> unsigned {
211      throw_format_error("width is not integer");
212      return 0;
213    }
214  };
215  
216  // Workaround for a bug with the XL compiler when initializing
217  // printf_arg_formatter's base class.
218  template <typename Char>
219  auto make_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s)
220      -> arg_formatter<Char> {
221    return {iter, s, locale_ref()};
222  }
223  
224  // The ``printf`` argument formatter.
225  template <typename Char>
226  class printf_arg_formatter : public arg_formatter<Char> {
227   private:
228    using base = arg_formatter<Char>;
229    using context_type = basic_printf_context<Char>;
230  
231    context_type& context_;
232  
233    void write_null_pointer(bool is_string = false) {
234      auto s = this->specs;
235      s.type = presentation_type::none;
236      write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
237    }
238  
239   public:
240    printf_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s,
241                         context_type& ctx)
242        : base(make_arg_formatter(iter, s)), context_(ctx) {}
243  
244    void operator()(monostate value) { base::operator()(value); }
245  
246    template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
247    void operator()(T value) {
248      // MSVC2013 fails to compile separate overloads for bool and Char so use
249      // std::is_same instead.
250      if (!std::is_same<T, Char>::value) {
251        base::operator()(value);
252        return;
253      }
254      format_specs<Char> fmt_specs = this->specs;
255      if (fmt_specs.type != presentation_type::none &&
256          fmt_specs.type != presentation_type::chr) {
257        return (*this)(static_cast<int>(value));
258      }
259      fmt_specs.sign = sign::none;
260      fmt_specs.alt = false;
261      fmt_specs.fill[0] = ' ';  // Ignore '0' flag for char types.
262      // align::numeric needs to be overwritten here since the '0' flag is
263      // ignored for non-numeric types
264      if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
265        fmt_specs.align = align::right;
266      write<Char>(this->out, static_cast<Char>(value), fmt_specs);
267    }
268  
269    template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
270    void operator()(T value) {
271      base::operator()(value);
272    }
273  
274    /** Formats a null-terminated C string. */
275    void operator()(const char* value) {
276      if (value)
277        base::operator()(value);
278      else
279        write_null_pointer(this->specs.type != presentation_type::pointer);
280    }
281  
282    /** Formats a null-terminated wide C string. */
283    void operator()(const wchar_t* value) {
284      if (value)
285        base::operator()(value);
286      else
287        write_null_pointer(this->specs.type != presentation_type::pointer);
288    }
289  
290    void operator()(basic_string_view<Char> value) { base::operator()(value); }
291  
292    /** Formats a pointer. */
293    void operator()(const void* value) {
294      if (value)
295        base::operator()(value);
296      else
297        write_null_pointer();
298    }
299  
300    /** Formats an argument of a custom (user-defined) type. */
301    void operator()(typename basic_format_arg<context_type>::handle handle) {
302      auto parse_ctx = basic_format_parse_context<Char>({});
303      handle.format(parse_ctx, context_);
304    }
305  };
306  
307  template <typename Char>
308  void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) {
309    for (; it != end; ++it) {
310      switch (*it) {
311      case '-':
312        specs.align = align::left;
313        break;
314      case '+':
315        specs.sign = sign::plus;
316        break;
317      case '0':
318        specs.fill[0] = '0';
319        break;
320      case ' ':
321        if (specs.sign != sign::plus) specs.sign = sign::space;
322        break;
323      case '#':
324        specs.alt = true;
325        break;
326      default:
327        return;
328      }
329    }
330  }
331  
332  template <typename Char, typename GetArg>
333  auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
334                    GetArg get_arg) -> int {
335    int arg_index = -1;
336    Char c = *it;
337    if (c >= '0' && c <= '9') {
338      // Parse an argument index (if followed by '$') or a width possibly
339      // preceded with '0' flag(s).
340      int value = parse_nonnegative_int(it, end, -1);
341      if (it != end && *it == '$') {  // value is an argument index
342        ++it;
343        arg_index = value != -1 ? value : max_value<int>();
344      } else {
345        if (c == '0') specs.fill[0] = '0';
346        if (value != 0) {
347          // Nonzero value means that we parsed width and don't need to
348          // parse it or flags again, so return now.
349          if (value == -1) throw_format_error("number is too big");
350          specs.width = value;
351          return arg_index;
352        }
353      }
354    }
355    parse_flags(specs, it, end);
356    // Parse width.
357    if (it != end) {
358      if (*it >= '0' && *it <= '9') {
359        specs.width = parse_nonnegative_int(it, end, -1);
360        if (specs.width == -1) throw_format_error("number is too big");
361      } else if (*it == '*') {
362        ++it;
363        specs.width = static_cast<int>(visit_format_arg(
364            detail::printf_width_handler<Char>(specs), get_arg(-1)));
365      }
366    }
367    return arg_index;
368  }
369  
370  inline auto parse_printf_presentation_type(char c, type t)
371      -> presentation_type {
372    using pt = presentation_type;
373    constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
374    switch (c) {
375    case 'd':
376      return in(t, integral_set) ? pt::dec : pt::none;
377    case 'o':
378      return in(t, integral_set) ? pt::oct : pt::none;
379    case 'x':
380      return in(t, integral_set) ? pt::hex_lower : pt::none;
381    case 'X':
382      return in(t, integral_set) ? pt::hex_upper : pt::none;
383    case 'a':
384      return in(t, float_set) ? pt::hexfloat_lower : pt::none;
385    case 'A':
386      return in(t, float_set) ? pt::hexfloat_upper : pt::none;
387    case 'e':
388      return in(t, float_set) ? pt::exp_lower : pt::none;
389    case 'E':
390      return in(t, float_set) ? pt::exp_upper : pt::none;
391    case 'f':
392      return in(t, float_set) ? pt::fixed_lower : pt::none;
393    case 'F':
394      return in(t, float_set) ? pt::fixed_upper : pt::none;
395    case 'g':
396      return in(t, float_set) ? pt::general_lower : pt::none;
397    case 'G':
398      return in(t, float_set) ? pt::general_upper : pt::none;
399    case 'c':
400      return in(t, integral_set) ? pt::chr : pt::none;
401    case 's':
402      return in(t, string_set | cstring_set) ? pt::string : pt::none;
403    case 'p':
404      return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
405    default:
406      return pt::none;
407    }
408  }
409  
410  template <typename Char, typename Context>
411  void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
412               basic_format_args<Context> args) {
413    using iterator = buffer_appender<Char>;
414    auto out = iterator(buf);
415    auto context = basic_printf_context<Char>(out, args);
416    auto parse_ctx = basic_format_parse_context<Char>(format);
417  
418    // Returns the argument with specified index or, if arg_index is -1, the next
419    // argument.
420    auto get_arg = [&](int arg_index) {
421      if (arg_index < 0)
422        arg_index = parse_ctx.next_arg_id();
423      else
424        parse_ctx.check_arg_id(--arg_index);
425      return detail::get_arg(context, arg_index);
426    };
427  
428    const Char* start = parse_ctx.begin();
429    const Char* end = parse_ctx.end();
430    auto it = start;
431    while (it != end) {
432      if (!find<false, Char>(it, end, '%', it)) {
433        it = end;  // find leaves it == nullptr if it doesn't find '%'.
434        break;
435      }
436      Char c = *it++;
437      if (it != end && *it == c) {
438        write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
439        start = ++it;
440        continue;
441      }
442      write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
443  
444      auto specs = format_specs<Char>();
445      specs.align = align::right;
446  
447      // Parse argument index, flags and width.
448      int arg_index = parse_header(it, end, specs, get_arg);
449      if (arg_index == 0) throw_format_error("argument not found");
450  
451      // Parse precision.
452      if (it != end && *it == '.') {
453        ++it;
454        c = it != end ? *it : 0;
455        if ('0' <= c && c <= '9') {
456          specs.precision = parse_nonnegative_int(it, end, 0);
457        } else if (c == '*') {
458          ++it;
459          specs.precision = static_cast<int>(
460              visit_format_arg(printf_precision_handler(), get_arg(-1)));
461        } else {
462          specs.precision = 0;
463        }
464      }
465  
466      auto arg = get_arg(arg_index);
467      // For d, i, o, u, x, and X conversion specifiers, if a precision is
468      // specified, the '0' flag is ignored
469      if (specs.precision >= 0 && arg.is_integral()) {
470        // Ignore '0' for non-numeric types or if '-' present.
471        specs.fill[0] = ' ';
472      }
473      if (specs.precision >= 0 && arg.type() == type::cstring_type) {
474        auto str = visit_format_arg(get_cstring<Char>(), arg);
475        auto str_end = str + specs.precision;
476        auto nul = std::find(str, str_end, Char());
477        auto sv = basic_string_view<Char>(
478            str, to_unsigned(nul != str_end ? nul - str : specs.precision));
479        arg = make_arg<basic_printf_context<Char>>(sv);
480      }
481      if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false;
482      if (specs.fill[0] == '0') {
483        if (arg.is_arithmetic() && specs.align != align::left)
484          specs.align = align::numeric;
485        else
486          specs.fill[0] = ' ';  // Ignore '0' flag for non-numeric types or if '-'
487                                // flag is also present.
488      }
489  
490      // Parse length and convert the argument to the required type.
491      c = it != end ? *it++ : 0;
492      Char t = it != end ? *it : 0;
493      switch (c) {
494      case 'h':
495        if (t == 'h') {
496          ++it;
497          t = it != end ? *it : 0;
498          convert_arg<signed char>(arg, t);
499        } else {
500          convert_arg<short>(arg, t);
501        }
502        break;
503      case 'l':
504        if (t == 'l') {
505          ++it;
506          t = it != end ? *it : 0;
507          convert_arg<long long>(arg, t);
508        } else {
509          convert_arg<long>(arg, t);
510        }
511        break;
512      case 'j':
513        convert_arg<intmax_t>(arg, t);
514        break;
515      case 'z':
516        convert_arg<size_t>(arg, t);
517        break;
518      case 't':
519        convert_arg<std::ptrdiff_t>(arg, t);
520        break;
521      case 'L':
522        // printf produces garbage when 'L' is omitted for long double, no
523        // need to do the same.
524        break;
525      default:
526        --it;
527        convert_arg<void>(arg, c);
528      }
529  
530      // Parse type.
531      if (it == end) throw_format_error("invalid format string");
532      char type = static_cast<char>(*it++);
533      if (arg.is_integral()) {
534        // Normalize type.
535        switch (type) {
536        case 'i':
537        case 'u':
538          type = 'd';
539          break;
540        case 'c':
541          visit_format_arg(char_converter<basic_printf_context<Char>>(arg), arg);
542          break;
543        }
544      }
545      specs.type = parse_printf_presentation_type(type, arg.type());
546      if (specs.type == presentation_type::none)
547        throw_format_error("invalid format specifier");
548  
549      start = it;
550  
551      // Format argument.
552      visit_format_arg(printf_arg_formatter<Char>(out, specs, context), arg);
553    }
554    write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
555  }
556  }  // namespace detail
557  
558  using printf_context = basic_printf_context<char>;
559  using wprintf_context = basic_printf_context<wchar_t>;
560  
561  using printf_args = basic_format_args<printf_context>;
562  using wprintf_args = basic_format_args<wprintf_context>;
563  
564  /**
565    \rst
566    Constructs an `~fmt::format_arg_store` object that contains references to
567    arguments and can be implicitly converted to `~fmt::printf_args`.
568    \endrst
569   */
570  template <typename... T>
571  inline auto make_printf_args(const T&... args)
572      -> format_arg_store<printf_context, T...> {
573    return {args...};
574  }
575  
576  // DEPRECATED!
577  template <typename... T>
578  inline auto make_wprintf_args(const T&... args)
579      -> format_arg_store<wprintf_context, T...> {
580    return {args...};
581  }
582  
583  template <typename Char>
584  inline auto vsprintf(
585      basic_string_view<Char> fmt,
586      basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
587      -> std::basic_string<Char> {
588    auto buf = basic_memory_buffer<Char>();
589    detail::vprintf(buf, fmt, args);
590    return to_string(buf);
591  }
592  
593  /**
594    \rst
595    Formats arguments and returns the result as a string.
596  
597    **Example**::
598  
599      std::string message = fmt::sprintf("The answer is %d", 42);
600    \endrst
601  */
602  template <typename S, typename... T,
603            typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
604  inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
605    return vsprintf(detail::to_string_view(fmt),
606                    fmt::make_format_args<basic_printf_context<Char>>(args...));
607  }
608  
609  template <typename Char>
610  inline auto vfprintf(
611      std::FILE* f, basic_string_view<Char> fmt,
612      basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
613      -> int {
614    auto buf = basic_memory_buffer<Char>();
615    detail::vprintf(buf, fmt, args);
616    size_t size = buf.size();
617    return std::fwrite(buf.data(), sizeof(Char), size, f) < size
618               ? -1
619               : static_cast<int>(size);
620  }
621  
622  /**
623    \rst
624    Prints formatted data to the file *f*.
625  
626    **Example**::
627  
628      fmt::fprintf(stderr, "Don't %s!", "panic");
629    \endrst
630   */
631  template <typename S, typename... T, typename Char = char_t<S>>
632  inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
633    return vfprintf(f, detail::to_string_view(fmt),
634                    fmt::make_format_args<basic_printf_context<Char>>(args...));
635  }
636  
637  template <typename Char>
638  FMT_DEPRECATED inline auto vprintf(
639      basic_string_view<Char> fmt,
640      basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
641      -> int {
642    return vfprintf(stdout, fmt, args);
643  }
644  
645  /**
646    \rst
647    Prints formatted data to ``stdout``.
648  
649    **Example**::
650  
651      fmt::printf("Elapsed time: %.2f seconds", 1.23);
652    \endrst
653   */
654  template <typename... T>
655  inline auto printf(string_view fmt, const T&... args) -> int {
656    return vfprintf(stdout, fmt, make_printf_args(args...));
657  }
658  template <typename... T>
659  FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt,
660                                    const T&... args) -> int {
661    return vfprintf(stdout, fmt, make_wprintf_args(args...));
662  }
663  
664  FMT_END_EXPORT
665  FMT_END_NAMESPACE
666  
667  #endif  // FMT_PRINTF_H_