printf.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Assertions.h>
  7. #include <AK/PrintfImplementation.h>
  8. #include <AK/String.h>
  9. #include <AK/StringBuilder.h>
  10. #include <AK/Types.h>
  11. #include <LibMain/Main.h>
  12. #include <stdio.h>
  13. #include <unistd.h>
  14. [[gnu::noreturn]] static void fail(char const* message)
  15. {
  16. fputs("\e[31m", stderr);
  17. fputs(message, stderr);
  18. fputs("\e[0m\n", stderr);
  19. exit(1);
  20. }
  21. template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument, typename CharType>
  22. requires(IsSame<CharType, char>) struct PrintfImpl : public PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument, CharType> {
  23. ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, int const& nwritten)
  24. : PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument>(putch, bufptr, nwritten)
  25. {
  26. }
  27. ALWAYS_INLINE int format_q(PrintfImplementation::ModifierState const& state, ArgumentListRefT& ap) const
  28. {
  29. auto state_copy = state;
  30. auto str = NextArgument<char const*>()(ap);
  31. if (!str)
  32. str = "(null)";
  33. constexpr auto make_len_or_escape = [](auto str, bool mk_len, size_t field_width, auto putc) {
  34. unsigned len = 2;
  35. if (!mk_len)
  36. putc('"');
  37. for (size_t i = 0; str[i] && (mk_len ? true : (field_width >= len)); ++i) {
  38. auto ch = str[i];
  39. switch (ch) {
  40. case '"':
  41. case '$':
  42. case '\\':
  43. ++len;
  44. if (!mk_len)
  45. putc('\\');
  46. }
  47. ++len;
  48. if (!mk_len)
  49. putc(ch);
  50. }
  51. if (!mk_len)
  52. putc('"');
  53. return len;
  54. };
  55. auto len = make_len_or_escape(str, true, state_copy.field_width, [&](auto c) { this->m_putch(this->m_bufptr, c); });
  56. if (!state_copy.dot && (!state_copy.field_width || state_copy.field_width < len))
  57. state_copy.field_width = len;
  58. size_t pad_amount = state_copy.field_width > len ? state_copy.field_width - len : 0;
  59. if (!state_copy.left_pad) {
  60. for (size_t i = 0; i < pad_amount; ++i)
  61. this->m_putch(this->m_bufptr, ' ');
  62. }
  63. make_len_or_escape(str, false, state_copy.field_width, [&](auto c) { this->m_putch(this->m_bufptr, c); });
  64. if (state_copy.left_pad) {
  65. for (size_t i = 0; i < pad_amount; ++i)
  66. this->m_putch(this->m_bufptr, ' ');
  67. }
  68. return state_copy.field_width;
  69. }
  70. };
  71. template<typename T, typename V>
  72. struct ArgvNextArgument {
  73. ALWAYS_INLINE T operator()(V) const
  74. {
  75. static_assert(sizeof(V) != sizeof(V), "Base instantiated");
  76. return declval<T>();
  77. }
  78. };
  79. template<typename V>
  80. struct ArgvNextArgument<char*, V> {
  81. ALWAYS_INLINE char* operator()(V arg) const
  82. {
  83. if (arg.argc == 0)
  84. fail("Not enough arguments");
  85. auto result = *arg.argv++;
  86. --arg.argc;
  87. return result;
  88. }
  89. };
  90. template<typename V>
  91. struct ArgvNextArgument<char const*, V> {
  92. ALWAYS_INLINE char const* operator()(V arg) const
  93. {
  94. if (arg.argc == 0)
  95. return "";
  96. auto result = *arg.argv++;
  97. --arg.argc;
  98. return result;
  99. }
  100. };
  101. template<typename V>
  102. struct ArgvNextArgument<wchar_t const*, V> {
  103. ALWAYS_INLINE wchar_t const* operator()(V arg) const
  104. {
  105. if (arg.argc == 0)
  106. return L"";
  107. return L"";
  108. }
  109. };
  110. template<typename V>
  111. struct ArgvNextArgument<int, V> {
  112. ALWAYS_INLINE int operator()(V arg) const
  113. {
  114. if (arg.argc == 0)
  115. return 0;
  116. auto result = *arg.argv++;
  117. --arg.argc;
  118. return atoi(result);
  119. }
  120. };
  121. template<typename V>
  122. struct ArgvNextArgument<unsigned, V> {
  123. ALWAYS_INLINE unsigned operator()(V arg) const
  124. {
  125. if (arg.argc == 0)
  126. return 0;
  127. auto result = *arg.argv++;
  128. --arg.argc;
  129. return strtoul(result, nullptr, 10);
  130. }
  131. };
  132. template<typename V>
  133. struct ArgvNextArgument<long int, V> {
  134. ALWAYS_INLINE long int operator()(V arg) const
  135. {
  136. if (arg.argc == 0)
  137. return 0;
  138. auto result = *arg.argv++;
  139. --arg.argc;
  140. return strtol(result, nullptr, 10);
  141. }
  142. };
  143. template<typename V>
  144. struct ArgvNextArgument<long long int, V> {
  145. ALWAYS_INLINE long long int operator()(V arg) const
  146. {
  147. if (arg.argc == 0)
  148. return 0;
  149. auto result = *arg.argv++;
  150. --arg.argc;
  151. return strtoll(result, nullptr, 10);
  152. }
  153. };
  154. template<typename V>
  155. struct ArgvNextArgument<unsigned long int, V> {
  156. ALWAYS_INLINE unsigned long int operator()(V arg) const
  157. {
  158. if (arg.argc == 0)
  159. return 0;
  160. auto result = *arg.argv++;
  161. --arg.argc;
  162. return strtoul(result, nullptr, 10);
  163. }
  164. };
  165. template<typename V>
  166. struct ArgvNextArgument<unsigned long long int, V> {
  167. ALWAYS_INLINE unsigned long long int operator()(V arg) const
  168. {
  169. if (arg.argc == 0)
  170. return 0;
  171. auto result = *arg.argv++;
  172. --arg.argc;
  173. return strtoull(result, nullptr, 10);
  174. }
  175. };
  176. template<typename V>
  177. struct ArgvNextArgument<double, V> {
  178. ALWAYS_INLINE double operator()(V arg) const
  179. {
  180. if (arg.argc == 0)
  181. return 0;
  182. auto result = *arg.argv++;
  183. --arg.argc;
  184. return strtod(result, nullptr);
  185. }
  186. };
  187. template<typename V>
  188. struct ArgvNextArgument<int*, V> {
  189. ALWAYS_INLINE int* operator()(V) const
  190. {
  191. VERIFY_NOT_REACHED();
  192. return nullptr;
  193. }
  194. };
  195. struct ArgvWithCount {
  196. char**& argv;
  197. int& argc;
  198. };
  199. static String handle_escapes(char const* string)
  200. {
  201. StringBuilder builder;
  202. for (auto c = *string; c; c = *++string) {
  203. if (c == '\\') {
  204. if (string[1]) {
  205. switch (c = *++string) {
  206. case '\\':
  207. case '"':
  208. builder.append(c);
  209. break;
  210. case 'a':
  211. builder.append('\a');
  212. break;
  213. case 'b':
  214. builder.append('\b');
  215. break;
  216. case 'c':
  217. return builder.build();
  218. case 'e':
  219. builder.append('\e');
  220. break;
  221. case 'f':
  222. builder.append('\f');
  223. break;
  224. case 'n':
  225. builder.append('\n');
  226. break;
  227. case 'r':
  228. builder.append('\r');
  229. break;
  230. case 't':
  231. builder.append('\t');
  232. break;
  233. case 'v':
  234. builder.append('\v');
  235. break;
  236. case 'x':
  237. fail("Unsupported escape '\\x'");
  238. case 'u':
  239. fail("Unsupported escape '\\u'");
  240. case 'U':
  241. fail("Unsupported escape '\\U'");
  242. default:
  243. builder.append(c);
  244. }
  245. } else {
  246. builder.append(c);
  247. }
  248. } else {
  249. builder.append(c);
  250. }
  251. }
  252. return builder.build();
  253. }
  254. ErrorOr<int> serenity_main(Main::Arguments arguments)
  255. {
  256. if (arguments.argc < 2)
  257. return Error::from_errno(EINVAL);
  258. auto argc = arguments.argc;
  259. auto argv = arguments.argv;
  260. ++argv;
  261. String format = handle_escapes(*(argv++));
  262. auto format_string = format.characters();
  263. argc -= 2;
  264. ArgvWithCount arg { argv, argc };
  265. auto putch = [](auto*, auto ch) {
  266. putchar(ch);
  267. };
  268. auto previous_argc = 0;
  269. do {
  270. previous_argc = argc;
  271. PrintfImplementation::printf_internal<decltype(putch), PrintfImpl, ArgvWithCount, ArgvNextArgument, char>(putch, nullptr, format_string, arg);
  272. } while (argc && previous_argc != argc);
  273. return 0;
  274. }