Full Code of FireyFly/hexd for AI

master ebfa9b5f76b5 cached
7 files
12.8 KB
4.1k tokens
6 symbols
1 requests
Download .txt
Repository: FireyFly/hexd
Branch: master
Commit: ebfa9b5f76b5
Files: 7
Total size: 12.8 KB

Directory structure:
gitextract_i2xq9q4j/

├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── hexd.1
└── hexd.c

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/hexd


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 1.1.0
  * default to colours/formatting based on whether output is a TTY
  * add verbose option to show all bytes (and not omit repeated lines)
  * add -h as an option to show usage
  * fix misaligned output in case -w width doesn't divide BUFSIZ
  * fix downcasting issue from `off_t` to a potentially smaller size

## 1.0.0
  initial release


================================================
FILE: LICENSE
================================================
Copyright (C) 2013 Jonas ‘FireFly’ Höglund


Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
CFLAGS += -Wall -std=c11

PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man

.PHONY: all
all: hexd

.PHONY: clean
clean:
	rm -f hexd

.PHONY: install
install: hexd
	mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
	install hexd $(DESTDIR)$(BINDIR)/hexd
	install hexd.1 $(DESTDIR)$(MANDIR)/man1/hexd.1


================================================
FILE: README.md
================================================
**hexd** prints a human-readable hexdump of the specified files, or standard
input if omitted.  Its main distinguishing feature is the use of colours to
visually indicate which range of values an octet belongs to, aiding in
spotting patterns in binary data.

By default, *hexd* relies on 256-color SGR escape sequences.  Most terminal
emulators should support these today, but technically they're only defacto
standard.  However, you can override the formatting used with the
`HEXD_COLORS` environment variable (see manpage), or use the `-p` option for
plaintext output.

## Screenshot
![Screenshot](meta/screenshot.png "Output after being run on an ELF binary")

## License
MIT license.

## See also
* [pixd](http://github.com/FireyFly/pixd):
  like *hexd*, but visualizes the data fed to it using a 256-colour palette
  and half-block ("▀") characters.


================================================
FILE: hexd.1
================================================
.Dd February 18, 2022
.Dt HEXD 1
.Os
.Sh NAME
.Nm hexd
.Nd human-friendly hexdump tool
.Sh SYNOPSIS
.Nm
.Op Fl p
.Op Fl P
.Op Fl v
.Op Fl g Ar groupsize
.Op Fl r Ar range
.Op Fl w Ar width
.Op Ar
.Sh DESCRIPTION
.Nm
prints a human-readable hexdump of the specified files, or standard input if
omitted.  Its main distinguishing feature is the use of colours to visually
indicate which range of values an octet belongs to, aiding in spotting
patterns in binary data.
.Pp
The ranges an octet is classified into are
.Em zero
.Li ( 0x00 ) ,
.Em low
.Li ( 0x01..0x1F ) ,
.Em printable
.Li ( 0x20..0x7E ) ,
.Em high
.Li ( 0x7F..0xFE )
and
.Em all
.Li ( 0xFF ) .
.Pp
By default, colours are used if output is a terminal, and omitted if not.
.Pp
Repeated output lines are collapsed into only one copy followed by a line with
only '*', unless
.Fl v
is used.
.Sh OPTIONS
If no
.Ar file
operands are specified, standard input is read instead.  Available options are
listed below.
.Bl -tag -width Ds
.It Fl h
Print usage information.
.It Fl p
Plain: disable colours/formatting.
.It Fl P
Pretty: enable colours/formatting.
.It Fl v
Verbose: show every hexdump line (don't collapse repetition with '*').
.It Fl g Ar groupsize
Number of octets per group, set to
.Li 8
by default.
.It Fl r Ar range
Range of octets to print from each file.
Specified as either
.Em start-end
or
.Em start+count ,
where
.Em start
and
.Em end Ns / Ns Em count
are positive integers specified in either decimal, hexadecimal or octal
(C-style notation).
.Pp
When the former syntax is used, both ends of the range are optional and
default to the start or end of the file when omitted.
.It Fl w Ar width
Number of octets per line, separated into groups (see
.Fl g ) .
Set to
.Li 16
by default.
.El
.Sh ENVIRONMENT
.Ev HEXD_COLORS
can be used to override the formatting used by
.Nm
to classify octets.  If set, it should consist of space-separated pairs of the
form
.Em key=value ,
where
.Em key
is one of 'zero', 'low', 'printable', 'high' or 'all', and
.Em value
is an SGR formatting string.  SGR formatting is interpreted by your terminal
emulator; consult its documentation or ECMA-48 for more details.
.Pp
For example, the default formatting used when
.Ev HEXD_COLORS
is not defined corresponds to the value
.Pp
.D1 Em zero=38;5;238 low=38;5;150 high=38;5;141 all=38;5;167
.Sh EXAMPLES
Here are some examples of useful uses of hexd's features.
.Bl -tag -width Ds
.It Em hexd -r0x1000+0x200 foo.bin
Display the 512-byte range in 'foo.bin' starting at offset 0x1000.  Useful
when files contain other embedded files/formats at a certain location (e.g.
archive files).
.It Em hexd -r-0x10 *.bin
Show the first 16 bytes of each of the *.bin files, with a heading above each
file (if more than one).  This is useful for example to compare headers of
several samples of an unknown format.
.It Em curl -s http://example.com | hexd -P | less -R
.Nm
works as a filter, too.  For paging long hexdumps,
.Xr less 1 Ns 's
.Fl R
flag is useful.
.El
.Sh SEE ALSO
.Xr hexdump 1 ,
.Xr od 1 ,
.Xr xxd 1
.Sh AUTHORS
Written by
.An FireFly


================================================
FILE: hexd.c
================================================
#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
#include <err.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MIN(X,Y) ((X) < (Y)? (X) : (Y))
typedef uint8_t u8;

//-- Options ----------------
struct offset_range { off_t start, end; };

size_t option_columns      = 16;
size_t option_groupsize    = 8;
bool option_use_formatting = true;
bool option_collapse_repetition = true;
struct offset_range option_range  = { 0, -1 };

const char *formatting_zero      = "38;5;238";
const char *formatting_all       = "38;5;167";
const char *formatting_low       = "38;5;150";
const char *formatting_high      = "38;5;141";
const char *formatting_printable = "";

//-- Hexdump impl -----------
const char *format_of(int v) {
  return v == 0x00?  formatting_zero
       : v == 0xFF?  formatting_all
       : v <  0x20?  formatting_low
       : v >= 0x7F?  formatting_high
       :             formatting_printable;
}

const char *CHAR_AREA_HIGH_LUT[] = {
  "€", ".", "‚", "ƒ", "„", "…", "†", "‡", "ˆ", "‰", "Š", "‹", "Œ", ".", "Ž", ".",
  ".", "‘", "’", "“", "”", "•", "–", "—", "˜", "™", "š", "›", "œ", ".", "ž", "Ÿ",
  ".", "¡", "¢", "£", "¤", "¥", "¦", "§", "¨", "©", "ª", "«", "¬", ".", "®", "¯",
  "°", "±", "²", "³", "´", "µ", "¶", "·", "¸", "¹", "º", "»", "¼", "½", "¾", "¿",
  "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï",
  "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß",
  "à", "á", "â", "ã", "ä", "å", "æ", "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï",
  "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷", "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ",
};

void hexdump(FILE *f, const char *filename) {
  u8 line[option_columns];
  u8 prev_line[option_columns];

  bool first_line = true, printed_asterisk = false;

  // Seek to start; fall back to a consuming loop for non-seekable files
  if (fseeko(f, option_range.start, SEEK_SET) < 0) {
    off_t remaining = option_range.start;
    while (remaining != 0 && fgetc(f) != EOF) remaining--;
    if (ferror(f)) err(1, "(while seeking) %s", filename);
  }

  for (off_t offset = option_range.start; offset < option_range.end || option_range.end == -1; offset += option_columns) {
    off_t read = offset - option_range.start;
    size_t n = fread(line, 1, option_columns, f);
    if (n == 0) break;

    // Contract repeated identical lines
    if (!first_line
          && option_collapse_repetition
          && memcmp(line, prev_line, option_columns) == 0
          && n == option_columns) {
      if (!printed_asterisk) {
        printf("%8s\n", "*");
        printed_asterisk = true;
      }
      continue;
    }
    printed_asterisk = false;

    // Offset
    intmax_t offset = option_range.start + read;
    printf("%5jx%03jx", offset >> 12, offset & 0xFFF);

    // Print hex area
    const char *prev_fmt = NULL;
    for (size_t j = 0; j < option_columns; j++) {
      if (option_groupsize != 0 && j % option_groupsize == 0) printf(" ");
      if (j < n) {
        const char *fmt = format_of(line[j]);
        if (prev_fmt != fmt && option_use_formatting) printf("\x1B[%sm", fmt);
        printf(" %02x", line[j]);
        prev_fmt = fmt;
      } else {
        printf("   ");
      }
    }
    putchar(' ');

    // Print char area
    for (size_t j = 0; j < option_columns; j++) {
      if (option_groupsize != 0 && j % option_groupsize == 0) printf(" ");
      if (j < n) {
        const char *fmt = format_of(line[j]);
        if (prev_fmt != fmt && option_use_formatting) printf("\x1B[%sm", fmt);
        if (line[j] >= 0x80) printf("%s", CHAR_AREA_HIGH_LUT[line[j] - 0x80]);
        else putchar(isprint(line[j])? line[j] : '.');
        prev_fmt = fmt;
      } else {
        putchar(' ');
      }
    }
    printf("%s\n", option_use_formatting? "\x1B[m" : "");

    memcpy(prev_line, line, n);
    first_line = false;
    if (n < option_columns) break;
  }

  if (ferror(f)) err(1, "(while reading) %s", filename);
}

//-- Entry point ------------
/** Parses a range "start-end" (both ends optional) or "start+size" (neither
 *  optional) into a `struct offset_range` instance. */
struct offset_range parse_range(const char *str) {
  struct offset_range res = { 0, -1 };
  const char *first = str, *delim = str + strcspn(str, "+-"), *second = delim + 1;
  if (*delim == '\0') errx(1, "no delimiter in range %s", str);

  char *end;
  if (first != delim) {
    res.start = strtoimax(first, &end, 0);
    if (!isdigit(*first) || end != delim) errx(1, "invalid start value in range %s", str);
  }
  if (*second != '\0') {
    res.end = strtoimax(second, &end, 0);
    if (!isdigit(*second) || *end != '\0') errx(1, "invalid end/size value in range %s", str);
  }

  if (*delim == '+') {
    if (first == delim) errx(1, "start unspecified in range %s", str);
    if (*second == '\0') errx(1, "size unspecified in range %s", str);
    res.end += res.start;
  }

  if (res.end < res.start && res.end != -1) errx(1, "end was less than start in range %s", str);
  return res;
}

int main(int argc, char *argv[]) {
  // Default to colourful output if output is a TTY
  option_use_formatting = isatty(1);

  // Parse options
  int opt;
  while (opt = getopt(argc, argv, "g:hpPr:w:v"), opt != -1) {
    switch (opt) {
      case 'g': option_groupsize = atol(optarg); break;
      case 'p': option_use_formatting = false; break;
      case 'P': option_use_formatting = true; break;
      case 'r': option_range = parse_range(optarg); break;
      case 'v': option_collapse_repetition = false; break;
      case 'w': option_columns = atol(optarg); break;
      case 'h': // fall through
      default:
        fprintf(stderr, "usage: hexd [-p] [-P] [-v] [-g groupsize] [-r range] [-w width]\n");
        return 1;
    }
  }
  argc -= optind;
  argv += optind;

  // Parse HEXD_COLORS
  char *colors_var = getenv("HEXD_COLORS");
  if (colors_var != NULL) {
    colors_var = strdup(colors_var);
    if (colors_var == NULL) errx(1, "strdup");

    for (char *p = colors_var, *token; token = strtok(p, " "), token != NULL; p = NULL) {
      char *key = token, *value = strchr(token, '=');
      if (value == NULL) warnx("no '=' found in HEXD_COLORS property '%s'", p);
      *value++ = '\0';

      if      (strcmp(key, "zero")      == 0) formatting_zero      = value;
      else if (strcmp(key, "low")       == 0) formatting_low       = value;
      else if (strcmp(key, "printable") == 0) formatting_printable = value;
      else if (strcmp(key, "high")      == 0) formatting_high      = value;
      else if (strcmp(key, "all")       == 0) formatting_all       = value;
      else warnx("unknown HEXD_COLORS property '%s'", key);
    }
  }

  // Hexdump files
  if (argc == 0) {
    hexdump(stdin, "(stdin)");
  } else {
    for (int i = 0; i < argc; i++) {
      FILE *f = fopen(argv[i], "r");
      if (f == NULL) {
        warn("%s", argv[i]);
        continue;
      }

      if (argc > 1) {
        printf("%s====> %s%s%s <====\n", i > 0? "\n" : "",
                                         option_use_formatting? "\x1B[1m" : "",
                                         argv[i],
                                         option_use_formatting? "\x1B[m" : "");
      }

      hexdump(f, argv[i]);
      fclose(f);
    }
  }

  free(colors_var);
  return 0;
}
Download .txt
gitextract_i2xq9q4j/

├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── Makefile
├── README.md
├── hexd.1
└── hexd.c
Download .txt
SYMBOL INDEX (6 symbols across 1 files)

FILE: hexd.c
  type u8 (line 13) | typedef uint8_t u8;
  type offset_range (line 16) | struct offset_range { off_t start, end; }
  type offset_range (line 22) | struct offset_range
  function hexdump (line 50) | void hexdump(FILE *f, const char *filename) {
  function parse_range (line 126) | struct offset_range parse_range(const char *str) {
  function main (line 151) | int main(int argc, char *argv[]) {
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (14K chars).
[
  {
    "path": ".gitignore",
    "chars": 6,
    "preview": "/hexd\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 360,
    "preview": "# Changelog\n\n## 1.1.0\n  * default to colours/formatting based on whether output is a TTY\n  * add verbose option to show "
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "Copyright (C) 2013 Jonas ‘FireFly’ Höglund\n\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "Makefile",
    "chars": 331,
    "preview": "CFLAGS += -Wall -std=c11\n\nPREFIX ?= /usr/local\nBINDIR ?= $(PREFIX)/bin\nMANDIR ?= $(PREFIX)/share/man\n\n.PHONY: all\nall: h"
  },
  {
    "path": "README.md",
    "chars": 855,
    "preview": "**hexd** prints a human-readable hexdump of the specified files, or standard\ninput if omitted.  Its main distinguishing "
  },
  {
    "path": "hexd.1",
    "chars": 3082,
    "preview": ".Dd February 18, 2022\n.Dt HEXD 1\n.Os\n.Sh NAME\n.Nm hexd\n.Nd human-friendly hexdump tool\n.Sh SYNOPSIS\n.Nm\n.Op Fl p\n.Op Fl "
  },
  {
    "path": "hexd.c",
    "chars": 7374,
    "preview": "#define _POSIX_C_SOURCE 200809L\n#include <ctype.h>\n#include <err.h>\n#include <inttypes.h>\n#include <stdbool.h>\n#include "
  }
]

About this extraction

This page contains the full source code of the FireyFly/hexd GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (12.8 KB), approximately 4.1k tokens, and a symbol index with 6 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!