From 8512671a90036c66450b6ea995be9356b377066e Mon Sep 17 00:00:00 2001 From: Laurent Mazet Date: Mon, 24 Apr 2023 11:19:33 +0200 Subject: [PATCH] minimal skeleton --- color.c | 96 +++++++++++++++++++++++++++++++++ color.h | 41 ++++++++++++++ debug.c | 5 ++ debug.h | 32 +++++++++++ getcomments.pl | 85 +++++++++++++++++++++++++++++ makefile | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ webserver.c | 95 ++++++++++++++++++++++++++++++++ 7 files changed, 498 insertions(+) create mode 100644 color.c create mode 100644 color.h create mode 100644 debug.c create mode 100644 debug.h create mode 100644 getcomments.pl create mode 100644 makefile create mode 100644 webserver.c diff --git a/color.c b/color.c new file mode 100644 index 0000000..7aec785 --- /dev/null +++ b/color.c @@ -0,0 +1,96 @@ +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#include "color.h" + +#ifdef _WIN32 /* Windows */ + +void color_set (FILE *fid, color_e color) +{ + /* save default configuration */ + static WORD init = 0; + if (init == 0) { + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info); + init = info.wAttributes; + } + + /* default attribute */ + WORD attr = 0; + + /* define foreground color */ + if (FG_DEFAULT == (color & FG_MASK)) { + attr |= init & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + } else { + attr |= (color & FG_BRIGHT) ? FOREGROUND_INTENSITY : 0; + switch (color & FG_MASK) { + case FG_RED: attr |= FOREGROUND_RED; break; + case FG_GREEN: attr |= FOREGROUND_GREEN; break; + case FG_BLUE: attr |= FOREGROUND_BLUE; break; + case FG_YELLOW: attr |= FOREGROUND_RED | FOREGROUND_GREEN; break; + case FG_MAGENTA: attr |= FOREGROUND_RED | FOREGROUND_BLUE; break; + case FG_CYAN: attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; break; + case FG_WHITE: attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; + } + } + + /* define background color */ + if (BG_DEFAULT == (color & BG_MASK)) { + attr |= init & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); + } else { + attr |= (color & BG_BRIGHT) ? BACKGROUND_INTENSITY : 0; + switch (color&BG_MASK) { + case BG_RED: attr |= BACKGROUND_RED; break; + case BG_GREEN: attr |= BACKGROUND_GREEN; break; + case BG_BLUE: attr |= BACKGROUND_BLUE; break; + case BG_YELLOW: attr |= BACKGROUND_RED | BACKGROUND_GREEN; break; + case BG_MAGENTA: attr |= BACKGROUND_RED | BACKGROUND_BLUE; break; + case BG_CYAN: attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; break; + case BG_WHITE: attr |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break; + } + } + + /* define underline state */ + if (color & UNDERLINE) { + attr |= COMMON_LVB_UNDERSCORE; + } + + /* set text attribute */ + SetConsoleTextAttribute (GetStdHandle ((fid == stdout) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE), attr); +} + +#else /* Linux */ + +void color_set (FILE *fid, color_e color) +{ + /* check if it's a terminal */ + if (!isatty (fileno (fid))) { + return; + } + + /* default color */ + fprintf (fid, "\033[m"); + + /* set foreground color */ + if (FG_DEFAULT != (color & FG_MASK)) { + fprintf (fid, "\033[%dm", 29 + (color & FG_MASK) + ((color & FG_BRIGHT) ? 60 : 0)); + } + + /* set background color */ + if (BG_DEFAULT != (color & BG_MASK)) { + fprintf (fid, "\033[%dm", 39 + ((color & BG_MASK ) >> 8) + ((color & BG_BRIGHT) ? 60 : 0)); + } + + /* set underline state */ + if (color & UNDERLINE) { + fprintf (fid, "\033[4m"); + } +} + +#endif /* _WIN32 */ + +/* vim: set ts=4 sw=4 et: */ diff --git a/color.h b/color.h new file mode 100644 index 0000000..6a2e8dc --- /dev/null +++ b/color.h @@ -0,0 +1,41 @@ +#ifndef __COLOR_H__ +#define __COLOR_H__ + +#include "stdio.h" + +typedef enum { + FG_DEFAULT = 0x00, + FG_BLACK = 0x01, + FG_RED = 0x02, + FG_GREEN = 0x03, + FG_YELLOW = 0x04, + FG_BLUE = 0x05, + FG_MAGENTA = 0x06, + FG_CYAN = 0x07, + FG_WHITE = 0x08, + FG_BRIGHT = 0x80, + FG_MASK = 0x7F, + + BG_DEFAULT = 0x0000, + BG_BLACK = 0x0100, + BG_RED = 0x0200, + BG_GREEN = 0x0300, + BG_YELLOW = 0x0400, + BG_BLUE = 0x0500, + BG_MAGENTA = 0x0600, + BG_CYAN = 0x0700, + BG_WHITE = 0x0800, + BG_BRIGHT = 0x8000, + BG_MASK = 0x7F00, + + UNDERLINE = 0x10000, + + COLOR_DEFAULT = FG_DEFAULT | BG_DEFAULT +} color_e; + +/* Set text color, COLOR_DEFAULT will revert to default setting */ +void color_set (FILE *fid, color_e color); + +#endif /* __COLOR_H__ */ + +/* vim: set ts=4 sw=4 et: */ 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..46442d4 --- /dev/null +++ b/debug.h @@ -0,0 +1,32 @@ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include "color.h" + +/* constants */ + +#define DEBUG 3 +#define INFO 2 +#define WARNING 1 +#define ERROR 0 + +/* macros */ + +#define VERBOSE(level, statement...) \ + do { if (level <= verbose) { CHANGE_COLOR(level); statement; CHANGE_COLOR(-1); } } while(0) + +#define CHANGE_COLOR(level) \ + color_set ((level == ERROR) ? stderr : stdout, \ + (level == ERROR) ? FG_RED : \ + (level == WARNING) ? FG_YELLOW : \ + (level == INFO) ? FG_BLUE : \ + (level == DEBUG) ? FG_GREEN : COLOR_DEFAULT) + +/* vim: set ts=4 sw=4 et: */ +/* 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/makefile b/makefile new file mode 100644 index 0000000..b8a856e --- /dev/null +++ b/makefile @@ -0,0 +1,144 @@ +# 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) $(GCOV) +LDFLAGS += -g $(GCOV) + +# Targets + +ALLEXE = +ALLEXE += webserver +#ALLEXE += skel + +SHELL = bash + +#MAKE = mingw32-make +MAKEFLAGS += -s +include $(wildcard .makefile) + +# 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 + GCOV="-coverage -O0" $(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 + grep '#####' *.c.gcov || true + +%.test: %.c + $(call TITLE, "Building $@") +# awk '/\/\* *test:.*\*\// { sub(/^.*\/\* *test: */, ""); sub(/ *\*\/.*$$/, ""); print }' $< > $@ + perl -- getcomments.pl -p='test:\s' -f='%' $< > $@ + $(call PASS, SUCCESS) + +test_%: %.test %.exe + IFS=$$'\n'; RC=0; \ + for test in `cat $< | sed 's,${<:.test=.exe},$(VALGRIND) ./${<:.test=.exe},g'`; do \ + echo "=== $$test ==="; \ + eval $$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 --log-fd=3"; \ + export VALGRIND; \ + $(MAKE) $(@:valgrind_%=test_%) 3>$@.log + +%.d: %.c + $(call TITLE, "Building $@") + $(CC) $(INCLUDES) -MM $< -o $@~ + echo ${<:.c=.o}: $(shell perl -- getcomments.pl -p='depend:\s' -f='%' $<) >> $@~ + mv $@~ $@ + $(call PASS, SUCCESS) + +%.ld: %.c + $(call TITLE, "Building $@") + echo ${<:.c=.exe}: $(shell perl -- 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 perl -- getcomments.pl -p='cflags:\s' -f='%' $<) -c $< -o $@ + $(call PASS, SUCCESS) + + +%.exe: %.o %.d + $(call TITLE, "Building $@") + $(CC) $(LDFLAGS) $< $(shell perl -- 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 diff --git a/webserver.c b/webserver.c new file mode 100644 index 0000000..c5d2199 --- /dev/null +++ b/webserver.c @@ -0,0 +1,95 @@ +/* depend: */ +/* cflags: */ +/* linker: color.o debug.o */ + +#include +#include + +#include "debug.h" + +/* constants */ + +#define BUFFER_SIZE 4096 + +/* macros */ + +/* gobal variables */ + +char *progname = NULL; + +/* help function */ + +int usage (int ret) +{ + FILE *fid = ret ? stderr : stdout; + fprintf (fid, "usage: %s\n", progname); + fprintf (fid, " -h : help message\n"); + fprintf (fid, " -v : verbose level (%d)\n", verbose); + + return ret; +} + +/* main function */ + +int main (int argc, char *argv[]) +{ + int i = 0; + int ret = 0; + + /* program name */ + + progname = argv[0]; + while (progname[i] != '\0') { + if ((progname[i] == '/') || (progname[i] == '\\')) { + progname += i + 1; + i = 0; + } else { + i++; + } + } + + /* argument processing */ + + while (argc-- > 1) { + char *arg = *(++argv); + if (arg[0] != '-') { + VERBOSE (ERROR, fprintf (stderr, "%s: invalid option -- '%s'\n", progname, arg); usage (1)); + return 1; + } + char c = arg[1]; + switch (c) { +/* + case 'i': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (ERROR, fprintf (stderr, "%s: missing input prompt\n", progname); usage (1)); + return 1; + } + iprompt = arg; + break; +*/ + case 'v': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (ERROR, fprintf (stderr, "%s: missing verbose level\n", progname); usage (1)); + return 1; + } + verbose = atoi (arg); + break; + case 'h': + default: + return usage (c != 'h'); + } + } + + return ret; +} + +// test: webserver.exe -h +// test: webserver.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }' +// test: echo 1 | webserver.exe -v3 | grep -q value +// test: webserver.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }' +// test: webserver.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }' +// test: webserver.exe error 2>&1 | grep -q 'invalid option' + +/* vim: set ts=4 sw=4 et: */ -- 2.30.2