logo

utils-extra

Collection of extra tools for Unixes

xcd.c (4142B)


  1. // utils-extra: Collection of extra tools for Unixes
  2. // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  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. ret = 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. if (ret <= 0)
  117. {
  118. goto werr;
  119. }
  120. cols = 0;
  121. }
  122. ret = print_hex_rgb((unsigned char)c);
  123. if(ret != 0)
  124. {
  125. goto werr;
  126. }
  127. line[cols] = c;
  128. cols++;
  129. bytes++;
  130. }
  131. // Fill the rest of the hex space with spaces
  132. for(; cols < WIDTH; cols++)
  133. {
  134. ret = printf(" ");
  135. if(ret <= 0)
  136. {
  137. goto werr;
  138. }
  139. }
  140. if(print_xcd_reset() != 0)
  141. {
  142. goto werr;
  143. }
  144. ret = print_plain_rgb(line, (size_t)cols);
  145. if(ret != 0)
  146. {
  147. goto werr;
  148. }
  149. pos_rgb = rgb_char((unsigned char)bytes);
  150. ret = printf(
  151. "\n[38;2;%d;%d;%dm0x%06x\n", (int)pos_rgb.red, (int)pos_rgb.green, (int)pos_rgb.blue, bytes);
  152. if(ret <= 0)
  153. {
  154. goto werr;
  155. }
  156. if(print_xcd_reset() != 0)
  157. {
  158. goto werr;
  159. }
  160. return 0;
  161. werr:
  162. fprintf(stderr, "\nxcd: Write error: %s\n", strerror(errno));
  163. return 1;
  164. }
  165. int
  166. main(int argc, char *argv[])
  167. {
  168. int err = 0;
  169. if(argc <= 1)
  170. {
  171. if(concat(stdin) != 0)
  172. {
  173. err = 1;
  174. goto cleanup;
  175. }
  176. }
  177. else
  178. {
  179. for(int argi = 1; (err == 0) && (argi < argc); argi++)
  180. {
  181. if(strncmp(argv[argi], "-", 2) == 0)
  182. {
  183. if(concat(stdin) != 0)
  184. {
  185. err = 1;
  186. goto cleanup;
  187. }
  188. }
  189. else
  190. {
  191. FILE *file = fopen(argv[argi], "r");
  192. if(!file)
  193. {
  194. fprintf(stderr, "\nxcd: Error opening ‘%s’: %s\n", argv[argi], strerror(errno));
  195. err = 1;
  196. goto cleanup;
  197. }
  198. else
  199. {
  200. err += concat(file);
  201. err += fclose(file);
  202. if(err != 0)
  203. {
  204. fprintf(stderr, "\nxcd: Error closing ‘%s’: %s\n", argv[argi], strerror(errno));
  205. err = 1;
  206. goto cleanup;
  207. }
  208. }
  209. }
  210. }
  211. }
  212. cleanup:
  213. printf("");
  214. return err;
  215. }