sstream.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "pocketpy/common/sstream.h"
  2. #include "pocketpy/common/str.h"
  3. #include "pocketpy/common/utils.h"
  4. #include "pocketpy/common/dmath.h"
  5. #include "pocketpy/common/floatconv.h"
  6. #include "pocketpy/pocketpy.h"
  7. #include <stdarg.h>
  8. #include <assert.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <ctype.h>
  12. void c11_sbuf__ctor(c11_sbuf* self) {
  13. c11_vector__ctor(&self->data, sizeof(char));
  14. c11_vector__reserve(&self->data, sizeof(c11_string) + 64);
  15. self->data.length = sizeof(c11_string);
  16. }
  17. void c11_sbuf__dtor(c11_sbuf* self) { c11_vector__dtor(&self->data); }
  18. void c11_sbuf__write_char(c11_sbuf* self, char c) { c11_vector__push(char, &self->data, c); }
  19. void c11_sbuf__write_pad(c11_sbuf* self, int count, char pad) {
  20. for(int i = 0; i < count; i++) {
  21. c11_sbuf__write_char(self, pad);
  22. }
  23. }
  24. void c11_sbuf__write_int(c11_sbuf* self, int i) {
  25. // len('-2147483648') == 11
  26. c11_vector__reserve(&self->data, self->data.length + 11 + 1);
  27. char* p = (char*)self->data.data + self->data.length;
  28. int n = snprintf(p, 11 + 1, "%d", i);
  29. self->data.length += n;
  30. }
  31. void c11_sbuf__write_i64(c11_sbuf* self, int64_t val) {
  32. // len('-9223372036854775808') == 20
  33. c11_vector__reserve(&self->data, self->data.length + 20 + 1);
  34. char* p = (char*)self->data.data + self->data.length;
  35. int n = snprintf(p, 20 + 1, "%lld", (long long)val);
  36. self->data.length += n;
  37. }
  38. void c11_sbuf__write_f64(c11_sbuf* self, double val, int precision) {
  39. if(dmath_isinf(val)) {
  40. c11_sbuf__write_cstr(self, val > 0 ? "inf" : "-inf");
  41. return;
  42. }
  43. if(dmath_isnan(val)) {
  44. c11_sbuf__write_cstr(self, "nan");
  45. return;
  46. }
  47. if(precision < 0) {
  48. char b[C11_F64_SHORTEST_BUF_SIZE];
  49. int size = c11__f64_to_shortest(b, sizeof(b), val);
  50. assert(size > 0); // C11_F64_SHORTEST_BUF_SIZE is always enough
  51. c11_sbuf__write_cstrn(self, b, size);
  52. // a float should still look like a float once rendered
  53. bool all_is_digit = true;
  54. for(int i = 0; i < size; i++) {
  55. if(b[i] == '.' || b[i] == 'e') {
  56. all_is_digit = false;
  57. break;
  58. }
  59. }
  60. if(all_is_digit) c11_sbuf__write_cstr(self, ".0");
  61. } else {
  62. if(precision > C11_F64_MAX_PRECISION) precision = C11_F64_MAX_PRECISION;
  63. // "%.*f" of a large value needs a lot of room, so render into the
  64. // buffer itself instead of a fixed-size scratch array
  65. int capacity = C11_F64_FIXED_BUF_SIZE(precision);
  66. c11_vector__reserve(&self->data, self->data.length + capacity);
  67. char* p = (char*)self->data.data + self->data.length;
  68. self->data.length += c11__f64_to_fixed(p, capacity, val, precision);
  69. }
  70. }
  71. void c11_sbuf__write_sv(c11_sbuf* self, c11_sv sv) {
  72. c11_sbuf__write_cstrn(self, sv.data, sv.size);
  73. }
  74. void c11_sbuf__write_cstr(c11_sbuf* self, const char* str) {
  75. c11_sbuf__write_cstrn(self, str, strlen(str));
  76. }
  77. void c11_sbuf__write_cstrn(c11_sbuf* self, const char* str, int n) {
  78. c11_vector__extend(&self->data, str, n);
  79. }
  80. void c11_sbuf__write_quoted(c11_sbuf* self, c11_sv sv, char quote) {
  81. assert(quote == '"' || quote == '\'');
  82. c11_sbuf__write_char(self, quote);
  83. for(int i = 0; i < sv.size; i++) {
  84. char c = sv.data[i];
  85. switch(c) {
  86. case '"':
  87. case '\'':
  88. if(c == quote) c11_sbuf__write_char(self, '\\');
  89. c11_sbuf__write_char(self, c);
  90. break;
  91. case '\\': c11_sbuf__write_cstrn(self, "\\\\", 2); break;
  92. case '\n': c11_sbuf__write_cstrn(self, "\\n", 2); break;
  93. case '\r': c11_sbuf__write_cstrn(self, "\\r", 2); break;
  94. case '\t': c11_sbuf__write_cstrn(self, "\\t", 2); break;
  95. case '\b': c11_sbuf__write_cstrn(self, "\\b", 2); break;
  96. default: {
  97. int u8bytes = c11__u8_header(c, true);
  98. if(i + u8bytes > sv.size) u8bytes = 0; // invalid utf8
  99. if(u8bytes <= 1) {
  100. // not a valid utf8 char, or ascii
  101. if(!isprint((unsigned char)c)) {
  102. unsigned char uc = (unsigned char)c;
  103. c11_sbuf__write_cstrn(self, "\\x", 2);
  104. c11_sbuf__write_char(self, PK_HEX_TABLE[uc >> 4]);
  105. c11_sbuf__write_char(self, PK_HEX_TABLE[uc & 0xf]);
  106. } else {
  107. c11_sbuf__write_char(self, c);
  108. }
  109. } else {
  110. for(int j = 0; j < u8bytes; j++) {
  111. c11_sbuf__write_char(self, sv.data[i + j]);
  112. }
  113. i += u8bytes - 1;
  114. }
  115. break;
  116. }
  117. }
  118. }
  119. c11_sbuf__write_char(self, quote);
  120. }
  121. void c11_sbuf__write_hex(c11_sbuf* self, unsigned char c, bool non_zero) {
  122. unsigned char high = c >> 4;
  123. unsigned char low = c & 0xf;
  124. if(non_zero) {
  125. if(high) c11_sbuf__write_char(self, PK_HEX_TABLE[high]);
  126. if(high || low) c11_sbuf__write_char(self, PK_HEX_TABLE[low]);
  127. } else {
  128. c11_sbuf__write_char(self, PK_HEX_TABLE[high]);
  129. c11_sbuf__write_char(self, PK_HEX_TABLE[low]);
  130. }
  131. }
  132. void c11_sbuf__write_ptr(c11_sbuf* self, void* p) {
  133. if(p == NULL) {
  134. c11_sbuf__write_cstr(self, "0x0");
  135. return;
  136. }
  137. c11_sbuf__write_cstr(self, "0x");
  138. uintptr_t p_t = (uintptr_t)(p);
  139. bool non_zero = true;
  140. for(int i = sizeof(void*) - 1; i >= 0; i--) {
  141. unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
  142. c11_sbuf__write_hex(self, cpnt, non_zero);
  143. if(cpnt != 0) non_zero = false;
  144. }
  145. }
  146. c11_string* c11_sbuf__submit(c11_sbuf* self) {
  147. c11_vector__push(char, &self->data, '\0');
  148. int arr_length;
  149. c11_string* retval = c11_vector__submit(&self->data, &arr_length);
  150. retval->size = arr_length - sizeof(c11_string) - 1;
  151. return retval;
  152. }
  153. void c11_sbuf__py_submit(c11_sbuf* self, py_Ref out) {
  154. c11_string* res = c11_sbuf__submit(self);
  155. py_newstrv(out, (c11_sv){res->data, res->size});
  156. c11_string__delete(res);
  157. }
  158. void pk_vsprintf(c11_sbuf* ss, const char* fmt, va_list args) {
  159. while(*fmt) {
  160. char c = *fmt;
  161. if(c != '%') {
  162. c11_sbuf__write_char(ss, c);
  163. fmt++;
  164. continue;
  165. }
  166. fmt++;
  167. c = *fmt;
  168. switch(c) {
  169. case 'd': {
  170. int i = va_arg(args, int);
  171. c11_sbuf__write_int(ss, i);
  172. break;
  173. }
  174. case 'i': {
  175. int64_t i = va_arg(args, int64_t);
  176. c11_sbuf__write_i64(ss, i);
  177. break;
  178. }
  179. case 'f': {
  180. double d = va_arg(args, double);
  181. c11_sbuf__write_f64(ss, d, -1);
  182. break;
  183. }
  184. case 's': {
  185. const char* s = va_arg(args, const char*);
  186. c11_sbuf__write_cstr(ss, s);
  187. break;
  188. }
  189. case 'q': {
  190. c11_sv sv = va_arg(args, c11_sv);
  191. c11_sbuf__write_quoted(ss, sv, '\'');
  192. break;
  193. }
  194. case 'Q': {
  195. c11_sv sv = va_arg(args, c11_sv);
  196. c11_sbuf__write_quoted(ss, sv, '"');
  197. break;
  198. }
  199. case 'v': {
  200. c11_sv sv = va_arg(args, c11_sv);
  201. c11_sbuf__write_sv(ss, sv);
  202. break;
  203. }
  204. case 'c': {
  205. char c = va_arg(args, int);
  206. c11_sbuf__write_char(ss, c);
  207. break;
  208. }
  209. case 'p': {
  210. void* p = va_arg(args, void*);
  211. c11_sbuf__write_ptr(ss, p);
  212. break;
  213. }
  214. case 't': {
  215. py_Type t = va_arg(args, int);
  216. c11_sbuf__write_cstr(ss, py_tpname(t));
  217. break;
  218. }
  219. case 'n': {
  220. py_Name n = va_arg(args, void*);
  221. c11_sbuf__write_cstr(ss, py_name2str(n));
  222. break;
  223. }
  224. case '%': c11_sbuf__write_char(ss, '%'); break;
  225. default:
  226. c11_sbuf__write_char(ss, c);
  227. assert(false); // invalid format
  228. break;
  229. }
  230. fmt++;
  231. }
  232. }
  233. void pk_sprintf(c11_sbuf* ss, const char* fmt, ...) {
  234. va_list args;
  235. va_start(args, fmt);
  236. pk_vsprintf(ss, fmt, args);
  237. va_end(args);
  238. }