mirror of
https://github.com/vhaudiquet/cindex.git
synced 2025-12-18 04:06:04 +00:00
268 lines
7.7 KiB
Bash
Executable File
268 lines
7.7 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
gcc_dumpmachine=$(gcc -dumpmachine)
|
|
gcc_version=$(gcc -dumpversion)
|
|
|
|
gcc_program_output=/tmp/a.out
|
|
|
|
# Check for --local-system option
|
|
if [ "$1" == "--local-system" ]; then
|
|
local_system=1
|
|
|
|
# Check for local system name
|
|
if [ -z "$2" ]; then
|
|
echo "Error: local system name not specified"
|
|
echo "Usage: ./index.sh [--local-system <name> <./lib,./include path>]"
|
|
return 1 2>/dev/null || exit 1
|
|
fi
|
|
local_system_name=$2
|
|
|
|
# Check for local system path
|
|
if [ -z "$3" ]; then
|
|
echo "Error: local system path not specified"
|
|
echo "Usage: ./index.sh [--local-system <name> <./lib,./include path>]"
|
|
return 1 2>/dev/null || exit 1
|
|
fi
|
|
local_system_path=$3
|
|
else
|
|
local_system=0
|
|
fi
|
|
|
|
# LIBC
|
|
libc_names=("glibc" "musl" "uClibc-ng" "dietlibc")
|
|
|
|
# Present/Absent markers (colors)
|
|
p="\e[32m"
|
|
pe="\e[0m"
|
|
n="\e[31m"
|
|
ne="\e[0m"
|
|
|
|
# Warning markers (colors)
|
|
w="\e[33m"
|
|
we="\e[0m"
|
|
|
|
# C Standards
|
|
cstd=("c89" "c99" "c11" "c2x")
|
|
|
|
# SuS standards
|
|
sus=("susv2" "susv3" "susv4")
|
|
|
|
# Headers
|
|
sus_headers=("aio" "arpa/inet" "assert" "complex" "cpio" "ctype" "dirent" "dlfcn" "errno" "fcntl" "fenv" "float" "fmtmsg" "fnmatch" "ftw" "glob" "grp" "iconv" "inttypes" "iso646" "langinfo" "libgen" "limits" "locale" "math" "monetary" "mqueue" "ndbm" "net/if" "netdb" "netinet/in" "netinet/tcp" "nl_types" "poll" "pthread" "pwd" "regex" "sched" "search" "semaphore" "setjmp" "signal" "spawn" "stdarg" "stdbool" "stddef" "stdint" "stdio" "stdlib" "string" "strings" "stropts" "sys/ipc" "sys/mman" "sys/msg" "sys/resource" "sys/select" "sys/sem" "sys/shm" "sys/socket" "sys/stat" "sys/statvfs" "sys/time" "sys/times" "sys/types" "sys/uio" "sys/un" "sys/utsname" "sys/wait" "syslog" "tar" "termios" "tgmath" "time" "trace" "ulimit" "unistd" "utime" "utmpx" "wchar" "wctype" "wordexp")
|
|
c89=("assert" "ctype" "errno" "float" "limits" "locale" "math" "setjmp" "signal" "stdarg" "stddef" "stdio" "stdlib" "string" "time")
|
|
c99=(${c89[@]} "complex" "fenv" "inttypes" "iso646" "stdbool" "stdint" "tgmath" "wchar" "wctype")
|
|
c11=(${c99[@]} "stdalign" "stdatomic" "stdnoreturn" "threads")
|
|
c2x=(${c11[@]} "stdbit" "stdckdint")
|
|
|
|
# Headers list
|
|
combined=("${sus_headers[@]}" "${c2x[@]}")
|
|
headers=($(printf '%s\n' ${combined[@]} | sort -u))
|
|
|
|
# Import functions
|
|
source ./stdh.sh
|
|
|
|
check_std_c() {
|
|
for std in ${cstd[@]}; do
|
|
json+="\"${std}\":"
|
|
|
|
# Check if header is included in current standard
|
|
std_headers=($(eval 'echo ${'$std'[@]}'))
|
|
printf '%s\0' "${std_headers[@]}" | grep -Fxqz -- $header_name
|
|
if [ ! $? -eq 0 ]; then
|
|
json+="false,"
|
|
echo -e -n $n$std$ne" "
|
|
continue
|
|
fi
|
|
|
|
# Compile a program doing `if(function)`
|
|
echo -e "#include <${header_name}.h>\nint main()\n{\n\tif("$f") return 0; else return 1;\n}\n" | gcc -std=$std -xc - -o ${gcc_program_output} >/dev/null 2>&1
|
|
|
|
# Check gcc output
|
|
if [ $? -eq 0 ]; then
|
|
${gcc_program_output}
|
|
if [ $? -eq 0 ]; then
|
|
json+="true"
|
|
echo -e -n $p$std$pe" "
|
|
else
|
|
json+="false"
|
|
echo -e -n $n$std$ne" "
|
|
fi
|
|
else
|
|
# Check if function is in fact a macro
|
|
echo -e "#include <${header_name}.h>\nint main()\n{\n\t#ifdef ${f}\n\treturn 0;\n\t#else\n\treturn 1;\n\t#endif\n}\n" | gcc -std=$std -xc - -o ${gcc_program_output} >/dev/null 2>&1
|
|
if [ ! $? -eq 0 ]; then
|
|
# This should never fail unless header is broken
|
|
echo -e "\nFatal: ${f}() in ${header_name} resolution as macro made gcc fail"
|
|
echo " This should never happen, please report this bug"
|
|
return 1 2>/dev/null || exit 1
|
|
fi
|
|
${gcc_program_output}
|
|
if [ $? -eq 0 ]; then
|
|
json+="true"
|
|
echo -e -n $p$std$pe" "
|
|
else
|
|
json+="false"
|
|
echo -e -n $n$std$ne" "
|
|
fi
|
|
fi
|
|
json+=","
|
|
done
|
|
}
|
|
|
|
check_for_libc() {
|
|
lib_name=$1
|
|
lib_dir=$2
|
|
lib_path=$2/lib/libc.a
|
|
|
|
# Check for symbol in libc
|
|
json+="\""$lib_name"\":"
|
|
objdump -t $lib_path | grep -w $f"$" >/dev/null
|
|
if [ $? -eq 0 ]; then
|
|
json+="true"
|
|
echo -e -n $p$lib_name$pe" "
|
|
else
|
|
# Function not found in libc : check in other libraries in the same directory
|
|
found=false
|
|
other_libs=($(find ${lib_dir}/lib -maxdepth 1 -name "*.a" '!' -name "libc.a"))
|
|
|
|
# If header is math.h/complex.h, begin searching in math library
|
|
if [ $header_name = "math" ] || [ $header_name = "complex" ] || [ $header_name = "fenv" ]; then
|
|
other_libs+=($other_libs)
|
|
other_libs[0]="${lib_dir}/lib/libm.a"
|
|
fi
|
|
|
|
# If header is threads.h/pthread.h, begin searching in libpthread
|
|
if [ $header_name = "threads" ] || [ $header_name = "pthread" ]; then
|
|
other_libs+=($other_libs)
|
|
other_libs[0]="${lib_dir}/lib/libpthread.a"
|
|
fi
|
|
|
|
# If header is aio.h, begin searching in librt
|
|
if [ $header_name = "aio" ]; then
|
|
other_libs+=($other_libs)
|
|
other_libs[0]="${lib_dir}/lib/librt.a"
|
|
fi
|
|
|
|
for lib in ${other_libs[@]}; do
|
|
objdump -t $lib 2>/dev/null | grep -w $f"$" >/dev/null 2>&1
|
|
if [ $? -eq 0 ]; then
|
|
# Obtain library name, and remove extension
|
|
olib_name=$(basename $lib)
|
|
olib_name=${olib_name%.*}
|
|
olib_name=${olib_name%-*}
|
|
|
|
found=true
|
|
json+="true"
|
|
echo -e -n $p$lib_name"(${olib_name})"$pe" "
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ $found = false ]; then
|
|
# Function not found in any library ; check in headers
|
|
# Check if header is present
|
|
if [ -f "${lib_dir}/include/${header_name}.h" ]; then
|
|
if [ $local_system -eq 0 ]; then
|
|
link_entry=""
|
|
# Check for crt1.o, crti.o and crtn.o
|
|
if [ -f "${lib_dir}/lib/crt1.o" ]; then
|
|
link_entry+="-l:crt1.o "
|
|
fi
|
|
if [ -f "${lib_dir}/lib/crti.o" ]; then
|
|
link_entry+="-l:crti.o "
|
|
fi
|
|
if [ -f "${lib_dir}/lib/crtn.o" ]; then
|
|
link_entry+="-l:crtn.o "
|
|
fi
|
|
|
|
# Check for start.o
|
|
if [ -f "${lib_dir}/lib/start.o" ]; then
|
|
link_entry+="-l:start.o "
|
|
fi
|
|
|
|
echo -e "#include <${header_name}.h>\nint main()\n{\n\t#ifdef ${f}\n\t\treturn 0;\n\t#else\n\t\treturn 1;\n\t#endif\n}" | gcc -o ${gcc_program_output} -ffreestanding -nostdlib -xc -I${lib_dir}/include/ -I/usr/lib/gcc/${gcc_dumpmachine}/${gcc_version}/include - -L${lib_dir}/lib/ ${link_entry} -lc -lgcc -lgcc_eh -static >/dev/null 2>&1
|
|
else
|
|
echo -e "#include <${header_name}.h>\nint main()\n{\n\t#ifdef ${f}\n\t\treturn 0;\n\t#else\n\t\treturn 1;\n\t#endif\n}" | gcc -o ${gcc_program_output} -xc - >/dev/null 2>&1
|
|
fi
|
|
|
|
if [ $? -eq 0 ]; then
|
|
${gcc_program_output}
|
|
if [ $? -eq 0 ]; then
|
|
json+="true"
|
|
echo -e -n $p$lib_name"(macro)"$pe" "
|
|
else
|
|
json+="false"
|
|
echo -e -n $n$lib_name$ne" "
|
|
fi
|
|
else
|
|
json+="false"
|
|
echo -e -n $n$lib_name$ne$w"(?)"$we" "
|
|
fi
|
|
else
|
|
json+="false"
|
|
echo -e -n $n$lib_name$ne" "
|
|
fi
|
|
fi
|
|
fi
|
|
json+=","
|
|
}
|
|
|
|
check_for_sus() {
|
|
# Check for function file in ./susvx/functions/$f
|
|
for s in ${sus[@]}; do
|
|
json+="\""$s"\":"
|
|
if [ -f "./$s/functions/$f.html" ] || [ -f "./$s/xsh/$f.html" ] || [ -f "./$s/xns/$f.html" ]; then
|
|
json+="true"
|
|
echo -e -n $p$s$pe" "
|
|
else
|
|
json+="false"
|
|
echo -e -n $n$s$ne" "
|
|
fi
|
|
json+=","
|
|
done
|
|
}
|
|
|
|
for i in ${!headers[@]}; do
|
|
header_name=${headers[$i]}
|
|
echo "header file "$header_name".h:"
|
|
json="["
|
|
header_name_clean=$(echo $header_name | sed 's/\//_/g')
|
|
header_fns=($(eval 'echo ${'$header_name_clean'[@]}'))
|
|
for f in ${header_fns[@]}; do
|
|
json+="{\"name\":\""$f"\",\"type\":\"function\","
|
|
|
|
echo -n "checking for "$f"()... "
|
|
|
|
# Check for symbol in libc
|
|
if [ $local_system -eq 0 ]; then
|
|
for i in ${!libc_names[@]}; do
|
|
lib_name=${libc_names[$i]}
|
|
lib_dir="./libs/${lib_name}"
|
|
|
|
check_for_libc $lib_name $lib_dir
|
|
done
|
|
else
|
|
check_for_libc $local_system_name $local_system_path
|
|
fi
|
|
|
|
# Check for standards
|
|
if [ $local_system -eq 0 ]; then
|
|
check_std_c
|
|
check_for_sus
|
|
fi
|
|
|
|
json+="\"header\":\"${header_name}\"},"
|
|
echo ""
|
|
done
|
|
|
|
# Output JSON
|
|
json+="{}"
|
|
json+=" ]"
|
|
o="output/${header_name}.json"
|
|
mkdir -p "${o%/*}"
|
|
echo -e $json >output/$header_name.json
|
|
done
|
|
|
|
# Cleanup
|
|
rm -f ${gcc_program_output}
|