]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Minimal object-oriented programming style.
authorBruno Haible <bruno@clisp.org>
Tue, 7 Nov 2006 14:44:28 +0000 (14:44 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:14:19 +0000 (12:14 +0200)
gnulib-local/build-aux/moopp [new file with mode: 0755]
gnulib-local/lib/moo.h [new file with mode: 0644]
gnulib-local/modules/moo [new file with mode: 0644]

diff --git a/gnulib-local/build-aux/moopp b/gnulib-local/build-aux/moopp
new file mode 100755 (executable)
index 0000000..4093c57
--- /dev/null
@@ -0,0 +1,583 @@
+#!/bin/sh
+# Minimal Object-Oriented style PreProcessor.
+
+# Copyright (C) 2006 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 2, 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, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# 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_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
+}
+
+if test $# -lt 2; then
+  func_fatal_error "Usage: $0 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
+}'
+
+# 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 '\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 '\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_start_creation "${main_classname}.priv.h"
+{
+  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 "};"
+} > "${main_classname}.priv.h" || func_fatal_error "failed"
+
+func_start_creation "${main_classname}.vt.h"
+{
+  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,$,;,'
+} > "${main_classname}.vt.h" || func_fatal_error "failed"
+
+# 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,'
+
+source_header_file_base=`echo "$source_header_file" | sed -e 's,^.*/,,'`
+newfile=`echo "$source_header_file_base" | sed -e 's,\.oo\.h$,.h,'`
+func_start_creation "$newfile"
+{
+  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\""
+  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 "#ifdef __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; }"
+  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; }"
+    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 "$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
+  # 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 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}"
+  echo
+  echo "extern 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_fatal_error "failed"
+
+source_impl_file_base=`echo "$source_impl_file" | sed -e 's,^.*/,,'`
+newfile=`echo "$source_impl_file_base" | sed -e 's,\.oo\.c$,.c,'`
+func_start_creation "$newfile"
+{
+  echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'
+  echo
+  echo "#line 1 \"${source_impl_file_base}\""
+  cat "$source_impl_file" | sed -e "${impl_decl_lineno}"',$d'
+  echo "#line "`expr 3 + ${impl_decl_lineno} + 1`" \"$newfile\""
+  # 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 "#ifndef __cplusplus"
+  echo "#define ${main_classname}_representation any_${rootclassname}_representation"
+  echo "#endif"
+  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\""
+  # 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
+        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" || func_fatal_error "failed"
diff --git a/gnulib-local/lib/moo.h b/gnulib-local/lib/moo.h
new file mode 100644 (file)
index 0000000..e5f3736
--- /dev/null
@@ -0,0 +1,257 @@
+/* Minimal object-oriented facilities for C.
+   Copyright (C) 2006 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 Library General Public License as published
+   by the Free Software Foundation; either version 2, 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+   USA.  */
+
+/* This file defines minimal facilities for object-oriented programming
+   style in ANSI C.
+
+   The facilities allow to define classes with single inheritance and
+   "virtual" methods.
+
+   Strict type checking is provided in combination with a C++ compiler:
+   The code compiles in ANSI C with less strict type checking; when
+   compiled with a C++ compiler, strict type checking is done.
+
+   In contrast to [OOC] and [OOPC], this implementation concentrates on the
+   bare essentials of an object-oriented programming style.  It does not
+   provide features that are "sometimes useful", but not essential.
+
+   Features:
+     - Combination of fields and methods into a single object.      YES
+     - Description of objects of same shape and same behaviour
+       by a class.                                                  YES
+     - Single inheritance.                                          YES
+     - Multiple inheritance.                                        NO
+     - Operator overloading (compile-time polymorphism).            NO
+     - Virtual methods (run-time polymorphism).                     YES
+     - Information hiding: private/protected/public.         private fields
+     - Static fields and methods.                                   NO
+     - Constructors, destructors.                                   NO
+     - 'new', 'delete'.                                             NO
+     - Exception handling.                                          NO
+     - Garbage collection.                                          NO
+     - Templates / Generic classes with parameters.                 NO
+     - Namespaces.                                                  NO
+     - Hidden 'this' pointer in methods.                            NO
+     - Declaring or implementing several classes in the same file.  NO
+
+   Rationale for NO:
+     - Multiple inheritance is not supported because programming languages
+       like Java and C# prove that they are not necessary. Modern design
+       patterns use delegation more often than composition; this reduces
+       the pressure to use multiple inheritance.
+       Multiple inheritance of "interfaces" (classes without fields) might
+       be considered, though.
+     - Operator overloading is not essential: The programmer can rename
+       methods so that they carry unambiguous method names. This also makes
+       the code more readable.
+     - Virtual methods are supported. Non-virtual methods are not: they
+       constitute an assumption about the possible subclasses which is more
+       often wrong than right. In other words, non-virtual methods are a
+       premature optimization - "the root of all evil", according to
+       Donald E. Knuth.
+     - Information hiding: 'protected' is not supported because it is always
+       inappropriate: it prohibits the use of the delegation design pattern.
+       'private' is implemented on fields. There are no 'public' fields,
+       since the use of getters/setters allows for overriding in subclasses
+       and is more maintainable (ability to set breakpoints). On the other
+       hand, all methods are 'public'. 'private` methods are not supported
+       because methods with static linkage can be used instead.
+     - Static fields and methods are not supported because normal variables
+       and functions with static or extern linkage can be used instead.
+     - Constructors and destructors are not supported.  The programmer can
+       define 'init' and 'do_free' methods himself.
+     - 'new', 'delete' are not supported because they only provide the
+       grouping of two lines of code into a single line of code.
+     - Exception handling is not supported because conventions with a return
+       code can be used instead.
+     - Garbage collection is not supported. Without it the programmer's life
+       is harder, but not impossible. The programmer has to think about
+       ownership of objects.
+     - Templates / Generic classes with parameters are not supported because
+       they are mostly used for container classes, and container classes can
+       be implemented in a simpler object-oriented way that requires only a
+       very limited form of class inheritance.
+     - Namespaces are not implemented, because they can be simulated by a
+       consistent naming convention.
+     - A hidden 'this' pointer in methods is not implemented. It reduces the
+       transparency of the code (because what looks like a variable access can
+       be an access through 'this') and is simply not needed.
+     - Declaring or implementing several classes in the same file is not
+       supported, because it is anyway good practice to define each class in
+       its own .oo.h / .oo.c file.
+
+   Syntax:
+
+   The syntax resembles C++, but deviates from C++ where the C++ syntax is
+   just too braindead.
+
+   A root class is declared in a .oo.h file:
+
+     struct rootfoo
+     {
+     methods:
+       int method1 (rootfoo_t x, ...); ...
+     };
+
+   and in the corresponding .oo.c file:
+
+     struct rootfoo
+     {
+     fields:
+       int field1; ...
+     };
+
+   A subclass is declared in a .oo.h file as well:
+
+     struct subclass : struct rootfoo
+     {
+     methods:
+       int method2 (subclass_t x, ...); ...
+     };
+
+   and in the corresponding .oo.c file:
+
+     struct subclass : struct rootfoo
+     {
+     fields:
+       int field2; ...
+     };
+
+   This defines:
+     - An incomplete type 'struct any_rootfoo_representation' or
+       'struct subclass_representation', respectively. It denotes the memory
+       occupied by an object of the respective class. The prefix 'any_' is
+       present only for a root class.
+     - A type 'rootfoo_t' or 'subclass_t' that is equivalent to a pointer
+       'struct any_rootfoo_representation *' or
+       'struct subclass_representation *', respectively.
+     - A type 'struct rootfoo_implementation' or
+       'struct subclass_implementation', respectively. It contains a virtual
+       function table for the corresponding type.
+     - A type 'struct rootfoo_representation_header' or
+       'struct subclass_representation_header', respectively, that defines
+       the part of the memory representation containing the virtual function
+       table pointer.
+     - Functions 'rootfoo_method1 (rootfoo_t x, ...);' ...
+                 'subclass_method1 (subclass_t x, ...);' ...
+                 'subclass_method2 (subclass_t x, ...);' ...
+       that invoke the corresponding methods. They are realized as inline
+       functions if possible.
+     - A declaration of 'rootfoo_typeinfo' or 'subclass_typeinfo', respectively,
+       each being a typeinfo_t instance.
+     - A declaration of 'ROOTFOO_SUPERCLASSES' or 'SUBCLASS_SUPERCLASSES',
+       respectively, each being an initializer for an array of typeinfo_t.
+     - A declaration of 'rootfoo_vtable' or 'subclass_vtable', respectively,
+       being an instance of 'struct rootfoo_implementation' or
+       'struct subclass_implementation', respectively.
+     - A header file "rootfoo.priv.h" or "subclass.priv.h" that defines the
+       private fields of 'struct rootfoo_representation' or
+       'struct subclass_representation', respectively.
+
+   A class implementation looks like this, in a .oo.c file:
+
+     struct subclass : struct rootfoo
+     {
+     fields:
+       int field2; ...
+     };
+
+     int subclass::method1 (subclass_t x, ...) { ... } [optional]
+     int subclass::method2 (subclass_t x, ...) { ... }
+     ...
+
+   At the place of the second "struct subclass" definition, the type
+   'struct subclass_representation' is expanded, and the macro 'super' is
+   defined, referring to the vtable of the superclass. For root classes,
+   'super' is not defined. Also, 'subclass_typeinfo' is defined.
+
+   Each method subclass::method_i defines the implementation of a method
+   for the particular class. Its C name is subclass__method_i (not to be
+   confused with subclass_method_i, which is the externally visible function
+   that invokes this method).
+
+   Methods that are not defined implicitly inherited from the superclass.
+
+   At the end of the file, 'subclass_vtable' is defined, as well as
+     'subclass_method1 (subclass_t x, ...);' ...
+     'subclass_method2 (subclass_t x, ...);' ...
+   if they were not already defined as inline functions in the header file.
+
+   Object representation in memory:
+     - Objects have as their first field, called 'vtable', a pointer to a table
+       to data and function pointers that depend only on the class, not on the
+       object instance.
+     - One of the first fields of the vtable is a pointer to the
+       'superclasses'; this is a NULL-terminated array of pointers to
+       typeinfo_t objects, starting with the class itself, then its
+       superclass etc.
+
+
+   [OOC] Axel-Tobias Schreiner: Object-oriented programming with ANSI-C. 1993.
+
+   [OOPC] Laurent Deniau: Object Oriented Programming in C. 2001.
+
+ */
+
+#ifndef _MOO_H
+#define _MOO_H
+
+/* Get size_t, abort().  */
+#include <stdlib.h>
+
+/* An object of this type is defined for each class.  */
+typedef struct
+{
+  const char *classname;
+} typeinfo_t;
+
+/* IS_INSTANCE (OBJ, ROOTCLASSNAME, CLASSNAME)
+   IS_INSTANCE_PRIVATE (OBJ, ROOTCLASSNAME, CLASSNAME)
+   test whether an object is instance of a given class, given as lower case
+   class name.
+   IS_INSTANCE can be used anywhere; IS_INSTANCE_PRIVATE can only be used in
+   the file that implements CLASSNAME but is better optimized.  */
+#define IS_INSTANCE(obj,rootclassname,classname) \
+  (((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses_length \
+   >= classname##_implementation.superclasses_length \
+   && ((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses \
+      [((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses_length \
+       - classname##_implementation.superclasses_length] \
+      == & classname##_typeinfo)
+#define IS_INSTANCE_PRIVATE(obj,rootclassname,classname) \
+  (((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses_length \
+   >= sizeof (classname##_superclasses) / sizeof (classname##_superclasses[0]) \
+   && ((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses \
+      [((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses_length \
+       - sizeof (classname##_superclasses) / sizeof (classname##_superclasses[0])] \
+      == & classname##_typeinfo)
+/* This instance test consists of two comparisons.  One could even optimize
+   this to a single comparison, by limiting the inheritance depth to a fixed
+   limit, for example, say, depth <= 10.  The superclasses list would then
+   need to be stored in reverse order, from the root down to the class itself,
+   and be filled up with NULLs so that the array has length 10.  The instance
+   test would look like this:
+     #define IS_INSTANCE_PRIVATE(obj,rootclassname,classname) \
+       (((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses \
+        [classname##_superclasses_length - 1] \
+        == & classname##_typeinfo)
+   but the classname##_superclasses_length would no longer be available as a
+   simple sizeof expression.  */
+
+#endif /* _MOO_H */
diff --git a/gnulib-local/modules/moo b/gnulib-local/modules/moo
new file mode 100644 (file)
index 0000000..5e2f197
--- /dev/null
@@ -0,0 +1,23 @@
+Description:
+Minimal object-oriented programming style.
+
+Files:
+build-aux/moopp
+lib/moo.h
+
+Depends-on:
+
+configure.ac:
+AC_REQUIRE([AC_C_INLINE])
+
+Makefile.am:
+
+Include:
+"moo.h"
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible
+