Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

8 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
9 роки тому
9 роки тому
10 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. /*
  2. * Copyright 2024 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* Copyright (C) 2002-2015 Igor Sysoev
  17. * Copyright (C) 2011-2015 Nginx, Inc.
  18. * All rights reserved.
  19. *
  20. * Redistribution and use in source and binary forms, with or without
  21. * modification, are permitted provided that the following conditions are met:
  22. * * Redistributions of source code must retain the above copyright
  23. * notice, this list of conditions and the following disclaimer.
  24. * * Redistributions in binary form must reproduce the above copyright
  25. * notice, this list of conditions and the following disclaimer in the
  26. * documentation and/or other materials provided with the distribution.
  27. *
  28. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  29. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  30. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  32. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  33. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  35. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  36. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. */
  39. #include "printf.h"
  40. #include "str_util.h"
  41. #include "contrib/fpconv/fpconv.h"
  42. /**
  43. * From FreeBSD libutil code
  44. */
  45. static const int maxscale = 6;
  46. static const char _hex[] = "0123456789abcdef";
  47. static const char _HEX[] = "0123456789ABCDEF";
  48. static char *
  49. rspamd_humanize_number(char *buf, char *last, int64_t num, gboolean bytes)
  50. {
  51. const char *prefixes;
  52. int i, r, remainder, sign;
  53. int64_t divisor;
  54. gsize len = last - buf;
  55. remainder = 0;
  56. if (!bytes) {
  57. divisor = 1000;
  58. prefixes = "\0\0\0\0k\0\0\0M\0\0\0G\0\0\0T\0\0\0P\0\0\0E";
  59. }
  60. else {
  61. divisor = 1024;
  62. prefixes = "B\0\0\0KiB\0MiB\0GiB\0TiB\0PiB\0EiB";
  63. }
  64. #define SCALE2PREFIX(scale) (&prefixes[(scale) *4])
  65. if (num < 0) {
  66. sign = -1;
  67. num = -num;
  68. }
  69. else {
  70. sign = 1;
  71. }
  72. /*
  73. * Divide the number until it fits the given column.
  74. * If there will be an overflow by the rounding below,
  75. * divide once more.
  76. */
  77. for (i = 0; i < maxscale && num > divisor; i++) {
  78. remainder = num % divisor;
  79. num /= divisor;
  80. }
  81. if (remainder == 0 || num > divisor / 2) {
  82. r = rspamd_snprintf(buf, len, "%L%s",
  83. sign * (num + (remainder + 50) / divisor),
  84. SCALE2PREFIX(i));
  85. }
  86. else {
  87. /* Floating point version */
  88. r = rspamd_snprintf(buf, len, "%.2f%s",
  89. sign * (num + remainder / (double) divisor),
  90. SCALE2PREFIX(i));
  91. }
  92. #undef SCALE2PREFIX
  93. return buf + r;
  94. }
  95. static inline unsigned
  96. rspamd_decimal_digits32(uint32_t val)
  97. {
  98. static const uint32_t powers_of_10[] = {
  99. 0,
  100. 10,
  101. 100,
  102. 1000,
  103. 10000,
  104. 100000,
  105. 1000000,
  106. 10000000,
  107. 100000000,
  108. 1000000000};
  109. unsigned tmp;
  110. #if defined(_MSC_VER)
  111. unsigned long r = 0;
  112. _BitScanReverse(&r, val | 1);
  113. tmp = (r + 1) * 1233 >> 12;
  114. #elif defined(__GNUC__) && (__GNUC__ >= 3)
  115. tmp = (32 - __builtin_clz(val | 1U)) * 1233 >> 12;
  116. #else /* Software version */
  117. static const unsigned debruijn_tbl[32] = {0, 9, 1, 10, 13, 21, 2, 29,
  118. 11, 14, 16, 18, 22, 25, 3, 30,
  119. 8, 12, 20, 28, 15, 17, 24, 7,
  120. 19, 27, 23, 6, 26, 5, 4, 31};
  121. uint32_t v = val | 1;
  122. v |= v >> 1;
  123. v |= v >> 2;
  124. v |= v >> 4;
  125. v |= v >> 8;
  126. v |= v >> 16;
  127. tmp = (1 + debruijn_tbl[(v * 0x07C4ACDDU) >> 27]) * 1233 >> 12;
  128. #endif
  129. return tmp - (val < powers_of_10[tmp]) + 1;
  130. }
  131. static inline unsigned
  132. rspamd_decimal_digits64(uint64_t val)
  133. {
  134. static const uint64_t powers_of_10[] = {
  135. 0,
  136. 10ULL,
  137. 100ULL,
  138. 1000ULL,
  139. 10000ULL,
  140. 100000ULL,
  141. 1000000ULL,
  142. 10000000ULL,
  143. 100000000ULL,
  144. 1000000000ULL,
  145. 10000000000ULL,
  146. 100000000000ULL,
  147. 1000000000000ULL,
  148. 10000000000000ULL,
  149. 100000000000000ULL,
  150. 1000000000000000ULL,
  151. 10000000000000000ULL,
  152. 100000000000000000ULL,
  153. 1000000000000000000ULL,
  154. 10000000000000000000ULL};
  155. unsigned tmp;
  156. #if defined(_MSC_VER)
  157. #if _M_IX86
  158. unsigned long r = 0;
  159. uint64_t m = val | 1;
  160. if (_BitScanReverse(&r, m >> 32)) {
  161. r += 32;
  162. }
  163. else {
  164. _BitScanReverse(&r, m & 0xFFFFFFFF);
  165. }
  166. tmp = (r + 1) * 1233 >> 12;
  167. #else
  168. unsigned long r = 0;
  169. _BitScanReverse64(&r, val | 1);
  170. tmp = (r + 1) * 1233 >> 12;
  171. #endif
  172. #elif defined(__GNUC__) && (__GNUC__ >= 3)
  173. tmp = (64 - __builtin_clzll(val | 1ULL)) * 1233 >> 12;
  174. #else /* Software version */
  175. static const unsigned debruijn_tbl[32] = {0, 9, 1, 10, 13, 21, 2, 29,
  176. 11, 14, 16, 18, 22, 25, 3, 30,
  177. 8, 12, 20, 28, 15, 17, 24, 7,
  178. 19, 27, 23, 6, 26, 5, 4, 31};
  179. uint32_t v = val >> 32;
  180. if (v) {
  181. v |= 1;
  182. v |= v >> 1;
  183. v |= v >> 2;
  184. v |= v >> 4;
  185. v |= v >> 8;
  186. v |= v >> 16;
  187. tmp = 32 + debruijn_tbl[(v * 0x07C4ACDDU) >> 27];
  188. }
  189. else {
  190. v = val & 0xFFFFFFFF;
  191. v |= 1;
  192. v |= v >> 1;
  193. v |= v >> 2;
  194. v |= v >> 4;
  195. v |= v >> 8;
  196. v |= v >> 16;
  197. tmp = debruijn_tbl[(v * 0x07C4ACDDU) >> 27];
  198. }
  199. tmp = (tmp + 1) * 1233 >> 12;
  200. #endif
  201. return tmp - (val < powers_of_10[tmp]) + 1;
  202. }
  203. /*
  204. * Idea from https://github.com/miloyip/itoa-benchmark:
  205. * Uses lookup table (LUT) of digit pairs for division/modulo of 100.
  206. *
  207. * Mentioned in:
  208. * https://www.slideshare.net/andreialexandrescu1/three-optimization-tips-for-c-15708507
  209. */
  210. static const char int_lookup_table[200] = {
  211. '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
  212. '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
  213. '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
  214. '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
  215. '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
  216. '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
  217. '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
  218. '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
  219. '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
  220. '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
  221. '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
  222. '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
  223. '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
  224. '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
  225. '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
  226. '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
  227. '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
  228. '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
  229. '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
  230. '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'};
  231. static inline unsigned int
  232. rspamd_uint32_print(uint32_t in, char *out)
  233. {
  234. unsigned int ndigits = rspamd_decimal_digits32(in);
  235. char *p;
  236. p = out + ndigits - 1;
  237. while (in >= 100) {
  238. unsigned idx = (in % 100) * 2;
  239. /* Do two digits at once */
  240. *p-- = int_lookup_table[idx + 1];
  241. *p-- = int_lookup_table[idx];
  242. in /= 100;
  243. }
  244. if (in < 10) {
  245. *p = ((char) in) + '0';
  246. }
  247. else {
  248. unsigned idx = in * 2;
  249. *p-- = int_lookup_table[idx + 1];
  250. *p = int_lookup_table[idx];
  251. }
  252. return ndigits;
  253. }
  254. static inline unsigned int
  255. rspamd_uint64_print(uint64_t in, char *out)
  256. {
  257. unsigned int ndigits = rspamd_decimal_digits64(in);
  258. uint32_t v32;
  259. char *p;
  260. p = out + ndigits - 1;
  261. while (in >= 100000000) {
  262. v32 = (uint32_t) (in % 100000000);
  263. uint32_t a, b, a1, a2, b1, b2;
  264. /* Initial spill */
  265. a = v32 / 10000;
  266. b = v32 % 10000;
  267. a1 = (a / 100) * 2;
  268. a2 = (a % 100) * 2;
  269. b1 = (b / 100) * 2;
  270. b2 = (b % 100) * 2;
  271. /* Fill 8 digits at once */
  272. *p-- = int_lookup_table[b2 + 1];
  273. *p-- = int_lookup_table[b2];
  274. *p-- = int_lookup_table[b1 + 1];
  275. *p-- = int_lookup_table[b1];
  276. *p-- = int_lookup_table[a2 + 1];
  277. *p-- = int_lookup_table[a2];
  278. *p-- = int_lookup_table[a1 + 1];
  279. *p-- = int_lookup_table[a1];
  280. in /= 100000000;
  281. }
  282. /* Remaining 32 bit */
  283. v32 = (uint32_t) in;
  284. while (v32 >= 100) {
  285. unsigned idx = (v32 % 100) << 1;
  286. /* Do 2 digits at once */
  287. *p-- = int_lookup_table[idx + 1];
  288. *p-- = int_lookup_table[idx];
  289. v32 /= 100;
  290. }
  291. if (v32 < 10) {
  292. *p = ((char) v32) + '0';
  293. }
  294. else {
  295. unsigned idx = v32 * 2;
  296. *p-- = int_lookup_table[idx + 1];
  297. *p = int_lookup_table[idx];
  298. }
  299. return ndigits;
  300. }
  301. static inline int
  302. rspamd_ffsll(long long n)
  303. {
  304. #ifdef __has_builtin
  305. #if __has_builtin(__builtin_ffsll)
  306. return __builtin_ffsll(n);
  307. #elif __has_builtin(__builtin_ctzll)
  308. if (n == 0) {
  309. return 0;
  310. }
  311. return __builtin_ctzll(n) + 1;
  312. #endif
  313. #endif /* __has_builtin */
  314. #ifdef HAVE_FFSL
  315. return ffsl(n);
  316. #else
  317. if (n == 0) {
  318. return 0;
  319. }
  320. int bit;
  321. for (bit = 1; !(n & 1); bit++) {
  322. n = ((unsigned long long) n) >> 1;
  323. }
  324. return bit;
  325. #endif
  326. }
  327. static char *
  328. rspamd_sprintf_num(char *buf, char *last, uint64_t ui64, char zero,
  329. unsigned int hexadecimal, unsigned int binary, unsigned int width)
  330. {
  331. char *p, temp[64];
  332. size_t len = 0;
  333. if (G_LIKELY(hexadecimal == 0 && binary == 0)) {
  334. p = temp;
  335. if (ui64 < G_MAXUINT32) {
  336. len = rspamd_uint32_print((uint32_t) ui64, temp);
  337. }
  338. else {
  339. len = rspamd_uint64_print(ui64, temp);
  340. }
  341. }
  342. else if (hexadecimal == 1) {
  343. p = temp + sizeof(temp);
  344. do {
  345. *--p = _hex[(uint32_t) (ui64 & 0xf)];
  346. } while (ui64 >>= 4);
  347. len = (temp + sizeof(temp)) - p;
  348. }
  349. else if (hexadecimal == 2) { /* hexadecimal == 2 */
  350. p = temp + sizeof(temp);
  351. do {
  352. *--p = _HEX[(uint32_t) (ui64 & 0xf)];
  353. } while (ui64 >>= 4);
  354. len = (temp + sizeof(temp)) - p;
  355. }
  356. else if (binary > 0) {
  357. int first_bit = MIN(sizeof(temp), rspamd_ffsll(ui64));
  358. p = temp + sizeof(temp);
  359. for (int i = 0; i <= first_bit; i++, ui64 >>= 1) {
  360. *--p = '0' + (ui64 & 0x1);
  361. }
  362. len = (temp + sizeof(temp)) - p;
  363. }
  364. /* zero or space padding */
  365. if (len < width) {
  366. width -= len;
  367. while (width-- > 0 && buf < last) {
  368. *buf++ = zero;
  369. }
  370. }
  371. /* number safe copy */
  372. if (buf + len > last) {
  373. len = last - buf;
  374. }
  375. return ((char *) memcpy(buf, p, len)) + len;
  376. }
  377. struct rspamd_printf_char_buf {
  378. char *begin;
  379. char *pos;
  380. glong remain;
  381. };
  382. static glong
  383. rspamd_printf_append_char(const char *buf, glong buflen, gpointer ud)
  384. {
  385. struct rspamd_printf_char_buf *dst = (struct rspamd_printf_char_buf *) ud;
  386. glong wr;
  387. if (dst->remain <= 0) {
  388. return dst->remain;
  389. }
  390. wr = MIN(dst->remain, buflen);
  391. memcpy(dst->pos, buf, wr);
  392. dst->remain -= wr;
  393. dst->pos += wr;
  394. return wr;
  395. }
  396. static glong
  397. rspamd_printf_append_file(const char *buf, glong buflen, gpointer ud)
  398. {
  399. FILE *dst = (FILE *) ud;
  400. if (buflen > 0) {
  401. return fwrite(buf, 1, buflen, dst);
  402. }
  403. else {
  404. return 0;
  405. }
  406. }
  407. static glong
  408. rspamd_printf_append_gstring(const char *buf, glong buflen, gpointer ud)
  409. {
  410. GString *dst = (GString *) ud;
  411. if (buflen > 0) {
  412. g_string_append_len(dst, buf, buflen);
  413. }
  414. return buflen;
  415. }
  416. static glong
  417. rspamd_printf_append_fstring(const char *buf, glong buflen, gpointer ud)
  418. {
  419. rspamd_fstring_t **dst = ud;
  420. if (buflen > 0) {
  421. *dst = rspamd_fstring_append(*dst, buf, buflen);
  422. }
  423. return buflen;
  424. }
  425. glong rspamd_fprintf(FILE *f, const char *fmt, ...)
  426. {
  427. va_list args;
  428. glong r;
  429. va_start(args, fmt);
  430. r = rspamd_vprintf_common(rspamd_printf_append_file, f, fmt, args);
  431. va_end(args);
  432. return r;
  433. }
  434. glong rspamd_printf(const char *fmt, ...)
  435. {
  436. va_list args;
  437. glong r;
  438. va_start(args, fmt);
  439. r = rspamd_vprintf_common(rspamd_printf_append_file, stdout, fmt, args);
  440. va_end(args);
  441. return r;
  442. }
  443. glong rspamd_log_fprintf(FILE *f, const char *fmt, ...)
  444. {
  445. va_list args;
  446. glong r;
  447. va_start(args, fmt);
  448. r = rspamd_vprintf_common(rspamd_printf_append_file, f, fmt, args);
  449. va_end(args);
  450. fflush(f);
  451. return r;
  452. }
  453. glong rspamd_snprintf(char *buf, glong max, const char *fmt, ...)
  454. {
  455. char *r;
  456. va_list args;
  457. va_start(args, fmt);
  458. r = rspamd_vsnprintf(buf, max, fmt, args);
  459. va_end(args);
  460. return (r - buf);
  461. }
  462. char *
  463. rspamd_vsnprintf(char *buf, glong max, const char *fmt, va_list args)
  464. {
  465. struct rspamd_printf_char_buf dst;
  466. dst.begin = buf;
  467. dst.pos = dst.begin;
  468. dst.remain = max - 1;
  469. (void) rspamd_vprintf_common(rspamd_printf_append_char, &dst, fmt, args);
  470. *dst.pos = '\0';
  471. return dst.pos;
  472. }
  473. glong rspamd_printf_gstring(GString *s, const char *fmt, ...)
  474. {
  475. va_list args;
  476. glong r;
  477. va_start(args, fmt);
  478. r = rspamd_vprintf_gstring(s, fmt, args);
  479. va_end(args);
  480. return r;
  481. }
  482. glong rspamd_vprintf_gstring(GString *s, const char *fmt, va_list args)
  483. {
  484. return rspamd_vprintf_common(rspamd_printf_append_gstring, s, fmt, args);
  485. }
  486. glong rspamd_printf_fstring(rspamd_fstring_t **s, const char *fmt, ...)
  487. {
  488. va_list args;
  489. glong r;
  490. va_start(args, fmt);
  491. r = rspamd_vprintf_fstring(s, fmt, args);
  492. va_end(args);
  493. return r;
  494. }
  495. glong rspamd_vprintf_fstring(rspamd_fstring_t **s, const char *fmt, va_list args)
  496. {
  497. return rspamd_vprintf_common(rspamd_printf_append_fstring, s, fmt, args);
  498. }
  499. #define RSPAMD_PRINTF_APPEND(buf, len) \
  500. do { \
  501. RSPAMD_PRINTF_APPEND_BUF(buf, len); \
  502. fmt++; \
  503. buf_start = fmt; \
  504. } while (0)
  505. #define RSPAMD_PRINTF_APPEND_BUF(buf, len) \
  506. do { \
  507. wr = func((buf), (len), apd); \
  508. if (wr < (__typeof(wr)) (len)) { \
  509. goto oob; \
  510. } \
  511. written += wr; \
  512. } while (0)
  513. glong rspamd_vprintf_common(rspamd_printf_append_func func,
  514. gpointer apd,
  515. const char *fmt,
  516. va_list args)
  517. {
  518. char zero, numbuf[G_ASCII_DTOSTR_BUF_SIZE], dtoabuf[32], *p, *last;
  519. unsigned char c;
  520. const char *buf_start = fmt;
  521. int d;
  522. double f;
  523. glong written = 0, wr, slen;
  524. int64_t i64;
  525. uint64_t ui64;
  526. unsigned int width, sign, hex, humanize, bytes, frac_width, b32, b64;
  527. rspamd_fstring_t *v;
  528. rspamd_ftok_t *tok;
  529. GString *gs;
  530. GError *err;
  531. while (*fmt) {
  532. /*
  533. * "buf < last" means that we could copy at least one character:
  534. * the plain character, "%%", "%c", and minus without the checking
  535. */
  536. if (*fmt == '%') {
  537. /* Append what we have in buf */
  538. if (fmt > buf_start) {
  539. wr = func(buf_start, fmt - buf_start, apd);
  540. if (wr <= 0) {
  541. goto oob;
  542. }
  543. written += wr;
  544. }
  545. i64 = 0;
  546. ui64 = 0;
  547. zero = (char) ((*++fmt == '0') ? '0' : ' ');
  548. width = 0;
  549. sign = 1;
  550. hex = 0;
  551. b32 = 0;
  552. b64 = 0;
  553. bytes = 0;
  554. humanize = 0;
  555. frac_width = 0;
  556. slen = -1;
  557. while (*fmt >= '0' && *fmt <= '9') {
  558. width = width * 10 + *fmt++ - '0';
  559. }
  560. for (;;) {
  561. switch (*fmt) {
  562. case 'u':
  563. sign = 0;
  564. fmt++;
  565. continue;
  566. case 'm':
  567. fmt++;
  568. continue;
  569. case 'X':
  570. hex = 2;
  571. sign = 0;
  572. fmt++;
  573. continue;
  574. case 'x':
  575. hex = 1;
  576. sign = 0;
  577. fmt++;
  578. continue;
  579. case 'b':
  580. b32 = 1;
  581. sign = 0;
  582. fmt++;
  583. continue;
  584. case 'B':
  585. b64 = 1;
  586. sign = 0;
  587. fmt++;
  588. continue;
  589. case 'H':
  590. humanize = 1;
  591. bytes = 1;
  592. sign = 0;
  593. fmt++;
  594. continue;
  595. case 'h':
  596. humanize = 1;
  597. sign = 0;
  598. fmt++;
  599. continue;
  600. case '.':
  601. fmt++;
  602. if (*fmt == '*') {
  603. d = (int) va_arg(args, int);
  604. if (G_UNLIKELY(d < 0)) {
  605. return 0;
  606. }
  607. frac_width = (unsigned int) d;
  608. fmt++;
  609. }
  610. else {
  611. while (*fmt >= '0' && *fmt <= '9') {
  612. frac_width = frac_width * 10 + *fmt++ - '0';
  613. }
  614. }
  615. break;
  616. case '*':
  617. d = (int) va_arg(args, int);
  618. if (G_UNLIKELY(d < 0)) {
  619. return 0;
  620. }
  621. slen = (glong) d;
  622. fmt++;
  623. continue;
  624. default:
  625. break;
  626. }
  627. break;
  628. }
  629. switch (*fmt) {
  630. case 'V':
  631. v = va_arg(args, rspamd_fstring_t *);
  632. if (v) {
  633. slen = v->len;
  634. if (G_UNLIKELY(width != 0)) {
  635. slen = MIN(v->len, width);
  636. }
  637. RSPAMD_PRINTF_APPEND(v->str, slen);
  638. }
  639. else {
  640. RSPAMD_PRINTF_APPEND("(NULL)", 6);
  641. }
  642. continue;
  643. case 'T':
  644. tok = va_arg(args, rspamd_ftok_t *);
  645. if (tok) {
  646. slen = tok->len;
  647. if (G_UNLIKELY(width != 0)) {
  648. slen = MIN(tok->len, width);
  649. }
  650. RSPAMD_PRINTF_APPEND(tok->begin, slen);
  651. }
  652. else {
  653. RSPAMD_PRINTF_APPEND("(NULL)", 6);
  654. }
  655. continue;
  656. case 'v':
  657. gs = va_arg(args, GString *);
  658. if (gs) {
  659. slen = gs->len;
  660. if (G_UNLIKELY(width != 0)) {
  661. slen = MIN(gs->len, width);
  662. }
  663. RSPAMD_PRINTF_APPEND(gs->str, slen);
  664. }
  665. else {
  666. RSPAMD_PRINTF_APPEND("(NULL)", 6);
  667. }
  668. continue;
  669. case 'e':
  670. err = va_arg(args, GError *);
  671. if (err) {
  672. p = err->message;
  673. if (p == NULL) {
  674. p = "(NULL)";
  675. }
  676. }
  677. else {
  678. p = "unknown error";
  679. }
  680. slen = strlen(p);
  681. RSPAMD_PRINTF_APPEND(p, slen);
  682. continue;
  683. case 's':
  684. p = va_arg(args, char *);
  685. if (p == NULL) {
  686. p = "(NULL)";
  687. slen = sizeof("(NULL)") - 1;
  688. }
  689. if (G_UNLIKELY(b32)) {
  690. char *b32buf;
  691. if (G_UNLIKELY(slen == -1)) {
  692. if (G_LIKELY(width != 0)) {
  693. slen = width;
  694. }
  695. else {
  696. /* NULL terminated string */
  697. slen = strlen(p);
  698. }
  699. }
  700. b32buf = rspamd_encode_base32(p, slen, RSPAMD_BASE32_DEFAULT);
  701. if (b32buf) {
  702. RSPAMD_PRINTF_APPEND(b32buf, strlen(b32buf));
  703. g_free(b32buf);
  704. }
  705. else {
  706. RSPAMD_PRINTF_APPEND("(NULL)", sizeof("(NULL)") - 1);
  707. }
  708. }
  709. else if (G_UNLIKELY(hex)) {
  710. char hexbuf[2];
  711. if (G_UNLIKELY(slen == -1)) {
  712. if (G_LIKELY(width != 0)) {
  713. slen = width;
  714. }
  715. else {
  716. /* NULL terminated string */
  717. slen = strlen(p);
  718. }
  719. }
  720. while (slen) {
  721. hexbuf[0] = hex == 2 ? _HEX[(*p >> 4u) & 0xfu] : _hex[(*p >> 4u) & 0xfu];
  722. hexbuf[1] = hex == 2 ? _HEX[*p & 0xfu] : _hex[*p & 0xfu];
  723. RSPAMD_PRINTF_APPEND_BUF(hexbuf, 2);
  724. p++;
  725. slen--;
  726. }
  727. fmt++;
  728. buf_start = fmt;
  729. }
  730. else if (G_UNLIKELY(b64)) {
  731. char *b64buf;
  732. gsize olen = 0;
  733. if (G_UNLIKELY(slen == -1)) {
  734. if (G_LIKELY(width != 0)) {
  735. slen = width;
  736. }
  737. else {
  738. /* NULL terminated string */
  739. slen = strlen(p);
  740. }
  741. }
  742. b64buf = rspamd_encode_base64(p, slen, 0, &olen);
  743. if (b64buf) {
  744. RSPAMD_PRINTF_APPEND(b64buf, olen);
  745. g_free(b64buf);
  746. }
  747. else {
  748. RSPAMD_PRINTF_APPEND("(NULL)", sizeof("(NULL)") - 1);
  749. }
  750. }
  751. else {
  752. if (slen == -1) {
  753. /* NULL terminated string */
  754. slen = strlen(p);
  755. }
  756. if (G_UNLIKELY(width != 0)) {
  757. slen = MIN(slen, width);
  758. }
  759. RSPAMD_PRINTF_APPEND(p, slen);
  760. }
  761. continue;
  762. case 'O':
  763. i64 = (int64_t) va_arg(args, off_t);
  764. sign = 1;
  765. break;
  766. case 'P':
  767. i64 = (int64_t) va_arg(args, pid_t);
  768. sign = 1;
  769. break;
  770. case 't':
  771. i64 = (int64_t) va_arg(args, time_t);
  772. sign = 1;
  773. break;
  774. case 'z':
  775. if (sign) {
  776. i64 = (int64_t) va_arg(args, ssize_t);
  777. }
  778. else {
  779. ui64 = (uint64_t) va_arg(args, size_t);
  780. }
  781. break;
  782. case 'd':
  783. if (sign) {
  784. i64 = (int64_t) va_arg(args, int);
  785. }
  786. else {
  787. ui64 = (uint64_t) va_arg(args, unsigned int);
  788. }
  789. break;
  790. case 'l':
  791. if (sign) {
  792. i64 = (int64_t) va_arg(args, glong);
  793. }
  794. else {
  795. ui64 = (uint64_t) va_arg(args, gulong);
  796. }
  797. break;
  798. case 'D':
  799. if (sign) {
  800. i64 = (int64_t) va_arg(args, int32_t);
  801. }
  802. else {
  803. ui64 = (uint64_t) va_arg(args, uint32_t);
  804. }
  805. break;
  806. case 'L':
  807. if (sign) {
  808. i64 = va_arg(args, int64_t);
  809. }
  810. else {
  811. ui64 = va_arg(args, uint64_t);
  812. }
  813. break;
  814. case 'f':
  815. f = (double) va_arg(args, double);
  816. slen = fpconv_dtoa(f, dtoabuf, frac_width, false);
  817. RSPAMD_PRINTF_APPEND(dtoabuf, slen);
  818. continue;
  819. case 'g':
  820. f = (double) va_arg(args, double);
  821. slen = fpconv_dtoa(f, dtoabuf, 0, true);
  822. RSPAMD_PRINTF_APPEND(dtoabuf, slen);
  823. continue;
  824. case 'F':
  825. f = (double) va_arg(args, long double);
  826. slen = fpconv_dtoa(f, dtoabuf, frac_width, false);
  827. RSPAMD_PRINTF_APPEND(dtoabuf, slen);
  828. continue;
  829. case 'G':
  830. f = (double) va_arg(args, long double);
  831. slen = fpconv_dtoa(f, dtoabuf, 0, true);
  832. RSPAMD_PRINTF_APPEND(dtoabuf, slen);
  833. continue;
  834. case 'p':
  835. ui64 = (uintptr_t) va_arg(args, void *);
  836. hex = 2;
  837. sign = 0;
  838. zero = '0';
  839. width = sizeof(void *) * 2;
  840. break;
  841. case 'c':
  842. c = va_arg(args, int);
  843. c &= 0xffu;
  844. if (G_UNLIKELY(hex)) {
  845. char hexbuf[2];
  846. hexbuf[0] = hex == 2 ? _HEX[(c >> 4u) & 0xfu] : _hex[(c >> 4u) & 0xfu];
  847. hexbuf[1] = hex == 2 ? _HEX[c & 0xfu] : _hex[c & 0xfu];
  848. RSPAMD_PRINTF_APPEND(hexbuf, 2);
  849. }
  850. else {
  851. RSPAMD_PRINTF_APPEND(&c, 1);
  852. }
  853. continue;
  854. case 'Z':
  855. c = '\0';
  856. RSPAMD_PRINTF_APPEND(&c, 1);
  857. continue;
  858. case 'N':
  859. c = '\n';
  860. RSPAMD_PRINTF_APPEND(&c, 1);
  861. continue;
  862. case '%':
  863. c = '%';
  864. RSPAMD_PRINTF_APPEND(&c, 1);
  865. continue;
  866. default:
  867. c = *fmt;
  868. RSPAMD_PRINTF_APPEND(&c, 1);
  869. continue;
  870. }
  871. /* Print number */
  872. p = numbuf;
  873. last = p + sizeof(numbuf);
  874. if (sign) {
  875. if (i64 < 0) {
  876. *p++ = '-';
  877. ui64 = (uint64_t) -i64;
  878. }
  879. else {
  880. ui64 = (uint64_t) i64;
  881. }
  882. }
  883. if (!humanize) {
  884. p = rspamd_sprintf_num(p, last, ui64, zero, hex, b64 + b32, width);
  885. }
  886. else {
  887. p = rspamd_humanize_number(p, last, ui64, bytes);
  888. }
  889. slen = p - numbuf;
  890. RSPAMD_PRINTF_APPEND(numbuf, slen);
  891. }
  892. else {
  893. fmt++;
  894. }
  895. }
  896. /* Finish buffer */
  897. if (fmt > buf_start) {
  898. wr = func(buf_start, fmt - buf_start, apd);
  899. if (wr <= 0) {
  900. goto oob;
  901. }
  902. written += wr;
  903. }
  904. oob:
  905. return written;
  906. }