IRC client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pls.c 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* Copyright (C) 2018 Curtis McEnroe <june@causal.agency>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Affero General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <errno.h>
  17. #include <stdarg.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <wchar.h>
  21. #include "chat.h"
  22. wchar_t *wcsnchr(const wchar_t *wcs, size_t len, wchar_t chr) {
  23. len = wcsnlen(wcs, len);
  24. for (size_t i = 0; i < len; ++i) {
  25. if (wcs[i] == chr) return (wchar_t *)&wcs[i];
  26. }
  27. return NULL;
  28. }
  29. wchar_t *wcsnrchr(const wchar_t *wcs, size_t len, wchar_t chr) {
  30. len = wcsnlen(wcs, len);
  31. for (size_t i = len - 1; i < len; --i) {
  32. if (wcs[i] == chr) return (wchar_t *)&wcs[i];
  33. }
  34. return NULL;
  35. }
  36. wchar_t *ambstowcs(const char *src) {
  37. size_t len = mbsrtowcs(NULL, &src, 0, NULL);
  38. if (len == (size_t)-1) return NULL;
  39. wchar_t *dst = malloc(sizeof(*dst) * (1 + len));
  40. if (!dst) return NULL;
  41. len = mbsrtowcs(dst, &src, len, NULL);
  42. if (len == (size_t)-1) {
  43. free(dst);
  44. return NULL;
  45. }
  46. dst[len] = L'\0';
  47. return dst;
  48. }
  49. char *awcstombs(const wchar_t *src) {
  50. size_t len = wcsrtombs(NULL, &src, 0, NULL);
  51. if (len == (size_t)-1) return NULL;
  52. char *dst = malloc(sizeof(*dst) * (1 + len));
  53. if (!dst) return NULL;
  54. len = wcsrtombs(dst, &src, len, NULL);
  55. if (len == (size_t)-1) {
  56. free(dst);
  57. return NULL;
  58. }
  59. dst[len] = '\0';
  60. return dst;
  61. }
  62. char *awcsntombs(const wchar_t *src, size_t nwc) {
  63. size_t len = wcsnrtombs(NULL, &src, nwc, 0, NULL);
  64. if (len == (size_t)-1) return NULL;
  65. char *dst = malloc(sizeof(*dst) * (1 + len));
  66. if (!dst) return NULL;
  67. len = wcsnrtombs(dst, &src, nwc, len, NULL);
  68. if (len == (size_t)-1) {
  69. free(dst);
  70. return NULL;
  71. }
  72. dst[len] = '\0';
  73. return dst;
  74. }
  75. // From <https://en.cppreference.com/w/c/io/fwprintf#Notes>:
  76. //
  77. // While narrow strings provide snprintf, which makes it possible to determine
  78. // the required output buffer size, there is no equivalent for wide strings
  79. // (until C11's snwprintf_s), and in order to determine the buffer size, the
  80. // program may need to call swprintf, check the result value, and reallocate a
  81. // larger buffer, trying again until successful.
  82. //
  83. // snwprintf_s, unlike swprintf_s, will truncate the result to fit within the
  84. // array pointed to by buffer, even though truncation is treated as an error by
  85. // most bounds-checked functions.
  86. int vaswprintf(wchar_t **ret, const wchar_t *format, va_list ap) {
  87. *ret = NULL;
  88. for (size_t cap = 2 * wcslen(format);; cap *= 2) {
  89. wchar_t *buf = realloc(*ret, sizeof(*buf) * (1 + cap));
  90. if (!buf) goto fail;
  91. *ret = buf;
  92. va_list _ap;
  93. va_copy(_ap, ap);
  94. errno = EOVERFLOW; // vswprintf may not set errno.
  95. int len = vswprintf(*ret, 1 + cap, format, _ap);
  96. va_end(_ap);
  97. if (len >= 0) return len;
  98. if (errno != EOVERFLOW) goto fail;
  99. }
  100. fail:
  101. free(*ret);
  102. *ret = NULL;
  103. return -1;
  104. }
  105. int aswprintf(wchar_t **ret, const wchar_t *format, ...) {
  106. va_list ap;
  107. va_start(ap, format);
  108. int n = vaswprintf(ret, format, ap);
  109. va_end(ap);
  110. return n;
  111. }
  112. static const char Base64[64] =
  113. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  114. char *base64(const byte *src, size_t len) {
  115. char *dst = malloc(1 + 4 * (len + 2) / 3);
  116. if (!dst) return NULL;
  117. size_t i = 0;
  118. while (len > 2) {
  119. dst[i++] = Base64[0x3F & (src[0] >> 2)];
  120. dst[i++] = Base64[0x3F & (src[0] << 4 | src[1] >> 4)];
  121. dst[i++] = Base64[0x3F & (src[1] << 2 | src[2] >> 6)];
  122. dst[i++] = Base64[0x3F & src[2]];
  123. src += 3;
  124. len -= 3;
  125. }
  126. if (len) {
  127. dst[i++] = Base64[0x3F & (src[0] >> 2)];
  128. if (len > 1) {
  129. dst[i++] = Base64[0x3F & (src[0] << 4 | src[1] >> 4)];
  130. dst[i++] = Base64[0x3F & (src[1] << 2)];
  131. } else {
  132. dst[i++] = Base64[0x3F & (src[0] << 4)];
  133. dst[i++] = '=';
  134. }
  135. dst[i++] = '=';
  136. }
  137. dst[i] = '\0';
  138. return dst;
  139. }
  140. #ifdef TEST
  141. #include <assert.h>
  142. #include <string.h>
  143. int main() {
  144. char *cat = base64((byte *)"cat", 3);
  145. char *ca = base64((byte *)"ca", 2);
  146. char *c = base64((byte *)"c", 1);
  147. assert(cat);
  148. assert(ca);
  149. assert(c);
  150. assert(!strcmp("Y2F0", cat));
  151. assert(!strcmp("Y2E=", ca));
  152. assert(!strcmp("Yw==", c));
  153. free(cat);
  154. free(ca);
  155. free(c);
  156. char *fzf = base64((byte []) { 0xFF, 0x00, 0xFF }, 3);
  157. char *zfz = base64((byte []) { 0x00, 0xFF, 0x00 }, 3);
  158. assert(fzf);
  159. assert(zfz);
  160. assert(!strcmp("/wD/", fzf));
  161. assert(!strcmp("AP8A", zfz));
  162. free(fzf);
  163. free(zfz);
  164. }
  165. #endif