#!/bin/sh
# $XConsortium: elistgen.usl /main/2 1996/12/04 10:13:26 swick $
#
# #########################################################################
# Construct shared-library export lists for Novell based on standardized
# export list description file
#
# Usage: exportlistgen libFoo.so libFoo.elist > libFoo.lopt
#
#	libFoo.so    => shared library of interest
#	libFoo.elist => Meta description of necessary export list.
#
#    The output file, "libFoo.lopt" may then be passed to the linker to 
#    reconstruct the shared library.
#
# (c) Copyright 1996 Digital Equipment Corporation.
# (c) Copyright 1996 Hewlett-Packard Company.
# (c) Copyright 1996 International Business Machines Corp.
# (c) Copyright 1996 Sun Microsystems, Inc.
# (c) Copyright 1996 Novell, Inc. 
# (c) Copyright 1996 FUJITSU LIMITED.
# (c) Copyright 1996 Hitachi.
#
# #########################################################################

# Utility programs
FILTER=			# C++ symbol demangler
AWK=awk				# awk

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

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

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

# Extract the globally visible symbols from target library.
# The NMLIST generated here is later used to cross-check the symbols in the
# supplied export-list.
nm -p $1 | $AWK '
    / [TD] [^\$]/{print $3}   # Text, Data, BSS, or Secondary symbols
' > $NMLIST

# Demangle the global library symbols. This operation is necessary to convert
# mangled C++ symbols into their C++ notation.
${FILTER:-cat} $NMLIST > $FILTLIST

# Clean up the export-list description file.
# Note that C++ symbols may have embedded spaces in them.
cat $2 | $AWK '
    BEGIN           {
	csyms     = 0;		# C   language symbols in libfoo.list
	cplusplus = 0;		# C++ language symbols in libfoo.list
	isyms     = 0;		# C   internal symbols in libfoo.elist
	iplusplus = 0;		# C++ internal symbols in libfoo.elist
	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" || $1 == "public" || $1 == "private" {
	csyms ++;
	print $1 ";;" $2;
	next;
    }
    $1 == "publicC++" || $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;
	}
    }
' > $EXPORTLIST

# Read in the above files and write result to stdout.  The contents
# of NMLIST and FILTLIST are used to construct a symbol lookup table.
# The contents of EXPORTLIST are converted with the help of this table.
# 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")
	    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 {
	# Parse our instructions for this symbol.
	if ($1 == "internal" || $1 == "internalC++")
	    export = 1;
	else if ($1 == "private" || $1 == "privateC++")
	    export = 2;
	else if ($1 == "public" || $1 == "publicC++")
	    export = 3;
	else # $1 == "force"
	    export = 4;

	# Process it.
	if (length(syms[$3]) > 0) {
	    # This symbol is present in the library.
	    if (donelist[$3])
		print "# Warning: Duplicate entry for", $3, 
		    "in export list" | "cat 1>&2";
	    if (donelist[$3] < export) {
		if (export > 1)
		    print syms[$3];
		donelist[$3] = export;
	    }
	} else { 
	    # Do not complain about unknown forced-export symbols.
	    if (export == 4) {
		print $3;
		donelist[$3] = export;
	    } else
		print "# Warning:", $3,
		    "was not in the nm list for this library" | "cat 1>&2";
	}

	next;
    }
    END { 
	# Ignore built-in linker symbols.
	if (implicit == 0) {
	    if (!donelist["_DYNAMIC"])
		donelist["_DYNAMIC"] = 1;
	    if (!donelist["_GLOBAL_OFFSET_TABLE_"])
		donelist["_GLOBAL_OFFSET_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] && (length(syms[i]) > 0)) {
		# Ignore C++ compiler symbols
		if (implicit == 0 &&
		    (syms[i] !~ /^__vtbl__[0-9]*_/) &&
		    (syms[i] !~ /^__cpp_unixware_[0-9]*$/))
		    print "# Warning:", syms[i],
		          "was not in the export list" | "cat 1>&2";
	        if (implicit > 1)
		    print syms[i];
	    }
	}
    }
'

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