From a1ab98f9f84d29c6735b1061202a4225bdad2bb8 Mon Sep 17 00:00:00 2001 From: Laurent Mazet Date: Mon, 9 Jan 2023 17:27:59 +0100 Subject: [PATCH] initial version --- debug.c | 5 ++ debug.h | 21 +++++ getcomments.pl | 85 +++++++++++++++++++++ hexdump.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 142 ++++++++++++++++++++++++++++++++++ 5 files changed, 456 insertions(+) create mode 100644 debug.c create mode 100644 debug.h create mode 100644 getcomments.pl create mode 100644 hexdump.c create mode 100644 makefile diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..151e615 --- /dev/null +++ b/debug.c @@ -0,0 +1,5 @@ +#include "debug.h" + +int verbose = 1; + +/* vim: set ts=4 sw=4 et: */ diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..32dc0ca --- /dev/null +++ b/debug.h @@ -0,0 +1,21 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +/* constants */ + +#define DEBUG 3 +#define INFO 2 +#define WARNING 1 +#define ERROR 0 + +/* macros */ + +#define VERBOSE(level, statement...) do { if (level <= verbose) { statement; } } while(0) + +/* gobal variables */ + +extern int verbose; + +#endif /* __DEBUG_H__ */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/getcomments.pl b/getcomments.pl new file mode 100644 index 0000000..47edf67 --- /dev/null +++ b/getcomments.pl @@ -0,0 +1,85 @@ +#!/usr/bin/perl + +use strict; + +# default value +my $format = "%"; +my $pattern = ""; + +# help message +sub usage() { + + print <) { + my $cmt; + + # process c++ comments + ($cmt, $_) = m{//\s*(.*?)\s*$()} if (m{//} && !m{/\*.*//}); + + # process standard c comments + ($cmt, $_) = m{^.*?/\*\s*(.*?)\s*\*/(.*)}s if (m{/\*.*\*/}s); + + push(@comments, $cmt) if ($cmt); + + # empty buffer if no comment is present + undef($_) if (!m{/[/*]}); + } + + # close file + close (IN); + + # display comment blocks + foreach my $block (@comments) { + if (($block) = ($block =~ /$pattern(.*)/s)) { + ($_ = $format) =~ s/%/$block/gs; + print "$_\n"; + } + } +} diff --git a/hexdump.c b/hexdump.c new file mode 100644 index 0000000..32cb1a5 --- /dev/null +++ b/hexdump.c @@ -0,0 +1,203 @@ +/* depend: */ +/* cflags: */ +/* linker: debug.o */ + +#include +#include +#include +#include +#include +#include + +#include "debug.h" + +/* macros */ + +#define CEIL(x, y) (((x) + (y) - 1) / (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) + +//#define BUFFERSIZE 4096 +#define BUFFERSIZE 256 +#define NBCOLS 8 + +/* gobal variables */ + +char *progname = NULL; + +/* help function */ + +void usage (int ret) +{ + FILE *fd = ret ? stderr : stdout; + fprintf (fd, "usage: %s [-i file] [-h] [-n nbcols] [-o file] [-v]\n", progname); + fprintf (fd, " -i : input file\n"); + fprintf (fd, " -h : help message\n"); + fprintf (fd, " -n : number of columns\n"); + fprintf (fd, " -o : output file\n"); + fprintf (fd, " -v : verbose level (%d)\n", verbose); + + exit (ret); +} + +/* get number of digits */ + +int getnbdigits (long int l) { + int n = 0; + while (l) { + n += 2; + l /= 256; + } + return n; +} + +/* print a line */ + +void printline (char *buffer, int nbcols, int nb, int addr, int nbdigits) { + int i; + + printf ("0x%0*x:", nbdigits, addr); + for (i = 0; i < nb; i++) { + printf (" %02x", buffer[i]); + } + for (i = nb; i < nbcols; i++) { + printf (" "); + } + printf (" "); + for (i = 0; i < nb; i++) { + char c = buffer[i]; + printf ("%c", (c > 31) && (c < 127) ? c : '.'); + } + printf ("\n"); +} + +/* indent function */ + +int hexdump (FILE *fin, int nbcols) { + char buffer[BUFFERSIZE] = {0}; + int i; + + char *pt = buffer; + + /* get file size */ + int nbdigits = 0; + if (fin != stdin) { + fseek (fin, 0 , SEEK_END); + long int filesize = ftell (fin); + fseek (fin, 0 , SEEK_SET); + nbdigits = getnbdigits (filesize); + } else { + nbdigits = 6; + } + + int addr = 0; + int nb = 0; + while (!feof (fin)) { + nb += fread (pt, 1, BUFFERSIZE - (pt - buffer), fin); + pt = buffer; + + /* print line */ + while ((nb - (int)(pt - buffer)) / nbcols > 0) { + printline (pt, nbcols, nbcols, addr, nbdigits); + pt += nbcols; + addr += nbcols; + } + + /* copy end buffer */ + nb -= pt - buffer; + for (i = 0; i < nb; i++) { + buffer[i] = pt[i]; + } + pt = buffer + nb; + } + + /* last line */ + if (nb > 0) { + printline (buffer, nbcols, nb, addr, nbdigits); + } + + return 0; +} + +/* main function */ + +int main (int argc, char *argv[]) +{ + char *input = NULL; + char *output = NULL; + int nbcols = NBCOLS; + + /* get basename */ + char *pt = progname = argv[0]; + while (*pt) { + if ((*pt == '/') || (*pt == '\\')) { + progname = pt + 1; + } + pt++; + } + + int c; + while ((c = getopt(argc, argv, "i:hn:o:v:")) != EOF) { + switch (c) { + case 'i': + input = optarg; + break; + case 'n': + nbcols = atoi (optarg); + break; + case 'o': + output = optarg; + break; + case 'v': + verbose = atoi (optarg); + break; + case 'h': + default: + usage (c != 'h'); + } + } + if (argc - optind != 0) { + fprintf (stderr, "%s: invalid option -- %s\n", progname, argv[optind]); + usage (1); + } + + /* check input */ + FILE *fin = NULL; + if (input) { + fin = fopen (input, "rb"); + if (!fin) { + VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", input)); + } + } else { + fin = stdin; + } + + /* check output */ + FILE *fout = NULL; + if (output) { + fout = fopen (input, "wb"); + if (!fout) { + VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", output)); + fclose (fin); + } + } else { + fout = stdout; + } + + hexdump (fin, nbcols); + + /* close all */ + fclose (fin); + fclose (fout); + + return 0; +} + +// test: hexdump.exe -h +// test: hexdump.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }' +// test: hexdump.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }' +// test: hexdump.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }' +// test: hexdump.exe -i hexdump.c | grep -q '0x[0-9a-f]*: ' +// test: hexdump.exe -i hexdump.c -n 3|head -2|tail -1| grep '0x0003: 64 65 70 dep' + +/* vim: set ts=4 sw=4 et: */ diff --git a/makefile b/makefile new file mode 100644 index 0000000..77a6c83 --- /dev/null +++ b/makefile @@ -0,0 +1,142 @@ +# Default flags + +CC = gcc + +INCLUDES = -I../debug -D__MEMORY_ALLOCATION__ +OFLAGS = -O4 -Os +#OFLAGS = -O4 -ffast-math -finline-functions +#OFLAGS = -O4 -finline-functions +#OFLAGS += -mtune=pentium3 -mmmx -msse -msse2 -m3dnow +#OFLAGS += -minline-all-stringops -fsingle-precision-constant +#OFLAGS += -malign-double +CFLAGS += -W -Wall -Wextra -g +CFLAGS += -std=c99 -D_XOPEN_SOURCE=500 +CFLAGS += $(OFLAGS) $(INCLUDES) $(GCOVER) +LDFLAGS += -g + +# Targets + +ALLEXE = +ALLEXE += hexdump +#ALLEXE += skel + +SHELL = bash + +MAKE = mingw32-make +MAKEFLAGS += -s + +# Functions + +TITLE = echo -en "\033[0;1m$(strip $(1))\033[0;0m:\t" +PASS = echo -e "\033[1;32m$(strip $(1))\033[0;0m" +WARN = echo -e "\033[1;33m$(strip $(1))\033[0;0m" +FAIL = echo -e "\033[1;31m$(strip $(1))\033[0;0m" + +MKDIR = mkdir -p $(1) && chmod a+rx,go-w $(1) + +INSTALL = test -d `dirname $(2)` || $(call MKDIR, `dirname $(2)`) && cp -pa $(1) $(2) && chmod a+rX,go-w $(2) + +VALID = $(call TITLE, $(1)) && $(2) && $(call PASS, SUCCESS) || { $(call FAIL, FAILED); test; } + +## Generic rules + +all: depends + $(MAKE) $(ALLEXE:%=%.exe) + +count: + wc $(wildcard *.c *.h) $(MAKEFILE_LIST) + +clean: + $(call TITLE, "Cleaning") + touch clean + rm -f clean $(wildcard *.d *.ld *.log *.o *.test *~ .exec_*) + $(call PASS, SUCCESS) + +depends: $(patsubst %.c, %.d, $(wildcard *.c)) $(patsubst %, %.ld, $(ALLEXE)) + +gcovs: + $(MAKE) $(addprefix gcov_,$(ALLEXE)) + +purge: clean + $(call TITLE, "Purging") + touch purge + rm -f purge $(ALLEXE:%=%.exe) + $(call PASS, SUCCESS) + +valgrinds: + $(MAKE) $(addprefix valgrind_,$(ALLEXE)) + +wipe: purge + $(call TITLE, "Wiping") + touch wipe + rm -f wipe $(wildcard *.gcda *.gcno *.gcov) + $(call PASS, SUCCESS) + +tests: all + $(MAKE) $(addprefix test_,$(ALLEXE)) + +## Main rules + +include $(wildcard *.d) +include $(wildcard *.ld) + +gcov_%: + $(MAKE) purge + CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs -ftest-coverage" $(MAKE) + $(MAKE) test_$(@:gcov_%=%) + gcov `sed -e 's/\.exe:/.c/;s/\.o/.c/g' $(@:gcov_%=%.ld)` + touch gcov + rm -f gcov $(wildcard *.gcda *.gcno) + $(MAKE) purge + +%.test: %.c + $(call TITLE, "Building $@") +# awk '/\/\* *test:.*\*\// { sub(/^.*\/\* *test: */, ""); sub(/ *\*\/.*$$/, ""); print }' $< > $@ + ./getcomments.pl -p='test:\s' -f='%' $< > $@ + $(call PASS, SUCCESS) + +test_%: %.test %.exe + IFS=$$'\n'; RC=0; \ + for test in `cat $< | sed 's,${<:.test=.exe},./${<:.test=.exe},g'`; do \ + echo "=== $$test ==="; \ + eval $(VALGRIND) $$test; \ + [ $$? -eq 0 ] && echo -e "\033[1;32mSUCCESS\033[0;0m" \ + || { echo -e "\033[1;31mFAILED\033[0;0m"; RC=1; }; \ + done; \ + test "$$RC" -ne 1 + +valgrind_%: %.exe + VALGRIND="valgrind -v --leak-check=full --show-reachable=yes --log-fd=2"; \ + export VALGRIND; \ + $(MAKE) $(@:valgrind_%=test_%) + +%.d: %.c + $(call TITLE, "Building $@") + $(CC) $(INCLUDES) -MM $< -o $@~ + echo ${<:.c=.o}: $(shell ./getcomments.pl -p='depend:\s' -f='%' $<) >> $@~ + mv $@~ $@ + $(call PASS, SUCCESS) + +%.ld: %.c + $(call TITLE, "Building $@") + echo ${<:.c=.exe}: $(shell ./getcomments.pl -p='linker:\s' -f='%' $< | awk '{for (i=1;i<=NF;i++) if ($$(i) ~ /.o$$/) printf " %s", $$(i)}') > $@ + $(call PASS, SUCCESS) + +%.o: %.c + $(call TITLE, "Building $@") + $(CC) $(CFLAGS) $(INCLUDES) $(shell ./getcomments.pl -p='cflags:\s' -f='%' $<) -c $< -o $@ + $(call PASS, SUCCESS) + + +%.exe: %.o %.d + $(call TITLE, "Building $@") + $(CC) $(LDFLAGS) $(shell ./getcomments.pl -p='linker:\s' -f='%' ${<:.o=.c}) $< -o $@ + $(call PASS, SUCCESS) + +## Phony + +.PHONY: all clean count depends gcovs purge tests + +## Precious + +.PRECIOUS: %.d %.o -- 2.30.2