Skip to content

Instantly share code, notes, and snippets.

@imaami
Last active March 6, 2024 19:52
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save imaami/5d81c30861dac2944af782789e520e59 to your computer and use it in GitHub Desktop.
Save imaami/5d81c30861dac2944af782789e520e59 to your computer and use it in GitHub Desktop.
#template<>
#!/usr/bin/env bash
file="$1"
[[ -e "$file" ]] || exit 1
declare -r B='[[:blank:]]'
declare -a sed_args=()
lines="$(grep -En "^$B*#$B*template$B*<$B*[^>[:blank:]]+($B+-[DU][^>[:blank:]]+)*$B*>$B*(/[/\*].*)?$" "$file")"
while read -r line; do
[[ $line ]] || continue
lnum="${line%%:*}"
line="${line#*:}"
prefix="${line%%template*}"
hdr_file=$(sed -En "s/^[^<]+<$B*([^>[:blank:]]+).*$/\1/p" <<< "$line")
raw_opt=($(sed -En "s/^[^<]+<$B*[^>[:blank:]]+(($B+-[DU][^>[:blank:]]+)*)$B*>.*$/\1/p" <<< "$line"))
declare -a opts=()
for raw in "${raw_opt[@]}"; do
if [[ "$raw" == -D* ]]; then
name="${raw:2}"
name="${name%%=*}"
opts+=("-D$name")
elif [[ "$raw" == -U* ]]; then
name="${raw:2}"
opts+=("-U$name")
fi
done
out=""
for opt in "${opts[@]}"; do
name="${opt:2}"
out+="${prefix}pragma push_macro(\"$name\")\n"
done
for raw in "${raw_opt[@]}"; do
name="${raw:2}"
name="${name%%=*}"
if [[ "$raw" == -D* ]]; then
value="${raw/#-D$name}"
value="${value/#=}"
out+="${prefix}define $name${value:+ $value}\n"
elif [[ "$raw" == -U* ]]; then
out+="${prefix}undef $name\n"
fi
done
out+="${prefix}include \"$hdr_file\"\n"
for opt in "${opts[@]}"; do
name="${opt:2}"
out+="${prefix}pragma pop_macro(\"$name\")\n"
done
out="${out%\\n}"
out="${out//\//\\/}"
sed_args+=("-e '${lnum}s/.*/${out}/'")
done <<< "$lines"
if (( (n = ${#sed_args[@]}) )); then
cmnd='sed'
for ((i = n - 1; i >= 0; i--)) ; do
cmnd+=" ${sed_args[i]}"
done
eval "$cmnd ${file@Q}"
else
cat "$file"
fi
override BIN := test
override SRC := test.c msg.c
override OBJ := $(SRC:%=%.o)
override DEP := $(SRC:%=%.d)
CFLAGS := -O2 -march=native -mtune=native -flto
$(BIN): $(OBJ)
$(CC) $(CFLAGS) -o $@ $^
msg.c.o: c_template.sh
%.c.o: %.c
$(if $(filter c_template.sh,$^),./c_template.sh $< | $(CC) -xc -,$(CC) $<) $(CFLAGS) -o $@ -I. -c -MMD -MQ $@ -MF $<.d
-include $(DEP)
.PHONY: clean
clean:
rm -f $(BIN) $(OBJ) $(DEP)
#include <stddef.h>
#include <stdint.h>
#include "msg.h"
#define VAR(line, data) char SYM_(line)[sizeof(data)]
#define SYM(line) SYM_(line)
#define SYM_(line) str##line
static const union {
struct {
#template<msg_defs.h -D_S(n,s)=VAR(__LINE__,s);>
};
char data[0];
} str = { {
#template<msg_defs.h -D_S(n,s)=s,>
} };
typedef __typeof__(_Generic(
&(char[1u + (sizeof(str) - 1u > 0xfful)
+ (sizeof(str) - 1u > 0xfffful)
+ (sizeof(str) - 1u > 0xfffffffful)]){0}
, char(*)[1]: (uint8_t)0, char(*)[2]: (uint16_t)0
, char(*)[3]: (uint32_t)0, char(*)[4]: (uint64_t)0
)) off_type;
static const off_type off[] = {
#template<msg_defs.h -D_S(n,s)=[n]=offsetof(__typeof__(str),SYM(__LINE__)),>
};
char const *msg_string (enum msg msg) {
return &str.data[off[msg]];
}
#ifndef MSG_H_
#define MSG_H_
enum msg { MSG1, MSG2, MSG3 };
extern char const *msg_string (enum msg msg);
#endif /* MSG_H_ */
_S(MSG1, "first message string")
_S(MSG3, "third message string")
_S(MSG2, "second message string")
#include <stdio.h>
#include "msg.h"
int main (void) {
printf("[MSG1] = \"%s\"\n[MSG2] = \"%s\"\n[MSG3] = \"%s\"\n",
msg_string(MSG1), msg_string(MSG2), msg_string(MSG3));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment