#!/bin/sh

# Generate a table that describes the socket options in the tree.  We assume
# that the socket options are of the form
#	#define OPT 123 /* type,type; rest */
# in the listed files.

if [ $# -ne 1 ]; then
	echo "usage: $(basename $0) freebsd-sys-dir"
	exit 1
fi
sysdir=$1

gen_table() {

    unifdef -k -D__BSD_VISIBLE__=1 -U_KERNEL < ${sysdir}/$1 | \
	sed -n '/#define[[:space:]]*.*\/\*.*;.*\*\//p' | \
	awk -vlevel=$2 '
BEGIN { printf("static struct sockopt_entry %s[] = {\n", tolower(level)); }
{
	s=$5;
	if (match(s, ";$") == 0) {
		s=$6;
	}
	gsub(";", "", s);
	if (match(s, "^buf") == 0) {
		s = toupper(s);
		printf ("\t{ %-12s, %-20s, {", level, $2);
		split(s, a, ",");
		for (t in a) {
			printf (" SOCKOPT_TYPE_%s,", a[t]);
		}
		printf(" } },\n");
	}
}
END { printf("\t{ SOCK_LEVEL_NONE }\n};\n\n"); }
'
}

gen_types() {

    unifdef -k -D__BSD_VISIBLE__=1 -U_KERNEL | \
	sed -n '/#define[[:space:]]*.*\/\*.*;.*\*\//p' | \
	awk '
{
	s=$5;
	if (match(s, ";$") == 0) {
		s=$6;
	}
	gsub(";", "", s);
	if (match(s, "^buf") == 0) {
		s = toupper(s);
		split(s, a, ",");
		for (t in a) {
			printf ("\tSOCKOPT_TYPE_%s, \n", a[t]);
		}
	}
}'
}

cat <<EOF
/* Auto-generated by $(basename $0) -- do not edit */
#pragma once

#define SOCK_LEVEL_NONE -1234

#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>

enum sockopt_type {
	SOCKOPT_TYPE_NONE = 0,
EOF
cat ${sysdir}/sys/socket.h ${sysdir}/netinet/in.h ${sysdir}/netinet6/in6.h \
    ${sysdir}/netinet/tcp.h ${sysdir}/netinet/udp.h ${sysdir}/sys/un.h | \
    gen_types | sort -u
cat <<EOF
};

struct sockopt_entry {
	int level;
	int optname;
	enum sockopt_type type[5];
};
EOF

gen_table sys/socket.h SOL_SOCKET
gen_table netinet/in.h IPPROTO_IP
gen_table netinet6/in6.h IPPROTO_IPV6
gen_table netinet/tcp.h IPPROTO_TCP
gen_table netinet/udp.h IPPROTO_UDP
gen_table sys/un.h SOL_LOCAL

cat <<EOF
static struct sockopt_cache {
	int level;
	struct sockopt_entry *entry;
} so_cache[] = {
	{ SOL_SOCKET,   sol_socket },
	{ IPPROTO_IP,   ipproto_ip },
	{ IPPROTO_IPV6, ipproto_ipv6 },
	{ IPPROTO_TCP,  ipproto_tcp },
	{ IPPROTO_UDP,  ipproto_udp },
	{ SOL_LOCAL,    sol_local },
};
EOF
