Last active
January 15, 2021 12:49
-
-
Save gvanem/4290a4c74ac75983928502303cb4c0c2 to your computer and use it in GitHub Desktop.
A Gnu-makefile to generate a file (curl_opt_err.c) with all current 'CURLOPT_x' and 'CURLE_x' values.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# A Gnu-makefile to generate a C-program ($(PROGRAM).c) with all | |
# current 'CURLOPT_x' and 'CURLE_x' values. | |
# | |
# NB! must be invoked from libcurl's './lib' directory. | |
# | |
# By G. Vanem <gvanem@yahoo.no> 2014 - 2018. | |
# | |
# The basename of what this makefile generates; | |
# A 'curl_opt_err.c' and a 'curl_opt_err.exe' (on Windows). | |
# Should work on non-Windows too; will produce a 'curl_opt_err' | |
# by the below '$(PROGRAM)$(EXE):' rule. | |
# | |
# To use MSVC, do a: | |
# c:\curl\lib> make -f mk-opt-err-list.mak CC=cl | |
# | |
# Or for 'clang-cl', do a: | |
# c:\curl\lib> make -f mk-opt-err-list.mak CC=clang-cl | |
# | |
# Or for 'gcc', do a: | |
# c:\curl\lib> make -f mk-opt-err-list.mak CC=gcc | |
# | |
PROGRAM = curl_opt_err | |
THIS_FILE = $(MAKEFILE_LIST) | |
# | |
# The following assumes you have a MSys/Cygwin 'echo.exe' program with colour support. | |
# On non-Windows that should be no issue (?) | |
# | |
BRIGHT_GREEN = \e[1;32m | |
colour_msg = @echo -e "$(1)\e[0m" | |
green_msg = $(call colour_msg,$(BRIGHT_GREEN)$(strip $(1))) | |
# | |
# Extract all 'CURLOPT()' macros in '../include/curl/curl.h' and | |
# build a list of *current* 'CURLOPT_x' using the 'ADD_CURRENT_OPT()' macro. | |
# | |
OPTIONS = grep '^\ \ CURLOPT(' ../include/curl/curl.h | cut -f1 -d, | sed 's/CURLOPT(//' | |
OPTIONS := $(shell $(OPTIONS)) | |
# | |
# Extract all 'CURLE_x' enums in '../include/curl/curl.h' and | |
# build a list for the below 'ADD_ERR()' loop. | |
# | |
ERRORS = grep --only-matching '^\ \ CURLE_[_A-Z0-9]*' ../include/curl/curl.h | |
ERRORS := $(shell $(ERRORS)) | |
# | |
# Count all '#define CURL' lines generated in '$(PROGRAM).symbols'. | |
# | |
NUM_SYMBOLS = $(shell grep -c --only-matching '^\#define CURL' $(PROGRAM).symbols) | |
# | |
# List obsolete '#define CURLOPT_x' lines generated in '$(PROGRAM).symbols'. | |
# I.e. 'x_LAST' was last featured in version x.y.z. | |
# | |
CURLOPT_OBSOLETE = $(shell grep --only-matching '^\#define CURLOPT_.*_LAST' $(PROGRAM).symbols | cut -f2 -d' ') | |
define Usage | |
Usage: "$(MAKE) -f mk-opt-err-list.mak CC=[cl | clang-cl | gcc] [all | clean]" | |
endef | |
# | |
# Check the given $(CC). | |
# | |
ifeq ($(CC),gcc) | |
CFLAGS = -Wall | |
LDFLAGS = | |
else ifeq ($(CC),cl) | |
CFLAGS = -nologo -MD -Zi | |
MSVC_STYLE = 1 | |
else ifeq ($(CC),clang-cl) | |
export CL= | |
CFLAGS = -nologo -MD -Zi -W4 -Wno-microsoft-include | |
MSVC_STYLE = 1 | |
else | |
$(error $(Usage)) | |
endif | |
CFLAGS += -I../include | |
ifeq ($(OS),Windows_NT) | |
EXE = .exe | |
ifeq ($(CC),gcc) | |
CFLAGS += -m32 | |
LDFLAGS = -m32 # Assumes a dual-mode MinGW | |
endif | |
endif | |
ifeq ($(MSVC_STYLE),1) | |
LDFLAGS = -nologo -incremental:no | |
endif | |
define MAIN_PROGRAM_TOP | |
/* | |
* This file has been generated by $(realpath $(THIS_FILE)) at | |
* $(shell date +%d-%B-%Y). DO NOT EDIT! | |
*/ | |
#include "curl_setup.h" | |
/** | |
* "$(PROGRAM).symbols" is generated by 'perl ../docs/libcurl/symbols.pl'. | |
* | |
* \todo put this in a search-list to search for obsolete symbols. | |
* '!LIBCURL_HAS(sym)' -> 0, a symbol ending in '_LAST'. | |
*/ | |
#include "$(PROGRAM).symbols" | |
/* No version info for these. | |
*/ | |
#define CURLOPT_OBSOLETE40_FIRST 0 | |
#define CURLOPT_OBSOLETE72_FIRST 0 | |
#define CURLE_OBSOLETE20_FIRST 0 | |
#define CURLE_OBSOLETE24_FIRST 0 | |
#define CURLE_OBSOLETE29_FIRST 0 | |
#define CURLE_OBSOLETE32_FIRST 0 | |
#define CURLE_OBSOLETE40_FIRST 0 | |
#define CURLE_OBSOLETE44_FIRST 0 | |
#define CURLE_OBSOLETE46_FIRST 0 | |
#define CURLE_OBSOLETE50_FIRST 0 | |
#define CURLE_OBSOLETE51_FIRST 0 | |
#define CURLE_OBSOLETE57_FIRST 0 | |
/* # of CURLE_OBSOLETE codes. | |
*/ | |
static unsigned num_obsoleted_err = 0; | |
struct key_val { | |
unsigned val; | |
const char *name; | |
unsigned added_ver; /* In what version was it added? (hex-encoded) */ | |
unsigned removed_ver; /* In what version was it removed? (hex-encoded) */ | |
const char *man3_page; | |
}; | |
#if defined(_WIN32) | |
#include <io.h> | |
#define FILE_EXIST(fname) (access(fname,0) == 0) | |
#define SLASH '\\' | |
#else | |
#include <unistd.h> | |
#define FILE_EXIST(fname) (chmod(fname,0) != -1) | |
#define SLASH '/' | |
#endif | |
static char our_dir [1000]; /* The directory of '$(PROGRAM)$(EXE)' */ | |
/* Since there seems to be no obsolete 'CURLE_x' values, there are no 'CURLE_x_LAST'. | |
*/ | |
#define ADD_ERR(err) { err, #err, err ##_FIRST, 0, NULL } | |
#define ADD_CURRENT_OPT(opt) { opt, #opt, opt ##_FIRST, 0, "../docs/libcurl/opts/" #opt ".3" } | |
#define ADD_OBSOLETE_OPT(opt) { opt, #opt, 0, opt, "../docs/libcurl/opts/" #opt ".3" } | |
#define DIM(array) (int) (sizeof(array) / sizeof(array[0])) | |
/** \todo print obsoleted symbols as e.g. '<7.1.1' ? | |
*/ | |
static const char *decode_version (const struct key_val *kv, int added) | |
{ | |
static char ver_str [20]; | |
unsigned ver = added ? kv->added_ver : kv->removed_ver; | |
if (ver == 0 /* || !_libcurl_has(kv->val) */) | |
return (""); | |
snprintf (ver_str, sizeof(ver_str), "%d.%d.%d", (ver >> 16) & 255, (ver & 0xFF00) >> 8, ver & 255); | |
return (ver_str); | |
} | |
#if 0 | |
static const char *removed_in_version (struct key_val *kv) | |
{ | |
static ver_str [20]; | |
unsigned ver = kv->removed_ver; | |
if (!_libcurl_has(kv->val)) | |
snprintf (ver_str, sizeof(ver_str), "%-6s", decode_version(kv,0)); | |
else strcpy (ver_str, ""); | |
return (ver_str); | |
} | |
#endif | |
endef | |
define MAIN_PROGRAM_BOTTOM | |
static const char *decode_err (const struct key_val *e) | |
{ | |
if (!strncmp(e->name, "CURLE_OBSOLETE", sizeof("CURLE_OBSOLETE")-1)) | |
{ | |
num_obsoleted_err++; | |
return ("<Historic, obsolete>"); | |
} | |
return curl_easy_strerror ((CURLcode)e->val); | |
} | |
static void print_all_CURLEs (void) | |
{ | |
const struct key_val *e = errors; | |
int i; | |
puts ("\nCURLE_x value version curl_easy_strerror()\n" | |
"=================================================================="); | |
for (i = 0; i < DIM(errors); i++, e++) | |
printf ("%-30.30s %2u %-6s %s\n", | |
e->name, e->val, decode_version(e,1), decode_err(e)); | |
} | |
static const char *decode_opt (unsigned opt) | |
{ | |
static char ret[100]; | |
const char *type = "long"; /* CURLOPTTYPE_LONG == 0 */ | |
if (opt >= CURLOPTTYPE_OFF_T) | |
{ | |
opt -= CURLOPTTYPE_OFF_T; | |
type = "off_t"; | |
} | |
else if (opt >= CURLOPTTYPE_FUNCTIONPOINT) | |
{ | |
opt -= CURLOPTTYPE_FUNCTIONPOINT; | |
type = "function"; | |
} | |
else if (opt >= CURLOPTTYPE_OBJECTPOINT) | |
{ | |
opt -= CURLOPTTYPE_OBJECTPOINT; | |
type = "object/string"; | |
} | |
snprintf (ret, sizeof(ret), "%3u: %s", opt, type); | |
return (ret); | |
} | |
static int man3_page_exist (const struct key_val *o, const char **expected_name) | |
{ | |
static char file [1000]; | |
*expected_name = NULL; | |
if (!o->man3_page) | |
return (0); | |
if (!strncmp(o->name,"CURLOPT_OBSOLETE",16)) /* Ignore these */ | |
return (1); | |
snprintf (file, sizeof(file), "%s/%s", our_dir, o->man3_page); | |
*expected_name = file; | |
return FILE_EXIST (file); | |
} | |
static void print_all_CURLOPTs (void) | |
{ | |
const struct key_val *o = current_options; | |
const char *p; | |
int i; | |
puts ("Idx CURLOPT_x value: arg type raw val version\n" | |
"================================================================================"); | |
for (i = 0; i < DIM(current_options); i++, o++) | |
{ | |
const char *expected_3name; | |
int exists = man3_page_exist (o, &expected_3name); | |
printf ("%3d: %-35.35s -> %-20s %5u %-6s", | |
i, o->name, decode_opt(o->val), o->val, decode_version(o,1)); | |
if (!exists) | |
printf (" missing '%s'", expected_3name); | |
putchar ('\n'); | |
} | |
puts ("\nThese are obsolete:"); | |
o = obsolete_options; | |
for (i = 0; i < DIM(obsolete_options); i++, o++) | |
{ | |
size_t last_len = strlen(o->name); | |
p = strrchr (o->name, '_'); | |
if (p && !strcmp(p,"_LAST")) | |
last_len -= sizeof("_LAST") - 1; | |
printf ("%3d: %-67.*s %-6s\n", | |
i, (int)last_len, o->name, decode_version(o,0)); | |
} | |
} | |
static int do_help (void) | |
{ | |
const char *help = " -o: print all CURLOPT_x values.\n" $\\ | |
" -e: print all CURLE_x values.\n"; | |
printf ("Usage: %s%c%s\n%s", our_dir, SLASH, "$(PROGRAM)$(EXE)", help); | |
return (0); | |
} | |
int main (int argc, char **argv) | |
{ | |
char *slash = strrchr (argv[0], SLASH); | |
if (slash) | |
{ | |
strncpy (our_dir, argv[0], (size_t)(slash-argv[0])); | |
*slash = '\0'; | |
} | |
else | |
strcpy (our_dir, "."); | |
if (argc != 2 || !strcmp(argv[1],"-h") || !strcmp(argv[1],"--help") ) | |
return do_help(); | |
if (!strcmp(argv[1],"-o")) | |
print_all_CURLOPTs(); | |
else if (!strcmp(argv[1],"-e")) | |
print_all_CURLEs(); | |
printf ("\nCurrent ver: %s.\n", LIBCURL_VERSION); | |
printf ("Obsolete symbols: CURLOPT: %u\n" | |
" CURLE: %u.\n", | |
DIM(obsolete_options), num_obsoleted_err); | |
return (0); | |
} | |
endef | |
all: check_libdir $(PROGRAM)$(EXE) | |
$(PROGRAM).c: make_symbols $(THIS_FILE) | |
$(file > $@,$(MAIN_PROGRAM_TOP)) | |
$(file >> $@, static const struct key_val current_options[] = {) | |
$(foreach o, $(sort $(OPTIONS)), \ | |
$(file >> $@, ADD_CURRENT_OPT ($(o)),)) | |
$(file >> $@, };) | |
$(file >> $@,) | |
$(file >> $@, static const struct key_val obsolete_options[] = {) | |
$(foreach o, $(sort $(CURLOPT_OBSOLETE)), \ | |
$(file >> $@, ADD_OBSOLETE_OPT ($(o)),)) | |
$(file >> $@, };) | |
$(file >> $@,) | |
$(file >> $@, static const struct key_val errors[] = {) | |
$(foreach e, $(ERRORS), \ | |
$(file >> $@, ADD_ERR ($(e)), ) ) | |
$(file >> $@, };) | |
$(file >> $@,$(MAIN_PROGRAM_BOTTOM)) | |
$(call green_msg, $(words $(OPTIONS)) CURLOPT_x values generated for $@.) | |
$(call green_msg, $(words $(ERRORS)) CURLE_x values generated for $@.) | |
make_symbols: $(PROGRAM).symbols | |
$(call green_msg, $(NUM_SYMBOLS) CURL symbols generated for $<.) | |
@echo 'These are obsolete:' | |
@$(foreach o, $(CURLOPT_OBSOLETE), \ | |
echo ' $(o)' ;) | |
$(PROGRAM).symbols: $(THIS_FILE) | |
$(call green_msg, Generating $@.) | |
@echo -ne "// Generated by 'perl ../docs/libcurl/symbols.pl'.\n// DO NOT EDIT.\n" > $@ | |
(cd ../docs/libcurl; perl symbols.pl) >> $@ | |
$(PROGRAM)$(EXE): $(PROGRAM).c | |
$(call green_msg, Compiling and linking $@.) | |
$(call compile_and_link, $@, $<) | |
@echo '$@ done.' | |
check_libdir: | |
ifeq ($(wildcard curl_setup.h),) | |
$(error Must be invoked from libcurl's './lib' directory.) | |
endif | |
ifeq ($(MSVC_STYLE),1) | |
define compile_and_link | |
$(CC) -c $(CFLAGS) $(2) | |
link -out:$(strip $(1)) $(LDFLAGS) $(2:.c=.obj) libcurl_imp.lib | |
rm -f $(2:.c=.obj) | |
endef | |
else | |
compile_and_link = $(CC) -o $(1) $(CFLAGS) $(LDFLAGS) $(2) -L . -lcurl | |
endif | |
clean: | |
rm -f $(PROGRAM).* |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment