xcd.c (3605B)
- // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+xcd-rgb@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #define _XOPEN_SOURCE 700
- #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() */
- #ifndef M_PI
- #define 3.14159265358979323846
- #endif
- #ifndef ARG0_XCD_RGB
- const char *argv0 = "xcd-rgb";
- #else
- const char *argv0 = "xcd";
- #endif
- struct rgb
- {
- int r, g, b;
- };
- static struct rgb
- rgb_char(uint8_t i)
- {
- double freq = 0.018;
- if(i == 0) return (struct rgb){64, 64, 64};
- struct rgb color;
- color.r = sin(freq * i + 0 * M_PI / 3) * 127 + 128;
- color.g = sin(freq * i + 2 * M_PI / 3) * 127 + 128;
- color.b = sin(freq * i + 4 * M_PI / 3) * 127 + 128;
- return color;
- }
- static int
- print_hex_rgb(uint8_t c)
- {
- struct rgb color = rgb_char(c);
- if(printf("\033[38;2;%d;%d;%dm%02hhx ", color.r, color.g, color.b, c) <= 0) return 1;
- return 0;
- }
- static int
- print_xcd_reset()
- {
- if(printf("\033[0m\033[48;2;0;0;0m") <= 0) return 1;
- return 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(line[i]);
- if(printf(
- "\033[38;2;%d;%d;%dm%c", color.r, color.g, color.b, isprint(line[i]) ? line[i] : '.') <=
- 0)
- return 1;
- }
- if(print_xcd_reset() != 0) return 1;
- if(printf("<") <= 0) return 1;
- return 0;
- }
- #define WIDTH 16
- static int
- concat(FILE *stream)
- {
- long unsigned int bytes = 0;
- errno = 0;
- if(print_xcd_reset() != 0) goto werr;
- struct rgb pos_rgb = rgb_char(bytes);
- if(printf("\033[38;2;%d;%d;%dm0x%06lx ", pos_rgb.r, pos_rgb.g, pos_rgb.b, bytes) < 0) goto werr;
- size_t cols = 0;
- char line[WIDTH] = "";
- char c;
- while(fread(&c, 1, 1, stream) > 0)
- {
- if(cols >= WIDTH)
- {
- print_plain_rgb(line, cols);
- memset(&line, 0, WIDTH);
- pos_rgb = rgb_char(bytes);
- if(printf("\n\033[38;2;%d;%d;%dm0x%06lx ", pos_rgb.r, pos_rgb.g, pos_rgb.b, bytes) < 0)
- goto werr;
- cols = 0;
- }
- if(print_hex_rgb(c) != 0) goto werr;
- line[cols] = c;
- cols++;
- bytes++;
- }
- // Fill the rest of the hex space with spaces
- for(; cols < WIDTH; cols++)
- if(printf(" ") <= 0) goto werr;
- if(print_plain_rgb(line, cols) != 0) goto werr;
- pos_rgb = rgb_char(bytes);
- if(printf("\n\033[38;2;%d;%d;%dm0x%06lx\n", pos_rgb.r, pos_rgb.g, pos_rgb.b, bytes) <= 0)
- goto werr;
- if(print_xcd_reset() != 0) goto werr;
- return 0;
- werr:
- fprintf(stderr, "\n\033[0m%s: error: Failed writing to stdout: %s\n", argv0, strerror(errno));
- return 1;
- }
- int
- main(int argc, char *argv[])
- {
- int err = 0;
- if(argc <= 1)
- {
- err = concat(stdin);
- printf("\033[0m");
- return err;
- }
- for(int argi = 1; (err == 0) && (argi < argc); argi++)
- {
- if(strncmp(argv[argi], "-", 2) == 0)
- {
- if(concat(stdin) != 0)
- {
- err = 1;
- break;
- }
- continue;
- }
- FILE *file = fopen(argv[argi], "rb");
- if(!file)
- {
- fprintf(stderr,
- "\n\033[0m%s: error: Failed opening file ‘%s’: %s\n",
- argv0,
- argv[argi],
- strerror(errno));
- err = 1;
- break;
- }
- err += concat(file);
- if(fclose(file) != 0)
- {
- fprintf(stderr,
- "\n\033[0m%s: error: Failed closing file ‘%s’: %s\n",
- argv0,
- argv[argi],
- strerror(errno));
- err = 1;
- break;
- }
- }
- printf("\033[0m");
- return err;
- }