xcd.c (4094B)
- // Collection of Unix tools, comparable to coreutils
- // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #include <ctype.h> /* isprint() */
- #include <errno.h> /* errno */
- #include <math.h> /* sin() */
- #include <stdint.h> /* uint8_t */
- #include <stdio.h> /* printf(), fread(), fopen(), fclose() */
- #include <string.h> /* memset(), strerror() */
- struct rgb
- {
- double red, green, blue;
- };
- static struct rgb
- rgb_char(unsigned char i)
- {
- double freq = 0.018;
- if(i == 0)
- {
- return (struct rgb){64, 64, 64};
- }
- else
- {
- struct rgb color;
- double pi = 3.14159;
- color.red = sin(freq * i + 0 * pi / 3) * 127 + 128;
- color.green = sin(freq * i + 2 * pi / 3) * 127 + 128;
- color.blue = sin(freq * i + 4 * pi / 3) * 127 + 128;
- return color;
- }
- }
- static int
- print_hex_rgb(unsigned char c)
- {
- struct rgb color = rgb_char(c);
- int ret = printf("[38;2;%d;%d;%dm%02hhx ", (int)color.red, (int)color.green, (int)color.blue, c);
- return (ret <= 0) ? 1 : 0;
- }
- static int
- print_xcd_reset()
- {
- int ret = printf("[0m[48;2;0;0;0m");
- return (ret <= 0) ? 1 : 0;
- }
- static int
- print_plain_rgb(char *line, size_t len)
- {
- if(print_xcd_reset() != 0)
- {
- return 1;
- }
- if(printf(" >") <= 0)
- {
- return 1;
- }
- for(size_t i = 0; i < len; i++)
- {
- struct rgb color = rgb_char((unsigned char)line[i]);
- int ret = 0;
- ret = printf("[38;2;%d;%d;%dm%c",
- (int)color.red,
- (int)color.green,
- (int)color.blue,
- isprint(line[i]) ? line[i] : '.');
- if(ret <= 0)
- {
- return 1;
- }
- }
- if(print_xcd_reset() != 0)
- {
- return 1;
- }
- if(printf("<") <= 0)
- {
- return 1;
- }
- return 0;
- }
- #define WIDTH 16
- int
- concat(FILE *stream)
- {
- int cols = 0;
- char line[WIDTH];
- char c;
- unsigned int bytes = 0;
- struct rgb pos_rgb;
- int ret = 0;
- errno = 0;
- memset(&line, 0, WIDTH);
- if(print_xcd_reset() != 0)
- {
- goto werr;
- }
- pos_rgb = rgb_char((unsigned char)bytes);
- ret = printf(
- "[38;2;%d;%d;%dm0x%06x ", (int)pos_rgb.red, (int)pos_rgb.green, (int)pos_rgb.blue, bytes);
- if(ret <= 0)
- {
- goto werr;
- }
- while(fread(&c, 1, 1, stream) > 0)
- {
- if(cols >= WIDTH)
- {
- print_plain_rgb(line, (size_t)cols);
- memset(&line, 0, WIDTH);
- pos_rgb = rgb_char((unsigned char)bytes);
- printf("\n[38;2;%d;%d;%dm0x%06x ",
- (int)pos_rgb.red,
- (int)pos_rgb.green,
- (int)pos_rgb.blue,
- bytes);
- cols = 0;
- }
- ret = print_hex_rgb((unsigned char)c);
- if(ret != 0)
- {
- goto werr;
- }
- line[cols] = c;
- cols++;
- bytes++;
- }
- // Fill the rest of the hex space with spaces
- for(; cols < WIDTH; cols++)
- {
- ret = printf(" ");
- if(ret <= 0)
- {
- goto werr;
- }
- }
- if(print_xcd_reset() != 0)
- {
- goto werr;
- }
- ret = print_plain_rgb(line, (size_t)cols);
- if(ret != 0)
- {
- goto werr;
- }
- pos_rgb = rgb_char((unsigned char)bytes);
- ret = printf(
- "\n[38;2;%d;%d;%dm0x%06x\n", (int)pos_rgb.red, (int)pos_rgb.green, (int)pos_rgb.blue, bytes);
- if(ret <= 0)
- {
- goto werr;
- }
- if(print_xcd_reset() != 0)
- {
- goto werr;
- }
- return 0;
- werr:
- fprintf(stderr, "\n[0mxcd: Write error: %s\n", strerror(errno));
- return 1;
- }
- int
- main(int argc, char *argv[])
- {
- int err = 0;
- if(argc <= 1)
- {
- if(concat(stdin) != 0)
- {
- err = 1;
- goto cleanup;
- }
- }
- else
- {
- for(int argi = 1; (err == 0) && (argi < argc); argi++)
- {
- if(strncmp(argv[argi], "-", 2) == 0)
- {
- if(concat(stdin) != 0)
- {
- err = 1;
- goto cleanup;
- }
- }
- else
- {
- FILE *file = fopen(argv[argi], "r");
- if(!file)
- {
- fprintf(stderr, "\n[0mxcd: Error opening ‘%s’: %s\n", argv[argi], strerror(errno));
- err = 1;
- goto cleanup;
- }
- else
- {
- err += concat(file);
- err += fclose(file);
- if(err != 0)
- {
- fprintf(stderr, "\n[0mxcd: Error closing ‘%s’: %s\n", argv[argi], strerror(errno));
- err = 1;
- goto cleanup;
- }
- }
- }
- }
- }
- cleanup:
- printf("[0m");
- return err;
- }