XCOMM!/bin/sh -f
XCOMM $XConsortium: exportlistgen.sun /main/3 1996/10/11 13:54:11 swick $
XCOMM
XCOMM ########################################################################
XCOMM Construct shared-library scoping mapfile for Solaris based on standardized
XCOMM export list description file
XCOMM
XCOMM Usage: exportlistgen libfoo.so libfoo.elist > mapfile.scope
XCOMM
XCOMM	libfoo.so    => shared library of interest
XCOMM	libfoo.elist => Meta description of necessary export list.
XCOMM
XCOMM    The output file, "mapfile.scope" may then be passed to the Solaris 
XCOMM    linker to reconstruct the shared library, libfoo.so.
XCOMM
XCOMM ########################################################################

XCOMM Utility programs
FILTER=CXXFILT			# C++ symbol demangler
AWK=awk				# Awk

XCOMM For nm, cat, pr, expand, awk, c++filt
PATH=/usr/bin:/bin:/usr/ccs/bin:/usr/ucb:/opt/SUNWspro/bin

XCOMM Try to detect broken versions of c++filt.
if [ `echo _okay | ${FILTER:-cat}` != "_okay" ]; then
    if [ -x /opt/SUNWspro/bin/c++filt ]; then
	echo "# Your $FILTER is broken -- using /opt/SUNWspro/bin/c++filt."
	FILTER=/opt/SUNWspro/bin/c++filt
    else
	echo "# ERROR: no working $FILTER available."
	exit 1
    fi;
fi;

XCOMM Temporary files
EXPORTLIST=/tmp/elistgen1.$$	# export directives from "libfoo.list"
NMLIST=/tmp/elistgen2.$$	# name list from libfoo.sl
FILTLIST=/tmp/elistgen3.$$	# demangled (C++) version of above

XCOMM Print useful information at the top of the output
echo "#" `date`
echo "# This scoping mapfile was produced by" $0
echo "# Export list description taken from:" $2
echo "# Target library:" $1
echo "# Target Operating System:" `uname -msrv`
echo "# "

XCOMM Extract the globally visible symbols from target library
XCOMM The NMLIST generated here is later used to cross-check the symbols in the
nm -p $1 | $AWK '/ [ TDBS] /{print $3}' > $NMLIST

XCOMM Extract the globally visible symbols from target library
XCOMM The NMLIST generated here is later used to cross-check the symbols in the
${FILTER:-cat} $NMLIST > $FILTLIST

XCOMM Clean up the export-list description file.  Sort the directives.
$AWK '
    BEGIN {
	csyms     = 0;	# C   public symbols in libfoo.list
	cplusplus = 0;	# C++ public symbols in libfoo.list
	isyms     = 0;	# C   internal symbols in libfoo.list
	iplusplus = 0;	# C++ internal symbols in libfoo.list
	implicit  = "";	# Handling of implicit symbols
    }
    $1 == "default" {
	# A default clause suppresses warnings about implicit symbols.
	if ($2 != "" && $2 != "force" && $2 != "public" && $2 != "private" && $2 != "internal") {
	    print "# Warning: illegal default clause:", $2 | "cat 1>&2";
	    next;
	}
	if (implicit != "")
	    print "# Warning: multiple default clauses." | "cat 1>&2";
	implicit = $2;
	next;
    }
    $1 == "force" {
	csyms ++;
	print $1 ";;" $2;
	next;
    }
    $1 == "public" {
	csyms ++;
	print $1 ";;" $2;
	next;
    }
    $1 == "publicC++" {
	cplusplus ++;
	string = $2;
	for (n = 3; n <= NF; n++)
	    string = string " " $n;
	print $1 ";;" string;
	next;
    }
    $1 == "private" {
	csyms ++;
	print $1 ";;" $2;
	next;
    }
    $1 == "privateC++" {
	cplusplus ++;
	string = $2;
	for (n = 3; n <= NF; n++)
	    string = string " " $n;
	print $1 ";;" string;
	next;
    }
    $1 == "internal" {
	isyms ++;
	print $1 ";;" $2;
	next;
    }
    $1 == "internalC++" {
	iplusplus ++;
	string = $2;
	for (n = 3; n <= NF; n++)
	    string = string " " $n;
	print $1 ";;" string;
	next;
    }
    $1 == "#line" || $1 == "#" {
	# cpp will have removed comments, but may have added other stuff.
	next;
    }
    NF > 0 {
	print "# Warning: unrecognized directive:", $0 | "cat 1>&2";
	next;
    }
    END {
	printf("# Exporting %d C and %d C++ symbols, hiding %d and %d.\n", csyms, cplusplus, isyms, iplusplus) | "cat 1>&2";
	if (implicit != "") {
	    print "# Unspecified symbols are " implicit "." | "cat 1>&2";
	    print "default;;" implicit;
	}
    }
' $2 1>$EXPORTLIST


XCOMM Read in the above files and write result to stdout.  The contents
XCOMM of NMLIST and FILTLIST are used to construct a symbol lookup table.
XCOMM The contents of EXPORTLIST are converted with the help of this table.
XCOMM Use ";" as a delimiter in the symbol lookup table.
(pr -m -s";" -t -w1024 $NMLIST $FILTLIST | expand -1; cat $EXPORTLIST) | $AWK '
    BEGIN {
	FS = ";";
	implicit = 0;
    }
    NF == 2 {
	# This is "pr" output, i.e., symbol translation table
	syms[$2] = $1;
	next;
    }
    NF == 3 && $1 == "default" {
	# Treatment of unspecified symbols.
	if ($3 == "internal" || $3 == "internalC++")
	    implicit = 1;
	else if ($3 == "private" || $3 == "privateC++")
	    implicit = 2;
	else if ($3 == "public" || $3 == "publicC++")
	    implicit = 3;
	else # $3 == "force"
	    implicit = 4;
	next;
    }
    NF == 3 {
	# An export directive.  Parse our instructions for this symbol.
	if ($1 == "internal" || $1 == "internalC++")
	    export = 1;
	else if ($3 == "private" || $3 == "privateC++")
	    export = 2;
	else if ($3 == "public" || $3 == "publicC++")
	    export = 3;
	else # $3 == "force"
	    export = 4;

	if (length(syms[$3]) > 0) {
	    if (donelist[$3])
		print "# Warning: Duplicate entry for", $3, "in export list" | "cat 1>&2";
	    if (donelist[$3] < export)
		donelist[$3] = export;
	} else { 
	    if (export == 4)
		donelist[$3] = export;
	    else
		print "# Warning:", $3, "was not in the nm list for this library" | "cat 1>&2";
	}
	next;
    }
    END { 
	# Ignore magic linker symbols.
	if (implicit == 0) {
	    if (!donelist["_DYNAMIC"])
		donelist["_DYNAMIC"] = 1;
	    if (!donelist["_GLOBAL_OFFSET_TABLE_"])
		donelist["_GLOBAL_OFFSET_TABLE_"] = 1;
	    if (!donelist["_PROCEDURE_LINKAGE_TABLE_"])
		donelist["_PROCEDURE_LINKAGE_TABLE_"] = 1;
	    if (!donelist["_edata"])
		donelist["_edata"] = 1;
	    if (!donelist["_end"])
		donelist["_end"] = 1;
	    if (!donelist["_etext"])
		donelist["_etext"] = 1;
        }

	# Process implicit symbols.
	for (i in syms) {
	    if (donelist[i] == 0 && length(syms[i]) > 0) {
		if (implicit == 0) {
		    # Ignore magic symbols introduced by the C++ compiler.
		    if ((syms[i] !~ /^__vtbl__[0-9]*_/) && (syms[i] !~ /^__ptbl_vec__/))
			print "# Warning:", syms[i], "was not in the export list" | "cat 1>&2";
		} else {
		    donelist[i] = implicit;
		}
	    }
	}

	# Generate the linker file.
	print "";
	print "SUNW.1.1 {";
	print "    global:";
	for (i in syms)
	    if (donelist[i] >= 2 && length(syms[i]) > 0)
		print "        " syms[i] ";";
	print "    local:";
	print "        *;";
	print "};";

	print "";
	print "SUNW_private.1.1 {";
	print "    global:";
	for (i in syms)
	    if (donelist[i] == 1 && length(syms[i]) > 0)
		print "        " syms[i] ";";
	print "} SUNW.1.1;"
    }
'

XCOMM Clean up temporary files
rm $EXPORTLIST
rm $NMLIST
rm $FILTLIST
