bind.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright 2020 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "absl/strings/internal/str_format/bind.h"
  15. #include <algorithm>
  16. #include <cassert>
  17. #include <cerrno>
  18. #include <cstddef>
  19. #include <cstdio>
  20. #include <ios>
  21. #include <limits>
  22. #include <ostream>
  23. #include <sstream>
  24. #include <string>
  25. #include "absl/base/config.h"
  26. #include "absl/base/optimization.h"
  27. #include "absl/strings/internal/str_format/arg.h"
  28. #include "absl/strings/internal/str_format/constexpr_parser.h"
  29. #include "absl/strings/internal/str_format/extension.h"
  30. #include "absl/strings/internal/str_format/output.h"
  31. #include "absl/strings/string_view.h"
  32. #include "absl/types/span.h"
  33. namespace absl {
  34. ABSL_NAMESPACE_BEGIN
  35. namespace str_format_internal {
  36. namespace {
  37. inline bool BindFromPosition(int position, int* value,
  38. absl::Span<const FormatArgImpl> pack) {
  39. assert(position > 0);
  40. if (static_cast<size_t>(position) > pack.size()) {
  41. return false;
  42. }
  43. // -1 because positions are 1-based
  44. return FormatArgImplFriend::ToInt(pack[static_cast<size_t>(position) - 1],
  45. value);
  46. }
  47. class ArgContext {
  48. public:
  49. explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
  50. // Fill 'bound' with the results of applying the context's argument pack
  51. // to the specified 'unbound'. We synthesize a BoundConversion by
  52. // lining up a UnboundConversion with a user argument. We also
  53. // resolve any '*' specifiers for width and precision, so after
  54. // this call, 'bound' has all the information it needs to be formatted.
  55. // Returns false on failure.
  56. bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
  57. private:
  58. absl::Span<const FormatArgImpl> pack_;
  59. };
  60. inline bool ArgContext::Bind(const UnboundConversion* unbound,
  61. BoundConversion* bound) {
  62. const FormatArgImpl* arg = nullptr;
  63. int arg_position = unbound->arg_position;
  64. if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
  65. arg = &pack_[static_cast<size_t>(arg_position - 1)]; // 1-based
  66. if (unbound->flags != Flags::kBasic) {
  67. int width = unbound->width.value();
  68. bool force_left = false;
  69. if (unbound->width.is_from_arg()) {
  70. if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
  71. return false;
  72. if (width < 0) {
  73. // "A negative field width is taken as a '-' flag followed by a
  74. // positive field width."
  75. force_left = true;
  76. // Make sure we don't overflow the width when negating it.
  77. width = -std::max(width, -std::numeric_limits<int>::max());
  78. }
  79. }
  80. int precision = unbound->precision.value();
  81. if (unbound->precision.is_from_arg()) {
  82. if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
  83. pack_))
  84. return false;
  85. }
  86. FormatConversionSpecImplFriend::SetWidth(width, bound);
  87. FormatConversionSpecImplFriend::SetPrecision(precision, bound);
  88. if (force_left) {
  89. FormatConversionSpecImplFriend::SetFlags(unbound->flags | Flags::kLeft,
  90. bound);
  91. } else {
  92. FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
  93. }
  94. FormatConversionSpecImplFriend::SetLengthMod(unbound->length_mod, bound);
  95. } else {
  96. FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
  97. FormatConversionSpecImplFriend::SetWidth(-1, bound);
  98. FormatConversionSpecImplFriend::SetPrecision(-1, bound);
  99. }
  100. FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound);
  101. bound->set_arg(arg);
  102. return true;
  103. }
  104. template <typename Converter>
  105. class ConverterConsumer {
  106. public:
  107. ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
  108. : converter_(converter), arg_context_(pack) {}
  109. bool Append(string_view s) {
  110. converter_.Append(s);
  111. return true;
  112. }
  113. bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
  114. BoundConversion bound;
  115. if (!arg_context_.Bind(&conv, &bound)) return false;
  116. return converter_.ConvertOne(bound, conv_string);
  117. }
  118. private:
  119. Converter converter_;
  120. ArgContext arg_context_;
  121. };
  122. template <typename Converter>
  123. bool ConvertAll(const UntypedFormatSpecImpl format,
  124. absl::Span<const FormatArgImpl> args, Converter converter) {
  125. if (format.has_parsed_conversion()) {
  126. return format.parsed_conversion()->ProcessFormat(
  127. ConverterConsumer<Converter>(converter, args));
  128. } else {
  129. return ParseFormatString(format.str(),
  130. ConverterConsumer<Converter>(converter, args));
  131. }
  132. }
  133. class DefaultConverter {
  134. public:
  135. explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
  136. void Append(string_view s) const { sink_->Append(s); }
  137. bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
  138. return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
  139. }
  140. private:
  141. FormatSinkImpl* sink_;
  142. };
  143. class SummarizingConverter {
  144. public:
  145. explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
  146. void Append(string_view s) const { sink_->Append(s); }
  147. bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
  148. UntypedFormatSpecImpl spec("%d");
  149. std::ostringstream ss;
  150. ss << "{" << Streamable(spec, {*bound.arg()}) << ":"
  151. << FormatConversionSpecImplFriend::FlagsToString(bound);
  152. if (bound.width() >= 0) ss << bound.width();
  153. if (bound.precision() >= 0) ss << "." << bound.precision();
  154. ss << bound.conversion_char() << "}";
  155. Append(ss.str());
  156. return true;
  157. }
  158. private:
  159. FormatSinkImpl* sink_;
  160. };
  161. } // namespace
  162. bool BindWithPack(const UnboundConversion* props,
  163. absl::Span<const FormatArgImpl> pack,
  164. BoundConversion* bound) {
  165. return ArgContext(pack).Bind(props, bound);
  166. }
  167. std::string Summarize(const UntypedFormatSpecImpl format,
  168. absl::Span<const FormatArgImpl> args) {
  169. typedef SummarizingConverter Converter;
  170. std::string out;
  171. {
  172. // inner block to destroy sink before returning out. It ensures a last
  173. // flush.
  174. FormatSinkImpl sink(&out);
  175. if (!ConvertAll(format, args, Converter(&sink))) {
  176. return "";
  177. }
  178. }
  179. return out;
  180. }
  181. bool FormatUntyped(FormatRawSinkImpl raw_sink,
  182. const UntypedFormatSpecImpl format,
  183. absl::Span<const FormatArgImpl> args) {
  184. FormatSinkImpl sink(raw_sink);
  185. using Converter = DefaultConverter;
  186. return ConvertAll(format, args, Converter(&sink));
  187. }
  188. std::ostream& Streamable::Print(std::ostream& os) const {
  189. if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
  190. return os;
  191. }
  192. std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
  193. absl::Span<const FormatArgImpl> args) {
  194. size_t orig = out->size();
  195. if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
  196. out->erase(orig);
  197. }
  198. return *out;
  199. }
  200. std::string FormatPack(UntypedFormatSpecImpl format,
  201. absl::Span<const FormatArgImpl> args) {
  202. std::string out;
  203. if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) {
  204. out.clear();
  205. }
  206. return out;
  207. }
  208. int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
  209. absl::Span<const FormatArgImpl> args) {
  210. FILERawSink sink(output);
  211. if (!FormatUntyped(&sink, format, args)) {
  212. errno = EINVAL;
  213. return -1;
  214. }
  215. if (sink.error()) {
  216. errno = sink.error();
  217. return -1;
  218. }
  219. if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
  220. errno = EFBIG;
  221. return -1;
  222. }
  223. return static_cast<int>(sink.count());
  224. }
  225. int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
  226. absl::Span<const FormatArgImpl> args) {
  227. BufferRawSink sink(output, size ? size - 1 : 0);
  228. if (!FormatUntyped(&sink, format, args)) {
  229. errno = EINVAL;
  230. return -1;
  231. }
  232. size_t total = sink.total_written();
  233. if (size) output[std::min(total, size - 1)] = 0;
  234. return static_cast<int>(total);
  235. }
  236. } // namespace str_format_internal
  237. ABSL_NAMESPACE_END
  238. } // namespace absl