summaryrefslogtreecommitdiff
path: root/gen
diff options
context:
space:
mode:
Diffstat (limited to 'gen')
-rw-r--r--gen/ftm.m422
-rw-r--r--gen/mk.sh271
-rwxr-xr-xgen/mkh.sh173
3 files changed, 466 insertions, 0 deletions
diff --git a/gen/ftm.m4 b/gen/ftm.m4
new file mode 100644
index 00000000..9b55c423
--- /dev/null
+++ b/gen/ftm.m4
@@ -0,0 +1,22 @@
+define(`STDC',
+ `ifelse($#, 2,
+ `ifelse($1, 1, `!defined __STDC_VERSION__ || __STDC_VERSION__ < $2', `defined __STDC_VERSION__ && $1 <= __STDC_VERSION__ && __STDC_VERSION__ < $2')',
+ `ifelse($1, 1, `', `defined __STDC_VERSION__ && $1 <= __STDC_VERSION__')')
+')dnl
+
+define(`POSIX',
+ `ifelse($#, 2,
+ `ifelse($1, 1, `defined _POSIX_SOURCE && (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < $2)', `defined _POSIX_C_SOURCE && $1 <= _POSIX_C_SOURCE && _POSIX_C_SOURCE < $2')',
+ `ifelse($1, 1, `defined _POSIX_SOURCE', `defined _POSIX_C_SOURCE && $1 <= _POSIX_C_SOURCE')')
+')dnl
+
+define(`XEXT', `defined _XOPEN_SOURCE && ((defined _XOPEN_SOURCE_EXTENDED && _XOPEN_SOURCE_EXTENDED == 1) || 500 <= _XOPEN_SOURCE)')
+define(`XOPEN',
+ `ifelse($#, 2,
+ `ifelse($1, 4, `defined _XOPEN_SOURCE && _XOPEN_SOURCE < $2',
+ `ifelse($1, 400, `XEXT() && _XOPEN_SOURCE < $2',
+ `defined _XOPEN_SOURCE && $1 <= _XOPEN_SOURCE && _XOPEN_SOURCE < $2')')',
+ `ifelse($1, 4, `defined _XOPEN_SOURCE',
+ `ifelse($1, 400, `XEXT()',
+ `defined _XOPEN_SOURCE && $1 <= _XOPEN_SOURCE')')')
+')dnl
diff --git a/gen/mk.sh b/gen/mk.sh
new file mode 100644
index 00000000..bbf8c8c1
--- /dev/null
+++ b/gen/mk.sh
@@ -0,0 +1,271 @@
+#!/bin/sh
+
+TOPDIR=$(dirname $0)
+DEPS=${TOPDIR}/.deps
+SRCDIR=${TOPDIR}/src
+
+classify_source () {
+ NAME=$(basename $1 .c)
+
+ if grep -q "^REFERENCE(" $1; then
+ echo REFERENCE
+ elif grep -q "^#define ${NAME}[ (]" $1; then
+ echo MACRO
+ elif grep -q "#undef ${NAME}" $1; then
+ echo MACRO
+ elif grep -q '^typedef .*(\*' $1; then
+ echo FNTYPE
+ elif grep -q "^typedef " $1; then
+ echo TYPE
+ elif grep -q "^struct (^ )*;$" $1; then
+ echo TYPE
+ elif grep -q "^typedef .*{$" $1; then
+ echo TYPE_LONG
+ elif grep -q "^struct.*{" $1; then
+ echo RECORD
+ elif grep -q "^union.*{" $1; then
+ echo RECORD
+ elif grep -q "^[A-Za-z_].*[ \*]${NAME}[[;]" $1; then
+ echo EXTERN
+ elif grep -q 'TGFN' $1; then
+ echo TGFN
+ else
+ echo FUNCTION
+ fi
+}
+
+version_guard () {
+ parsed=/tmp/$(basename $1).v
+ grep -F -e 'STDC(' -e 'POSIX(' -e 'XOPEN(' $1 | sort | m4 $(dirname $0)/ftm.m4 - | grep . > $parsed
+ lines=$(wc -l $parsed | cut -f1 -d' ')
+
+ if [ $lines -ne 0 ]; then
+ printf '#if'
+ loop=1
+ while [ $loop -lt $lines ]; do
+ printf '\t(%s) || \\\n' "$(sed -ne "${loop}p;q" $parsed)"
+ loop=$((loop + 1))
+ done
+
+ printf '\t(%s)\n' "$(sed -ne "${loop}p" $parsed)"
+ fi
+
+ rm -f $parsed
+}
+
+get_declaration () {
+ case ${2:-$(classify_source $1)} in
+
+ REFERENCE)
+ ref="$(grep -F 'REFERENCE(' $1 | m4 -DREFERENCE='$1')"
+ if (echo "$ref" | grep -q '<.*>'); then
+ echo "#include $ref"
+ else
+ get_declaration "src/${ref}"
+ fi
+ ;;
+
+ MACRO)
+ if ! (grep -q '#undef' $1 && grep -q 'MAY-BE-UNDEF' $1); then
+ grep -E '^(#(if|def|undef|el|end)| )' $1
+ fi
+ ;;
+
+ TYPE|TYPE_LONG|RECORD|FNTYPE)
+ base=$(basename $1 .c)
+ printf '#ifndef __TYPE_%s_DEFINED__\n#define __TYPE_%s_DEFINED__\n' "$base" "$base"
+
+ if grep -q '^#if' $1; then
+ sed -ne '/^#if/,/#endif/p' $1
+ elif grep -qE '^(typedef|struct|union) .*\{' $1; then
+ sed -ne '/{$/,/^}/p' $1
+ elif grep -qE '^(typedef|struct|union) .*[^;]$' $1; then
+ grep -E '^(typedef|struct|union| )' $1
+ else
+ grep -E '^(typedef|struct|union) ' $1
+ fi
+
+ printf '#endif\n\n'
+ ;;
+
+ EXTERN)
+ echo "extern $(grep '^[a-zA-Z_].*;$' $1)"
+ ;;
+
+ FUNCTION)
+ echo "$(grep '^[a-zA-Z_].*)' $1 | head -n1);"
+ ;;
+
+ TGFN)
+ echo "$(grep 'TGFN.*)$' $1 | m4 -DTGFN='$1' -DTYPE='double');"
+ echo "$(grep 'TGFN.*)$' $1 | m4 -DTGFN='$1f' -DTYPE='float');"
+ echo "$(grep 'TGFN.*)$' $1 | m4 -DTGFN='$1l' -DTYPE='long double');"
+ ;;
+
+ *)
+ # unknown type, so try guessing
+ get_declaration $1
+ ;;
+
+ esac
+}
+
+stdc_base() {
+ (grep 'STDC(' $1 | m4 -DSTDC='$1') || echo 0
+}
+
+posix_base() {
+ (grep 'POSIX(' $1 | m4 -DPOSIX='$1') || echo 0
+}
+
+xopen_base() {
+ (grep 'XOPEN(' $1 | m4 -DXOPEN='$1') || echo 0
+}
+
+find_all() {
+ rm -rf "${DEPS}"
+ mkdir -p "${DEPS}"
+ find "${SRCDIR}" -name \*.c > "${DEPS}/all.c"
+ find "${SRCDIR}" -name \*.ref > "${DEPS}/all.ref"
+ find "${SRCDIR}" -name \*.s > "${DEPS}/all.s"
+ grep '#include <.*>' $(cat "${DEPS}/all.c" "${DEPS}/all.ref") |
+ sed 's/^.*<\(.*\.h\)>.*/\1/' | sort -u > "${DEPS}/all.h"
+}
+
+version_sources() {
+ for file in $(cat "${DEPS}/all.c" "${DEPS}/all.ref"); do
+ printf '%s\n' "$file"
+ c_version=$(stdc_base "${file}")
+ p_version=$(posix_base "${file}")
+ x_version=$(xopen_base "${file}")
+
+ if [ -n "${c_version}" ]; then
+ mkdir -p "${DEPS}/c.${c_version}"
+ echo "$file" >> "${DEPS}/c.${c_version}/sources"
+ fi
+
+ if [ -n "${p_version}" ]; then
+ mkdir -p "${DEPS}/p.${p_version}"
+ echo "$file" >> "${DEPS}/p.${p_version}/sources"
+ fi
+
+ if [ -n "${x_version}" ]; then
+ mkdir -p "${DEPS}/x.${x_version}"
+ echo "$file" >> "${DEPS}/x.${x_version}/sources"
+ fi
+ done
+}
+
+make_headers_mk() {
+ if ! [ -f "${DEPS}/all.h" ]; then
+ find_all
+ fi
+
+ rm -f "${TOPDIR}/.headers.mk"
+ printf '.POSIX:\n.DEFAULT: headers\n\n' > "${TOPDIR}/.headers.mk"
+ printf 'include .config.mk\n\n' >> "${TOPDIR}/.headers.mk"
+
+ for header in $(cat "${DEPS}/all.h"); do
+ printf 'Building dependencies for <%s>\n' "$header"
+ printf '$(INCDIR)/%s: mkh.sh ' "$header" >> "${TOPDIR}/.headers.mk"
+ mkdir -p $(dirname "${TOPDIR}/.deps/h/${header}.deps")
+ grep -l "#include <${header}>" $(cat "${DEPS}/all.c" "${DEPS}/all.ref") > "${TOPDIR}/.deps/h/${header}.deps"
+ sed -e "s#${SRCDIR}#\$(SRCDIR)#" < "${TOPDIR}/.deps/h/${header}.deps" | tr '\n' ' ' >> "${TOPDIR}/.headers.mk"
+ printf '\n\tINCDIR=$(INCDIR) sh mkh.sh $(INCDIR)/%s\n\n' "${header}" >> "${TOPDIR}/.headers.mk"
+ done
+
+ printf 'headers: ' >> "${TOPDIR}/.headers.mk"
+ for header in $(cat "${DEPS}/all.h"); do
+ printf ' \\\n\t$(INCDIR)/%s' "$header" >> "${TOPDIR}/.headers.mk"
+ done
+
+ printf '\n' >> "${TOPDIR}/.headers.mk"
+}
+
+make_deps_mk() {
+ if ! [ -f "${DEPS}/all.c" ]; then
+ find_all
+ fi
+
+ rm -f "${TOPDIR}/.deps.mk"
+ rm -f "${DEPS}"/lib*
+
+ printf '.POSIX:\n.SILENT:\ndefault: all\n\n' > "${TOPDIR}/.deps.mk"
+ printf 'include .config.mk\n\n' >> "${TOPDIR}/.deps.mk"
+ printf 'BASE_CFLAGS=-I$(INCDIR) -Isrc -fno-builtin -nostdinc\n' >> "${TOPDIR}/.deps.mk"
+ printf '\n' >> "${TOPDIR}/.deps.mk"
+
+ printf '.POSIX:\nlibc_C_0_OBJS=' > "${DEPS}/libc.C_0"
+ # Assume all assembly is useful regardless of standard version
+ for file in $(sed -e 's/\.[^.]*\.s$/.ARCH.s/g' .deps/all.s | sort -u); do
+ BASE=$(basename $file .ARCH.s)
+ SRC=$(echo $file | sed -e 's/\.ARCH\./.$(ARCHITECTURE)-$(WORDSIZE)./')
+ printf 'libc.a($(OBJDIR)/%s.$(ARCHITECTURE)-$(WORDSIZE).o): $(OBJDIR)/%s.$(ARCHITECTURE)-$(WORDSIZE).o\n' $BASE $BASE >> "${TOPDIR}/.deps.mk"
+ printf ' \\\n\tlibc.a($(OBJDIR)/%s.$(ARCHITECTURE)-$(WORDSIZE).o)' $BASE >> "${DEPS}/libc.C_0"
+ printf '$(OBJDIR)/%s.$(ARCHITECTURE)-$(WORDSIZE).o: %s\n' $BASE $SRC >> "${TOPDIR}/.deps.mk"
+ printf '\t$(CC) $(BASE_CFLAGS) $(CFLAGS) -c %s -o $@\n' $SRC >> "${TOPDIR}/.deps.mk"
+ printf '\t echo [AS] $@\n\n' >> "${TOPDIR}/.deps.mk"
+ done
+
+ for file in $(cat "${DEPS}/all.c"); do
+ printf 'Building dependencies from %s\n' "$file"
+ type=$(classify_source "${file}")
+
+ if [ ${type} = EXTERN -o ${type} = TGFN -o ${type} = FUNCTION ]; then
+ LINK=$(grep -F 'LINK(' $file | m4 -DLINK='$1')
+ LIB=lib${LINK:-c}
+ OBJ=$(basename $file .c).o
+
+ printf '%s.a(%s): $(OBJDIR)/%s\n' $LIB $OBJ $OBJ >> "${TOPDIR}/.deps.mk"
+ printf '$(OBJDIR)/%s: %s' "$OBJ" "$file" >> "${TOPDIR}/.deps.mk"
+ #for header in $(grep '#include' "${file}"); do
+ #printf ' \\\n\t$(INCDIR)/%s' "$header" >> "${TOPDIR}/.deps.mk"
+ #done
+ printf '\n\t$(CC) $(BASE_CFLAGS) $(CFLAGS) -c %s -o $@\n' "$file" >> "${TOPDIR}/.deps.mk"
+ printf '\techo [CC] $@\n' >> "${TOPDIR}/.deps.mk"
+
+ cver=$(stdc_base $file)
+ pver=$(posix_base $file)
+ xver=$(xopen_base $file)
+
+ if [ -n "$cver" ]; then
+ if ! [ -f "${DEPS}/${LIB}.C_${cver}" ]; then
+ printf '.POSIX:\n%s_C_%s_OBJS=' "${LIB}" "${cver}" > "${DEPS}/${LIB}.C_${cver}"
+ fi
+ printf ' \\\n\t%s.a($(OBJDIR)/%s)' $LIB $OBJ >> "${DEPS}/${LIB}.C_${cver}"
+ fi
+
+ if [ -n "$pver" ]; then
+ if ! [ -f "${DEPS}/${LIB}.POSIX_${pver}" ]; then
+ printf '.POSIX:\n%s_POSIX_%s_OBJS=' "${LIB}" "${pver}" > "${DEPS}/${LIB}.POSIX_${pver}"
+ fi
+ printf ' \\\n\t%s.a($(OBJDIR)/%s)' $LIB $OBJ >> "${DEPS}/${LIB}.POSIX_${pver}"
+ fi
+
+ if [ -n "$xver" ]; then
+ if ! [ -f "${DEPS}/${LIB}.XOPEN_${xver}" ]; then
+ printf '.POSIX:\n%s_XOPEN_%s_OBJS=' "${LIB}" "${xver}" > "${DEPS}/${LIB}.XOPEN_${xver}"
+ fi
+ printf ' \\\n\t%s.a($(OBJDIR)/%s)' $LIB $OBJ >> "${DEPS}/${LIB}.XOPEN_${xver}"
+ fi
+
+ if [ -z "$cver" ] && [ -z "$pver" ] && [ -z "$xver" ]; then
+ if ! [ -f "${DEPS}/${LIB}.C_0" ]; then
+ printf '.POSIX:\n%s_C_0_OBJS=' "${LIB}" > "${DEPS}/${LIB}.C_0"
+ fi
+ printf ' \\\n\t%s.a($(OBJDIR)/%s)' $LIB $OBJ >> "${DEPS}/${LIB}.C_0"
+ fi
+ fi
+ done
+
+ printf '\n' >> "${TOPDIR}/.deps.mk"
+
+ for libdep in ${DEPS}/lib*; do
+ LIB=$(basename $libdep | sed -e 's/\..*$//')
+ VER=$(basename $libdep | sed -e 's/^.*\.//')
+ echo adding dependencies for $LIB v $VER
+ printf 'include $(TOPDIR)/.deps/%s\n' $(basename $libdep) >> "${TOPDIR}/.deps.mk"
+ done
+
+ printf '\n' >> "${TOPDIR}/.deps.mk"
+}
diff --git a/gen/mkh.sh b/gen/mkh.sh
new file mode 100755
index 00000000..c4c4d6d4
--- /dev/null
+++ b/gen/mkh.sh
@@ -0,0 +1,173 @@
+#!/bin/sh
+
+TOPDIR=$(dirname $0)
+if [ -z "${INCDIR}" ]; then
+ INCDIR="${TOPDIR}/include"
+fi
+. "${TOPDIR}/mk.sh"
+
+export LC_ALL=POSIX
+export LANG=POSIX
+HEADER=$1
+HEADERNAME=$(echo $HEADER | sed -e "s#^${INCDIR}/*##")
+GUARD=__$(echo $HEADERNAME | tr a-z/. A-Z__)__
+mkdir -p $(dirname $HEADER)
+exec > $HEADER
+
+if [ $(basename $HEADER) != assert.h ]; then
+ printf '#ifndef %s\n#define %s\n\n' ${GUARD} ${GUARD}
+fi
+
+printf "/*\nUNG's Not GNU\n\n%s\n*/\n\n" "$(cat LICENSE)"
+
+rm -rf $HEADER.*
+for i in $(cat "${TOPDIR}/.deps/h/${HEADERNAME}.deps" | sort -u); do
+ # TODO: refs
+ type=$(classify_source $i)
+ source=$i
+ if [ $type = "REFERENCE" ] && ! grep -Fq 'REFERENCE(<' $source; then
+ source=src/$(grep REFERENCE $i | m4 -DREFERENCE='$1')
+ type=$(classify_source $source)
+ fi
+ version=v$(grep -F -e 'STDC(' -e 'POSIX(' -e 'XOPEN(' $i | sed -e 's/STDC/C/' | sort | tr , - | tr -d '() \n')
+ mkdir -p $HEADER.$type
+ echo $source >> $HEADER.$type/$version
+
+ if ! [ -f $(dirname $0)/.deps/ftm/$version ]; then
+ mkdir -p $(dirname $0)/.deps/ftm
+ version_guard $source > $(dirname $0)/.deps/ftm/$version
+ fi
+
+ printf '%s <%s> (%s)\n' "$i" "$HEADER" "$version" >&2
+done
+
+###
+### TODO: prevent _XOPEN_SOURCE expanding to empty string
+###
+if grep -Fq -e '_XOPEN_SOURCE <' -e '< _XOPEN_SOURCE' $(cat $(HEADER.*/*); then
+cat <<-EOF
+ #if defined _XOPEN_SOURCE && _XOPEN_SOURCE - 1 < 0
+ # undef _XOPEN_SOURCE
+ # define _XOPEN_SOURCE 400
+ #endif
+EOF
+fi
+
+if grep -Fq 'POSIX(' $(cat $HEADER.*/*); then
+cat <<-EOF
+ #if defined _XOPEN_SOURCE && !defined _POSIX_C_SOURCE
+ # if (_XOPEN_SOURCE >= 700)
+ # define _POSIX_C_SOURCE 200809L
+ # elif (_XOPEN_SOURCE >= 600)
+ # define _POSIX_C_SOURCE 200112L
+ # elif (_XOPEN_SOURCE >= 500)
+ # define _POSIX_C_SOURCE 199506L
+ # else
+ # define _POSIX_C_SOURCE 2
+ # endif
+ #endif
+
+ #if defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE
+ # define _POSIX_SOURCE
+ #endif
+
+EOF
+fi
+
+if grep -Fq -e 'POSIX(' -e 'XOPEN(' $(cat $HEADER.*/*); then
+cat <<-EOF
+ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 19901L
+ # if (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L)
+ # error POSIX.1-2001 and later require a C99 compiler
+ # elif(defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 600)
+ # error XOPEN Issue 6 and later require a C99 compiler
+ # endif
+ #endif
+EOF
+fi
+
+for type in REFERENCE MACRO TYPE TYPE_LONG RECORD FNTYPE EXTERN; do
+ if [ -d $HEADER.$type ]; then
+ for v in $HEADER.$type/*; do
+ version=$(cat $(dirname $0)/.deps/ftm/$(basename $v | sed -e 's/^.*\.//'))
+ if [ -n "$version" ]; then
+ printf '%s\n' "$version"
+ fi
+
+ for i in $(sort -u $v); do
+ printf '/* %s */\n' $i
+ get_declaration $i
+ done
+
+ if [ -n "$version" ]; then
+ printf '#endif\n'
+ fi
+
+ printf '\n'
+ done
+ rm -rf $HEADER.$type
+ fi
+done
+
+if [ -d $HEADER.TGFN ]; then
+ for v in $HEADER.TGFN/*; do
+ version=$(cat $(dirname $0)/.deps/ftm/$(basename $v | sed -e 's/^.*\.//'))
+ if [ -n "$version" ]; then
+ printf '%s\n' "$version"
+ fi
+
+ for i in $(sort -u $v); do
+ printf '/* %s */\n' $i
+ get_declaration $i TGFN
+ done
+
+ if [ -n "$version" ]; then
+ printf '#endif\n'
+ fi
+
+ printf '\n'
+ done
+ rm -rf $HEADER.TGFN
+fi
+
+if [ -d $HEADER.FUNCTION ]; then
+ if grep -q restrict $(cat $HEADER.FUNCTION/*); then
+ if grep -Fq -e 'STDC(1)' -e 'STDC(1,' -e 'STDC(199409' $(grep -l restrict $(cat $HEADER.FUNCTION/*)) || ! grep -Fq 'STDC(' $(grep -l restrict $(cat $HEADER.FUNCTION/*)); then
+ printf '#if (!defined __STDC_VERSION__) || (__STDC_VERSION__ < 199901L)\n'
+ printf '#define restrict\n'
+ printf '#endif\n\n'
+ fi
+ fi
+
+ ### TODO: only if header works with C<11
+ if grep -q _Noreturn $(cat $HEADER.FUNCTION/*); then
+ printf '#if (!defined __STDC_VERSION__) || (__STDC_VERSION__ < 200112L)\n'
+ printf '#define _Noreturn\n'
+ printf '#endif\n\n'
+ fi
+
+ for v in $HEADER.FUNCTION/*; do
+ version=$(cat $(dirname $0)/.deps/ftm/$(basename $v | sed -e 's/^.*\.//'))
+ if [ -n "$version" ]; then
+ printf '%s\n' "$version"
+ fi
+
+ for i in $(sort -u $v); do
+ printf '/* %s */\n' $i
+ get_declaration $i FUNCTION | sed -e 's/\([a-zA-Z_][a-zA-Z_0-9]*\)\([,)]\)/__\1\2/g;s/(__\([a-zA-Z_][a-zA-Z_0-9]*\))/(\1)/g'
+ done
+
+ if [ -n "$version" ]; then
+ printf '#endif\n'
+ fi
+
+ printf '\n'
+ done
+ rm -rf $HEADER.FUNCTION
+fi
+
+rm -rf $HEADER.REFERENCE
+
+if [ $(basename $HEADER) != assert.h ]; then
+ printf '\n#endif\n'
+fi