#!/usr/bin/tclsh

if {[llength $argv] == 0} {
	puts {usage: sourclist [--arch <OBJ-ARCH-ABI>] <binfile>}
	exit
}

# last argument is assumed to be the binary file name
set bin_name [lindex $argv end]

# check for architecture
set arch ""
regexp -- {--arch ([^ ]+)} $argv dummy arch

set src_dump [exec objdump -ld $bin_name | sed -n "s/^\\(.*\\w\\):.*\$/\\1/p" | sort | uniq]
set src_list [split $src_dump "\n"]


### ADD FILES TO COLLECTION OF RELEVANT SOURCE FILES ###
proc add_file {file} {
	global ascii_basenames ascii_dirnames

	if {[file exists $file]} {

		set dir_name  [exec dirname  $file]
		set base_name [exec basename $file]

		#
		# resolve all ../ within the pathname
		#
		set effective_dir [exec sh -c "cd $dir_name; pwd"]
		set effective_file "$effective_dir/$base_name"

		#
		# only account ASCII files
		#
		set file_type [exec file -b -L $effective_file]
		if {[regexp {ASCII} $file_type dummy]} {

			#
			# use file names as array indices
			# this way, multiple equal file names
			# result only in one array element
			#
			set ascii_basenames($effective_file) $base_name
			set ascii_dirnames($effective_file)  $effective_dir
		}
	}
}


#
# add all files that are referenced from debug info
#
foreach src_file $src_list {
	add_file $src_file
}


#
# create a sorted list of file names from array indices
#
set ascii_file_list [array names ascii_basenames]
set ascii_file_list [lsort $ascii_file_list]


### ADD ALL FILES THAT ARE REFERRED BY DEPENDENCY FILE ###
#
# src_file   source file to check
# arch       architecture e.g. OBJ-x86_586-l4v2
#
proc add_dependencies {src_file arch} {
	global ascii_basenames ascii_dirnames

	if {[string match "*.c" $src_file]} {

		#
		# dependency filename: <OBJ-DIR>/.<FNAME>.o.d
		#
		regsub {^(.*).c$} $ascii_basenames($src_file) {.\1.o.d} dep_basename

	} else {
		return
	}

	set dir_name $ascii_dirnames($src_file)

	#
	# create OBJ-x86_586 out of OBJ-x86_586-l4v2
	#
	regsub -- {-\w+$} $arch "" gen_arch

	#
	# try different locations for the dep file
	#
	set dep_file ""
	set try_file "$dir_name/$dep_basename"
	if {[file exists $try_file]} {set dep_file $try_file}

	set try_file "$dir_name/$gen_arch/$dep_basename"
	if {[file exists $try_file]} {set dep_file $try_file}

	set try_file "$dir_name/$arch/$dep_basename"
	if {[file exists $try_file]} {set dep_file $try_file}

	if {$dep_file == ""} {
		puts stderr "Warning: no dependency file for $src_file"
		return
	}

	#
	# read dependency info from dep file
	#
	set dep_info [exec cat $dep_file]
	regsub -all {\\\n\t*} $dep_info "" dep_info
	set dep_info [split $dep_info "\n"]
	set dep_list [lrange [lindex $dep_info" 0] 2 end]

	foreach dep $dep_list {

		#
		# file name is absolute path
		#
		if {[string match "/*" $dep]} {
			add_file $dep

		# file name is relative to dep dir
		} else {
			set dep_dir [exec dirname $dep_file]
			add_file "$dep_dir/$dep"
		}
	}
}


foreach file $ascii_file_list {
	add_dependencies $file $arch
}


#
# output all collected files
#
set ascii_file_list [array names ascii_basenames]
set ascii_file_list [lsort $ascii_file_list]

foreach file $ascii_file_list {
	puts "$file"
}
