output.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. #include "output.h"
  2. #include <util/string/cast.h>
  3. #include "format.h"
  4. #include <util/memory/tempbuf.h>
  5. #include <util/generic/singleton.h>
  6. #include <util/generic/yexception.h>
  7. #include <util/charset/utf8.h>
  8. #include <util/charset/wide.h>
  9. #if defined(_android_)
  10. #include <util/system/dynlib.h>
  11. #include <util/system/guard.h>
  12. #include <util/system/mutex.h>
  13. #include <android/log.h>
  14. #endif
  15. #include <cerrno>
  16. #include <string>
  17. #include <string_view>
  18. #include <cstdio>
  19. #if defined(_win_)
  20. #include <io.h>
  21. #endif
  22. constexpr size_t MAX_UTF8_BYTES = 4; // UTF-8-encoded code point takes between 1 and 4 bytes
  23. IOutputStream::IOutputStream() noexcept = default;
  24. IOutputStream::~IOutputStream() = default;
  25. void IOutputStream::DoFlush() {
  26. /*
  27. * do nothing
  28. */
  29. }
  30. void IOutputStream::DoFinish() {
  31. Flush();
  32. }
  33. void IOutputStream::DoWriteV(const TPart* parts, size_t count) {
  34. for (size_t i = 0; i < count; ++i) {
  35. const TPart& part = parts[i];
  36. DoWrite(part.buf, part.len);
  37. }
  38. }
  39. void IOutputStream::DoWriteC(char ch) {
  40. DoWrite(&ch, 1);
  41. }
  42. template <>
  43. void Out<wchar16>(IOutputStream& o, wchar16 ch) {
  44. const wchar32 w32ch = ReadSymbol(&ch, &ch + 1);
  45. size_t length;
  46. unsigned char buffer[MAX_UTF8_BYTES];
  47. WriteUTF8Char(w32ch, length, buffer);
  48. o.Write(buffer, length);
  49. }
  50. template <>
  51. void Out<wchar32>(IOutputStream& o, wchar32 ch) {
  52. size_t length;
  53. unsigned char buffer[MAX_UTF8_BYTES];
  54. WriteUTF8Char(ch, length, buffer);
  55. o.Write(buffer, length);
  56. }
  57. static void WriteString(IOutputStream& o, const wchar16* w, size_t n) {
  58. const size_t buflen = (n * MAX_UTF8_BYTES); // * 4 because the conversion functions can convert unicode character into maximum 4 bytes of UTF8
  59. TTempBuf buffer(buflen + 1);
  60. char* const data = buffer.Data();
  61. size_t written = 0;
  62. WideToUTF8(w, n, data, written);
  63. data[written] = 0;
  64. o.Write(data, written);
  65. }
  66. static void WriteString(IOutputStream& o, const wchar32* w, size_t n) {
  67. const size_t buflen = (n * MAX_UTF8_BYTES); // * 4 because the conversion functions can convert unicode character into maximum 4 bytes of UTF8
  68. TTempBuf buffer(buflen + 1);
  69. char* const data = buffer.Data();
  70. size_t written = 0;
  71. WideToUTF8(w, n, data, written);
  72. data[written] = 0;
  73. o.Write(data, written);
  74. }
  75. template <>
  76. void Out<TString>(IOutputStream& o, const TString& p) {
  77. o.Write(p.data(), p.size());
  78. }
  79. template <>
  80. void Out<std::string>(IOutputStream& o, const std::string& p) {
  81. o.Write(p.data(), p.length());
  82. }
  83. template <>
  84. void Out<std::string_view>(IOutputStream& o, const std::string_view& p) {
  85. o.Write(p.data(), p.length());
  86. }
  87. template <>
  88. void Out<std::u16string_view>(IOutputStream& o, const std::u16string_view& p) {
  89. WriteString(o, p.data(), p.length());
  90. }
  91. template <>
  92. void Out<std::u32string_view>(IOutputStream& o, const std::u32string_view& p) {
  93. WriteString(o, p.data(), p.length());
  94. }
  95. template <>
  96. void Out<TStringBuf>(IOutputStream& o, const TStringBuf& p) {
  97. o.Write(p.data(), p.length());
  98. }
  99. template <>
  100. void Out<TWtringBuf>(IOutputStream& o, const TWtringBuf& p) {
  101. WriteString(o, p.data(), p.length());
  102. }
  103. template <>
  104. void Out<TUtf32StringBuf>(IOutputStream& o, const TUtf32StringBuf& p) {
  105. WriteString(o, p.data(), p.length());
  106. }
  107. template <>
  108. void Out<const wchar16*>(IOutputStream& o, const wchar16* w) {
  109. if (w) {
  110. WriteString(o, w, std::char_traits<wchar16>::length(w));
  111. } else {
  112. o.Write("(null)");
  113. }
  114. }
  115. template <>
  116. void Out<const wchar32*>(IOutputStream& o, const wchar32* w) {
  117. if (w) {
  118. WriteString(o, w, std::char_traits<wchar32>::length(w));
  119. } else {
  120. o.Write("(null)");
  121. }
  122. }
  123. template <>
  124. void Out<TUtf16String>(IOutputStream& o, const TUtf16String& w) {
  125. WriteString(o, w.c_str(), w.size());
  126. }
  127. template <>
  128. void Out<TUtf32String>(IOutputStream& o, const TUtf32String& w) {
  129. WriteString(o, w.c_str(), w.size());
  130. }
  131. #define DEF_CONV_DEFAULT(type) \
  132. template <> \
  133. void Out<type>(IOutputStream & o, type p) { \
  134. o << ToString(p); \
  135. }
  136. #define DEF_CONV_CHR(type) \
  137. template <> \
  138. void Out<type>(IOutputStream & o, type p) { \
  139. o.Write((char)p); \
  140. }
  141. #define DEF_CONV_NUM(type, len) \
  142. template <> \
  143. void Out<type>(IOutputStream & o, type p) { \
  144. char buf[len]; \
  145. o.Write(buf, ToString(p, buf, sizeof(buf))); \
  146. } \
  147. \
  148. template <> \
  149. void Out<volatile type>(IOutputStream & o, volatile type p) { \
  150. Out<type>(o, p); \
  151. }
  152. DEF_CONV_NUM(bool, 64)
  153. DEF_CONV_CHR(char)
  154. DEF_CONV_CHR(signed char)
  155. DEF_CONV_CHR(unsigned char)
  156. DEF_CONV_NUM(signed short, 64)
  157. DEF_CONV_NUM(signed int, 64)
  158. DEF_CONV_NUM(signed long int, 64)
  159. DEF_CONV_NUM(signed long long int, 64)
  160. DEF_CONV_NUM(unsigned short, 64)
  161. DEF_CONV_NUM(unsigned int, 64)
  162. DEF_CONV_NUM(unsigned long int, 64)
  163. DEF_CONV_NUM(unsigned long long int, 64)
  164. DEF_CONV_NUM(float, 512)
  165. DEF_CONV_NUM(double, 512)
  166. DEF_CONV_NUM(long double, 512)
  167. #if !defined(_YNDX_LIBCXX_ENABLE_VECTOR_BOOL_COMPRESSION) || (_YNDX_LIBCXX_ENABLE_VECTOR_BOOL_COMPRESSION == 1)
  168. // TODO: acknowledge std::bitset::reference for both libc++ and libstdc++
  169. template <>
  170. void Out<typename std::vector<bool>::reference>(IOutputStream& o, const std::vector<bool>::reference& bit) {
  171. return Out<bool>(o, static_cast<bool>(bit));
  172. }
  173. #endif
  174. #ifndef TSTRING_IS_STD_STRING
  175. template <>
  176. void Out<TBasicCharRef<TString>>(IOutputStream& o, const TBasicCharRef<TString>& c) {
  177. o << static_cast<char>(c);
  178. }
  179. template <>
  180. void Out<TBasicCharRef<TUtf16String>>(IOutputStream& o, const TBasicCharRef<TUtf16String>& c) {
  181. o << static_cast<wchar16>(c);
  182. }
  183. template <>
  184. void Out<TBasicCharRef<TUtf32String>>(IOutputStream& o, const TBasicCharRef<TUtf32String>& c) {
  185. o << static_cast<wchar32>(c);
  186. }
  187. #endif
  188. template <>
  189. void Out<const void*>(IOutputStream& o, const void* t) {
  190. o << Hex(size_t(t));
  191. }
  192. template <>
  193. void Out<void*>(IOutputStream& o, void* t) {
  194. Out<const void*>(o, t);
  195. }
  196. using TNullPtr = decltype(nullptr);
  197. template <>
  198. void Out<TNullPtr>(IOutputStream& o, TTypeTraits<TNullPtr>::TFuncParam) {
  199. o << TStringBuf("nullptr");
  200. }
  201. #if defined(_android_)
  202. namespace {
  203. class TAndroidStdIOStreams {
  204. public:
  205. TAndroidStdIOStreams()
  206. : LogLibrary("liblog.so")
  207. , LogFuncPtr((TLogFuncPtr)LogLibrary.Sym("__android_log_write"))
  208. , Out(LogFuncPtr)
  209. , Err(LogFuncPtr)
  210. {
  211. }
  212. public:
  213. using TLogFuncPtr = void (*)(int, const char*, const char*);
  214. class TAndroidStdOutput: public IOutputStream {
  215. public:
  216. inline TAndroidStdOutput(TLogFuncPtr logFuncPtr) noexcept
  217. : Buffer()
  218. , LogFuncPtr(logFuncPtr)
  219. {
  220. }
  221. virtual ~TAndroidStdOutput() {
  222. }
  223. private:
  224. virtual void DoWrite(const void* buf, size_t len) override {
  225. with_lock (BufferMutex) {
  226. Buffer.Write(buf, len);
  227. }
  228. }
  229. virtual void DoFlush() override {
  230. with_lock (BufferMutex) {
  231. LogFuncPtr(ANDROID_LOG_DEBUG, GetTag(), Buffer.Data());
  232. Buffer.Clear();
  233. }
  234. }
  235. virtual const char* GetTag() const = 0;
  236. private:
  237. TMutex BufferMutex;
  238. TStringStream Buffer;
  239. TLogFuncPtr LogFuncPtr;
  240. };
  241. class TStdErr: public TAndroidStdOutput {
  242. public:
  243. TStdErr(TLogFuncPtr logFuncPtr)
  244. : TAndroidStdOutput(logFuncPtr)
  245. {
  246. }
  247. virtual ~TStdErr() {
  248. }
  249. private:
  250. virtual const char* GetTag() const override {
  251. return "stderr";
  252. }
  253. };
  254. class TStdOut: public TAndroidStdOutput {
  255. public:
  256. TStdOut(TLogFuncPtr logFuncPtr)
  257. : TAndroidStdOutput(logFuncPtr)
  258. {
  259. }
  260. virtual ~TStdOut() {
  261. }
  262. private:
  263. virtual const char* GetTag() const override {
  264. return "stdout";
  265. }
  266. };
  267. static bool Enabled;
  268. TDynamicLibrary LogLibrary; // field order is important, see constructor
  269. TLogFuncPtr LogFuncPtr;
  270. TStdOut Out;
  271. TStdErr Err;
  272. static inline TAndroidStdIOStreams& Instance() {
  273. return *SingletonWithPriority<TAndroidStdIOStreams, 4>();
  274. }
  275. };
  276. bool TAndroidStdIOStreams::Enabled = false;
  277. }
  278. #endif // _android_
  279. namespace {
  280. class TStdOutput: public IOutputStream {
  281. public:
  282. inline TStdOutput(FILE* f) noexcept
  283. : F_(f)
  284. {
  285. }
  286. ~TStdOutput() override = default;
  287. private:
  288. void DoWrite(const void* buf, size_t len) override {
  289. if (len != fwrite(buf, 1, len, F_)) {
  290. #if defined(_win_)
  291. // On Windows, if 'F_' is console -- 'fwrite' returns count of written characters.
  292. // If, for example, console output codepage is UTF-8, then returned value is
  293. // not equal to 'len'. So, we ignore some 'errno' values...
  294. if ((errno == 0 || errno == EINVAL || errno == EILSEQ) && _isatty(fileno(F_))) {
  295. return;
  296. }
  297. #endif
  298. ythrow TSystemError() << "write failed";
  299. }
  300. }
  301. void DoFlush() override {
  302. if (fflush(F_) != 0) {
  303. ythrow TSystemError() << "fflush failed";
  304. }
  305. }
  306. private:
  307. FILE* F_;
  308. };
  309. struct TStdIOStreams {
  310. struct TStdErr: public TStdOutput {
  311. inline TStdErr()
  312. : TStdOutput(stderr)
  313. {
  314. }
  315. ~TStdErr() override = default;
  316. };
  317. struct TStdOut: public TStdOutput {
  318. inline TStdOut()
  319. : TStdOutput(stdout)
  320. {
  321. }
  322. ~TStdOut() override = default;
  323. };
  324. TStdOut Out;
  325. TStdErr Err;
  326. static inline TStdIOStreams& Instance() {
  327. return *SingletonWithPriority<TStdIOStreams, 4>();
  328. }
  329. };
  330. }
  331. IOutputStream& NPrivate::StdErrStream() noexcept {
  332. #if defined(_android_)
  333. if (TAndroidStdIOStreams::Enabled) {
  334. return TAndroidStdIOStreams::Instance().Err;
  335. }
  336. #endif
  337. return TStdIOStreams::Instance().Err;
  338. }
  339. IOutputStream& NPrivate::StdOutStream() noexcept {
  340. #if defined(_android_)
  341. if (TAndroidStdIOStreams::Enabled) {
  342. return TAndroidStdIOStreams::Instance().Out;
  343. }
  344. #endif
  345. return TStdIOStreams::Instance().Out;
  346. }
  347. void RedirectStdioToAndroidLog(bool redirect) {
  348. #if defined(_android_)
  349. TAndroidStdIOStreams::Enabled = redirect;
  350. #else
  351. Y_UNUSED(redirect);
  352. #endif
  353. }