#!/bin/sh

# Prepare linux headers for use with glibc
#
# By Jürg Billeter  <j@bitron.ch>
#
# Based on work of
#	Jim Gifford (Headers Sanitation Script)
#	Ryan Oliver
#	Joe Ciccone
#	Matt Darcy
#	Greg Schafer
#	Tushar Teredesai
#	D.J. Lucas
#	Jeremy Huntwork
#	Andrew Benton
#	Florian Schanda
#	Stewart Ravenhall (Strip C comments Script)
#	Paolo Bonzini

[ -x "$UNIFDEF" ] || UNIFDEF="unifdef"
[ -d "$KERNEL_PATH" ] || KERNEL_PATH=$PWD
[ -n "$LLC_PATH" ] || LLC_PATH=$PWD
DIST_PATH=$PWD

LINUXVERSION=$(basename $KERNEL_PATH | sed -e 's/^.*\([0-9]\+\.[0-9]\+\.[0-9]\+\).*$/\1/')

a=$'\001'
b=$'\002'

if [ "$KERNEL_PATH" != "$LLC_PATH" ]
then
	mkdir -p $LLC_PATH/include/asm
	cp -a $KERNEL_PATH/include/asm-$(uname -m | sed -e 's/i[456]86/i386/')/* $LLC_PATH/include/asm
	cp -a $KERNEL_PATH/include/{asm-generic,linux} $LLC_PATH/include
else
	mv $LLC_PATH/include/asm-$(uname -m | sed -e 's/i[456]86/i386/') $LLC_PATH/include/asm
fi

cd $LLC_PATH/include

DIRECTORIES="asm-generic asm linux"

# remove obsolete headers
REMOVE_HEADERS="linux/config.h linux/devfs_fs.h"

# remove broken headers
REMOVE_HEADERS="$REMOVE_HEADERS $(echo linux/{netfilter/xt_connbytes.h,reiserfs_fs.h})"

# remove kernel-internal asm headers
REMOVE_HEADERS="$REMOVE_HEADERS $(echo asm-generic/{atomic.h,bitops.h,cputime.h,div64.h,dma-mapping.h,dma-mapping-broken.h,emergency-restart.h,ide_iops.h,local.h,mutex-dec.h,mutex-xchg.h,pci.h,pci-dma-compat.h,pgtable.h,pgtable-nopmd.h,pgtable-nopud.h,siginfo.h,termios.h,tlb.h,topology.h,xor.h} asm/{agp.h,apic.h,arch_hooks.h,atomic.h,bitops.h,bugs.h,cache.h,cacheflush.h,calling.h,checksum.h,compat.h,cpu.h,cputime.h,current.h,desc.h,div64.h,dma.h,dma-mapping.h,dwarf2.h,e820.h,edac.h,fixmap.h,floppy.h,fpu32.h,gart-mapping.h,genapic.h,hardirq.h,hpet.h,hw_irq.h,i387.h,i8253.h,i8259.h,io.h,io_apic.h,ipcbuf.h,ipi.h,irq.h,kexec.h,kprobes.h,local.h,mach-bigsmp/,mach-default/,mach-es7000/,mach-generic/,mach-numaq/,mach-summit/,mach-visws/,mach-voyager/,mach_apic.h,mmu.h,mmu_context.h,module.h,mpspec.h,msgbuf.h,msi.h,mutex.h,nmi.h,node.h,numa.h,parport.h,pci.h,pci-direct.h,pgalloc.h,pgtable.h,pgtable-2level-defs.h,pgtable-2level.h,pgtable-3level-defs.h,pgtable-3level.h,processor.h,proto.h,scatterlist.h,segment.h,sembuf.h,shmbuf.h,sigcontext32.h,siginfo.h,signal.h,smp.h,spinlock.h,spinlock_types.h,srat.h,suspend.h,swiotlb.h,system.h,timer.h,timex.h,tlb.h,tlbflush.h,topology.h,uaccess.h,ucontext.h,user32.h,vic.h,voyager.h,xor.h})"

# remove kernel-internal headers
REMOVE_HEADERS="$REMOVE_HEADERS $(echo linux/{8250_pci.h,ac97_codec.h,acpi.h,adfs_fs_i.h,adfs_fs_sb.h,aio.h,amba/,amifd.h,amifdreg.h,arcdevice.h,ata.h,attribute_container.h,b1pcmcia.h,backing-dev.h,backlight.h,bio.h,bitmap.h,bitops.h,bit_spinlock.h,blkdev.h,blockgroup_lock.h,bootmem.h,buffer_head.h,cache.h,calc64.h,circ_buf.h,clk.h,coda_cache.h,coda_linux.h,coda_psdev.h,com20020.h,compat.h,compat_ioctl.h,compiler*.h,completion.h,console.h,consolemap.h,console_struct.h,cpufreq.h,cpu.h,cpumask.h,cpuset.h,cramfs_fs_sb.h,crash_dump.h,crc16.h,crc32c.h,crc32.h,crypto.h,cryptohash.h,ctype.h,cyclades.h,cyclomx.h,cycx_cfm.h,cycx_drv.h,cycx_x25.h,dcache.h,dcookies.h,debugfs.h,delay.h,devfs_fs_kernel.h,device.h,device-mapper.h,devpts_fs.h,dio.h,dm9000.h,dma-mapping.h,dmapool.h,dmi.h,dnotify.h,ds1286.h,ds17287rtc.h,ds1742rtc.h,edd.h,efi.h,efs_dir.h,efs_fs.h,efs_fs_i.h,efs_fs_sb.h,efs_vh.h,eisa.h,elevator.h,elfcore.h,elf-fdpic.h,err.h,etherdevice.h,ext2_fs_sb.h,ext3_fs_i.h,ext3_fs_sb.h,ext3_jbd.h,fcdevice.h,fddidevice.h,file.h,firmware.h,font.h,fs_enet_pd.h,fsl_devices.h,fsnotify.h,fs_struct.h,gameport.h,genalloc.h,generic_serial.h,gfp.h,hardirq.h,harrier_defs.h,hash.h,hdpu_features.h,highmem.h,highuid.h,hil.h,hil_mlc.h,hippidevice.h,hpet.h,hp_sdc.h,hrtimer.h,hugetlb.h,hwmon.h,hwmon-sysfs.h,hwmon-vid.h,i2c-algo-bit.h,i2c-algo-pca.h,i2c-algo-pcf.h,i2c-algo-sgi.h,i2c-algo-sibyte.h,i2c.h,i2c-isa.h,i2c-pxa.h,i2o.h,ibmtr.h,ide.h,idr.h,if_wanpipe_common.h,inetdevice.h,inet.h,init.h,initrd.h,init_task.h,interrupt.h,ioc3.h,ioc4.h,ioctl32.h,io.h,ioport.h,ipc.h,ipmi_smi.h,ipx.h,irq_cpustat.h,irq.h,isapnp.h,isdn/capilli.h,isdn_divertif.h,isicom.h,istallion.h,jffs2_fs_i.h,jffs2_fs_sb.h,jhash.h,jiffies.h,journal-head.h,kallsyms.h,kbd_diacr.h,kbd_kern.h,kernel_stat.h,kexec.h,key.h,key-ui.h,kfifo.h,klist.h,kmalloc_sizes.h,kmod.h,kobj_map.h,kprobes.h,kthread.h,ktime.h,lapb.h,lcd.h,libata.h,libps2.h,linux_logo.h,list.h,lockd/,mbcache.h,mc6821.h,mca.h,mca-legacy.h,memory.h,memory_hotplug.h,mempool.h,miscdevice.h,mm.h,mm_inline.h,mman.h,mmc/,mod_devicetable.h,module.h,moduleloader.h,moduleparam.h,mpage.h,msg.h,mtd/,mutex.h,mutex-debug.h,namei.h,netfilter_ipv4/{ip_conntrack_amanda.h,ip_conntrack_core.h,ip_conntrack_helper.h,ip_conntrack_icmp.h,ip_conntrack_protocol.h,ip_nat_core.h,ip_nat_helper.h,ip_nat_protocol.h,listhelp.h},netpoll.h,nfs_fs_sb.h,nfs_page.h,nfs_xdr.h,nfs4_acl.h,nfsd/,nfsd_idmap.h,nls.h,nmi.h,node.h,nodemask.h,nubus.h,oprofile.h,pagemap.h,pagevec.h,page-flags.h,parport_pc.h,pcieport_if.h,pci-acpi.h,percpu.h,percpu_counter.h,phy.h,pid.h,pipe_fs_i.h,platform_device.h,pm_legacy.h,posix_acl.h,posix_acl_xattr.h,posix-timers.h,ppp_channel.h,prefetch.h,prio_tree.h,proc_fs.h,quotaops.h,radix-tree.h,raid/{bitmap.h,linear.h,md.h,md_k.h,multipath.h,raid0.h,raid1.h,raid5.h,raid10.h,xor.h},raid_class.h,ramfs.h,reiserfs_acl.h,reiserfs_fs_i.h,reiserfs_fs_sb.h,relayfs_fs.h,rmap.h,root_dev.h,rose.h,rslib.h,rwsem.h,rwsem-spinlock.h,scatterlist.h,sched.h,scx200_gpio.h,sdla_asy.h,sdla_chdlc.h,sdla_fr.h,sdla_ppp.h,sdla_x25.h,sdladrv.h,seccomp.h,security.h,selection.h,sem.h,seqlock.h,serial_8250.h,serial_ip3106.h,serial167.h,serialP.h,shm.h,shmem_fs.h,skbuff.h,smp.h,smp_lock.h,socket.h,spi/,spinlock.h,spinlock_api_smp.h,spinlock_api_up.h,spinlock_types.h,spinlock_types_up.h,spinlock_up.h,stallion.h,sunrpc/,superhyway.h,suspend.h,swap.h,swapops.h,syscalls.h,sysdev.h,sysfs.h,sysrq.h,timer.h,topology.h,transport_class.h,trdevice.h,tty_driver.h,tty_flip.h,tty_ldisc.h,udf_fs.h,udf_fs_i.h,udf_fs_sb.h,ufs_fs_i.h,umem.h,usb_input.h,usb_isp116x.h,usb_otg.h,usb_sl811.h,vmalloc.h,vt_buffer.h,vt_kern.h,wanpipe.h,workqueue.h,writeback.h,x1205.h,xattr.h,zconf.h,zlib.h,zorro.h,zutil.h})"

# remove kernel headers which have a replacement in glibc
# Compatibility headers will be created if $COMPAT is set
REMOVE_HEADERS="$REMOVE_HEADERS $(echo linux/{acct.h,ax25.h,dirent.h,elf.h,if.h,in.h,ip.h,netrom.h,quota.h,resource.h,route.h,signal.h,stat.h,tcp.h,time.h,timex.h,udp.h,un.h,utime.h,wait.h})"

for header in $(find $DIRECTORIES -name "*.h")
do
	# remove non-userspace sections
	cp $header{,.orig}
	$UNIFDEF -U__KERNEL__ $header.orig > $header
	rm $header.orig
	
	# check whether file is practically empty
	# strip C comments and strip empty ifndef _LINUX_FILE_H shell
	sed '
		# If no start comment then go to end of script
		/\/\*/!b
		:a
		s:/\*:'"$a"':g
		s:\*/:'"$b"':g

		# If no end comment
		/'"$b"'/!{
			:b

			# If not last line then read in next one
			$!{
				N
				ba
			}

			# If last line then remove from start
			# comment to end of line
			# then go to end of script
			s:'"$a[^$b]"'*$::
			bc
		}

		# Remove comments
		'"s:$a[^$b]*$b"'::g
		/'"$a"'/ bb

		:c
		s:'"$a"':/*:g
		s:'"$b"':*/:g
	' $header | tr "\n" " " | sed -e 's/#ifndef[[:space:]]\+[[:alnum:]_]\+[[:space:]]\+#define[[:space:]]\+[[:alnum:]_]\+[[:space:]]1\?[[:space:]]*#endif//' | tr -d "[:space:]" | grep -q . || REMOVE_HEADERS="$REMOVE_HEADERS $header"
done

# delete the headers marked for removal
rm -rvf $REMOVE_HEADERS

# remove sparse annotations (necessary due to linux/compiler.h removal)
echo 's/\b\(__user\|__iomem\|__force\|__attribute_const__\)\b//g' > /tmp/linux-glibc-headers.sed
	
# replace kernel-only types
# (should be reported as bugs upstream if the affected headers are really needed in userspace)
echo 's/\b[us]\(8\|16\|32\|64\)\b/__&/g' >> /tmp/linux-glibc-headers.sed

# replace endian-dependent types
echo 's/\b__\(be\|le\)\(16\|32\|64\)\b/__u\2/g' >> /tmp/linux-glibc-headers.sed

# remove references to deleted headers
echo $REMOVE_HEADERS | tr " " "\n" | sed -e 's%/%\\/%g' -e 's%^%/include.*%' -e 's%$%/d%' >> /tmp/linux-glibc-headers.sed

find $DIRECTORIES -name "*.h" | xargs sed -i -f /tmp/linux-glibc-headers.sed

rm -f /tmp/linux-glibc-headers.sed


## If $COMPAT set
## Replace removed kernel headers that have a glibc equivelent.
## No terribly creative scripting here...just do it.

if [ -n "$COMPAT" ]
then
	## /usr/include/sys/*
	for FILE in linux/{acct.h,quota.h,resource.h,socket.h,stat.h,time.h,timex.h,un.h,wait.h}
	do
		GFILE=`echo "${FILE}" | sed 's@linux@sys@'`
		echo '#if defined(__GNUC__) && !defined(__STRICT_ANSI__)' > ${FILE}
		echo "#warning \"You should include <${GFILE}>.  This time I will do it for you. \"" >> ${FILE}
		echo "#endif" >> ${FILE}
		echo "#include <${GFILE}>" >> ${FILE}
	done

	## /usr/include/net/*
	for FILE in linux/{if.h,route.h}
	do
		GFILE=`echo "${FILE}" | sed 's@linux@net@'`
		echo '#if defined(__GNUC__) && !defined(__STRICT_ANSI__)' > ${FILE}
		echo "#warning \"You should include <${GFILE}>.  This time I will do it for you. \"" >> ${FILE}
		echo "#endif" >> ${FILE}
		echo "#include <${GFILE}>" >> ${FILE}
	done

	## /usr/include/netinet/*
	for FILE in linux/{in.h,ip.h,tcp.h,udp.h}
	do
		GFILE=`echo "${FILE}" | sed 's@linux@netinet@'`
		echo '#if defined(__GNUC__) && !defined(__STRICT_ANSI__)' > ${FILE}
		echo "#warning \"You should include <${GFILE}>.  This time I will do it for you. \"" >> ${FILE}
		echo "#endif" >> ${FILE}
		echo "#include <${GFILE}>" >> ${FILE}
	done

	## /usr/include/*
	for FILE in linux/{dirent.h,elf.h,signal.h,utime.h}
	do
		GFILE=`echo "${FILE}" | sed 's@linux/@@'`
		echo '#if defined(__GNUC__) && !defined(__STRICT_ANSI__)' > ${FILE}
		echo "#warning \"You should include <${GFILE}>.  This time I will do it for you. \"" >> ${FILE}
		echo "#endif" >> ${FILE}
		echo "#include <${GFILE}>" >> ${FILE}
	done

	## /usr/include/linux/ax25.h
	echo '#if defined(__GNUC__) && !defined(__STRICT_ANSI__)' > linux/ax25.h
	echo "#warning \"You should include <netax25/ax25.h>. This time I will do it for you. \"" >> linux/ax25.h
	echo "#endif" >> linux/ax25.h
	echo "#include <netax25/ax25.h>" >> linux/ax25.h

	## /usr/include/linux/netrom.h
	echo '#if defined(__GNUC__) && !defined(__STRICT_ANSI__)' > linux/netrom.h
	echo "#warning \"You should include <netrom/netrom.h>. This time I will do it for you. \"" >> linux/netrom.h
	echo "#endif" >> linux/netrom.h
	echo "#include <netrom/netrom.h>" >> linux/netrom.h

	## /usr/include/asm/io.h
	echo '#if defined(__GNUC__) && !defined(__STRICT_ANSI__)' > asm/io.h
	echo "#warning \"You should include <sys/io.h>. This time I will do it for you. \"" >> asm/io.h
	echo "#endif" >> asm/io.h
	echo "#include <sys/io.h>" >> asm/io.h

	## /usr/include/linux/compiler.h
	echo '#warning "Do not include <linux/compiler.h> in userspace!"' >> linux/compiler.h

	## /usr/include/linux/config.h
	echo '#warning "Do not include <linux/config.h> in userspace!"' >> linux/config.h
fi


## Create version.h
# Pulled from Jim's current script
P1=$(echo $LINUXVERSION | cut -d. -f1)
P2=$(echo $LINUXVERSION | cut -d. -f2)
P3=$(echo $LINUXVERSION | cut -d. -f3)
let LINUXCODE="($P1<<16)+($P2<<8)+$P3"
echo "#ifndef _LINUX_VERSION_H" > linux/version.h
echo "#define _LINUX_VERSION_H" >> linux/version.h
echo "" >> linux/version.h
echo "#define UTS_RELEASE \"$P1.$P2.$P3\"" >> linux/version.h
echo "#define LINUX_VERSION_CODE $LINUXCODE"  >> linux/version.h
echo "#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))"  >> linux/version.h
echo "" >> linux/version.h
echo "#endif"  >> linux/version.h


if [ "$KERNEL_PATH" != "$LLC_PATH" ]
then
	cd $LLC_PATH/..
	tar -jcf $DIST_PATH/$(basename "$LLC_PATH").tar.bz2 $(basename $LLC_PATH)
fi
