facf0c92e0
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
767 lines
31 KiB
Bash
Executable File
767 lines
31 KiB
Bash
Executable File
#!/bin/sh
|
|
# Minimal Object-Oriented style PreProcessor.
|
|
|
|
# Copyright (C) 2006-2008, 2016, 2018-2019 Free Software Foundation, Inc.
|
|
# Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
# As a special exception to the GNU General Public License, if you
|
|
# distribute this file as part of a program that contains a
|
|
# configuration script generated by Autoconf, you may include it under
|
|
# the same distribution terms that you use for the rest of that program.
|
|
|
|
# Usage: moopp source.oo.c source.oo.h superclass.oo.h ...
|
|
# Arguments:
|
|
# - the source file of the class,
|
|
# - the header file declaring the class,
|
|
# - the header file declaring its superclass,
|
|
# - etc. up to the root class.
|
|
# Creates four files in the current directory:
|
|
# - source.c, the preprocessing result of source.oo.c,
|
|
# - source.h, the preprocessing result of source.oo.h,
|
|
# - class.priv.h, a file declaring the private fields of the class,
|
|
# - class.vt.h, a file declaring the virtual function table of the class.
|
|
|
|
# This implementation of the preprocessor is a quick hack. It makes assumptions
|
|
# about the source code:
|
|
# - GNU indentation style,
|
|
# - the struct declaration must be in a single line,
|
|
# - no comments on the struct declaration line,
|
|
# - no #ifs in relevant position,
|
|
# - ...
|
|
# Someday this should be rewritten to use a proper tokenizer and parser.
|
|
|
|
# func_usage
|
|
# outputs to stdout the --help usage message.
|
|
func_usage ()
|
|
{
|
|
echo "\
|
|
Usage: moopp [OPTION]... SOURCE.oo.c SOURCE.oo.h SUPERCLASS.oo.h ...
|
|
|
|
Preprocesses SOURCE.oo.c into CLASS.c and SOURCE.oo.h into CLASS.h,
|
|
where CLASS is the name of the class defined in these files.
|
|
|
|
See moo.h for the object-oriented features and the syntax of the input files.
|
|
|
|
Options:
|
|
--help print this help and exit
|
|
--version print version information and exit
|
|
--dllexport=NAME Arrange so that the specified class name can be accessed
|
|
from outside the shared library it is compiled into.
|
|
This option can be repeated.
|
|
|
|
Report bugs to <bruno@clisp.org>."
|
|
}
|
|
|
|
# func_version
|
|
# outputs to stdout the --version message.
|
|
func_version ()
|
|
{
|
|
echo "$progname (GNU $package) $version"
|
|
echo "Copyright (C) 2006-2019 Free Software Foundation, Inc.
|
|
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
|
|
This is free software: you are free to change and redistribute it.
|
|
There is NO WARRANTY, to the extent permitted by law."
|
|
echo "Written by" "Bruno Haible"
|
|
}
|
|
|
|
# func_fatal_error message
|
|
# outputs to stderr a fatal error message, and terminates the program.
|
|
func_fatal_error ()
|
|
{
|
|
echo "moopp: *** $1" 1>&2
|
|
echo "moopp: *** Stop." 1>&2
|
|
exit 1
|
|
}
|
|
|
|
# Command-line option processing.
|
|
# Removes the OPTIONS from the arguments. Sets the variables:
|
|
# - dllexports list of class names to export from Woe32 DLLs
|
|
dllexports=
|
|
while test $# -gt 0; do
|
|
case "$1" in
|
|
--dllexport | --dllexpor | --dllexpo | --dllexp | --dllex | --dlle )
|
|
shift
|
|
if test $# = 0; then
|
|
func_fatal_error "missing argument for --dllexport"
|
|
fi
|
|
case "$1" in
|
|
-*) func_fatal_error "missing argument for --dllexport" ;;
|
|
esac
|
|
dllexports="$dllexports $1"
|
|
shift ;;
|
|
--dllexport=* )
|
|
arg=`echo "X$1" | sed -e 's/^X--dllexport=//'`
|
|
dllexports="$dllexports $arg"
|
|
shift ;;
|
|
--help | --hel | --he | --h )
|
|
func_usage
|
|
exit 0 ;;
|
|
--version | --versio | --versi | --vers | --ver | --ve | --v )
|
|
func_version
|
|
exit 0 ;;
|
|
-- ) # Stop option prcessing
|
|
shift; break ;;
|
|
-* )
|
|
func_fatal_error "unrecognized option: $option"
|
|
;;
|
|
* )
|
|
break ;;
|
|
esac
|
|
done
|
|
|
|
if test $# -lt 2; then
|
|
func_fatal_error "Usage: $0 [OPTION]... source.oo.c source.oo.h superclass.oo.h ..."
|
|
fi
|
|
|
|
# Check that all files exist.
|
|
for file
|
|
do
|
|
test -r "$file" || {
|
|
func_fatal_error "file $file does not exist"
|
|
}
|
|
done
|
|
|
|
source_impl_file="$1"
|
|
source_header_file="$2"
|
|
shift
|
|
shift
|
|
|
|
case "$source_impl_file" in
|
|
*.oo.c) ;;
|
|
*) func_fatal_error "invalid class source file name: $source_impl_file" ;;
|
|
esac
|
|
case "$source_header_file" in
|
|
*.oo.h) ;;
|
|
*) func_fatal_error "invalid class header file name: $source_header_file" ;;
|
|
esac
|
|
|
|
# A sed expression that removes empty lines.
|
|
sed_remove_empty_lines='/^$/d'
|
|
|
|
# A sed expression that removes ANSI C and ISO C99 comments.
|
|
sed_remove_comments="
|
|
/[/][/*]/{
|
|
ta
|
|
:a
|
|
s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)//.*,\\1,
|
|
te
|
|
s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*]\\([^*]\\|[*][^/*]\\)*[*][*]*/,\\1 ,
|
|
ta
|
|
/^\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*[/][*]/{
|
|
s,^\\(\\([^\"'/]\\|\"\\([^\\\"]\\|[\\].\\)*\"\\|'\\([^\\']\\|[\\].\\)*'\\|[/][^\"'/*]\\|[/]\"\\([^\\\"]\\|[\\].\\)*\"\\|[/]'\\([^\\']\\|[\\].\\)*'\\)*\\)/[*].*,\\1 ,
|
|
tu
|
|
:u
|
|
n
|
|
s,^\\([^*]\\|[*][^/*]\\)*[*][*]*/,,
|
|
tv
|
|
s,^.*\$,,
|
|
bu
|
|
:v
|
|
}
|
|
:e
|
|
}"
|
|
# The same thing as an extended regular expression, for use with
|
|
# sed --regexp-extended.
|
|
sed_remove_comments_ERE="
|
|
/[/][/*]/{
|
|
ta
|
|
:a
|
|
s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)//.*,\\1,
|
|
te
|
|
s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)/[*]([^*]|[*][^/*])*[*][*]*/,\\1 ,
|
|
ta
|
|
/^([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*[/][*]/{
|
|
s,^(([^\"'/]|\"([^\\\"]|[\\].)*\"|'([^\\']|[\\].)*'|[/][^\"'/*]|[/]\"([^\\\"]|[\\].)*\"|[/]'([^\\']|[\\].)*')*)/[*].*,\\1 ,
|
|
tu
|
|
:u
|
|
n
|
|
s,^([^*]|[*][^/*])*[*][*]*/,,
|
|
tv
|
|
s,^.*\$,,
|
|
bu
|
|
:v
|
|
}
|
|
:e
|
|
}"
|
|
|
|
# Check that 'sed' supports the kind of regular expressions used in
|
|
# sed_remove_comments. The use of \| meaning alternation of basic regular
|
|
# expressions is a GNU extension.
|
|
sed_test='s,^\(\(a\|X\)*\)//.*,\1,'
|
|
sed_result=`echo 'aaa//bcd' | sed -e "$sed_test"`
|
|
test "$sed_result" = 'aaa' \
|
|
|| func_fatal_error "The 'sed' program is not GNU sed. Try installing GNU sed."
|
|
|
|
# func_check_impl_syntax file
|
|
# Check the syntax of the source implementation file.
|
|
# Output:
|
|
# - classname name of the class being defined (without 'struct')
|
|
# - superclassname name of the superclass, or empty for a root class
|
|
# - impl_decl_lineno line number of the class name declaration ('struct')
|
|
# - impl_beg_lineno line number of the start of the class declaration ('{')
|
|
# - impl_end_lineno line number of the end of the class declaration ('}')
|
|
# - fields field declarations, including preprocessor directives
|
|
func_check_impl_syntax ()
|
|
{
|
|
file="$1"
|
|
sed -e "$sed_remove_comments" < "$file" | grep '^fields:' > /dev/null || {
|
|
func_fatal_error "$file does not contain 'fields:'"
|
|
}
|
|
test `sed -e "$sed_remove_comments" < "$file" | grep -c '^fields:'` = 1 || {
|
|
func_fatal_error "$file contains more than one 'fields:'"
|
|
}
|
|
fields_lineno=`sed -e "$sed_remove_comments" < "$file" | grep -n '^fields:' | sed -e 's,:.*,,'`
|
|
sed_before_fields="$fields_lineno"',$d'
|
|
impl_decl_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_fields" | grep -n '^struct[ ]' | tail -n 1 | sed -e 's,:.*,,'`
|
|
test -n "$impl_decl_lineno" || {
|
|
func_fatal_error "$file: class declaration not found"
|
|
}
|
|
class_line=`sed -e "$sed_remove_comments" < "$file" | sed -n -e "$impl_decl_lineno"'p'`
|
|
sed_extract_classname='s,^struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p'
|
|
classname=`echo "$class_line" | sed -n -e "$sed_extract_classname"`
|
|
test -n "$classname" || {
|
|
func_fatal_error "$0: $file: class name not recognized at line $impl_decl_lineno"
|
|
}
|
|
superclassname=
|
|
if echo "$class_line" | grep ':' > /dev/null; then
|
|
sed_extract_superclassname='s,^.*:[ ]*struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p'
|
|
superclassname=`echo "$class_line" | sed -n -e "$sed_extract_superclassname"`
|
|
test -n "$superclassname" || {
|
|
func_fatal_error "$file: superclass name not recognized at line $impl_decl_lineno"
|
|
}
|
|
fi
|
|
impl_beg_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_fields" | grep -n '^{' | tail -n 1 | sed -e 's,:.*,,'`
|
|
{ test -n "$impl_beg_lineno" && test "$impl_decl_lineno" -lt "$impl_beg_lineno"; } || {
|
|
func_fatal_error "$file: opening brace of class declaration not found after line $impl_decl_lineno"
|
|
}
|
|
sed_after_fields='1,'"$fields_lineno"'d'
|
|
impl_end_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_after_fields" | grep -n '^}' | sed -e '1q' | sed -e 's,:.*,,'`
|
|
test -n "$impl_end_lineno" || {
|
|
func_fatal_error "$file: closing brace of class declaration not found after line $fields_lineno"
|
|
}
|
|
impl_end_lineno=`expr $fields_lineno + $impl_end_lineno`
|
|
sed_extract_fields="$impl_end_lineno"',$d;1,'"$fields_lineno"'d'
|
|
fields=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_extract_fields"`
|
|
}
|
|
|
|
# func_check_header_syntax file
|
|
# Check the syntax of a header file.
|
|
# Output:
|
|
# - classname name of the class being defined (without 'struct')
|
|
# - superclassname name of the superclass, or empty for a root class
|
|
# - class_decl_lineno line number of the class name declaration ('struct')
|
|
# - class_beg_lineno line number of the start of the class declaration ('{')
|
|
# - class_end_lineno line number of the end of the class declaration ('}')
|
|
# - methods newline-separated list of method declarations
|
|
func_check_header_syntax ()
|
|
{
|
|
file="$1"
|
|
sed -e "$sed_remove_comments" < "$file" | grep '^methods:' > /dev/null || {
|
|
func_fatal_error "$file does not contain 'methods:'"
|
|
}
|
|
test `sed -e "$sed_remove_comments" < "$file" | grep -c '^methods:'` = 1 || {
|
|
func_fatal_error "$file contains more than one 'methods:'"
|
|
}
|
|
methods_lineno=`sed -e "$sed_remove_comments" < "$file" | grep -n '^methods:' | sed -e 's,:.*,,'`
|
|
sed_before_methods="$methods_lineno"',$d'
|
|
class_decl_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_methods" | grep -n '^struct[ ]' | tail -n 1 | sed -e 's,:.*,,'`
|
|
test -n "$class_decl_lineno" || {
|
|
func_fatal_error "$file: class declaration not found"
|
|
}
|
|
class_line=`sed -e "$sed_remove_comments" < "$file" | sed -n -e "$class_decl_lineno"'p'`
|
|
sed_extract_classname='s,^struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p'
|
|
classname=`echo "$class_line" | sed -n -e "$sed_extract_classname"`
|
|
test -n "$classname" || {
|
|
func_fatal_error "$0: $file: class name not recognized at line $class_decl_lineno"
|
|
}
|
|
superclassname=
|
|
if echo "$class_line" | grep ':' > /dev/null; then
|
|
sed_extract_superclassname='s,^.*:[ ]*struct[ ][ ]*\([A-Za-z_0-9]*\).*,\1,p'
|
|
superclassname=`echo "$class_line" | sed -n -e "$sed_extract_superclassname"`
|
|
test -n "$superclassname" || {
|
|
func_fatal_error "$file: superclass name not recognized at line $class_decl_lineno"
|
|
}
|
|
fi
|
|
class_beg_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_before_methods" | grep -n '^{' | tail -n 1 | sed -e 's,:.*,,'`
|
|
{ test -n "$class_beg_lineno" && test "$class_decl_lineno" -lt "$class_beg_lineno"; } || {
|
|
func_fatal_error "$file: opening brace of class declaration not found after line $class_decl_lineno"
|
|
}
|
|
sed_after_methods='1,'"$methods_lineno"'d'
|
|
class_end_lineno=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_after_methods" | grep -n '^}' | sed -e '1q' | sed -e 's,:.*,,'`
|
|
test -n "$class_end_lineno" || {
|
|
func_fatal_error "$file: closing brace of class declaration not found after line $methods_lineno"
|
|
}
|
|
class_end_lineno=`expr $methods_lineno + $class_end_lineno`
|
|
sed_extract_methods="$class_end_lineno"',$d;1,'"$methods_lineno"'d'
|
|
methods=`sed -e "$sed_remove_comments" < "$file" | sed -e "$sed_extract_methods" | tr '\015\n' ' ' | tr ';' '\n' | sed -e 's,[ ]*$,,'`
|
|
sed_remove_valid_arg1_lines='/([ ]*'"$classname"'_t[ ]*[A-Za-z_0-9]*[ ]*[,)]/d'
|
|
sed_extract_method_name='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*(.*$,\1,'
|
|
methods_with_bad_arg1=`echo "$methods" | sed -e "$sed_remove_empty_lines" -e "$sed_remove_valid_arg1_lines" -e "$sed_extract_method_name"`
|
|
if test -n "$methods_with_bad_arg1"; then
|
|
methods_with_bad_arg1=`{ echo "$methods_with_bad_arg1" | sed -e 's/$/, /' | tr -d '\015\n'; echo; } | sed -e 's/\(, \)*$//'`
|
|
func_fatal_error "$file: some methods don't have a first argument of type ${classname}_t: $methods_with_bad_arg1"
|
|
fi
|
|
}
|
|
|
|
func_check_impl_syntax "$source_impl_file"
|
|
impl_classname="$classname"
|
|
impl_superclassname="$superclassname"
|
|
|
|
func_check_header_syntax "$source_header_file"
|
|
main_classname="$classname"
|
|
main_superclassname="$superclassname"
|
|
main_class_decl_lineno="$class_decl_lineno"
|
|
main_class_beg_lineno="$class_beg_lineno"
|
|
main_class_end_lineno="$class_end_lineno"
|
|
main_methods="$methods"
|
|
all_superclasses=
|
|
all_methods="$methods"
|
|
inherited_methods=
|
|
last_header_file="$source_header_file"
|
|
expected_superclassname="$superclassname"
|
|
|
|
for file
|
|
do
|
|
if test -z "$expected_superclassname"; then
|
|
func_fatal_error "file $last_header_file does not specify a superclass; superfluous command line argument $file"
|
|
fi
|
|
func_check_header_syntax "$file"
|
|
all_superclasses="$classname $all_superclasses"
|
|
all_methods="$methods
|
|
$all_methods"
|
|
inherited_methods="$methods
|
|
$inherited_methods"
|
|
if test "$classname" != "$expected_superclassname"; then
|
|
func_fatal_error "file $last_header_file specifies superclass '$expected_superclassname', but file $file defines class '$classname'"
|
|
fi
|
|
last_header_file="$file"
|
|
expected_superclassname="$superclassname"
|
|
done
|
|
|
|
if test -n "$expected_superclassname"; then
|
|
func_fatal_error "$0: file $last_header_file specifies superclass '$expected_superclassname', please specify the header file that defines it as additional command line argument"
|
|
fi
|
|
|
|
if test "$impl_classname" != "$main_classname"; then
|
|
func_fatal_error "file $source_header_file specifies class '$main_classname', but file $source_impl_file specifies class '$impl_classname'"
|
|
fi
|
|
if test "$impl_superclassname" != "$main_superclassname"; then
|
|
if test -z "$main_superclassname"; then
|
|
func_fatal_error "file $source_header_file specifies no superclass, but file $source_impl_file specifies a superclass '$impl_superclassname'"
|
|
fi
|
|
if test -z "$impl_superclassname"; then
|
|
func_fatal_error "file $source_header_file specifies a superclass '$main_superclassname', but file $source_impl_file specifies no superclass"
|
|
fi
|
|
func_fatal_error "file $source_header_file specifies a superclass '$main_superclassname', but file $source_impl_file specifies a superclass '$impl_superclassname'"
|
|
fi
|
|
|
|
# func_start_creation file
|
|
# starts the creation of the named file.
|
|
func_start_creation ()
|
|
{
|
|
file="$1"
|
|
if test -f "$file"; then
|
|
echo "Updating $file (backup in ${file}~)"
|
|
mv -f "$file" "${file}~" || func_fatal_error "failed"
|
|
else
|
|
echo "Creating $file"
|
|
fi
|
|
}
|
|
|
|
# func_emit_priv_h newfile
|
|
# outputs to $newfile the contents of class.priv.h.
|
|
func_emit_priv_h ()
|
|
{
|
|
newfile="$1"
|
|
{
|
|
echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'
|
|
echo
|
|
if test -n "${main_superclassname}"; then
|
|
echo "/* Field layout of superclass. */"
|
|
echo "#include \"${main_superclassname}.priv.h\""
|
|
echo
|
|
fi
|
|
echo "/* Field layout of ${main_classname} class. */"
|
|
echo "struct ${main_classname}_representation"
|
|
echo "{"
|
|
if test -n "${main_superclassname}"; then
|
|
echo " struct ${main_superclassname}_representation base;"
|
|
else
|
|
echo " const void *vtable;"
|
|
fi
|
|
echo "$fields" | sed -e "$sed_remove_empty_lines"
|
|
echo "};"
|
|
} > "$newfile"
|
|
}
|
|
|
|
# func_emit_vt_h newfile
|
|
# outputs to $newfile the contents of class.vt.h.
|
|
func_emit_vt_h ()
|
|
{
|
|
newfile="$1"
|
|
{
|
|
echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'
|
|
echo
|
|
if test -n "${main_superclassname}"; then
|
|
echo "/* Virtual function table layout of superclass. */"
|
|
echo "#include \"${main_superclassname}.vt.h\""
|
|
echo
|
|
fi
|
|
echo "/* Virtual function table layout of ${main_classname} class. */"
|
|
echo "$main_methods" | sed -e "$sed_remove_empty_lines" -e 's/\([^A-Za-z_0-9]\)\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*([^,)]*/\1(*\2) (THIS_ARG/' -e 's,$,;,'
|
|
} > "$newfile"
|
|
}
|
|
|
|
# In C++ mode, we have a precise type checking. But in C mode, we have only
|
|
# loose type checking: So that rootclass_t and subclass_t are assignment
|
|
# compatible, we have to define subclass_t as identical to rootclass_t.
|
|
# Therefore we need an alias name for the representation of any type in the
|
|
# hierarchy.
|
|
if test -z "$main_superclassname"; then
|
|
main_repclassalias="any_${main_classname}_representation"
|
|
else
|
|
main_repclassalias="${main_classname}_representation"
|
|
fi
|
|
|
|
sed_extract_method_rettype='s,^\(.*[^A-Za-z_0-9]\)[A-Za-z_0-9][A-Za-z_0-9]*[ ]*(.*$,\1,
|
|
s,^[ ]*,,
|
|
s,[ ]*$,,'
|
|
sed_extract_method_name='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*(.*$,\1,'
|
|
sed_extract_method_arglist='s,^.*[^A-Za-z_0-9][A-Za-z_0-9][A-Za-z_0-9]*[ ]*([^,)]*\(.*\)).*$,'"${main_classname}_t"' first_arg\1,'
|
|
sed_extract_method_args='s,^.*[^A-Za-z_0-9]\([A-Za-z_0-9][A-Za-z_0-9]*\)$,\1,'
|
|
|
|
# func_emit_source_h newfile newfile_base
|
|
# outputs to $newfile the contents of source.h.
|
|
source_header_file_base=`echo "$source_header_file" | sed -e 's,^.*/,,'`
|
|
func_emit_source_h ()
|
|
{
|
|
newfile="$1"
|
|
newfile_base="$2"
|
|
# Use DLL_VARIABLE if and only if the main classname is among the names
|
|
# specified with --dllexport options.
|
|
dllexport_for_variables=
|
|
for name in $dllexports; do
|
|
if test "${main_classname}" = "${name}"; then
|
|
dllexport_for_variables=" DLL_VARIABLE"
|
|
break
|
|
fi
|
|
done
|
|
{
|
|
echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'
|
|
echo
|
|
echo "#line 1 \"${source_header_file_base}\""
|
|
cat "$source_header_file" | sed -e "${main_class_decl_lineno}"',$d'
|
|
echo "#line "`expr 3 + ${main_class_decl_lineno} + 1`" \"$newfile_base\""
|
|
echo "struct ${main_repclassalias};"
|
|
echo "/* ${main_classname}_t is defined as a pointer to struct ${main_repclassalias}."
|
|
echo " In C++ mode, we use a smart pointer class."
|
|
echo " In C mode, we have no other choice than a typedef to the root class type. */"
|
|
echo "#if IS_CPLUSPLUS"
|
|
echo "struct ${main_classname}_t"
|
|
echo "{"
|
|
echo "private:"
|
|
echo " struct ${main_repclassalias} *_pointer;"
|
|
echo "public:"
|
|
echo " ${main_classname}_t () : _pointer (NULL) {}"
|
|
echo " ${main_classname}_t (struct ${main_repclassalias} *pointer) : _pointer (pointer) {}"
|
|
echo " struct ${main_repclassalias} * operator -> () { return _pointer; }"
|
|
echo " operator struct ${main_repclassalias} * () { return _pointer; }"
|
|
atroot=yes
|
|
for classname in $all_superclasses; do
|
|
if test -n "$atroot"; then
|
|
repclassalias="any_${classname}_representation"
|
|
else
|
|
repclassalias="${classname}_representation"
|
|
fi
|
|
echo " operator struct ${repclassalias} * () { return (struct ${repclassalias} *) _pointer; }"
|
|
atroot=
|
|
done
|
|
# The 'operator void *' is needed to avoid ambiguous conversion chains.
|
|
echo " operator void * () { return _pointer; }"
|
|
# The 'operator ==' and 'operator !=' are needed to avoid ambiguous comparisons with NULL.
|
|
echo " bool operator == (const void *p) { return _pointer == p; }"
|
|
echo " bool operator != (const void *p) { return _pointer != p; }"
|
|
atroot=yes
|
|
for classname in $all_superclasses; do
|
|
if test -n "$atroot"; then
|
|
repclassalias="any_${classname}_representation"
|
|
else
|
|
repclassalias="${classname}_representation"
|
|
fi
|
|
echo " operator ${classname}_t () { return (${classname}_t) (struct ${repclassalias} *) _pointer; }"
|
|
# The 'explicit' constructors allow to downcast.
|
|
echo " explicit ${main_classname}_t (${classname}_t x) : _pointer ((struct ${main_repclassalias} *) (void *) x) {}"
|
|
atroot=
|
|
done
|
|
echo "};"
|
|
echo "#else"
|
|
if test -n "${main_superclassname}"; then
|
|
echo "typedef ${main_superclassname}_t ${main_classname}_t;"
|
|
else
|
|
echo "typedef struct ${main_repclassalias} * ${main_classname}_t;"
|
|
fi
|
|
echo "#endif"
|
|
echo
|
|
echo "/* Functions that invoke the methods. */"
|
|
echo "#ifdef __cplusplus"
|
|
echo "extern \"C\" {"
|
|
echo "#endif"
|
|
echo "$all_methods" | sed -e "$sed_remove_empty_lines" -e 's/\([^A-Za-z_0-9]\)\([A-Za-z_0-9][A-Za-z_0-9]*\)[ ]*([^,)]*/\1'"${main_classname}_"'\2 ('"${main_classname}_t first_arg"'/' -e 's,^,extern ,' -e 's,$,;,'
|
|
echo "#ifdef __cplusplus"
|
|
echo "}"
|
|
echo "#endif"
|
|
echo
|
|
# Now come the implementation details.
|
|
echo "/* Type representing an implementation of ${main_classname}_t. */"
|
|
echo "struct ${main_classname}_implementation"
|
|
echo "{"
|
|
echo " const typeinfo_t * const *superclasses;"
|
|
echo " size_t superclasses_length;"
|
|
echo " size_t instance_size;"
|
|
echo "#define THIS_ARG ${main_classname}_t first_arg"
|
|
echo "#include \"${main_classname}.vt.h\""
|
|
echo "#undef THIS_ARG"
|
|
echo "};"
|
|
echo
|
|
echo "/* Public portion of the object pointed to by a ${main_classname}_t. */"
|
|
echo "struct ${main_classname}_representation_header"
|
|
echo "{"
|
|
echo " const struct ${main_classname}_implementation *vtable;"
|
|
echo "};"
|
|
echo
|
|
echo "#if HAVE_INLINE"
|
|
echo
|
|
echo "/* Define the functions that invoke the methods as inline accesses to"
|
|
echo " the ${main_classname}_implementation."
|
|
echo " Use #define to avoid a warning because of extern vs. static. */"
|
|
echo
|
|
echo "$all_methods" | sed -e "$sed_remove_empty_lines" |
|
|
while read method; do
|
|
rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"`
|
|
name=`echo "$method" | sed -e "$sed_extract_method_name"`
|
|
arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"`
|
|
if test "$arglist" = "void"; then
|
|
args=
|
|
else
|
|
args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'`
|
|
fi
|
|
if test "$rettype" = "void"; then
|
|
return=
|
|
else
|
|
return="return "
|
|
fi
|
|
echo "# define ${main_classname}_${name} ${main_classname}_${name}_inline"
|
|
echo "static inline $rettype"
|
|
echo "${main_classname}_${name} ($arglist)"
|
|
echo "{"
|
|
echo " const struct ${main_classname}_implementation *vtable ="
|
|
echo " ((struct ${main_classname}_representation_header *) (struct ${main_repclassalias} *) first_arg)->vtable;"
|
|
echo " ${return}vtable->${name} ($args);"
|
|
echo "}"
|
|
echo
|
|
done
|
|
echo "#endif"
|
|
echo
|
|
echo "extern${dllexport_for_variables} const typeinfo_t ${main_classname}_typeinfo;"
|
|
if test -n "${main_superclassname}"; then
|
|
superclasses_array_initializer="${main_superclassname}_SUPERCLASSES"
|
|
else
|
|
superclasses_array_initializer="NULL"
|
|
fi
|
|
echo "#define ${main_classname}_SUPERCLASSES &${main_classname}_typeinfo, ${superclasses_array_initializer}"
|
|
if test -n "${main_superclassname}"; then
|
|
echo "#define ${main_classname}_SUPERCLASSES_LENGTH (1 + ${main_superclassname}_SUPERCLASSES_LENGTH)"
|
|
else
|
|
echo "#define ${main_classname}_SUPERCLASSES_LENGTH (1 + 1)"
|
|
fi
|
|
echo
|
|
echo "extern${dllexport_for_variables} const struct ${main_classname}_implementation ${main_classname}_vtable;"
|
|
echo
|
|
echo "#line "`expr $main_class_end_lineno + 1`" \"${source_header_file_base}\""
|
|
cat "$source_header_file" | sed -e "1,${main_class_end_lineno}d"
|
|
} > "$newfile"
|
|
}
|
|
|
|
# func_emit_source_c newfile newfile_base
|
|
# outputs to $newfile the contents of source.c.
|
|
source_impl_file_base=`echo "$source_impl_file" | sed -e 's,^.*/,,'`
|
|
func_emit_source_c ()
|
|
{
|
|
newfile="$1"
|
|
newfile_base="$2"
|
|
{
|
|
echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'
|
|
echo
|
|
# In C mode, where subclass_t is identical to rootclass_t, we define the
|
|
# any_rootclass_representation type to the right one for subclass.
|
|
if test -n "$all_superclasses"; then
|
|
for classname in $all_superclasses; do
|
|
rootclassname="$classname"
|
|
break
|
|
done
|
|
else
|
|
rootclassname="$main_classname"
|
|
fi
|
|
echo "#if !IS_CPLUSPLUS"
|
|
echo "#define ${main_classname}_representation any_${rootclassname}_representation"
|
|
echo "#endif"
|
|
echo "#line 1 \"${source_impl_file_base}\""
|
|
cat "$source_impl_file" | sed -e "${impl_decl_lineno}"',$d'
|
|
echo "#line "`expr 6 + ${impl_decl_lineno} + 1`" \"$newfile_base\""
|
|
echo "#include \"${main_classname}.priv.h\""
|
|
echo
|
|
echo "const typeinfo_t ${main_classname}_typeinfo = { \"${main_classname}\" };"
|
|
echo
|
|
echo "static const typeinfo_t * const ${main_classname}_superclasses[] ="
|
|
echo " { ${main_classname}_SUPERCLASSES };"
|
|
echo
|
|
if test -n "${main_superclassname}"; then
|
|
echo "#define super ${main_superclassname}_vtable"
|
|
echo
|
|
fi
|
|
echo "#line "`expr $impl_end_lineno + 1`" \"${source_impl_file_base}\""
|
|
cat "$source_impl_file" | sed -e "1,${impl_end_lineno}d" | sed -e "s,${main_classname}::,${main_classname}__,g"
|
|
echo
|
|
lineno=`wc -l < "$newfile"`
|
|
echo "#line "`expr $lineno + 2`" \"$newfile_base\""
|
|
# Define trivial stubs for methods that are not defined or overridden.
|
|
inherited_method_names=`echo "$inherited_methods" | sed -e "$sed_remove_empty_lines" | sed -e "$sed_extract_method_name"`
|
|
echo "$all_methods" | sed -e "$sed_remove_empty_lines" |
|
|
while read method; do
|
|
rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"`
|
|
name=`echo "$method" | sed -e "$sed_extract_method_name"`
|
|
arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"`
|
|
if test "$arglist" = "void"; then
|
|
args=
|
|
else
|
|
args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'`
|
|
fi
|
|
if test "$rettype" = "void"; then
|
|
return=
|
|
else
|
|
return="return "
|
|
fi
|
|
if cat "$source_impl_file" | sed -e "1,${impl_end_lineno}d" | sed -e "$sed_remove_comments" | grep "${main_classname}::${name} *(" > /dev/null; then
|
|
# The class defines or overrides the method.
|
|
:
|
|
else
|
|
# Add a stub for the method.
|
|
inherited=
|
|
for i in $inherited_method_names; do
|
|
if test "$i" = "$name"; then
|
|
inherited=yes
|
|
fi
|
|
done
|
|
# First a prototype, to avoid gcc -Wmissing-prototypes warnings.
|
|
echo "$rettype ${main_classname}__${name} ($arglist);"
|
|
echo "$rettype"
|
|
echo "${main_classname}__${name} ($arglist)"
|
|
echo "{"
|
|
if test -n "$inherited"; then
|
|
echo " ${return}super.${name} ($args);"
|
|
else
|
|
echo " /* Abstract (unimplemented) method called. */"
|
|
echo " abort ();"
|
|
# Avoid C++ compiler warning about missing return value.
|
|
echo " #ifndef __GNUC__"
|
|
echo " ${return}${main_classname}__${name} ($args);"
|
|
echo " #endif"
|
|
fi
|
|
echo "}"
|
|
echo
|
|
fi
|
|
done
|
|
echo
|
|
echo "const struct ${main_classname}_implementation ${main_classname}_vtable ="
|
|
echo "{"
|
|
echo " ${main_classname}_superclasses,"
|
|
echo " sizeof (${main_classname}_superclasses) / sizeof (${main_classname}_superclasses[0]),"
|
|
echo " sizeof (struct ${main_classname}_representation),"
|
|
echo "$all_methods" | sed -e "$sed_remove_empty_lines" |
|
|
while read method; do
|
|
name=`echo "$method" | sed -e "$sed_extract_method_name"`
|
|
echo " ${main_classname}__${name},"
|
|
done
|
|
echo "};"
|
|
echo
|
|
echo "#if !HAVE_INLINE"
|
|
echo
|
|
echo "/* Define the functions that invoke the methods. */"
|
|
echo
|
|
echo "$all_methods" | sed -e "$sed_remove_empty_lines" |
|
|
while read method; do
|
|
rettype=`echo "$method" | sed -e "$sed_extract_method_rettype"`
|
|
name=`echo "$method" | sed -e "$sed_extract_method_name"`
|
|
arglist=`echo "$method" | sed -e "$sed_extract_method_arglist"`
|
|
if test "$arglist" = "void"; then
|
|
args=
|
|
else
|
|
args=`{ echo "$arglist" | tr ',' '\n' | sed -e "$sed_extract_method_args" | tr '\n' ','; echo; } | sed -e 's/,$//'`
|
|
fi
|
|
if test "$rettype" = "void"; then
|
|
return=
|
|
else
|
|
return="return "
|
|
fi
|
|
echo "$rettype"
|
|
echo "${main_classname}_${name} ($arglist)"
|
|
echo "{"
|
|
echo " const struct ${main_classname}_implementation *vtable ="
|
|
echo " ((struct ${main_classname}_representation_header *) (struct ${main_repclassalias} *) first_arg)->vtable;"
|
|
echo " ${return}vtable->${name} ($args);"
|
|
echo "}"
|
|
echo
|
|
done
|
|
echo "#endif"
|
|
} > "$newfile"
|
|
}
|
|
|
|
# Generate the files in the source directory, not in the current directory.
|
|
# This is needed because they need to be distributed, since not all platforms
|
|
# have GNU 'sed' preinstalled.
|
|
|
|
sed_butbase='s,[^/]*$,,'
|
|
destdir=`echo "$source_impl_file" | sed -e "$sed_butbase"`
|
|
|
|
# Generate the source.h file first. The Makefile.am snippets rely on the
|
|
# fact that the other generated files have the same or a newer timestamp.
|
|
#
|
|
# Also, generate the source.c file last. The Makefile.am snippets don't know
|
|
# about the other generated files; they assume that when the source.c file
|
|
# is finished, this command is complete.
|
|
|
|
new_source_header_file_base=`echo "$source_header_file_base" | sed -e 's,\.oo\.h$,.h,'`
|
|
new_source_header_file="${destdir}$new_source_header_file_base"
|
|
func_start_creation "$new_source_header_file"
|
|
func_emit_source_h "$new_source_header_file" "$new_source_header_file_base" \
|
|
|| func_fatal_error "failed"
|
|
|
|
new_priv_header_file="${destdir}${main_classname}.priv.h"
|
|
func_start_creation "$new_priv_header_file"
|
|
func_emit_priv_h "$new_priv_header_file" \
|
|
|| func_fatal_error "failed"
|
|
|
|
new_vt_header_file="${destdir}${main_classname}.vt.h"
|
|
func_start_creation "$new_vt_header_file"
|
|
func_emit_vt_h "$new_vt_header_file" \
|
|
|| func_fatal_error "failed"
|
|
|
|
new_source_impl_file_base=`echo "$source_impl_file_base" | sed -e 's,\.oo\.c$,.c,'`
|
|
new_source_impl_file="${destdir}$new_source_impl_file_base"
|
|
func_start_creation "$new_source_impl_file"
|
|
func_emit_source_c "$new_source_impl_file" "$new_source_impl_file_base" \
|
|
|| func_fatal_error "failed"
|