#! /bin/sh
# unistd-na, e4a hp'01; build NASM compliant syscalls/fcntl ref include-files
# unistd-as, by <ln -s unistd-na unistd-as>
#			build AS compliant syscalls/fcntl ref include-files
# ############################################################################# #
#
# unistd-{na,as} [ path_to_linux_kernel_source ]
#
# generated lists (customize filenames, below):
#
# 1) file ${n}, syscall names & numbers %assign-ments
#	%assign max_syscalls ${c}	; top of syscall no-s
#	%assign __NR_<..name..>		; syscall numeric defns by name
#
# 2) file ${f}, %assign-ments
#	%assign ..<item>.. value	; fcntl constants
#
# 3) ${d}, data assembly file
#	%assign max_syscalls ${c}
#		dd max_syscalls		; 4-aligned
#		dd (syscalref.e-syscalref)
#		dd 0			; for num & stg storage consistency
#	syscalref:			; label
#					; repetitive data blocks follow:
#		dw <syscall-no.>	; 16bit syscall number
#		db len,"..name..",0	; asciz name w/ leading countbyte
#					; count may be omitted -re below-
#	syscalref.e:
#		dd 0			; list terminator, zero num & stg
#
# 4) ${a} w/ the repetitive blocks, only
#		dw <syscall-no.>	; 16bit syscall number
#		db len,"..name..",0	; asciz name w/ leading countbyte
#
# datafile generated w/o non-numeric, alias-ed refs to syscalls numbers;
# to including, out-comment the line below "# exclude syscalls by alias"
#
# the list structure set up to supporting different searching methods,
# customizing to the particular requirements could save a few bytes...
# search w/ countbyte inclusive is fastest, requires no additional checks.
#
# environment vari, used if set, ${1} w/ predence over $LXSRC
#	LXSRC, LSUST, LXVER, LXPGS, FCNTL, IOCTL, TMIOS, TMBIT, TRMDS, TRMSZ
#
# ############################################################################# #

# eliminate any possibly predefined functions
unset a b c d f i j l lx m n p s td tm tn v x y

# system utils used:
#	basename, cat, cut, dirname, grep, rm, sort

# main path to host system source
[ -n "${1}" ]&&lx=${1}||{ [ -n "${LXSRC}" ]&&lx=${LXSRC}||lx="/usr/src/linux"; }

# ############################################################################# #
# customize:

# <cb="any non-empty value"> for counted name strings, else generate just asciz
cb="with countbyte"

t=$(dirname ${0});		# this dir
t=$(dirname ${t});		# $t: l4 main dir

[ -z "$(pwd|grep "lib4th")" ]||cb=;# $cb: no count-byte for lib4th

# destn filenames, includes
d=./scdata.inc;			# data asm of syscall numbers & name strings
n=./scdefs.inc;			# %assign-ed syscall no. to names vari defn's
f=./scfctl.inc;			# fcntl selectors, modifiers
a=./scdasm.inc;			# short ${d}, num & stg only
r=${t}/src/l4lxsrc.inc;		# filenames of linux data sources

# text praefix for syscalls no. definitions in sourcefile
m=__NR_

# syscalls definition source file(s)
[ "$(uname)" = "Linux" ]&&{
# Linux source:
	[ -n "${LXUST}" ]||LXUST=/include/asm/unistd.h
# kernel version file, e.g. linux: <version.h> expected in dir <../linux>
# $v for output files will be set to "unknown" if version not found
	[ -n "${LXVER}" ]||LXVER=/include/linux/version.h
	[ -n "${LXPGS}" ]||LXPGS=/include/asm/page.h;
};#||{ ..other..  }||{ ..OS-s may follow.. }
# syscall files:
#	Linux:		include/asm/unistd.h
#	NetBSD,OpenBSD: ..somepath../sys/syscall.h
#	AtheOS,BeOS:	-?-

# path's to files w/
k=${lx}${LXVER};		# kernel version
p=${lx}${LXPGS};		# source of PAGE_SIZE &c
l=${lx}${LXUST};		# host's syscalls defns
#echo L:$l

# temps
tm=./m;				# collecting numbers, for syscalls top no.
td=./d;				# inclusion asm data
tn=./n;				# vari defn-s
tv=./v;				# aux. bash vari for aliased syscalls
rm -f ${td} ${tm} ${tn} ${tv}

# ----------------------------------------------------------------------------- #
# OS specific (e.g. i386-pc-Linux 2.2.19), to generating
#	syscalls and fcntl, ioctl control data from the actual Linux source
# ----------------------------------------------------------------------------- #
# Linux:

# this script can't (yet?) translate a "C" structure, thus:
# re include/asm/term{io,bit}s.h
#	disps into struct termios expected w/ asmutils
#	if missing, un-comment TRMDS and TRMSZ definitions, below, and verify!

# ############################################################################# #

# store host data source files to lib4th for 4th access
[ -n "${FCNTL}" ]||FCNTL="/include/asm/fcntl.h"
# ioctl codes
[ -n "${IOCTL}" ]||IOCTL="/include/asm/ioctls.h"
# terminal control
[ -n "${TMIOS}" ]||TMIOS="/include/asm/termios.h"
[ -n "${TMBIT}" ]||TMBIT="/include/asm/termbits.h"

[ "$(basename ${0})" = "unistd-as" ]&&{
    al='.align';	# "align" pseudo op
    st='.equ';		# assign value to variable
    pf='#'		# ?define, 1st char
    dl=',';		# assignment items delimiter
    dd='.long';		# asm	32bit data
    dw='.word';		#	16bit
    db='.byte';		#	8bit
    sg='.ascii';	#	character stg
    oa='';		# octal numbers affix
    cs='// ';		# comment
# system call macro, in data-file
    ma='.macro sys_ r0=eax,r1=ebx,r2=ecx,r3=edx,r4=esi,r5=edi,r6=ebp'
# end
    me='.endm'
# body
    mb=".ifc \\\r0,eax\n.else;.ifc \\\r0,%eax\n.else\n\tmov \$${m}\\\r0,eax\n.endif;.endif\n\tint \$0x80"
#example w/ args:
#    sc=".ifc \\r0,eax\n.elifc \\r0,%eax\n.else\nmovl \\r0,eax\n.endif\nint 0x80"
}||{
    al='align'
    st='%assign'
    st='%assign'
    pf='%'
    dl='	'
    dd='dd'
    dw='dw'
    db='db'
    sg='db'
    oa='q'
    cs='; '
    mb="%ifnidni %{1},eax\n\tmov eax,${m}%{1}\n%endif\n\tint 0x80"
    ma='%macro sys_ 1.nolist eax'
    me='%endm'
}
# syscall by:
#	AtheOS,Linux:	int 0x80
#	NetBSD,OpenBSD:	int 0x80; jnc .ok; neg eax; .ok:
#	BeOS:		int 0x25 -uncertain-

# termios structure
[ -n "${TRMDS}" ]||TRMDS="\
${st} termios_c_iflag${dl}0\n\
${st} termios_c_oflag${dl}4\n\
${st} termios_c_cflag${dl}8\n\
${st} termios_c_lflag${dl}12\n\
${st} termios_c_line${dl}16\n\
${st} termios_c_cc${dl}17"
# #	size of <termios> structure
TRMSZ="${pf}ifndef termios_size\n${st} termios_size${dl}(termios_c_cc+NCCS+3)/4\n${pf}endif"

# -- files -- #

lxf () { local n b l;[ -z "${2}" ]&&{ n=0;b="\t";l=; }||{ n="\"${2}${3}\"";b="<$(basename ${2})>";l="\'${1}t\'"; }; [ -n "${1}" ]&&echo -e ";- ${b}\t\t\t\t\t\t\t${l}\n.${1}t:">>${r};echo -e "\n\tdb ${n}">>${r}; }
lxl () { echo -e${1} ";-\n;-=====================================\n;-"	>>${r}; }

# collecting i/o files & devices control defns to file ./src/l4xsrc.inc
echo "; lib4th (C) 2001 hp"		> ${r}
lxl
echo ";- \"$(uname)\" source files"	>>${r}
lxl
echo -e "\n;-\n;- lxpath\t( -- p u )\t\t\t\t\t\t\tlinux\n;-\tpath to host constants sources files">>${r}
echo -e "lxpath:GA\n\tspush\n\tmov eax,.s-Y\n\tjmp zcount\n\ta\n.s:"	>>${r}
echo "$(dirname ${l})
$(dirname ${k})
$(dirname ${p})
$(dirname ${lx}${FCNTL})
$(dirname ${lx}${IOCTL})
$(dirname ${lx}${TMIOS})
$(dirname ${lx}${TMBIT})"|sort -bdfr|uniq|while read y;do lxf $(basename ${y}) ${y} ":";done
lxf lsrp ${lx};		# path to src
lxf e;	 		# list terminator
echo -e "\n;-\n;- lxfiles\t( -- p u )\t\t\t\t\t\t\tlinux\n;-\tcompiled host constants source files list">>${r}
echo -e "lxfiles:GA\n\tspush\n\tmov eax,.s-Y\n\tjmp zcount\n\ta\n.s:"	>>${r}
echo "${l}
${k}
${p}
${lx}${FCNTL}
${lx}${IOCTL}
${lx}${TMIOS}
${lx}${TMBIT}"|sort -bdf|uniq|while read y;do x=$(basename ${y});lxf ${x} ${y};lxf e${x};done
lxf e;			#\list 
lxf f;	 		#/ terminator
lxl n
echo " l4lxsrc.inc <eof>"						>>${r}

# page_shift from kernel source (dft = 12, i.e. PAGE_SIZE := 4K)
[ -r ${p} ]&&v="$(grep '^#define' ${p}|grep 'PAGE_SHIFT')"
j=0
[ -n "${v}" ]&&{
    for i in ${v}
    do
	j=$((${j}+1))
	[ "${j}" != "3" ]||{ v=$(echo ${i}|sed -e "s/\"//g;s/\./0/g");break; }
    done
}
[ -n "${v}" ]||v='12';#		default setting
p=${v}
v='0.0.00'
# kernel version, else <0.0.00>
[ -r ${k} ]&&{ read v v v<${k};v=0$(echo ${v}|sed -e "s/\"//g;s/\./0/g"); }

grep "${m}" ${l}|grep "^#define"|cut -d\  -f2-|cut -d/ -f1|sed -e "s/${m}//"|while read i j
do [ "$((${j}))" -eq 0 ]&&j=$((${i}))||declare __NR_${i}=$((${j}));echo "${i}=$((${j}))";done>>${tv}
source ${tv}

tifs=${IFS};IFS="=${IFS}"
while read i j
do
	[ "$((${j}))" -eq 0 ]&&j=$((${i}))
	echo "${st} ${m}${i}${dl}${j}">>${tn}
# exclude syscalls by alias, else out-comment the "||continue" part
	[ "${j}" = "$((${j}))" ]&&echo ${j}>>${tm};#||continue
	echo "	${dw} ${j}">>${td}
	[ -z "${cb}" ]||echo "	${db} ${#i}">>${td}
	echo -e "	${sg} \"${i}\"\n	${db} 0">>${td}
done<${tv}
IFS=${tifs}

# top syscall code
for i in $(sort -nr ${tm});do c=${i};break;done

# common to all supported hosts' syscalls
[ -z "${A4SI}" -o -z "${OSF}" ]||{
echo "; ${A4SI}">${t}/inc/a4c.inc;o=0;\
cat ${t}/inc/asmutils/au/${A4SI}|grep "^%assign *SYS_"|while read a b c d;\
do
    [ -z "$c" ]||
	{ [ $((${o})) -gt $((${c})) ]&&echo -e "\n %assign top_sycommon $o">>${t}/inc/a4c.inc&&break; }||
	{
	    for i in ${OSF};do [ "${i}" = "${A4SI}" ]||{ grep "${b}" ${t}/inc/asmutils/au/${i}>/dev/null||b=; };done
	    [ -z "${b}" ]||{ o=$c;i=${b:4};echo -e "\tdb ${#i},\"$i\",$c">>${t}/inc/a4c.inc; }
	}
done
}

# assemble destn. files, $n:numeric vari, $d:data assembly
echo "${cs} ${n} : kernel ${v}, syscall numbers assigned to their names">${n}
echo -e "\n${ma}\n${mb}\n${me}">>${n}
echo -e "\n${pf}define kernel_vers \"${v}\"">>${n}
echo -e "${pf}define page_shift \"${p}\"">>${n}
echo -e "${st} max_syscalls${dl}${c}\n">>${n}
echo "${cs} ${a} : kernel ${v}, syscall numbers and names assembly">${a}
echo "${cs} ${d} : kernel ${v}, syscall numbers and names assembly">${d}
echo -e "\n${pf}define page_shift \"${p}\"\n">>${a}
echo -e "\n${pf}define page_shift \"${p}\"">>${d}
echo -e "\n${st} max_syscalls${dl}${c}\n\n\t${al} 4\n\t${dd} ${c},syscalref.e-syscalref,0\nsyscalref:">>${d}
cat ${tn}>>${n}
cat ${td}>>${d}
cat ${td}>>${a}
echo -e "\n${cs} ${n} <eof>">>${n}
echo -e "syscalref.e:\n\t${dd} 0\n\n${cs} ${d} <eof>">>${d}
echo -e "\n${cs} ${a} <eof>">>${a}

# fcntl-s
unset a b c d
echo -e "${cs} ${f} : kernel ${v}, fcntl cons\n\n">${f}
[ -z "${TRMDS}" ]||echo -e ${TRMDS}>>${f}
cat ${lx}${FCNTL} ${lx}${IOCTL} ${lx}${TMIOS} ${lx}${TMBIT}|grep 'define'|grep -v '('|while read a b c d
do [ -z "${c}" ]||{ [ "${c:0:1}" == "0" -a "${c:1:1}" != "x" ]&&c=${c}${oa};echo "${st} ${b}${dl}${c}">>${f}; };done
[ -z "${TRMSZ}" ]||echo -e ${TRMSZ}>>${f}
echo -e "\n${cs} ${f} <eof>">>${f}

# clr temps
rm -f ${td} ${tm} ${tn} ${tv}

# ############################################################################# #
# unistd-na <eof>
