logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git

xcd.c (4100B)


  1. // Collection of Unix tools, comparable to coreutils
  2. // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
  4. #define _POSIX_C_SOURCE 200809L
  5. #include <ctype.h> /* isprint() */
  6. #include <errno.h> /* errno */
  7. #include <math.h> /* sin() */
  8. #include <stdint.h> /* uint8_t */
  9. #include <stdio.h> /* printf(), fread(), fopen(), fclose() */
  10. #include <string.h> /* memset(), strerror() */
  11. struct rgb
  12. {
  13. double red, green, blue;
  14. };
  15. static struct rgb
  16. rgb_char(unsigned char i)
  17. {
  18. double freq = 0.018;
  19. if(i == 0)
  20. {
  21. return (struct rgb){64, 64, 64};
  22. }
  23. else
  24. {
  25. struct rgb color;
  26. double pi = 3.14159;
  27. color.red = sin(freq * i + 0 * pi / 3) * 127 + 128;
  28. color.green = sin(freq * i + 2 * pi / 3) * 127 + 128;
  29. color.blue = sin(freq * i + 4 * pi / 3) * 127 + 128;
  30. return color;
  31. }
  32. }
  33. static int
  34. print_hex_rgb(unsigned char c)
  35. {
  36. struct rgb color = rgb_char(c);
  37. int ret = printf("[38;2;%d;%d;%dm%02hhx ", (int)color.red, (int)color.green, (int)color.blue, c);
  38. return (ret <= 0) ? 1 : 0;
  39. }
  40. static int
  41. print_xcd_reset()
  42. {
  43. int ret = printf("");
  44. return (ret <= 0) ? 1 : 0;
  45. }
  46. static int
  47. print_plain_rgb(char *line, size_t len)
  48. {
  49. if(print_xcd_reset() != 0)
  50. {
  51. return 1;
  52. }
  53. if(printf(" >") <= 0)
  54. {
  55. return 1;
  56. }
  57. for(size_t i = 0; i < len; i++)
  58. {
  59. struct rgb color = rgb_char((unsigned char)line[i]);
  60. int ret = 0;
  61. ret = printf("[38;2;%d;%d;%dm%c",
  62. (int)color.red,
  63. (int)color.green,
  64. (int)color.blue,
  65. isprint(line[i]) ? line[i] : '.');
  66. if(ret <= 0)
  67. {
  68. return 1;
  69. }
  70. }
  71. if(print_xcd_reset() != 0)
  72. {
  73. return 1;
  74. }
  75. if(printf("<") <= 0)
  76. {
  77. return 1;
  78. }
  79. return 0;
  80. }
  81. #define WIDTH 16
  82. int
  83. concat(FILE *stream)
  84. {
  85. int cols = 0;
  86. char line[WIDTH];
  87. char c;
  88. unsigned int bytes = 0;
  89. struct rgb pos_rgb;
  90. int ret = 0;
  91. errno = 0;
  92. memset(&line, 0, WIDTH);
  93. if(print_xcd_reset() != 0)
  94. {
  95. goto werr;
  96. }
  97. pos_rgb = rgb_char((unsigned char)bytes);
  98. ret = printf(
  99. "[38;2;%d;%d;%dm0x%06x ", (int)pos_rgb.red, (int)pos_rgb.green, (int)pos_rgb.blue, bytes);
  100. if(ret <= 0)
  101. {
  102. goto werr;
  103. }
  104. while(fread(&c, 1, 1, stream) > 0)
  105. {
  106. if(cols >= WIDTH)
  107. {
  108. print_plain_rgb(line, (size_t)cols);
  109. memset(&line, 0, WIDTH);
  110. pos_rgb = rgb_char((unsigned char)bytes);
  111. printf("\n[38;2;%d;%d;%dm0x%06x ",
  112. (int)pos_rgb.red,
  113. (int)pos_rgb.green,
  114. (int)pos_rgb.blue,
  115. bytes);
  116. cols = 0;
  117. }
  118. ret = print_hex_rgb((unsigned char)c);
  119. if(ret != 0)
  120. {
  121. goto werr;
  122. }
  123. line[cols] = c;
  124. cols++;
  125. bytes++;
  126. }
  127. // Fill the rest of the hex space with spaces
  128. for(; cols < WIDTH; cols++)
  129. {
  130. ret = printf(" ");
  131. if(ret <= 0)
  132. {
  133. goto werr;
  134. }
  135. }
  136. if(print_xcd_reset() != 0)
  137. {
  138. goto werr;
  139. }
  140. ret = print_plain_rgb(line, (size_t)cols);
  141. if(ret != 0)
  142. {
  143. goto werr;
  144. }
  145. pos_rgb = rgb_char((unsigned char)bytes);
  146. ret = printf(
  147. "\n[38;2;%d;%d;%dm0x%06x\n", (int)pos_rgb.red, (int)pos_rgb.green, (int)pos_rgb.blue, bytes);
  148. if(ret <= 0)
  149. {
  150. goto werr;
  151. }
  152. if(print_xcd_reset() != 0)
  153. {
  154. goto werr;
  155. }
  156. return 0;
  157. werr:
  158. fprintf(stderr, "\nWrite error: %s\n", strerror(errno));
  159. return 1;
  160. }
  161. int
  162. main(int argc, char *argv[])
  163. {
  164. int err = 0;
  165. if(argc <= 1)
  166. {
  167. if(concat(stdin) != 0)
  168. {
  169. err = 1;
  170. goto cleanup;
  171. }
  172. }
  173. else
  174. {
  175. for(int argi = 1; (err == 0) && (argi < argc); argi++)
  176. {
  177. if(strncmp(argv[argi], "-", 2) == 0)
  178. {
  179. if(concat(stdin) != 0)
  180. {
  181. err = 1;
  182. goto cleanup;
  183. }
  184. }
  185. else
  186. {
  187. FILE *file = fopen(argv[argi], "r");
  188. if(!file)
  189. {
  190. fprintf(stderr, "\nError opening ā€˜%sā€™: %s\n", argv[argi], strerror(errno));
  191. err = 1;
  192. goto cleanup;
  193. }
  194. else
  195. {
  196. err += concat(file);
  197. err += fclose(file);
  198. if(err != 0)
  199. {
  200. fprintf(stderr, "\nError closing ā€˜%sā€™: %s\n", argv[argi], strerror(errno));
  201. err = 1;
  202. goto cleanup;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. cleanup:
  209. printf("");
  210. return err;
  211. }